UNPKG

@ceeblue/webrtc-client

Version:
1,430 lines (1,400 loc) 56.6 kB
import { WebSocketReliableError, EventEmitter, Connect, Loggable } from '@ceeblue/web-utils'; import * as webUtils from '@ceeblue/web-utils'; export { webUtils as utils }; /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * List the media type in their string version as received from server */ declare enum MType { AUDIO = "audio", VIDEO = "video", DATA = "data" } /** * Media Source representation */ type MSource = { hrn: string; type: string; priority: number; relurl: string; url: string; simul_tracks: number; total_matches: number; }; /** * Media Track representation */ type MTrack = { idx: number; trackid: number; name: string; type: MType; codec: string; firstms: number; lastms: number; bps: number; maxbps: number; init: string; channels: number; rate: number; size: number; fpks: number; width: number; height: number; up?: MTrack; down?: MTrack; }; /** * Metadata representation */ declare class Metadata { type: string; /** * Width resolution size */ width: number; /** * Height resolution size */ height: number; /** * Sources available to play the stream */ sources: Map<string, MSource>; /** * Tracks sorted by descending BPS */ tracks: Map<number, MTrack>; /** * Audio tracks sorted by descending BPS */ audios: Array<MTrack>; /** * Video tracks sorted by descending BPS */ videos: Array<MTrack>; /** * Data track */ datas: Array<MTrack>; /** * Return a new metadata subset with only track with a codec supported * @param codecs codecs supported * @returns the subset of metadata */ subset(codecs?: Set<string>): Metadata; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ declare enum StreamState { UNKNOWN = "", ONLINE = "Stream is online", OFFLINE = "Stream is offline", INITIALIZING = "Stream is initializing", BOOTING = "Stream is booting", WAITING = "Stream is waiting for data" } type StreamMetadataError = /** * Represents a Stream metadata error. */ { type: 'StreamMetadataError'; name: string; stream: string; } /** * Represents a {@link WebSocketReliableError} error */ | WebSocketReliableError; /** * Use StreamMetadata to get real-time information on a server stream, including: * - the list of tracks and their properties, * - the list of availables sources and their properties, * @example * const streamMetadata = new StreamMetadata(Connect.buildURL(endPoint, streamName)); * streamMetadata.onMetadata = metadata => { * console.log(metadata); * } * */ declare class StreamMetadata extends EventEmitter { /** * Event fired when stream state is changing * @param state */ onState(state: StreamState): void; /** * Event fired when the stream is closed * @param error error description on an improper closure * @event */ onClose(error?: StreamMetadataError): void; /** * Event fired when metadata is present in the stream * @param metadata * @event */ onMetadata(metadata: Metadata): void; /** * URL of the connection */ get url(): string; /** * State of the stream as indicated by the server */ get streamState(): StreamState; /** * Returns the {@link Connect.Params} object containing the connection parameters */ get connectParams(): Connect.Params; /** * Returns the {@link Metadata} object description */ get metadata(): Metadata | undefined; /** * Returns true if the connection is closed */ get closed(): boolean; private _ws; private _metadata?; private _connectParams; private _streamState; /** * Create a new StreamMetadata instance, connects to the server using WebSocket and * listen to metadata events. */ constructor(connectParams: Connect.Params); /** * Close the stream metadata channel * @param error error description on an improper closure */ close(error?: StreamMetadataError): void; private _addSortedTrack; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * This is the structure returned by the connectionInfos() method * to get statistics about current connection */ type ConnectionInfos = { /** * inputs channel */ inputs: { audio?: RTCInboundRtpStreamStats; video?: RTCInboundRtpStreamStats; }; /** * outputs channel */ outputs: { audio?: RTCOutboundRtpStreamStats; video?: RTCOutboundRtpStreamStats; }; /** * Selected candidate pair */ candidate?: RTCIceCandidatePairStats; }; type ConnectorError = /** * Represents a Connection error. */ { type: 'ConnectorError'; name: 'Connection failed'; detail: string; } /** * Represents a Connection idle error. */ | { type: 'ConnectorError'; name: 'Connection idle'; } /** * Represents a RTCPeerConnection creation error. */ | { type: 'ConnectorError'; name: 'RTCPeerConnection failed'; detail: string; } /** * Represents a SIP handshake error. */ | { type: 'ConnectorError'; name: 'SIP failed'; detail: string; } /** * Represents access denied error. */ | { type: 'ConnectorError'; name: 'Access denied'; } /** * Represents a {@link WebSocketReliableError} error */ | WebSocketReliableError; /** * IConnector is a common interface for representing a stream connection with the server. * * This interface can serve the both roles: player or streamer. */ interface IConnector extends EventEmitter { /** * Call when connector is open * @param stream MediaStream description provided from the server if we are the player, * or build from the local camera if we are the streamer. * @event */ onOpen(stream: MediaStream): void; /** * Call when connector is closed * @param error error description on an improper closure * @event */ onClose(error?: ConnectorError): void; /** * True when connector is opened, in other words when {@link onOpen} event is fired */ readonly opened: boolean; /** * True when connector is closed, in other words when {@link onClose} event is fired */ readonly closed: boolean; /** * Media Stream description delivred from the server if we are player, * or build from the local camera if we are the streamer. */ readonly stream?: MediaStream; /** * Stream name, for example `as+bc3f535f-37f3-458b-8171-b4c5e77a6137` */ readonly streamName: string; /** * Indicate codecs supported, should be set before than {@link onOpen} happen */ readonly codecs: Set<string>; /** * Request connections infos with caching option to save loading cost * @param cacheDuration indicate how many time we can cache the last connection informations * @returns Promise with a ConnectionInfos on success */ connectionInfos(cacheDuration?: number): Promise<ConnectionInfos>; /** * Close the connector * @param error the error reason if is not a proper close */ close(error?: ConnectorError): void; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * MediaReport is a structure returned by {@link IController.onMediaReport} event. * It contains the media controller statistics. */ type MediaReport = { type: string; millis: number; tracks: string[]; stats: { jitter_ms: number; loss_num: number; loss_perc: number; nack_num: number; }; }; /** * RTPProps is a structure returned by {@link IController.onRTPProps} event. * It contains the RTP controller statistics. */ type RTPProps = { type: string; result: boolean; drop: number; nack: number; }; /** * PlayingInfos is a structure returned by {@link IController.onPlaying} event. * It contains the current playing information, updated every second. */ type PlayingInfos = { type: string; begin: number; current: number; end: number; tracks: number[]; }; /** * IController is a controller interface extending a stream connector * with the capability of sending and receiving commands with the server. * * This interface can serve the both roles: player or streamer. */ interface IController extends IConnector { /** * Call to distribute {@link RTPProps} * @param rtpProps RTP properties * @event */ onRTPProps(rtpProps: RTPProps): void; /** * Call to distribute {@link MediaReport} * @param mediaReport Media report informations * @event */ onMediaReport(mediaReport: MediaReport): void; /** * Call to distribute video bitrate informations * @param videoBitrate Current video bitrate * @param videoBitrateConstraint Video bitrate constraint computed by the server * @event */ onVideoBitrate(videoBitrate: number, videoBitrateConstraint: number): void; /** * Call to distribute {@link PlayingInfos} * @param playingInfos Current playing informations * @event */ onPlaying(playingInfos: PlayingInfos): void; /** * Sets server properties for packet error (nack) and delayed packet loss (drop) * for a streamer controller and fires an onRTPProps event if changed successfully. * NOTE: Method can also retrieve current server values if called without arguments. * @param nack Waiting period before declaring a packet error * @param drop Waiting period before considering delayed packets as lost */ setRTPProps(nack?: number, drop?: number): void; /** * Configure the video bitrate on the server side for a streamer controller * @param value video bitrate in bps */ setVideoBitrate(value: number): void; /** * Configure the audio and video track to play for a player controller * @param tracks.audio Audio track * @param tracks.video Video track */ setTracks(tracks: { audio?: number; video?: number; }): void; /** * Send a generic command to control the streaming session * @param type type of command * @param params parameters of the command * @example * controller.send('video_bitrate', {video_bitrate: 0}); */ send(type: string, params: object): void; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * MBRParams is the structure used to initialize an {@link MBRAbstract} instance. */ type MBRParams = { /** * Number of milliseconds to increase the delay of the next Up try when we are congested * @defaultValue 1400 */ learningUpStep?: number; /** * Maximum delay in milliseconds to wait before trying to Up again * @defaultValue 28000 */ maximumUpDelay?: number; }; /** * MBRAbstract is the base class for multi-bitrate algorithm used by {@link Player} * to switch between tracks quality depending on the network's congestion. */ declare abstract class MBRAbstract extends Loggable implements MBRParams { /** * delay before to increase bitrate when network quality is good */ get upDelay(): number; /** * delay added on every congestion to report next bitrate increasing */ get learningUpStep(): number; /** * maximum delay before to increase bitrate when network quality is good */ get maximumUpDelay(): number; private _mTrack?; private _learningUpStep; private _upDelay; private _maximumUpDelay; private _testTime; private _appreciationTime?; /** * Build the MBR implementation, call {@link compute} to use it * @param params MBR parameters */ constructor(params: MBRParams); /** * Reset the MBR algorithm to its initial state */ reset(): void; /** * Call this method regularly to control if we have to change track, it will update * the tracks if needed and return true if a track has changed. * @param metadata Metadata of the stream * @param tracks the audio and video track number, this object can be updated with the new track numbers * @param stats Statistics to use to determine if we have to decrease bitrate now * @returns true if a track has changed, false otherwise */ compute(metadata: Metadata, tracks: { audio?: number; video?: number; }, stats: { audio?: RTCInboundRtpStreamStats; video?: RTCInboundRtpStreamStats; }): boolean; /** * Try to select the next track to use if available * @param track the track number to update * @param metadata the metadata of the stream * @param down True if it is a down change, false if it is an up change * @returns the new track to use or undefined if no change is possible */ private updateTrack; /** * Check if we are congested and need to reduce the bitrate now * Implement this method to define your own congestion algorithm * * @param elapsed Time since beginning of congestion, on a new state 'elapsed' is equals to 0 on first call * @param trackRef Track used as reference for statistics, is always the video track playing excepting if the stream is a pure audio stream * @param stats Statistics to use to determine if we have to decrease bitrate now * @returns true if we can decrease bitrate quality now */ protected abstract _downBitrate(elapsed: number, trackRef: MTrack, stats: RTCInboundRtpStreamStats): boolean; /** * Called when {@link _downBitrate} returns false to check if we can increase the bitrate now * Implement this method to define your own congestion algorithm * * @param elapsed Time since beginning of good network state, on the first call 'elapsed' is equals to 0 * @param trackRef Track used as reference for statistics, is always the video track playing excepting if the stream is a pure audio stream * @param stats Statistics to use to determine if we have to increase bitrate now * @returns true if we can increase bitrate quality now */ protected abstract _upBitrate(elapsed: number, trackRef: MTrack, stats: RTCInboundRtpStreamStats): boolean; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ type PlayerError = /** * Represents a {@link ConnectorError} error */ ConnectorError /** * Represents a {@link WebSocketReliableError} error */ | WebSocketReliableError /** * Represents a {@link StreamMetadataError} error */ | StreamMetadataError; /** * Use Player to start playing a WebRTC stream. * You can use a controllable version using a `WSController` as connector, or change it to use a `HTTPConnector` (HTTP WHEP). * By default it uses a `WSController` excepting if on {@link Player.start} you use a {@link Connect.Params.endPoint} prefixed with a `http://` protocol. * With a controllable connector you can change track during the playback, what is not possible with a HTTP(WHEP) connector. * * In addition then a player with a controllable connector uses a MultiBitrate algorithm to switch track automatically * regarding network congestion. You can disable it and fix manually a track by selecting it after a start call. * At last it's possible to indicate which are tracks to play in first by setting audio and video tracks before * start call. In this case it can be usefull to get metadata information about the stream before to play it, * see {@link Player.start} to achieve it. * * @example * const player = new Player(); * // const player = new Player(isWHEP ? HTTPConnector : WSController); * player.onStart = stream => { * videoElement.srcObject = stream; * console.log('start playing'); * } * player.onStop = _ => { * console.log('stop playing'); * } * // optionnaly set initial video track to play before start() call * player.videoTrack = 1; * // start playback * player.start({ * endPoint: address, // if address is prefixed by `http://` it uses a HTTPConnector (HTTP-WHEP) if Player is build without contructor argument * streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' * }); * // Tracks are in a MBR mode: video track 1 can change regarding network congestion * ... * // Fix video track to 2, disable MBR mode * player.videoTrack = 2; * ... * player.stop(); * */ declare class Player extends EventEmitter { private Connector?; /** * Event fired when streaming starts * @param stream * @event */ onStart(stream: MediaStream): void; /** * Event fired when streaming stops * @param error error description on an improper stop * @event */ onStop(error?: PlayerError): void; /** * Event fired when stream state is changing * @param state */ onState(state: StreamState): void; /** * Event fired every second to report information while content plays * @param playing * @event */ onPlaying(playing: PlayingInfos): void; /** * Event fired when metadata is present in the stream * @param metadata * @event */ onMetadata(metadata: Metadata): void; /** * Event fired when data is received in the stream * @param time * @param track * @param data * @event */ onData(time: number, track: number, data: any): void; /** * Stream name, for example `as+bc3f535f-37f3-458b-8171-b4c5e77a6137` */ get streamName(): string; /** * Playable media stream as specified by [MediaStream](https://developer.mozilla.org/docs/Web/API/MediaStream) */ get stream(): MediaStream | undefined; /** * Returns true when player is running (between a {@link Player.start} and a {@link Player.stop}) */ get running(): boolean; /** * Returns the {@link IController} instance when starting with a connector with controllable ability, * or undefined if stream is not starting or stream is not controllable. */ get controller(): IController | undefined; /** * Returns the {@link IConnector} instance, or undefined if stream is not starting. */ get connector(): IConnector | undefined; /** * State of the stream as indicated by the server */ get streamState(): StreamState; /** * Returns the {@link Metadata} object description */ get metadata(): Metadata | undefined; /** * Last playing information, such as current position and playback buffer bounds * See {@link PlayingInfos} */ get playingInfos(): PlayingInfos | undefined; /** * Index of the audio track, can be undefined if player is not playing */ get audioTrack(): number | undefined; /** * Sets the current audio track to the index provided, it can be set before calling {@link Player.start} * to select the initial audio track, or set after {@link Player.start} to fix track and disable MBR * While playing you can set it to `undefined` to activate MBR when session is controllable */ set audioTrack(idx: number | undefined); /** * Index of the video track, can be undefined if player is not playing */ get videoTrack(): number | undefined; /** * Sets the current video track to the index provided, it can be set before calling {@link Player.start} * to select the initial video track, or set after {@link Player.start} to fix track and disable MBR * While playing you can set it to `undefined` to activate MBR when session is controllable */ set videoTrack(idx: number | undefined); /** * The list of tracks currently receiving */ get dataTracks(): Array<number>; /** * Set the data track ids to receive */ set dataTracks(tracks: Array<number>); private _connector?; private _controller?; private _streamMetadata?; private _audioTrack?; private _videoTrack?; private _audioTrackFixed?; private _videoTrackFixed?; private _dataTracks; private _playingInfos?; private _streamData?; private _metadata?; /** * Constructs a new Player instance, optionally with a custom connector * This doesn't start the playback, you must call {@link Player.start} method * By default if no connector is indicated it uses a {@link WSController} (WebSocket {@link IController}) * excepting if {@link Connect.Params.endPoint} is prefixed with a `http://` protocol in such case it uses * instead a {@link HTTPConnector} (HTTP {@link IConnector}). To force a HTTPConnector build explicitly * with {@link HTTPConnector} as Connector argument. * @param Connector Connector class to use for signaling, or nothing to let's {@link Player.start} method determines it automatically. * @example * // Default build * const player = new Player(); * player.start({ * endPoint: address, // if address is prefixed by `http://` it uses a HTTPConnector (HTTP-WHIP), otherwise it uses a WSController (WebSocket) * streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' * }); * // Force connector selection whatever the address used in endPoint * const player = new Player(isWHIP ? HTTPConnector : WSController); * player.start({ * endPoint: address, // optional protocol prefix has no incidence on connector selection * streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' * }) */ constructor(Connector?: (new (connectParams: Connect.Params) => IConnector) | undefined); /** * Returns connection info, such as round trip time, requests sent and received, * bytes sent and received, and bitrates * NOTE: This call is resource-intensive for the CPU. * @returns {Promise<ConnectionInfos>} A promise for a ConnectionInfos */ connectionInfos(): Promise<ConnectionInfos>; /** * Starts playing the stream * The connector is determined automatically from {@link Connect.Params.endPoint} if not forced in the constructor. * * Instead to use a {@link Connect.Params} you can prefer use a already built {@link StreamMetadata} instance to * the same end-point, it allows to discover tracks in amount and initialize track selection to start playback. * * The `multiBitrate` option can take three different types of value: * - A {@link MBRParams} object to configured the default MBRLinear implementation, default value `{}` * - `undefined` to disable MBR management * - Use a custom {@link MBRAbstract} implementation instance * * In addition you can disable MBR while playing by set audio or video track to an explicit value ({@link Player.videoTrack} and {@link Player.audioTrack}). * * @param params Connection parameters or a StreamMetadata object already connected to the same end-point * Note that if you pass a StreamMetadata object its life-time management is fully delegated to the Player * @param multiBitrate Multi-bitrate implementation or MBRParams to configure the default implementation * @example * // Default start with MBR activated * player.start({ * endPoint: address, * streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' * }); * // Start with selected initial track, in using a StreamMetadata object preinitialized * const streamMetadata = new StreamMetadata({ * endPoint: address, * streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' * }); * streamMetadata.onMetadata = metadata => { * // start to play with higher bitrate selection (audios and videos are sorted by descending BPS) * player.audioTrack = metadata.audios[0].idx; * player.videoTrack = metadata.videos[0].idx; * // give the streamMetadata channel to reuse instead of opening a new again * player.start(streamMetadata); * // Now MBR select automatically the best tracks regarding network congestion * ... * // Fix audioTrack to the high rendition (disable MBR for audio track) * player.audioTrack = 1; * ... * // Reactivate MBR for audio * player.audioTrack = undefined; * } */ start(params: Connect.Params | StreamMetadata, multiBitrate?: MBRAbstract | MBRParams | undefined): void; /** * Stops playing the stream * @param error error description on an improper stop */ stop(error?: PlayerError): void; private _updateTracks; private _initStreamMetadata; private _newStreamData; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * ABRParams is the structure used to initialize an {@link ABRAbstract} instance. */ type ABRParams = { /** * Startup bitrate in bps * @defaultValue 2000000 */ startup?: number; /** * Minimum bitrate in bps * @defaultValue 200000 */ minimum?: number; /** * Maximum bitrate in bps * @defaultValue 3000000 */ maximum?: number; /** * The `recoverySteps` parameter defines the step size used to gradually restore the bitrate * towards the ideal bandwidth, aiming to approach the {@link ABRParams.maximum} limit. * * Initially set to the configured value (default: 2), this factor determines the number of steps * taken to adapt the bitrate based on network conditions : * - If network congestion is detected, the step count increases to avoid overshooting. * - Once the network stabilizes, the step count decreases, returning gradually to its initial value. * * In essence, `recoverySteps` controls the initial speed at which the system recovers a high transfer rate. * * @warning Only used by ABRLinear * @defaultValue 2 */ recoverySteps?: number; /** * The `appreciationDuration` parameter defines the duration (in milliseconds) for recognizing a stable network * condition. By default it is set to 4 seconds, which is longer than the typical GOP unit, usually set to 2 seconds. * * @warning Only used by ABRLinear. * @defaultValue 4000 */ appreciationDuration?: number; }; /** * ABRAbstract is the base class for adaptive bitrate algorithm used by {@link Streamer} * when it has a controller connector. */ declare abstract class ABRAbstract extends EventEmitter implements ABRParams { /** * Get the configured initial bitrate */ get startup(): number; /** * Update the initial bitrate */ set startup(value: number); /** * Get the minimum bitrate */ get minimum(): number; /** * Update the minimum bitrate */ set minimum(value: number); /** * Get the maximum bitrate */ get maximum(): number; /** * Update the maximum bitrate */ set maximum(value: number); /** * Get the current bitrate constraint */ get constraint(): number | undefined; /** * Get {@link ABRParams.recoverySteps} */ get recoverySteps(): number; /** * Set {@link ABRParams.recoverySteps} */ set recoverySteps(value: number); /** * Get {@link ABRParams.appreciationDuration} */ get appreciationDuration(): number; /** * Set {@link ABRParams.appreciationDuration} */ set appreciationDuration(value: number); /** * Get the current bitrate */ get value(): number | undefined; /** * @returns the current bitrate * @override */ valueOf(): number | undefined; /** * Get the {@link https://developer.mozilla.org/docs/Web/API/MediaStream MediaStream} if set */ get stream(): MediaStream | undefined; private _bitrateConstraint?; private _bitrate?; private _startup; private _maximum; private _minimum; private _recoverySteps; private _appreciationDuration; private _stream?; /** * Build the ABR implementation, call {@link compute} to use it * @param params ABR parameters * @param stream If set it can change dynamically the source resolution regarding the network quality */ constructor(params: ABRParams, stream?: MediaStream); /** * Call this method regularly to control if we have to increase or decrease the stream bitrate * depending on the network conditions. * @param bitrate the current bitrate * @param bitrateConstraint the current bitrate constraint * @param mediaReport the media report structure received from the server * @returns the wanted bitrate */ compute(bitrate: number | undefined, bitrateConstraint?: number, mediaReport?: MediaReport): number; /** * Reset the ABR algorithm to its initial state */ reset(): void; /** * Implement this method to define your own congestion algorithm, the method must * return the wanted bitrate or undefined to not change the current bitrate. * @param bitrate the current bitrate * @param bitrateConstraint the current bitrate constraint * @param mediaReport the media report structure received from the server * @returns the wanted bitrate or undefined to not change the current bitrate */ protected abstract _computeBitrate(bitrate: number, bitrateConstraint?: number, mediaReport?: MediaReport): number; protected _updateVideoConstraints(videoBitrate: number): void; private _upgradeVideoConstraint; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ type StreamerError = /** * Represents a {@link ConnectorError} error */ ConnectorError /** * Represents a {@link WebSocketReliableError} error */ | WebSocketReliableError; /** * Use Streamer to broadcast to a WebRTC server. * * You can use a controllable version using a `WSController` as connector, or change it to use a `HTTPConnector` (HTTP WHIP). * By default it uses a `WSController` excepting if on {@link Streamer.start} you use a {@link Connect.Params.endPoint} prefixed with a `http://` protocol. * With a controllable connector you can change video bitrate during the streaming, what is not possible with a HTTP(WHIP) connector. * * @example * const streamer = new Streamer(); * // const streamer = new Streamer(isWHEP ? HTTPConnector : WSController); * streamer.onStart = stream => { * console.log('start streaming'); * } * streamer.onStop = _ => { * console.log('stop streaming'); * } * navigator.mediaDevices * .getUserMedia({ audio: true, video: true }) * .then(stream => { * streamer.start(stream, { * endPoint: address, // if address is prefixed by `http://` it uses a HTTPConnector (HTTP-WHIP) if Streamer is build without contructor argument * streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' * }); * ... * streamer.stop(); * }); */ declare class Streamer extends EventEmitter { private Connector?; /** * Event fired when the stream has started * @param stream * @event */ onStart(stream: MediaStream): void; /** * Event fired when the stream has stopped * @param error error description on an improper stop * @event */ onStop(error?: StreamerError): void; /** * Event fired when an RTP setting change occurs * @param props */ onRTPProps(props: RTPProps): void; /** * Event fired to report media statistics * @param mediaReport */ onMediaReport(mediaReport: MediaReport): void; /** * Event fired when a video bitrate change occurs * @param videoBitrate * @param videoBitrateConstraint */ onVideoBitrate(videoBitrate: number, videoBitrateConstraint: number): void; /** * Stream name, for example `as+bc3f535f-37f3-458b-8171-b4c5e77a6137` */ get streamName(): string; /** * Camera media stream as specified by [MediaStream](https://developer.mozilla.org/docs/Web/API/MediaStream) */ get stream(): MediaStream | undefined; /** * Returns true when streamer is running (between a {@link Streamer.start} and a {@link Streamer.stop}) */ get running(): boolean; /** * Returns the {@link IController} instance when starting with a connector with controllable ability, * or undefined if stream is not starting or stream is not controllable. */ get controller(): IController | undefined; /** * Returns the {@link IConnector} instance, or undefined if stream is not starting. */ get connector(): IConnector | undefined; /** * Last {@link MediaReport} statistics */ get mediaReport(): MediaReport | undefined; /** * Last {@link RTPProps} statistics */ get rtpProps(): RTPProps | undefined; /** * Video bitrate configured by the server, * can be undefined on start or when there is no controllable connector * @note Use {@link connectionInfos} to get the current precise audio or video bitrate */ get videoBitrate(): number | undefined; /** * Configure the video bitrate from the server, * possible only if your {@link Streamer} instance is built with a controllable connector * Set undefined to remove this configuration */ set videoBitrate(value: number | undefined); /** * Video bitrate constraint configured by the server, * can be undefined on start or when there is no controllable connector * @note Use {@link connectionInfos} to get the current precise audio or video bitrate */ get videoBitrateConstraint(): number | undefined; private _connector?; private _controller?; private _mediaReport?; private _videoBitrate?; private _videoBitrateConstraint?; private _videoBitrateFixed; private _rtpProps?; /** * Constructs a new Streamer instance, optionally with a custom connector * This doesn't start the broadcast, you must call start() method * @param Connector Connector class to use for signaling, can be determined automatically from URL in the start() method */ constructor(Connector?: (new (connectParams: Connect.Params, stream: MediaStream) => IConnector) | undefined); /** * Sets server properties for packet error (nack) and delayed packet loss (drop) * and fires an onRTPProps event if changed successfully. * NOTE: Method can also retrieve current server values if called without arguments. * @param nack Waiting period before declaring a packet error * @param drop Waiting period before considering delayed packets as lost */ setRTPProps(nack?: number, drop?: number): void; /** * Returns connection info, such as round trip time, requests sent and received, * bytes sent and received, and bitrates * NOTE: This call is resource-intensive for the CPU. * @returns {Promise<ConnectionInfos>} A promise for a ConnectionInfos */ connectionInfos(): Promise<ConnectionInfos>; /** * Starts broadcasting the stream * The connector is determined automatically from {@link Connect.Params.endPoint} if not forced in the constructor. * * The `adaptiveBitrate` option can take three different types of value: * - A {@link ABRParams} parameters to configure the default ABRLinear implementation * - undefined to disable ABR management * - Use a custom {@link ABRAbstract} implementation instance * * @param stream {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaStream MediaStream} instance to stream * @param params Connection parameters * @param adaptiveBitrate Adaptive bitrate implementation or ABRParams to configure the default implementation */ start(stream: MediaStream, params: Connect.Params, adaptiveBitrate?: ABRAbstract | ABRParams | undefined): void; /** * Stop streaming the stream * @param error error description on an improper stop */ stop(error?: StreamerError): void; private _computeVideoBitrate; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * SIPConnector is a common abstract class for negotiating a new RTCPeerConnection connection * with the server. * * The child class must implement the _sip method to send the offer to the server and get the answer. * */ declare abstract class SIPConnector extends EventEmitter implements IConnector { /** * @override{@inheritDoc IConnector.onOpen} * @event */ onOpen(stream: MediaStream): void; /** * @override{@inheritDoc IConnector.onClose} * @event */ onClose(error?: ConnectorError): void; /** * @override{@inheritDoc IConnector.opened} */ get opened(): boolean; /** * @override{@inheritDoc IConnector.closed} */ get closed(): boolean; /** * @override{@inheritDoc IConnector.stream} */ get stream(): MediaStream | undefined; /** * @override{@inheritDoc IConnector.streamName} */ get streamName(): string; /** * @override{@inheritDoc IConnector.codecs} */ get codecs(): Set<string>; private _streamName; private _endPoint; private _stream?; private _peerConnection?; private _closed; private _connectionInfos?; private _connectionInfosTime; private _codecs; private _peerConnectionIdleTimeout?; /** * Create a new SIPConnector instance. The RTCPeerConnection is created only when calling _open(). * * By default, a listener channel is negotiated. * To create a streamer channel, pass a stream parameter. */ constructor(connectParams: Connect.Params, stream?: MediaStream); /** * Returns connection info, such as round trip time, requests sent and received, * bytes sent and received, and bitrates * NOTE: This call is resource-intensive for the CPU. * @returns {Promise<ConnectionInfos>} A promise that resolves to an RTCStatsReport object */ connectionInfos(cacheDuration?: number): Promise<ConnectionInfos>; /** * @override{@inheritDoc IConnector.close} */ close(error?: ConnectorError): void; /** * Operates Session Initiation Protocol, this method implement the logic * to send the SDP offer to the server and get the SDP answer in response. * * @param offer SIP Offer * @returns a Promise with SIP Answer as result */ protected abstract _sip(offer: string): Promise<string>; /** * Main function which creates the RTCPeerConnection, creates the offer, * calls the _sip method, then set the answer and calls onOpen */ protected _open(iceServer?: RTCIceServer): void; /** * Fill the codecs set with the codecs found in the sdp * * @param sdp the sdp to parse */ private updateCodecs; /** * To call onOpen just once */ private _tryToOpen; private _startPeerConnectionIdleTimeout; private _clearPeerConnectionIdleTimeout; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * Use HTTPConnector to negotiate a new RTCPeerConnection connection with the server * using WHIP (WebRTC HTTP Ingest Protocol) or WHEP (WebRTC HTTP Egress Protocol). * @example * // Listener channel (no initial 'stream' parameter), listen to a stream without sending data * const connection = new HTTPConnector({endPoint, streamName}); * // we get the media stream from server * connection.onOpen = stream => videoElement.srcObject = stream; * * // Streamer channel (with initial 'stream' parameter), sends and receives media streams * const connection = new HTTPConnector({endPoint, streamName}, {stream: await navigator.mediaDevices.getUserMedia()}); * // the media stream here is our local camera as passed in the above constructor * connection.onOpen = stream => {} */ declare class HTTPConnector extends SIPConnector { private _fetch; private _url; /** * Start the HTTPConnector. * * By default, a listener channel is negotiated. * To create a streamer channel, give a media stream parameter */ constructor(connectParams: Connect.Params, stream?: MediaStream); /** * @override{@inheritDoc SIPConnector.close} */ close(error?: ConnectorError): void; /** * @override{@inheritDoc SIPConnector._sip} */ protected _sip(offer: string): Promise<string>; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * Use WSController to negotiate a new RTCPeerConnection connection with the server * using WebSocket custom signaling and keep that connection open for communication. * @example * // Listener channel (no 'stream' parameter), listen to a stream without sending data * const connection = new WSController({endPoint, streamName}); * connection.onOpen = stream => videoElement.srcObject = stream; * * // Streamer channel (with 'stream' parameter), sends and receives media streams * const connection = new WSController({endPoint, streamName}, {stream: await navigator.mediaDevices.getUserMedia()}); * connection.onOpen = stream => {} */ declare class WSController extends SIPConnector implements IController { /** * @override{@inheritDoc IController.onRTPProps} * @event */ onRTPProps(rtpProps: RTPProps): void; /** * @override{@inheritDoc IController.onMediaReport} * @event */ onMediaReport(mediaReport: MediaReport): void; /** * @override{@inheritDoc IController.onVideoBitrate} * @event */ onVideoBitrate(videoBitrate: number, videoBitrateConstraint: number): void; /** * @override{@inheritDoc IController.onPlaying} * @event */ onPlaying(playing: PlayingInfos): void; private _ws; private _promise?; private _reportWatchdogInterval?; private _reportReceivedTimestamp?; /** * Instantiate the WSController, connect to the WebSocket endpoint * and call _open() to create the RTCPeerConnection. * * By default, a listener channel is negotiated. * To create a streamer channel, pass a stream parameter. */ constructor(connectParams: Connect.Params, stream?: MediaStream); /** * @override{@inheritDoc IController.setRTPProps} */ setRTPProps(nack?: number, drop?: number): void; /** * @override{@inheritDoc IController.setVideoBitrate} */ setVideoBitrate(value: number): void; /** * @override{@inheritDoc IController.setTracks} */ setTracks(tracks: { audio?: number; video?: number; }): void; /** * @override{@inheritDoc IController.send} */ send(type: string, params: object): void; /** * @override{@inheritDoc SIPConnector.close} */ close(error?: ConnectorError): void; /** * @override{@inheritDoc SIPConnector._sip} */ protected _sip(offer: string): Promise<string>; protected _eventHandler(ev: any): void; private _startReportWatchdog; private _clearReportWatchdog; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * ABRGrade is an adaptive bitrate algorithm implementing {@link ABRAbstract} * that uses current bitrate, bitrateConstraint, loss infos of mediaReport * and some level constants to adapt the bitrate in a robust way */ declare class ABRGrade extends ABRAbstract { private _vars; /** * @override{@inheritDoc ABRAbstract.constructor} */ constructor(params: ABRParams, stream?: MediaStream); /** * @override{@inheritDoc ABRAbstract.reset} */ reset(): void; /** * @override {@inheritDoc ABRAbstract._computeBitrate} */ protected _computeBitrate(bitrate: number, bitrateConstraint?: number, mediaReport?: MediaReport): number; private _bitrateRecoveryHandler; private _increaseTargetBitrate; private _decreaseTargetBitrate; private _increaseRecoveryTimeout; private _decreaseRecoveryTimeout; private _formatBitrate; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * ABRLinear is an adaptive bitrate algorithm implementing {@link ABRAbstract} * that uses current bitrate and loss infos in mediaReport to adapt in real-time the bitrate */ declare class ABRLinear extends ABRAbstract { private _vars; /** * @override{@inheritDoc ABRAbstract.constructor} */ constructor(params: ABRParams, stream?: MediaStream); /** * @override */ reset(): void; /** * Compute ideal bitrate regarding current bitrate, bitrateConstraint and loss infos in mediaReport * @override{@inheritDoc ABRAbstract._computeBitrate} */ protected _computeBitrate(bitrate: number, bitrateConstraint?: number, mediaReport?: MediaReport): number; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * MBRLinear is a multi-bitrate algorithm by implementing {@link MBRLinear} that switches between tracks * quality depending on the network's congestion which is evaluated using the gradiant from the number * of lost packets and the number of NACK received. * * In addition before to evaluate the network quality as good it waits to get a full GOP size of frames for video. */ declare class MBRLinear extends MBRAbstract { private _lost; private _nackCount; private _keyFramesDecoded; /** * @override{@inheritDoc MBRAbstract.constructor} */ constructor(params: MBRParams); /** * @override{@inheritDoc MBRAbstract._downBitrate} */ protected _downBitrate(elapsed: number, trackRef: MTrack, stats: RTCInboundRtpStreamStats): boolean; /** * @override{@inheritDoc MBRAbstract._downBitrate} */ protected _upBitrate(elapsed: number, trackRef: MTrack, stats: RTCInboundRtpStreamStats): boolean; } /** * Copyright 2023 Ceeblue B.V. * This file is part of https://github.com/CeeblueTV/webrtc-client which is released under GNU Affero General Public License. * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details. */ /** * IStats is the interface used to implement statistics seralization * The serialized object can then be sent to a server for analysis with {@link Telemetry}. * @example * // MyStats implementation * class MyStats extends IStats { * constructor(obj) { * this._obj = obj; * // Subscribe to onClose event to signal object release (will stop this stats report) * obj.onClose = () => this.onRelease(); * } * async serialize() { * // serialize stats to a JSON object {recvBytes, sendBytes} * return { * recvBytes: this._obj.recvBytes, * sendBytes: this._obj.sendBytes * } * } * } */ interface IStats extends Loggable { /** * Must be called when the resource is closed