import { Atom, Signal, Scope } from 'nrgy';
import {
  EventError,
  EventOk,
  SyncResult,
  HttpClientFetchError,
  HttpClientResponseError,
  JazzSdkPlugin,
  JazzRoom,
  JazzClient,
  QueryAtom,
  Query,
  ConfigFlags,
  JazzRoomParticipantId,
  LocalAudioOutputDevice,
  JazzSdk,
  MediaType,
  JazzRoomVideoRequest,
  JazzRoomVideoQuality,
  JazzRoomVideoSource,
  LogLevel,
  LogEvent,
} from '@salutejs/jazz-sdk-web';
import { Controller } from 'rx-effects';
import { Observable } from 'rxjs';
import { toQuery, toAction } from 'nrgy/rx-effects';
import { observe } from 'nrgy/rxjs';

type ServerRecordingEventStarted = {
  type: 'serverRecordStarted';
};
type ServerRecordingEventStopped = {
  type: 'serverRecordStopped';
  payload: {
    reason?: 'DURATION_LIMIT_EXCEEDED' | 'STOP_MANUALLY';
  };
};
type ServerRecordingEventUploaded = {
  type: 'serverRecordUploaded';
};
type ServerRecordingEventStartError = {
  type: 'serverRecordStartError';
  payload?: {
    error: 'forbidden' | 'alreadyStarted' | 'storageCapacityExceeded';
  };
};
type ServerRecordingEventStopError = {
  type: 'serverRecordStopError';
  payload?: {
    error: 'forbidden' | 'notStarted';
  };
};
type ServerRecordingEventUploadError = {
  type: 'serverRecordUploadedError';
};
type ServerRecordingEventError = {
  type: 'serverRecordError';
};
type ServerRecordingEventAutoStartError = {
  type: 'serverRecordAutoStartError';
  payload?: {
    error: 'internalError' | 'hasNoPermission' | 'storageSizeExceeded';
  };
};
type ServerRecordingEvents =
  | ServerRecordingEventStarted
  | ServerRecordingEventStopped
  | ServerRecordingEventUploaded
  | ServerRecordingEventStartError
  | ServerRecordingEventStopError
  | ServerRecordingEventUploadError
  | ServerRecordingEventError
  | ServerRecordingEventAutoStartError;
type RoomServerRecordingStatus =
  | 'inactive'
  | 'processStarting'
  | 'recording'
  | 'processStopping';
type RoomServerRecordingSupportedStatus =
  | 'supported'
  | 'pending'
  | 'unsupported';
type BaseServerRecordingRoomService = {
  events: Signal<ServerRecordingEvents>;
  /**
   * Starts server recording
   * @throws {ServerRecordingError} When recording fails to start with codes:
   * - 'FORBIDDEN'
   * - 'VIDEO_RECORD_ALREADY_STARTED'
   * - 'VIDEO_RECORD_STORAGE_CAPACITY_EXCEEDED'
   * - 'VIDEO_RECORD_START_ERROR'
   */
  startServerRecording: () => Promise<void>;
  /**
   * Stops server recording
   * @throws {ServerRecordingError} When recording fails to stop with codes:
   * - 'FORBIDDEN'
   * - 'VIDEO_RECORD_STOP_ERROR'
   * - 'VIDEO_RECORD_NOT_STARTED'
   */
  stopServerRecording: () => Promise<void>;
};
type ServerRecordingRoomService = BaseServerRecordingRoomService & {
  serverSupportedStatus: Atom<RoomServerRecordingSupportedStatus>;
  isReady: Atom<boolean>;
  status: Atom<RoomServerRecordingStatus>;
  canManageServerRecordList: Atom<boolean>;
  canManageServerRecord: Atom<boolean>;
};
declare class ServerRecordingError extends Error {
  readonly code: string;
  readonly error?: string;
  constructor(code: string, message?: string);
}

type ServerRecordingStartErrorEvent = EventError<
  | 'FORBIDDEN'
  | 'VIDEO_RECORD_ALREADY_STARTED'
  | 'VIDEO_RECORD_STORAGE_CAPACITY_EXCEEDED'
  | 'VIDEO_RECORD_START_ERROR'
>;
type ServerRecordingStopErrorEvent = EventError<
  'FORBIDDEN' | 'VIDEO_RECORD_STOP_ERROR' | 'VIDEO_RECORD_NOT_STARTED'
>;
type ServerRecordingMessages =
  | EventOk<'video-record-started'>
  | EventOk<'video-record-uploaded'>
  | EventOk<
      'video-record-stopped', // запись остановлена
      {
        reason: 'STOP_MANUALLY' | 'DURATION_LIMIT_EXCEEDED';
      }
    >
  | EventError<
      'START_ERROR' | 'AUTOSTART_ERROR' | 'RECORD_ERROR' | 'UPLOAD_ERROR', // ошибка загрузки записи
      unknown,
      'video-record-error'
    >;

/**
 * Symbols used internally within ts-pattern to construct and discriminate
 * Guard, Not, and Select, and AnonymousSelect patterns
 *
 * Symbols have the advantage of not appearing in auto-complete suggestions in
 * user defined patterns, and eliminate the risk of property
 * overlap between ts-pattern internals and user defined patterns.
 *
 * These symbols have to be visible to tsc for type inference to work, but
 * users should not import them
 * @module
 * @private
 * @internal
 */
declare const toExclude: unique symbol;
type toExclude = typeof toExclude;
declare const matcher: unique symbol;
type matcher = typeof matcher;

type ValueOf<a> = a extends any[] ? a[number] : a[keyof a];
type Cast<a, b> = a extends b ? a : never;
type BuiltInObjects =
  | Function
  | Date
  | RegExp
  | Generator
  | {
      readonly [Symbol.toStringTag]: string;
    }
  | any[];
type IsPlainObject<o, excludeUnion = BuiltInObjects> = o extends object
  ? o extends string | excludeUnion
    ? false
    : true
  : false;
type Compute<a extends any> = a extends BuiltInObjects
  ? a
  : {
      [k in keyof a]: a[k];
    };
type Primitives =
  | number
  | boolean
  | string
  | undefined
  | null
  | symbol
  | bigint;

type None = {
  type: 'none';
};
type Some<key extends string> = {
  type: 'some';
  key: key;
};
type SelectionType = None | Some<string>;

type MatcherType =
  | 'not'
  | 'optional'
  | 'or'
  | 'and'
  | 'array'
  | 'select'
  | 'default';
type MatcherProtocol<
  input,
  narrowed,
  matcherType extends MatcherType,
  selections extends SelectionType,
  excluded,
> = {
  match: <I>(value: I | input) => MatchResult;
  getSelectionKeys?: () => string[];
  matcherType?: matcherType;
};
type MatchResult = {
  matched: boolean;
  selections?: Record<string, any>;
};
/**
 * A `Matcher` is an object implementing the match
 * protocol. It must define a `symbols.matcher` property
 * which returns an object with a `match()` method, taking
 * the input value and returning whether the pattern matches
 * or not, along with optional selections.
 */
interface Matcher<
  input,
  narrowed,
  matcherType extends MatcherType = 'default',
  selections extends SelectionType = None,
  excluded = narrowed,
> {
  [matcher](): MatcherProtocol<
    input,
    narrowed,
    matcherType,
    selections,
    excluded
  >;
}
type UnknownMatcher = Matcher<unknown, unknown, any, any>;
type OptionalP<input, p> = Matcher<input, p, 'optional'>;
type GuardP<input, narrowed> = Matcher<input, narrowed>;
interface ToExclude<a> {
  [toExclude]: a;
}
type UnknownPattern =
  | readonly []
  | readonly [UnknownPattern, ...UnknownPattern[]]
  | {
      readonly [k: string]: UnknownPattern;
    }
  | Set<UnknownPattern>
  | Map<unknown, UnknownPattern>
  | Primitives
  | UnknownMatcher;
/**
 * `Pattern<a>` is the generic type for patterns matching a value of type `a`. A pattern can be any (nested) javascript value.
 *
 * They can also be wildcards, like `P._`, `P.string`, `P.number`,
 * or other matchers, like `P.when(predicate)`, `P.not(pattern)`, etc.
 *
 * [Read documentation for `P.Pattern` on GitHub](https://github.com/gvergnaud/ts-pattern#patterns)
 *
 * @example
 * const pattern: P.Pattern<User> = { name: P.string }
 */
type Pattern<a> =
  | Matcher<a, unknown, any, any>
  | (a extends Primitives
      ? a
      : unknown extends a
        ? UnknownPattern
        : a extends readonly (infer i)[]
          ? a extends readonly [any, ...any]
            ? {
                readonly [index in keyof a]: Pattern<a[index]>;
              }
            : readonly [] | readonly [Pattern<i>, ...Pattern<i>[]]
          : a extends Map<infer k, infer v>
            ? Map<k, Pattern<v>>
            : a extends Set<infer v>
              ? Set<Pattern<v>>
              : a extends object
                ? {
                    readonly [k in keyof a]?: Pattern<Exclude<a[k], undefined>>;
                  }
                : a);

type OptionalKeys<p> = ValueOf<{
  [k in keyof p]: p[k] extends Matcher<any, any, infer matcherType>
    ? matcherType extends 'optional'
      ? k
      : never
    : never;
}>;
type ReduceUnion<tuple extends any[], output = never> = tuple extends readonly [
  infer p,
  ...infer tail,
]
  ? ReduceUnion<tail, output | InvertPattern<p>>
  : output;
type ReduceIntersection<
  tuple extends any[],
  output = unknown,
> = tuple extends readonly [infer p, ...infer tail]
  ? ReduceIntersection<tail, output & InvertPattern<p>>
  : output;
/**
 * ### InvertPattern
 * Since patterns have special wildcard values, we need a way
 * to transform a pattern into the type of value it represents
 */
type InvertPattern<p> =
  p extends Matcher<infer input, infer narrowed, infer matcherType, any>
    ? {
        not: ToExclude<InvertPattern<narrowed>>;
        select: InvertPattern<narrowed>;
        array: InvertPattern<narrowed>[];
        optional: InvertPattern<narrowed> | undefined;
        and: ReduceIntersection<Cast<narrowed, any[]>>;
        or: ReduceUnion<Cast<narrowed, any[]>>;
        default: [narrowed] extends [never] ? input : narrowed;
      }[matcherType]
    : p extends Primitives
      ? p
      : p extends readonly (infer pp)[]
        ? p extends readonly [infer p1, infer p2, infer p3, infer p4, infer p5]
          ? [
              InvertPattern<p1>,
              InvertPattern<p2>,
              InvertPattern<p3>,
              InvertPattern<p4>,
              InvertPattern<p5>,
            ]
          : p extends readonly [infer p1, infer p2, infer p3, infer p4]
            ? [
                InvertPattern<p1>,
                InvertPattern<p2>,
                InvertPattern<p3>,
                InvertPattern<p4>,
              ]
            : p extends readonly [infer p1, infer p2, infer p3]
              ? [InvertPattern<p1>, InvertPattern<p2>, InvertPattern<p3>]
              : p extends readonly [infer p1, infer p2]
                ? [InvertPattern<p1>, InvertPattern<p2>]
                : p extends readonly [infer p1]
                  ? [InvertPattern<p1>]
                  : p extends readonly []
                    ? []
                    : InvertPattern<pp>[]
        : p extends Map<infer pk, infer pv>
          ? Map<pk, InvertPattern<pv>>
          : p extends Set<infer pv>
            ? Set<InvertPattern<pv>>
            : IsPlainObject<p> extends true
              ? OptionalKeys<p> extends infer optKeys
                ? [optKeys] extends [never]
                  ? {
                      [k in Exclude<keyof p, optKeys>]: InvertPattern<p[k]>;
                    }
                  : Compute<
                      {
                        [k in Exclude<keyof p, optKeys>]: InvertPattern<p[k]>;
                      } & {
                        [k in Cast<optKeys, keyof p>]?: InvertPattern<p[k]>;
                      }
                    >
                : never
              : p;

type PInfer<p extends Pattern<any>> = InvertPattern<p>;
declare const getVideoStoragePattern: {
  usedMb: GuardP<unknown, number>;
  availableMb: OptionalP<unknown, GuardP<unknown, number>>;
  capacityMb: GuardP<unknown, number>;
};
type StartVideoRecordErrors =
  | {
      type: 'storageQuotaExceeded';
    }
  | {
      type: 'clientError';
    };
type StartVideoRecordResponse = SyncResult<
  undefined,
  | HttpClientFetchError
  | HttpClientResponseError<StartVideoRecordErrors, void, void>
>;
type GetVideoFindRequest = Readonly<{
  pageNumber?: number;
  pageSize: number;
}>;
type GetVideoFindResponse = {
  totalPages: number;
  records: VideoRecord[];
  pageNumber?: number;
  pageSize?: number;
};
type VideoRecord = {
  id: number;
  title: string;
  createdAt: string;
  durationSeconds: number;
  publicId?: string;
  sizeMb?: number;
  publicAccess?: boolean;
  watchUrl?: string | null;
  downloadUrl?: string;
  permissions: {
    canTogglePublicAccess: boolean;
  };
};
type GetVideoResponse = VideoRecord;
type GetVideoStorageResponse = PInfer<typeof getVideoStoragePattern>;
type RoomRecordingServiceClient = Readonly<{
  getVideoStorage: () => Promise<GetVideoStorageResponse>;
  startVideoRecord: (roomId: string) => Promise<StartVideoRecordResponse>;
  stopVideoRecord: (roomId: string) => Promise<void>;
  getVideoFind: (request: GetVideoFindRequest) => Promise<GetVideoFindResponse>;
  getVideo: (recordId: string) => Promise<GetVideoResponse>;
  updateVideoTitle: (recordId: number, title: string) => Promise<void>;
  updateVideoPublicAccess: (
    recordId: number,
    publicAccess: boolean,
  ) => Promise<void>;
  deleteVideo: (recordId: number) => Promise<void>;
  getDownloadLink: (recordPublicId: string) => Promise<string>;
  getS3DownloadLink: (url: string) => Promise<string | undefined>;
}>;

declare function serverRecordingPlugin(): JazzSdkPlugin;

declare const getServerRecording: (
  jazzRoom: JazzRoom,
) => ServerRecordingRoomService;

declare const getServerRecordingClient: (
  jazzRoom: JazzRoom | JazzClient,
) => RoomRecordingServiceClient;

type AudioLevelService = {
  addMediaStream: (stream: MediaStream) => AudioLevel;
  removeMediaStream: (stream: MediaStream) => void;
};
type AudioLevel = {
  /**
   * @example 50
   * @description the min value is 0 and the max value is 100
   */
  level: QueryAtom<number>;
  isActive: QueryAtom<boolean>;
};

type AudioMixerEventStopAudio = Readonly<{
  type: 'stopAudio';
}>;
type AudioMixerEventStoppedAudio = Readonly<{
  type: 'stoppedAudio';
}>;
type AudioMixerEventStartAudio = Readonly<{
  type: 'startAudio';
}>;
type AudioMixerEventStartedAudio = Readonly<{
  type: 'startedAudio';
}>;
type AudioMixerEventAddMediaStream = Readonly<{
  type: 'addMediaStream';
  payload: {
    mediaStream: MediaStream;
    audioElement: HTMLAudioElement;
  };
}>;
type AudioMixerEventRemoveMediaStream = Readonly<{
  type: 'removeMediaStream';
  payload: {
    mediaStream: MediaStream;
    audioElement: HTMLAudioElement;
  };
}>;
type AudioMixerEventGainChanged = Readonly<{
  type: 'gainChanged';
  payload: {
    value: number;
  };
}>;
type AudioMixerEvent =
  | AudioMixerEventStopAudio
  | AudioMixerEventStoppedAudio
  | AudioMixerEventStartAudio
  | AudioMixerEventStartedAudio
  | AudioMixerEventAddMediaStream
  | AudioMixerEventRemoveMediaStream
  | AudioMixerEventGainChanged;
type AudioMixinNode = Controller<{
  destinationNode: MediaStreamAudioDestinationNode;
  addStream: (stream: MediaStream) => void;
  removeStream: (stream: MediaStream) => void;
}>;
type AudioMixer = Controller<{
  $isSuspended: Query<boolean>;
  isReady: Query<boolean>;
  /**
   * Creating all the elements for audio capture and playback of external audio streams,
   * after that, loopback is immediately launched, if it is enabled.
   * Until this function works, the audio will not be played.
   */
  startAudio: () => Promise<void>;
  /**
   * Stops loopback if it was enabled and then clears all audio capture and playback elements.
   */
  stopAudio: () => Promise<void>;
  addMediaStream: (mediaStreams: MediaStream) => void;
  removeMediaStream: (mediaStreams: MediaStream) => void;
  removeAllMediaStreams: () => void;
  $outputGain: Query<number>;
  setOutputGain: (volume: number) => void;
  setOutputDevice: (deviceId: string) => Promise<void>;
  soundCheck: () => void;
  setRemoteInputMixer: (mixer: InputAudioMixerFactory | undefined) => void;
  getAudioContext: () => AudioContext;
  createMixinNode: () => Promise<AudioMixinNode>;
  setAudioSourcesPlayback: (enabled: boolean) => void;
  event$: Observable<AudioMixerEvent>;
}>;
type AudioEffectFactory<T extends Controller> = (
  audioContext: AudioContext,
) => T;
type AudioSource = Readonly<{
  sourceNode: Atom<MediaStreamAudioSourceNode>;
  scope: Scope;
  element: HTMLAudioElement;
  streamId: string;
}>;
type InputAudioMixer = Controller<{
  output: AudioNode;
  connect: (source: AudioSource) => Controller;
}>;
type InputAudioMixerFactory = AudioEffectFactory<InputAudioMixer>;

type AudioMixerFlags = ConfigFlags<{
  loopbackEnabled: boolean;
  loopbackMaxChromiumVersion: number;
  loopbackRestartOnDisconnect: boolean;
  loopbackMungeCandidates: boolean;
  loopbackStunServer?: string;
}>;

type AudioTrack = {
  participantId: JazzRoomParticipantId;
  mediaStream: MediaStream;
};
type AudioMixerParticipantsManager = Controller<{
  $mutedParticipants: Query<ReadonlySet<JazzRoomParticipantId>>;
  addTracks: (tracks: AudioTrack[]) => void;
  removeTracks: (tracks: AudioTrack[]) => void;
  removeAllTracks: () => void;
  muteParticipants: (
    isMuted: boolean,
    ids: Array<JazzRoomParticipantId>,
  ) => void;
}>;

type AudioOutputMixer = {
  $isSuspended: Query<boolean>;
  event$: Observable<AudioMixerEvent>;
  startAudio: () => Promise<void>;
  stopAudio: () => Promise<void>;
  setOutputDevice: (audioOutput: LocalAudioOutputDevice) => Promise<void>;
  outputGain: Query<number>;
  setOutputGain: (volume: number) => void;
  addMediaStream: (mediaStream: MediaStream) => void;
  removeMediaStream: (mediaStream: MediaStream) => void;
  muteParticipants: (
    isMuted: boolean,
    ids: Array<JazzRoomParticipantId>,
  ) => void;
};

type AudioOutputMixerPluginOptions = Partial<{
  flags?: Partial<AudioMixerFlags>;
}>;
type AudioOutputMixerContext = {
  audioMixer: AudioMixer;
  audioOutputMixer: AudioOutputMixer;
  audioMixerParticipantsManager: AudioMixerParticipantsManager;
  audioLevel: AudioLevelService;
};

/**
 * Позволяет локально управлять звуком участников конференций
 */
declare function audioOutputMixerPlugin(
  options?: AudioOutputMixerPluginOptions,
): JazzSdkPlugin;

declare const AUDIO_GAIN_DEFAULT = 1;
declare const MIN_AUDIO_GAIN_VALUE = 0;
declare const MAX_AUDIO_GAIN_VALUE = 10;

/**
 * @example
 * ```js
 * const { getAudioOutputMixer } from '@salutejs/jazz-sdk-web-plugins';
 * const audioOutputMixer = getAudioOutputMixer(sdk);
 * const initOutputGain = audioOutputMixer.outputGain.get();
 * ```
 * @example
 * ```js
 * const { getAudioOutputMixer } from '@salutejs/jazz-sdk-web-plugins';
 * const audioOutputMixer = getAudioOutputMixer(sdk);
 * audioOutputMixer.setOutputGain(5);
 * ```
 * @example
 * ```js
 * const { getAudioOutputMixer } from '@salutejs/jazz-sdk-web-plugins';
 * const audioOutputMixer = getAudioOutputMixer(sdk);
 * const unsubscribe = handleEvent(
 *   audioOutputMixer.event$,
 *   'gainChanged',
 *   ({ payload }) => {
 *     setOutputGain(payload.value);
 *   },
 * );
 * ```
 */
declare function getAudioOutputMixer(sdk: JazzSdk): AudioOutputMixer;

type RoomAudioMixerEvent = Readonly<
  | {
      type: 'muteParticipantsChanged';
      payload: {
        isMuted: boolean;
        participantIds: JazzRoomParticipantId[];
      };
    }
  | {
      type: 'muteAllParticipantsChanged';
      payload: {
        isMuted: boolean;
      };
    }
>;
type AudioOutputMixerManager = {
  mutedParticipants: Query<ReadonlySet<JazzRoomParticipantId>>;
  isMutedAll: Query<boolean>;
  muteParticipants: (
    isMuted: boolean,
    participantIds: JazzRoomParticipantId[] | JazzRoomParticipantId,
  ) => void;
  muteAllParticipants: (isMutedAll: boolean) => void;
  event$: Observable<RoomAudioMixerEvent>;
};

/**
 * @example
 * ```js
 * const { getAudioOutputMixerManager } from '@salutejs/jazz-sdk-web-plugins'
 * const audioOutputMixerManger = getAudioOutputMixerManager(room)
 * audioOutputMixerManger.mutedParticipants.get().has(participantId)
 * ```
 * @example
 * ```js
 * const { getAudioOutputMixerManager } from '@salutejs/jazz-sdk-web-plugins'
 * const audioOutputMixerManger = getAudioOutputMixerManager(room)
 *
 * const unsubscribe = handleEvent(
 *  audioOutputMixerManger.event$,
 *  'muteParticipantsChanged',
 *  ({ payload }) => {
 *    if (payload.participantIds.some((id) => participantId === id)) {
 *      setIsMuted(payload.isMuted);
 *    }
 *  },
 * );
 * ```
 * @example
 * ```js
 * const { getAudioOutputMixerManager } from '@salutejs/jazz-sdk-web-plugins'
 * const audioOutputMixerManger = getAudioOutputMixerManager(room)
 * audioOutputMixerManger.muteParticipants(!isMuted, [participantId]);
 * ```
 */
declare function getAudioOutputMixerManager(
  room: JazzRoom,
): AudioOutputMixerManager;

declare type AllEventTypes = '*';

declare interface BaseEventBusReadonly<EVENTS extends EventLike>
  extends BaseEventBusSubscriber<EVENTS> {
  name?: string;
}

declare interface BaseEventBusSubscriber<EVENTS extends EventLike> {
  /**
   * Method for subscribing to bus events.
   * In addition to events of the type, you can also specify the * event,
   * which will allow you to subscribe to all bus events.
   * The method returns a function for unsubscribing the callback
   * (this can also be done via the off or removeEventListener methods).
   *
   * If the onSubscribe lifecycle method is passed,
   * it will be called when this event is sent.
   *
   * If the transport was destroyed, this method will do nothing.
   *
   * @example
   * ```ts
   * type Events = { event: string };
   * const eventBus = createBaseEventBus<Events>();
   *
   * const unsubscriber = eventBus.on('event', (event, payload) => console.log(payload));
   * unsubscriber();
   *
   * eventBus.send('event', 'test');
   * ```
   */
  on<EVENT extends string & keyof EVENTS>(
    event: EVENT,
    callback: (event: EVENT, payload: EVENTS[EVENT]) => void,
  ): Unsubscriber;
  /**
   * unsubscribe from an event.
   * If there are no subscribers left for the event, we remove it from the map.
   *
   * If the onUnsubscribe lifecycle callback is passed,
   * it will be called each time this function is called.
   *
   * If the transport was destroyed, the method does not work.
   *
   * @example
   * ```ts
   * type Events = { event: string };
   * const eventBus = createBaseEventBus<Events>();
   *
   * function handler(type: string, payload: string): void {}
   *
   * eventBus.on('event', handler);
   * eventBus.off('event', handler);
   * ```
   */
  off<EVENT extends string & keyof EVENTS>(
    event: EVENT,
    callback: (event: EVENT, payload: EVENTS[EVENT]) => void,
  ): void;
}

declare interface BaseTransportNodeReadonly {
  name?: string;
  __isRoot: Readonly<false>;
  /**
   * A property indicating that a class has been destroyed.
   * Once resolved, all methods in it stop working and the data is cleared.
   */
  isDestroyed: boolean;
  /**
   * Method to get the root node object referenced by the node.
   */
  getTransports: () => TransportRootNodes;
}

declare interface BaseTransportRoot extends DestroyedNode {
  name?: string;
  __isRoot: Readonly<true>;
}

declare interface DestroyedNode {
  isDestroyed: boolean;
  destroy(): void;
}

declare type EventLike = Record<string, unknown>;

declare type Namespace = string;

declare interface SubscribeNodeSubscribers<EVENTS extends EventLike> {
  on<
    EVENTS_KEYS extends keyof EVENTS,
    TYPE extends string,
    NAMESPACES extends UtilsTypeFilterTypesWithNamespaces<
      string & EVENTS_KEYS,
      TYPE
    >,
    EVENT_TYPE extends
      | `${NAMESPACES}:${AllEventTypes}`
      | AllEventTypes
      | (string & EVENTS_KEYS),
    NEW_NAMESPACE extends UtilsTypeFilterTypesWithNamespaces<EVENT_TYPE, TYPE>,
    CALLBACK_EVENTS extends EVENT_TYPE extends AllEventTypes
      ? string & EVENTS_KEYS
      : EVENT_TYPE extends `${NAMESPACES}:${AllEventTypes}`
        ? UtilsTypeRemoveNamespaceFromType<string & EVENTS_KEYS, NEW_NAMESPACE>
        : EVENT_TYPE,
    CALLBACK_PARAMS extends {
      [TYPE in CALLBACK_EVENTS]: [event: TYPE, payload: EVENTS[TYPE]];
    },
  >(
    event: EVENT_TYPE,
    callback: (...args: CALLBACK_PARAMS[CALLBACK_EVENTS]) => void,
  ): Unsubscriber;
  once<
    EVENTS_KEYS extends keyof EVENTS,
    TYPE extends string,
    NAMESPACES extends UtilsTypeFilterTypesWithNamespaces<
      string & EVENTS_KEYS,
      TYPE
    >,
    EVENT_TYPE extends
      | `${NAMESPACES}:${AllEventTypes}`
      | AllEventTypes
      | (string & EVENTS_KEYS),
    NEW_NAMESPACE extends UtilsTypeFilterTypesWithNamespaces<EVENT_TYPE, TYPE>,
    CALLBACK_EVENTS extends EVENT_TYPE extends AllEventTypes
      ? string & EVENTS_KEYS
      : EVENT_TYPE extends `${NAMESPACES}:${AllEventTypes}`
        ? UtilsTypeRemoveNamespaceFromType<string & EVENTS_KEYS, NEW_NAMESPACE>
        : EVENT_TYPE,
    CALLBACK_PARAMS extends {
      [TYPE in CALLBACK_EVENTS]: [event: TYPE, payload: EVENTS[TYPE]];
    },
  >(
    event: EVENT_TYPE,
    callback: (...args: CALLBACK_PARAMS[CALLBACK_EVENTS]) => void,
  ): Unsubscriber;
  off<
    EVENTS_KEYS extends keyof EVENTS,
    TYPE extends string,
    NAMESPACES extends UtilsTypeFilterTypesWithNamespaces<
      string & EVENTS_KEYS,
      TYPE
    >,
    EVENT_TYPE extends
      | `${NAMESPACES}:${AllEventTypes}`
      | AllEventTypes
      | (string & EVENTS_KEYS),
  >(
    type: EVENT_TYPE,
    callback: (...args: any[]) => void,
  ): void;
}

declare interface SubscribeReadonlyNode<EVENTS extends EventLike>
  extends SubscribeReadonlyNodeExtends<EVENTS> {}

declare type SubscribeReadonlyNodeExtends<EVENTS extends EventLike> =
  BaseTransportNodeReadonly & SubscribeNodeSubscribers<EVENTS>;

declare type TransportLifecycleEvents<EVENTS extends EventLike> = {
  /**
   * The transport was cleared. After that,
   * it stops functioning and all data in it is cleared.
   */
  destroy: undefined;
  /**
   * Subscribed to some event.
   * The object indicates what event was subscribed to and whether it is the first.
   */
  subscribe: {
    event: string & keyof EVENTS;
    mode: 'on' | 'once';
    subscriber: Parameters<TransportRootSubscribers<EVENTS>['on']>[1];
    subscribersCount: number;
  };
  /**
   * Unsubscribed from some event.
   * The object indicates what event was unsubscribed from and whether there are more subscribers.
   */
  unsubscribe: {
    event: string & keyof EVENTS;
    mode: 'on' | 'once';
    subscriber: Parameters<TransportRootSubscribers<EVENTS>['off']>[1];
    subscribersCount: number;
  };
};

declare interface TransportReadonlyNode<EVENTS extends EventLike>
  extends TransportReadonlyNodeBase<EVENTS> {
  lifecycle: TransportRoot<EVENTS>['lifecycle'];
}

declare type TransportReadonlyNodeBase<EVENTS extends EventLike> =
  TransportRootSubscribers<EVENTS> & BaseTransportNodeReadonly;

declare interface TransportRoot<EVENTS extends EventLike>
  extends TransportRootBase<EVENTS> {
  /**
   * Sync mode sending events
   *
   * @default false
   */
  sync?: Readonly<boolean>;
  /**
   * Method for sending an event to listeners.
   * If the transport was destroyed,
   * or no one is subscribed to this event, the method will do nothing.
   *
   * If there are subscribers to *,
   * they will listen to all events that were forwarded.
   *
   * The method works in 2 modes: synchronous and asynchronous (asynchronous mode is enabled by default).
   * To change this, you need to pass the 3rd argument.
   *
   * @example
   * ```ts
   * type Events = { event: string, event_empty: undefined };
   * const transport = createTransport<Events>();
   *
   * transport.on('event', (event, payload) => console.log(payload));
   * transport.on('event_empty', (event, payload) => console.log(payload));
   * transport.on('*', (event, payload) => console.log(payload));
   *
   * transport.send('event', 'test');
   * transport.send('event_empty');
   * transport.send('event_empty', undefined);
   * ```
   */
  send<
    TYPE extends string & keyof EVENTS,
    PARAMETERS extends EVENTS[TYPE] extends undefined
      ? (payload?: EVENTS[TYPE]) => void
      : (payload: EVENTS[TYPE]) => void,
  >(
    type: TYPE,
    ...other: Parameters<PARAMETERS>
  ): void;
  /**
   * Method for getting a node that has only subscription interfaces (on/once/off).
   * Recommended for use in public API services to hide methods
   * for direct control of transport state from the outside.
   */
  asReadonly(): TransportReadonlyNode<EVENTS>;
}

declare type TransportRootBase<EVENTS extends EventLike> =
  TransportRootSubscribers<EVENTS> &
    BaseTransportRoot & {
      /**
       * Transport lifecycle event bus. You can subscribe to 3 events:
       * 1) destroy - the transport was cleared. After that, it stops functioning and all data in it is cleared.
       * 2) subscribe - subscribed to some event. The object indicates what event was subscribed to and whether it is the first.
       * 3) unsubscribe - unsubscribed from some event. The object indicates what event was unsubscribed from and whether there are more subscribers.
       *
       * When the main transport is destroyed, the lifecycle event bus also dies.
       *
       * @example
       * ```ts
       * const transport = createTransport<Events>();
       *
       * transport.lifecycle.on('destroy', () => console.log('transport is destroy'));
       * transport.lifecycle.on('subscribe', ({ event, isFirstSubscribe }) => console.log(`subscribe to event ${event} isFirst=${isFirstSubscribe}`));
       * transport.lifecycle.on('unubscribe', ({ event, isHasSubscribers }) => console.log(`unsubscribe from event ${event} isHasSubscribers=${isHasSubscribers}`));
       *
       * const unsubscriber1 = transport.on('event1', () => {}) // subscribe to event event1 isFirst=true
       * const unsubscriber2 = transport.on('event1', () => {}) // subscribe to event event1 isFirst=false
       * const unsubscriber3 = transport.on('event2', () => {}) // subscribe to event event2 isFirst=true
       *
       * unsubscriber3() // unsubscribe from event event2 isHasSubscribers=false
       * unsubscriber2() // unsubscribe from event event1 isHasSubscribers=true
       * unsubscriber1() // unsubscribe from event event1 isHasSubscribers=false
       *
       * transport.destroy(); // transport is destroy
       * ```
       */
      lifecycle: Readonly<
        BaseEventBusReadonly<TransportLifecycleEvents<EVENTS>>
      >;
    };

declare type TransportRootNodes = Record<Namespace, Array<TransportRoot<any>>>;

declare interface TransportRootSubscribers<EVENTS extends EventLike> {
  /**
   * Method for subscribing to bus events.
   * In addition to events of the type, you can also specify the * event,
   * which will allow you to subscribe to all bus events.
   * The method returns a function for unsubscribing the callback
   * (this can also be done via the off or removeEventListener methods).
   *
   * If the onSubscribe lifecycle method is passed,
   * it will be called when this event is sent.
   *
   * If the transport was destroyed, this method will do nothing.
   *
   * @example
   * ```ts
   * type Events = { event: string };
   * const transport = createTransport<Events>();
   *
   * transport.on('event', (event, payload) => console.log(payload));
   * const unsubscriber = transport.on('*', (event, payload) => console.log(payload));
   * unsubscriber();
   *
   * transport.send('event', 'test');
   * ```
   */
  on<
    EVENT_TYPE extends string & (keyof EVENTS | AllEventTypes),
    EVENT extends EVENT_TYPE extends AllEventTypes
      ? string & keyof EVENTS
      : EVENT_TYPE,
    CB extends {
      [TYPE in EVENT]: [TYPE, EVENTS[TYPE]];
    },
  >(
    event: EVENT_TYPE,
    callback: (...args: CB[EVENT]) => void,
  ): Unsubscriber;
  /**
   * A method for one-time subscription to bus events.
   * In addition to events of the type, you can also specify an event *,
   * which will allow you to subscribe to all bus events.
   * The method returns a function for unsubscribing the callback
   * (this can also be done via the off or removeEventListener methods).
   *
   * If the onSubscribe lifecycle method is passed,
   * it will be called when this event is sent.
   *
   * If the transport was destroyed, this method will do nothing.
   *
   * @example
   * ```ts
   * type Events = { event: string };
   * const transport = createTransport<Events>();
   *
   * transport.once('event', (event, payload) => console.log(payload));
   * const unsubscriber = transport.once('*', (event, payload) => console.log(payload));
   * unsubscriber();
   *
   * transport.send('event', 'test');
   * transport.send('event', 'test'); // not call subscribers
   * ```
   */
  once<
    EVENT_TYPE extends string & (keyof EVENTS | AllEventTypes),
    EVENT extends EVENT_TYPE extends AllEventTypes
      ? string & keyof EVENTS
      : EVENT_TYPE,
    CB extends {
      [TYPE in EVENT]: [TYPE, EVENTS[TYPE]];
    },
  >(
    event: EVENT_TYPE,
    callback: (...args: CB[EVENT]) => void,
  ): Unsubscriber;
  /**
   * unsubscribe from an event.
   * If there are no subscribers left for the event, we remove it from the map.
   *
   * If the onUnsubscribe lifecycle callback is passed,
   * it will be called each time this function is called.
   *
   * If the transport was destroyed, the method does not work.
   *
   * @example
   * ```ts
   * type Events = { event: string };
   * const transport = createTransport<Events>();
   *
   * function handler(type: string, payload: string): void {}
   *
   * transport.on('event', handler);
   * transport.off('event', handler);
   * ```
   */
  off<EVENT_TYPE extends string & (keyof EVENTS | AllEventTypes)>(
    event: EVENT_TYPE,
    callback: (...args: any[]) => void,
  ): void;
}

/**
 * unsubscribe function to unsubscribe from an event.
 */
declare type Unsubscriber = () => void;

/**
 * Utility type for getting namespace from event name (max size 5 namespaces)
 *
 * @example
 *
 * UtilsTypeFilterTypesWithNamespaces<'namespace1:event', 'event'> // 'namespace1'
 * UtilsTypeFilterTypesWithNamespaces<'namespace1:namespace2:event', 'event'> // 'namespace1:namespace2'
 * UtilsTypeFilterTypesWithNamespaces<'namespace1:namespace2:namespace3:event', 'event'> // 'namespace1:namespace2:namespace3'
 */
declare type UtilsTypeFilterTypesWithNamespaces<
  STR extends string,
  TYPE extends string,
> = STR extends `${infer NAMESPACE_1}:${infer NAMESPACE_2}:${infer NAMESPACE_3}:${infer NAMESPACE_4}:${infer NAMESPACE_5}:${TYPE}`
  ? `${NAMESPACE_1}:${NAMESPACE_2}:${NAMESPACE_3}:${NAMESPACE_4}:${NAMESPACE_5}`
  : STR extends `${infer NAMESPACE_1}:${infer NAMESPACE_2}:${infer NAMESPACE_3}:${infer NAMESPACE_4}:${TYPE}`
    ? `${NAMESPACE_1}:${NAMESPACE_2}:${NAMESPACE_3}:${NAMESPACE_4}`
    : STR extends `${infer NAMESPACE_1}:${infer NAMESPACE_2}:${infer NAMESPACE_3}:${TYPE}`
      ? `${NAMESPACE_1}:${NAMESPACE_2}:${NAMESPACE_3}`
      : STR extends `${infer NAMESPACE_1}:${infer NAMESPACE_2}:${TYPE}`
        ? `${NAMESPACE_1}:${NAMESPACE_2}`
        : STR extends `${infer NAMESPACE}:${TYPE}`
          ? `${NAMESPACE}`
          : never;

/**
 * Utility type of extraction from event name type without namespace
 *
 * @example
 * UtilsTypeRemoveNamespaceFromType<'namespace:event', 'namespace'> // 'event'
 */
declare type UtilsTypeRemoveNamespaceFromType<
  NAMESPACED_TYPE extends string,
  NAMESPACE extends string,
> = NAMESPACED_TYPE extends `${NAMESPACE}:${infer TYPE}` ? TYPE : never;

type VideoElementPoolSettingsVideoSource = Exclude<MediaType, 'audio'>;
type VideoElementPoolSettingsPausedSources = {
  [key in VideoElementPoolSettingsVideoSource]?: boolean;
};
type VideoElementPoolSettingsEvents = {
  pausedAllVideoChange: {
    isPaused: boolean;
  };
  pauseVideSourcesChange: {
    pausedVideoSources: VideoElementPoolSettingsPausedSources;
  };
};
/**
 * @deprecated please use on/once/off API
 */
type VideoElementPoolSettingsEventsDeprecated =
  | {
      type: 'pausedAllVideoChange';
      payload: {
        isPaused: boolean;
      };
    }
  | {
      type: 'pauseVideSourcesChange';
      payload: {
        pausedVideoSources: VideoElementPoolSettingsPausedSources;
      };
    };
/**
 * Сервис для работы с общими настройками
 * возможности запускать видео элементы
 *
 * Применяется как глобально, так и для
 * videoElementPoolForRoom
 */
type VideoElementPoolSettingsService = {
  eventsSignal: Signal<VideoElementPoolSettingsEventsDeprecated>;
  events: TransportReadonlyNode<VideoElementPoolSettingsEvents>;
  isPausedAllVideo: Atom<boolean>;
  getIsPausedAllVideo: () => boolean;
  /**
   * Остановка или запуск видео элементов.
   */
  setPauseAllVideo: (isPaused: boolean) => void;
  pausedVideoSources: Atom<VideoElementPoolSettingsPausedSources>;
  getPausedVideoSources: () => VideoElementPoolSettingsPausedSources;
  /**
   * Остановка или запуск видео элементов нужного типа.
   * Влияет на видео элементы в videoElementPoolForRoom
   */
  playVideoSources: (
    sources:
      | VideoElementPoolSettingsVideoSource
      | VideoElementPoolSettingsVideoSource[],
  ) => void;
  pauseVideoSources: (
    sources:
      | VideoElementPoolSettingsVideoSource
      | VideoElementPoolSettingsVideoSource[],
  ) => void;
};

type VideoSizeSettings = {
  width: number;
  height: number;
};
type Source = Exclude<MediaType, 'audio'>;
type RequestVideoElement = {
  /**
   * тип используемого видео
   */
  source: Source;
  /**
   * необходимо ли следить за размером видео элемента
   * по умолчанию считается, что параметр включен
   *
   * Если параметр `true`, то если элемент виден, то
   * к нему подключается resizeObserver. Как только элемент
   * перестает быть видим - происходим отписка.
   * Каждый раз, когда меняется размер отправляется запрос
   * в плагин displayEndpoints
   *
   * Если элемент имеет статичные размеры и они точно не изменятся
   * то можно выключить это свойство для экономии ресурсов
   *
   * А также если нужно управлять размером запрашиваемого видео
   * в ручном режиме через `setUsageVideoSize`
   *
   * @default true
   */
  watchResize?: boolean;
  /**
   * игнорирование глобального занижения
   * запрашиваемого качества
   *
   * @default false
   */
  ignoreMaxVideoSize?: boolean;
};
type DisplayEndpointsEvents = {
  setMaxRequestVideoSizeAllVideos: {
    settings: VideoSizeSettings;
  };
  clearMaxRequestVideoSizeAllVideos: undefined;
};
/**
 * @deprecated please use on/once/off API
 */
type DisplayEndpointsEventsDeprecated =
  | {
      type: 'setMaxRequestVideoSizeAllVideos';
      payload: {
        settings: VideoSizeSettings;
      };
    }
  | {
      type: 'clearMaxRequestVideoSizeAllVideos';
    };
/**
 * Сервис для взаимодействия с реальными displayEndpoints
 *
 * В зону ответственности входит отслеживание видимости
 * и размеров видео элементов, а также запущены они или нет
 * и в зависимости от этих знаний дергает нужные ручки
 *
 * Элемент будет зарегистрирован в реальных displayEndpoints
 * только если он виден на странице и не стоит на паузе
 */
type DisplayEndpointsService = {
  events: TransportReadonlyNode<DisplayEndpointsEvents>;
  registerElement: (
    participantId: JazzRoomParticipantId,
    request: RequestVideoElement,
    element: HTMLVideoElement,
  ) => void;
  unregisterElement: (element: HTMLVideoElement) => void;
  /**
   * Метод для ручной активации элемента. Используется если у элемента нет стрима,
   * напр. с подписками в Next.
   */
  activateElement: (element: HTMLVideoElement) => void;
  /**
   * метод отправки в displayEndpoints plugin
   * обновленных размеров, при этом эти значения не сохраняются
   * и если передан watResize=true, то при обновление размера
   * видео элемента эти значения будут затерты
   */
  setUsageVideoSize: (
    element: HTMLVideoElement,
    settings?: VideoSizeSettings,
  ) => void;
  /**
   * жестко устанавливает размер видео (если он виден)
   * и отключает resizeObserver для этого элемента
   *
   * если передать undefined данная политика отключается
   */
  setUsageVideoSizeWithSaving: (
    element: HTMLVideoElement,
    settings: VideoSizeSettings | undefined,
  ) => void;
  maxVideoSizeAllVideos: Atom<VideoSizeSettings | undefined>;
  getMaxVideoSizeAllVideos: () => VideoSizeSettings | undefined;
  /**
   * Метод установки верхней планки всех запрашиваемых видео
   * Нужно для случаев, когда нужно ограничить качество всех видео на странице
   *
   * Для игнорирования этой настройки можно передать параметр `ignoreMaxVideoSize=true`
   * при регистрации видео элемента
   */
  setMaxVideoSizeAllVideos: (videoSize: VideoSizeSettings | undefined) => void;
  setWatchResize: (element: HTMLVideoElement, isWatch: boolean) => void;
};

type VideoElementPoolFlags = ConfigFlags<{
  /**
   * If the video in the conference could not start immediately,
   * we try to lower and raise it back.
   * This helps in cases where packet loss has occurred.
   *
   * @default true
   */
  videoLossEnabled: boolean;
  /**
   * @default 5_000 ms
   */
  videoLossTimeout: number;
  /**
   * Allow the function of stopping all video elements
   * created outside the conference for a separate video stream.
   *
   * @default false
   */
  allVideoPauseForStreamElementsEnabled: boolean;
  /**
   * When stopping all videos in videoElementPool, do not disable local video elements.
   *
   * @default true
   */
  ignoreLocalVideoForPauseAllVideoEnabled: boolean;
  /**
   * When stopping a video type in videoElementPool, do not disable the local video element.
   *
   * @default true
   */
  ignoreLocalVideoForPauseVideoSourceEnabled: boolean;
  /**
   * Allow the video of an element created using getVideoElementForStream
   * to stop if the element is out of sight
   *
   * @default true
   */
  stopElementsForStreamIfNotInteractionEnabled: boolean;
  /**
   * Delayed release of the element.
   * It is necessary that when re-rendering the application,
   * the deletion and creation of an element with all registrations does not occur.
   * If the item is "released" and requested back faster than the release occurs,
   * then it will be reused
   *
   * @default 2_000 ms
   */
  delayReleaseVideoElement: number;
  /**
   * If the video element is not visible, then an unsubscription from displayEndpoints
   * will be delayed to avoid "flashing video" during re-renders and other cases
   * when the element disappears and appears for a short time.
   *
   * If rendering occurs, then the minimum time value between
   * the flag delayReleaseVideoElement and delayStopRequestVideoIfNotInteraction is taken.
   *
   * In order for the unsubscription to occur instantly, you need to specify the value 0.
   *
   * @default 10_000 ms
   */
  delayStopRequestVideoIfNotInteraction: number;
  /**
   * If you need to track the size of the video stream.
   * The `getVideoElement` method returns the streamSize property,
   * in which once every N seconds (regulated by the `streamSizeCheckInterval` flag)
   * the value of the video stream size will be calculated and placed.
   *
   * @default false
   */
  streamSizeCheckEnabled: boolean;
  /**
   * The interval for checking the size of the video stream.
   * If you specify 0, it will be equivalent to passing the `streamSizeCheckEnabled` parameter false.
   *
   * @default 1_000 ms
   */
  streamSizeCheckInterval: number;
  /**
   * Enabling the feature of limiting the number of requested videos in high quality.
   * If a video in full HD is requested for more than the `maxQualitySubscribersLimit` flag,
   * its quality is lowered to 640x480.
   * When the queue is released, their quality is restored to the originally requested one.
   *
   * @default true
   */
  maxQualitySubscribersLimitEnabled: boolean;
  /**
   * The maximum number of videos requested in full HD quality.
   * It works when the maxQualitySubscribersLimitEnabled flag is enabled.
   * If more videos are requested, their quality is lowered to 640x480.
   *
   * @default 16
   */
  maxQualitySubscribersLimit: number;
  /**
   * the mode of operation of the plugin
   *
   * if you select `scoped`, then each room will have its own isolated version
   *
   * if `singleton` is selected, only 1 instance will be created,
   * which will be used for all rooms and all video elements will fall into it.
   * It may be useful if the plugin is used in child windows of the electron application.
   *
   * It is `recommended` to use the `scoped` mode
   * @default scoped
   */
  mode: 'scoped' | 'singleton';
}>;

type RoomVideoElementsVideoEvents = {
  /**
   * событие любого обновления стрима в комнтае
   * то есть (addTrack, removeTrack, trackMuteChange and etc.)
   *
   * потенциально есть возможность,
   * что трек будет unmute, но стрим будет пустой
   */
  trackUpdated: {
    stream: MediaStream | null | undefined;
    isMuted: boolean;
    isPaused: boolean;
  };
  /**
   * событие остановки видео элемента
   * см `videoElementPoolForRoom.setPauseAllVideo`
   * и  `videoElementPoolForRoom.playVideoSources`.
   */
  elementsPausedChanged: {
    stream: MediaStream | null | undefined;
    isMuted: boolean;
    isPaused: boolean;
  };
};
/**
 * @deprecated please use on/once/off new API
 */
type RoomVideoElementsVideoEventsDeprecated$1 =
  /**
   * событие любого обновления стрима в комнтае
   * то есть (addTrack, removeTrack, trackMuteChange and etc.)
   *
   * потенциально есть возможность,
   * что трек будет unmute, но стрим будет пустой
   */
  | {
      type: 'trackUpdated';
      payload: {
        stream: MediaStream | null | undefined;
        isMuted: boolean;
        isPaused: boolean;
      };
    }
  /**
   * событие остановки видео элемента
   * см `videoElementPoolForRoom.setPauseAllVideo`
   * и  `videoElementPoolForRoom.playVideoSources`.
   */
  | {
      type: 'elementsPausedChanged';
      payload: {
        stream: MediaStream | null | undefined;
        isMuted: boolean;
        isPaused: boolean;
      };
    };

type VideoElementPoolSettings = VideoElementPoolFlags;
type VideoElementPoolPluginOptions = Partial<VideoElementPoolSettings>;

type VideoElementPoolForRoomEvents = VideoElementPoolSettingsEvents &
  DisplayEndpointsEvents;
/**
 * @deprecated please use on/once/off new API
 */
type VideoElementPoolForRoomEventsDeprecated =
  VideoElementPoolSettingsEventsDeprecated & DisplayEndpointsEventsDeprecated;
type VideoElementPoolForRoomVideoSource = Exclude<MediaType, 'audio'>;
type VideoElementPoolForRoomVideoSizeSettings = {
  width: number;
  height: number;
};
type VideoElementPoolForRoomElementEvents = RoomVideoElementsVideoEvents;
/**
 * @deprecated use on/once/off new API
 */
type VideoElementPoolForRoomElementEventsDeprecated =
  RoomVideoElementsVideoEventsDeprecated$1;
type VideoElementPoolForRoomElement = {
  /**
   * HTMLVideoElement для встройки на страницу
   * механиками videoElementPool в него будет
   * подставляться актуальный mediaStream
   * а также он будет запускаться и останавливаться
   */
  videoElement: HTMLVideoElement;
  /**
   * замьючен ли videoSource
   */
  isMuted: Atom<boolean>;
  /**
   * стоит ли данный videoSource на паузе
   * по дефолту состояние повторяет isMuted
   *
   * но при размьюченном видео может быть false, если:
   * 1) все видео элементы стоят на паузе
   * см `setPauseAllVideo`
   * данное поведение можно игнорировать
   * с помощью настройки `ignoreAllVideoPause`
   *
   * 2) данный videoSource отключен
   * см `playVideoSources`
   * данное поведение можно игнорировать
   * с помощью настройки `ignoreSourcePause`
   */
  isPaused: Atom<boolean>;
  /**
   * mediaStream, который сейчас используется
   * для всех видео элементов
   */
  stream: Atom<MediaStream | null | undefined>;
  /**
   * размер видео стрима. Если стрима нет или видео замьючено,
   * то вычисления не происходит и значения высоты и ширины
   * равны 0
   */
  streamSize: Atom<VideoElementPoolStreamSize>;
  /**
   * videoSource. Используется в качестве атома
   * для удобства взаимодействия и сохранения
   * единого стиля данных
   */
  source: Atom<VideoElementPoolForRoomVideoSource>;
  /**
   * @deprecated use on/once/off new API
   */
  events: Signal<VideoElementPoolForRoomElementEventsDeprecated>;
  on: TransportReadonlyNode<VideoElementPoolForRoomElementEvents>['on'];
  once: TransportReadonlyNode<VideoElementPoolForRoomElementEvents>['once'];
  off: TransportReadonlyNode<VideoElementPoolForRoomElementEvents>['off'];
  /**
   * установка размера запрашиваемого видео
   * при этом происходит остановка отслеживания размера видео элемента
   *
   * для отмены этого поведения нужно передать undefined
   * или это произойдет автоматически≤ если высота или ширина будут равны 0
   */
  setVideoSize: (
    settings: VideoElementPoolForRoomVideoSizeSettings | undefined,
  ) => void;
  /**
   * динамический запуск или остановка отслеживания размера видео элемента
   * отслеживание работает только если видео элемент виден на странице
   * и он не остановлен (см свойство `isPaused`)
   */
  setIsWatchResize: (isWatch: boolean) => void;
  /**
   * не рекомендуется к использованию
   *
   * Ручной запуск видео элемента
   *
   * Метод работает только если данный videoSource
   * не стоит на паузе и все видео не стоят на паузе
   * или если есть соответсвующие настройки игнорирования
   */
  play: () => void;
  /**
   * не рекомендуется к использованию
   *
   * ручная остановка видео элемента
   */
  pause: () => void;
  release: () => void;
};
type VideoElementPoolForRoomRequestVideoElement = {
  source: VideoElementPoolForRoomVideoSource;
  /**
   * игнорирование остановки всех видео элементов
   * см `setPauseAllVideo`
   *
   * @default false
   */
  ignoreAllVideoPause?: boolean;
  /**
   * игнорирование остановки конкретного типа видео
   * см `pauseVideoSources`
   *
   * @default false
   */
  ignoreVideoSourcePause?: boolean;
  /**
   * игнорирование верхней планки запрашиваемого видео
   * см `setMaxVideoSizeAllVideos`
   *
   * @default false
   */
  ignoreMaxVideoSize?: boolean;
  /**
   * нужно ли отслеживать изменение размера видео элемента
   * Отслеживание работает только если видео элемент виден
   * и не стоит на паузе
   *
   * @default true
   */
  watchResize?: boolean;
  /**
   * HTMLVideoElement props, которые можно установить сразу
   * при инициализации видео элемента
   */
  videoElementProps?: Partial<HTMLVideoElement>;
};
/**
 * Сервис для работы с видео элементами в комнате
 */
type VideoElementPoolForRoomService = {
  /**
   * @deprecated use on/once/off new API
   */
  events: Signal<VideoElementPoolForRoomEventsDeprecated>;
  on: SubscribeReadonlyNode<VideoElementPoolForRoomEvents>['on'];
  once: SubscribeReadonlyNode<VideoElementPoolForRoomEvents>['once'];
  off: SubscribeReadonlyNode<VideoElementPoolForRoomEvents>['off'];
  isPausedAllVideo: VideoElementPoolSettingsService['isPausedAllVideo'];
  getIsPausedAllVideo: VideoElementPoolSettingsService['getIsPausedAllVideo'];
  /**
   * Остановка или запуск всех видео элементов в комнате.
   * Все видео элементы ставятся на паузу и из них выгружаются стримы
   * При обратном запуске работа видео элементов нормализуется
   *
   * Не касается элементов с настройкой `ignoreAllVideoPause`
   * Имеет более низкий приоритет над настройкой для всего videoElementPool
   * т.е. если если глобально видео остановлены, а в videoElementPoolForRoom
   * запущено, то все видео будут остановлены
   *
   * Влияет на свойство isPaused у каждого элемента
   *
   * Если стрим у видео элемента остановлен (isMute), то запуск его не коснется
   */
  setPauseAllVideo: VideoElementPoolSettingsService['setPauseAllVideo'];
  pausedVideoSources: VideoElementPoolSettingsService['pausedVideoSources'];
  getPausedVideoSources: VideoElementPoolSettingsService['getPausedVideoSources'];
  /**
   * Остановка или запуск всех видео данного videoSource в комнате.
   * Все видео элементы данного типа ставятся на паузу и из них выгружаются стримы
   * При обратном запуске работа видео элементов нормализуется
   *
   * Не касается элементов с настройкой `ignoreVideoSourcePause`
   * Имеет более низкий приоритет над настройкой для всего videoElementPool
   * т.е. если если глобально видео остановлены, а в videoElementPoolForRoom
   * запущено, то все видео будут остановлены
   *
   * Влияет на свойство isPaused у каждого элемента
   *
   * Если стрим у видео элемента остановлен (isMute), то запуск его не коснется
   */
  pauseVideoSources: VideoElementPoolSettingsService['pauseVideoSources'];
  playVideoSources: VideoElementPoolSettingsService['playVideoSources'];
  maxVideoSizeAllVideos: DisplayEndpointsService['maxVideoSizeAllVideos'];
  getMaxVideoSizeAllVideos: DisplayEndpointsService['getMaxVideoSizeAllVideos'];
  /**
   * Метод установки верхней планки всех запрашиваемых видео
   * Нужно для случаев, когда нужно ограничить качество всех видео в комнате
   *
   * Для игнорирования этой настройки можно передать параметр `ignoreMaxVideoSize`
   * при получение видео элемента
   */
  setMaxVideoSizeAllVideos: DisplayEndpointsService['setMaxVideoSizeAllVideos'];
  /**
   * метод получения видео элемента в videoElementPool
   * со всеми методами взаимодействия и отслеживания его состояния
   *
   * Для конфигурации поведения используйте настройки плагина
   */
  getVideoElement: (
    participantId: JazzRoomParticipantId,
    request: VideoElementPoolForRoomRequestVideoElement,
  ) => VideoElementPoolForRoomElement;
  /**
   * release all elements
   * not recommended
   */
  release: () => void;
};

type VideoElementPoolGlobalEvents = VideoElementPoolSettingsEvents;
/**
 * @deprecated use on/once/off API
 */
type VideoElementPoolGlobalEventsDeprecated =
  VideoElementPoolSettingsEventsDeprecated;
type VideoElementPoolGlobalElementEvents = {
  pausedChange: {
    isPaused: boolean;
  };
  /**
   * стрим загружен в видео элемент
   * и готов для отображения на странице
   */
  isLoadingStreamChange: {
    isLoading: boolean;
  };
  streamUpdate: {
    stream: MediaStream | null | undefined;
  };
};
/**
 * @deprecated use on/once/off new API
 */
type VideoElementPoolGlobalElementEventsDeprecated =
  | {
      type: 'pausedChange';
      payload: {
        isPaused: boolean;
      };
    }
  | {
      type: 'isLoadingStreamChange';
      payload: {
        isLoading: boolean;
      };
    }
  | {
      type: 'streamUpdate';
      payload: {
        stream: MediaStream | null | undefined;
      };
    };
type VideoElementPoolStreamSize = {
  width: number;
  height: number;
};
type VideoElementPoolGlobalElementForStream = {
  videoElement: HTMLVideoElement;
  /**
   * Находится ли элемент на паузе.
   * Элемент может быть приостановлен, если:
   * 1) stream с активным MediaStreamTrack не установлен
   * 2) Элемент не отображается, если включена настройка `stopElementsForStreamIfNotInteractionEnabled`.
   * 3) Все видеоролики остановлены (см метод `changePauseAllVideo`)
   * и включена настройка `allVideoPauseForStreamElementsEnabled`.
   */
  isPaused: Atom<boolean>;
  /**
   * Зависит от того, загружен ли поток в элемент video.
   * Когда значение свойства становится равным true, элемент будет готов к отображению видео.
   *
   * При обновление стрима в элементе значение сбрасывается и по новой ждет,
   * когда произойдет загрузка
   */
  isLoadedStream: Atom<boolean>;
  /**
   * mediaStream, который сейчас используется
   * для всех видео элементов
   */
  stream: Atom<MediaStream | null | undefined>;
  /**
   * размер видео стрима. Если стрима нет или видео замьючено,
   * то вычисления не происходит и значения высоты и ширины
   * равны 0
   */
  streamSize: Atom<VideoElementPoolStreamSize>;
  /**
   * @deprecated use on/once/off new API
   */
  events: Signal<VideoElementPoolGlobalElementEventsDeprecated>;
  on: TransportReadonlyNode<VideoElementPoolGlobalElementEvents>['on'];
  once: TransportReadonlyNode<VideoElementPoolGlobalElementEvents>['once'];
  off: TransportReadonlyNode<VideoElementPoolGlobalElementEvents>['off'];
  /**
   * метод для обновления MediaStream в элементе
   */
  setStream: (stream: MediaStream | null | undefined) => void;
  /**
   * метод для ручного запуска видео элемента
   * не запуститься, если это запрещено политиками (см свойство isPaused)
   */
  play: () => void;
  /**
   * метод для ручной остановки видео элемента
   */
  pause: () => void;
  /**
   * метод для высвобождения видео элемента
   * и выполнения отписки всех методов
   *
   * Если видео элемент больше не нужен, то обязателен к выполнению
   */
  release: () => Promise<void>;
};
type VideoElementPoolGlobalSettings = {
  stream?: MediaStream | null | undefined;
  videoElementProps?: Partial<HTMLVideoElement>;
  /**
   * необходимо ли вычислять размер видео стрима
   * Будет работать, если:
   * 1) фича включена (флаг streamSizeCheckEnabled)
   * 2) видео элемент виден
   * 3) есть видео стрим с живым видео треком
   * 4) видео элемент не стоит на паузе
   *
   * @default false
   */
  watchStreamSize?: boolean;
  /**
   * необходимо ли отслеживать, что элемент виден на странице
   *
   * @default VideoElementPoolSettings['stopElementsForStreamIfNotInteractionEnabled']
   */
  watchIsVisible?: boolean;
};
/**
 * Сервис для работы с видео элементами вне конференций
 */
type VideoElementPoolGlobalService = {
  /**
   * @deprecated please use on/once/off API
   */
  events: Signal<VideoElementPoolGlobalEventsDeprecated>;
  on: TransportReadonlyNode<VideoElementPoolGlobalEvents>['on'];
  once: TransportReadonlyNode<VideoElementPoolGlobalEvents>['once'];
  off: TransportReadonlyNode<VideoElementPoolGlobalEvents>['off'];
  isPausedAllVideo: VideoElementPoolSettingsService['isPausedAllVideo'];
  getIsPausedAllVideo: VideoElementPoolSettingsService['getIsPausedAllVideo'];
  /**
   * Остановка или запуск всех видео элементов в приложение.
   * Распространяется на все videoElementPoolForRoom.
   * Все видео элементы ставятся на паузу и из них выгружаются стримы
   * При обратном запуске работа видео элементов нормализуется
   *
   * Имеет более высокий приоритет над настройкой для всех videoElementPoolForRoom
   * т.е. если если глобально видео остановлены, а в videoElementPoolForRoom
   * запущено, то все видео будут остановлены
   *
   * Влияет на свойство isPaused у каждого элемента
   */
  setPauseAllVideo: VideoElementPoolSettingsService['setPauseAllVideo'];
  pausedVideoSources: VideoElementPoolSettingsService['pausedVideoSources'];
  getPausedVideoSources: VideoElementPoolSettingsService['getPausedVideoSources'];
  /**
   * Остановка или запуск всех видео данного videoSource в приложение.
   * Распространяется на все videoElementPoolForRoom.
   * Все видео элементы данного типа ставятся на паузу и из них выгружаются стримы
   * При обратном запуске работа видео элементов нормализуется
   *
   * Имеет более высокий приоритет над настройкой для всех videoElementPoolForRoom
   * т.е. если если глобально видео остановлены, а в videoElementPoolForRoom
   * запущено, то все видео будут остановлены
   *
   * Влияет на свойство isPaused у каждого элемента
   */
  playVideoSources: VideoElementPoolSettingsService['playVideoSources'];
  pauseVideoSources: VideoElementPoolSettingsService['pauseVideoSources'];
  /**
   * Метод получения видео элемента для ручного подставления в него стрима
   * и отслеживания его состояния
   */
  getVideoElementForStream: (
    settings?: VideoElementPoolGlobalSettings,
  ) => VideoElementPoolGlobalElementForStream;
  /**
   * Способ получения VideoElementPool для конкретной комнаты.
   * VideoElementPoolForRoom комнаты содержит все необходимые методы для создания видео элементов,
   * связанных с комнатой, а также для управления ими.
   * Вы также можете получить его с помощью helper `getVideoElementPoolForRoom`
   */
  getVideoElementPoolForRoom: (
    room: JazzRoom,
  ) => VideoElementPoolForRoomService;
};

/** @deprecated use new API */
type VideoElementPoolManagerDeprecated = {
  getVideoElementPool: (room: JazzRoom) => VideoElementPoolForRoomDeprecated;
  releaseVideoElementPool: (room: JazzRoom) => void;
};
/** @deprecated use new API */
type PausedMediaTypesDeprecated = {
  [key in MediaType]?: boolean;
};
/** @deprecated use new API */
type VideoElementPoolEventDeprecated = Readonly<{
  type: 'mediaPaused';
  payload: PausedMediaTypesDeprecated;
}>;
/** @deprecated use new API */
type RoomVideoElementsVideoEventsDeprecated =
  | {
      type: 'trackUpdated';
      payload: {
        stream: MediaStream | null | undefined;
        isMuted: boolean;
        isPaused: boolean;
      };
    }
  | {
      type: 'elementsPausedChanged';
      payload: {
        stream: MediaStream | null | undefined;
        isMuted: boolean;
        isPaused: boolean;
      };
    };
/** @deprecated use new API */
type ElementDeprecated = {
  videoElement: HTMLVideoElement;
  isMuted: Query<boolean>;
  isPaused: Query<boolean>;
  stream: Query<MediaStream | null | undefined>;
  event$: Observable<RoomVideoElementsVideoEventsDeprecated>;
  releaseElement: () => void;
};
/** @deprecated use new API */
type VideoElementPoolForRoomDeprecated = {
  event$: Observable<VideoElementPoolEventDeprecated>;
  /**
   * A method for obtaining a video element with substituting a stream of the participant's video stream into it.
   * If there is a free element in the pool, the element will not be re-created.
   */
  getElement: (
    participantId: JazzRoomParticipantId,
    request: JazzRoomVideoRequest,
  ) => ElementDeprecated;
  /**
   * Release all elements in videoPool
   */
  release: () => void;
  /**
   * The method of updating the video stream quality used.
   */
  setQuality: (
    element: HTMLVideoElement,
    quality: JazzRoomVideoQuality,
  ) => void;
  getPausedMediaTypes: () => PausedMediaTypesDeprecated;
  /**
   * The method play all video elements of this type.
   */
  playSource: (source?: JazzRoomVideoSource) => void;
  /**
   * The method pauses all video elements of this type.
   * If a new video element of the type appears, it will also not be launched
   */
  pauseSource: (source?: JazzRoomVideoSource) => void;
};

/**
 * пару ручек для приведения новых форматов данных
 * в старые интерфейсы
 */
declare const atomToRxEffectsQuery: typeof toQuery;
declare const signalToRxEffectsAction: typeof toAction;
declare const atomToRxObserve: typeof observe;
declare const signalToRxObserve: typeof observe;
type Unsubscribe = () => void;
declare function subscribeAtom<T>(
  source: Atom<T>,
  callback: (payload: T) => void,
): Unsubscribe;

declare function getAppVideoElementPool(
  sdk: JazzSdk,
): VideoElementPoolGlobalService;
/**
 * @deprecated use getAppVideoElementPool and getVideoElementPoolForRoom with new API
 */
declare function getVideoElementPoolManager(): VideoElementPoolManagerDeprecated;

declare function getVideoElementPoolForRoom(
  room: JazzRoom,
): VideoElementPoolForRoomService;
/**
 * @deprecated use getVideoElementPoolForRoom with new API
 */
declare function getVideoElementPool(
  room: JazzRoom,
): VideoElementPoolForRoomDeprecated;

/**
 * It allows you to integrate videos into the page through the video element,
 * as well as track the status of tracks.
 */
declare function videoElementPoolPlugin(
  options?: VideoElementPoolPluginOptions,
): JazzSdkPlugin;

type MediaMetricsFlags = ConfigFlags<{
  /**
   * The interval for collecting statistics.
   * Statistics are collected exclusively during the conference.
   *
   * @default 5_000 ms
   */
  interval: number;
  /**
   * Automatic start of statistics collection at the entrance to the conference.
   * If the flag is enabled, statistics are collected once
   * in a while (changed by the interval setting).
   *
   * If the setting is disabled,
   * the start and stop of statistics collection can be controlled using
   * the startCollectMetrics and stopCollectMetrics methods,
   * or to collect statistics by calling the collectClientMetrics method.
   *
   * @default true
   */
  autoStartCollectMetricsEnabled: boolean;
}>;

type MediaMetricsPluginSettings = MediaMetricsFlags;
type MediaMetricsPluginOptions = Partial<MediaMetricsPluginSettings>;

/**
 * Plugin for getting media statistics
 */
declare function mediaMetricsPlugin(
  options?: MediaMetricsPluginOptions,
): JazzSdkPlugin;

type RtcParticipantSid = string;
type ConnectionQualityName = 'EXCELLENT' | 'GOOD' | 'POOR' | 'LOST';
type ConnectionQualityUpdate = {
  participantSid: RtcParticipantSid;
  quality: ConnectionQualityName;
  score: number;
};
type ConnectionQuality = {
  quality: ConnectionQualityUpdate['quality'];
  score: ConnectionQualityUpdate['score'];
};
type ConnectionStatus = 'active' | 'inactive' | 'interrupted' | 'restoring';
/**
 * @deprecated use on/once/off new API
 */
type ConnectionQualityEventsDeprecated =
  | {
      type: 'connectionQualityUpdate';
      payload: ConnectionQualityEvents['connectionQualityUpdate'];
    }
  | {
      type: 'connectionStatusUpdate';
      payload: ConnectionQualityEvents['connectionStatusUpdate'];
    };
type ConnectionQualityEvents = {
  connectionQualityUpdate: {
    participantId: JazzRoomParticipantId;
    quality: ConnectionQualityUpdate['quality'];
    score: ConnectionQualityUpdate['score'];
  };
  connectionStatusUpdate: {
    participantId: JazzRoomParticipantId;
    status: ConnectionStatus;
  };
};
type ConnectionQualities = Map<JazzRoomParticipantId, ConnectionQuality>;
/**
 * A service for tracking the connection status of users in a conference.
 */
type ConnectionQualityService = {
  /**
   * @deprecated use on/once/off new API
   */
  events: Signal<ConnectionQualityEventsDeprecated>;
  on: TransportRoot<ConnectionQualityEvents>['on'];
  once: TransportRoot<ConnectionQualityEvents>['once'];
  off: TransportRoot<ConnectionQualityEvents>['off'];
  connectionQualities: Atom<ConnectionQualities>;
  getConnectionQuality: (
    participantId: JazzRoomParticipantId,
  ) => Atom<ConnectionQuality>;
};

type RTCCommonPeerConnectionStatsReading = {
  peerConnection?: RTCPeerConnectionStats;
  mediaPlayout?: RTCAudioPlayoutStats;
  dataChannels?: Record<RTCDataChannelStats['id'], RTCDataChannelStats>;
  /** after start media channel */
  certificates?: Record<RTCCertificateStats['id'], RTCCertificateStats>;
  localCandidates?: Record<
    RTCIceLocalCandidateStats['id'],
    RTCIceLocalCandidateStats
  >;
  remoteCandidates?: Record<
    RTCIceRemoteCandidateStats['id'],
    RTCIceRemoteCandidateStats
  >;
  codecs?: Record<RTCCodecStats['id'], RTCCodecStats>;
  candidatePairsSucceededId?: RTCIceCandidatePairStats['id'];
  candidatePairs?: Record<
    RTCIceCandidatePairStats['id'],
    RTCIceCandidatePairStats
  >;
  transport?: RTCTransportStats;
};
type RTCCommonStats = {
  /**
   * A string that uniquely identifies the object that
   * is being monitored to produce this set of statistics
   */
  id: string;
  /**
   * A DOMHighResTimeStamp object indicating the time at which the
   * sample was taken for this statistics object.
   */
  timestamp: number;
  /**
   * A string indicating the type of statistics that the object contains.
   */
  type: string;
};
/**
 * Statistics describing the state of the RTCPeerConnection.
 */
type RTCPeerConnectionStats = RTCCommonStats & {
  type: 'peer-connection';
  /**
   * A positive integer value indicating the number of unique RTCDataChannel objects
   * that have entered the open state during their lifetime.
   */
  dataChannelsOpened: number;
  /**
   * A positive integer value indicating the number of unique RTCDataChannel objects
   * that have left the open state during their lifetime
   * (channels that transition to closing or closed without ever being open are not counted in this number).
   * A channel will leave the open state if either end of the connection or the underlying transport is closed.
   */
  dataChannelsClosed: number;
};
/**
 * Statistics related to audio playout. It is accessed by the RTCAudioPlayoutStats.
 *
 * not supported in Safari and Firefox
 */
type RTCAudioPlayoutStats = RTCCommonStats & {
  type: 'media-playout';
  /**
   * For audio playout, this has the value "audio".
   * This reflects the kind attribute MediaStreamTrack(s) being played out.
   */
  kind: MediaStreamTrack['kind'];
  /**
   * If the playout path is unable to produce audio samples on time for device playout,
   * samples are synthesized to be playout out instead.
   * synthesizedSamplesDuration is measured in seconds and is incremented each time
   * an audio sample is synthesized by this playout path. This metric can be used together
   * with total Samples Duration to calculate the percentage of played out media being synthesized.
   *
   * Synthesization typically only happens if the pipeline is underperforming.
   * Samples synthesized by the RTCInboundRtpStreamStats are not counted for here,
   * but in RTCInboundRtpStreamStats.concealedSamples.
   */
  synthesizedSamplesDuration: number;
  /**
   * The number of synthesized samples events.
   * This counter increases every time a sample is synthesized after a non-synthesized sample.
   * That is, multiple consecutive synthesized samples will increase synthesizedSamplesDuration
   * multiple times but is a single synthesization samples event.
   */
  synthesizedSamplesEvents: number;
  /**
   * The total duration, in seconds, of all audio samples that have been playout.
   * Includes both synthesized and non-synthesized samples.
   */
  totalSamplesDuration: number;
  /**
   * When audio samples are pulled by the playout device,
   * this counter is incremented with the estimated delay of the playout path for that audio sample.
   * The playout delay includes the delay from being emitted to the actual time of playout on the device.
   * This metric can be used together with totalSamplesCount
   * to calculate the average playout delay per sample.
   */
  totalPlayoutDelay: number;
  /**
   * When audio samples are pulled by the playout device,
   * this counter is incremented with the number of samples emitted for playout.
   */
  totalSamplesCount: number;
};
/**
 * Statistics about a certificate being used by an RTCIceTransport.
 *
 * not Supported in Firefox
 */
type RTCCertificateStats = RTCCommonStats & {
  type: 'certificate';
  /**
   * A string containing the base-64 representation of the DER-encoded certificate.
   */
  base64Certificate: string;
  /**
   * A string containing the certificate fingerprint,
   * which is calculated using the hash function specified in fingerprintAlgorithm.
   */
  fingerprint: string;
  /**
   * A string containing the hash function used to compute the certificate fingerprint, such as "sha-256".
   */
  fingerprintAlgorithm: string;
  /**
   * The issuerCertificateId refers to the stats object that contains the next certificate in the certificate chain.
   * If the current certificate is at the end of the chain (i.e. a self-signed certificate), this will not be set
   */
  issuerCertificateId?: string;
};
/**
 * Statistics about a local ICE candidate associated with the connection's RTCIceTransports.
 */
type RTCIceLocalCandidateStats = RTCIceCandidateStats & {
  type: 'local-candidate';
  /**
   * not-documentation
   */
  networkType: string;
};
/**
 * Statistics about a remote ICE candidate associated with the connection's RTCIceTransports.
 */
type RTCIceRemoteCandidateStats = RTCIceCandidateStats & {
  type: 'remote-candidate';
  /**
   * The ICE rel-addr defined in [RFC5245] section 15.1.
   * Only set for serverreflexive, peerreflexive and relay candidates.
   */
  relatedAddress?: RTCIceCandidate['relatedAddress'];
  /**
   * The ICE rel-addr defined in [RFC5245] section 15.1.
   * Only set for serverreflexive, peerreflexive and relay candidates.
   */
  relatedPort?: RTCIceCandidate['relatedPort'];
};
/**
 * Statistics about a remote ICE candidate associated with the connection's RTCIceTransports.
 */
type RTCIceCandidateStats = RTCCommonStats & {
  /**
   * It is a unique identifier that is associated to the object that
   * was inspected to produce the RTCTransportStats associated with this candidate.
   */
  transportId: RTCTransportStats['id'];
  /**
   * A string containing the address of the candidate.
   * This value may be an IPv4 address, an IPv6 address,
   * or a fully-qualified domain name. This property was
   * previously named ip and only accepted IP addresses.
   *
   * not supported in Safari
   */
  address?: RTCIceCandidate['address'];
  /**
   * A string containing the address of the candidate.
   * This value may be an IPv4 address, an IPv6 address,
   * or a fully-qualified domain name. This property was
   * previously named ip and only accepted IP addresses.
   *
   * not supported in Safari
   */
  ip?: RTCIceCandidate['address'];
  /**
   * A string matching one of the values in RTCIceCandidate.type,
   * indicating what kind of candidate the object provides statistics for.
   */
  candidateType: RTCIceCandidate['type'];
  /**
   * A Boolean value indicating whether or not the candidate has been released or deleted;
   * the default value is false. For local candidates,
   * its value is true if the candidate has been deleted or released.
   * For host candidates, true means that any network resources (usually a network socket)
   * associated with the candidate have already been released.
   * For TURN candidates, the TURN allocation is no longer active for deleted candidates.
   * This property is not present for remote candidates
   */
  deleted?: boolean;
  /**
   * The network port number used by the candidate.
   */
  port?: RTCIceCandidate['port'];
  /**
   * The candidate's priority, corresponding to RTCIceCandidate.priority.
   */
  priority?: RTCIceCandidate['priority'];
  /**
   * A string specifying the protocol (tcp or udp) used to transmit data on the port.
   */
  protocol?: RTCIceCandidate['protocol'];
  /**
   * A string identifying the protocol used by the endpoint for communicating with the TURN server;
   * valid values are tcp, udp, and tls. Only present for local candidates.
   */
  relayProtocol?: RTCIceCandidate['protocol'] | 'tls';
  /**
   * For local candidates, the url property is the URL of the ICE server
   * from which the candidate was received. This URL matches the one included
   * in the RTCPeerConnectionIceEvent object representing the icecandidate event
   * that delivered the candidate to the local peer.
   */
  url?: string;
  /**
   * (experimental) The ICE foundation as defined in [RFC5245] section 15.1
   *
   * not supported in Firefox and Safari
   */
  foundation?: RTCIceCandidate['foundation'];
  /**
   * The ICE username fragment as defined in [RFC5245] section 7.1.2.3.
   *
   * Not supported in Safari and Firefox
   */
  usernameFragment?: RTCIceCandidate['usernameFragment'];
  /**
   * The ICE candidate TCP type, as defined іn RTCIceTcpCandidateType and used in RTCIceCandidate.
   */
  tcpType: RTCIceCandidate['tcpType'];
  /**
   * not-documentation API
   */
  isRemote?: boolean;
};
type RTCIceCandidatePairStats = RTCCommonStats & {
  type: 'candidate-pair';
  /**
   * A number representing the available inbound capacity of the network.
   * This reports the total number of bits per second available for all of the candidate pair's incoming RTP streams.
   * It does not take into account the size of the Internet Protocol (IP) overhead,
   * nor any other transport layers such as TCP or UDP.
   */
  availableIncomingBitrate?: number;
  /**
   * A number representing the approximate available outbound capacity of the network.
   * This reports the total number of bits per second available for all of the candidate pair's outgoing RTP streams.
   * It does not take into account the size of the IP overhead, nor any other transport layers such as TCP or UDP.
   *
   * not supported Firefox and Safari
   */
  availableOutgoingBitrate?: number;
  /**
   * An integer representing the total number of bytes discarded due to socket errors on this candidate pair.
   *
   * Experimental
   *
   * not supported Firefox and Safari
   */
  bytesDiscardedOnSend?: number;
  /**
   * An integer representing the total number of payload bytes received on this candidate pair.
   */
  bytesReceived?: number;
  /**
   * An integer representing the total number of payload bytes sent on this candidate pair
   * (the total number of bytes sent excluding any headers, padding, or other protocol overhead).
   */
  bytesSent?: number;
  /**
   * An integer representing the total number of STUN consent requests sent on this candidate pair.
   *
   * Experimental
   *
   * not supported Firefox and Safari
   */
  consentRequestsSent?: number;
  /**
   * A number representing the total time, in seconds,
   * that elapsed between the most recently-sent STUN request and the response being received.
   * This may be based upon requests that were involved in confirming permission to open the connection.
   *
   * not supported Firefox and Safari
   */
  currentRoundTripTime?: number;
  /**
   * A DOMHighResTimeStamp value indicating the time at which
   * the last packet was received by the local peer from the remote peer for this candidate pair.
   * Timestamps are not recorded for STUN packets.
   *
   * not supported Safari
   */
  lastPacketReceivedTimestamp?: number;
  /**
   * A DOMHighResTimeStamp value indicating the time at which
   * the last packet was sent from the local peer to the remote peer for this candidate pair.
   * Timestamps are not recorded for STUN packets.
   *
   * not supported Safari
   */
  lastPacketSentTimestamp?: number;
  /**
   * A string representing the unique ID corresponding to the RTCIceCandidate
   * from the data included in the RTCIceCandidateStats object providing statistics
   * for the candidate pair's local candidate.
   */
  localCandidateId?: RTCIceCandidateStats['id'];
  /**
   * A string containing a unique ID corresponding to the remote candidate from
   * which data was taken to construct the RTCIceCandidateStats object describing
   * the remote end of the connection.
   */
  remoteCandidateId?: RTCIceCandidateStats['id'];
  /**
   * A Boolean value which, if true, indicates that the candidate pair described
   * by this object is one which has been proposed for use, and will be (or was)
   * used if its priority is the highest among the nominated candidate pairs.
   * See RFC 5245, section 7.1.3.2.4 for details.
   */
  nominated?: boolean;
  /**
   * An integer representing the total number of packets discarded due
   * to socket errors on this candidate pair.
   *
   * Experimental
   *
   * not supported Firefox and Safari
   */
  packetsDiscardedOnSend?: number;
  /**
   * An integer representing the total number of packets received on this candidate pair.
   *
   * Experimental
   *
   * not supported Firefox and Safari
   */
  packetsReceived?: number;
  /**
   * An integer representing the total number of packets sent on this candidate pair.
   *
   * Experimental
   *
   * not supported Firefox and Safari
   */
  packetsSent?: number;
  /**
   * An integer representing the total number of connectivity
   * check requests that have been received, including retransmissions.
   * This value includes both connectivity checks and STUN consent checks.
   *
   * not supported Firefox
   */
  requestsReceived?: number;
  /**
   * An integer representing the total number of connectivity
   * check requests that have been sent, not including retransmissions.
   *
   * not supported Firefox
   */
  requestsSent?: number;
  /**
   * An integer representing the total number of connectivity check responses that have been received.
   *
   * not supported Firefox
   */
  responsesReceived?: number;
  /**
   * An integer representing the total number of connectivity check responses that have been sent.
   * This includes both connectivity check requests and STUN consent requests.
   */
  responsesSent?: number;
  /**
   * A string which indicates the state of the connection between the two candidates.
   *
   * https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidatePairStats/state
   */
  state?:
    | 'failed'
    /**
     * No check has been performed yet for this candidate pair,
     * and performing the check is blocked until another check is successful.
     * Once that check has succeeded, this pair will unfreeze and move into the waiting state.
     */
    | 'frozen'
    /**
     * A check has been initiated for this pair,
     * but the check's transaction is still in progress.
     */
    | 'in-progress'
    /**
     * A check for this pair has been completed successfully.
     */
    | 'succeeded'
    /**
     * This pair has not yet been checked,
     * but the check can be performed as soon as this pair is the highest priority pair
     * remaining in the waiting state.
     */
    | 'waiting';
  /**
   * A number indicating the total time, in seconds, that has elapsed
   * between sending STUN requests and receiving responses to them,
   * for all such requests made to date on this candidate pair.
   * This includes both connectivity check and consent check requests.
   * You can compute the average round trip time (RTT) by dividing this value by responsesReceived.
   *
   * not supported Firefox
   */
  totalRoundTripTime?: number;
  /**
   * A string that uniquely identifies the RTCIceTransport that was inspected
   * to obtain the transport-related statistics (as found in RTCTransportStats)
   * used in generating this object.
   */
  transportId?: RTCTransportStats['id'];
  /**
   * An integer value indicating the candidate pair's priority.
   * @deprecated
   *
   * not supported Safari
   */
  priority?: number;
  /**
   * A Boolean value indicating whether or not data
   * can be sent over the connection described by the candidate pair.
   *
   * @deprecated
   */
  readable?: boolean;
  /**
   * A Boolean value indicating whether or not data can be received
   * on the connection described by the candidate pair.
   *
   * @deprecated
   */
  writable?: boolean;
};
/**
 * Statistics about a transport used by the connection.
 *
 * Not supported in Firefox
 */
type RTCTransportStats = RTCCommonStats & {
  type: 'transport';
  /**
   * The total number of payload bytes received on this transport
   * (bytes received, not including headers, padding or ICE connectivity checks).
   *
   * Not supported in Firefox
   */
  bytesReceived?: number;
  /**
   * The total number of payload bytes sent on this transport
   * (bytes sent, not including headers, padding or ICE connectivity checks).
   *
   * Not supported in Firefox
   */
  bytesSent?: number;
  /**
   * A string indicating the name of the cipher suite used for the DTLS transport,
   * as defined in the "Description" column of the TLS Cipher Suites section in the IANA cipher suite registry.
   * For example "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256".
   *
   * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
   *
   * Not supported in Firefox
   */
  dtlsCipher?: string;
  /**
   * The DTLS role of the associated RTCPeerConnection.
   *
   * Experimental
   *
   * Not supported in Firefox and Safari
   */
  dtlsRole?:
    | 'client'
    | 'server'
    /**
     * before the DTLS negotiation starts
     */
    | 'unknown';
  /**
   * The state read-only property of the RTCDtlsTransport interface provides
   * information which describes a Datagram Transport Layer Security (DTLS) transport state.
   *
   * Not supported in Firefox
   */
  dtlsState?:
    | 'new'
    /**
     * DTLS is in the process of negotiating a secure connection and verifying the remote fingerprint.
     */
    | 'connecting'
    /**
     * DTLS has completed negotiation of a secure connection and verified the remote fingerprint.
     */
    | 'connected'
    /**
     * The transport has been closed intentionally as the result of receipt
     * of a close_notify alert, or calling RTCPeerConnection.close().
     */
    | 'closed'
    /**
     * The transport has failed as the result of an error
     * (such as receipt of an error alert or failure to validate the remote fingerprint).
     */
    | 'failed';
  /**
   * A string indicating the local username fragment used in message validation procedures for this transport.
   * This is the same value as the local RTCIceCandidate.usernameFragment,
   * and will change if the connection is renegotiated.
   *
   * Experimental
   *
   * Not supported in Firefox and Safari
   */
  iceLocalUsernameFragment?: RTCIceCandidate['usernameFragment'];
  /**
   * The role read-only property of the RTCIceTransport interface indicates
   * which ICE role the transport is fulfilling: that of the controlling agent,
   * or the agent that is being controlled.
   *
   * Experimental
   *
   * Not supported in Firefox and Safari
   */
  iceRole?:
    | 'controlled'
    /**
     * The RTCIceTransport object is serving as the controlling agent.
     */
    | 'controlling'
    /**
     * The role has not yet been determined.
     */
    | 'unknown';
  /**
   * The state read-only property of the RTCIceTransport interface returns the current state of the ICE transport,
   * so you can determine the state of ICE gathering in which the ICE agent currently is operating.
   *
   * Experimental
   *
   * Not supported in Firefox and Safari
   */
  iceState?:
    | 'new'
    /**
     * At least one remote candidate has been received,
     * and the RTCIceTransport has begun examining pairings of remote and local candidates
     * in order to attempt to identify viable pairs that could be used to establish a connection.
     * Keep in mind that gathering of local candidates may still be underway, and, similarly,
     * the remote device also may still be gathering candidates of its own.
     */
    | 'checking'
    /**
     * A viable candidate pair has been found and selected,
     * and the RTCIceTransport has connected the two peers together using that pair.
     * However, there are still candidates pairings to consider, and there may still
     * be gathering underway on one or both of the two devices.
     *
     * The transport may revert from the "connected" state to the "checking" state
     * if either peer decides to cancel consent to use the selected candidate pair,
     * and may revert to "disconnected" if there are no candidates left to check
     * but one or both clients are still gathering candidates.
     */
    | 'connected'
    /**
     * The transport has finished gathering local candidates and has received a notification
     * from the remote peer that no more candidates will be sent.
     * In addition, all candidate pairs have been considered
     * and a pair has been selected for use. If consent checks fail
     * on all successful candidate pairs, the transport state will change to "failed".
     */
    | 'completed'
    /**
     * The ICE agent has determined that connectivity has been lost for this RTCIceTransport.
     * This is not a failure state (that's "failed").
     * A value of "disconnected" means that a transient issue has occurred
     * that has broken the connection, but that should resolve itself automatically
     * without your code having to take any action. See The disconnected state for additional details.
     */
    | 'disconnected'
    /**
     * The RTCIceTransport has finished the gathering process,
     * has received the "no more candidates" notification from the remote peer,
     * and has finished checking pairs of candidates,
     * without successfully finding a pair that is both valid and for which consent can be obtained.
     * This is a terminal state, indicating that the connection cannot be achieved or maintained.
     */
    | 'failed'
    /**
     * The transport has shut down and is no longer responding to STUN requests.
     */
    | 'closed';
  /**
   * A string containing the unique identifier for the object
   * that was inspected to produce the RTCIceCandidatePairStats associated with this transport.
   *
   * Not supported in Firefox
   */
  selectedCandidatePairId?: RTCIceCandidatePairStats['id'];
  /**
   * A string containing the id of the local certificate used by this transport.
   * Only present for DTLS transports, and after DTLS has been negotiated.
   *
   * Not supported in Firefox
   */
  localCertificateId?: RTCCertificateStats['id'];
  /**
   * The total number of packets sent over this transport.
   *
   * Experimental
   *
   * Not supported in Firefox and Safari
   */
  packetsSent?: number;
  /**
   * The total number of packets received on this transport.
   *
   * Experimental
   *
   * Not supported in Firefox and Safari
   */
  packetsReceived?: number;
  /**
   * A string containing the id or the remote certificate used by this transport.
   * Only present for DTLS transports, and after DTLS has been negotiated.
   *
   * Not supported in Firefox
   */
  remoteCertificateId?: RTCCertificateStats['id'];
  /**
   * The number of times that the selected candidate pair of this transport has changed.
   * The value is initially zero and increases whenever a candidate pair selected or lost.
   *
   * Not supported in Firefox and Safari
   */
  selectedCandidatePairChanges?: number;
  /**
   * A string indicating the descriptive name of the protection profile used
   * for the Secure Real-time Transport Protocol (SRTP) transport,
   * as defined in the "Profile" column of the IANA DTLS-SRTP protection profile registry and RFC5764.
   *
   * https://www.iana.org/assignments/srtp-protection/srtp-protection.xhtml#srtp-protection-1
   * https://www.rfc-editor.org/rfc/rfc5764.html#section-4.1.2
   *
   * For example "AES_CM_128_HMAC_SHA1_80" specifies the following profile,
   * where maximum_lifetime is the maximum number of packets that can be protected by a single set of keys.
   *
   * Not supported in Firefox
   */
  srtpCipher?: string;
  /**
   * A string containing the negotiated TLS version.
   * This is present for DTLS transports,
   * and only exists after DTLS has been negotiated.
   *
   * The value comes from the DTLS handshake ServerHello.version,
   * and is represented as four upper case hexadecimal digits,
   * where the digits represent the two bytes of the version.
   * Note however that the bytes might not map directly to version numbers.
   * For example, DTLS represents version 1.2 as 'FEFD' which numerically is {254, 253}.
   *
   * Not supported in Firefox
   */
  tlsVersion?: string;
};
/**
 * Statistics related to one RTCDataChannel on the connection.
 */
type RTCDataChannelStats = RTCCommonStats & {
  type: 'data-channel';
  /**
   * A positive integer value indicating the total number
   * of payload bytes sent on the associated RTCDataChannel.
   */
  bytesSent?: number;
  /**
   * A positive integer value indicating the total number
   * of payload bytes received on the associated RTCDataChannel.
   */
  bytesReceived?: number;
  /**
   * A positive integer value containing the id of the associated RTCDataChannel.
   */
  dataChannelIdentifier?: RTCDataChannel['id'];
  /**
   * A string containing the label of the associated RTCDataChannel.
   */
  label?: RTCDataChannel['label'];
  /**
   * A positive integer value indicating the total number
   * of message events fired for received messages on the associated RTCDataChannel.
   */
  messagesReceived?: number;
  /**
   * A positive integer value indicating the total number
   * of message events fired for sent messages on the channel.
   */
  messagesSent?: number;
  /**
   * A string containing the protocol of the associated RTCDataChannel.
   */
  protocol?: RTCDataChannel['protocol'];
  /**
   * The readyState of the associated RTCDataChannel.
   */
  state: RTCDataChannel['readyState'];
};
/**
 * Statistics about a specific codec being used by streams being sent or received by this connection.
 */
type RTCCodecStats = RTCCommonStats & {
  type: 'codec';
  /**
   * A positive number indicating the number of channels supported by the codec.
   */
  channels?: number;
  /**
   * A positive number containing the media sampling rate.
   */
  clockRate?: number;
  /**
   * A string containing the media MIME type/subtype, such as video/VP8.
   */
  mimeType: string;
  /**
   * A positive integer value in the range of 0 to 127
   * indicating the payload type used in RTP encoding or decoding.
   */
  payloadType: number;
  /**
   * A string containing the format-specific parameters
   * of the "a=fmtp" line in the codec's SDP (if present).
   */
  sdpFmtpLine: string;
  /**
   * It is a unique identifier that is associated to the object that
   * was inspected to produce the RTCTransportStats associated with this candidate.
   *
   * not supported in Safari
   */
  transportId: RTCTransportStats['id'];
};
type RTCMediaSourceStats = RTCCommonStats & {
  /**
   * A string indicating whether this object represents stats for a video source or a media source.
   * For an RTCAudioSourceStats this will always be audio.
   * For an RTCVideoSourceStats this will always be video.
   */
  kind: MediaStreamTrack['kind'];
  /**
   * A string that contains the id value of the MediaStreamTrack associated with the audio or video source.
   */
  trackIdentifier: MediaStreamTrack['id'];
  /**
   * The id of the RTCSenderAudioTrackAttachmentStats or RTCSenderVideoTrackAttachmentStats
   * object containing the current track attachment to the RTCRtpSender responsible for this stream.
   *
   * @deprecated
   */
  trackId?: string;
};
type RTCRtpStreamStats = {
  /**
   * A string that uniquely identifies the object that
   * was inspected to produce the RTCCodecStats object
   * associated with this RTP stream.
   */
  codecId?: RTCCodecStats['id'];
  /**
   * A string that uniquely identifies the object which was inspected
   * to produce the RTCTransportStats object associated with this RTP stream.
   *
   * not supported in Firefox
   */
  transportId?: RTCTransportStats['id'];
  /**
   * A string indicating whether the MediaStreamTrack
   * associated with the stream is an audio or a video track.
   */
  kind: MediaStreamTrack['kind'];
  /**
   * A positive integer that identifies the SSRC of the RTP packets in this stream.
   */
  ssrc: number;
};
type RTCReceivedRtpStreamStats = {
  /**
   * A number indicating the packet jitter for this synchronization source,
   * measured in seconds.
   *
   * https://developer.mozilla.org/en-US/docs/Glossary/Jitter
   *
   * not supported in Safari
   */
  jitter?: number;
  /**
   * An integer indicating the total number of RTP packets lost for this SSRC,
   * as measured at the remote endpoint.
   * This value can be negative if duplicate packets were received.
   *
   * not supported in Safari
   */
  packetsLost?: number;
  /**
   * A positive integer indicating the total number
   * of RTP packets received for this SSRC,
   * including retransmissions.
   *
   * Experimental
   *
   * not supported in Chrome, Edge, Opera and Safari
   */
  packetsReceived?: number;
};
type RTCSentRtpStreamStats = RTCMediaSourceStats &
  RTCRtpStreamStats & {
    /**
     * Total number of RTP packets sent for this SSRC.
     * This includes retransmissions.
     * Calculated as defined in [RFC3550] section 6.4.1.
     *
     * not Supported in Safari
     */
    packetsSent?: number;
    /**
     * Total number of bytes sent for this SSRC.
     * This includes retransmissions.
     * Calculated as defined in [RFC3550] section 6.4.1.
     *
     * not Supported in Safari
     */
    bytesSent?: number;
  };

type RTCPublisherPeerConnectionStatsReading =
  RTCCommonPeerConnectionStatsReading & {
    /** for media tracks  */
    audioTracks?: Record<RTCAudioSourceStats['id'], RTCAudioSourceStats>;
    videoTracks?: Record<RTCVideoSourceStats['id'], RTCVideoSourceStats>;
    /**
     * mediaSourceId => RTCAudioSourceStats['id'] not Firefox
     * remoteId => RTCRemoteInboundRtpAudioStreamStats['id'] not Safari 15.3
     */
    outboundAudioTracks?: Record<
      RTCOutboundRtpAudioStreamStats['ssrc'],
      RTCOutboundRtpAudioStreamStats
    >;
    outboundVideoTracks?: Record<
      RTCOutboundRtpVideoStreamStats['ssrc'],
      RTCOutboundRtpVideoStreamStats
    >;
    /**
     * Safari 15.3 not have remoteId for mapping data
     * if there is no remote Id, another flow parsing is used.
     * or 'remote-inbound-rtp' not allowed
     */
    outboundAudioTrackHasRemoteId: boolean;
    outboundVideoTrackHasRemoteId: boolean;
    outboundAudioTracksHasRemoteId?: Record<
      RTCOutboundRtpAudioStreamStats['ssrc'],
      boolean
    >;
    outboundVideoTracksHasRemoteId?: Record<
      RTCOutboundRtpVideoStreamStats['ssrc'],
      boolean
    >;
    remoteInboundsAudioTracks?: Record<
      RTCRemoteInboundRtpAudioStreamStats['id'],
      RTCRemoteInboundRtpAudioStreamStats
    >;
    remoteInboundsVideoTracks?: Record<
      RTCRemoteInboundRtpVideoStreamStats['id'],
      RTCRemoteInboundRtpVideoStreamStats
    >;
  };
type RTCPublisherPeerConnectionStats =
  | RTCPeerConnectionStats
  | RTCAudioPlayoutStats
  | RTCCertificateStats
  | RTCIceLocalCandidateStats
  | RTCIceRemoteCandidateStats
  | RTCDataChannelStats
  | RTCCodecStats
  | RTCIceCandidatePairStats
  | RTCTransportStats
  | RTCVideoSourceStats
  | RTCAudioSourceStats
  | RTCRemoteInboundRtpVideoStreamStats
  | RTCRemoteInboundRtpAudioStreamStats
  | RTCOutboundRtpVideoStreamStats
  | RTCOutboundRtpAudioStreamStats;
/**
 * The RTCVideoSourceStats dictionary represents a video track that is attached to one or more senders.
 * It is an RTCMediaSourceStats whose kind is "video".
 */
type RTCVideoSourceStats = RTCMediaSourceStats & {
  type: 'media-source';
  kind: 'video';
  /**
   * A positive number that indicates the total number of frames originating from this video source.
   *
   * not supported in Safari
   */
  frames?: number;
  /**
   * A positive number that represents the number of frames originating from this video source in the last second.
   * This property is not defined on this stats object for the first second of its existence.
   *
   * not supported in Safari
   */
  framesPerSecond?: number;
  /**
   * A number that represents the height, in pixels, of the last frame originating from this source.
   * This property is not defined on this stats object until after the first frame has been produced.
   *
   * not supported in Safari
   */
  height?: number;
  /**
   * A number that represents the width, in pixels, of the most recent frame originating from this source.
   * This property is not defined on this stats object until after the first frame has been produced.
   *
   * not supported in Safari
   */
  width?: number;
};
/**
 * Statistics about the media produced by the MediaStreamTrack attached to an RTP sender.
 * The dictionary this key maps to depends on the track's kind.
 */
type RTCAudioSourceStats = RTCMediaSourceStats & {
  type: 'media-source';
  kind: 'audio';
  /**
   * A number that represents the audio level of the media source.
   *
   * Experimental
   *
   * not supported in Firefox and Safari
   */
  audioLevel?: number;
  /**
   * A number that represents the total audio energy
   * of the media source over the lifetime of the stats object.
   *
   * read more
   * https://www.w3.org/TR/webrtc-stats/#webidl-637796216
   * https://developer.mozilla.org/en-US/docs/Web/API/RTCAudioSourceStats
   *
   * Experimental
   *
   * not supported in Firefox and Safari
   */
  totalAudioEnergy?: number;
  /**
   * A number that represents the total duration of all samples produced
   * by the media source over the lifetime of the stats object.
   *
   * Experimental
   *
   * not supported in Firefox and Safari
   */
  totalSamplesDuration?: number;
  /**
   * Only exists when the MediaStreamTrack is sourced from a microphone where echo cancellation is applied.
   * Calculated in decibels, as defined in [ECHO] (2012) section 3.14.
   *
   * If multiple audio channels are used,
   * the channel of the least audio energy is considered for any sample.
   *
   * not supported in Firefox and Safari
   */
  echoReturnLoss?: number;
  /**
   * Only exists when the MediaStreamTrack is sourced from a microphone where echo cancellation is applied.
   * Calculated in decibels, as defined in [ECHO] (2012) section 3.15.
   *
   * If multiple audio channels are used,
   * the channel of the least audio energy is considered for any sample.
   *
   * not supported in Firefox and Safari
   */
  echoReturnLossEnhancement?: number;
};
/**
 * Statistics describing the state of the inbound data stream from the perspective of the remote peer.
 */
type RTCRemoteInboundRtpVideoStreamStats = RTCRemoteInboundRtpStreamStats & {
  kind: 'video';
};
/**
 * Statistics describing the state of the inbound data stream from the perspective of the remote peer.
 */
type RTCRemoteInboundRtpAudioStreamStats = RTCRemoteInboundRtpStreamStats & {
  kind: 'audio';
};
type RTCRemoteInboundRtpStreamStats = RTCCommonStats &
  RTCReceivedRtpStreamStats &
  RTCRtpStreamStats & {
    type: 'remote-inbound-rtp';
    /**
     * A number indicating the fraction of packets lost
     * for this SSRC since the last sender or receiver report.
     *
     * not supported in Safari
     */
    fractionLost?: number;
    /**
     * A string that is used to find the local RTCOutboundRtpStreamStats object
     * that shares the same synchronization source (SSRC).
     */
    localId?: RTCOutboundRtpStreamStats['id'];
    /**
     * A number that indicates the estimated round trip time (RTT) for this SSRC, in seconds.
     * This property will not exist until valid RTT data has been received.
     */
    roundTripTime?: number;
    /**
     * A positive integer indicating the total number
     * of valid round trip time measurements received for this synchronization source (SSRC).
     *
     * not supported in Safari
     */
    roundTripTimeMeasurements?: number;
    /**
     * A number indicating the cumulative sum of all round trip time measurements since the beginning of the session, in seconds.
     * The average round trip time can be computed by dividing totalRoundTripTime by roundTripTimeMeasurements.
     *
     * not supported in Safari
     */
    totalRoundTripTime?: number;
  };
/**
 * Statistics describing the state of one of the outbound data streams on this connection.
 */
type RTCOutboundRtpVideoStreamStats = RTCOutboundRtpStreamStats & {
  kind: 'video';
  /**
   * An integer value which indicates the total number of Full Intra Request (FIR)
   * packets which this RTCRtpSender has sent to the remote RTCRtpReceiver.
   * This is an indicator of how often the stream has lagged,
   * requiring frames to be skipped in order to catch up.
   * Valid only for video streams.
   */
  firCount?: number;
  /**
   * The number of frames that have been successfully encoded
   * so far for sending on this RTP stream.
   * Only valid for video streams.
   */
  framesEncoded?: number;
  /**
   * An integer specifying the number of times the remote receiver has notified
   * this RTCRtpSender that some amount of encoded video data for one or more frames has been lost,
   * using Picture Loss Indication (PLI) packets.
   * Only available for video streams.
   */
  pliCount?: number;
  /**
   * A 64-bit value containing the sum of the QP values
   * for every frame encoded by this RTCRtpSender.
   * Valid only for video streams.
   *
   * not supported in Safari
   */
  qpSum?: number;
  /**
   * A record of the total time, in seconds, that this stream has spent in each quality limitation state.
   * The record includes a mapping for all RTCQualityLimitationReason types, including "none".
   *
   * The sum of all entries minus qualityLimitationDurations["none"]
   * gives the total time that the stream has been limited.
   *
   * Experimental
   *
   * not supported in Firefox and Safari
   */
  qualityLimitationDurations?: Record<
    Exclude<
      RTCOutboundRtpVideoStreamStats['qualityLimitationReason'],
      undefined
    >,
    number
  >;
  /**
   * The current reason for limiting the resolution and/or framerate, or "none" if not limited.
   *
   * One of the string none, cpu, bandwidth, or other,
   * explaining why the resolution and/or frame rate is being limited for this RTP stream.
   * Valid only for video streams.
   *
   * Experimental
   *
   * not supported in Firefox and Safari
   */
  qualityLimitationReason?: 'none' | 'cpu' | 'bandwidth' | 'other';
  /**
   * The number of times that the resolution has changed because we are quality limited
   * (qualityLimitationReason has a value other than "none").
   * The counter is initially zero and increases when the resolution goes up or down.
   * For example, if a 720p track is sent as 480p for some time and then recovers to 720p,
   * qualityLimitationResolutionChanges will have the value 2.
   */
  qualityLimitationResolutionChanges?: number;
  /**
   * An integer indicating the number of times this sender received a Slice Loss Indication (SLI)
   * frame from the remote peer, indicating
   * that one or more consecutive video macroblocks have been lost or corrupted.
   * Available only for video streams.
   */
  sliCount?: number;
  /**
   * A cumulative sum of the target frame sizes
   * (the targeted maximum size of the frame in bytes when the codec is asked to compress it)
   * for all of the frames encoded so far.
   * This will likely differ from the total of the actual frame sizes.
   *
   * not supported in Safari
   */
  totalEncodedBytesTarget?: number;
  /**
   * A floating-point value indicating the total number
   * of seconds that have been spent encoding
   * the frames encoded so far by this RTCRtpSender.
   *
   * not supported in Safari
   */
  totalEncodeTime?: number;
  /**
   * Only exists if a rid has been set for this RTP stream.
   * If rid is set this value will be present regardless
   * if the RID RTP header extension has been negotiated.
   */
  rid?: string;
  /**
   * Represents the width of the last encoded frame.
   * The resolution of the encoded frame may be lower than the media source
   * (see RTCVideoSourceStats.width).
   * Before the first frame is encoded this member MUST NOT exist.
   *
   * not supported in Safari
   */
  frameWidth?: RTCVideoSourceStats['width'];
  /**
   * Represents the height of the last encoded frame.
   * The resolution of the encoded frame may be lower than the media source
   * (see RTCVideoSourceStats.height).
   * Before the first frame is encoded this member MUST NOT exist.
   *
   * not supported in Safari
   */
  frameHeight?: RTCVideoSourceStats['height'];
  /**
   * The number of encoded frames during the last second.
   * This may be lower than the media source frame rate
   * (see RTCVideoSourceStats.framesPerSecond).
   *
   * not supported in Safari
   */
  framesPerSecond?: RTCVideoSourceStats['framesPerSecond'];
  /**
   * Represents the total number of frames sent on this RTP stream.
   *
   * not supported in Safari
   */
  framesSent?: number;
  /**
   * Represents the total number of huge frames sent by this RTP stream.
   * Huge frames, by definition, are frames that have an encoded size
   * at least 2.5 times the average size of the frames.
   * The average size of the frames is defined as the target bitrate per second divided
   * by the target FPS at the time the frame was encoded.
   * These are usually complex to encode frames with a lot of changes in the picture.
   * This can be used to estimate, e.g slide changes in the streamed presentation.
   */
  hugeFramesSent?: number;
  /**
   *  It represents the total number of key frames,
   * such as key frames in VP8 [RFC6386] or IDR-frames in H.264 [RFC6184],
   * successfully encoded for this RTP media stream. This is a subset of framesEncoded.
   * framesEncoded - keyFramesEncoded gives you the number of delta frames encoded.
   *
   * not supported in Firefox and Safari
   */
  keyFramesEncoded?: number;
  /**
   * MUST NOT exist unless exposing hardware is allowed.
   *
   * Identifies the encoder implementation used.
   * This is useful for diagnosing interoperability issues.
   */
  encoderImplementation?: string;
  /**
   * MUST NOT exist unless exposing hardware is allowed.
   *
   * Whether the encoder currently used is considered power efficient by the user agent.
   * This SHOULD reflect if the configuration results in hardware acceleration,
   * but the user agent MAY take other information into account when deciding
   * if the configuration is considered power efficient.
   */
  powerEfficientEncoder?: boolean;
  /**
   * Only exists when a scalability mode is currently configured for this RTP stream.
   *
   * https://w3c.github.io/webrtc-svc/#scalabilitymodes*
   *
   * Experimental
   *
   * not supported in Firefox and Safari
   */
  scalabilityMode?: string;
};
/**
 * Statistics describing the state of one of the outbound data streams on this connection.
 */
type RTCOutboundRtpAudioStreamStats = RTCOutboundRtpStreamStats & {
  kind: 'audio';
};
type RTCOutboundRtpStreamStats = RTCCommonStats &
  RTCSentRtpStreamStats & {
    type: 'outbound-rtp';
    /**
     * Indicates whether this RTP stream is configured to be sent or disabled.
     * Note that an active stream can still not be sending,
     * e.g. when being limited by network conditions.
     *
     * not supported in Firefox and Safari
     */
    active?: boolean;
    mediaType?: string;
    /**
     * If the RTCRtpTransceiver owning this stream has a mid value that is not null,
     * this is that value, otherwise this member MUST NOT be present.
     *
     * Experimental
     *
     * not supported in Firefox and Safari
     */
    mid?: RTCRtpTransceiver['mid'];
    /**
     * The identifier of the stats object representing the track currently
     * attached to the sender of this stream, an RTCMediaSourceStats.
     *
     * not supported in Firefox
     */
    mediaSourceId?: RTCMediaSourceStats['id'];
    /**
     * A floating-point value indicating the average RTCP interval
     * between two consecutive compound RTCP packets.
     */
    averageRtcpInterval?: number;
    /**
     * An integer value indicating the total number of Negative ACKnowledgement (NACK)
     * packets this RTCRtpSender has received from the remote RTCRtpReceiver.
     */
    nackCount?: number;
    /**
     * A string which identifies the RTCRemoteInboundRtpStreamStats object
     * that provides statistics for the remote peer for this same SSRC.
     * This ID is stable across multiple calls to getStats()
     */
    remoteId?: RTCRemoteInboundRtpStreamStats['id'];
    /**
     * The total number of bytes that have been retransmitted
     * for this source as of the time the statistics were sampled.
     * These retransmitted bytes comprise the packets included
     * in the value returned by retransmittedPacketsSent.
     */
    retransmittedBytesSent?: number;
    /**
     * The total number of packets that have needed to be retransmitted
     * for this source as of the time the statistics were sampled.
     * These retransmitted packets are included
     * in the value returned by packetsSent.
     */
    retransmittedPacketsSent?: number;
    /**
     * The id of the RTCAudioSenderStats or RTCVideoSenderStats
     * object containing statistics about this stream's RTCRtpSender.
     *
     * @deprecated
     */
    senderId?: string;
    /**
     * Reflects the current encoder target in bits per second.
     * The target is an instantanous value reflecting the encoder's settings,
     * but the resulting payload bytes sent per second, excluding retransmissions,
     * SHOULD closely correlate to the target. See also bytesSent and retransmittedBytesSent.
     * The targetBitrate is defined in the same way
     * as the Transport Independent Application Specific (TIAS) bitrate [RFC3890].
     *
     * not supported in Firefox
     */
    targetBitrate?: number;
    /**
     * Total number of RTP header and padding bytes sent for this SSRC.
     * This does not include the size of transport layer headers such as IP or UDP.
     * headerBytesSent + bytesSent equals the number
     * of bytes sent as payload over the transport.
     */
    headerBytesSent?: number;
    /**
     * If RTX is negotiated for retransmissions on a separate RTP stream,
     * this is the SSRC of the RTX stream that is associated with this stream's ssrc.
     * If RTX is not negotiated, this value MUST NOT be present.
     */
    rtxSsrc?: number;
    /**
     * The total number of seconds that packets have spent buffered
     * locally before being transmitted onto the network.
     * The time is measured from when a packet is emitted from the
     * RTP packetizer until it is handed over to the OS network socket.
     * This measurement is added to totalPacketSendDelay
     * when packetsSent is incremented.
     *
     * not supported in Firefox and Safari
     */
    totalPacketSendDelay?: number;
  };

type RTCSubscriberPeerConnectionStatsReading =
  RTCCommonPeerConnectionStatsReading & {
    /** tracks */
    inboundAudioTracks?: Record<
      RTCInboundRtpAudioStreamStats['ssrc'],
      RTCInboundRtpAudioStreamStats
    >;
    inboundVideoTracks?: Record<
      RTCInboundRtpVideoStreamStats['ssrc'],
      RTCInboundRtpVideoStreamStats
    >;
    remoteOutboundAudioTracks?: Record<
      RTCRemoteOutboundRtpStreamStats['ssrc'],
      RTCRemoteOutboundRtpStreamStats
    >;
    remoteOutboundVideoTracks?: Record<
      RTCRemoteOutboundRtpStreamStats['ssrc'],
      RTCRemoteOutboundRtpStreamStats
    >;
  };
type RTCSubscriberPeerConnectionStats =
  /** common stats */
  | RTCPeerConnectionStats
  | RTCAudioPlayoutStats
  | RTCCertificateStats
  | RTCIceLocalCandidateStats
  | RTCIceRemoteCandidateStats
  | RTCDataChannelStats
  | RTCCodecStats
  | RTCIceCandidatePairStats
  | RTCTransportStats
  /** only subscriber */
  | RTCInboundRtpVideoStreamStats
  | RTCInboundRtpAudioStreamStats
  | RTCRemoteOutboundRtpStreamStats;
type RTCInboundRtpVideoStreamStats = RTCInboundRtpStreamStats & {
  kind: 'video';
  mediaType: string;
  /**
   * An integer value which indicates the total number of Full Intra Request (FIR) packets
   * which this receiver has sent to the sender.
   * This is an indicator of how often the stream has lagged,
   * requiring frames to be skipped in order to catch up.
   * This value is only available for video streams.
   */
  firCount?: number;
  /**
   * A long integer value indicating the total number of frames
   * of video which have been correctly decoded so far for this media source.
   * This is the number of frames that would have been rendered
   * if none were dropped.
   * Only valid for video streams.
   */
  framesDecoded?: number;
  /**
   * It represents the total number of frames that have been rendered.
   * It is incremented just after a frame has been rendered.
   */
  framesRendered?: number;
  /**
   * It represents the total number of key frames, such as key frames
   * in VP8 [RFC6386] or IDR-frames in H.264 [RFC6184],
   * successfully decoded for this RTP media stream.
   * This is a subset of framesDecoded.
   * framesDecoded - keyFramesDecoded gives you the number of delta frames decoded.
   */
  keyFramesDecoded?: number;
  /**
   * The total number of frames dropped prior to decode or dropped
   * because the frame missed its display deadline for this receiver's track.
   * The measurement begins when the receiver is created and
   * is a cumulative metric as defined in Appendix A (g) of [RFC7004].
   */
  framesDropped?: number;
  /**
   * Represents the width of the last decoded frame.
   * Before the first frame is decoded this member MUST NOT exist.
   */
  frameWidth?: number;
  /**
   * Represents the height of the last decoded frame.
   * Before the first frame is decoded this member MUST NOT exist.
   */
  frameHeight?: number;
  /**
   *  The number of decoded frames in the last second.
   */
  framesPerSecond?: number;
  /**
   * A DOMHighResTimeStamp indicating the time at which the last packet was received for this source.
   * The timestamp property, on the other hand,
   * indicates the time at which the statistics object was generated.
   */
  lastPacketReceivedTimestamp?: DOMHighResTimeStamp;
  /**
   * An integer specifying the number of times the receiver has notified the sender
   * that some amount of encoded video data for one or more frames has been lost,
   * using Picture Loss Indication (PLI) packets.
   * This is only available for video streams.
   */
  pliCount?: number;
  /**
   * A 64-bit value containing the sum of the QP values for every frame decoded by this RTP receiver.
   * You can determine the average QP per frame by dividing this value by framesDecoded.
   * Valid only for video streams.
   */
  qpSum?: number;
  /**
   * An integer indicating the number of times the receiver sent a Slice Loss Indication (SLI) frame
   * to the sender to tell it that one or more consecutive (in terms of scan order)
   * video macroblocks have been lost or corrupted.
   * Available only for video streams.
   */
  sliCount?: number;
  /**
   * Total number of seconds that have been spent decoding the framesDecoded frames of this stream.
   * The average decode time can be calculated by dividing this value with framesDecoded.
   * The time it takes to decode one frame is the time passed between feeding the decoder
   * a frame and the decoder returning decoded data for that frame.
   */
  totalDecodeTime?: number;
  /**
   * Sum of the interframe delays in seconds between consecutively rendered frames,
   * recorded just after a frame has been rendered. The interframe delay variance
   * be calculated from totalInterFrameDelay, totalSquaredInterFrameDelay,
   * and framesRendered according to the formula:
   * (totalSquaredInterFrameDelay - totalInterFrameDelay^2/ framesRendered)/framesRendered.
   */
  totalInterFrameDelay?: number;
  /**
   * Sum of the squared interframe delays in seconds between consecutively rendered frames,
   * recorded just after a frame has been rendered. See totalInterFrameDelay
   * for details on how to calculate the interframe delay variance.
   */
  totalSquaredInterFrameDelay?: number;
  /**
   * Count the total number of video pauses experienced by this receiver.
   * Video is considered to be paused if time passed since last rendered frame exceeds 5 seconds.
   * pauseCount is incremented when a frame is rendered after such a pause.
   */
  pauseCount?: number;
  /**
   * Total duration of pauses (for definition of pause see pauseCount), in seconds.
   * This value is updated when a frame is rendered.
   */
  totalPausesDuration?: number;
  /**
   * Count the total number of video freezes experienced by this receiver.
   * It is a freeze if frame duration, which is time interval between two consecutively rendered frames,
   * is equal or exceeds Max(3 * avg_frame_duration_ms, avg_frame_duration_ms + 150),
   * where avg_frame_duration_ms is linear average of durations of last 30 rendered frames.
   */
  freezeCount?: number;
  /**
   * Total duration of rendered frames which are considered as frozen
   * (for definition of freeze see freezeCount), in seconds.
   * This value is updated when a frame is rendered.
   */
  totalFreezesDuration?: number;
  /**
   * Represents the total number of complete frames received on this RTP stream.
   * This metric is incremented when the complete frame is received.
   */
  framesReceived?: number;
  /**
   * Identifies the decoder implementation used.
   * This is useful for diagnosing interoperability issues.
   */
  decoderImplementation?: string;
  /**
   * Whether the decoder currently used is considered power efficient by the user agent.
   * This SHOULD reflect if the configuration results in hardware acceleration,
   * but the user agent MAY take other information into account when deciding
   * if the configuration is considered power efficient.
   */
  powerEfficientDecoder?: boolean;
  /**
   * It represents the total number of frames correctly decoded for this
   * RTP stream that consist of more than one RTP packet. For such frames the totalAssemblyTime is incremented.
   * The average frame assembly time can be calculated
   * by dividing the totalAssemblyTime with framesAssembledFromMultiplePackets.
   */
  framesAssembledFromMultiplePackets?: number;
  /**
   * The sum of the time, in seconds, each video frame takes from the time the first RTP packet
   * is received (reception timestamp) and to the time the last RTP packet of a frame is received.
   * Only incremented for frames consisting of more than one RTP packet.
   *
   * Given the complexities involved, the time of arrival or the reception timestamp
   * is measured as close to the network layer as possible. This metric is not incremented
   * for frames that are not decoded, i.e., framesDropped or frames that fail decoding
   * for other reasons (if any).
   * Only incremented for frames consisting of more than one RTP packet.
   */
  totalAssemblyTime?: number;
  /**
   * Represents the cumulative sum of all corruption probability measurements that
   * have been made for this SSRC, see corruptionMeasurements
   * regarding when this attribute SHOULD be present.
   */
  totalCorruptionProbability?: number;
  /**
   * Represents the cumulative sum of all corruption probability measurements
   * squared that have been made for this SSRC, see corruptionMeasurements
   * regarding when this attribute SHOULD be present.
   */
  totalSquaredCorruptionProbability?: number;
  /**
   * When the user agent is able to make a corruption probability measurement,
   * this counter is incremented for each such measurement and totalCorruptionProbability
   * and totalSquaredCorruptionProbability are aggregated with this measurement
   * and measurement squared respectively.
   * If the corruption-detection header extension is present in the RTP packets,
   * corruption probability measurements MUST be present.
   */
  corruptionMeasurements?: number;
};
type RTCInboundRtpAudioStreamStats = RTCInboundRtpStreamStats & {
  kind: 'audio';
  mediaType: string;
  /**
   * The total number of samples that have been received on this RTP stream.
   * This includes concealedSamples.
   */
  totalSamplesReceived?: number;
  /**
   * The total number of samples that are concealed samples. A concealed sample is
   * a sample that was replaced with synthesized samples generated locally before being played out.
   * Examples of samples that have to be concealed are samples from lost packets (reported in packetsLost)
   * or samples from packets that arrive too late to be played out (reported in packetsDiscarded).
   */
  concealedSamples?: number;
  /**
   * The total number of concealed samples inserted that are "silent".
   * Playing out silent samples results in silence or comfort noise.
   * This is a subset of concealedSamples.
   */
  silentConcealedSamples?: number;
  /**
   * The number of concealment events.
   * This counter increases every time a concealed sample is synthesized after a non-concealed sample.
   * That is, multiple consecutive concealed samples will increase the concealedSamples count multiple times
   * but is a single concealment event.
   */
  concealmentEvents?: number;
  /**
   * When playout is slowed down, this counter is increased by the difference between the number
   * of samples received and the number of samples played out.
   * If playout is slowed down by inserting samples,
   * this will be the number of inserted samples.
   */
  insertedSamplesForDeceleration?: number;
  /**
   * When playout is sped up, this counter is increased by the difference between the number
   * of samples received and the number of samples played out.
   * If speedup is achieved by removing samples, this will be the count of samples removed.
   */
  removedSamplesForAcceleration?: number;
  /**
   * Represents the audio level of the receiving track.
   * For audio levels of tracks attached locally, see RTCAudioSourceStats instead.
   *
   * The value is between 0..1 (linear), where 1.0 represents 0 dBov, 0 represents silence,
   * and 0.5 represents approximately 6 dBSPL change in the sound pressure level from 0 dBov.
   *
   * The audioLevel is averaged over some small interval, using the algorithm described under totalAudioEnergy.
   * The interval used is implementation dependent.
   */
  audioLevel?: number;
  /**
   * Represents the audio energy of the receiving track.
   * For audio energy of tracks attached locally, see RTCAudioSourceStats instead.
   *
   * This value MUST be computed as follows: for each audio sample that is received (and thus counted by totalSamplesReceived),
   * add the sample's value divided by the highest-intensity encodable value,
   * squared and then multiplied by the duration of the sample in seconds.
   * In other words, duration * Math.pow(energy/maxEnergy, 2).
   *
   * This can be used to obtain a root mean square (RMS) value that uses the same units as audioLevel, as defined in [RFC6464].
   * It can be converted to these units using the formula Math.sqrt(totalAudioEnergy/totalSamplesDuration).
   * This calculation can also be performed using the differences between the values of two different getStats() calls,
   * in order to compute the average audio level over any desired time interval. In other words,
   * do Math.sqrt((energy2 - energy1)/(duration2 - duration1)).
   *
   * If multiple audio channels are used, the audio energy
   * of a sample refers to the highest energy of any channel.
   */
  totalAudioEnergy?: number;
  /**
   * Represents the audio duration of the receiving track.
   * For audio durations of tracks attached locally, see RTCAudioSourceStats instead.
   *
   * Represents the total duration in seconds of all samples that have been received
   * (and thus counted by totalSamplesReceived). Can be used with totalAudioEnergy
   * to compute an average audio level over different intervals.
   */
  totalSamplesDuration?: number;
  /**
   * If audio playout is happening, this is used to look up the corresponding RTCAudioPlayoutStats.
   */
  playoutId?: RTCAudioPlayoutStats['id'];
};
/**
 * Statistics describing the state of one
 * of the connection's inbound data streams.
 */
type RTCInboundRtpStreamStats = RTCMediaSourceStats &
  RTCRtpStreamStats &
  RTCReceivedRtpStreamStats & {
    type: 'inbound-rtp';
    /**
     * A floating-point value indicating the average RTCP interval
     * between two consecutive compound RTCP packets.
     */
    averageRtcpInterval?: number;
    /**
     * A 64-bit integer which indicates the total number
     * of bytes that have been received so far for this media source.
     */
    bytesReceived?: number;
    /**
     * An integer value indicating the number of RTP Forward Error Correction (FEC) packets
     * which have been received for this source, for which the error correction payload was discarded.
     */
    fecPacketsDiscarded?: number;
    /**
     * Total number of RTP FEC bytes received for this SSRC, only including payload bytes.
     * This is a subset of bytesReceived.
     * If a FEC mechanism that uses a different ssrc was negotiated,
     * FEC packets are sent over a separate SSRC but is still accounted for here.
     */
    fecBytesReceived?: number;
    /**
     * An integer value indicating the total number of RTP FEC packets received for this source.
     * This counter may also be incremented when FEC packets arrive in-band along with media content;
     * this can happen with Opus, for example.
     */
    fecPacketsReceived?: number;
    /**
     * An integer value indicating the total number of Negative ACKnowledgement (NACK)
     * packets this receiver has sent.
     */
    nackCount?: number;
    /**
     * An integer value indicating the total number of packets that
     * have been discarded because they were duplicates.
     * These packets are not counted by packetsDiscarded.
     */
    packetsDuplicated?: number;
    /**
     * An integer totaling the number of RTP packets that could not be decrypted.
     * These packets are not counted by packetsDiscarded.
     */
    packetsFailedDecryption?: number;
    /**
     * A record of key-value pairs with strings as the keys mapped to 32-bit integer values,
     * each indicating the total number of packets this receiver has received on this RTP stream
     * from this source for each Differentiated Services Code Point (DSCP).
     */
    perDscpPacketsReceived?: number;
    /**
     * A string indicating which identifies the RTCAudioReceiverStats or RTCVideoReceiverStats object
     * associated with the stream's receiver. This ID is stable across multiple calls to getStats().
     *
     * @deprecated
     */
    receiverId?: string;
    /**
     * A string which identifies the RTCRemoteOutboundRtpStreamStats object that provides statistics
     * for the remote peer for this same SSRC.
     * This ID is stable across multiple calls to getStats().
     */
    remoteId?: RTCRemoteOutboundRtpStreamStats['id'];
    /**
     * If the RTCRtpTransceiver owning this stream has a mid value that is not null,
     * this is that value, otherwise this member MUST NOT be present.
     */
    mid?: RTCRtpTransceiver['mid'];
    /**
     * Total number of RTP header and padding bytes received for this SSRC. This includes retransmissions.
     * This does not include the size of transport layer headers such as IP or UDP.
     * headerBytesReceived + bytesReceived equals the number of bytes received as payload over the transport.
     */
    headerBytesReceived?: number;
    /**
     * The cumulative number of RTP packets discarded by the jitter buffer due to late or early-arrival, i.e.,
     * these packets are not played out. RTP packets discarded due to packet duplication
     * are not reported in this metric [XRBLOCK-STATS]. Calculated as defined
     * in [RFC7002] section 3.2 and Appendix A.a.
     */
    packetsDiscarded?: number;
    /**
     * It is the sum of the time, in seconds, each audio sample or video frame takes from the time
     * the first RTP packet is received (reception timestamp) and to the time the corresponding sample
     * or frame is decoded (decoded timestamp). At this point the audio sample or video frame is ready
     * for playout by the MediaStreamTrack. Typically ready for playout here means after the audio sample
     * or video frame is fully decoded by the decoder.
     *
     * Given the complexities involved, the time of arrival or the reception timestamp is measured
     * as close to the network layer as possible and the decoded timestamp is measured as soon
     * as the complete sample or frame is decoded.
     *
     * In the case of audio, several samples are received in the same RTP packet,
     * all samples will share the same reception timestamp and different decoded timestamps.
     * In the case of video, the frame is received over several RTP packets,
     * in this case the earliest timestamp containing the frame is counted as the reception timestamp,
     * and the decoded timestamp corresponds to when the complete frame is decoded.
     *
     * This metric is not incremented for frames that are not decoded, i.e. framesDropped.
     * The average processing delay can be calculated by dividing the totalProcessingDelay
     * with the framesDecoded for video (or povisional stats spec totalSamplesDecoded for audio).
     */
    totalProcessingDelay?: number;
    /**
     * This is the estimated playout time of this receiver's track.
     * The playout time is the NTP timestamp of the last playable audio sample
     * or video frame that has a known timestamp (from an RTCP SR packet mapping RTP timestamps to NTP timestamps),
     * extrapolated with the time elapsed since it was ready to be played out. This is the "current time"
     * of the track in NTP clock time of the sender and can be present even
     * if there is no audio currently playing.
     *
     * This can be useful for estimating how much audio and video is out of sync for two tracks from the same source,
     * audioInboundRtpStats.estimatedPlayoutTimestamp - videoInboundRtpStats.estimatedPlayoutTimestamp.
     */
    estimatedPlayoutTimestamp?: DOMHighResTimeStamp;
    /**
     * The purpose of the jitter buffer is to recombine RTP packets into frames (in the case of video) and have smooth playout.
     * The model described here assumes that the samples or frames are still compressed and have not yet been decoded.
     * It is the sum of the time, in seconds, each audio sample or a video frame takes from the time the first packet
     * is received by the jitter buffer (ingest timestamp) to the time it exits the jitter buffer (emit timestamp).
     * In the case of audio, several samples belong to the same RTP packet, hence they will have the same ingest timestamp
     * but different jitter buffer emit timestamps. In the case of video, the frame maybe is received over several RTP packets,
     * hence the ingest timestamp is the earliest packet of the frame that entered the jitter buffer and the emit timestamp
     * is when the whole frame exits the jitter buffer. This metric increases upon samples or frames exiting,
     * having completed their time in the buffer (and incrementing jitterBufferEmittedCount).
     * The average jitter buffer delay can be calculated by dividing the jitterBufferDelay with the jitterBufferEmittedCount.
     */
    jitterBufferDelay?: number;
    /**
     * This value is increased by the target jitter buffer delay every time a sample is emitted by the jitter buffer.
     * The added target is the target delay, in seconds, at the time that the sample was emitted from the jitter buffer.
     * To get the average target delay, divide by jitterBufferEmittedCount.
     */
    jitterBufferTargetDelay?: number;
    /**
     * The total number of audio samples or video frames that have come
     * out of the jitter buffer (increasing jitterBufferDelay).
     */
    jitterBufferEmittedCount?: number;
    /**
     * There are various reasons why the jitter buffer delay might be increased to a higher value,
     * such as to achieve AV synchronization or because a jitterBufferTarget was set on a RTCRtpReceiver.
     * When using one of these mechanisms, it can be useful to keep track of the minimal jitter buffer delay
     * that could have been achieved, so WebRTC clients can track the amount of additional delay that is being added.
     *
     * This metric works the same way as jitterBufferTargetDelay, except that it is not affected by external mechanisms
     * that increase the jitter buffer target delay, such as jitterBufferTarget (see link above), AV sync, or any other mechanisms.
     * This metric is purely based on the network characteristics such as jitter and packet loss, and can be seen
     * as the minimum obtainable jitter buffer delay if no external factors would affect it.
     * The metric is updated every time jitterBufferEmittedCount is updated.
     */
    jitterBufferMinimumDelay?: number;
    /**
     * The total number of retransmitted packets that were received for this SSRC. This is a subset of packetsReceived.
     * If RTX is not negotiated, retransmitted packets can not be identified and this member MUST NOT exist.
     */
    retransmittedPacketsReceived?: number;
    /**
     * The total number of retransmitted bytes that were received for this SSRC, only including payload bytes.
     * This is a subset of bytesReceived.
     * If RTX is not negotiated, retransmitted packets can not be identified and this member MUST NOT exist.
     */
    retransmittedBytesReceived?: number;
    /**
     * If RTX is negotiated for retransmissions on a separate RTP stream,
     * this is the SSRC of the RTX stream that is associated with this stream's ssrc.
     * If RTX is not negotiated, this value MUST NOT be present.
     */
    rtxSsrc?: number;
    /**
     * If a FEC mechanism that uses a separate RTP stream is negotiated,
     * this is the SSRC of the FEC stream that is associated with this stream's ssrc.
     * If FEC is not negotiated or uses the same RTP stream, this value MUST NOT be present.
     */
    fecSsrc?: number;
  };
/**
 * Statistics describing the state of the outbound data stream from the perspective of the remote peer.
 */
type RTCRemoteOutboundRtpStreamStats = RTCSentRtpStreamStats & {
  type: 'remote-outbound-rtp';
  /**
   * A string which is used to find the local RTCInboundRtpStreamStats
   * object that shares the same synchronization source (SSRC).
   *
   * not Supported in Safari
   */
  localId?: RTCInboundRtpStreamStats['id'];
  /**
   * A DOMHighResTimeStamp specifying the timestamp (on the remote device)
   * at which the statistics in the RTCRemoteOutboundRtpStreamStats object were sent by the remote endpoint.
   * This is different from the timestamp; it represents the time at which the object's statistics were received
   * or generated by the local endpoint.
   *
   * not Supported in Safari
   */
  remoteTimestamp?: DOMHighResTimeStamp;
  /**
   * A positive integer indicating the total number of RTCP Sender Report (SR)
   * blocks sent for this synchronization source (SSRC).
   *
   * not Supported in Firefox and Safari
   *
   * Experimental
   */
  reportsSent?: number;
  /**
   * A positive number that represents the total number of valid round trip time
   * measurements received for this synchronization source (SSRC).
   *
   * not Supported in Firefox and Safari
   *
   * Experimental
   */
  roundTripTimeMeasurements?: number;
  /**
   * A number indicating the cumulative sum of all round trip time measurements since
   * the beginning of the session, in seconds.
   * The average round trip time can be computed
   * by dividing totalRoundTripTime by roundTripTimeMeasurements.
   *
   * not Supported in Firefox and Safari
   *
   * Experimental
   */
  totalRoundTripTime?: number;
};

type RTCCommonPeerConnectionStatsBandWidth = {
  upload?: number;
  download?: number;
};
type RTCPacketsStats = {
  packetsTotal: number;
  packetsLost: number;
};
type RTCIceLocalCandidateStatsMapped = RTCIceLocalCandidateStats & {
  mappedAddress?: string;
};
type RTCIceRemoteCandidateStatsMapped = RTCIceRemoteCandidateStats & {
  mappedAddress?: string;
};
type RTCCommonPeerConnectionStatsMapped = {
  mediaPlayout?: RTCPublisherPeerConnectionStatsReading['mediaPlayout'];
  peerConnection?: RTCPublisherPeerConnectionStatsReading['peerConnection'];
  codecs?: RTCPublisherPeerConnectionStatsReading['codecs'];
  transport?: RTCPublisherPeerConnectionStatsReading['transport'];
  dataChannels?: RTCPublisherPeerConnectionStatsReading['dataChannels'];
  candidatePairs?: RTCPublisherPeerConnectionStatsReading['candidatePairs'];
  activeCandidatePair?: RTCIceCandidatePairStats;
  bandWidth?: RTCCommonPeerConnectionStatsBandWidth;
  localCandidates?: RTCPublisherPeerConnectionStatsReading['localCandidates'];
  localCandidate?: RTCIceLocalCandidateStatsMapped;
  remoteCandidates?: RTCPublisherPeerConnectionStatsReading['remoteCandidates'];
  remoteCandidate?: RTCIceRemoteCandidateStatsMapped;
  certificates?: RTCPublisherPeerConnectionStatsReading['certificates'];
  localCertificate?: RTCCertificateStats;
  remoteCertificate?: RTCCertificateStats;
};

type RTCPublisherPeerConnectionStatsMapped =
  RTCCommonPeerConnectionStatsMapped & {
    audioTracks?: RTCPublisherPeerConnectionStatsAudioTracksMapped;
    /**
     * for only Firefox
     * Firefox not have RTCOutboundRtpAudioStreamStats['mediaSourceId']
     * for mapped data to audioTracks
     */
    mediaSourceAudioTracks?: RTCAudioSourceStatsMapped;
    videoTracks?: RTCPublisherPeerConnectionStatsVideoTracksMapped;
    /**
     * for only Firefox
     * Firefox not have RTCOutboundRtpVideoStreamStats['mediaSourceId']
     * for mapped data to videoTracks
     */
    mediaSourceVideoTracks?: RTCVideoSourceStatsMapped;
    uploadBitrateAudio?: number;
    uploadBitrateVideo?: number;
    uploadBitrate?: number;
    packetsSendAudio?: number;
    packetsSendVideo?: number;
    packetsSend?: number;
    packetsLostAudio?: number;
    packetsLostVideo?: number;
    packetsLost?: number;
    maxRttAudio?: number;
    maxRttVideo?: number;
    maxRtt?: number;
    maxJitterAudio?: number;
    maxJitterVideo?: number;
    maxJitter?: number;
  };
type RTCPublisherPeerConnectionStatsAudioTrackMapped =
  RTCPublisherPeerConnectionStatsTrackMapped & {
    mediaSource?: RTCAudioSourceStats;
    outbound?: RTCOutboundRtpAudioStreamStats;
    remoteInbound?: RTCRemoteInboundRtpAudioStreamStats;
  };
type RTCPublisherPeerConnectionStatsAudioTracksMapped = Record<
  RTCRemoteInboundRtpAudioStreamStats['ssrc'],
  RTCPublisherPeerConnectionStatsAudioTrackMapped
>;
/**
 * for only Firefox
 * Firefox not have RTCOutboundRtpAudioStreamStats['mediaSourceId']
 * for mapped data to audioTracks
 */
type RTCAudioSourceStatsMapped = Record<
  RTCAudioSourceStats['trackIdentifier'],
  RTCAudioSourceStats
>;
type RTCPublisherPeerConnectionStatsVideoTrackMapped =
  RTCPublisherPeerConnectionStatsTrackMapped & {
    mediaSource?: RTCVideoSourceStats;
    outbound?: RTCOutboundRtpVideoStreamStats;
    remoteInbound?: RTCRemoteInboundRtpVideoStreamStats;
    fps?: number;
  };
type RTCPublisherPeerConnectionStatsVideoTracksMapped = Record<
  RTCRemoteInboundRtpVideoStreamStats['ssrc'],
  RTCPublisherPeerConnectionStatsVideoTrackMapped
>;
/**
 * for only Firefox
 * Firefox not have RTCOutboundRtpVideoStreamStats['mediaSourceId']
 * for mapped data to videoTracks
 */
type RTCVideoSourceStatsMapped = Record<
  RTCVideoSourceStats['trackIdentifier'],
  RTCVideoSourceStats
>;
type RTCPublisherPeerConnectionStatsTrackMapped = {
  codec?: RTCCodecStats;
  uploadBitrate?: number;
  packetsSend?: number;
  packetsLost?: number;
  rtt?: number;
  jitter?: number;
};

type RTCSubscriberPeerConnectionStatsMapped =
  RTCCommonPeerConnectionStatsMapped & {
    audioTracks?: RTCSubscriberPeerConnectionStatsAudioTracksMapped;
    videoTracks?: RTCSubscriberPeerConnectionStatsVideoTracksMapped;
    downloadAudioBitrate?: number;
    downloadVideoBitrate?: number;
    downloadBitrate?: number;
    packetsReceivedAudio?: number;
    packetsReceivedVideo?: number;
    packetsReceived?: number;
    packetsLostAudio?: number;
    packetsLostVideo?: number;
    packetsLost?: number;
    maxRttAudio?: number;
    maxRttVideo?: number;
    maxRtt?: number;
    maxJitterAudio?: number;
    maxJitterVideo?: number;
    maxJitter?: number;
  };
type RTCSubscriberPeerConnectionStatsAudioTrackMapped =
  RTCSubscriberPeerConnectionStatsTrackMapped & {
    inbound?: RTCInboundRtpAudioStreamStats;
    remoteOutbound?: RTCRemoteOutboundRtpStreamStats;
  };
type RTCSubscriberPeerConnectionStatsAudioTracksMapped = Record<
  RTCInboundRtpAudioStreamStats['ssrc'],
  RTCSubscriberPeerConnectionStatsAudioTrackMapped
>;
type RTCSubscriberPeerConnectionStatsVideoTrackMapped =
  RTCSubscriberPeerConnectionStatsTrackMapped & {
    inbound?: RTCInboundRtpVideoStreamStats;
    remoteOutbound?: RTCRemoteOutboundRtpStreamStats;
  };
type RTCSubscriberPeerConnectionStatsTrackMapped = {
  codec?: RTCCodecStats;
  downloadBitrate?: number;
  packetsReceived?: number;
  packetsLost?: number;
  rtt?: number;
  jitter?: number;
};
type RTCSubscriberPeerConnectionStatsVideoTracksMapped = Record<
  RTCInboundRtpVideoStreamStats['ssrc'],
  RTCSubscriberPeerConnectionStatsVideoTrackMapped
>;

type WebRTCMetricsControllerService = {
  getPublisherTrackStats: <
    MEDIA_TYPE extends MediaType,
    RESULT extends MEDIA_TYPE extends 'audio'
      ? RTCPublisherPeerConnectionStatsAudioTrackMapped
      : RTCPublisherPeerConnectionStatsVideoTrackMapped,
  >(
    participantId: JazzRoomParticipantId,
    mediaType: MEDIA_TYPE,
  ) => RESULT | RESULT[] | undefined;
  getSubscriberTrackStats: <
    MEDIA_TYPE extends MediaType,
    RESULT extends MEDIA_TYPE extends 'audio'
      ? RTCSubscriberPeerConnectionStatsAudioTrackMapped
      : RTCSubscriberPeerConnectionStatsVideoTrackMapped,
  >(
    participantId: JazzRoomParticipantId,
    mediaType: MEDIA_TYPE,
  ) => RESULT | undefined;
  collectClientMetrics: () => Promise<WebRTCMetricsCollected>;
};
type WebRTCMetricsCollected = {
  publisher?: RTCPublisherPeerConnectionStatsMapped;
  subscriber?: RTCSubscriberPeerConnectionStatsMapped;
};
/**
 * @deprecated use on/once/off new API
 */
type WebRTCMetricsEventDeprecated =
  /**
   * события отправки сырой статистики
   */
  | {
      type: 'pcPublisherInitMetrics';
      payload: WebRTCMetricsEvent['pcPublisherInitMetrics'];
    }
  | {
      type: 'pcSubscriberInitMetrics';
      payload: WebRTCMetricsEvent['pcSubscriberInitMetrics'];
    }
  /**
   * события отправки распарсеной статистики
   */
  | {
      type: 'pcPublisherMetrics';
      payload: WebRTCMetricsEvent['pcPublisherMetrics'];
    }
  | {
      type: 'pcSubscriberMetrics';
      payload: WebRTCMetricsEvent['pcSubscriberMetrics'];
    }
  | {
      type: 'mediaStartPerformance';
      payload: WebRTCMetricsEvent['mediaStartPerformance'];
    };
type WebRTCMetricsEvent = {
  /**
   * события отправки сырой статистики
   */
  pcPublisherInitMetrics: {
    stats: RTCStatsReport;
  };
  pcSubscriberInitMetrics: {
    stats: RTCStatsReport;
  };
  /**
   * события отправки распарсеной статистики
   */
  pcPublisherMetrics: {
    stats: RTCPublisherPeerConnectionStatsMapped;
  };
  pcSubscriberMetrics: {
    stats: RTCSubscriberPeerConnectionStatsMapped;
  };
  /** событие времени старта медийки */
  mediaStartPerformance: MediaStartPerformance;
};
type MediaStartPerformance = {
  roomConnected: number;
  transportConnected: number;
  mediaSessionTime: number;
  iceConnected: number;
};
/**
 * A service for collecting media statistics from PeerConnection.
 * It collects metrics for publisher and subscriber separately.
 * Metrics can be obtained by subscribing to events.
 */
type WebRTCMetricsService = {
  publisherStats: Atom<RTCPublisherPeerConnectionStatsMapped | undefined>;
  subscriberStats: Atom<RTCSubscriberPeerConnectionStatsMapped | undefined>;
  mediaStartPerformance: Atom<Partial<MediaStartPerformance>>;
  /**
   * @deprecated use on/once/off new API
   */
  events: Signal<WebRTCMetricsEventDeprecated>;
  on: TransportRoot<WebRTCMetricsEvent>['on'];
  once: TransportRoot<WebRTCMetricsEvent>['once'];
  off: TransportRoot<WebRTCMetricsEvent>['off'];
  startCollectMetrics: () => void;
  stopCollectMetrics: () => void;
  collectClientMetrics: WebRTCMetricsControllerService['collectClientMetrics'];
  getPublisherTrackStats: WebRTCMetricsControllerService['getPublisherTrackStats'];
  getSubscriberTrackStats: WebRTCMetricsControllerService['getSubscriberTrackStats'];
};

declare function getMediaMetricsService(room: JazzRoom): WebRTCMetricsService;
declare function getConnectionQualityService(
  room: JazzRoom,
): ConnectionQualityService;

type LogsPluginOptions = Readonly<{
  /**
   * @default 'info'
   */
  logLevel?: LogLevel;
  /**
   * @default true
   */
  isEnableStdout?: boolean;
  subscribe?: (event: LogEvent) => void;
}>;
/**
 * Позволяет подписаться на события логов в JazzSDK
 */
declare function logsPlugin(options?: LogsPluginOptions): JazzSdkPlugin;

export {
  AUDIO_GAIN_DEFAULT,
  type AudioMixerEvent,
  type AudioMixerEventAddMediaStream,
  type AudioMixerEventGainChanged,
  type AudioMixerEventRemoveMediaStream,
  type AudioMixerEventStartAudio,
  type AudioMixerEventStartedAudio,
  type AudioMixerEventStopAudio,
  type AudioMixerEventStoppedAudio,
  type AudioOutputMixer,
  type AudioOutputMixerContext,
  type AudioOutputMixerManager,
  type ConnectionQualities,
  type ConnectionQuality,
  type ConnectionQualityEvents,
  type ConnectionQualityEventsDeprecated,
  type ConnectionQualityName,
  type ConnectionQualityService,
  type ConnectionStatus,
  type ElementDeprecated,
  MAX_AUDIO_GAIN_VALUE,
  MIN_AUDIO_GAIN_VALUE,
  type MediaMetricsPluginOptions,
  type MediaMetricsPluginSettings,
  type MediaStartPerformance,
  type PausedMediaTypesDeprecated,
  type RTCAudioPlayoutStats,
  type RTCAudioSourceStats,
  type RTCAudioSourceStatsMapped,
  type RTCCertificateStats,
  type RTCCodecStats,
  type RTCCommonPeerConnectionStatsBandWidth,
  type RTCCommonPeerConnectionStatsMapped,
  type RTCCommonPeerConnectionStatsReading,
  type RTCCommonStats,
  type RTCDataChannelStats,
  type RTCIceCandidatePairStats,
  type RTCIceCandidateStats,
  type RTCIceLocalCandidateStats,
  type RTCIceLocalCandidateStatsMapped,
  type RTCIceRemoteCandidateStats,
  type RTCIceRemoteCandidateStatsMapped,
  type RTCInboundRtpAudioStreamStats,
  type RTCInboundRtpStreamStats,
  type RTCInboundRtpVideoStreamStats,
  type RTCMediaSourceStats,
  type RTCOutboundRtpAudioStreamStats,
  type RTCOutboundRtpStreamStats,
  type RTCOutboundRtpVideoStreamStats,
  type RTCPacketsStats,
  type RTCPeerConnectionStats,
  type RTCPublisherPeerConnectionStats,
  type RTCPublisherPeerConnectionStatsAudioTrackMapped,
  type RTCPublisherPeerConnectionStatsAudioTracksMapped,
  type RTCPublisherPeerConnectionStatsMapped,
  type RTCPublisherPeerConnectionStatsReading,
  type RTCPublisherPeerConnectionStatsTrackMapped,
  type RTCPublisherPeerConnectionStatsVideoTrackMapped,
  type RTCPublisherPeerConnectionStatsVideoTracksMapped,
  type RTCReceivedRtpStreamStats,
  type RTCRemoteInboundRtpAudioStreamStats,
  type RTCRemoteInboundRtpStreamStats,
  type RTCRemoteInboundRtpVideoStreamStats,
  type RTCRemoteOutboundRtpStreamStats,
  type RTCRtpStreamStats,
  type RTCSentRtpStreamStats,
  type RTCSubscriberPeerConnectionStats,
  type RTCSubscriberPeerConnectionStatsAudioTrackMapped,
  type RTCSubscriberPeerConnectionStatsAudioTracksMapped,
  type RTCSubscriberPeerConnectionStatsMapped,
  type RTCSubscriberPeerConnectionStatsReading,
  type RTCSubscriberPeerConnectionStatsTrackMapped,
  type RTCSubscriberPeerConnectionStatsVideoTrackMapped,
  type RTCSubscriberPeerConnectionStatsVideoTracksMapped,
  type RTCTransportStats,
  type RTCVideoSourceStats,
  type RTCVideoSourceStatsMapped,
  type RoomRecordingServiceClient,
  type RoomServerRecordingStatus,
  type RoomServerRecordingSupportedStatus,
  ServerRecordingError,
  type ServerRecordingEventAutoStartError,
  type ServerRecordingEventError,
  type ServerRecordingEventStartError,
  type ServerRecordingEventStarted,
  type ServerRecordingEventStopError,
  type ServerRecordingEventStopped,
  type ServerRecordingEventUploadError,
  type ServerRecordingEventUploaded,
  type ServerRecordingEvents,
  type ServerRecordingMessages,
  type ServerRecordingRoomService,
  type ServerRecordingStartErrorEvent,
  type ServerRecordingStopErrorEvent,
  type VideoElementPoolEventDeprecated,
  type VideoElementPoolForRoomDeprecated,
  type VideoElementPoolForRoomElement,
  type VideoElementPoolForRoomElementEvents,
  type VideoElementPoolForRoomElementEventsDeprecated,
  type VideoElementPoolForRoomEvents,
  type VideoElementPoolForRoomEventsDeprecated,
  type VideoElementPoolForRoomRequestVideoElement,
  type VideoElementPoolForRoomService,
  type VideoElementPoolForRoomVideoSizeSettings,
  type VideoElementPoolForRoomVideoSource,
  type VideoElementPoolGlobalElementEvents,
  type VideoElementPoolGlobalElementEventsDeprecated,
  type VideoElementPoolGlobalElementForStream,
  type VideoElementPoolGlobalEvents,
  type VideoElementPoolGlobalEventsDeprecated,
  type VideoElementPoolGlobalService,
  type VideoElementPoolGlobalSettings,
  type VideoElementPoolManagerDeprecated,
  type VideoElementPoolPluginOptions,
  type VideoElementPoolSettings,
  type VideoElementPoolSettingsPausedSources,
  type VideoElementPoolSettingsVideoSource,
  type VideoElementPoolStreamSize,
  type WebRTCMetricsCollected,
  type WebRTCMetricsEvent,
  type WebRTCMetricsEventDeprecated,
  type WebRTCMetricsService,
  atomToRxEffectsQuery,
  atomToRxObserve,
  audioOutputMixerPlugin,
  getAppVideoElementPool,
  getAudioOutputMixer,
  getAudioOutputMixerManager,
  getConnectionQualityService,
  getMediaMetricsService,
  getServerRecording,
  getServerRecordingClient,
  getVideoElementPool,
  getVideoElementPoolForRoom,
  getVideoElementPoolManager,
  logsPlugin,
  mediaMetricsPlugin,
  serverRecordingPlugin,
  signalToRxEffectsAction,
  signalToRxObserve,
  subscribeAtom,
  videoElementPoolPlugin,
};
