livekit-client
Version:
JavaScript/TypeScript client SDK for LiveKit
180 lines (149 loc) • 4.93 kB
text/typescript
import { Encryption_Type } from '@livekit/protocol';
import type {
SubscriptionError,
TrackInfo,
UpdateSubscription,
UpdateTrackSettings,
} from '@livekit/protocol';
import { EventEmitter } from 'events';
import type TypedEventEmitter from 'typed-emitter';
import log, { LoggerNames, getLogger } from '../../logger';
import { TrackEvent } from '../events';
import type { LoggerOptions, TranscriptionSegment } from '../types';
import LocalAudioTrack from './LocalAudioTrack';
import LocalVideoTrack from './LocalVideoTrack';
import RemoteAudioTrack from './RemoteAudioTrack';
import type RemoteTrack from './RemoteTrack';
import RemoteVideoTrack from './RemoteVideoTrack';
import { Track } from './Track';
import { getLogContextFromTrack } from './utils';
export class TrackPublication extends (EventEmitter as new () => TypedEventEmitter<PublicationEventCallbacks>) {
kind: Track.Kind;
trackName: string;
trackSid: Track.SID;
track?: Track;
source: Track.Source;
/** MimeType of the published track */
mimeType?: string;
/** dimension of the original published stream, video-only */
dimensions?: Track.Dimensions;
/** true if track was simulcasted to server, video-only */
simulcasted?: boolean;
/** @internal */
trackInfo?: TrackInfo;
protected metadataMuted: boolean = false;
protected encryption: Encryption_Type = Encryption_Type.NONE;
protected log = log;
private loggerContextCb?: LoggerOptions['loggerContextCb'];
constructor(kind: Track.Kind, id: string, name: string, loggerOptions?: LoggerOptions) {
super();
this.log = getLogger(loggerOptions?.loggerName ?? LoggerNames.Publication);
this.loggerContextCb = this.loggerContextCb;
this.setMaxListeners(100);
this.kind = kind;
this.trackSid = id;
this.trackName = name;
this.source = Track.Source.Unknown;
}
/** @internal */
setTrack(track?: Track) {
if (this.track) {
this.track.off(TrackEvent.Muted, this.handleMuted);
this.track.off(TrackEvent.Unmuted, this.handleUnmuted);
}
this.track = track;
if (track) {
// forward events
track.on(TrackEvent.Muted, this.handleMuted);
track.on(TrackEvent.Unmuted, this.handleUnmuted);
}
}
protected get logContext() {
return {
...this.loggerContextCb?.(),
...getLogContextFromTrack(this),
};
}
get isMuted(): boolean {
return this.metadataMuted;
}
get isEnabled(): boolean {
return true;
}
get isSubscribed(): boolean {
return this.track !== undefined;
}
get isEncrypted(): boolean {
return this.encryption !== Encryption_Type.NONE;
}
/**
* an [AudioTrack] if this publication holds an audio track
*/
get audioTrack(): LocalAudioTrack | RemoteAudioTrack | undefined {
if (this.track instanceof LocalAudioTrack || this.track instanceof RemoteAudioTrack) {
return this.track;
}
}
/**
* an [VideoTrack] if this publication holds a video track
*/
get videoTrack(): LocalVideoTrack | RemoteVideoTrack | undefined {
if (this.track instanceof LocalVideoTrack || this.track instanceof RemoteVideoTrack) {
return this.track;
}
}
handleMuted = () => {
this.emit(TrackEvent.Muted);
};
handleUnmuted = () => {
this.emit(TrackEvent.Unmuted);
};
/** @internal */
updateInfo(info: TrackInfo) {
this.trackSid = info.sid;
this.trackName = info.name;
this.source = Track.sourceFromProto(info.source);
this.mimeType = info.mimeType;
if (this.kind === Track.Kind.Video && info.width > 0) {
this.dimensions = {
width: info.width,
height: info.height,
};
this.simulcasted = info.simulcast;
}
this.encryption = info.encryption;
this.trackInfo = info;
this.log.debug('update publication info', { ...this.logContext, info });
}
}
export namespace TrackPublication {
export enum SubscriptionStatus {
Desired = 'desired',
Subscribed = 'subscribed',
Unsubscribed = 'unsubscribed',
}
export enum PermissionStatus {
Allowed = 'allowed',
NotAllowed = 'not_allowed',
}
}
export type PublicationEventCallbacks = {
muted: () => void;
unmuted: () => void;
ended: (track?: Track) => void;
updateSettings: (settings: UpdateTrackSettings) => void;
subscriptionPermissionChanged: (
status: TrackPublication.PermissionStatus,
prevStatus: TrackPublication.PermissionStatus,
) => void;
updateSubscription: (sub: UpdateSubscription) => void;
subscribed: (track: RemoteTrack) => void;
unsubscribed: (track: RemoteTrack) => void;
subscriptionStatusChanged: (
status: TrackPublication.SubscriptionStatus,
prevStatus: TrackPublication.SubscriptionStatus,
) => void;
subscriptionFailed: (error: SubscriptionError) => void;
transcriptionReceived: (transcription: TranscriptionSegment[]) => void;
timeSyncUpdate: (timestamp: number) => void;
};