gstwebrtc-api: Improve JSDocs, add TypeScript type definitions

* Moves some parts of the docs around to make them better parseable by
JSDoc (e.g. @classdesc moved to the constructor gets rid of duplicated
doc page for the entire class)

* Gets rid of unnecessary manual assignment of methods/properties
example: @method GstWebRTCAPI#createConsumerSession
Due to a bug in JSDoc, it doesn't automatically pick up docs in classes
marked with 'export default class ...'. Just making the export separate
is enough to fix this. I suppose this bug was why every documented part
was manually assigned to each class, and this is no longer necessary.

* Removes forced GstWebRTCAPI namespace from docs
I'm not sure why things were left this way, but at least since
563eff1193 our classes aren't actually in
any namespace (well, maybe apart from SessionState?), you can import
them one by one and no such namespace is present anywhere. I removed
that, kind of as a byproduct of the point above.

* Removes external: from type references
This is problematic because JSDoc handles this fine, but any IDE I've
tried couldn't parse those references correctly from the JSDocs, and
neither could the TypeScript compiler when autogenerating type
definitions. After removing the external: prefix, all tooling is picking
those types up fine, but JSDoc's docs end up losing links when refering
to said types. I left the definitions in index.js, so that they still
show up in the sidebar and can be easily referred to.

* Adds TypeScript type definitions (d.ts)
Those are autogenerated by running `npx tsc` in the main dir and then
manually corrected by 1) removing all undocumented ('private') functions
and 2) writing definitions for the Listener interfaces which TS can't
automatically infer from JSDocs. This makes it much easier to use our
library in TypeScript-based projects.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/2049>
This commit is contained in:
Piotr Brzeziński 2025-01-14 18:13:45 +01:00 committed by GStreamer Marge Bot
parent 23c9b28ec7
commit 35a238b66f
21 changed files with 351 additions and 220 deletions

View file

@ -56,6 +56,10 @@
"no-multiple-empty-lines": "error",
"no-trailing-spaces": "error",
"quotes": "error",
"semi": "error"
}
"semi": "error",
"jsdoc/no-undefined-types": "warn"
},
"plugins": [
"jsdoc"
]
}

View file

@ -0,0 +1,5 @@
{
"plugins": [
"node_modules/jsdoc-tsimport-plugin/index.js"
]
}

View file

@ -32,6 +32,7 @@
"docs/",
"src/",
"test/",
"types/",
"index.html",
"LICENSE-MPL-2.0",
"webpack.config.cjs"
@ -39,16 +40,19 @@
"devDependencies": {
"chai": "4.3.8",
"eslint": "8.49.0",
"eslint-plugin-jsdoc": "50.6.1",
"html-webpack-plugin": "5.5.3",
"jsdoc": "4.0.2",
"mocha": "10.2.0",
"rimraf": "5.0.1",
"terser-webpack-plugin": "5.3.9",
"typescript": "5.7.3",
"webpack": "5.88.2",
"webpack-cli": "5.1.4",
"webpack-dev-server": "4.15.1"
},
"dependencies": {
"jsdoc-tsimport-plugin": "1.0.5",
"patch-package": "8.0.0",
"webrtc-adapter": "8.2.3"
},
@ -56,11 +60,13 @@
"check": "eslint src",
"format": "eslint --fix --fix-type layout src",
"build": "rimraf dist && webpack",
"docs": "rimraf docs && jsdoc src/*.js -d docs/ -p package.json -R README.md",
"docs": "rimraf docs && jsdoc src/*.js -d docs/ -p package.json -R README.md -c jsdoc.conf.json",
"make": "npm run check && npm run build && npm run docs",
"test": "mocha --node-env=test --exit",
"prepack": "npm run test && npm run make",
"start": "webpack serve",
"postinstall": "patch-package"
}
},
"types": "types/index.d.ts",
"main": "src/index.js"
}

View file

@ -53,7 +53,7 @@ function normalizeProducer(producer, excludedId) {
return Object.freeze(normalizedProducer);
}
export default class ComChannel extends EventTarget {
class ComChannel extends EventTarget {
constructor(url, meta, webrtcConfig) {
super();
@ -336,3 +336,5 @@ export default class ComChannel extends EventTarget {
}
}
}
export default ComChannel;

View file

@ -27,9 +27,14 @@
* @property {number} reconnectionTimeout=2500 - Timeout in milliseconds to reconnect to the signaling server in
* case of an unexpected disconnection.
* @property {object} webrtcConfig={iceServers...} - The WebRTC peer connection configuration passed to
* {@link external:RTCPeerConnection}. Default configuration only includes a list of free STUN servers
* {@link RTCPeerConnection}. Default configuration only includes a list of free STUN servers
* (<i>stun[0-4].l.google.com:19302</i>).
*/
/**
* Default GstWebRTCAPI configuration.
* @type {GstWebRTCConfig}
*/
const defaultConfig = Object.freeze({
meta: null,
signalingServerUrl: "ws://127.0.0.1:8443",
@ -46,4 +51,4 @@ const defaultConfig = Object.freeze({
}
});
export { defaultConfig as default };
export default defaultConfig;

View file

@ -15,30 +15,30 @@ import RemoteController from "./remote-controller.js";
/**
* Event name: "streamsChanged".<br>
* Triggered when the underlying media streams of a {@link GstWebRTCAPI.ConsumerSession} change.
* Triggered when the underlying media streams of a {@link ConsumerSession} change.
* @event GstWebRTCAPI#StreamsChangedEvent
* @type {external:Event}
* @see GstWebRTCAPI.ConsumerSession#streams
* @type {Event}
* @see ConsumerSession#streams
*/
/**
* Event name: "remoteControllerChanged".<br>
* Triggered when the underlying remote controller of a {@link GstWebRTCAPI.ConsumerSession} changes.
* Triggered when the underlying remote controller of a {@link ConsumerSession} changes.
* @event GstWebRTCAPI#RemoteControllerChangedEvent
* @type {external:Event}
* @see GstWebRTCAPI.ConsumerSession#remoteController
* @type {Event}
* @see ConsumerSession#remoteController
*/
/**
* @class GstWebRTCAPI.ConsumerSession
* @class ConsumerSession
* @hideconstructor
* @classdesc Consumer session managing a peer-to-peer WebRTC channel between a remote producer and this client
* instance.
* <p>Call {@link GstWebRTCAPI#createConsumerSession} to create a ConsumerSession instance.</p>
* @extends {GstWebRTCAPI.WebRTCSession}
* @extends {WebRTCSession}
* @fires {@link GstWebRTCAPI#event:StreamsChangedEvent}
* @fires {@link GstWebRTCAPI#event:RemoteControllerChangedEvent}
*/
export default class ConsumerSession extends WebRTCSession {
class ConsumerSession extends WebRTCSession {
constructor(peerId, comChannel, offerOptions) {
super(peerId, comChannel);
this._streams = [];
@ -60,6 +60,7 @@ export default class ConsumerSession extends WebRTCSession {
/**
* Defines whether the SDP should be munged in order to enable stereo with chrome.
* @method
* @param {boolean} enable - Enable or disable the hack, default is false
*/
set mungeStereoHack(enable) {
@ -69,36 +70,35 @@ export default class ConsumerSession extends WebRTCSession {
}
/**
* The array of remote media streams consumed locally through this WebRTC channel.
* @member {external:MediaStream[]} GstWebRTCAPI.ConsumerSession#streams
* @readonly
*/
* The array of remote media streams consumed locally through this WebRTC channel.
* @type {MediaStream[]}
* @readonly
*/
get streams() {
return this._streams;
}
/**
* The remote controller associated with this WebRTC consumer session. Value may be null if consumer session
* has no remote controller.
* @member {GstWebRTCAPI.RemoteController} GstWebRTCAPI.ConsumerSession#remoteController
* @readonly
*/
* The remote controller associated with this WebRTC consumer session. Value may be null if consumer session
* has no remote controller.
* @type {RemoteController}
* @readonly
*/
get remoteController() {
return this._remoteController;
}
/**
* Connects the consumer session to its remote producer.<br>
* This method must be called after creating the consumer session in order to start receiving the remote streams.
* It registers this consumer session to the signaling server and gets ready to receive audio/video streams.
* <p>Even on success, streaming can fail later if any error occurs during or after connection. In order to know
* the effective streaming state, you should be listening to the [error]{@link GstWebRTCAPI#event:ErrorEvent},
* [stateChanged]{@link GstWebRTCAPI#event:StateChangedEvent} and/or [closed]{@link GstWebRTCAPI#event:ClosedEvent}
* events.</p>
* @method GstWebRTCAPI.ConsumerSession#connect
* @returns {boolean} true in case of success (may fail later during or after connection) or false in case of
* immediate error (wrong session state or no connection to the signaling server).
*/
* Connects the consumer session to its remote producer.<br>
* This method must be called after creating the consumer session in order to start receiving the remote streams.
* It registers this consumer session to the signaling server and gets ready to receive audio/video streams.
* <p>Even on success, streaming can fail later if any error occurs during or after connection. In order to know
* the effective streaming state, you should be listening to the [error]{@link GstWebRTCAPI#event:ErrorEvent},
* [stateChanged]{@link GstWebRTCAPI#event:StateChangedEvent} and/or [closed]{@link GstWebRTCAPI#event:ClosedEvent}
* events.</p>
* @returns {boolean} true in case of success (may fail later during or after connection) or false in case of
* immediate error (wrong session state or no connection to the signaling server).
*/
connect() {
if (!this._comChannel || (this._state === SessionState.closed)) {
return false;
@ -357,3 +357,5 @@ export default class ConsumerSession extends WebRTCSession {
}
}
}
export default ConsumerSession;

View file

@ -12,16 +12,16 @@
import defaultConfig from "./config.js";
import ComChannel from "./com-channel.js";
import SessionState from "./session-state.js";
import ConsumerSession from "./consumer-session.js";
import ProducerSession from "./producer-session.js";
/**
* @class GstWebRTCAPI
* @classdesc The API entry point that manages a WebRTC.
*/
export default class GstWebRTCAPI {
class GstWebRTCAPI {
/**
* @constructor GstWebRTCAPI
* @param {GstWebRTCConfig} [userConfig] - The user configuration.<br>Only the parameters different from the default
* ones need to be provided.
* @class GstWebRTCAPI
* @classdesc The API entry point that manages a WebRTC.
* @constructor
* @param {import('./config.js').GstWebRTCConfig} [userConfig] - The user configuration.<br>
* Only the parameters different from the default ones need to be provided.
*/
constructor(userConfig) {
this._channel = null;
@ -43,12 +43,12 @@ export default class GstWebRTCAPI {
}
/**
* @interface GstWebRTCAPI.ConnectionListener
* @interface ConnectionListener
*/
/**
* Callback method called when this client connects to the WebRTC signaling server.
* The callback implementation should not throw any exception.
* @method GstWebRTCAPI.ConnectionListener#connected
* @method ConnectionListener#connected
* @abstract
* @param {string} clientId - The unique identifier of this WebRTC client.<br>This identifier is provided by the
* signaling server to uniquely identify each connected peer.
@ -56,15 +56,14 @@ export default class GstWebRTCAPI {
/**
* Callback method called when this client disconnects from the WebRTC signaling server.
* The callback implementation should not throw any exception.
* @method GstWebRTCAPI.ConnectionListener#disconnected
* @method ConnectionListener#disconnected
* @abstract
*/
/**
* Registers a connection listener that will be called each time the WebRTC API connects to or disconnects from the
* signaling server.
* @method GstWebRTCAPI#registerConnectionListener
* @param {GstWebRTCAPI.ConnectionListener} listener - The connection listener to register.
* @param {ConnectionListener} listener - The connection listener to register.
* @returns {boolean} true in case of success (or if the listener was already registered), or false if the listener
* doesn't implement all callback functions and cannot be registered.
*/
@ -85,8 +84,7 @@ export default class GstWebRTCAPI {
/**
* Unregisters a connection listener.<br>
* The removed listener will never be called again and can be garbage collected.
* @method GstWebRTCAPI#unregisterConnectionListener
* @param {GstWebRTCAPI.ConnectionListener} listener - The connection listener to unregister.
* @param {ConnectionListener} listener - The connection listener to unregister.
* @returns {boolean} true if the listener is found and unregistered, or false if the listener was not previously
* registered.
*/
@ -102,7 +100,6 @@ export default class GstWebRTCAPI {
/**
* Unregisters all previously registered connection listeners.
* @method GstWebRTCAPI#unregisterAllConnectionListeners
*/
unregisterAllConnectionListeners() {
this._connectionListeners = [];
@ -113,12 +110,11 @@ export default class GstWebRTCAPI {
* <p>You can only create one producer session at a time.<br>
* To request streaming from a new stream you will first need to close the previous producer session.</p>
* <p>You can only request a producer session while you are connected to the signaling server. You can use the
* {@link GstWebRTCAPI.ConnectionListener} interface and {@link GstWebRTCAPI#registerConnectionListener} method to
* {@link ConnectionListener} interface and {@link GstWebRTCAPI#registerConnectionListener} method to
* listen to the connection state.</p>
* @method GstWebRTCAPI#createProducerSession
* @param {external:MediaStream} stream - The audio/video stream to offer as a producer through WebRTC.
* @returns {GstWebRTCAPI.ProducerSession} The created producer session or null in case of error. To start streaming,
* you still need to call {@link GstWebRTCAPI.ProducerSession#start} after adding on the returned session all the event
* @param {MediaStream} stream - The audio/video stream to offer as a producer through WebRTC.
* @returns {ProducerSession} The created producer session or null in case of error. To start streaming,
* you still need to call {@link ProducerSession#start} after adding on the returned session all the event
* listeners you may need.
*/
createProducerSession(stream) {
@ -130,7 +126,7 @@ export default class GstWebRTCAPI {
/**
* Information about a remote producer registered by the signaling server.
* @typedef {object} GstWebRTCAPI.Producer
* @typedef {object} Producer
* @readonly
* @property {string} id - The remote producer unique identifier set by the signaling server (always non-empty).
* @property {object} meta - Free-form object containing extra information about the remote producer (always non-null,
@ -140,38 +136,36 @@ export default class GstWebRTCAPI {
/**
* Gets the list of all remote WebRTC producers available on the signaling server.
* <p>The remote producers list is only populated once you've connected to the signaling server. You can use the
* {@link GstWebRTCAPI.ConnectionListener} interface and {@link GstWebRTCAPI#registerConnectionListener} method to
* {@link ConnectionListener} interface and {@link GstWebRTCAPI#registerConnectionListener} method to
* listen to the connection state.</p>
* @method GstWebRTCAPI#getAvailableProducers
* @returns {GstWebRTCAPI.Producer[]} The list of remote WebRTC producers available.
* @returns {Producer[]} The list of remote WebRTC producers available.
*/
getAvailableProducers() {
return Object.values(this._producers);
}
/**
* @interface GstWebRTCAPI.ProducersListener
* @interface ProducersListener
*/
/**
* Callback method called when a remote producer is added on the signaling server.
* The callback implementation should not throw any exception.
* @method GstWebRTCAPI.ProducersListener#producerAdded
* @method ProducersListener#producerAdded
* @abstract
* @param {GstWebRTCAPI.Producer} producer - The remote producer added on server-side.
* @param {Producer} producer - The remote producer added on server-side.
*/
/**
* Callback method called when a remote producer is removed from the signaling server.
* The callback implementation should not throw any exception.
* @method GstWebRTCAPI.ProducersListener#producerRemoved
* @method ProducersListener#producerRemoved
* @abstract
* @param {GstWebRTCAPI.Producer} producer - The remote producer removed on server-side.
* @param {Producer} producer - The remote producer removed on server-side.
*/
/**
* Registers a producers listener that will be called each time a producer is added or removed on the signaling
* server.
* @method GstWebRTCAPI#registerProducersListener
* @param {GstWebRTCAPI.ProducersListener} listener - The producer listener to register.
* @param {ProducersListener} listener - The producer listener to register.
* @returns {boolean} true in case of success (or if the listener was already registered), or false if the listener
* doesn't implement all callback functions and cannot be registered.
*/
@ -192,8 +186,7 @@ export default class GstWebRTCAPI {
/**
* Unregisters a producers listener.<br>
* The removed listener will never be called again and can be garbage collected.
* @method GstWebRTCAPI#unregisterProducersListener
* @param {GstWebRTCAPI.ProducersListener} listener - The producers listener to unregister.
* @param {ProducersListener} listener - The producers listener to unregister.
* @returns {boolean} true if the listener is found and unregistered, or false if the listener was not previously
* registered.
*/
@ -209,7 +202,6 @@ export default class GstWebRTCAPI {
/**
* Unregisters all previously registered producers listeners.
* @method GstWebRTCAPI#unregisterAllProducersListeners
*/
unregisterAllProducersListeners() {
this._producersListeners = [];
@ -219,13 +211,12 @@ export default class GstWebRTCAPI {
* Creates a consumer session by connecting the local client to a remote WebRTC producer.
* <p>You can only create one consumer session per remote producer.</p>
* <p>You can only request a new consumer session while you are connected to the signaling server. You can use the
* {@link GstWebRTCAPI.ConnectionListener} interface and {@link GstWebRTCAPI#registerConnectionListener} method to
* {@link ConnectionListener} interface and {@link GstWebRTCAPI#registerConnectionListener} method to
* listen to the connection state.</p>
* @method GstWebRTCAPI#createConsumerSession
* @param {string} producerId - The unique identifier of the remote producer to connect to.
* @returns {GstWebRTCAPI.ConsumerSession} The WebRTC session between the selected remote producer and this local
* @returns {ConsumerSession} The WebRTC session between the selected remote producer and this local
* consumer, or null in case of error. To start connecting and receiving the remote streams, you still need to call
* {@link GstWebRTCAPI.ConsumerSession#connect} after adding on the returned session all the event listeners you may
* {@link ConsumerSession#connect} after adding on the returned session all the event listeners you may
* need.
*/
createConsumerSession(producerId) {
@ -238,12 +229,11 @@ export default class GstWebRTCAPI {
/**
* Creates a consumer session by connecting the local client to a remote WebRTC producer and creating the offer.
* <p>See {@link GstWebRTCAPI#createConsumerSession} for more information</p>
* @method GstWebRTCAPI#createConsumerSessionWithOfferOptions
* @param {string} producerId - The unique identifier of the remote producer to connect to.
* @param {external:RTCOfferOptions} offerOptions - An object to use when creating the offer.
* @returns {GstWebRTCAPI.ConsumerSession} The WebRTC session between the selected remote producer and this local
* @param {RTCOfferOptions} offerOptions - An object to use when creating the offer.
* @returns {ConsumerSession} The WebRTC session between the selected remote producer and this local
* consumer, or null in case of error. To start connecting and receiving the remote streams, you still need to call
* {@link GstWebRTCAPI.ConsumerSession#connect} after adding on the returned session all the event listeners you may
* {@link ConsumerSession#connect} after adding on the returned session all the event listeners you may
* need.
*/
createConsumerSessionWithOfferOptions(producerId, offerOptions) {
@ -365,3 +355,5 @@ export default class GstWebRTCAPI {
}
GstWebRTCAPI.SessionState = SessionState;
export default GstWebRTCAPI;

View file

@ -24,6 +24,10 @@ import GstWebRTCAPI from "./gstwebrtc-api.js";
* @external RTCDataChannel
* @see https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel
*/
/**
* @external RTCOfferOptions
* @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer#options
*/
/**
* @external EventTarget
* @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget
@ -52,3 +56,5 @@ import GstWebRTCAPI from "./gstwebrtc-api.js";
if (!window.GstWebRTCAPI) {
window.GstWebRTCAPI = GstWebRTCAPI;
}
export default GstWebRTCAPI;

View file

@ -13,10 +13,10 @@ import WebRTCSession from "./webrtc-session.js";
import SessionState from "./session-state.js";
/**
* @class GstWebRTCAPI.ClientSession
* @class ClientSession
* @hideconstructor
* @classdesc Client session representing a link between a remote consumer and a local producer session.
* @extends {GstWebRTCAPI.WebRTCSession}
* @extends {WebRTCSession}
*/
class ClientSession extends WebRTCSession {
constructor(peerId, sessionId, comChannel, stream) {
@ -102,35 +102,35 @@ class ClientSession extends WebRTCSession {
/**
* Event name: "clientConsumerAdded".<br>
* Triggered when a remote consumer peer connects to a local {@link GstWebRTCAPI.ProducerSession}.
* Triggered when a remote consumer peer connects to a local {@link ProducerSession}.
* @event GstWebRTCAPI#ClientConsumerAddedEvent
* @type {external:CustomEvent}
* @property {GstWebRTCAPI.ClientSession} detail - The WebRTC session associated with the added consumer peer.
* @see GstWebRTCAPI.ProducerSession
* @type {CustomEvent}
* @property {ClientSession} detail - The WebRTC session associated with the added consumer peer.
* @see ProducerSession
*/
/**
* Event name: "clientConsumerRemoved".<br>
* Triggered when a remote consumer peer disconnects from a local {@link GstWebRTCAPI.ProducerSession}.
* Triggered when a remote consumer peer disconnects from a local {@link ProducerSession}.
* @event GstWebRTCAPI#ClientConsumerRemovedEvent
* @type {external:CustomEvent}
* @property {GstWebRTCAPI.ClientSession} detail - The WebRTC session associated with the removed consumer peer.
* @see GstWebRTCAPI.ProducerSession
* @type {CustomEvent}
* @property {ClientSession} detail - The WebRTC session associated with the removed consumer peer.
* @see ProducerSession
*/
/**
* @class GstWebRTCAPI.ProducerSession
* @class ProducerSession
* @hideconstructor
* @classdesc Producer session managing the streaming out of a local {@link external:MediaStream}.<br>
* @classdesc Producer session managing the streaming out of a local {@link MediaStream}.<br>
* It manages all underlying WebRTC connections to each peer client consuming the stream.
* <p>Call {@link GstWebRTCAPI#createProducerSession} to create a ProducerSession instance.</p>
* @extends {external:EventTarget}
* @extends {EventTarget}
* @fires {@link GstWebRTCAPI#event:ErrorEvent}
* @fires {@link GstWebRTCAPI#event:StateChangedEvent}
* @fires {@link GstWebRTCAPI#event:ClosedEvent}
* @fires {@link GstWebRTCAPI#event:ClientConsumerAddedEvent}
* @fires {@link GstWebRTCAPI#event:ClientConsumerRemovedEvent}
*/
export default class ProducerSession extends EventTarget {
class ProducerSession extends EventTarget {
constructor(comChannel, stream) {
super();
@ -141,35 +141,34 @@ export default class ProducerSession extends EventTarget {
}
/**
* The local stream produced out by this session.
* @member {external:MediaStream} GstWebRTCAPI.ProducerSession#stream
* @readonly
*/
* The local stream produced out by this session.
* @type {MediaStream}
* @readonly
*/
get stream() {
return this._stream;
}
/**
* The current producer session state.
* @member {GstWebRTCAPI.SessionState} GstWebRTCAPI.ProducerSession#state
* @readonly
*/
* The current producer session state.
* @type {SessionState}
* @readonly
*/
get state() {
return this._state;
}
/**
* Starts the producer session.<br>
* This method must be called after creating the producer session in order to start streaming. It registers this
* producer session to the signaling server and gets ready to serve peer requests from consumers.
* <p>Even on success, streaming can fail later if any error occurs during or after connection. In order to know
* the effective streaming state, you should be listening to the [error]{@link GstWebRTCAPI#event:ErrorEvent},
* [stateChanged]{@link GstWebRTCAPI#event:StateChangedEvent} and/or [closed]{@link GstWebRTCAPI#event:ClosedEvent}
* events.</p>
* @method GstWebRTCAPI.ProducerSession#start
* @returns {boolean} true in case of success (may fail later during or after connection) or false in case of
* immediate error (wrong session state or no connection to the signaling server).
*/
* Starts the producer session.<br>
* This method must be called after creating the producer session in order to start streaming. It registers this
* producer session to the signaling server and gets ready to serve peer requests from consumers.
* <p>Even on success, streaming can fail later if any error occurs during or after connection. In order to know
* the effective streaming state, you should be listening to the [error]{@link GstWebRTCAPI#event:ErrorEvent},
* [stateChanged]{@link GstWebRTCAPI#event:StateChangedEvent} and/or [closed]{@link GstWebRTCAPI#event:ClosedEvent}
* events.</p>
* @returns {boolean} true in case of success (may fail later during or after connection) or false in case of
* immediate error (wrong session state or no connection to the signaling server).
*/
start() {
if (!this._comChannel || (this._state === SessionState.closed)) {
return false;
@ -200,11 +199,10 @@ export default class ProducerSession extends EventTarget {
}
/**
* Terminates the producer session.<br>
* It immediately disconnects all peer consumers attached to this producer session and unregisters the producer
* from the signaling server.
* @method GstWebRTCAPI.ProducerSession#close
*/
* Terminates the producer session.<br>
* It immediately disconnects all peer consumers attached to this producer session and unregisters the producer
* from the signaling server.
*/
close() {
if (this._state !== SessionState.closed) {
for (const track of this._stream.getTracks()) {
@ -277,3 +275,5 @@ export default class ProducerSession extends EventTarget {
}
}
}
export default ProducerSession;

View file

@ -10,6 +10,7 @@
*/
import getKeysymString from "./keysyms.js";
import ConsumerSession from "./consumer-session.js";
const eventsNames = Object.freeze([
"wheel",
@ -68,21 +69,21 @@ function getModifiers(event) {
* Event name: "info".<br>
* Triggered when a remote peer sends an information message over the control data channel.
* @event GstWebRTCAPI#InfoEvent
* @type {external:CustomEvent}
* @type {CustomEvent}
* @property {object} detail - The info message
* @see GstWebRTCAPI.RemoteController
* @see RemoteController
*/
/**
* Event name: "controlResponse".<br>
* Triggered when a remote peer sends a response after a control request.
* @event GstWebRTCAPI#ControlResponseEvent
* @type {external:CustomEvent}
* @type {CustomEvent}
* @property {object} detail - The response message
* @see GstWebRTCAPI.RemoteController
* @see RemoteController
*/
/**
* @class GstWebRTCAPI.RemoteController
* @class RemoteController
* @hideconstructor
* @classdesc Manages a specific WebRTC data channel created by a remote GStreamer webrtcsink producer and offering
* remote control of the producer through
@ -90,18 +91,18 @@ function getModifiers(event) {
* <p>The remote control data channel is created by the GStreamer webrtcsink element on the producer side. Then it is
* announced through the consumer session thanks to the {@link gstWebRTCAPI#event:RemoteControllerChangedEvent}
* event.</p>
* <p>You can attach an {@link external:HTMLVideoElement} to the remote controller, then all mouse and keyboard events
* <p>You can attach an {@link HTMLVideoElement} to the remote controller, then all mouse and keyboard events
* emitted by this element will be automatically relayed to the remote producer.</p>
* @extends {external:EventTarget}
* @extends {EventTarget}
* @fires {@link GstWebRTCAPI#event:ErrorEvent}
* @fires {@link GstWebRTCAPI#event:ClosedEvent}
* @fires {@link GstWebRTCAPI#event:InfoEvent}
* @fires {@link GstWebRTCAPI#event:ControlResponseEvent}
* @see GstWebRTCAPI.ConsumerSession#remoteController
* @see GstWebRTCAPI.RemoteController#attachVideoElement
* @see ConsumerSession#remoteController
* @see RemoteController#attachVideoElement
* @see https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/tree/main/net/webrtc/gstwebrtc-api#produce-a-gstreamer-interactive-webrtc-stream-with-remote-control
*/
export default class RemoteController extends EventTarget {
class RemoteController extends EventTarget {
constructor(rtcDataChannel, consumerSession) {
super();
@ -150,44 +151,43 @@ export default class RemoteController extends EventTarget {
/**
* The underlying WebRTC data channel connected to a remote GStreamer webrtcsink producer offering remote control.
* The value may be null if the remote controller has been closed.
* @member {external:RTCDataChannel} GstWebRTCAPI.RemoteController#rtcDataChannel
* @readonly
*/
* The underlying WebRTC data channel connected to a remote GStreamer webrtcsink producer offering remote control.
* The value may be null if the remote controller has been closed.
* @type {RTCDataChannel}
* @readonly
*/
get rtcDataChannel() {
return this._rtcDataChannel;
}
/**
* The consumer session associated with this remote controller.
* @member {GstWebRTCAPI.ConsumerSession} GstWebRTCAPI.RemoteController#consumerSession
* @readonly
*/
* The consumer session associated with this remote controller.
* @type {ConsumerSession}
* @readonly
*/
get consumerSession() {
return this._consumerSession;
}
/**
* The video element that is currently used to send all mouse and keyboard events to the remote producer. Value may
* be null if no video element is attached.
* @member {external:HTMLVideoElement} GstWebRTCAPI.RemoteController#videoElement
* @readonly
* @see GstWebRTCAPI.RemoteController#attachVideoElement
*/
* The video element that is currently used to send all mouse and keyboard events to the remote producer. Value may
* be null if no video element is attached.
* @type {HTMLVideoElement}
* @readonly
* @see RemoteController#attachVideoElement
*/
get videoElement() {
return this._videoElement;
}
/**
* Associates a video element with this remote controller.<br>
* When a video element is attached to this remote controller, all mouse and keyboard events emitted by this
* element will be sent to the remote GStreamer webrtcink producer.
* @method GstWebRTCAPI.RemoteController#attachVideoElement
* @param {external:HTMLVideoElement|null} element - the video element to use to relay mouse and keyboard events,
* or null to detach any previously attached element. If the provided element parameter is not null and not a
* valid instance of an {@link external:HTMLVideoElement}, then the method does nothing.
*/
* Associates a video element with this remote controller.<br>
* When a video element is attached to this remote controller, all mouse and keyboard events emitted by this
* element will be sent to the remote GStreamer webrtcink producer.
* @param {HTMLVideoElement|null} element - the video element to use to relay mouse and keyboard events,
* or null to detach any previously attached element. If the provided element parameter is not null and not a
* valid instance of an {@link HTMLVideoElement}, then the method does nothing.
*/
attachVideoElement(element) {
if ((element instanceof HTMLVideoElement) && (element !== this._videoElement)) {
if (this._videoElement) {
@ -218,13 +218,12 @@ export default class RemoteController extends EventTarget {
}
/**
* Send a request over the control data channel.<br>
*
* @method GstWebRTCAPI.RemoteController#sendControlRequest
* @fires {@link GstWebRTCAPI#event:ErrorEvent}
* @param {object|string} request - The request to send over the channel
* @returns {number} The identifier attributed to the request, or -1 if an exception occurred
*/
* Send a request over the control data channel.<br>
*
* @fires {@link GstWebRTCAPI#event:ErrorEvent}
* @param {object|string} request - The request to send over the channel
* @returns {number} The identifier attributed to the request, or -1 if an exception occurred
*/
sendControlRequest(request) {
try {
if (!request || ((typeof (request) !== "object") && (typeof (request) !== "string"))) {
@ -253,11 +252,10 @@ export default class RemoteController extends EventTarget {
}
/**
* Closes the remote controller channel.<br>
* It immediately shuts down the underlying WebRTC data channel connected to a remote GStreamer webrtcsink
* producer and detaches any video element that may be used to relay mouse and keyboard events.
* @method GstWebRTCAPI.RemoteController#close
*/
* Closes the remote controller channel.<br>
* It immediately shuts down the underlying WebRTC data channel connected to a remote GStreamer webrtcsink
* producer and detaches any video element that may be used to relay mouse and keyboard events.
*/
close() {
this.attachVideoElement(null);
@ -417,3 +415,5 @@ export default class RemoteController extends EventTarget {
}
}
}
export default RemoteController;

View file

@ -12,21 +12,29 @@
/**
* Session states enumeration.<br>
* Session state always increases from idle to closed and never switches backwards.
* @typedef {enum} GstWebRTCAPI.SessionState
* @enum {number}
* @readonly
* @property {0} idle - Default state when creating a new session, goes to <i>connecting</i> when starting
* the session.
* @property {1} connecting - Session is trying to connect to remote peers, goes to <i>streaming</i> in case of
* success or <i>closed</i> in case of error.
* @property {2} streaming - Session is correctly connected to remote peers and currently streaming audio/video, goes
* to <i>closed</i> when any peer closes the session.
* @property {3} closed - Session is closed and can be garbage collected, state will not change anymore.
*/
const SessionState = Object.freeze({
const SessionState = /** @type {const} */ {
/**
* (0) Default state when creating a new session, goes to <i>connecting</i> when starting the session.
*/
idle: 0,
/**
* (1) Session is trying to connect to remote peers, goes to <i>streaming</i> in case of
* success or <i>closed</i> in case of error.
*/
connecting: 1,
/**
* (2) Session is correctly connected to remote peers and currently streaming audio/video, goes
* to <i>closed</i> when any peer closes the session.
*/
streaming: 2,
/**
* (3) Session is closed and can be garbage collected, state will not change anymore.
*/
closed: 3
});
};
Object.freeze(SessionState);
export { SessionState as default };
export default SessionState;

View file

@ -10,60 +10,62 @@
*/
import SessionState from "./session-state.js";
import ProducerSession from "./producer-session.js";
import ClientSession from "./producer-session.js";
/**
* Event name: "error".<br>
* Triggered when any kind of error occurs.
* <p>When emitted by a session, it is in general an unrecoverable error. Normally, the session is automatically closed
* but in the specific case of a {@link GstWebRTCAPI.ProducerSession}, when the error occurs on an underlying
* {@link GstWebRTCAPI.ClientSession} between the producer session and a remote client consuming the streamed media,
* then only the failing {@link GstWebRTCAPI.ClientSession} is closed. The producer session can keep on serving the
* but in the specific case of a {@link ProducerSession}, when the error occurs on an underlying
* {@link ClientSession} between the producer session and a remote client consuming the streamed media,
* then only the failing {@link ClientSession} is closed. The producer session can keep on serving the
* other consumer peers.</p>
* @event GstWebRTCAPI#ErrorEvent
* @type {external:ErrorEvent}
* @type {ErrorEvent}
* @property {string} message - The error message.
* @property {external:Error} error - The error exception.
* @see GstWebRTCAPI.WebRTCSession
* @see GstWebRTCAPI.RemoteController
* @property {Error} error - The error exception.
* @see WebRTCSession
* @see RemoteController
*/
/**
* Event name: "stateChanged".<br>
* Triggered each time a session state changes.
* @event GstWebRTCAPI#StateChangedEvent
* @type {external:Event}
* @see GstWebRTCAPI.WebRTCSession#state
* @type {Event}
* @see WebRTCSession#state
*/
/**
* Event name: "rtcPeerConnectionChanged".<br>
* Triggered each time a session internal {@link external:RTCPeerConnection} changes. This can occur during the session
* Triggered each time a session internal {@link RTCPeerConnection} changes. This can occur during the session
* connecting state when the peer-to-peer WebRTC connection is established, and when closing the
* {@link GstWebRTCAPI.WebRTCSession}.
* {@link WebRTCSession}.
* @event GstWebRTCAPI#RTCPeerConnectionChangedEvent
* @type {external:Event}
* @see GstWebRTCAPI.WebRTCSession#rtcPeerConnection
* @type {Event}
* @see WebRTCSession#rtcPeerConnection
*/
/**
* Event name: "closed".<br>
* Triggered when a session is definitively closed (then it can be garbage collected as session instances are not
* reusable).
* @event GstWebRTCAPI#ClosedEvent
* @type {external:Event}
* @type {Event}
*/
/**
* @class GstWebRTCAPI.WebRTCSession
* @class WebRTCSession
* @hideconstructor
* @classdesc Manages a WebRTC session between a producer and a consumer (peer-to-peer channel).
* @extends {external:EventTarget}
* @extends {EventTarget}
* @fires {@link GstWebRTCAPI#event:ErrorEvent}
* @fires {@link GstWebRTCAPI#event:StateChangedEvent}
* @fires {@link GstWebRTCAPI#event:RTCPeerConnectionChangedEvent}
* @fires {@link GstWebRTCAPI#event:ClosedEvent}
* @see GstWebRTCAPI.ConsumerSession
* @see GstWebRTCAPI.ProducerSession
* @see GstWebRTCAPI.ClientSession
* @see ConsumerSession
* @see ProducerSession
* @see ClientSession
*/
export default class WebRTCSession extends EventTarget {
class WebRTCSession extends EventTarget {
constructor(peerId, comChannel) {
super();
@ -75,53 +77,52 @@ export default class WebRTCSession extends EventTarget {
}
/**
* Unique identifier of the remote peer to which this session is connected.
* @member {string} GstWebRTCAPI.WebRTCSession#peerId
* @readonly
*/
* Unique identifier of the remote peer to which this session is connected.
* @type {string}
* @readonly
*/
get peerId() {
return this._peerId;
}
/**
* Unique identifier of this session (defined by the signaling server).<br>
* The local session ID equals "" until it is created on server side. This is done during the connection handshake.
* The local session ID is guaranteed to be valid and to correctly reflect the signaling server value once
* session state has switched to {@link GstWebRTCAPI.SessionState#streaming}.
* @member {string} GstWebRTCAPI.WebRTCSession#sessionId
* @readonly
*/
* Unique identifier of this session (defined by the signaling server).<br>
* The local session ID equals "" until it is created on server side. This is done during the connection handshake.
* The local session ID is guaranteed to be valid and to correctly reflect the signaling server value once
* session state has switched to {@link SessionState#streaming}.
* @type {string}
* @readonly
*/
get sessionId() {
return this._sessionId;
}
/**
* The current WebRTC session state.
* @member {GstWebRTCAPI.SessionState} GstWebRTCAPI.WebRTCSession#state
* @readonly
*/
* The current WebRTC session state.
* @type {SessionState}
* @readonly
*/
get state() {
return this._state;
}
/**
* The internal {@link external:RTCPeerConnection} used to manage the underlying WebRTC connection with session
* peer. Value may be null if session has no active WebRTC connection. You can listen to the
* {@link GstWebRTCAPI#event:RTCPeerConnectionChangedEvent} event to be informed when the connection is established
* or destroyed.
* @member {external:RTCPeerConnection} GstWebRTCAPI.WebRTCSession#rtcPeerConnection
* @readonly
*/
* The internal {@link RTCPeerConnection} used to manage the underlying WebRTC connection with session
* peer. Value may be null if session has no active WebRTC connection. You can listen to the
* {@link GstWebRTCAPI#event:RTCPeerConnectionChangedEvent} event to be informed when the connection is established
* or destroyed.
* @type {RTCPeerConnection}
* @readonly
*/
get rtcPeerConnection() {
return this._rtcPeerConnection;
}
/**
* Terminates the WebRTC session.<br>
* It immediately disconnects the remote peer attached to this session and unregisters the session from the
* signaling server.
* @method GstWebRTCAPI.WebRTCSession#close
*/
* Terminates the WebRTC session.<br>
* It immediately disconnects the remote peer attached to this session and unregisters the session from the
* signaling server.
*/
close() {
if (this._state !== SessionState.closed) {
if ((this._state !== SessionState.idle) && this._comChannel && this._sessionId) {
@ -146,3 +147,5 @@ export default class WebRTCSession extends EventTarget {
}
}
}
export default WebRTCSession;

View file

@ -0,0 +1,10 @@
{
"include": ["src/index.js"],
"compilerOptions": {
"allowJs": true,
"declaration": true,
"emitDeclarationOnly": true,
"removeComments": true,
"outDir": "./types",
}
}

View file

@ -0,0 +1,8 @@
export default defaultConfig;
export type GstWebRTCConfig = {
meta: object;
signalingServerUrl: string;
reconnectionTimeout: number;
webrtcConfig: object;
};
declare const defaultConfig: GstWebRTCConfig;

View file

@ -0,0 +1,9 @@
export default ConsumerSession;
declare class ConsumerSession extends WebRTCSession {
set mungeStereoHack(enable: boolean);
readonly get streams(): MediaStream[];
readonly get remoteController(): RemoteController;
connect(): boolean;
}
import WebRTCSession from "./webrtc-session.js";
import RemoteController from "./remote-controller.js";

View file

@ -0,0 +1,34 @@
export default GstWebRTCAPI;
declare class GstWebRTCAPI {
constructor(userConfig?: import("./config.js").GstWebRTCConfig);
registerConnectionListener(listener: ConnectionListener): boolean;
unregisterConnectionListener(listener: ConnectionListener): boolean;
unregisterAllConnectionListeners(): void;
createProducerSession(stream: MediaStream): ProducerSession;
getAvailableProducers(): any[];
registerProducersListener(listener: ProducersListener): boolean;
unregisterProducersListener(listener: ProducersListener): boolean;
unregisterAllProducersListeners(): void;
createConsumerSession(producerId: string): ConsumerSession;
createConsumerSessionWithOfferOptions(producerId: string, offerOptions: any): ConsumerSession;
}
declare namespace GstWebRTCAPI {
export { SessionState };
}
import ProducerSession from "./producer-session.js";
import ConsumerSession from "./consumer-session.js";
import SessionState from "./session-state.js";
/* Added manually */
interface ConnectionListener {
connected(clientId: string): void;
disconnected(): void;
}
interface ProducersListener {
producerAdded(producer: Producer): void;
producerRemoved(producer: Producer): void;
}
type Producer = {
readonly id: string;
readonly meta: Record<string, unknown>;
};

View file

@ -0,0 +1,2 @@
export default GstWebRTCAPI;
import GstWebRTCAPI from "./gstwebrtc-api.js";

View file

@ -0,0 +1,8 @@
export default ProducerSession;
declare class ProducerSession extends EventTarget {
readonly get stream(): MediaStream;
readonly get state(): SessionState;
start(): boolean;
close(): void;
}
import SessionState from "./session-state.js";

View file

@ -0,0 +1,10 @@
export default RemoteController;
declare class RemoteController extends EventTarget {
readonly get rtcDataChannel(): RTCDataChannel;
readonly get consumerSession(): ConsumerSession;
readonly get videoElement(): HTMLVideoElement;
attachVideoElement(element: HTMLVideoElement | null): void;
sendControlRequest(request: object | string): number;
close(): void;
}
import ConsumerSession from "./consumer-session.js";

View file

@ -0,0 +1,8 @@
export default SessionState;
type SessionState = number;
declare namespace SessionState {
let idle: number;
let connecting: number;
let streaming: number;
let closed: number;
}

View file

@ -0,0 +1,9 @@
export default WebRTCSession;
declare class WebRTCSession extends EventTarget {
readonly get peerId(): string;
readonly get sessionId(): string;
readonly get state(): SessionState;
readonly get rtcPeerConnection(): RTCPeerConnection;
close(): void;
}
import SessionState from "./session-state.js";