diff --git a/package.json b/package.json index a83bb4f..a7c0e38 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,8 @@ "description": "Meetecho adapter for the Janus WebRTC Server", "version": "1.6.9", "type": "module", + "main": "src/janode.js", + "types": "./types/janode.d", "keywords": [ "janus", "webrtc", @@ -24,16 +26,48 @@ "license": "ISC", "main": "./src/janode.js", "exports": { - ".": "./src/janode.js", - "./plugins/audiobridge": "./src/plugins/audiobridge-plugin.js", - "./plugins/echotest": "./src/plugins/echotest-plugin.js", - "./plugins/streaming": "./src/plugins/streaming-plugin.js", - "./plugins/videoroom": "./src/plugins/videoroom-plugin.js" + ".": { + "import": { + "types": "./types/janode.d.ts", + "default": "./src/janode.js" + } + }, + "./plugins/echotest": { + "import": { + "types": "./types/plugins/echotest-plugin.d.ts", + "default": "./src/plugins/echotest-plugin.js" + } + }, + "./plugins/streaming": { + "import": { + "types": "./types/plugins/streaming-plugin.d.ts", + "default": "./src/plugins/streaming-plugin.js" + } + }, + "./plugins/videoroom": { + "import": { + "types": "./types/plugins/videoroom-plugin.d.ts", + "default": "./src/plugins/videoroom-plugin.js" + } + }, + "./plugins/audiobridge": { + "import": { + "types": "./types/plugins/audiobridge-plugin.d.ts", + "default": "./src/plugins/audiobridge-plugin.js" + } + }, + "./session": { + "import": "./types/session.d.ts" + }, + "./connection": { + "import": "./types/connection.d.ts" + } }, "files": [ "src/*.js", "src/utils/*.js", - "src/plugins/*.js" + "src/plugins/*.js", + "types/**/*" ], "dependencies": { "isomorphic-ws": "^4.0.1", diff --git a/types/configuration.d.ts b/types/configuration.d.ts new file mode 100644 index 0000000..8620f34 --- /dev/null +++ b/types/configuration.d.ts @@ -0,0 +1,47 @@ +import { ServerObjectConf } from './janode.js' +export default Configuration; +/** + * Class representing a Janode configuration. + * The purpose of the class is basically filtering the input config and distinguish Janus API and Admin API connections. + */ +type AddressConfig = { + url: string + apisecret?: string +} +declare class Configuration { + /** + * Create a configuration. + * + * @private + * @param {module:janode~RawConfiguration} config + */ + private constructor(); + address: AddressConfig[]; + retry_time_secs: number; + max_retries: number; + is_admin: boolean; + /** + * Get the server list of this configuration. + * + * @returns {module:janode~ServerObjectConf[]} The address array + */ + getAddress(): ServerObjectConf; + /** + * Get the number of seconds between any attempt. + * + * @returns {number} The value of the property + */ + getRetryTimeSeconds(): number; + /** + * Get the max number of retries. + * + * @returns {number} The value of the property + */ + getMaxRetries(): number; + /** + * Check if the configuration is for an admin connection. + * + * @returns {boolean} True if the configuration will be used for an admin connection + */ + isAdmin(): boolean; +} diff --git a/types/connection.d.ts b/types/connection.d.ts new file mode 100644 index 0000000..e62a154 --- /dev/null +++ b/types/connection.d.ts @@ -0,0 +1,212 @@ +import Session from './session.js' +import { EventEmitter } from 'events' +export default Connection; +/** + * Class representing a Janode connection.
+ * + * Specific transports are picked by checking the connection URI.
+ * + * This class implements both the Janus API and Admin API.
+ * + * Connection extends EventEmitter, so an instance can emit events and users can subscribe to them.
+ * + * Users are not expected to create Connection instances, but insted use the Janode.connect() API.
+ * + * @hideconstructor + */ +declare class Connection extends EventEmitter { + /** + * Create a Janode Connection. + * + * @param {module:configuration~Configuration} server_config - The Janode configuration as created by the Configuration constructor. + */ + constructor(server_config: any); + /** + * The configuration in use for this connection. + * + * @private + * @type {module:configuration~Configuration} + */ + private _config; + /** + * The transaction manager used by this connection. + * + * @private + * @type {module:tmanager~TransactionManager} + */ + private _tm; + /** + * Keep track of the sessions. + * + * @private + * @type {Map} + */ + private _sessions; + /** + * The iterator to select available Janus addresses. + * + * @private + * @type {module:utils~CircularIterator} + */ + private _address_iterator; + /** + * A numerical identifier assigned for logging purposes. + * + * @type {number} + */ + id: number; + /** + * A more descriptive, not unique string (used for logging). + * + * @type {string} + */ + name: string; + /** + * The internal transport that will be used for the connection. + * + * @typedef {object} Transport + * @property {function} open + * @property {function} close + * @property {function} send + * @property {function} getRemoteHostname + */ + _transport: WsTransport | UnixTransport | { + open: (_: any) => Promise; + close: (_: any) => Promise; + send: (_: any) => Promise; + getRemoteHostname: (_: any) => never; + }; + /** + * Cleanup the connection closing all owned transactions and emitting the destroyed event + * and removing all registered listeners. + * + * @private + * @param {boolean} graceful - True if this is an expected disconnection + */ + private _signalClose; + /** + * Open a connection using the transport defined open method. + * Users do not need to call this method, since the connection is opened by Janode.connect(). + * + * @returns {Promise} A promise resolving with the Janode connection + */ + open(): Promise; + /** + * Manage a message sent to this session. If a session is involved let it manage the message. + * If the message involves a owned transaction and the response is a definitive one, + * the transaction will be closed. + * + * @private + * @param {object} janus_message + */ + private _handleMessage; + /** + * Decorate request with apisecret, token and transaction (if missing). + * + * @private + * @param {object} request + */ + private _decorateRequest; + /** + * Gracefully close the connection using the transport defined close method. + * + * @returns {Promise} + */ + close(): Promise; + /** + * Send a request from this connection using the transport defined send method. + * + * @param {object} request - The request to be sent + * @returns {Promise} A promise resolving with a response from Janus + */ + sendRequest(request: object): Promise; + /** + * Get the remote Janus hostname using the transport defined method. + * + * @returns {string} The hostname of the Janus server + */ + getRemoteHostname(): string; + /** + * Create a new session in this connection. + * + * @param {number} [ka_interval] - The time interval (seconds) for session keep-alive requests + * @returns {Promise} The newly created session + * + * @example + * + * const session = await connection.create(); + * Logger.info(`***** SESSION CREATED *****`); + */ + create(ka_interval?: number): Promise; + /** + * Janus GET INFO API. + * + * @returns {Promise} The Get Info response + * + * @example + * + * const info = await connection.getInfo(); + * Logger.info(`${info.name} ${info.version_string}`); + */ + getInfo(): Promise; + /*************/ + /*************/ + /** + * (Admin API) List the sessions in a janus instance. + * + * @returns {Promise} + * + * @example + * + * const data = await connection.listSessions(); + * Logger.info(`${JSON.stringify(data)}`); + */ + listSessions(): Promise; + /** + * (Admin API) List the handles in a session. + * + * @param {number} session_id - The identifier of the session + * @returns {Promise} + * + * @example + * + * const data = await connection.listSessions(); + * Logger.info(`${JSON.stringify(data)}`); + */ + listHandles(session_id: number): Promise; + /** + * (Admin API) Get an handle info. + * + * @param {number} session_id - The session identifier + * @param {number} handle_id - The handle identifier + * @returns {Promise} The Get Handle Info response + * + * @example + * + * const data = await connection.handleInfo(session.id, handle.id); + * Logger.info(`${JSON.stringify(data)}`); + */ + handleInfo(session_id: number, handle_id: number): Promise; + /** + * (Admin API) Start a packet capture on an handle. + * + * @param {number} session_id - The session identifier + * @param {number} handle_id - The handle identifier + * @param {string} folder - The folder in which save the pcap + * @param {string} filename - The pcap file name + * @param {number} [truncate] - Number of bytes to truncate the pcap to + * @returns {Promise} The start pcap response + */ + startPcap(session_id: number, handle_id: number, folder: string, filename: string, truncate?: number): Promise; + /** + * Stop an ogoing packet capture. + * + * @param {number} session_id - The session identifier + * @param {number} handle_id - The handle identifier + * @returns {Promise} The stop pcap response + */ + stopPcap(session_id: number, handle_id: number): Promise; +} +import WsTransport from "./transport-ws.js"; +import UnixTransport from "./transport-unix.js"; + diff --git a/types/handle.d.ts b/types/handle.d.ts new file mode 100644 index 0000000..5c4f2d6 --- /dev/null +++ b/types/handle.d.ts @@ -0,0 +1,199 @@ +import { EventEmitter } from 'events'; +import Session from './session.js' +export default Handle; +/** + * Class representing a Janode handle.
+ * + * Users implementing new plugins must extend this class and override the `handleMessage` function.
+ * + * Handle extends EventEmitter, so an instance can emit events and users can subscribe to them.
+ * + * Users are not expected to create Handle instances, but insted use the Session.attach() API. + * + * @hideconstructor + */ +declare class Handle extends EventEmitter { + /** + * Create a Janode handle. + * + * @param {module:session~Session} session - A reference to the parent session + * @param {number} id - The handle identifier + */ + constructor(session: Session, id: number); + /** + * The transaction manager used by this handle. + * + * @private + * @type {TransactionManager} + */ + private _tm; + /** + * A boolean flag indicating that the handle is being detached. + * Once the detach has been completed, the flag returns to false. + * + * @private + * @type {boolean} + */ + private _detaching; + /** + * A boolean flag indicating that the handle has been detached. + * + * @private + * @type {boolean} + */ + private _detached; + /** + * The parent Janode session. + * + * @type {Session} + */ + session: Session; + /** + * The handle unique id, usually taken from Janus response. + * + * @type {number} + */ + id: number; + /** + * A more descriptive, not unique string (used for logging). + * + * @type {string} + */ + name: string; + /** + * The callback function used for a session destroyed event. + * + * @private + */ + private _sessionDestroyedListener; + /** + * Cleanup the handle closing all owned transactions, emitting the detached event + * and removing all registered listeners. + * + * @private + */ + private _signalDetach; + /** + * Helper to check if a pending transaction is a trickle. + * + * @private + * @param {string} id - The transaction identifier + * @returns {boolean} + */ + private _isTrickleTx; + /** + * Helper to check if a pending transaction is a hangup. + * + * @private + * @param {string} id - The transaction identifier + * @returns {boolean} + */ + private _isHangupTx; + /** + * Helper to check if a pending transaction is a detach. + * + * @private + * @param {string} id - The transaction identifier + * @returns {boolean} + */ + private _isDetachTx; + /** + * Manage a message sent to this handle. If this involves a owned transaction + * and the response is a definitive one, the transaction will be closed. + * In case the instance implements a `handleMessage` method, this function will + * pass the message to it on order to let a plugin implements its custom logic. + * Generic Janus API events like `detached`, `hangup` etc. are handled here. + * + * @private + * @param {object} janus_message + */ + private _handleMessage; + /** + * Decorate request with handle id and transaction (if missing). + * + * @private + * @param {object} request + */ + private _decorateRequest; + /** + * Stub handleMessage (it is overriden by specific plugin handlers). + * Implementations must return falsy values for unhandled events and truthy value + * for handled events. + * + */ + handleMessage(): any; + /** + * Helper to check if the handle is managing a specific transaction. + * + * @property {string} id - The transaction id + * @returns {boolean} True if this handle is the owner + */ + ownsTransaction(id: string): boolean; + /** + * Helper to close a transaction with error. + * + * @property {string} id - The transaction id + * @property {string} error - The error message + * @returns {void} + */ + closeTransactionWithError(id: string, error: Error): void; + /** + * Helper to close a transaction with success. + * + * @property {string} id - The transaction id + * @property {object} [data] - The callback success data + * @returns {void} + */ + closeTransactionWithSuccess(id: string, data: any): void; + /** + * Send a request from this handle. + * + * @param {object} request + * @returns {Promise} A promsie resolving with the response to the request + */ + sendRequest(request: object): Promise; + /** + * Gracefully detach the Handle. + * + * @returns {Promise} + */ + detach(): Promise; + /** + * Close the peer connection associated to this handle. + * + * @returns {Promise} + */ + hangup(): Promise; + /** + * Send an ICE candidate / array of candidates. + * + * @param {RTCIceCandidate|RTCIceCandidate[]} candidate + * @returns {Promise} + */ + trickle(candidate: RTCIceCandidate | RTCIceCandidate[]): Promise; + /** + * Send ICE trickle complete message. + * + * @returns {Promise} + */ + trickleComplete(): Promise; + /** + * Send a `message` to Janus from this handle, with given body and optional jsep. + * + * @param {object} body - The body of the message + * @param {RTCSessionDescription} [jsep] + * @returns {Promise} A promise resolving with the response to the message + * + * @example + * // This is a plugin that sends a message with a custom body + * const body = { + * audio: true, + * video: true, + * record: false, + * }; + * + * await handle.message(body, jsep); + * + */ + message(body: object, jsep?: RTCSessionDescription): Promise; +} diff --git a/types/janode.d.ts b/types/janode.d.ts new file mode 100644 index 0000000..e19f4a8 --- /dev/null +++ b/types/janode.d.ts @@ -0,0 +1,170 @@ +import Handle from './handle.js' +import Logger from './utils/logger.js' + +import Connection from "./connection.js"; + +declare namespace _default { + export { connect }; + export { Logger }; + export { EVENT }; +} + +export default _default; +/** + * An object describing a janus server (e.g. url, secret). + */ +export type ServerObjectConf = { + /** + * - The URL to reach this server API + */ + url: string; + /** + * - The API secret for this server + */ + apisecret: string; +}; +/** + * The configuration passed by the user. + */ +export type RawConfiguration = { + /** + * - The key used to refer to this server in Janode.connect + */ + server_key: string; + /** + * - The server to connect to + */ + address: string; + /** + * - The seconds between any connection attempts + */ + retry_time_secs: number; + /** + * - The maximum number of retries before issuing a connection error + */ + max_retries: number; + /** + * - True if the connection is dedicated to the Janus Admin API + */ + is_admin: boolean; +}; +/** + * The plugin descriptor used when attaching a plugin from a session. + */ +export type PluginDescriptor = { + /** + * - The plugin id used when sending the attach request to Janus + */ + id: string; + /** + * - The class implementing the handle + */ + Handle?: Handle; + /** + * - The object with the list of events emitted by the plugin + */ + EVENT?: object; +}; +/** + * An object describing a janus server (e.g. url, secret). + * + * @typedef {object} ServerObjectConf + * @property {string} url - The URL to reach this server API + * @property {string} api_secret - The API secret for this server + */ +/** + * The configuration passed by the user. + * + * @typedef {object} RawConfiguration + * @property {string} server_key - The key used to refer to this server in Janode.connect + * @property {module:janode~ServerObjectConf[]|module:janode~ServerObjectConf} address - The server to connect to + * @property {number} retry_time_secs - The seconds between any connection attempts + * @property {number} max_retries - The maximum number of retries before issuing a connection error + * @property {boolean} is_admin - True if the connection is dedicated to the Janus Admin API + */ +/** + * The plugin descriptor used when attaching a plugin from a session. + * + * @typedef {object} PluginDescriptor + * @property {string} id - The plugin id used when sending the attach request to Janus + * @property {module:handle~Handle} [Handle] - The class implementing the handle + * @property {object} [EVENT] - The object with the list of events emitted by the plugin + */ +/** + * Connect using a defined configuration.
+ * + * The input configuration can be an object or an array. In case it is an array and the param "key" is provided, + * Janode will pick a server configuration according to "key" type. If it is a number it will pick the index "key" of the array. + * If it is a string it will pick the server configuration that matches the "server_key" property. + * In case "key" is missing, Janode will fallback to index 0. + * + * @param {module:janode~RawConfiguration|module:janode~RawConfiguration[]} config - The configuration to be used + * @param {number|string} [key=0] - The index of the config in the array to use, or the server of the arrray matching this server key + * @returns {Promise} The promise resolving with the Janode connection + * + * @example + * + * // simple example with single object and no key + * const connection = await Janode.connect({ + * address: { + * url: 'ws://127.0.0.1:8188/', + * apisecret: 'secret' + * }, + * }); + * + * // example with an array and a key 'server_2' + * // connection is established with ws://127.0.0.1:8002 + * const connection = await Janode.connect([{ + * server_key: 'server_1', + * address: { + * url: 'ws://127.0.0.1:8001/', + * apisecret: 'secret' + * }, + * }, + * { + * server_key: 'server_2', + * address: { + * url: 'ws://127.0.0.1:8002/', + * apisecret: 'secondsecret' + * }, + * }], 'server_2'); + * + * // example with an array and a key 'server_B' with multiple addresses + * // connection is attempted starting with ws://127.0.0.1:8003 + * const connection = await Janode.connect([{ + * server_key: 'server_A', + * address: { + * url: 'ws://127.0.0.1:8001/', + * apisecret: 'secret' + * }, + * }, + * { + * server_key: 'server_B', + * address: [{ + * url: 'ws://127.0.0.1:8003/', + * apisecret: 'secondsecret' + * }, + * { + * url: 'ws://127.0.0.2:9003/', + * apisecret: 'thirdsecret' + * }], + * }], 'server_B'); + */ + +export type ConnectConfig = { + address: ServerObjectConf[], + max_retries?:number + is_admin?:boolean + retry_time_secs?:number +} +declare function connect(config?: ConnectConfig, key?: number | string): Promise; +declare const EVENT: { + CONNECTION_CLOSED: string; + SESSION_DESTROYED: string; + HANDLE_DETACHED: string; + HANDLE_HANGUP: string; + HANDLE_MEDIA: string; + HANDLE_WEBRTCUP: string; + HANDLE_SLOWLINK: string; + CONNECTION_ERROR: string; +}; diff --git a/types/plugins/audiobridge-plugin.d.ts b/types/plugins/audiobridge-plugin.d.ts new file mode 100644 index 0000000..45e68f8 --- /dev/null +++ b/types/plugins/audiobridge-plugin.d.ts @@ -0,0 +1,685 @@ +import Handle from '../handle.js' +/** + * The payload of the plugin message (cfr. Janus docs). + * {@link https://janus.conf.meetecho.com/docs/audiobridge.html} + */ + +export type AudioBridgeMsg = 'join' + | 'listparticipants' + | 'kick' + | 'configure' + | 'leave' + | 'hangup' + | 'exists' + | 'list' + | 'create' + | 'destroy' + | 'allowed' + | 'rtp_forward' + | 'stop_rtp_forward' + | 'listforwarders' + | 'suspend' + | 'resume' + | 'enable_recording' + | 'mute' + | 'unmute' + + +export type AudioBridgeData = object; +export type RtpParticipant = { + /** + * - IP address you want media to be sent to + */ + ip: string; + /** + * - The port you want media to be sent to + */ + port: number; + /** + * - The payload type to use for RTP packets + */ + payload_type: number; +}; +/** + * The response event to a join request. + */ +export type AUDIOBRIDGE_EVENT_JOINED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed identifier + */ + feed: number | string; + /** + * - The display name, if available + */ + display?: string; + /** + * - True if the peer is a plain RTP participant + */ + rtp?: any; + /** + * - True if the peer is a plain RTP participant + */ + participants: Array<{ + feed: number | string + display: string + muted: boolean + setup: boolean + }>; + +}; +/** + * The response event for configure request. + */ +export type AUDIOBRIDGE_EVENT_CONFIGURED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed identifier + */ + feed: number | string; + /** + * - The display name, if available + */ + display?: string; + /** + * - The muted status + */ + muted?: boolean; + /** + * - [0-10] Opus-related complexity to use + */ + quality?: number; + /** + * - Volume percent value + */ + volume?: number; + /** + * - True if recording is active for this feed + */ + record?: boolean; + /** + * - The recording filename + */ + filename?: string; + /** + * - Number of packets to buffer before decoding + */ + prebuffer?: number; + /** + * - Group to assign to this participant + */ + group?: string; + /** + * - The JSEP answer + */ + jsep?: RTCSessionDescription; +}; +/** + * The response event for audiobridge hangup request. + */ +export type AUDIOBRIDGE_EVENT_AUDIO_HANGINGUP = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed that is being hung up + */ + feed: number | string; +}; +/** + * The response event for audiobridge leave request. + */ +export type AUDIOBRIDGE_EVENT_LEAVING = { + /** + * - The involved room + */ + room: number | string; + /** + * The feed that is leaving + */ + "feed-": number | string; +}; +/** + * The response event for audiobridge participants list request. + */ +export type AUDIOBRIDGE_EVENT_PARTICIPANTS_LIST = { + /** + * - The involved room + */ + room: number | string; + /** + * - The list of participants + */ + participants: { + feed: number | string; + display?: string; + muted?: boolean; + setup?: boolean; + talking?: boolean; + }; +}; +/** + * The response event for audiobridge participant kick request. + */ +export type AUDIOBRIDGE_EVENT_KICK_RESPONSE = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed that has been kicked out + */ + feed: number | string; +}; +/** + * The response event for audiobridge room exists request. + */ +export type AUDIOBRIDGE_EVENT_EXISTS = { + /** + * - The involved room + */ + room: number | string; + /** + * - True if the rooms exists + */ + exists: boolean; +}; +/** + * The response event for audiobridge room list request. + */ +export type AUDIOBRIDGE_EVENT_ROOMS_LIST = { + /** + * - The list of the rooms as returned by Janus + */ + list: object[]; +}; +/** + * The response event for audiobridge forwarder start request. + */ +export type AUDIOBRIDGE_EVENT_RTP_FWD = { + /** + * - The involved room + */ + room: number | string; + /** + * - Forwarder descriptor + */ + forwarder: { + host: string; + audio_port: number; + audio_stream: number; + group?: string; + }; +}; +/** + * The response event for audiobridge room create request. + */ +export type AUDIOBRIDGE_EVENT_CREATED = { + /** + * - The created room + */ + room: number | string; + /** + * - True if the room is being persisted in the Janus config file + */ + permanent: boolean; +}; +/** + * The response event for audiobridge room destroy request. + */ +export type AUDIOBRIDGE_EVENT_DESTROYED = { + /** + * - The destroyed room + */ + room: number | string; +}; +/** + * The response event for audiobridge forwarders list request. + */ +export type AUDIOBRIDGE_EVENT_FWD_LIST = { + /** + * - The involved room + */ + room: number | string; + /** + * - The list of forwarders + */ + forwarders: { + host: string; + audio_port: number; + audio_stream: number; + always: boolean; + group?: string; + }; +}; +/** + * The response event for audiobridge ACL token edit request. + */ +export type AUDIOBRIDGE_EVENT_ALLOWED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The updated, complete, list of allowed tokens + */ + list: string[]; +}; + +export type AUDIOBRIDGE_EVENT_ENABLE_RECORDING = { + room: number | string; + secret: string; + record: boolean; + filename?: string; + rec_dir?: string; +} +/** + * The response event for audiobridge suspend request. + */ +export type AUDIOBRIDGE_EVENT_SUSPEND_RESPONSE = { + /** + * @property {number|string} room - The involved room + */ + room: number | string; + /** + * @property {number|string} feed - The involved feed id + */ + feed: string; +} +/** + * The response event for audiobridge resume request. + * + */ +export type AUDIOBRIDGE_EVENT_RESUME_RESPONSE = { + /** + * @property {number|string} room - The involved room + */ + room: number | string; + /** + * @property {number|string} feed - The involved feed id + */ + feed: string; +} + +export class AudioBridgeHandle extends Handle { + /** + * The feed identifier assigned to this handle when it joined the audio bridge. + * + * @type {number|string} + */ + feed: number | string; + /** + * The identifier of the room the audiobridge handle has joined. + * + * @type {number|string} + */ + room: number | string; + /** + * The custom "handleMessage" needed for handling AudioBridge messages. + * + * @private + * @param {object} janus_message + * @returns {object} A falsy value for unhandled events, a truthy value for handled events + */ + // private handleMessage; + /** + * Join an audiobridge room. + * + * + * @param {object} params + * @param {number|string} params.room - The room to join + * @param {number|string} [params.feed] - The feed identifier for the participant, picked by Janus if omitted + * @param {string} [params.display] - The display name to use + * @param {boolean} [params.muted] - True to join in muted status + * @param {string} [params.pin] - The pin needed to join + * @param {string} [params.token] - The token to use when joining + * @param {number} [params.quality] - The opus quality for the encoder + * @param {number} [params.volume] - The percent volume + * @param {boolean} [params.record] - True to enable recording + * @param {string} [params.filename] - The recording filename + * @param {boolean} [params.suspended] - True to join in suspended status + * @param {boolean} [params.pause_events] - Wheter to pause notification events for suspended participants + * @param {module:audiobridge-plugin~RtpParticipant} [params.rtp_participant] - Set a descriptor object if you need a RTP participant + * @param {string} [params.group] - The group to assign to this participant + * @param {boolean} [params.generate_offer] - True to get Janus to send the SDP offer. + * @returns {Promise} + */ + join({ room, feed, display, muted, pin, token, quality, volume, record, filename, suspended, pause_events, rtp_participant, group, generate_offer }: { + room: number | string; + feed?: number; + display?: string; + muted?: boolean; + pin?: string; + token?: string; + quality?: number; + volume?: number; + record?: boolean; + filename?: string; + suspended?: boolean; + pause_events?: boolean; + rtp_participant?: any; + group?: string; + generate_offer?: boolean; + }): Promise + /** + * Configure an audiobridge handle. + * + * @param {object} params + * @param {string} [params.display] - The display name to use + * @param {boolean} [params.muted] - Set muted status + * @param {number} [params.quality] - Set opus quality + * @param {number} [params.bitrate] - Set received bitrate (overrides room default) + * @param {number} [params.volume] - Set volume percent + * @param {boolean} [params.record] - Enable recording + * @param {string} [params.filename] - Set recording filename + * @param {number} [params.expected_loss] - Set a new expected_loss value for this participant (overrides room default) + * @param {number} [params.prebuffer] - Set a new prebuffer value (overrides room default) + * @param {string} [params.group] - Set the group that the participant belongs to + * @param {RTCSessionDescription} [params.jsep=null] - JSEP offer + * @returns {Promise} + */ + configure({ display, muted, quality, bitrate, volume, record, filename, expected_loss, prebuffer, group, jsep }: { + display?: string; + muted?: boolean; + quality?: number; + bitrate?: number; + volume?: number; + record?: boolean; + filename?: string; + expected_loss?: number; + prebuffer?: number; + group?: string; + jsep?: RTCSessionDescription; + }): Promise + /** + * Request an audiobridge handle hangup. + * + * @returns {Promise} + * + */ + audioHangup(): Promise + /** + * Leave an audiobridge room. + * + * @returns {Promise} + */ + leave(): Promise + /** + * List participants inside a room. + * + * @param {object} params + * @param {number|string} params.room - The room where to execute the list + * @param {string} [params.secret] - The optional secret needed for managing the room + * @returns {Promise} + */ + listParticipants({ room, secret }: { + room: number | string + secret?: string + }): Promise + /** + * Kick an user out from a room. + * + * @param {object} params + * @param {number|string} params.room - The involved room + * @param {number|string} params.feed - The feed to kick out + * @param {string} [params.secret] - The optional secret needed for managing the room + * @returns {Promise} + */ + kick({ room, feed, secret }: { + room: number | string + feed: number | string + secret?: string + }): Promise + /** + * Check if a room exists. + * + * @param {object} params + * @param {number|string} params.room - The involved room + * @returns {Promise} + */ + exists({ room }: { + room: number | string; + }): Promise + /** + * List available audiobridge rooms. + * + * @returns {Promise} + */ + list(): Promise + /** + * Create an audiobridge room. + * + * @param {object} params + * @param {number|string} params.room - The room identifier + * @param {string} [params.description] - A room description + * @param {boolean} [params.permanent] - Set to true to persist the room in the Janus config file + * @param {number} [params.sampling_rate] - The sampling rate (bps) to be used in the room + * @param {number} [params.bitrate] - The bitrate (bps) to be used in the room, if missing the encoder decides + * @param {boolean} [params.is_private] - Set room as private (hidden in list) + * @param {string} [params.secret] - The secret to be used when managing the room + * @param {string} [params.pin] - The ping needed for joining the room + * @param {boolean} [params.record] - True to record the mixed audio + * @param {string} [params.filename] - The recording filename + * @param {string} [params.rec_dir] - The optional recording folder + * @param {boolean} [params.talking_events] - True to enable talking events + * @param {number} [params.talking_level_threshold] - Audio level threshold for talking events in the range [0, 127] + * @param {number} [params.talking_packets_threshold] - Audio packets threshold for talking events + * @param {number} [params.expected_loss] - The expected loss percentage in the audiobridge, if > 0 enables FEC + * @param {number} [params.prebuffer] - The prebuffer to use for every participant + * @param {boolean} [params.allow_rtp] - Allow plain RTP participants + * @param {string[]} [params.groups] - The available groups in the room + * @returns {Promise} + */ + create({ room, description, permanent, sampling_rate, bitrate, is_private, secret, pin, record, filename, rec_dir, talking_events, talking_level_threshold, talking_packets_threshold, expected_loss, prebuffer, allow_rtp, groups }: { + room: number | string; + description?: string; + permanent?: boolean; + sampling_rate?: number; + bitrate?: number; + is_private?: boolean; + secret?: string; + pin?: string; + record?: boolean; + filename?: string; + rec_dir?: string; + talking_events?: boolean; + talking_level_threshold?: number; + talking_packets_threshold?: number; + expected_loss?: number; + prebuffer?: number; + allow_rtp?: boolean; + groups?: string[]; + }): Promise + /** + * Destroy an audiobridge room. + * + * @param {object} params + * @param {number|string} params.room - The room to destroy + * @param {boolean} [params.permanent] - Set to true to remove the room from the Janus config file + * @param {string} [params.secret] - The optional secret needed to manage the room + * @returns {Promise} + */ + destroy({ room, permanent, secret }: { + room: number | string + permanent?: boolean + secret?: string + }): Promise + /** + * Edit an audiobridge token list. + * + * @param {object} params + * @param {number|string} params.room - The involved room + * @param {"enable"|"disable"|"add"|"remove"} params.action - The action to perform + * @param {string[]} params.list - The list of tokens to add/remove + * @param {string} [params.secret] - The optional secret needed to manage the room + * @returns {Promise} + */ + allow({ room, action, list, secret }: { + room: number | string; + action: "enable" | "disable" | "add" | "remove"; + list: string[]; + secret?: string; + }): Promise + /** + * Start a RTP forwarder. + * + * @param {object} params + * @param {number|string} params.room - The involved room + * @param {boolean} [params.always] - Whether silence should be forwarded when the room is empty + * @param {string} params.host - The host to forward to + * @param {number} params.audio_port - The port to forward to + * @param {number} [params.ssrc] - The SSRC to use to use when forwarding + * @param {number} [params.ptype] - The payload type to use to use when forwarding + * @param {string} [params.codec] - The codec to use in the forwarder + * @param {string} [params.group] - The group to forward + * @param {string} [params.secret] - The optional secret needed to manage the room + * @returns {Promise} + */ + startForward({ room, always, host, host_family, audio_port, group, ssrc, ptype, codec, secret }: { + room: number | string; + always?: boolean; + host: string; + host_family: string; + audio_port: number; + ssrc?: number; + ptype?: number; + codec?: string; + group?: string; + secret?: string; + }): Promise + /** + * Stop a RTP forwarder. + * + * @param {object} params + * @param {number|string} params.room - The involved room + * @param {number} params.stream - The forwarder identifier to stop + * @param {string} [params.secret] - The optional secret needed to manage the room + * @returns {Promise} + */ + stopForward({ room, stream, secret }: { + room: number | string; + stream: number; + secret?: string; + }): Promise + /** + * List active forwarders. + * + * @param {object} params + * @param {number|string} params.room - The involved room + * @param {string} [params.secret] - The optional secret needed to manage the room + * @returns {Promise} + */ + listForward({ room, secret }: { + room: number | string; + secret?: string; + }): Promise + + /** + * Enable/disable mixed audio recording. + * + * @param {object} params + * @param {number|string} params.room - The room identifier + * @param {boolean} params.record - Enable/disable recording + * @param {string} [params.secret] - The secret to be used when managing the room + * @param {string} [params.filename] - The recording filename + * @param {string} [params.rec_dir] - The optional recording folder + * @returns {Promise} + */ + enableRecording({ room, secret, record, filename, rec_dir }: { + room: number | string; + secret: string; + record: boolean; + filename?: string; + rec_dir?: string; + }): Promise<{ success: boolean }> + /** + * Suspend an audiobridge participant. + * + * @param {object} params + * @param {number|string} params.room - The involved room + * @param {number|string} params.feed - The feed id to be suspended + * @param {boolean} [params.stop_record] - Whether the recording of this participant should be stopped too + * @param {boolean} [params.pause_events] - Wheter to pause notification events for suspended participants + * @param {string} [params.secret] - The optional secret needed to manage the room + * @returns {Promise} + */ + suspend({ room, feed, stop_record, pause_events, secret }: { + room: number | string; + feed: string; + stop_record?: boolean; + pause_events?: boolean; + secret?: string; + }): Promise + /** + * Resume an audiobridge participant after a suspend. + * + * @param {object} params + * @param {number|string} params.room - The involved room + * @param {number|string} params.feed - The feed id to be resumed + * @param {boolean} [params.record] - Whether to start recording this resumed feed + * @param {string} [params.filename] - The recording filename + * @param {string} [params.secret] - The optional secret needed to manage the room + * @returns {Promise} + */ + resume({ room, feed, record, filename, secret }: { + room: number | string; + feed: string; + record?: boolean; + filename?: string; + secret?: string; + }): Promise + /** + * Mute an user in the audiobridge. + * + * @param {object} params + * @param {number|string} params.room - The involved room + * @param {number|string} params.feed - The feed to mute + * @param {string} [params.secret] - The optional secret needed for managing the room + * @returns {Promise} + */ + mute({ room, feed, secret }: { + room: number | string; + feed: string; + secret?: string; + }): Promise + /** + * Unmute an user in the audiobridge. + * + * @param {object} params + * @param {number|string} params.room - The involved room + * @param {number|string} params.feed - The feed to unmute + * @param {string} [params.secret] - The optional secret needed for managing the room + * @returns {Promise} + */ + unmute({ room, feed, secret }: { + room: number | string; + feed: string; + secret?: string; + }): Promise + +} + +export type AudioBridgeEvent = { + AUDIOBRIDGE_DESTROYED: string + AUDIOBRIDGE_KICKED: string + AUDIOBRIDGE_PEER_JOINED: string + AUDIOBRIDGE_PEER_CONFIGURED: string + AUDIOBRIDGE_PEER_KICKED: string + AUDIOBRIDGE_PEER_LEAVING: string + AUDIOBRIDGE_TALKING: string + AUDIOBRIDGE_PEER_TALKING: string + AUDIOBRIDGE_ERROR: string +} +declare var _default: { + id: string + Handle: AudioBridgeHandle + EVENT: AudioBridgeEvent +} +export default _default diff --git a/types/plugins/echotest-plugin.d.ts b/types/plugins/echotest-plugin.d.ts new file mode 100644 index 0000000..c58b1c8 --- /dev/null +++ b/types/plugins/echotest-plugin.d.ts @@ -0,0 +1,59 @@ +import {PluginDescriptor} from "../janode.js" +import Handle from "../handle.js" + +/** + * The payload of the plugin message (cfr. Janus docs). + * {@link https://janus.conf.meetecho.com/docs/echotest.html} + */ +export type EchoTestData = object +export type ECHOTEST_EVENT_RESULT = { + /** + * - The result status (ok, done ...) + */ + result: string + /** + * - The answer from Janus + */ + jsep?: RTCSessionDescription +} +/** + * The class implementing the EchoTest plugin (ref. {@link https://janus.conf.meetecho.com/docs/echotest.html}).
+ * + * It extends the base Janode Handle class and overrides the base "handleMessage" method.
+ * + * Moreover it defines some methods to support EchoTest operations.
+ * + * @hideconstructor + */ +export class EchoTestHandle extends Handle { + /** + * The custom "handleMessage" needed for handling EchoTest messages. + * + * @private + * @param {object} janus_message + * @returns {object} A falsy value for unhandled events, a truthy value for handled events + */ + //private handleMessage + /** + * Start/update an echotest session. + * + * @param {object} params + * @param {boolean} [audio] - True to request audio in this session + * @param {boolean} [video] - True to request video in this session + * @param {RTCSessionDescription} [jsep=null] - The JSEP offer + * @param {number} [bitrate=0] - The bitrate to force in the session + * @param {boolean} [record=false] - True to record the session + * @param {string} [filename=null] - The filename of the recording + * @returns {Promise} + */ + start({ audio, video, jsep, bitrate, record, filename }: { + audio: boolean + video: boolean + jsep: RTCSessionDescription + bitrate: number + record: boolean + filename:string + }): Promise +} +declare var _default: PluginDescriptor +export default _default diff --git a/types/plugins/streaming-plugin.d.ts b/types/plugins/streaming-plugin.d.ts new file mode 100644 index 0000000..a66e01e --- /dev/null +++ b/types/plugins/streaming-plugin.d.ts @@ -0,0 +1,372 @@ +/** + * The class implementing the Streaming plugin (ref. {@link https://janus.conf.meetecho.com/docs/streaming.html}).
+ * + * It extends the base Janode Handle class and overrides the "handleMessage" method.
+ * + * Moreover it defines many methods to support Streaming operations.
+ * + * @hideconstructor + */ +export class StreamingHandle extends Handle { + /** + * The mountpoint this handle has subscribed to. + * + * @type {number|string} + */ + mp: number | string; + /** + * The custom "handleMessage" needed for handling Streamiing messages. + * + * @private + * @param {object} janus_message + * @returns {object} A falsy value for unhandled events, a truthy value for handled events + */ + // private handleMessage; + /** + * Subscribe to a mountpoint. + * + * @param {object} params + * @param {number|string} params.id - The mp id + * @param {string} [params.pin] - The optional mp pin + * @param {boolean} [params.audio] - True to request audio + * @param {boolean} [params.video] - True to request video + * @param {boolean} [params.data] - True to request data + * @param {boolean} [params.restart=false] - True to trigger a restart + * @returns {Promise} + */ + watch({ id, pin, audio, video, data, restart }: { + id: number | string; + pin?: string; + audio?: boolean; + video?: boolean; + data?: boolean; + restart?: boolean; + }): Promise; + /** + * Start a mountpoint stream. + * + * @param {object} params + * @property {RTCSessionDescription} params.jsep + * @returns {Promise} + */ + start({ jsep }: { + jsep: RTCSessionDescription + }): Promise; + /** + * Pause the current stream. + * + * @returns {Promise} + */ + pause(): Promise; + /** + * Stop the current stream. + * + * @returns {Promise} + */ + stop(): Promise; + /** + * Switch to another mountpoint. + * + * @param {object} params + * @param {number|string} params.id - The mp id to switch to + * @returns {Promise} + */ + switch({ id }: { + id: number | string; + }): Promise; + /** + * Configure an active stream. + * + * @param {object} params + * @param {boolean} [params.audio] - Enable/disable audio + * @param {boolean} [params.video] - Enable/disable video + * @param {boolean} [params.data] - Enable/disable data + * @param {number} [params.substream] - Substream to switch to (simuclast) + * @param {number} [params.temporal] - Temporal layer to switch to (simulcast) + * @param {number} [params.fallback] - Fallback timer (simulcast) + * @param {number} [params.spatial_layer] - Spatial layer to switch to (svc) + * @param {number} [params.temporal_layer] - Temporal layer to switch to (svc) + * @returns {Promise} + */ + configure({ audio, video, data, substream, temporal, fallback, spatial_layer, temporal_layer }: { + audio?: boolean; + video?: boolean; + data?: boolean; + substream?: number; + temporal?: number; + fallback?: number; + spatial_layer?: number; + temporal_layer?: number; + }): Promise; + /** + * List all the available mountpoints. + * + * @returns {Promise} + */ + list(): Promise; + /** + * Get mountpoint info. + * + * @param {object} params + * @param {number|string} params.id + * @param {string} [params.secret] + * @returns {Promise} + */ + info({ id, secret }: { + id: number | string; + secret?: string; + }): Promise; + /** + * Start recording on a mountpoint + * + * @param {object} params + * @param {number|string} params.id + * @param {string} [params.audio] - The filename for audio + * @param {string} [params.video] - The filename for video + * @param {string} [params.data] - The filename for data + * @param {string} [params.secret] + * @returns {Promise} + */ + startRecording({ id, audio, video, data, secret }: { + id: number | string; + audio?: string; + video?: string; + data?: string; + secret?: string; + }): Promise; + /** + * Stop recording on a mountpoint. + * + * @param {object} params + * @param {number|string} params.id + * @param {boolean} [params.audio=true] - True to stop recording of audio + * @param {boolean} [params.video=true] - True to stop recording of video + * @param {boolean} [params.data=true] - True to stop recording of data + * @param {string} [params.secret] + * @returns {Promise} + */ + stopRecording({ id, audio, video, data, secret }: { + id: number | string; + audio?: boolean; + video?: boolean; + data?: boolean; + secret?: string; + }): Promise; + /** + * Enable a mountpoint. + * + * @param {object} params + * @param {number|string} params.id + * @param {string} [params.secret] + * @returns {Promise} + */ + enable({ id, secret }: { + id: number | string; + secret?: string; + }): Promise; + /** + * Disable a mountpoint. + * + * @param {object} params + * @param {number|string} params.id + * @param {boolean} [stop_recording=true] - True if the user wants to also stop the recording of a disabled moutnpoint + * @param {string} [params.secret] + * @returns {Promise} + */ + disable({ id, stop_recording, secret }: { + id: number | string; + stop_recording?:boolean + secret ?: string + }): Promise; + /** + * Create a RTP live mountpoint. + * + * @param {object} params + * @param {number|string} [params.id=0] - The id for the new mountpoint (if omitted Janus will pick one) + * @param {string} [params.description] - A description for the mp + * @param {string} [params.secret] - The secret that'll be needed to edit this mountpoint + * @param {string} [params.pin] - The pin that'll be needed to connect to the new mountpoint + * @param {boolean} [params.permanent=false] - True if Janus must persist the mp on a config file + * @param {boolean} [params.is_private=false] - Flag the mp as private + * @param {object} [params.audio] - The audio descriptor for the mp + * @param {number} [params.audio.port] - Port used for audio RTP + * @param {number} [params.audio.rtcpport] - Port used for audio RTCP + * @param {string} [params.audio.mcast] - Multicast address to listen to + * @param {number} [params.audio.pt] - Payload type that will be used + * @param {string} [params.audio.rtpmap] - rtpmap type that will be used + * @param {boolean} [params.audio.skew] - Set skew compensation + * @param {object} [params.video] - The video descriptor for the mp + * @param {number} [params.video.port] - Port used for video RTP + * @param {number} [params.video.rtcpport] - Port used for video RTCP + * @param {string} [params.video.mcast] - Multicast address to listen to + * @param {number} [params.video.pt] - Payload type that will be used + * @param {string} [params.video.rtpmap] - rtpmap that will be used + * @param {boolean} [params.video.skew] - Set skew compensation + * @param {string} [params.video.fmtp] - fmtp that will be used + * @param {boolean} [params.video.buffer] - Enable buffering of the keyframes + * @param {object} [params.data] - The datachannel descriptor for the mp + * @param {number} [params.data.port] - Port used for datachannels packets + * @param {boolean} [params.data.buffer] - Enable buffering of the datachannels + * @param {number} [params.threads] - The number of helper threads used in this mp + * @param {object} [params.metadata] - An opaque metadata to add to the mp + * @returns {Promise} + */ + createRtpMountpoint({ id, name, description, secret, pin, permanent, is_private, audio, video, data, threads, metadata }: { + id?: number | string; + name?: string + description?: string; + secret?: string; + pin?: string; + permanent?: boolean; + is_private?: boolean; + audio?: { + port?: number; + rtcpport?: number; + mcast?: string; + pt?: number; + rtpmap?: string; + skew?: boolean; + }; + video?: { + port?: number; + rtcpport?: number; + mcast?: string; + pt?: number; + rtpmap?: string; + skew?: boolean; + fmtp?: string; + buffer?: boolean; + }; + data?: { + port?: number; + buffer?: boolean; + }; + threads?: number; + metadata?: object; + }): Promise; + /** + * Destroy a mountpoint. + * + * @param {object} params + * @param {number|string} params.id + * @param {string} [params.secret] + * @returns {Promise} + */ + destroyMountpoint({ id, secret }: { + id: number | string; + secret?: string; + }): Promise; +} +declare var _default: { + id: string, + Handle: StreamingHandle + EVENT: object +}; +export default _default; +/** + * The payload of the plugin message (cfr. Janus docs). + * {@link https://janus.conf.meetecho.com/docs/streaming.html} + */ +export type StreamingData = object; +/** + * Success response for streaming requests. + */ +export type STREAMING_EVENT_OK = object; +/** + * Response event for mountpoint info request. + */ +export type STREAMING_EVENT_INFO = object; +/** + * Response event for mountpoint list request. + */ +export type STREAMING_EVENT_LIST = { + /** + * - The list of mountpoints as returned by Janus + */ + list: object[]; +}; +/** + * Response event for mountpoint create request. + */ +export type STREAMING_EVENT_CREATED = { + /** + * - The name of the mountpoint + */ + name: string; + /** + * - The identifier for the mountpoint + */ + id: number | string; + /** + * - An optional description + */ + description: string; + /** + * - The port for RTP audio + */ + audio_port?: number; + /** + * - The port RTCP audio + */ + audio_rtcp_port?: number; + /** + * - The port for RTP video + */ + video_port?: number; + /** + * - The port for RTCP video + */ + video_rtcp_port?: number; + /** + * - The port for datachannels + */ + data_port?: number; +}; +/** + * Response event for mountpoint destroy request. + */ +export type STREAMING_EVENT_DESTROYED = { + /** + * - The identifier of the dstroyed mountpoint + */ + id: number | string; +}; +/** + * A streaming status update event. + */ +export type STREAMING_EVENT_STATUS = { + /** + * - The current status of the stream + */ + status: string; + /** + * - The involved mountpoint identifier + */ + id?: number | string; + /** + * - True if the request had it true + */ + restart?: boolean; + /** + * - Optional JSEP offer from Janus + */ + jsep?: RTCSessionDescription; +}; +/** + * Response event for mountpoint switch request. + */ +export type STREAMING_EVENT_SWITCHED = { + /** + * - The string as returned by Janus + */ + switched: string; + /** + * - The identifier of the mp that has been switched to + */ + id: number | string; +}; +/** + * Response event for configure stream request + */ +export type STREAMING_EVENT_CONFIGURED = object; +import Handle from "../handle.js"; diff --git a/types/plugins/videoroom-plugin.d.ts b/types/plugins/videoroom-plugin.d.ts new file mode 100644 index 0000000..322a3b8 --- /dev/null +++ b/types/plugins/videoroom-plugin.d.ts @@ -0,0 +1,734 @@ +import Handle from "../handle.js"; +/** + * The class implementing the VideoRoom plugin (ref. {@link https://janus.conf.meetecho.com/docs/videoroom.html}).
+ * + * It extends the base Janode Handle class and overrides the "handleMessage" method.
+ * + * Moreover it defines many methods to support VideoRoom operations.
+ * + * @hideconstructor + */ +export class VideoRoomHandle extends Handle { + /** + * Either the feed identifier assigned to this publisher handle or the publisher's feed in case this handle is a subscriber. + * + * @type {number|string} + */ + feed: number | string; + /** + * The identifier of the videoroom the handle has joined. + * + * @type {number|string} + */ + room: number | string; + /** + * The custom "handleMessage" needed for handling VideoRoom messages. + * + * @private + * @param {object} janus_message + * @returns {object} A falsy value for unhandled events, a truthy value for handled events + */ + // private handleMessage; + /** + * Join a videoroom as publisher. + * + * @param {object} params + * @param {number|string} params.room - The room to join to + * @param {number|string} [params.feed=0] - The feed identifier to use, if missing it is picked by Janus + * @param {boolean} [params.audio] - True to request audio relaying + * @param {boolean} [params.video] - True to request video relaying + * @param {boolean} [params.data] - True to request datachannel relaying + * @param {string} [params.display] - The display name to use + * @param {number} [params.bitrate] - Bitrate cap + * @param {string} [params.token] - The optional token needed to join the room + * @param {string} [params.pin] - The optional pin needed to join the room + * @param {boolean} [params.record] - Enable the recording + * @param {string} [params.filename] - If recording, the base path/file to use for the recording + * @returns {Promise} + */ + joinPublisher({ room, feed, audio, video, data, bitrate, record, filename, display, token, pin }: { + room: number | string; + feed?: number | string; + audio?: boolean; + video?: boolean; + data?: boolean; + display?: string; + bitrate?: number; + token?: string; + pin?: string; + record?: boolean; + filename?: string; + }): Promise; + /** + * Join and configure videoroom handle as publisher. + * + * @param {object} params + * @param {number|string} params.room - The room to join to + * @param {number|string} [params.feed=0] - The feed identifier to use, if missing it is picked by Janus + * @param {boolean} [params.audio] - True to request audio relaying + * @param {boolean} [params.video] - True to request video relaying + * @param {boolean} [params.data] - True to request datachannel relaying + * @param {string} [params.display] - The display name to use + * @param {number} [params.bitrate] - Bitrate cap + * @param {string} [params.token] - The optional token needed to join the room + * @param {string} [params.pin] - The optional pin needed to join the room + * @param {boolean} [params.record] - Enable the recording + * @param {string} [params.filename] - If recording, the base path/file to use for the recording + * @param {RTCSessionDescription} [params.jsep] - The JSEP offer + * @returns {Promise} + */ + joinConfigurePublisher({ room, feed, audio, video, data, bitrate, record, filename, display, token, pin, jsep }: { + room: number | string; + feed?: number | string; + audio?: boolean; + video?: boolean; + data?: boolean; + display?: string; + bitrate?: number; + token?: string; + pin?: string; + record?: boolean; + filename?: string; + jsep?: RTCSessionDescription; + }): Promise; + /** + * Configure a publisher or subscriber handle.
+ * Room is detected from the context since a handle must have joined before.
+ * Can also be used by publishers to publish a feed.
+ * + * Use this API also to trigger ICE restarts. Publishers can omit the + * restart/update flags, while subscribers need to use them to force + * the operation. + * + * @param {object} params + * @param {boolean} [params.audio] - True to request audio relaying + * @param {boolean} [params.video] - True to request video relaying + * @param {boolean} [params.data] - True to request datachannel relaying + * @param {string} [params.display] - The display name to use (publishers only) + * @param {number} [params.bitrate] - Bitrate cap (publishers only) + * @param {boolean} [params.record] - True to record the feed (publishers only) + * @param {string} [params.filename] - If recording, the base path/file to use for the recording (publishers only) + * @param {boolean} [params.restart] - Set to force a ICE restart + * @param {boolean} [params.update] - Set to force a renegotiation + * @param {RTCSessionDescription} [params.jsep] - The JSEP offer (publishers only) + * @returns {Promise} + */ + configure({ audio, video, data, bitrate, record, filename, display, restart, update, jsep }: { + audio?: boolean; + video?: boolean; + data?: boolean; + display?: string; + bitrate?: number; + record?: boolean; + filename?: string; + restart?: boolean; + update?: boolean; + jsep?: RTCSessionDescription; + }): Promise; + /** + * Publish a feed in the room. + * Room is detected from the context since a handle must have joined before. + * + * @param {object} params + * @param {boolean} [params.audio] - True to request audio relaying + * @param {boolean} [params.video] - True to request video relaying + * @param {boolean} [params.data] - True to request datachannel relaying + * @param {string} [params.display] - The display name to use + * @param {number} [params.bitrate] - Bitrate cap + * @param {boolean} [params.record] - True to record the feed + * @param {string} [params.filename] - If recording, the base path/file to use for the recording + * @param {RTCSessionDescription} params.jsep - The JSEP offer + * @returns {Promise} + */ + publish({ audio, video, data, bitrate, record, filename, display, jsep }: { + audio?: boolean; + video?: boolean; + data?: boolean; + display?: string; + bitrate?: number; + record?: boolean; + filename?: string; + jsep: RTCSessionDescription; + }): Promise; + /** + * Unpublish a feed in the room. + * + * @returns {Promise} + */ + unpublish(): Promise; + /** + * Join a room as subscriber. + * + * @param {object} params + * @param {number|string} params.room - The room to join + * @param {number|string} [params.feed=0] - The feed the user wants to subscribe to + * @param {boolean} [params.audio] - True to subscribe to the audio feed + * @param {boolean} [params.video] - True to subscribe to the video feed + * @param {boolean} [params.data] - True to subscribe to the datachannels of the feed + * @param {string} [params.token] - The optional token needed + * @returns {Promise} + */ + joinSubscriber({ room, feed, audio, video, data, token }: { + room: number | string; + feed?: number | string; + audio?: boolean; + video?: boolean; + data?: boolean; + token?: string; + }): Promise; + /** + * Alias for "joinSubscriber". + * + * @see module:videoroom-plugin~VideoRoomHandle#joinSubscriber + */ + joinListener(params: any): Promise; + /** + * Start a subscriber stream. + * + * @param {object} params + * @param {RTCSessionDescription} params.jsep - The JSEP answer + * @returns {Promise} + */ + start({ jsep }: { + jsep: RTCSessionDescription; + }): Promise; + /** + * Pause a subscriber feed. + * + * @returns {Promise} + */ + pause(): Promise; + /** + * Leave a room. + * Can be used by both publishers and subscribers. + * + * @returns {Promise} + */ + leave(): Promise; + /** + * List the participants inside a room. + * + * @param {object} params + * @param {number|string} params.room - The room where the list is being requested + * @param {string} params.secret - The optional secret for the operation + * @returns {Promise} + */ + listParticipants({ room, secret }: { + room: number | string; + secret: string; + }): Promise; + /** + * Kick a publisher out from a room. + * + * @param {object} params + * @param {number|string} params.room - The room where the kick is being requested + * @param {number|string} params.feed - The identifier of the feed to kick out + * @param {string} params.secret - The optional secret for the operation + * @returns {Promise} + */ + kick({ room, feed, secret }: { + room: number | string; + feed: number | string; + secret: string; + }): Promise; + /** + * Check if a room exists. + * + * @param {object} params + * @param {number|string} params.room - The room to check + * @returns {Promise} + */ + exists({ room }: { + room: number | string; + }): Promise; + /** + * List all the available rooms. + * + * @returns {Promise} + */ + list(): Promise; + /** + * Create a new room. + * + * @param {object} params + * @param {number|string} [params.room] - The room identifier, if missing picked by janus + * @param {string} [params.description] - A textual description of the room + * @param {number} [params.max_publishers] - The max number of publishers allowed + * @param {boolean} [params.permanent] - True to make Janus persist the room on th config file + * @param {boolean} [params.is_private] - Make the room private (hidden from listing) + * @param {string} [params.secret] - The secret that will be used to modify the room + * @param {string} [params.pin] - The pin needed to access the room + * @param {number} [params.bitrate] - The bitrate cap that will be used for publishers + * @param {boolean} [params.bitrate_cap] - Make the bitrate cap an insormountable limit + * @param {number} [params.fir_freq] - The PLI interval in seconds + * @param {string} [params.audiocodec] - Comma separated list of allowed audio codecs + * @param {string} [params.videocodec] - Comma separated list of allowed video codecs + * @param {boolean} [params.talking_events] - True to enable talking events + * @param {number} [params.talking_level_threshold] - Audio level threshold for talking events in the range [0, 127] + * @param {number} [params.talking_packets_threshold] - Audio packets threshold for talking events + * @param {boolean} [params.record] - Wheter to enable recording of any publisher + * @param {string} [params.rec_dir] - Folder where recordings should be stored + * @param {boolean} [params.videoorient] - Whether the video-orientation RTP extension must be negotiated + * @param {string} [params.h264_profile] - H264 specific profile to prefer + * @returns {Promise} + */ + create({ room, description, max_publishers, permanent, is_private, secret, pin, bitrate, bitrate_cap, fir_freq, audiocodec, videocodec, talking_events, talking_level_threshold, talking_packets_threshold, record, rec_dir, videoorient, h264_profile }: { + room?: number | string; + description?: string; + max_publishers?: number; + permanent?: boolean; + is_private?: boolean; + secret?: string; + pin?: string; + bitrate?: number; + bitrate_cap?: boolean; + fir_freq?: number; + audiocodec?: string; + videocodec?: string; + talking_events?: boolean; + talking_level_threshold?: number; + talking_packets_threshold?: number; + record?: boolean; + rec_dir?: string; + videoorient?: boolean; + h264_profile?: string; + }): Promise; + /** + * Destroy a room. + * + * @param {object} params + * @param {number|string} params.room - The room to destroy + * @param {boolean} [params.permanent] - True to remove the room from the Janus config file + * @param {string} [params.secret] - The secret needed to manage the room + * @returns {Promise} + */ + destroy({ room, permanent, secret }: { + room: number | string; + permanent?: boolean; + secret?: string; + }): Promise; + /** + * Edit the ACL tokens for a room. + * + * @param {object} params + * @param {number|string} params.room - The room where to change the acl + * @param {"enable"|"disable"|"add"|"remove"} params.action - The action to execute on the acl + * @param {string[]} params.list - The list of tokens to execute the action onto + * @param {string} [params.secret] - The secret needed to manage the room + * @returns {Promise} + */ + allow({ room, action, list, secret }: { + room: number | string; + action: "enable" | "disable" | "add" | "remove"; + list: string[]; + secret?: string; + }): Promise; + /** + * Start a RTP forwarding in a room. + * + * @param {object} params + * @param {number|string} params.room - The room where to start a forwarder + * @param {number|string} params.feed - The feed identifier to forward (must be published) + * @param {string} params.host - The target host for the forwarder + * @param {number} [params.audio_port] - The target audio RTP port, if audio is to be forwarded + * @param {number} [params.audio_rtcp_port] - The target audio RTCP port, if audio is to be forwarded + * @param {number} [params.audio_ssrc] - The SSRC that will be used for audio RTP + * @param {number} [params.video_port] - The target video RTP port, if video is to be forwarded + * @param {number} [params.video_rtcp_port] - The target video RTCP port, if video is to be forwarded + * @param {number} [params.video_ssrc] - The SSRC that will be used for video RTP + * @param {number} [params.data_port] - The target datachannels port, if datachannels are to be forwarded + * @param {string} [params.secret] - The secret needed for managing the room + * @param {string} [params.admin_key] - The admin key needed for invoking the API + * @returns {Promise} + */ + startForward({ room, feed, host, audio_port, audio_rtcp_port, audio_ssrc, video_port, video_rtcp_port, video_ssrc, data_port, secret, admin_key }: { + room: number | string; + feed: number | string; + host: string; + audio_port?: number; + audio_rtcp_port?: number; + audio_ssrc?: number; + video_port?: number; + video_rtcp_port?: number; + video_ssrc?: number; + data_port?: number; + secret?: string; + admin_key?: string; + }): Promise; + /** + * Stop a RTP forwarder in a room. + * + * @param {object} params + * @param {number|string} params.room - The room where to stop a forwarder + * @param {number|string} params.feed - The feed identifier for the forwarder to stop (must be published) + * @param {number|string} params.stream - The forwarder identifier as returned by the start forward API + * @param {string} [params.secret] - The secret needed for managing the room + * @returns {Promise} + */ + stopForward({ room, feed, stream, secret }: { + room: number | string; + feed: number | string; + stream: number | string; + secret?: string; + }): Promise; + /** + * List the active forwarders in a room. + * + * @param {object} params + * @param {number|string} params.room - The room where to list the forwarders + * @param {string} [params.secret] - The secret needed for managing the room + * @returns {Promise} + */ + listForward({ room, secret }: { + room: number | string; + secret?: string; + }): Promise; +} +declare var _default: { + id: string + Handle: VideoRoomHandle + EVENT: object +}; +export default _default; +/** + * The payload of the plugin message (cfr. Janus docs). + * {@link https://janus.conf.meetecho.com/docs/videoroom.html} + */ +export type VideoRoomData = object; +/** + * The response event when a publisher has joined. + */ +export type VIDEOROOM_EVENT_PUB_JOINED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed identifier + */ + feed: number | string; + /** + * - The dsplay name, if available + */ + display?: string; + /** + * - A description of the room, if available + */ + description: string; + /** + * - The list of active publishers + */ + publishers: { + feed: number | string; + display: string; + }; + /** + * - The JSEP answer + */ + jsep?: RTCSessionDescription; +}; +/** + * The response event when a subscriber has joined. + */ +export type VIDEOROOM_EVENT_SUB_JOINED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The published feed identifier + */ + feed: number | string; + /** + * - The published feed display name + */ + display: string; +}; +/** + * The response event to a participant list request. + */ +export type VIDEOROOM_EVENT_PARTICIPANTS_LIST = { + /** + * - The involved room + */ + room: number | string; + /** + * - The current published feed + */ + feed: number | string; + /** + * - The list of current participants + */ + participants: { + feed: number | string; + display?: string; + publisher: boolean; + talking?: boolean; + }; +}; +/** + * The response event for room create request. + */ +export type VIDEOROOM_EVENT_CREATED = { + /** + * - The created room + */ + room: number | string; + /** + * - True if the room has been persisted on the Janus configuratin file + */ + permanent: boolean; +}; +/** + * The response event for room destroy request. + */ +export type VIDEOROOM_EVENT_DESTROYED = { + /** + * - The destroyed room + */ + room: number | string; + /** + * - True if the room has been removed from the Janus configuratin file + */ + permanent: boolean; +}; +/** + * The response event for room exists request. + */ +export type VIDEOROOM_EVENT_EXISTS = { + /** + * - The queried room + */ + room: number | string; +}; +/** + * Descriptrion of an active RTP forwarder. + */ +export type RtpForwarder = { + /** + * - The target host + */ + host: string; + /** + * - The RTP audio target port + */ + audio_port?: number; + /** + * - The RTCP audio target port + */ + audio_rtcp_port?: number; + /** + * - The audio forwarder identifier + */ + audio_stream?: number; + /** + * - The RTP video target port + */ + video_port?: number; + /** + * - The RTCP video target port + */ + video_rtcp_port?: number; + /** + * - The video forwarder identifier + */ + video_stream?: number; + /** + * - The datachannels target port + */ + data_port?: number; + /** + * - The datachannels forwarder identifier + */ + data_stream?: number; + /** + * - SSRC this forwarder is using + */ + ssrc?: number; + /** + * - payload type this forwarder is using + */ + pt?: number; + /** + * - video substream this video forwarder is relaying + */ + substream?: number; + /** + * - whether the RTP stream is encrypted + */ + srtp?: boolean; +}; +/** + * The response event for RTP forward start request. + */ +export type VIDEOROOM_EVENT_RTP_FWD_STARTED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The forwarder object + */ + forwarder: RtpForwarder; +}; +/** + * The response event for RTP forward stop request. + */ +export type VIDEOROOM_EVENT_RTP_FWD_STOPPED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed identifier being forwarded + */ + feed: number | string; + /** + * - The forwarder identifier + */ + stream: number; +}; +/** + * The response event for RTP forwarders list request. + */ +export type VIDEOROOM_EVENT_RTP_FWD_LIST = { + /** + * - The involved room + */ + room: number | string; + /** + * - The list of forwarders + */ + forwarders: { + feed: number | string; + forwarders: RtpForwarder[]; + }; +}; +/** + * The response event for videoroom list request. + */ +export type VIDEOROOM_EVENT_LIST = { + /** + * - The list of the room as returned by Janus + */ + list: object[]; +}; +/** + * The response event for ACL tokens edit (allowed) request. + */ +export type VIDEOROOM_EVENT_ALLOWED = { + /** + * - The updated, complete, list of allowed tokens + */ + list: string[]; +}; +/** + * The response event for publisher/subscriber configure request. + */ +export type VIDEOROOM_EVENT_CONFIGURED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed identifier + */ + feed: number | string; + /** + * - The display name, if available + */ + display?: string; + /** + * - True if the request had it true + */ + restart?: boolean; + /** + * - True if the request had it true + */ + update?: boolean; + /** + * - A string with the value returned by Janus + */ + configured: string; + /** + * - The JSEP answer + */ + jsep?: RTCSessionDescription; +}; +/** + * The response event for subscriber start request. + */ +export type VIDEOROOM_EVENT_STARTED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed that started + */ + feed: number | string; + /** + * - A string with the value returned by Janus + */ + started: string; +}; +/** + * The response event for subscriber pause request. + */ +export type VIDEOROOM_EVENT_PAUSED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed that has been paused + */ + feed: number | string; + /** + * - A string with the value returned by Janus + */ + paused: string; +}; +/** + * The response event for publisher unpublish request. + */ +export type VIDEOROOM_EVENT_UNPUBLISHED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed that unpublished + */ + feed: number | string; +}; +/** + * The response event for publiher/subscriber leave request. + */ +export type VIDEOROOM_EVENT_LEAVING = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed that left + */ + feed: number | string; + /** + * - An optional string with the reason of the leaving + */ + reason?: string; +}; +/** + * The response event for the kick request. + */ +export type VIDEOROOM_EVENT_KICKED = { + /** + * - The involved room + */ + room: number | string; + /** + * - The feed that has been kicked + */ + feed: number | string; +}; diff --git a/types/protocol.d.ts b/types/protocol.d.ts new file mode 100644 index 0000000..5a760b6 --- /dev/null +++ b/types/protocol.d.ts @@ -0,0 +1,58 @@ +export namespace JANUS { + namespace REQUEST { + const SERVER_INFO: string; + const CREATE_SESSION: string; + const KEEPALIVE: string; + const DESTROY_SESSION: string; + const ATTACH_PLUGIN: string; + const MESSAGE: string; + const TRICKLE: string; + const HANGUP: string; + const DETACH_PLUGIN: string; + } + const ACK: string; + namespace RESPONSE { + export const SUCCESS: string; + const SERVER_INFO_1: string; + export { SERVER_INFO_1 as SERVER_INFO }; + export const ERROR: string; + } + namespace EVENT { + const EVENT_1: string; + export { EVENT_1 as EVENT }; + export const DETACHED: string; + const HANGUP_1: string; + export { HANGUP_1 as HANGUP }; + export const MEDIA: string; + export const TIMEOUT: string; + export const WEBRTCUP: string; + export const SLOWLINK: string; + export const TRICKLE: string; + } + namespace ADMIN { + const LIST_SESSIONS: string; + const LIST_HANDLES: string; + const HANDLE_INFO: string; + const START_PCAP: string; + const STOP_PCAP: string; + } +} +export namespace JANODE { + export namespace EVENT_2 { + const CONNECTION_CLOSED: string; + const SESSION_DESTROYED: string; + const HANDLE_DETACHED: string; + const HANDLE_HANGUP: string; + const HANDLE_MEDIA: string; + const HANDLE_TRICKLE: string; + const HANDLE_WEBRTCUP: string; + const HANDLE_SLOWLINK: string; + const CONNECTION_ERROR: string; + } + export { EVENT_2 as EVENT }; +} +export function isResponseData(data: object): boolean; +export function isEventData(data: object): boolean; +export function isErrorData(data: object): boolean; +export function isTimeoutData(data: object): boolean; +export function isAckData(data: object): boolean; diff --git a/types/session.d.ts b/types/session.d.ts new file mode 100644 index 0000000..7c391c8 --- /dev/null +++ b/types/session.d.ts @@ -0,0 +1,181 @@ +import Connection from './connection.js' +import { EventEmitter } from 'events' +import {AudioBridgeEvent, AudioBridgeHandle} from './plugins/audiobridge-plugin.js' +import {EchoTestHandle} from './plugins/echotest-plugin.js' +import {StreamingHandle} from './plugins/streaming-plugin.js' +import {VideoRoomHandle} from './plugins/videoroom-plugin.js' + +export default Session; +/** + * Class representing a Janode session.
+ * + * Session extends EventEmitter, so an instance can emit events and users can subscribe to them.
+ * + * Users are not expected to create Session instances, but insted use the Connection.create() API. + * + * @hideconstructor + */ +declare class Session extends EventEmitter { + /** + * Create a Janode session. + * + * @param {module:connection~Connection} connection - A reference to the parent connection + * @param {number} id - The session identifier + * @param {number} [ka_interval=30] - The keepalive interval in seconds + */ + constructor(connection: Connection, id: number, ka_interval?: number); + /** + * The transaction manager used by this session. + * + * @private + * @type {TransactionManager} + */ + private _tm; + /** + * A boolean flag indicating that the session is being destroyed. + * Once the destroy has been completed, the flag returns to false. + * + * @private + * @type {boolean} + */ + private _destroying; + /** + * A boolean flag indicating that the session has been destroyed. + * + * @private + * @type {boolean} + */ + private _destroyed; + /** + * Keep track of the handles. + * + * @private + * @type {Map} + */ + private _handles; + /** + * The task of the peridic keep-alive. + * + * @private + */ + private _ka_task; + /** + * The parent Janode connection. + * + * @type {module:connection~Connection} + */ + connection: Connection; + /** + * The session unique id, usually taken from Janus response. + * + * @type {number} + */ + id: number; + /** + * A more descriptive, not unique string (used for logging). + * + * @type {string} + */ + name: string; + /** + * The callback function used for a connection closed event. + * + * @private + */ + private _closedListener; + /** + * The callback function used for a connection error event. + * + * @private + */ + private _errorListener; + /** + * Cleanup the session canceling the KA task, closing all owned transactions, emitting the destroyed event + * and removing all registered listeners. + * + * @private + */ + private _signalDestroy; + /** + * Send a keep-alive request. + * The returned promise will return upon keep-alive response or a wait timeout. + * + * @private + * @param {number} timeout - The timeout in milliseconds before detecting a ka timeout + * @returns {Promise} + */ + private _sendKeepAlive; + /** + * Helper method to enable the keep-alive task with a given period. + * + * @private + * @param {number} delay - The period of the task in milliseconds + */ + private _setKeepAlive; + /** + * Helper method to disable the keep-alive task. + * + * @private + */ + private _unsetKeepAlive; + /** + * Helper to check if a pending transaction is a keep-alive. + * + * @private + * @param {string} id - The transaction identifier + * @returns {boolean} + */ + private _isKeepaliveTx; + /** + * Manage a message sent to this session. If a handle is involved let it manage the message. + * Trickles transactions are closed here because the Janus API lacks the handle id in the ack. + * If the message involves a owned transaction and the response is a definitive one, + * the transaction will be closed. + * + * @private + * @param {object} janus_message + */ + private _handleMessage; + /** + * Decorate request with session id and transaction (if missing). + * + * @private + * @param {object} request + */ + private _decorateRequest; + /** + * Send a request from this session. + * + * @param {object} request + * @returns {Promise} A promise resolving with the response + */ + sendRequest(request: object): Promise; + /** + * Gracefully destroy the session. + * + * @returns {Promise} + */ + destroy(): Promise; + /** + * Attach a plugin in this session using a plugin descriptor. + * If the Handle param is missing, a new generic Handle will be attached. + * Returns a promise with the pending attach operation. + * + * @param {module:janode~PluginDescriptor} descriptor - The plugin descriptor + * @returns {Promise} + * + * @example + * + * // attach an echotest plugin with its specifc class + * import EchoTestPlugin from 'janode/src/plugins/echotest-plugin.js'; + * const echoHandle = await janodeSession.attach(EchoTestPlugin); + * + * // attach a plugin without using its custom implementation + * const handle = await session.attach({ id: 'janus.plugin.echotest' }); + * + */ + attach({id,Handle,EVENT}: {id:string, Handle:AudioBridgeHandle, EVENT:AudioBridgeEvent}): Promise + attach({id,Handle,EVENT}: {id:string, Handle:EchoTestHandle, EVENT:object}): Promise + attach({id,Handle,EVENT}: {id:string, Handle:StreamingHandle, EVENT:object}): Promise + attach({id,Handle,EVENT}: {id:string, Handle:VideoRoomHandle, EVENT:object}): Promise +} diff --git a/types/tmanager.d.ts b/types/tmanager.d.ts new file mode 100644 index 0000000..78d997a --- /dev/null +++ b/types/tmanager.d.ts @@ -0,0 +1,128 @@ +export default TransactionManager; +/** + * An object describing a pending transaction stored in the manager. + */ +export type PendingTransaction = { + /** + * - The transaction identifier + */ + id: string; + /** + * - A reference to the object that created the transaction + */ + owner: object; + /** + * - The janus request for the pending transaction + */ + request: string; + /** + * - The success callback + */ + done: Function; + /** + * - The error callback + */ + error: Function; +}; +/** + * Class representing a Janode Transaction Manager (TM). + * A transaction manager stores the pending transactions and has methods to create and close transactions. + * Every transaction objects has an identifier, a reference to the owner and a kind of janus request. + * + * @private + */ +declare class TransactionManager { + /** + * Create a Transacton Manager (TM) + * + * @param {string} [id] - The identifier given to the manager (got from a counter if missing) + */ + constructor(id?: string); + transactions: any; + id: string; + _dbgtask: number; + /** + * Clear the internal transaction table and the debugging printing task. + */ + clear(): void; + /** + * Check if the TM has a specific transaction. + * + * @param {string} id - The transaction id + * @returns {boolean} True if the manager contains the transaction + */ + has(id: string): boolean; + /** + * Get a specific transaction from the TM. + * + * @param {string} id - The transaction id + * @returns {PendingTransaction|void} The wanted transaction, or nothing if missing + */ + get(id: string): PendingTransaction | void; + /** + * Get the current size of the transaction table. + * + * @returns {number} The size of the table + */ + size(): number; + /** + * Add a pending transaction to the TM. + * + * @param {string} id - The transaction id + * @param {PendingTransaction} transaction + */ + set(id: string, transaction: PendingTransaction): void; + /** + * Delete a specific transaction from the TM. + * + * @param {string} id - The transaction id to delete + */ + delete(id: string): void; + /** + * Get the owner of a specific transaction id. + * + * @param {string} id - The transaction id + * @returns {object|void} A reference to the owner object, or nothing if transaction is missing + */ + getTransactionOwner(id: string): object | void; + /** + * Create a new transaction if id does not exist in the table and add it to the TM. + * + * @param {string} id - The transaction identifier + * @param {object} owner - A reference to the object that created the transaction + * @param {string} request - The janus request for the pending transaction + * @param {function} done - The success callback + * @param {function} error - The error callback + * @returns {PendingTransaction|void} The newly created transaction, or nothing if the id already exists + */ + createTransaction(id: string, owner: object, request: string, done: Function, error: Function): PendingTransaction | void; + /** + * Close a transaction with an error if the id is found and the owner matches. + * The closed transaction will be removed from the internal table and the error cb will be invoked with the error string. + * + * @param {string} id - The transaction identifier + * @param {object} owner - A reference to the transaction owner + * @param {string} error - The error string + * @returns {PendingTransaction|void} The closed transaction, or nothing if the id does not exist or the owner does not match + */ + closeTransactionWithError(id: string, owner: object, error: string): PendingTransaction | void; + /** + * Close all the stored transactions with an error. + * If an owner is specified only the owner's transaction will be closed. + * The closed transactions will be removed from the internal table. + * + * @param {object} [owner] - A reference to the transaction owner + * @param {string} error - The error string + */ + closeAllTransactionsWithError(owner?: object, error?: string): void; + /** + * Close a transaction with success if the id is found and the owner matches. + * The closed transaction will be removed from the internal table and the success cb will be invoked with the specified data. + * + * @param {string} id - The transaction identifier + * @param {object} owner - A reference to the transaction owner + * @param {*} data - The success callback data + * @returns {PendingTransaction|void} The closed transaction, or nothing if the id does not exist or the owner does not match + */ + closeTransactionWithSuccess(id: string, owner: object, data: any): PendingTransaction | void; +} diff --git a/types/transport-unix.d.ts b/types/transport-unix.d.ts new file mode 100644 index 0000000..f71692f --- /dev/null +++ b/types/transport-unix.d.ts @@ -0,0 +1,121 @@ +import Connection from "./connection.js"; + +export default TransportUnix; +/** + * Class representing a connection through Unix dgram sockets transport.
+ * + * In case of failure a connection will be retried according to the configuration (time interval and + * times to attempt). At every attempt, if multiple addresses are available for Janus, the next address + * will be tried. An error will be raised only if the maxmimum number of attempts have been reached.
+ * + * @private + */ +declare class TransportUnix { + /** + * Create a connection through Unix dgram socket. + * + * @param {module:connection~Connection} connection - The parent Janode connection + */ + constructor(connection: any); + /** + * The parent Janode connection. + * + * @type {module:connection~Connection} + */ + _connection: any; + /** + * The internal Unix Socket. + * + * @type {module:unix-dgram~Socket} + */ + _socket: any; + /** + * The local file to bind the socket to. + */ + _local_bind: string; + /** + * Internal counter for connection attempts. + * + * @type {number} + */ + _attempts: number; + /** + * A boolean flag indicating that the connection is being opened. + * + * @type {boolean} + */ + _opening: boolean; + /** + * A boolean flag indicating that the connection has been opened. + * + * @type {boolean} + */ + _opened: boolean; + /** + * A boolean flag indicating that the connection is being closed. + * + * @type {boolean} + */ + _closing: boolean; + /** + * A boolean flag indicating that the connection has been closed. + * + * @type {boolean} + */ + _closed: boolean; + /** + * A numerical identifier assigned for logging purposes. + * + * @type {number} + */ + id: number; + /** + * A more descriptive, not unique string (used for logging). + * + * @type {string} + */ + name: string; + /** + * Initialize the internal socket. + * + * @returns {Promise} + */ + _initUnixSocket(): Promise; + /** + * Internal helper to open a unix socket connection. + * In case of error retry the connection with another address from the available pool. + * If maximum number of attempts is reached, throws an error. + * + * @returns {module:unix-dgram~Socket} The unix socket + */ + _attemptOpen(): any; + _close(): void; + /** + * Open a transport connection. This is called from parent connection. + * + * @returns {Promise} A promise resolving with the Janode connection + */ + open(): Promise; + /** + * Get the remote Janus hostname. + * It is called from the parent connection. + * + * @returns {string} The hostname of the Janus server + */ + getRemoteHostname(): string; + /** + * Gracefully close the connection. + * It is called from the parent connection. + * + * @returns {Promise} + */ + close(): Promise; + /** + * Send a request from this connection. + * It is called from the parent connection. + * + * @param {object} request - The request to be sent + * @returns {Promise} A promise resolving with a response from Janus + */ + send(request: object): Promise; +} diff --git a/types/transport-ws.d.ts b/types/transport-ws.d.ts new file mode 100644 index 0000000..f02bf40 --- /dev/null +++ b/types/transport-ws.d.ts @@ -0,0 +1,146 @@ +import Connection from './connection.js' +export default TransportWs; +/** + * Class representing a connection through WebSocket transport.
+ * + * In case of failure a connection will be retried according to the configuration (time interval and + * times to attempt). At every attempt, if multiple addresses are available for Janus, the next address + * will be tried. An error will be raised only if the maxmimum number of attempts have been reached.
+ * + * Internally uses WebSockets API to establish a connection with Janus and uses ws ping/pong as keepalives.
+ * + * @private + */ +declare class TransportWs { + /** + * Create a connection through WebSocket. + * + * @param {module:connection~Connection} connection - The parent Janode connection + */ + constructor(connection: any); + /** + * The parent Janode connection. + * + * @type {module:connection~Connection} + */ + _connection: any; + /** + * The internal WebSocket connection. + * + * @type {WebSocket} + */ + _ws: WebSocket; + /** + * Internal counter for connection attempts. + * + * @type {number} + */ + _attempts: number; + /** + * A boolean flag indicating that the connection is being opened. + * + * @type {boolean} + */ + _opening: boolean; + /** + * A boolean flag indicating that the connection has been opened. + * + * @type {boolean} + */ + _opened: boolean; + /** + * A boolean flag indicating that the connection is being closed. + * + * @type {boolean} + */ + _closing: boolean; + /** + * A boolean flag indicating that the connection has been closed. + * + * @type {boolean} + */ + _closed: boolean; + /** + * The task of the peridic ws ping. + * + * @type {*} + */ + _ping_task: any; + /** + * A numerical identifier assigned for logging purposes. + * + * @type {number} + */ + id: number; + /** + * A more descriptive, not unique string (used for logging). + * + * @type {string} + */ + name: string; + /** + * Initialize the internal WebSocket. + * Wraps with a promise the standard WebSocket API opening. + * + * @returns {Promise} + */ + _initWebSocket(): Promise; + /** + * Internal helper to open a websocket connection. + * In case of error retry the connection with another address from the available pool. + * If maximum number of attempts is reached, throws an error. + * + * @returns {WebSocket} The websocket connection + */ + _attemptOpen(): WebSocket; + /** + * Open a transport connection. This is called from parent connection. + * + * @returns {Promise} A promise resolving with the Janode connection + */ + open(): Promise; + /** + * Send a ws ping frame. + * This API is only available when the library is not used in a browser. + * + * @returns {Promise} + */ + _ping(): Promise; + /** + * Set a ws ping-pong task. + * + * @param {number} delay - The ping interval in milliseconds + * @returns {void} + */ + _setPingTask(delay: number): void; + /** + * Remove the ws ping task. + * + * @returns {void} + */ + _unsetPingTask(): void; + /** + * Get the remote Janus hostname. + * It is called from the parent connection. + * + * @returns {string} The hostname of the Janus server + */ + getRemoteHostname(): string; + /** + * Gracefully close the connection. + * Wraps with a promise the standard WebSocket API "close". + * It is called from the parent connection. + * + * @returns {Promise} + */ + close(): Promise; + /** + * Send a request from this connection. + * Wraps with a promise the standard WebSocket API "send". + * It is called from the parent connection. + * + * @param {object} request - The request to be sent + * @returns {Promise} A promise resolving with a response from Janus + */ + send(request: object): Promise; +} diff --git a/types/utils/logger.d.ts b/types/utils/logger.d.ts new file mode 100644 index 0000000..b7c118c --- /dev/null +++ b/types/utils/logger.d.ts @@ -0,0 +1,9 @@ +export default Logger; +declare namespace Logger { + function debug(...args: any[]): void; + function verbose(...args: any[]): void; + function info(...args: any[]): void; + function warn(...args: any[]): void; + function error(...args: any[]): void; + function setLevel(lvl?: "none" | "error" | "warn" | "info" | "verb" | "debug"): string; +} diff --git a/types/utils/utils.d.ts b/types/utils/utils.d.ts new file mode 100644 index 0000000..9fc09b7 --- /dev/null +++ b/types/utils/utils.d.ts @@ -0,0 +1,16 @@ +export function randomString(len?: number): string; +export function getNumericID(_: any): string; +export function newIterator(list: any[]): CircularIterator; +export function delayOp(ms: number): Promise; +export function checkUrl(url_string: string, admitted: Array): boolean; +export function getCliArgument(arg_name: string, arg_type: ("string" | "number" | "boolean"), arg_default: string | number | boolean): string | number | boolean | void; +export type CircularIterator = { + /** + * - Advance the iterator and get the new element + */ + nextElem: Function; + /** + * - Get the current element without advancing + */ + currElem: Function; +};