UNPKG

@huddle01/web-core

Version:

The Huddle01 Javascript SDK offers a comprehensive suite of methods and event listeners that allow for seamless real-time audio and video communication with minimal coding required.

597 lines (594 loc) 25.5 kB
import { Producer, HandlerFactory, AppData } from 'mediasoup-client/lib/types'; import { Device } from 'mediasoup-client'; import { TDataMessage, TVolatileDataMessage, TPermissions, TTransportType } from 'types/dist/common.types'; import DeviceHandler, { CustomMediaKind } from './DeviceHandler.cjs'; import Transport from './Transport.cjs'; import Consumer from './Consumer.cjs'; import Socket from './Socket.cjs'; import { EnhancedEventEmitter } from './common-js/EnhancedEventEmitter.cjs'; import { VolatileDataMessage } from './Bot.cjs'; import { SupportedCodecs } from './types/common.types.cjs'; import './common-js/EnhancedMap.cjs'; import 'mediasoup-client/lib/RtpParameters'; import 'types/dist/clientToSushiEvents'; import 'types/dist/sushiToClientEvents'; import 'types/dist/socket.types'; import 'mediasoup-client/lib/DataConsumer'; import 'mediasoup-client/lib/DataProducer'; import './RemotePeer.cjs'; type RoomStats = { startTime: number; }; type LocalPeerEvents = { /** * Stream Playable Event, Triggered when the stream is ready to be played - * `Note: After the stream is fetched and track is not muted and enabled` */ 'stream-playable': [data: { label: string; producer: Producer; }]; 'stream-closed': [ data: { label: string; mediaKind?: CustomMediaKind; reason?: { code: number; tag: string; message?: string; }; } ]; 'stream-fetched': [ data: { mediaKind: CustomMediaKind; stream: MediaStream; label: string; } ]; 'stream-paused': [data: { mediaKind: CustomMediaKind; label: string; }]; 'receive-data': [data: TDataMessage]; 'receive-volatile-data': [data: TVolatileDataMessage]; reconnected: [data: Socket]; 'metadata-updated': [data: { metadata: unknown; }]; 'permissions-updated': [data: { permissions: TPermissions; role?: string; }]; 'role-updated': [data: { role: string; }]; 'device-created': [data: { device: Device; }]; 'new-send-transport': [data: { transport: Transport; }]; 'new-recv-transport': [data: { transport: Transport; }]; 'ice-transport-restarted': []; }; /** * LocalPeer is the main class which handles all the functionality of the client * Where Client Means the currently Running Application. */ declare class LocalPeer extends EnhancedEventEmitter<LocalPeerEvents> { /** * LocalPeer Instance, Singleton class, only one instance of this class can be created */ private static __instance; /** * PeerId of the current client, specific to the Local Peer who joined the meeting * * `NOTE: Until you dont join the room, this will be *null*` */ peerId: string | null; /** * Current Devices of the current client * e.g. Chrome, Firefox, Safari, ReactNative */ private __device; /** * custom handler factory for device, required when using aiortc client or something custom */ private __handlerFactory?; /** * SendTransport handles the sending of media from the client to the server */ private __sendTransport; /** * RecvTransport handles the receiving of media from the server to the client */ private __recvTransport; /** * Returns the room instance, throws an error if the room is not created * * @throws { Error } If the room is not created, Call createRoom() method before you can access the room in the LocalPeer */ private get room(); /** * Returns the underlying socket connection * @throws { Error } If the socket connection is not initialized */ get socket(): Socket; /** * Remote Peers Map, Stores all the remote peers */ private get __remotePeers(); /** * Turn Server used for this client */ private __turn; /** * Get the current device ( chrome, firefox, safari, reactnative ) for this client * * @throws { Error } If the device is not initialized */ private get device(); private __pendingConsumerTasks; private __pendingProducerTasks; private __pendingTasks; /** * Pending Transport Tasks, Stores the transportType and the promise of the transport * * `NOTE: Useful to check if the transport is already being created and pause all producing * and consuming until the transport is created` */ private __pendingTransportTasks; /** * Stores all the pending fetching stream tasks which are awaiting to be processed * If fetching called multiple times at once, it will handle the concurrency issues */ private __pendingFetchingStream; /** * Stores all the pending produce tasks which are awaiting to be processed * Mostly used when the room is not joined and produce functionality needs to be handled * * Cases such as socket experiencing a reconnect and produce is called. * Or in the cases where room is not joined and enableVideo or enableAudio is called */ private __waitingToProduce; /** * Stores all the pending consume tasks which are waiting for recv transport to be re-connected */ private __waitingToConsume; /** * DeviceHandler Instance, Handles the media devices for this client * e.g. Camera, Microphone */ deviceHandler: DeviceHandler; /** * ActiveStream Map holds MediaStream as Value and Key as Label */ private __activeStreams; /** * Handle the Client Side Permission for the Local Peer. */ private __permissions; /** * Stores the Metadata for the Local Peer. */ private __metadata; /** * Variable to check if the user has joined the room */ joined: boolean; /** * Variable to know if Volatile Messaging is enabled for the LocalPeer, * when using Volatile Messaging, the messages are sent over UDP using WebRTC * which makes the messages faster but not reliable and have much higher rate limit * and lower Latency. */ private __volatileMessaging; /** * Return the labels of the Media Stream that the Local Peer is producing to the room */ get labels(): string[]; /** * Get the Permissions of the Local Peer. (e.g canProduce, canConsume, canSendData, canRecvData etc) */ get permissions(): { admin: boolean; canConsume: boolean; canProduce: boolean; canProduceSources: { cam: boolean; mic: boolean; screen: boolean; }; canSendData: boolean; canRecvData: boolean; canUpdateMetadata: boolean; }; /** * Get the Role of the Local Peer. */ get role(): string | null; /** * Returns the token of the current socket connection, specific to the Local Peer who joined the meeting */ get token(): string | null; /** * Returns the roomId of the current joined room. */ get roomId(): string | null; /** * Returns the SendTransport * @returns { Transport } SendTransport * @throws { Error } If the SendTransport is not initialized */ get sendTransport(): Transport; /** * Returns the recvTransport * @returns { Transport } recvTransport * @throws { Error } If the recvTransport is not initialized */ get recvTransport(): Transport; /** * Returns the metadata associated to the LocalPeer */ getMetadata<T = unknown>(): T; /** * getStream returns the stream with the given label */ getStream: (data: { label: string; }) => MediaStream | null; /** * Updates the metadata associated to the LocalPeer, Triggers the `metadata-updated` event * @param metadata */ private __updateMetadata; /** * Returns the producer with the given label * @param label - Identifier of the producer * @returns { Producer } Producer * @returns { null } If the producer is not found */ getProducerWithLabel: (label: string) => Producer | null; /** * Registers the event handlers for the socket connection * @param socket - Socket Instance */ private __registerHandlerEvents; /** * Can be used to check which `direction` of webRTC connection is currently active for the peer. * * **NOTE: Peers with role as Bot will not have `recv` transport;** * @param transportType */ transportExists: (transportType: TTransportType) => Transport | null; static create(options: { handlerFactory?: HandlerFactory; volatileMessages?: boolean; }): LocalPeer; static getInstance(): LocalPeer; private constructor(); /** * Destroy the current peer, closes all the transports, producers and consumers * * @param code - Close Code */ close: () => void; /** * Produce a stream with a given label and appData to all the Remote Peers * * `canProduce must be true to produce a stream` * * `NOTE: This will notify all the RemotePeers that this producer has started producing and they should start consuming it if they want to` * * @param data - Data to produce a stream * - `label` - Unique Identifier for the stream ( string ) * - `stream` - MediaStream to produce ( MediaStream ) * - `stopTrackOnClose` - If true, it will stop the track when the producer is closed using stopProducing ( boolean ) * - `appData` - Application level custom data which can be added to the producer for the LocalPeer, this data will be available in the producer object and can be used only by the LocalPeer. ( Unknown Object ) * - `prefferedCodec` - Preferred Codec to be used for the stream ( SupportedCodecs ), make sure the codec is supported by the device ( 'Browser' or 'ReactNative' ) * * @summary This function is used to produce a stream with a given label and appData to all the Remote Peers if the send transport is not initialised * it will create a send transport and then produce the stream with the given label and appData to all the Remote Peers * * Send Transport is a secure channel which is used to send media from LocalPeer to all the RemotePeers in the room * * `localPeer.on('new-producer', ({label: string; producer: Producer}) => {})` * * @throws { Error } If Failed to produce, Reason will be in the error message, * @throws { Error } if `prefferedCodec` is not supported by the Device ( 'Browser' or 'ReactNative' ) */ produce: (data: { label: string; stream: MediaStream; stopTrackOnClose?: boolean; appData?: AppData; prefferedCodec?: SupportedCodecs; }) => Promise<Producer<AppData>>; /** * Enables the local web cam and starts producing the stream with the label `video` * @param customVideoStream (Optional) Custom Video Stream to produce, if not provided it will fetch the stream from the device * @param prefferedCodec (Optional) Preferred Codec to be used for the stream ( SupportedCodecs ), make sure the codec is supported by the device ( 'Browser' or 'ReactNative' ) * * @summary This functions handle the producing of media streams to all the remote peers in the room. * it enables the local web cam fetches the stream opens you web cam indicator light on the device * upon successfull fetching of the stream it produces the stream with the label `video` and `stopTrackOnClose: true` to all the remote peers in the room. * when closing using disableVideo it will stop the local track and close the producer which will notify all the RemotePeers that this producer has stopped producing * and they should stop consuming it. * * `NOTE: You can only produce to a room when you have joined the room, if you try to produce before joining the room it will throw an error` * * @throws { Error } If the stream is not found * @throws { Error } If Preffered Codec is not supported by the Device ( 'Browser' or 'ReactNative' ) * @throws { Error } If Failed to produce, Reason will be in the error message */ enableVideo: (data?: { customVideoStream?: MediaStream; prefferedCodec?: SupportedCodecs; } | undefined) => Promise<MediaStream | undefined>; /** * Enables the local screen share and starts producing the screen sharing stream * * @param prefferedCodec (Optional) Preferred Codec to be used for the stream ( SupportedCodecs ), make sure the codec is supported by the device ( 'Browser' or 'ReactNative' ) * *`NOTE: You can only produce to a room when you have joined the room, if you try to produce before joining the room it will fetch the stream and start producing when you join the room` * * @summary This functions handle the producing of media streams to all the remote peers in the room. * it enables the local mic fetches the stream opens you mic active indicator light on the device * upon successfull fetching of the stream it produces the stream with the label `audio` and `stopTrackOnClose: true` to all the remote peers in the room. * when closing using `disableAudio` it will stop the local audio track and close the producer which will notify all the RemotePeers that this producer has stopped producing * and they should stop consuming it. * * @throws { Error } If Preffered Codec is not supported by the Device ( 'Browser' or 'ReactNative' ) * @throws { Error } If Failed to produce, Reason will be in the error message */ startScreenShare: (data?: { prefferedCodec?: SupportedCodecs; } | undefined) => Promise<MediaStream | undefined>; /** * Enables the local mic and starts producing the stream with the label `audio` * @param customVideoStream (Optional) Custom Video Stream to produce, if not provided it will fetch the stream from the device * @param prefferedCodec (Optional) Preferred Codec to be used for the stream ( SupportedCodecs ), make sure the codec is supported by the device ( 'Browser' or 'ReactNative' ) * * @summary This functions handle the producing of media streams to all the remote peers in the room. * it enables the local mic fetches the stream opens you mic active indicator light on the device * upon successfull fetching of the stream it produces the stream with the label `audio` and `stopTrackOnClose: true` to all the remote peers in the room. * when closing using `disableAudio` it will stop the local audio track and close the producer which will notify all the RemotePeers that this producer has stopped producing * and they should stop consuming it. * * `NOTE: You can only produce to a room when you have joined the room, if you try to produce before joining the room it will fetch the stream and start producing when you join the room` * * @throws { Error } If the stream is not found * @throws { Error } If Preffered Codec is not supported by the Device ( 'Browser' or 'ReactNative' ) * @throws { Error } If Failed to produce, Reason will be in the error message */ enableAudio: (data?: { customAudioStream?: MediaStream; prefferedCodec?: SupportedCodecs; } | undefined) => Promise<MediaStream | undefined>; /** * Stops the underlying producing of a stream for a particular label * * `NOTE: This will notify all the RemotePeers that this producer has stopped producing and they should stop consuming it.` * * @param data Data to stop producing { label: string } */ stopProducing: (data: { label: string; }) => void; /** * Stops the underlying producing of a camera stream, stops the local track and closes the producer * * `NOTE: This will notify all the RemotePeers that this producer has stopped producing and they should stop consuming it. if you have joined the room, else it will just close the stream` * * @param data Data to stop producing { label: string } */ disableVideo: () => Promise<void>; /** * Replaces the current video stream with the new stream * * if you have produced a stream with label `video` or used the default function `enableVideo` and you want to replace it with a new stream * @param stream - New Video Stream */ replaceVideoStream: (stream: MediaStream) => Promise<void>; /** * Changes the Video source to the given deviceId, sets the preferred cam device as the given deviceId * @param deviceId */ changeVideoSource: (deviceId: string) => Promise<void>; /** * Replaces the current audio stream with the new stream * if you have produced a stream with label `audio` or used the default function `enableAudio` and you want to replace it with a new stream * @param stream - New Audio Stream * */ replaceAudioStream: (stream: MediaStream) => Promise<void>; /** * Replace the current stream with the new stream based on the label used to produce the stream * * @example * For Video * await localPeer.replaceStream({ * label: 'video', * newStream: newStream * }) * * If any custom label used * await localPeer.replaceStream({ * label: 'custom', * newStream: newStream * }) * * @param data - { label: string, newStream: MediaStream } * @throws { Error } - If replace Stream failed */ replaceStream: (data: { label: string; newStream: MediaStream; }) => Promise<void>; /** * Changes the Audio source to the given deviceId, sets the preferred mic device as the given deviceId * @param deviceId */ changeAudioSource: (deviceId: string) => Promise<void>; /** * Stops the underlying producing of a microphone stream, stops the local track and closes the producer * * `NOTE: This will notify all the RemotePeers that this producer has stopped producing and they should stop consuming it.` */ disableAudio: () => Promise<void>; /** * Pauses the audio stream, pauses the underlying producer but does not stop the local track - useful when user has joined the room and wants to pause the audio stream which is faster than disabling the audio stream * * `NOTE: Only use this function when peer has joined the room else use disableAudio, The LocalPeer will not be producing any audio stream but the local track will still be active, you can resume the audio stream using resumeAudio or stop the audio stream using disableAudio` * * @throws Error - If Pausing Audio Failed, it will disable the audio stream, and throw an error */ pauseAudio: () => Promise<void>; /** * Resumes the audio stream, resumes the underlying producer and starts producing the audio stream - useful when user has `joined the room` and wants to resume the audio stream * * `Note: Works only if the audio stream is paused using pauseAudio` * * @throws Error - If Resuming Audio Failed, it will disable the audio stream, and throw an error */ resumeAudio: () => Promise<void>; /** * Stops the underlying producing of a screen-share stream, stops the local track and closes the producer * * `NOTE: This will notify all the RemotePeers that this producer has stopped producing and they should stop consuming it. if you have joined the room, else it will just close the stream` */ stopScreenShare: () => Promise<void>; /** * Consumes a stream with the producerId and peerId of the RemotePeer, appData is application level custom data which * can be added to the consumer for the LocalPeer, this data will be available in the consumer object and can be used only by the LocalPeer. * * `NOTE: This will not notify the RemotePeers that you are consuming a stream, you have to notify them manually` * @summary Every time a RemotePeer is producing a Media in the Room, LocalPeer will be notified about it and it will be able to consume it. * Consuming is a process where the media is received from the RemotePeer and the stream can be played on the LocalPeers device. * * To get the consumer back you can use * * const remotePeer = this.room.getRemotePeerById(data.peerId); * * `remotePeer.on('stream-playable', ({ label: string; consumer: Consumer }) => {})` * * @param data - {peerId: string, label: string, appData: Record<string, unknown>} * @throws { Error } - If Consuming Stream Failed */ consume: (data: { peerId: string; label: string; appData: AppData; }) => Promise<Consumer>; /** * Stops the underlying consuming of a stream for a particular label * * `NOTE: This does not notify the remote peers that you are not consuming a stream` * * @param data */ stopConsuming: (data: { peerId: string; label: string; }) => void; /** * Activate Sending and Receving Volatile Messages, which uses WebRTC DataChannels over UDP * to send messages to the RemotePeers in the Room, this is faster than sending messages over WebSockets and has much lower Rate Limiting * Prefer using this for sending burst messages to the RemotePeers in the Room * @returns { ok: boolean, error?: Error } - error will be present if failed to activate volatile messaging */ private __activateVolatileMessaging; /** * Send Data Gives the functionality to send data to other remote peers or the whole room, * NOTE: This will be sent over WebSockets which are over TCP which will be slower and can be rate limited. * @returns { success: boolean, error?: string } - error will be present if failed to send data */ sendData: (data: { to: string[] | "*"; payload: string; label?: string; }) => Promise<{ success: boolean; error?: string; }>; /** * Send Volatile Data Gives the functionality to send data to other remote peers or the whole room, * NOTE: This will be sent over WebRTC DataChannels which are over UDP which will be faster and can be rate limited. * @returns { ok: boolean } - if the volatile data was sent, cannot guarantee if the data was received as its over UDP */ sendVolatileData: (data: Omit<VolatileDataMessage, "to" | "from">) => Promise<void>; /** * Send Message to update the metadata of the Local Peer * * `NOTE: This will notify every user in the room about the metadata update` * * @emits `localPeer.on(metadata-updated)` on succesful metadata update * * @throws { Error } - if unable to update Metadata for the peer. */ updateMetadata: <T = unknown>(data: T) => Promise<void>; /** * Update the role of the Remote Peer in the Room, this will emit an event `updated` with the updated role. * * @emits `localPeer.on('role-updated') in case role update was successful. */ updateRole: (data: { role: string; options?: { custom: TPermissions; }; }) => void; private __handler; /** * @description Registers the important internal listeners for the client, events such as reconnected, room-joined etc. */ private __registerInternalListeners; /** * @description Creates a Producer, if send transport is not initialized, it creates one and then creates a producer * @param data - Data to create a producer { label, stream, stopTrackOnClose, appData } * @returns - Producer */ private __createProducer; /** * @description Create a DataProducer on the server, Data Producer is used to send data other than Media stream to the server * @throws Error if DataProducer cannot be created * @param data */ private __createDataProducer; /** * Create WebRTC Transport (Send/Recv) on Server * @throws Error if Transport cannot be created * @param data - Transport Data { transportType } * @returns - Transport ( WebRTC Transport ) */ private __createTransportOnServer; /** * Sets the Remote Peers in the Room * @param roomInfo */ private __setRemotePeers; /** * Helper Function to close the consumer of a remote peer * @param data - Data to close the consumer { peerId, label } */ private __closeRemotePeerConsumer; /** * !important * Handler Function to handle the waiting to produce tasks when user is joining * the room with active stream, check if the user has valid permissions and based on * that allows the user to produce the stream */ private __handleWaitingToProduce; /** * Invoke the waiting to consume tasks and clear the waiting to consume array */ private __handleWaitingToConsume; /** * SyncMeetingState - Sync the Meeting State with the server, information such as new remote peer, change in producers etc. */ private __syncMeetingState; } export { type LocalPeerEvents, type RoomStats, LocalPeer as default };