@fishjam-cloud/ts-client
Version:
Typescript client library for Fishjam
1,301 lines (1,285 loc) • 64.3 kB
text/typescript
import { BinaryWriter, BinaryReader } from '@bufbuild/protobuf/wire';
import TypedEmitter from 'typed-emitter';
declare const AUTH_ERROR_REASONS: readonly ["missing token", "invalid token", "expired token", "room not found", "peer not found"];
type AuthErrorReason = (typeof AUTH_ERROR_REASONS)[number];
declare const isAuthError: (error: string) => error is AuthErrorReason;
declare const normalizeCloseReason: (reason: string) => string;
declare class TrackTypeError extends Error {
constructor();
}
declare enum PeerMessage_SdkDeprecation_Status {
STATUS_UNSPECIFIED = 0,
STATUS_UP_TO_DATE = 1,
STATUS_DEPRECATED = 2,
STATUS_UNSUPPORTED = 3,
UNRECOGNIZED = -1
}
/** Deprecation status for SDK version */
interface PeerMessage_SdkDeprecation {
status: PeerMessage_SdkDeprecation_Status;
message: string;
}
declare const PeerMessage_SdkDeprecation: MessageFns$3<PeerMessage_SdkDeprecation>;
type Builtin$3 = Date | Function | Uint8Array | string | number | boolean | undefined;
type DeepPartial$3<T> = T extends Builtin$3 ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial$3<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial$3<U>> : T extends {} ? {
[K in keyof T]?: DeepPartial$3<T[K]>;
} : Partial<T>;
type KeysOfUnion$3<T> = T extends T ? keyof T : never;
type Exact$3<P, I extends P> = P extends Builtin$3 ? P : P & {
[K in keyof P]: Exact$3<P[K], I[K]>;
} & {
[K in Exclude<keyof I, KeysOfUnion$3<P>>]: never;
};
interface MessageFns$3<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
fromJSON(object: any): T;
toJSON(message: T): unknown;
create<I extends Exact$3<DeepPartial$3<T>, I>>(base?: I): T;
fromPartial<I extends Exact$3<DeepPartial$3<T>, I>>(object: I): T;
}
declare const getLogger: (enableLogging: boolean) => {
readonly debug: (arg: unknown, ...args: unknown[]) => void;
readonly warn: (arg: unknown, ...args: unknown[]) => void;
readonly error: (arg: unknown, ...args: unknown[]) => void;
};
declare enum Variant {
VARIANT_UNSPECIFIED = 0,
VARIANT_LOW = 1,
VARIANT_MEDIUM = 2,
VARIANT_HIGH = 3,
UNRECOGNIZED = -1
}
/** Contains information about an ICE candidate which will be sent to the peer/server */
interface Candidate {
candidate: string;
sdpMLineIndex: number;
sdpMid: string;
usernameFragment: string;
}
declare const Candidate: MessageFns$2<Candidate>;
type Builtin$2 = Date | Function | Uint8Array | string | number | boolean | undefined;
type DeepPartial$2<T> = T extends Builtin$2 ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial$2<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial$2<U>> : T extends {} ? {
[K in keyof T]?: DeepPartial$2<T[K]>;
} : Partial<T>;
type KeysOfUnion$2<T> = T extends T ? keyof T : never;
type Exact$2<P, I extends P> = P extends Builtin$2 ? P : P & {
[K in keyof P]: Exact$2<P[K], I[K]>;
} & {
[K in Exclude<keyof I, KeysOfUnion$2<P>>]: never;
};
interface MessageFns$2<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
fromJSON(object: any): T;
toJSON(message: T): unknown;
create<I extends Exact$2<DeepPartial$2<T>, I>>(base?: I): T;
fromPartial<I extends Exact$2<DeepPartial$2<T>, I>>(object: I): T;
}
/** Defines any type of message sent from Peer to Membrane RTC Engine */
interface MediaEvent$1 {
connect?: MediaEvent_Connect | undefined;
disconnect?: MediaEvent_Disconnect | undefined;
updateEndpointMetadata?: MediaEvent_UpdateEndpointMetadata | undefined;
updateTrackMetadata?: MediaEvent_UpdateTrackMetadata | undefined;
renegotiateTracks?: MediaEvent_RenegotiateTracks | undefined;
candidate?: Candidate | undefined;
sdpOffer?: MediaEvent_SdpOffer | undefined;
trackBitrates?: MediaEvent_TrackBitrates | undefined;
enableTrackVariant?: MediaEvent_EnableTrackVariant | undefined;
disableTrackVariant?: MediaEvent_DisableTrackVariant | undefined;
setTargetTrackVariant?: MediaEvent_SetTargetTrackVariant | undefined;
unmuteTrack?: MediaEvent_UnmuteTrack | undefined;
}
declare const MediaEvent$1: MessageFns$1<MediaEvent$1>;
interface MediaEvent_VariantBitrate {
variant: Variant;
bitrate: number;
}
declare const MediaEvent_VariantBitrate: MessageFns$1<MediaEvent_VariantBitrate>;
/** Sent when a peer wants to join WebRTC Endpoint. */
interface MediaEvent_Connect {
metadataJson: string;
}
declare const MediaEvent_Connect: MessageFns$1<MediaEvent_Connect>;
/** Sent when a peer disconnects from WebRTC Endpoint. */
interface MediaEvent_Disconnect {
}
declare const MediaEvent_Disconnect: MessageFns$1<MediaEvent_Disconnect>;
/** Sent when a peer wants to update its metadata */
interface MediaEvent_UpdateEndpointMetadata {
metadataJson: string;
}
declare const MediaEvent_UpdateEndpointMetadata: MessageFns$1<MediaEvent_UpdateEndpointMetadata>;
/** Sent when a peer wants to update its track's metadata */
interface MediaEvent_UpdateTrackMetadata {
trackId: string;
metadataJson: string;
}
declare const MediaEvent_UpdateTrackMetadata: MessageFns$1<MediaEvent_UpdateTrackMetadata>;
/** Sent when peer wants to renegotiate connection due to adding a track or removing a track */
interface MediaEvent_RenegotiateTracks {
}
declare const MediaEvent_RenegotiateTracks: MessageFns$1<MediaEvent_RenegotiateTracks>;
/**
* Sent as a response to `offerData` media event during renegotiation
* Maps contain only information about current peer's `sendonly` tracks.
* The "mid" is an identifier used to associate an RTP packet with an MLine from the SDP offer/answer.
*/
interface MediaEvent_SdpOffer {
/** The value of the `sessionDescription.sdp` */
sdp: string;
trackIdToMetadataJson: {
[key: string]: string;
};
/** Maps track_id to its bitrate. The track_id in the TrackBitrates message is ignored (we use the map key), so it can be omitted. */
trackIdToBitrates: {
[key: string]: MediaEvent_TrackBitrates;
};
midToTrackId: {
[key: string]: string;
};
}
declare const MediaEvent_SdpOffer: MessageFns$1<MediaEvent_SdpOffer>;
/** Sent when Peer wants to update its track's bitrate */
interface MediaEvent_TrackBitrates {
trackId: string;
/** Bitrate of each variant. For non-simulcast tracks use VARIANT_UNSPECIFIED. */
variantBitrates: MediaEvent_VariantBitrate[];
}
declare const MediaEvent_TrackBitrates: MessageFns$1<MediaEvent_TrackBitrates>;
/** Sent when client disables one of the track variants */
interface MediaEvent_DisableTrackVariant {
trackId: string;
variant: Variant;
}
declare const MediaEvent_DisableTrackVariant: MessageFns$1<MediaEvent_DisableTrackVariant>;
/** Sent when client enables one of the track variants */
interface MediaEvent_EnableTrackVariant {
trackId: string;
variant: Variant;
}
declare const MediaEvent_EnableTrackVariant: MessageFns$1<MediaEvent_EnableTrackVariant>;
interface MediaEvent_SetTargetTrackVariant {
trackId: string;
variant: Variant;
}
declare const MediaEvent_SetTargetTrackVariant: MessageFns$1<MediaEvent_SetTargetTrackVariant>;
interface MediaEvent_UnmuteTrack {
trackId: string;
}
declare const MediaEvent_UnmuteTrack: MessageFns$1<MediaEvent_UnmuteTrack>;
type Builtin$1 = Date | Function | Uint8Array | string | number | boolean | undefined;
type DeepPartial$1<T> = T extends Builtin$1 ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial$1<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial$1<U>> : T extends {} ? {
[K in keyof T]?: DeepPartial$1<T[K]>;
} : Partial<T>;
type KeysOfUnion$1<T> = T extends T ? keyof T : never;
type Exact$1<P, I extends P> = P extends Builtin$1 ? P : P & {
[K in keyof P]: Exact$1<P[K], I[K]>;
} & {
[K in Exclude<keyof I, KeysOfUnion$1<P>>]: never;
};
interface MessageFns$1<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
fromJSON(object: any): T;
toJSON(message: T): unknown;
create<I extends Exact$1<DeepPartial$1<T>, I>>(base?: I): T;
fromPartial<I extends Exact$1<DeepPartial$1<T>, I>>(object: I): T;
}
interface MediaEvent_Track_SimulcastConfig {
enabled: boolean;
enabledVariants: Variant[];
disabledVariants: Variant[];
}
declare const MediaEvent_Track_SimulcastConfig: MessageFns<MediaEvent_Track_SimulcastConfig>;
interface MediaEvent_OfferData_TrackTypes {
audio: number;
video: number;
}
declare const MediaEvent_OfferData_TrackTypes: MessageFns<MediaEvent_OfferData_TrackTypes>;
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
type DeepPartial<T> = T extends Builtin ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? {
[K in keyof T]?: DeepPartial<T[K]>;
} : Partial<T>;
type KeysOfUnion<T> = T extends T ? keyof T : never;
type Exact<P, I extends P> = P extends Builtin ? P : P & {
[K in keyof P]: Exact<P[K], I[K]>;
} & {
[K in Exclude<keyof I, KeysOfUnion<P>>]: never;
};
interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
fromJSON(object: any): T;
toJSON(message: T): unknown;
create<I extends Exact<DeepPartial<T>, I>>(base?: I): T;
fromPartial<I extends Exact<DeepPartial<T>, I>>(object: I): T;
}
type SerializedMediaEvent = Uint8Array;
interface MediaEvent {
type: keyof MediaEvent$1;
key?: string;
data?: any;
}
type MediaStreamTrackId = string;
type TrackKind = 'audio' | 'video';
/**
* Type describing Voice Activity Detection statuses.
*
* - `speech` - voice activity has been detected
* - `silence` - lack of voice activity has been detected
*/
type VadStatus = 'speech' | 'silence';
/**
* Type describing maximal bandwidth that can be used, in kbps. 0 is interpreted as unlimited bandwidth.
*/
type BandwidthLimit = number;
/**
* Type describing bandwidth limit for simulcast track.
* It is a mapping (encoding => BandwidthLimit).
* If encoding isn't present in this mapping, it will be assumed that this particular encoding shouldn't have any bandwidth limit
*/
type SimulcastBandwidthLimit = Map<Variant, BandwidthLimit>;
/**
* Type describing bandwidth limitation of a Track, including simulcast and non-simulcast tracks.
* A sum type of `BandwidthLimit` and `SimulcastBandwidthLimit`
*/
type TrackBandwidthLimit = BandwidthLimit | SimulcastBandwidthLimit;
/**
* Type describing possible reasons for currently selected encoding.
* - `other` - the exact reason couldn't be determined
* - `encodingInactive` - previously selected encoding became inactive
* - `lowBandwidth` - there is no longer enough bandwidth to maintain previously selected encoding
*/
type EncodingReason = 'other' | 'encodingInactive' | 'lowBandwidth';
/**
* Track's context i.e. all data that can be useful when operating on track.
*/
interface TrackContextFields {
readonly track: MediaStreamTrack | null;
/**
* Stream this track belongs to.
*/
readonly stream: MediaStream | null;
/**
* Endpoint this track comes from.
*/
readonly endpoint: Endpoint;
/**
* Track id. It is generated by RTC engine and takes form `endpoint_id:<random_uuidv4>`.
* It is WebRTC agnostic i.e. it does not contain `mid` or `stream id`.
*/
readonly trackId: string;
/**
* Simulcast configuration.
* Only present for local tracks.
*/
readonly simulcastConfig?: MediaEvent_Track_SimulcastConfig;
/**
* Any info that was passed in {@link WebRTCEndpoint.addTrack}.
*/
readonly metadata?: unknown;
readonly maxBandwidth?: TrackBandwidthLimit;
readonly vadStatus: VadStatus;
/**
* Encoding that is currently received.
* Only present for remote tracks.
*/
readonly encoding?: Variant;
/**
* The reason of currently selected encoding.
* Only present for remote tracks.
*/
readonly encodingReason?: EncodingReason;
}
interface TrackContextEvents$1 {
/**
* Emitted each time track encoding has changed.
*
* Track encoding can change in the following cases:
* - when user requested a change
* - when sender stopped sending some encoding (because of bandwidth change)
* - when receiver doesn't have enough bandwidth
*
* Some of those reasons are indicated in {@link TrackContext.encodingReason}.
*/
encodingChanged: (context: TrackContext) => void;
/**
* Emitted every time an update about voice activity is received from the server.
*/
voiceActivityChanged: (context: TrackContext) => void;
}
interface TrackContext extends TrackContextFields, TypedEmitter<Required<TrackContextEvents$1>> {
}
type TrackNegotiationStatus = 'awaiting' | 'offered' | 'done';
/**
* Events emitted by the {@link WebRTCEndpoint} instance.
*/
interface WebRTCEndpointEvents {
/**
* Emitted each time WebRTCEndpoint need to send some data to the server.
*/
sendMediaEvent: (mediaEvent: SerializedMediaEvent) => void;
/**
* Emitted when endpoint of this {@link WebRTCEndpoint} instance is ready. Triggered by {@link WebRTCEndpoint.connect}
*/
connected: (endpointId: string, otherEndpoints: Endpoint[]) => void;
/**
* Emitted when endpoint of this {@link WebRTCEndpoint} instance was removed.
*/
disconnected: () => void;
/**
* Emitted when data in a new track arrives.
*
* This event is always emitted after {@link trackAdded}.
* It informs the user that data related to the given track arrives and can be played or displayed.
*/
trackReady: (ctx: TrackContext) => void;
/**
* Emitted each time the endpoint which was already in the room, adds new track. Fields track and stream will be set to null.
* These fields will be set to non-null value in {@link trackReady}
*/
trackAdded: (ctx: TrackContext) => void;
/**
* Emitted when some track will no longer be sent.
*
* It will also be emitted before {@link endpointRemoved} for each track of this endpoint.
*/
trackRemoved: (ctx: TrackContext) => void;
/**
* Emitted each time endpoint has its track metadata updated.
*/
trackUpdated: (ctx: TrackContext) => void;
/**
* Emitted each time new endpoint is added to the room.
*/
endpointAdded: (endpoint: Endpoint) => void;
/**
* Emitted each time endpoint is removed, emitted only for other endpoints.
*/
endpointRemoved: (endpoint: Endpoint) => void;
/**
* Emitted each time endpoint has its metadata updated.
*/
endpointUpdated: (endpoint: Endpoint) => void;
/**
* Emitted in case of errors related to multimedia session e.g. ICE connection.
*/
connectionError: (error: {
message: string;
event: Event;
}) => void;
/**
* Emitted in case of errors related to multimedia session e.g. ICE connection.
*/
signalingError: (error: {
message: string;
}) => void;
/**
* Currently, this event is only emitted when DisplayManager in RTC Engine is
* enabled and simulcast is disabled.
*
* Emitted when priority of video tracks have changed.
* @param enabledTracks - list of tracks which will be sent to client from SFU
* @param disabledTracks - list of tracks which will not be sent to client from SFU
*/
tracksPriorityChanged: (enabledTracks: TrackContext[], disabledTracks: TrackContext[]) => void;
/**
* Emitted every time the server estimates client's bandwidth.
*
* @param {bigint} estimation - client's available incoming bitrate estimated
* by the server. It's measured in bits per second.
*/
bandwidthEstimationChanged: (estimation: bigint) => void;
/**
* Emitted each time track encoding has been disabled.
*/
trackEncodingDisabled: (context: TrackContext, encoding: Variant) => void;
/**
* Emitted each time track encoding has been enabled.
*/
trackEncodingEnabled: (context: TrackContext, encoding: Variant) => void;
targetTrackEncodingRequested: (event: {
trackId: string;
variant: Variant;
}) => void;
disconnectRequested: (event: any) => void;
localTrackAdded: (event: {
trackId: string;
track: MediaStreamTrack;
stream: MediaStream;
trackMetadata?: unknown;
simulcastConfig: MediaEvent_Track_SimulcastConfig;
maxBandwidth: TrackBandwidthLimit;
}) => void;
localTrackRemoved: (event: {
trackId: string;
}) => void;
localTrackReplaced: (event: {
trackId: string;
track: MediaStreamTrack | null;
}) => void;
localTrackMuted: (event: {
trackId: string;
}) => void;
localTrackUnmuted: (event: {
trackId: string;
}) => void;
localTrackBandwidthSet: (event: {
trackId: string;
bandwidth: BandwidthLimit;
}) => void;
localTrackEncodingBandwidthSet: (event: {
trackId: string;
rid: Variant;
bandwidth: BandwidthLimit;
}) => void;
localTrackEncodingEnabled: (event: {
trackId: string;
encoding: Variant;
}) => void;
localTrackEncodingDisabled: (event: {
trackId: string;
encoding: Variant;
}) => void;
localEndpointMetadataChanged: (event: {
metadata: unknown;
}) => void;
localTrackMetadataChanged: (event: {
trackId: string;
metadata: unknown;
}) => void;
/**
* Emitted when data channels (for both reliable and lossy) are created and ready to send data.
* This event is fired after calling connectDataChannels().
*/
dataChannelsReady: () => void;
/**
* Emitted when data is received on any data channel.
* The payload includes the channel type (reliable/lossy) and the binary data.
*/
dataChannelPayload: (payload: DataChannelMessagePayload) => void;
/**
* Emitted when any data channel errors.
*/
dataChannelsError: (error: Error) => void;
}
/**
* Interface describing Endpoint.
*/
interface Endpoint {
/**
* Endpoint's id. It is assigned by user in custom logic that use backend API.
*/
id: string;
/**
* Type of the endpoint, e.g. "webrtc", "hls" or "rtsp".
*/
type: string;
/**
* Any information that was provided in {@link WebRTCEndpoint.connect}.
*/
metadata?: unknown;
/**
* List of tracks that are sent by the endpoint.
*/
tracks: Map<string, TrackContext>;
}
/**
* Options for publishing or subscribing to data.
*/
interface DataChannelOptions {
/**
* If true, uses the reliable data channel (ordered, guaranteed delivery).
* If false, uses the lossy data channel (unordered, low latency).
*/
reliable: boolean;
}
/**
* Callback type for receiving data from a data channel.
* @param data - The received data as a Uint8Array
*/
type DataCallback = (data: Uint8Array) => void;
/**
* Internal type for channel classification
* @internal
*/
type DataChannelType = 'reliable' | 'lossy';
/**
* Payload for data received events from data channels.
*/
interface DataChannelMessagePayload {
/**
* The type of channel the data was received on.
*/
channelType: DataChannelType;
/**
* The binary payload data.
*/
data: Uint8Array;
}
type WebRTCEndpointProps = {
/**
* Enables Fishjam SDK's debug logs in the console.
*/
debug?: boolean;
};
type Logger = ReturnType<typeof getLogger>;
declare class ConnectionManager {
private readonly connection;
constructor(iceServers: RTCIceServer[]);
isConnectionUnstable: () => boolean;
getConnection: () => RTCPeerConnection;
addTransceiversIfNeeded: (serverTracks: MediaEvent_OfferData_TrackTypes) => void;
private static isLiveRecvTransceiver;
private stopExcessRecvTransceivers;
addTransceiver: (track: MediaStreamTrack, transceiverConfig: RTCRtpTransceiverInit) => void;
setOnTrackReady: (onTrackReady: (event: RTCTrackEvent) => void) => void;
setRemoteDescription: (data: RTCSessionDescriptionInit) => Promise<void>;
isTrackInUse: (track: MediaStreamTrack) => boolean;
removeTrack: (sender: RTCRtpSender) => void;
findSender: (mediaStreamTrackId: MediaStreamTrackId) => RTCRtpSender;
addIceCandidate: (iceCandidate: RTCIceCandidate) => Promise<void>;
createDataChannel: (label: string, config: RTCDataChannelInit) => RTCDataChannel;
}
declare const TrackContextImpl_base: new () => TypedEmitter<Required<TrackContextEvents$1>>;
declare class TrackContextImpl extends TrackContextImpl_base implements TrackContext {
endpoint: Endpoint;
trackId: string;
track: MediaStreamTrack | null;
trackKind: TrackKind | null;
stream: MediaStream | null;
metadata?: unknown;
metadataParsingError?: any;
simulcastConfig?: MediaEvent_Track_SimulcastConfig;
maxBandwidth: TrackBandwidthLimit;
encoding?: Variant;
encodingReason?: EncodingReason;
vadStatus: VadStatus;
negotiationStatus: TrackNegotiationStatus;
pendingMetadataUpdate: boolean;
constructor(endpoint: Endpoint, trackId: string, metadata: any, simulcastConfig?: MediaEvent_Track_SimulcastConfig);
}
type EndpointWithTrackContext = Omit<Endpoint, 'tracks'> & {
tracks: Map<string, TrackContextImpl>;
};
declare const WebRTCEndpoint_base: new () => TypedEmitter<Required<WebRTCEndpointEvents>>;
/**
* Main class that is responsible for connecting to the RTC Engine, sending and receiving media.
*/
declare class WebRTCEndpoint extends WebRTCEndpoint_base {
private readonly localTrackManager;
private readonly remote;
private readonly local;
private readonly commandsQueue;
private readonly dataChannelManager;
private proposedIceServers;
private logger;
bandwidthEstimation: bigint;
connectionManager?: ConnectionManager;
private clearConnectionCallbacks;
constructor(props?: WebRTCEndpointProps);
/**
* Tries to connect to the RTC Engine. If user is successfully connected then {@link WebRTCEndpointEvents.connected}
* will be emitted.
*
* @param metadata - Any information that other endpoints will receive in {@link WebRTCEndpointEvents.endpointAdded}
* after accepting this endpoint
*
* @example
* ```ts
* let webrtc = new WebRTCEndpoint();
* webrtc.connect({displayName: "Bob"});
* ```
*/
connect: (metadata: unknown) => void;
/**
* Returns the current audio level for a local audio track, if available.
*
* This method only works for local **audio** tracks that have been negotiated
* with the remote peer and for which an underlying `RTCRtpSender` and
* statistics are available.
*
* @param trackId - Identifier of the local track to query, as used when
* adding or managing local tracks on this endpoint.
* @returns A promise that resolves to `{ level: number }` when an audio
* level can be determined for the given track, or `null` if:
* - the track does not exist,
* - the track is not an audio track,
* - the track has not yet been negotiated / no sender exists
*/
getLocalTrackAudioLevel(trackId: string): Promise<{
level: number;
} | null>;
/**
* Feeds media event received from RTC Engine to {@link WebRTCEndpoint}.
* This function should be called whenever some media event from RTC Engine
* was received and can result in {@link WebRTCEndpoint} generating some other
* media events.
*
* @param mediaEvent - String data received over custom signalling layer.
*
* @example
* This example assumes phoenix channels as signalling layer.
* As phoenix channels require objects, RTC Engine encapsulates binary data into
* map with one field that is converted to object with one field on the TS side.
* ```ts
* webrtcChannel.on("mediaEvent", (event) => webrtc.receiveMediaEvent(event.data));
* ```
*/
private mediaEventQueue;
receiveMediaEvent: (mediaEvent: SerializedMediaEvent) => Promise<void>;
private handleConnected;
private getEndpointId;
private onTrackReady;
/**
* Retrieves statistics related to the RTCPeerConnection.
* These statistics provide insights into the performance and status of the connection.
*
* @return {Promise<RTCStatsReport>}
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/getStats | MDN Web Docs: RTCPeerConnection.getStats()}
*/
getStatistics(selector?: MediaStreamTrack | null): Promise<RTCStatsReport>;
/**
* Returns a snapshot of currently received remote tracks.
*
* @example
* if (webRTCEndpoint.getRemoteTracks()[trackId]?.simulcastConfig?.enabled) {
* webRTCEndpoint.setTargetTrackEncoding(trackId, encoding);
* }
*/
getRemoteTracks(): Record<string, TrackContext>;
/**
* Returns a snapshot of currently received remote endpoints.
*/
getRemoteEndpoints(): Record<string, EndpointWithTrackContext>;
getLocalEndpoint(): EndpointWithTrackContext;
getBandwidthEstimation(): bigint;
getDataChannelsReadiness(): boolean;
private handleMediaEvent;
private onSdpAnswer;
/**
* Adds track that will be sent to the RTC Engine.
* @param track - Audio or video track e.g. from your microphone or camera.
* @param trackMetadata - Any information about this track that other endpoints will
* receive in {@link WebRTCEndpointEvents.endpointAdded}. E.g. this can source of the track - whether it's
* screensharing, webcam or some other media device.
* @param simulcastConfig - Simulcast configuration. For more information refer to {@link SimulcastConfig}.
* @param maxBandwidth - maximal bandwidth this track can use. **Currently processed with a threshold check**:
* if the value is a positive number, it will be used; otherwise, it defaults to 0 (unlimited).
* This option has no effect for simulcast and audio tracks.
* For simulcast tracks use `{@link WebRTCEndpoint.setTrackBandwidth}.
* @returns {string} Returns id of added track
* @example
* ```ts
* let localStream: MediaStream = new MediaStream();
* try {
* localAudioStream = await navigator.mediaDevices.getUserMedia(
* AUDIO_CONSTRAINTS
* );
* localAudioStream
* .getTracks()
* .forEach((track) => localStream.addTrack(track));
* } catch (error) {
* this.logger.error("Couldn't get microphone permission:", error);
* }
*
* try {
* localVideoStream = await navigator.mediaDevices.getUserMedia(
* VIDEO_CONSTRAINTS
* );
* localVideoStream
* .getTracks()
* .forEach((track) => localStream.addTrack(track));
* } catch (error) {
* this.logger.error("Couldn't get camera permission:", error);
* }
*
* localStream
* .getTracks()
* .forEach((track) => webrtc.addTrack(track, localStream));
* ```
*/
addTrack(track: MediaStreamTrack, trackMetadata?: unknown, simulcastConfig?: MediaEvent_Track_SimulcastConfig, maxBandwidth?: TrackBandwidthLimit, stream?: MediaStream): Promise<string>;
/**
* Replaces a track that is being sent to the RTC Engine.
* @param trackId - Audio or video track.
* @param {string} trackId - Id of audio or video track to replace.
* @param {MediaStreamTrack} newTrack
* @returns {Promise<boolean>} success
* @example
* ```ts
* // setup camera
* let localStream: MediaStream = new MediaStream();
* try {
* localVideoStream = await navigator.mediaDevices.getUserMedia(
* VIDEO_CONSTRAINTS
* );
* localVideoStream
* .getTracks()
* .forEach((track) => localStream.addTrack(track));
* } catch (error) {
* this.logger.error("Couldn't get camera permission:", error);
* }
* let oldTrackId;
* localStream
* .getTracks()
* .forEach((track) => trackId = webrtc.addTrack(track, localStream));
*
* // change camera
* const oldTrack = localStream.getVideoTracks()[0];
* let videoDeviceId = "abcd-1234";
* navigator.mediaDevices.getUserMedia({
* video: {
* ...(VIDEO_CONSTRAINTS as {}),
* deviceId: {
* exact: videoDeviceId,
* },
* }
* })
* .then((stream) => {
* let videoTrack = stream.getVideoTracks()[0];
* webrtc.replaceTrack(oldTrackId, videoTrack);
* })
* .catch((error) => {
* this.logger.error('Error switching camera', error);
* })
* ```
*/
replaceTrack(trackId: string, newTrack: MediaStreamTrack | null): Promise<void>;
/**
* Updates maximum bandwidth for the track identified by trackId.
* This value directly translates to quality of the stream and, in case of video, to the amount of RTP packets being sent.
* In case trackId points at the simulcast track bandwidth is split between all of the variant streams proportionally to their resolution.
*
* @param {string} trackId
* @param {BandwidthLimit} bandwidth in kbps
* @returns {Promise<boolean>} success
*/
setTrackBandwidth(trackId: string, bandwidth: BandwidthLimit): Promise<void>;
/**
* Updates maximum bandwidth for the given simulcast encoding of the given track.
*
* @param {string} trackId - id of the track
* @param {string} rid - rid of the encoding
* @param {BandwidthLimit} bandwidth - desired max bandwidth used by the encoding (in kbps)
* @returns
*/
setEncodingBandwidth(trackId: string, rid: Variant, bandwidth: BandwidthLimit): Promise<void>;
/**
* Removes a track from connection that was sent to the RTC Engine.
* @param {string} trackId - Id of audio or video track to remove.
* @example
* ```ts
* // setup camera
* let localStream: MediaStream = new MediaStream();
* try {
* localVideoStream = await navigator.mediaDevices.getUserMedia(
* VIDEO_CONSTRAINTS
* );
* localVideoStream
* .getTracks()
* .forEach((track) => localStream.addTrack(track));
* } catch (error) {
* this.logger.error("Couldn't get camera permission:", error);
* }
*
* let trackId
* localStream
* .getTracks()
* .forEach((track) => trackId = webrtc.addTrack(track, localStream));
*
* // remove track
* webrtc.removeTrack(trackId)
* ```
*/
removeTrack(trackId: string): Promise<void>;
/**
* Sets track variant that server should send to the client library.
*
* The variant will be sent whenever it is available.
* If chosen variant is temporarily unavailable, some other variant
* will be sent until the chosen variant becomes active again.
*
* @param {string} trackId - id of track
* @param {Encoding} variant - variant to receive
* @example
* ```ts
* webrtc.setTargetTrackEncoding(incomingTrackCtx.trackId, "l")
* ```
*/
setTargetTrackEncoding(trackId: string, variant: Variant): void;
/**
* Enables track encoding so that it will be sent to the server.
* @param {string} trackId - id of track
* @param {Encoding} encoding - encoding that will be enabled
* @example
* ```ts
* const trackId = webrtc.addTrack(track, stream, {}, {enabled: true, activeEncodings: ["l", "m", "h"]});
* webrtc.disableTrackEncoding(trackId, "l");
* // wait some time
* webrtc.enableTrackEncoding(trackId, "l");
* ```
*/
enableTrackEncoding: (trackId: string, encoding: Variant) => Promise<void>;
/**
* Disables track encoding so that it will be no longer sent to the server.
* @param {string} trackId - id of track
* @param {Encoding} encoding - encoding that will be disabled
* @example
* ```ts
* const trackId = webrtc.addTrack(track, stream, {}, {enabled: true, activeEncodings: ["l", "m", "h"]});
* webrtc.disableTrackEncoding(trackId, "l");
* ```
*/
disableTrackEncoding: (trackId: string, encoding: Variant) => Promise<void>;
/**
* Updates the metadata for the current endpoint.
* @param metadata - Data about this endpoint that other endpoints will receive upon being added.
*
* If the metadata is different from what is already tracked in the room, the optional
* event `endpointUpdated` will be emitted for other endpoint in the room.
*/
updateEndpointMetadata: (metadata: any) => void;
/**
* Updates the metadata for a specific track.
* @param trackId - trackId (generated in addTrack) of audio or video track.
* @param trackMetadata - Data about this track that other endpoint will receive upon being added.
*
* If the metadata is different from what is already tracked in the room, the optional
* event `trackUpdated` will be emitted for other endpoints in the room.
*/
updateTrackMetadata: (trackId: string, trackMetadata: any) => void;
/**
* Disconnects from the room. This function should be called when user disconnects from the room
* in a clean way e.g. by clicking a dedicated, custom button `disconnect`.
* As a result there will be generated one more media event that should be
* sent to the RTC Engine. Thanks to it each other endpoint will be notified
* that endpoint was removed in {@link WebRTCEndpointEvents.endpointRemoved},
*/
disconnect: () => void;
/**
* Create both reliable and lossy data channel.
* This method must be called before publishData() can be used.
* Emits the 'dataChannelsReady' event when both channels are open and ready.
*
* @example
* ```ts
* const webrtc = new WebRTCEndpoint();
*
* webrtc.on('dataChannelsReady', () => {
* console.log('Data channels ready, can now send data');
* webrtc.publishData(new TextEncoder().encode('Hello'), { reliable: true });
* });
*
* webrtc.connectDataChannels();
* ```
*/
connectDataChannels: () => Promise<void>;
/**
* Publish data through a data channel.
* The data channels must be created first by calling connectDataChannels() or enabling negotiateOnConnect.
* Throws an error if the channel doesn't exist or isn't ready yet.
*
* @param data - The data to send as Uint8Array
* @param options - Options specifying which channel to use (reliable or lossy)
* @throws Error if the channel doesn't exist or isn't ready
*
* @example
* ```ts
* // Subscribe to incoming data
* webrtc.on('dataReceived', ({ channelType, data }) => {
* console.log(`Received on ${channelType}:`, new TextDecoder().decode(data));
* });
*
* webrtc.on('dataChannelsReady', () => {
* // Send reliable data
* const data = new TextEncoder().encode('Hello World');
* webrtc.publishData(data, { reliable: true });
*
* // Send lossy data for low-latency updates
* const gameState = new Uint8Array([1, 2, 3, 4, 5]);
* webrtc.publishData(gameState, { reliable: false });
* });
*
* webrtc.connectDataChannels();
* ```
*/
publishData: (data: Uint8Array, options: DataChannelOptions) => void;
/**
* Cleans up {@link WebRTCEndpoint} instance.
*/
cleanUp: () => void;
private getTrackId;
private sendMediaEvent;
private createAndSendOffer;
private onOfferData;
private setupConnectionListeners;
private createNewConnection;
private onRemoteCandidate;
private onLocalCandidate;
private onIceCandidateError;
private onConnectionStateChange;
private onIceConnectionStateChange;
}
declare const JOIN_ERRORS: readonly ["reached peers limit", "room not found", "node not found", "invalid sdk version"];
type JoinErrorReason = (typeof JOIN_ERRORS)[number];
declare const isJoinError: (error: string) => error is JoinErrorReason;
type ReconnectionStatus = 'reconnecting' | 'idle' | 'error';
type ReconnectConfig = {
maxAttempts?: number;
initialDelay?: number;
delay?: number;
addTracksOnReconnect?: boolean;
};
/**
* Metadata attached to a track published by a peer.
* Sent over the signaling channel so other peers know what kind of track they're receiving.
* @category Tracks
*/
type TrackMetadata = {
/** The kind of media this track carries. */
type: 'camera' | 'microphone' | 'screenShareVideo' | 'screenShareAudio' | 'customVideo' | 'customAudio';
/** Whether the track is currently muted/disabled. */
paused: boolean;
/** The peer's display name, used in recordings. */
displayName?: string;
};
type GenericMetadata = Record<string, unknown> | undefined;
/**
*
* @category Connection
* @typeParam PeerMetadata Type of metadata set by peer while connecting to a room.
* @typeParam ServerMetadata Type of metadata set by the server while creating a peer.
*/
type Metadata<PeerMetadata = GenericMetadata, ServerMetadata = GenericMetadata> = {
peer: PeerMetadata;
server: ServerMetadata;
};
type TrackContextEvents = {
encodingChanged: (context: FishjamTrackContext) => void;
voiceActivityChanged: (context: FishjamTrackContext) => void;
};
interface FishjamTrackContext extends TypedEmitter<TrackContextEvents> {
readonly track: MediaStreamTrack | null;
readonly stream: MediaStream | null;
readonly endpoint: Endpoint;
readonly trackId: string;
readonly simulcastConfig?: MediaEvent_Track_SimulcastConfig;
readonly metadata?: TrackMetadata;
readonly maxBandwidth?: TrackBandwidthLimit;
readonly vadStatus: VadStatus;
readonly encoding?: Variant;
readonly encodingReason?: EncodingReason;
}
type Peer<PeerMetadata = GenericMetadata, ServerMetadata = GenericMetadata> = {
id: string;
type: string;
metadata?: Metadata<PeerMetadata, ServerMetadata>;
tracks: Map<string, FishjamTrackContext>;
};
type Component = Omit<Endpoint, 'type'> & {
type: 'recording' | 'hls' | 'file' | 'rtsp' | 'sip';
};
/**
* Events emitted by the client with their arguments.
*/
type MessageEvents<P, S> = {
/**
* Emitted when connect method invoked
*
*/
connectionStarted: () => void;
/**
* Emitted when the websocket connection is closed
*
* @param {CloseEvent} event - Close event object from the websocket
*/
socketClose: (event: CloseEvent) => void;
/**
* Emitted when occurs an error in the websocket connection
*
* @param {Event} event - Event object from the websocket
*/
socketError: (event: Event) => void;
/**
* Emitted when the websocket connection is opened
*
* @param {Event} event - Event object from the websocket
*/
socketOpen: (event: Event) => void;
/** Emitted when authentication is successful */
authSuccess: () => void;
/** Emitted when authentication fails */
authError: (reason: AuthErrorReason) => void;
/** Emitted when the connection is closed */
disconnected: () => void;
/** Emitted when the process of reconnection starts */
reconnectionStarted: () => void;
/** Emitted on successful reconnection */
reconnected: () => void;
/** Emitted when the maximum number of reconnection retries is reached */
reconnectionRetriesLimitReached: () => void;
/**
* Called when peer was accepted.
*/
joined: (peerId: string, peers: Peer<P, S>[], components: Component[]) => void;
/**
* Called when peer was not accepted
* @param metadata - Pass through for client application to communicate further actions to frontend
*/
joinError: (metadata: JoinErrorReason | unknown) => void;
/**
* Called when data in a new track arrives.
*
* This callback is always called after {@link MessageEvents.trackAdded}.
* It informs user that data related to the given track arrives and can be played or displayed.
*/
trackReady: (ctx: FishjamTrackContext) => void;
/**
* Called each time the peer which was already in the room, adds new track. Fields track and stream will be set to null.
* These fields will be set to non-null value in {@link MessageEvents.trackReady}
*/
trackAdded: (ctx: FishjamTrackContext) => void;
/**
* Called when some track will no longer be sent.
*
* It will also be called before {@link MessageEvents.peerLeft} for each track of this peer.
*/
trackRemoved: (ctx: FishjamTrackContext) => void;
/**
* Called each time peer has its track metadata updated.
*/
trackUpdated: (ctx: FishjamTrackContext) => void;
/**
* Called each time new peer joins the room.
*/
peerJoined: (peer: Peer<P, S>) => void;
/**
* Called each time peer leaves the room.
*/
peerLeft: (peer: Peer<P, S>) => void;
/**
* Called each time peer has its metadata updated.
*/
peerUpdated: (peer: Peer<P, S>) => void;
/**
* Called each time new peer joins the room.
*/
componentAdded: (peer: Component) => void;
/**
* Called each time peer leaves the room.
*/
componentRemoved: (peer: Component) => void;
/**
* Called each time peer has its metadata updated.
*/
componentUpdated: (peer: Component) => void;
/**
* Called in case of errors related to multimedia session e.g. ICE connection.
*/
connectionError: (error: {
message: string;
event?: Event;
}) => void;
/**
* Currently, this callback is only invoked when DisplayManager in RTC Engine is
* enabled and simulcast is disabled.
*
* Called when priority of video tracks have changed.
* @param enabledTracks - list of tracks which will be sent to client from SFU
* @param disabledTracks - list of tracks which will not be sent to client from SFU
*/
tracksPriorityChanged: (enabledTracks: FishjamTrackContext[], disabledTracks: FishjamTrackContext[]) => void;
/**
* Called every time the server estimates client's bandwidth.
*
* @param {bigint} estimation - client's available incoming bitrate estimated
* by the server. It's measured in bits per second.
*/
bandwidthEstimationChanged: (estimation: bigint) => void;
encodingChanged: TrackContextEvents['encodingChanged'];
targetTrackEncodingRequested: (event: Parameters<WebRTCEndpointEvents['targetTrackEncodingRequested']>[0]) => void;
localTrackAdded: (event: Parameters<WebRTCEndpointEvents['localTrackAdded']>[0]) => void;
localTrackRemoved: (event: Parameters<WebRTCEndpointEvents['localTrackRemoved']>[0]) => void;
localTrackReplaced: (event: Parameters<WebRTCEndpointEvents['localTrackReplaced']>[0]) => void;
localTrackMuted: (event: Parameters<WebRTCEndpointEvents['localTrackMuted']>[0]) => void;
localTrackUnmuted: (event: Parameters<WebRTCEndpointEvents['localTrackUnmuted']>[0]) => void;
localTrackBandwidthSet: (event: Parameters<WebRTCEndpointEvents['localTrackBandwidthSet']>[0]) => void;
localTrackEncodingBandwidthSet: (event: Parameters<WebRTCEndpointEvents['localTrackEncodingBandwidthSet']>[0]) => void;
localTrackEncodingEnabled: (event: Parameters<WebRTCEndpointEvents['localTrackEncodingEnabled']>[0]) => void;
localTrackEncodingDisabled: (event: Parameters<WebRTCEndpointEvents['localTrackEncodingDisabled']>[0]) => void;
localPeerMetadataChanged: (event: Parameters<WebRTCEndpointEvents['localEndpointMetadataChanged']>[0]) => void;
localTrackMetadataChanged: (event: Parameters<WebRTCEndpointEvents['localTrackMetadataChanged']>[0]) => void;
disconnectRequested: (event: Parameters<WebRTCEndpointEvents['disconnectRequested']>[0]) => void;
/**
* Emitted when data channel publishers (both reliable and lossy) are created and ready to send data.
*/
dataChannelsReady: () => void;
/**
* Emitted when data channel publishers (both reliable or lossy) fail.
*/
dataChannelsError: (error: Error) => void;
};
/**
* Represents the type of client used.
* @category Connection
*/
type ClientType = 'web' | 'mobile';
/** Configuration object for the client */
interface ConnectConfig<PeerMetadata> {
/** Metadata for the peer */
peerMetadata: PeerMetadata;
/** Token for authentication */
token: string;
/** Fishjam url */
url: string;
}
type CreateConfig = {
reconnect?: ReconnectConfig | boolean;
/**
* Enables Fishjam SDK's debug logs in the console.
*/
debug?: boolean;
/** Type of client used */
clientType?: ClientType;
};
declare const FishjamClient_base: {
new <P, S>(): TypedEmitter<MessageEvents<P, S>>;
};
/**
* FishjamClient is the main class to interact with Fishjam.
*
* @example
* ```typescript
* const client = new FishjamClient<PeerMetadata>();
* const peerToken = "YOUR_PEER_TOKEN";
*
* // You can listen to events emitted by the client
* client.on("joined", (peerId, peersInRoom) => {
* console.log("join success");
* });
*
* // Start the peer connection
* client.connect({
* peerMetadata: {},
* isSimulcastOn: false,
* token: peerToken
* });
*
* // Close the peer connection
* client.disconnect();
* ```
*
* You can register callbacks to handle the events emitted by the Client.
*
* @example
* ```typescript
*
* client.on("trackReady", (ctx) => {
* console.log("On track ready");
* });
* ```
*/
declare class FishjamClient<PeerMetadata = GenericMetadata, ServerMetadata = GenericMetadata> extends FishjamClient_base<PeerMetadata, ServerMetadata> {
private websocket;
private webrtc;
private removeEventListeners;
private debug;
private logger;
private clientType;
status: 'new' | 'initialized';
private connectConfig;
private isAudioOnlyConnection;
private reconnectManager;
private peerMessageQueue;
private sendStatisticsInterval;
private cameraStream;
private screenShareStream;
private trackIdToTrack;
constructor(config?: CreateConfig);
/**
* Uses the WebSocket connection and {@link !WebRTCEndpoint | WebRTCEndpoint} to join to the room. Registers the callbacks to
* handle the events emitted by the {@link !WebRTCEndpoint | WebRTCEndpoint}. Make sure that peer metadata is serializable.
*
* @example
* ```typescript
* const client = new FishjamClient<PeerMetadata>();
*
* client.connect({
* peerMetadata: {},
* token: peerToken
* });
* ```
*
* @param {ConnectConfig} config - Configuration object for the client
*/
connect(config: ConnectConfig<PeerMetadata>): Promise<void>;
private initConnection;
private getUrl;
private initWebsocket;
handleSdkDeprecation(sdkDeprecation: PeerMessage_SdkDeprecation): void;
/**
* Retrieves statistics related to the RTCPeerConnection.
* These statistics provide insights into the performance and status of the connection.
*
* @return {Promise<RTCStatsReport>}
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/getStats | MDN Web Docs: RTCPeerConnection.getStats()}
*/
getStatistics(selector?: MediaStreamTrack | null): Promise<RTCStatsReport>;
/**
* Returns a snapshot of currently received remote tracks.
*
* @example
* if (client.getRemoteTracks()[trackId]?.simulcastConfig?.enabled) {
* client.setTargetTrackEncoding(trackId, encoding);
* }
*/
getRemoteTracks(): Readonly<Record<string, FishjamTrackContext>>;
/**
* Returns a snapshot of currently received remote peers.
*/
getRemotePeers(): Record<string, Peer<PeerMetadata, ServerMetadata>>;
getRemoteComponents(): Record<string, Component>;
getLocalPeer(): Peer<PeerMetadata, ServerMetadata> | null;
getBandwidthEstimation(): bigint;
private isConnectingRelatedEvent;
private setupCallbacks;
private sendStatistics;
/**
* Register a callback to be called when the event is emitted.
* Full list of callbacks can be found here {@link MessageEvents}.
*
* @example
* ```ts
* const callback = ()=>{ };
*
* client.on("onJoinSuccess", callback);
* ```
*
* @param event - Event name from {@link MessageEvents}
* @param listener - Callback function to be called when the event is emitted
* @returns This
*/
on<E extends keyof MessageEvents<PeerMetadata, ServerMetadata>>(event: E, listener: MessageEvents<PeerMetadata, ServerMetadata>[E]): this;
/**
* Remove a callback from the list of callbacks to be called when the event is emitted.
*
* @example
* ```ts
* const callback = ()=>{ };
*
* client.on("onJoinSuccess", callback);
*
* client.off("onJoinSuccess", callback);
* ```
*
* @param event - Event name from {@link MessageEvents}
* @param listener - Reference to function to be removed from called callbacks
* @returns This
*/
off<E extends keyof MessageEvents<PeerMetadata, ServerMetadata>>(event: E, listener: MessageEvents<PeerMetadata, ServerMetadata>[E]): this;
private handleWebR