@salutejs/jazz-sdk-web-plugins
Version:
Jazz SDK plugins
1,552 lines (1,505 loc) • 91.6 kB
TypeScript
import { Signal, Atom, Scope } from 'nrgy';
import {
EventError,
EventOk,
SyncResult,
HttpClientFetchError,
HttpClientResponseError,
JazzSdkPlugin,
JazzRoomExtender,
JazzRoom,
JazzClientExtender,
JazzClient,
Extender,
MakeExtender,
QueryAtom,
ConfigFlags,
Query,
JazzRoomParticipantId,
LocalAudioOutputDevice,
JazzSdk,
MediaType,
LogLevel,
LogEvent,
ResultSuccess,
ResultFailure,
EventBus,
DeepUnion,
MeetingHistory,
Timestamp,
JazzRoomParticipantRole,
CollectMetricsHandler,
CollectMetricsMetric,
CollectMetricsMeta,
CollectMetricsMetricData,
CollectMetricsMetaActions,
ResponseExtender,
} from '@salutejs/jazz-sdk-web';
import { Controller } from 'nrgy/mvc';
import { Observable } from 'rxjs';
import { Controller as Controller$1 } from 'rx-effects';
import { toQuery, toAction } from 'nrgy/rx-effects';
import { observe } from 'nrgy/rxjs';
import * as ditox from 'ditox';
import { ModuleDeclaration } from 'ditox';
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'
>;
type GetVideoStorageResponse = {
usedMb: number;
availableMb?: number;
capacityMb: 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;
};
status: 'UPLOADED' | 'STOPPED';
};
type GetVideoResponse = VideoRecord;
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: <R extends JazzRoomExtender[]>(
jazzRoom: JazzRoom<R>,
) => ServerRecordingRoomService;
declare const getServerRecordingClient: <
R extends JazzRoomExtender[],
C extends JazzClientExtender[],
>(
jazzRoom: JazzRoom<R> | JazzClient<C>,
) => RoomRecordingServiceClient;
type ServerRecordingCreateRoomParams = {
serverVideoRecordAutoStartEnabled: boolean;
};
declare const withServerRecordingCreateRoom: (
params: ServerRecordingCreateRoomParams,
) => Extender;
type ServerRecordingJazzRoom = MakeExtender<
JazzRoomExtender,
{
permissions: {
canStartServerVideoRecord?: boolean;
};
}
>;
type ServerRecordingJazzClient = MakeExtender<
JazzClientExtender,
{
userInfo: {
features: {
serverVideoRecordAvailable?: boolean;
};
};
}
>;
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: Atom<boolean>;
isReady: Atom<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: Atom<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<{
sampleRate?: number;
latencyHint: string;
}>;
type AudioTrack = {
participantId: JazzRoomParticipantId;
mediaStream: MediaStream;
};
type AudioMixerParticipantsManager = Controller$1<{
$mutedParticipants: Query<ReadonlySet<JazzRoomParticipantId>>;
addTracks: (tracks: AudioTrack[]) => void;
removeTracks: (tracks: AudioTrack[]) => void;
removeAllTracks: () => void;
muteParticipants: (
isMuted: boolean,
ids: Array<JazzRoomParticipantId>,
) => void;
}>;
type AudioOutputMixer = {
/**
* @deprecated use isSuspended
*/
$isSuspended: Query<boolean>;
isSuspended: Atom<boolean>;
event$: Observable<AudioMixerEvent>;
startAudio: () => Promise<void>;
stopAudio: () => Promise<void>;
setOutputDevice: (audioOutput: LocalAudioOutputDevice) => Promise<void>;
outputGain: QueryAtom<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>;
audioLevelAnimationInterval?: number | undefined;
checkLoadFirstAudioPackage?: boolean;
}>;
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: QueryAtom<ReadonlySet<JazzRoomParticipantId>>;
isMutedAll: QueryAtom<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;
/**
* Event name for subscribe to all events in transport
*/
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>;
}
/**
* A node that has a cleanup mechanism. After the method chchchch is executed,
* the node becomes inactive because event subscriptions and message sending stop functioning.
*/
declare interface DestroyedNode {
/**
* whether the transport is destroyed.
* If the transport is destroyed,
* then subscriptions and event sending do not work, and the subscriber list is destroyed.
* Also, all dependent nodes are automatically unsubscribed from the destroyed node.
*/
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>>
>;
};
/**
* List of nodes the node is subscribed to.
*/
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;
};
};
/**
* Сервис для работы с общими настройками
* возможности запускать видео элементы
*
* Применяется как глобально, так и для
* videoElementPoolForRoom
*/
type VideoElementPoolSettingsService = {
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 VideoElementPoolStreamSize = {
width: number;
height: number;
};
type VideoElementPoolGlobalEvents = VideoElementPoolSettingsEvents;
type VideoElementPoolGlobalElementEvents = {
pausedChange: {
isPaused: boolean;
};
/**
* стрим загружен в видео элемент
* и готов для отображения на странице
*/
isLoadingStreamChange: {
isLoading: boolean;
};
streamUpdate: {
stream: MediaStream | null | undefined;
};
};
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>;
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 = {
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;
};
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;
};
/**
* Сервис для взаимодействия с реальными displayEndpoints
*
* В зону ответственности входит отслеживание видимости
* и размеров видео элементов, а также запущены они или нет
* и в зависимости от этих знаний дергает нужные ручки
*
* Элемент будет зарегистрирован в реальных displayEndpoints
* только если он виден на странице и не стоит на паузе
*/
type DisplayEndpointsService = {
events: TransportReadonlyNode<DisplayEndpointsEvents>;
registerElement: (
participantId: JazzRoomParticipantId,
request: RequestVideoElement,
element: HTMLVideoElement,
isMountedInDOMPromise: Promise<void>,
) => void;
unregisterElement: (element: HTMLVideoElement) => void;
/**
* Метод для ручной активации элемента. Используется если у элемента нет стрима,
* напр. с подписками в Next.
*/
activateElement: (element: HTMLVideoElement) => void;
deactivateElement: (element: HTMLVideoElement) => void;
/**
* Метод отписки подписчикоков на resize и intersection
*/
unsubscribeWatchObserver: (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;
clearAllTimers: () => void;
};
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;
};
};
type VideoElementPoolForRoomEvents = VideoElementPoolSettingsEvents &
DisplayEndpointsEvents;
type VideoElementPoolForRoomVideoSource = Exclude<MediaType, 'audio'>;
type VideoElementPoolForRoomVideoSizeSettings = {
width: number;
height: number;
};
type VideoElementPoolForRoomElementEvents = RoomVideoElementsVideoEvents;
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>;
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>;
/**
* Нужно ли дожидаться, когда видео будет смонтировано в DOM
* @default true
*/
waitForMountingInDOM?: boolean;
};
/**
* Сервис для работы с видео элементами в комнате
*/
type VideoElementPoolForRoomService = {
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 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 0 size (unsunscribe).
* When the queue is released, their quality is restored to the originally requested one.
*
* @default true
*/
maxQualitySubscribersLimitEnabled: boolean;
/**
* The maximum n