/* eslint-disable class-methods-use-this */
import {
getParamValidity, getRoomStateByName, isAString, statelessGetUserMedia, isAObj, generateUUID,
} from '../utils/helpers';
import { dispatchEvent } from '../utils/skylinkEventManager';
import { streamEnded } from '../skylink-events';
import { SDK_VERSION } from '../constants';
import PeerConnection from '../peer-connection/index';
import PeerData from '../peer-data/index';
import PeerPrivileged from '../peer-privileged/index';
import ScreenSharing from '../features/screen-sharing/index';
import MediaStream from '../media-stream/index';
import Room from '../room/index';
import Recording from '../features/recording/index';
import RTMP from '../features/rtmp/index';
import AsyncMessaging from '../features/messaging/async-messaging';
import EncryptedMessaging from '../features/messaging/encrypted-messaging';
import Messaging from '../features/messaging';
import DataTransfer from '../features/data-transfer';
/**
* @classdesc This class lists all the public methods of Skylink.
* @interface
* @private
*/
class SkylinkPublicInterface {
/**
* @description Method that starts a room session.
* <p>Resolves with an array of <code>MediaStreams</code> or null if pre-fetched
* stream was passed into <code>joinRoom</code> method. First item in array is <code>MediaStream</code> of kind audio and second item is
* <code>MediaStream</code> of kind video.</p>
* @param {joinRoomOptions} [options] - The options available to join the room and configure the session.
* @param {MediaStream} [prefetchedStream] - The pre-fetched media stream object obtained when the user calls {@link Skylink#getUserMedia|getUserMedia} method before {@link Skylink#joinRoom|joinRoom} method.
* @return {Promise.<MediaStreams>}
* @example
* Example 1: Calling joinRoom with options
*
* const joinRoomOptions = {
* audio: true,
* video: true,
* roomName: "Room_1",
* userData: {
* username: "GuestUser_1"
* },
* };
*
* skylink.joinRoom(joinRoomOptions)
* .then((streams) => {
* if (streams[0]) {
* window.attachMediaStream(audioEl, streams[0]); // first item in array is an audio stream
* }
* if (streams[1]) {
* window.attachMediaStream(videoEl, streams[1]); // second item in array is a video stream
* }
* })
* .catch((error) => {
* // handle error
* });
* @example
* Example 2: Retrieving a pre-fetched stream before calling joinRoom
*
* // REF: {@link Skylink#getUserMedia|getUserMedia}
* const prefetchedStreams = skylink.getUserMedia();
*
* const joinRoomOptions = {
* roomName: "Room_1",
* userData: {
* username: "GuestUser_1"
* },
* };
*
* skylink.joinRoom(joinRoomOptions, prefetchedStreams)
* .catch((error) => {
* // handle error
* });
* @alias Skylink#joinRoom
*/
async joinRoom(options = {}, prefetchedStream) {
return Room.joinRoom(options, prefetchedStream);
}
/**
* @description Method that sends a message to peers via the data channel connection.
* @param {String} [roomName] - The name of the room the message is intended for.
* When not provided, the message will be broadcast to all rooms where targetPeerId(s) are found (if provided).
* Note when roomName is provided, targetPeerId should be provided as null.
* @param {String|JSON} message - The message.
* @param {String|Array} [targetPeerId] - The target peer id to send message to.
* When provided as an Array, it will send the message to only peers which ids are in the list.
* When not provided, it will broadcast the message to all connected peers with data channel connection in a room.
* @example
* Example 1: Broadcasting to all peers in all rooms
*
* const message = "Hello everyone!";
*
* skylink.sendP2PMessage(message);
* @example
* Example 2: Broadcasting to all peers in a room
*
* const message = "Hello everyone!";
* const roomName = "Room_1";
*
* skylink.sendP2PMessage(roomName, message);
* @example
* Example 3: Sending message to a peer in all rooms
*
* const message = "Hello!";
* const targetPeerId = "peerId";
*
* skylink.sendP2PMessage(message, targetPeerId);
* @example
* Example 4: Sending message to a peer in a room
*
* const message = "Hello!";
* const targetPeerId = "peerId";
* const roomName = "Room_1";
*
* skylink.sendP2PMessage(roomName, message, targetPeerId);
* @example
* Example 5: Sending message to selected Peers in a room
*
* const message = "Hello!";
* const selectedPeers = ["peerId_1", "peerId_2"];
* const roomName = "Room_1";
*
* skylink.sendP2PMessage(roomName, message, selectedPeers);
* @example
* // Listen for onIncomingMessage event
* skylink.addEventListener(SkylinkEvents.ON_INCOMING_MESSAGE, (evt) => {
* const detail = evt.detail;
* if (detail.isSelf) {
* // handle message from self
* } else {
* // handle message from remote peer
* }
* }
* @fires {@link SkylinkEvents.event:ON_INCOMING_MESSAGE|ON_INCOMING_MESSAGE} event
* @alias Skylink#sendP2PMessage
*/
sendP2PMessage(roomName = '', message = '', targetPeerId = '') {
PeerConnection.sendP2PMessage(roomName, message, targetPeerId);
}
/**
* @description Function that sends a message to peers via the Signaling socket connection.
* <p><code>sendMessage</code> can also be used to trigger call actions on the remote. Refer to Example 3 for muting the remote peer.</p>
* @param {String} roomName - room name to send the message.
* @param {String|JSON} message - The message.
* @param {String|Array} [targetPeerId] - The target peer id to send message to.
* - When provided as an Array, it will send the message to only peers which ids are in the list.
* - When not provided, it will broadcast the message to all connected peers in the room.
* @param {String} [peerSessionId] - The peer session id can be used to attribute the message to a client across sessions. It will replace the
* peerId. The peer session id is returned in the peerInfo object. <i>This is an advanced feature.</i>
* @example
* Example 1: Broadcasting to all peers in a room
*
* let sendMessage = (roomName) => {
* const message = "Hi!";
* skylink.sendMessage(roomName, message);
* }
* @example
* Example 2: Broadcasting to selected peers
*
* let sendMessage = (roomName) => {
* const message = "Hi all!";
* const selectedPeers = ["PeerID_1", "PeerID_2"];
* skylink.sendMessage(roomName, message, selectedPeers);
* }
* @example
* Example 3: Muting the remote peer
*
* // The local peer - send custom message object
* const msgObject = JSON.stringify({ data: "data-content", type: "muteStreams", audio: true, video: false });
* this.skylink.sendP2PMessage(roomName, msgObject);
*
* // The remote peer - add an event listener for ON_INCOMING_MESSAGE and check for the custom message object
* SkylinkEventManager.addEventListener(skylinkConstants.EVENTS.ON_INCOMING_MESSAGE, (evt) => {
* const {message, peerId, isSelf, room} = evt.detail;
* const msg = JSON.parse(message.content);
* if (msg.type === "muteStreams") {
* skylink.muteStreams(roomName, { audioMuted: msg.audio, videoMuted: msg.video });
* }
* });
* @fires {@link SkylinkEvents.event:ON_INCOMING_MESSAGE|ON_INCOMING_MESSAGE} event
* @alias Skylink#sendMessage
* @since 0.4.0
*/
sendMessage(roomName = '', message = '', targetPeerId = '', peerSessionId = '') {
Messaging.sendMessage(roomName, message, targetPeerId, peerSessionId);
}
/**
* @description Method that retrieves the message history from server if Persistent Message feature is enabled for the key.
* @param {String} roomName - The name of the room.
* @param {String} [roomSessionId] - The room session id to retrieve the messages from. The room session id is found in the <code>peerInfo</code> object in
* most event payloads, e.g. <code>PEER_JOINED</code>.
* - A room session starts when the first peer joins a room. A room session ends when the last peer leaves the room.
* - Subsequent peers that join the same room, i.e. the same room name, starts a new room session.
* @example
* Example 1: Retrieving stored messages
*
* // add event listener to catch storedMessages event
* SkylinkEventManager.addEventListener(SkylinkConstants.EVENTS.STORED_MESSAGES, (evt) => {
* const { storedMessages } = evt.detail;
* storedMessages.content.forEach((message) => {
* // do something
* })
* });
*
* let getStoredMessages = (roomName) => {
* this.skylink.getStoredMessages(roomName);
* }
* @fires {@link SkylinkEvents.event:STORED_MESSAGES|STORED_MESSAGES} event
* @alias Skylink#getStoredMessages
* @since 2.1
*/
getStoredMessages(roomName, roomSessionId = '') {
const roomState = getRoomStateByName(roomName);
if (roomState) {
new AsyncMessaging(roomState).getStoredMessages(roomSessionId);
}
}
/**
* @description Method that gets the list of connected peers in the room.
* @param {String} roomName - The name of the room.
* @return {JSON.<String, peerInfo>|null} <code>peerInfo</code> keyed by peer id. Additional <code>isSelf</code> flag to determine if peer is user or not. Null is returned if room has not been created.
* @example
* Example 1: Get the list of currently connected peers in the same room
*
* const peers = skylink.getPeersInRoom(roomName);
* @alias Skylink#getPeersInRoom
*/
getPeersInRoom(roomName) {
if (getParamValidity(roomName, 'roomName', 'getPeersInRoom')) {
return PeerConnection.getPeersInRoom(roomName);
}
return null;
}
/**
* @description Method that returns the user / peer current session information.
* @param {String} roomName - The name of the room.
* @param {String|null} [peerId] The peer id to return the current session information from.
* - When not provided or that the peer id is does not exists, it will return
* the user current session information.
* @return {peerInfo|null} The user / peer current session information.
* @example
* Example 1: Get peer current session information
*
* const peerPeerInfo = skylink.getPeerInfo(peerId);
* @example
* Example 2: Get user current session information
*
* const userPeerInfo = skylink.getPeerInfo();
* @alias Skylink#getPeerInfo
*/
getPeerInfo(roomName, peerId = null) {
const roomState = getRoomStateByName(roomName);
if (peerId && roomState) {
return PeerData.getPeerInfo(peerId, roomState.room);
}
if (!peerId && roomState) {
return PeerData.getCurrentSessionInfo(roomState.room);
}
return null;
}
/**
* @description Method that returns the user / peer current custom data.
* @param {String} roomName - The room name.
* @param {String} [peerId] - The peer id to return the current custom data from.
* - When not provided or that the peer id is does not exists, it will return
* the user current custom data.
* @return {Object|null} The user / peer current custom data.
* @example
* Example 1: Get peer current custom data
*
* const peerUserData = skylink.getUserData(peerId);
* @example
* Example 2: Get user current custom data
*
* const userUserData = skylink.getUserData();
* @alias Skylink#getUserData
*/
getUserData(roomName, peerId) {
const roomState = getRoomStateByName(roomName);
if (roomState && roomState.room) {
return PeerData.getUserData(roomState, peerId);
}
return null;
}
/**
* @description Method that overwrites the user current custom data.
* @param {String} roomName - The room name.
* @param {JSON|String} userData - The updated custom data.
* @fires {@link SkylinkEvents.event:PEER_UPDATED|PEER_UPDATED} event if peer is in room with <code>isSelf=true</code>.
* @example
* Example 1: Update user custom data after joinRoom()
*
* // add event listener to catch setUserData changes
* SkylinkEventManager.addEventListener(SkylinkConstants.peerUpdated, (evt) => {
* const { detail } = evt;
* // do something
* });
*
* const userData = "afterjoin";
* skylink.setUserData(userData);
* @alias Skylink#setUserData
*/
setUserData(roomName, userData) {
const roomState = getRoomStateByName(roomName);
if (roomState && roomState.room) {
return PeerData.setUserData(roomState.room, userData);
}
return null;
}
/**
* @description Method that retrieves peer connection bandwidth stats and ICE connection status.
* @param {String} roomName - The room name.
* @param {String|Array} [peerId] The target peer id to retrieve connection stats from.
* - When provided as an Array, it will retrieve all connection stats from all the peer ids provided.
* - When not provided, it will retrieve all connection stats from the currently connected peers in the room.
* @return {Promise<Array.<object.<String|statistics>>>}
* @example
* Example 1: Retrieving connection statistics from all peers in a room
*
* skylink.getConnectionStatus("Room_1")
* .then((statistics) => {
* // handle statistics
* }
* .catch((error) => {
* // handle error
* }
* @example
* Example 2: Retrieving connection statistics from selected peers
*
* const selectedPeers = ["peerId_1", "peerId_2"];
* skylink.getConnectionStatus("Room_1", selectedPeers)
* .then((statistics) => {
* // handle statistics
* }
* .catch((error) => {
* // handle error
* }
* @alias Skylink#getConnectionStatus
*/
getConnectionStatus(roomName, peerId) {
const roomState = getRoomStateByName(roomName);
return PeerConnection.getConnectionStatus(roomState, peerId);
}
/**
* @description Method that retrieves the list of peer ids from rooms within the same App space.
* <blockquote class="info">
* Note that this feature requires <code>"isPrivileged"</code> flag to be enabled for the App Key
* provided in the {@link initOptions}, as only Users connecting using
* the App Key with this flag enabled (which we call privileged Users / peers) can retrieve the list of
* peer ids from rooms within the same App space.
* {@link https://support.temasys.com.sg/support/solutions/articles/12000012342-what-is-a-privileged-key-|What is a privileged key?}
* </blockquote>
* @param {String} roomName - The room name
* @param {Boolean} [showAll=false] - The flag if Signaling server should also return the list of privileged peer ids.
* By default, the Signaling server does not include the list of privileged peer ids in the return result.
* @return {Promise.<Object.<String, Array<String>>>} peerList - Array of peer ids, keyed by room name.
* @fires {@link SkylinkEvents.event:GET_PEERS_STATE_CHANGE|GET PEERS STATE CHANGE} event with parameter payload <code>state=ENQUIRED</code> upon calling <code>getPeers</code> method.
* @fires {@link SkylinkEvents.event:GET_PEERS_STATE_CHANGE|GET PEERS STATE CHANGE} event with parameter payload <code>state=RECEIVED</code> when peer list is received from Signaling server.
* @example
* Example 1: Retrieve un-privileged peers
*
* skylink.getPeers(location)
* .then((result) => {
* // do something
* })
* .catch((error) => {
* // handle error
* })
*
* Example 2: Retrieve all (privileged and un-privileged) peers
*
* skylink.getPeers(location, true)
* .then((result) => {
* // do something
* })
* .catch((error) => {
* // handle error
* })
* @alias Skylink#getPeers
* @since 0.6.1
*/
getPeers(roomName, showAll = false) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return PeerPrivileged.getPeerList(roomState.room, showAll);
}
return null;
}
/**
* @typedef {Object} dataChannelInfo
* @property {String} channelName - The data channel id.
* @property {String} channelProp - The data channel property.
* @property {String} channelType - The data channel type.
* @property {String} currentTransferId - The data channel connection
* current progressing transfer session. Defined as <code>null</code> when there is
* currently no transfer session progressing on the data channel connection
* @property {String} currentStreamId - The data channel connection
* current data streaming session id. Defined as <code>null</code> when there is currently
* no data streaming session on the data channel connection.
* @property {String} readyState - The data channel connection readyState.
* @property {String} bufferedAmountLow - The data channel buffered amount.
* @property {String} bufferedAmountLowThreshold - The data channel
* buffered amount threshold.
*/
/**
* @description Method that gets the current list of connected peers data channel connections in the room.
* @param {String} roomName - The room name.
* @return {Object.<string, Object.<String, dataChannelInfo>>} - The list of peer data channels keyed by peer id, keyed by data channel id.
* @example
* Example 1: Get the list of current peers data channels in the same room
*
* const channels = skylink.getPeersDataChannels("Room_1");
* @alias Skylink#getPeersDataChannels
* @since 0.6.18
*/
getPeersDataChannels(roomName) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return PeerData.getPeersDataChannels(roomState);
}
return null;
}
/**
* @typedef {Object} customSettings - The peer stream and data settings.
* @property {Boolean|JSON} data - The flag if peer has any data channel connections enabled.
* If <code>isSelf</code> value is <code>true</code>, this determines if user allows
* data channel connections, else if value is <code>false</code>, this determines if peer has any active
* data channel connections (where {@link SkylinkEvents.event:onDataChannelStateChanged|onDataChannelStateChangedEvent}
* triggers <code>state</code> as <code>OPEN</code> and <code>channelType</code> as
* <code>MESSAGING</code> for peer) with peer.
* @property {Boolean|JSON} audio - The peer stream audio settings keyed by stream id.
* When defined as <code>false</code>, it means there is no audio being sent from peer.
* @property {Boolean} audio[streamId].stereo - The flag if stereo band is configured
* when encoding audio codec is <code>OPUS</code> for receiving audio data.
* @property {Boolean} audio[streamId].echoCancellation - The flag if echo cancellation is enabled for audio tracks.
* @property {String} [audio[streamId].deviceId] - The peer stream audio track source id of the device used.
* @property {Boolean} audio[streamId].exactConstraints - The flag if peer stream audio track is sending exact
* requested values of <code>audio.deviceId</code> when provided.
* @property {Boolean|JSON} video - The peer stream video settings keyed by stream id.
* When defined as <code>false</code>, it means there is no video being sent from peer.
* @property {JSON} [video[streamId].resolution] - The peer stream video resolution.
* [Rel: {@link SkylinkConstants.VIDEO_RESOLUTION|VIDEO_RESOLUTION}]
* @property {Number|JSON} video[streamId].resolution.width - The peer stream video resolution width or
* video resolution width settings.
* When defined as a JSON Object, it is the user set resolution width settings with (<code>"min"</code> or
* <code>"max"</code> or <code>"ideal"</code> or <code>"exact"</code> etc configurations).
* @property {Number|JSON} video[streamId].resolution.height - The peer stream video resolution height or
* video resolution height settings.
* When defined as a JSON Object, it is the user set resolution height settings with (<code>"min"</code> or
* <code>"max"</code> or <code>"ideal"</code> or <code>"exact"</code> etc configurations).
* @property {Number|JSON} [video[streamId].frameRate] - The peer stream video
* <a href="https://en.wikipedia.org/wiki/Frame_rate">frameRate</a> per second (fps) or video frameRate settings.
* When defined as a JSON Object, it is the user set frameRate settings with (<code>"min"</code> or
* <code>"max"</code> or <code>"ideal"</code> or <code>"exact"</code> etc configurations).
* @property {Boolean} video[streamId].screenshare - The flag if peer stream is a screensharing stream.
* @property {String} [video[streamId].deviceId] - The peer stream video track source id of the device used.
* @property {Boolean} video[streamId].exactConstraints The flag if peer stream video track is sending exact
* requested values of <code>video.resolution</code>,
* <code>video.frameRate</code> and <code>video.deviceId</code>
* when provided.
* @property {String|JSON} [video[streamId].facingMode] - The peer stream video camera facing mode.
* When defined as a JSON Object, it is the user set facingMode settings with (<code>"min"</code> or
* <code>"max"</code> or <code>"ideal"</code> or <code>"exact"</code> etc configurations).
* @property {Object} maxBandwidth The maximum streaming bandwidth sent from peer.
* @property {Number} [maxBandwidth.audio] - The maximum audio streaming bandwidth sent from peer.
* @property {Number} [maxBandwidth.video] - The maximum video streaming bandwidth sent from peer.
* @property {Number} [maxBandwidth.data] - The maximum data streaming bandwidth sent from peer.
* @property {Object} mediaStatus The peer streaming media status.
* @property {Number} mediaStatus.audioMuted - The value of the audio status.
* <small>If peer <code>mediaStatus</code> is <code>-1</code>, audio is not present in the stream. If peer <code>mediaStatus</code> is <code>1</code>, audio is present
* in the stream and active (not muted). If peer <code>mediaStatus</code> is <code>0</code>, audio is present in the stream and muted.
* </small>
* @property {Number} mediaStatus.videoMuted - The value of the video status.
* <small>If peer <code>mediaStatus</code> is <code>-1</code>, video is not present in the stream. If peer <code>mediaStatus</code> is <code>1</code>, video is present
* in the stream and active (not muted). If peer <code>mediaStatus</code> is <code>0</code>, video is present in the stream and muted.
* </small>
*/
/**
* @description Method that gets the list of current custom peer settings sent and set.
* @param {String} roomName - The room name.
* @return {Object.<String, customSettings>|null} - The peer custom settings keyed by peer id.
* @example
* Example 1: Get the list of current peer custom settings from peers in a room.
*
* const currentPeerSettings = skylink.getPeersCustomSettings("Room_1");
* @alias Skylink#getPeersCustomSettings
* @since 0.6.18
*/
getPeersCustomSettings(roomName) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return PeerData.getPeersCustomSettings(roomState);
}
return null;
}
/**
* @description Method that refreshes the main messaging data channel.
* @param {String} roomName - The room name.
* @param {String} peerId - The target peer id of the peer data channel to refresh.
* @return {null}
* @example
* Example 1: Initiate refresh data channel
*
* skylink.refreshDatachannel("Room_1", "peerID_1");
*
* @alias Skylink#refreshDatachannel
* @since 0.6.30
*/
refreshDatachannel(roomName, peerId) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return PeerConnection.refreshDataChannel(roomState, peerId);
}
return null;
}
/**
* @description Method that refreshes peer connections to update with the current streaming.
* @param {String} roomName - The name of the room.
* @param {String|Array} [targetPeerId] <blockquote class="info">
* Note that this is ignored if MCU is enabled for the App Key provided in
* {@link initOptions}. <code>refreshConnection()</code> will "refresh"
* all peer connections. </blockquote>
* - The target peer id to refresh connection with.
* - When provided as an Array, it will refresh all connections with all the peer ids provided.
* - When not provided, it will refresh all the currently connected peers in the room.
* @param {Boolean} [iceRestart=false] <blockquote class="info">
* Note that this flag will not be honoured for MCU enabled peer connections where
* <code>options.mcuUseRenegoRestart</code> flag is set to <code>false</code> as it is not necessary since for MCU
* "restart" case is to invoke {@link Skylink#joinRoom|joinRoom} again, or that it is
* not supported by the MCU.</blockquote>
* The flag if ICE connections should restart when refreshing peer connections.
* This is used when ICE connection state is <code>FAILED</code> or <code>DISCONNECTED</code>, which
* can be retrieved with the {@link SkylinkEvents.event:ICE_CONNECTION_STATE|ICE CONNECTION STATE} event.
* @param {JSON} [options] <blockquote class="info">
* Note that for MCU connections, the <code>bandwidth</code>
* settings will override for all peers or the current room connection session settings.</blockquote>
* The custom peer configuration settings.
* @param {JSON} [options.bandwidth] The configuration to set the maximum streaming bandwidth to send to peers.
* Object signature follows {@link Skylink#joinRoom|joinRoom}
* <code>options.bandwidth</code> settings.
* @return {Promise.<refreshConnectionResolve>} - The Promise will always resolve.
* @example
* Example 1: Refreshing a peer connection
*
* skylink.refreshConnection(roomName, peerId)
* .then((result) => {
* const failedRefreshIds = Object.keys(result.refreshErrors);
* failedRefreshIds.forEach((peerId) => {
* // handle error
* });
* });
*
* @example
* Example 2: Refreshing a list of peer connections
* let selectedPeers = ["peerID_1", "peerID_2"];
*
* skylink.refreshConnection(roomName, selectedPeers)
* .then((result) => {
* const failedRefreshIds = Object.keys(result.refreshErrors);
* failedRefreshIds.forEach((peerId) => {
* // handle error
* });
* });
* @example
* Example 3: Refreshing all peer connections
*
* skylink.refreshConnection(roomName)
* .then((result) => {
* const failedRefreshIds = Object.keys(result.refreshErrors);
* failedRefreshIds.forEach((peerId) => {
* // handle error
* });
* });
* @alias Skylink#refreshConnection
* @since 0.5.5
*/
refreshConnection(roomName, targetPeerId, iceRestart, options) {
const roomState = getRoomStateByName(roomName);
return PeerConnection.refreshConnection(roomState, targetPeerId, iceRestart, options);
}
/**
* @description Method that returns starts screenshare and returns the stream.
* @param {String} roomName - The room name.
* @param {getDisplayMediaOptions} options - Screen share options.
* @return {MediaStream|null} - The screen share stream.
* @alias Skylink#shareScreen
* @since 2.0.0
*/
shareScreen(roomName, options) {
const streamId = null;
const roomState = getRoomStateByName(roomName);
if (roomState) {
const screenSharing = new ScreenSharing(roomState);
return screenSharing.start(streamId, options);
}
return null;
}
/**
* <blockquote class="info">
* For a better user experience, the functionality is throttled when invoked many times in less
* than the milliseconds interval configured in the {@link initOptions}.
* </blockquote>
* @description Method that retrieves camera stream.
* <p>Resolves with an array of <code>MediaStreams</code>. First item in array is <code>MediaStream</code> of kind audio and second item is
* <code>MediaStream</code> of kind video.</p>
* @param {String|null} roomName - The room name.
* - If no roomName is passed or <code>getUserMedia()</code> is called before {@link Skylink#joinRoom|joinRoom}, the returned stream will not be associated with a room. The stream must be maintained independently.
* To stop the stream, call {@link Skylink#stopPrefetchedStream|stopPrefetchedStream} method.
* @param {getUserMediaOptions} [options] - The camera stream configuration options.
* - When not provided, the value is set to <code>{ audio: true, video: true }</code>.
* @return {Promise.<MediaStreams>}
* @example
* Example 1: Get both audio and video after joinRoom
*
* skylink.getUserMedia(roomName, {
* audio: true,
* video: true,
* }).then((streams) => // do something)
* .catch((error) => // handle error);
* @example
* Example 2: Get only audio
*
* skylink.getUserMedia(roomName, {
* audio: true,
* video: false,
* }).then((streams) => // do something)
* .catch((error) => // handle error);
* @example
* Example 3: Configure resolution for video
*
* skylink.getUserMedia(roomName, {
* audio: true,
* video: { resolution: skylinkConstants.VIDEO_RESOLUTION.HD },
* }).then((streams) => // do something)
* .catch((error) => // handle error);
* @example
* Example 4: Configure stereo flag for OPUS codec audio (OPUS is always used by default)
*
* this.skylink.getUserMedia(roomName, {
* audio: {
* stereo: true,
* },
* video: true,
* }).then((streams) => // do something)
* .catch((error) => // handle error);
* @example
* Example 5: Get both audio and video before joinRoom
*
* // Note: the prefetched stream must be maintained independently
* skylink.getUserMedia({
* audio: true,
* video: true,
* }).then((streams) => // do something)
* .catch((error) => // handle error);
* @fires <b>If retrieval of fallback audio stream is successful:</b> <br/> - {@link SkylinkEvents.event:MEDIA_ACCESS_SUCCESS|MEDIA ACCESS SUCCESS} event with parameter payload <code>isScreensharing=false</code> and <code>isAudioFallback=false</code> if initial retrieval is successful.
* @fires <b>If initial retrieval is unsuccessful:</b> <br/> Fallback to retrieve audio only stream is triggered (configured in {@link initOptions} <code>audioFallback</code>) <br/>  - {@link SkylinkEvents.event:MEDIA_ACCESS_SUCCESS|MEDIA ACCESS SUCCESS} event{@link SkylinkEvents.event:MEDIA_ACCESS_FALLBACK|MEDIA ACCESS FALLBACK} event with parameter payload <code>state=FALLBACKING</code>, <code>isScreensharing=false</code> and <code>isAudioFallback=true</code> and <code>options.video=true</code> and <code>options.audio=true</code>. <br/> No fallback to retrieve audio only stream <br/> - {@link SkylinkEvents.event:MEDIA_ACCESS_ERROR|MEDIA ACCESS ERROR} event with parameter payload <code>isScreensharing=false</code> and <code>isAudioFallbackError=false</code>.
* @fires <b>If retrieval of fallback audio stream is successful:</b> <br/> - {@link SkylinkEvents.event:MEDIA_ACCESS_SUCCESS|MEDIA ACCESS SUCCESS} event with parameter payload <code>isScreensharing=false</code> and <code>isAudioFallback=true</code>.
* @fires <b>If retrieval of fallback audio stream is unsuccessful:</b> <br/> - {@link SkylinkEvents.event:MEDIA_ACCESS_SUCCESS|MEDIA ACCESS SUCCESS} event{@link SkylinkEvents.event:MEDIA_ACCESS_FALLBACK|MEDIA ACCESS FALLBACK} event with parameter payload <code>state=ERROR</code>, <code>isScreensharing=false</code> and <code>isAudioFallback=true</code>. <br/> - {@link SkylinkEvents.event:MEDIA_ACCESS_ERROR|MEDIA ACCESS ERROR} event with parameter payload <code>isScreensharing=false</code> and <code>isAudioFallbackError=true</code>.
* @alias Skylink#getUserMedia
* @since 0.5.6
*/
// eslint-disable-next-line consistent-return
getUserMedia(roomName = null, options) {
if (!roomName) {
return statelessGetUserMedia(options);
}
if (isAString(roomName)) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return MediaStream.processUserMediaOptions(roomState, options);
}
} else if (isAObj(roomName)) {
return statelessGetUserMedia(roomName);
}
}
/**
* @description Method that stops the {@link Skylink#getUserMedia} stream that is called without roomName param or before {@link Skylink#joinRoom|joinRoom} is called.
* @param {MediaStream} stream - The prefetched stream.
* @return {null}
* @fires {@link SkylinkEvents.event:STREAM_ENDED|STREAM ENDED} event
* @alias Skylink#stopPrefetchedStream
* @since 2.0
* @ignore
*/
stopPrefetchedStream(stream) {
if (stream) {
const isAudio = stream.getAudioTracks().length > 0;
const isVideo = stream.getVideoTracks().length > 0;
stream.getTracks().forEach((track) => {
track.stop();
});
dispatchEvent(streamEnded({
room: null,
peerId: null,
peerInfo: null,
isSelf: true,
isAudio,
isVideo,
streamId: stream.id,
}));
}
return null;
}
/**
* @description Method that stops the screen share stream returned from {@link Skylink#shareScreen|shareScreen} method.
* @param {String} roomName - The room name.
* @return {null}
* @example
* Example 1
*
* skylink.stopScreen(roomName);
*
* @fires {@link SkylinkEvents.event:MEDIA_ACCESS_STOPPED|MEDIA ACCESS STOPPED} event with parameter payload <code>isScreensharing</code> value as <code>true</code> and <code>isAudioFallback</code> value as <code>false</code> if there is a screen stream
* @fires {@link SkylinkEvents.event:STREAM_ENDED|STREAM ENDED} event with parameter payload <code>isSelf</code> value as <code>true</code> and <code>isScreensharing</code> value as <code>true</code> if user is in the room
* @fires {@link SkylinkEvents.event:PEER_UPDATED|PEER UPDATED} event with parameter payload <code>isSelf</code> value as <code>true</code>
* @fires {@link SkylinkEvents.event:ON_INCOMING_STREAM|ON INCOMING STREAM} event with parameter payload <code>isSelf</code> value as <code>true</code> and <code>stream</code> as {@link Skylink#getUserMedia} stream</a> if there is an existing <code>userMedia</code> stream
* @alias Skylink#stopScreen
* @since 0.6.0
*/
stopScreen(roomName) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
const screenSharing = new ScreenSharing(roomState);
screenSharing.stop();
}
return null;
}
/**
* @description Method that stops the <code>userMedia</code> stream (also known as a prefetched stream) returned from {@link
* Skylink#getUserMedia|getUserMedia}</a> method.
* @param {String} roomName - The room name.
* @param {String} streamId - The stream id of the stream to stop. If streamId is not set, all <code>userMedia</code> streams will be stopped.
* @return {Promise}
* @example
* Example 1: Stopping all the streams in a room
*
* skylink.stopStreams(roomName)
* .then(() => // do some thing);
*
* NOTE: If there is a need to call multiple stopStreams, it is recommended to implement it as a promise chain i.e. the previous call should
* resolve before the next call is made. This applies also to calling sendStream at the end of the stopStreams chain.
* Example 2: Stopping multiple streams with streamId
*
* skylink.stopStreams(roomName, streamID_1)
* .then(() => skylink.stopStreams(roomName, streamID_2));
*
* Example 3: Stopping a stream then sending a stream
*
* skylink.stopStreams(roomName, streamID_1)
* .then(() => skylink.sendStream(roomName, stream));
*
* @fires {@link SkylinkEvents.event:MEDIA_ACCESS_STOPPED|MEDIA ACCESS STOPPED} event with parameter payload <code>isSelf=true</code> and <code>isScreensharing=false</code> if there is a <code>getUserMedia</code> stream.
* @fires {@link SkylinkEvents.event:STREAM_ENDED|STREAM ENDED} event with parameter payload <code>isSelf=true</code> and <code>isScreensharing=false</code> if there is a <code>getUserMedia</code> stream and user is in a room.
* @fires {@link SkylinkEvents.event:PEER_UPDATED|PEER UPDATED} event with parameter payload <code>isSelf=true</code>.
* @alias Skylink#stopStreams
* @since 0.5.6
*/
stopStreams(roomName, streamId) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return MediaStream.stopStreams(roomState, streamId);
}
return null;
}
/**
* @description Method that stops the room session.
* @param {String} roomName - The room name to leave.
* @param {Boolean} [stopStreams=true] - The flag if streams should be stopped. Defaults to true.
* @return {Promise.<String>}
* @example
* Example 1:
*
* // add event listener to catch peerLeft events when remote peer leaves room
* SkylinkEventManager.addEventListener(SkylinkConstants.EVENTS.PEER_LEFT, (evt) => {
* const { detail } = evt;
* // handle remote peer left
* });
*
* skylink.leaveRoom(roomName)
* .then((roomName) => {
* // handle local peer left
* })
* .catch((error) => // handle error);
* @fires {@link SkylinkEvents.event:PEER_LEFT|PEER LEFT} event on the remote end of the connection.
* @alias Skylink#leaveRoom
* @since 0.5.5
*/
leaveRoom(roomName, stopStreams = true) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return Room.leaveRoom(roomState, stopStreams);
}
return null;
}
/**
* @description Method that stops all room sessions.
* @param {Boolean} stopStreams - The flag if streams should be stopped. Defaults to true.
* @return {Promise.<Array.<String>>}
* @alias Skylink#leaveAllRooms
* @since 2.0.0
*/
leaveAllRooms(stopStreams = true) {
return Room.leaveAllRooms(stopStreams);
}
/**
* @description Method that starts a recording session.
* <blockquote class="info">
* Note that this feature requires MCU and recording to be enabled for the App Key provided in
* {@link initOptions}. If recording feature is not available to
* be enabled in the {@link https://console.temasys.io|Temasys Developer Console}, please contact us on our support portal {@link https://temasys.atlassian.net/servicedesk/customer/portals|here}.
* </blockquote>
* @param {String} roomName - The room name.
* @return {Promise<String>} recordingId - The recording session id.
* @example
* Example 1: Start a recording session
*
* skylink.startRecording(roomName)
* .then(recordingId => {
* // do something
* })
* .catch(error => {
* // handle error
* });
* @fires {@link SkylinkEvents.event:RECORDING_STATE|RECORDING STATE} event with payload <code>state=START</code> if recording has started
* successfully.
* @fires {@link SkylinkEvents.event:RECORDING_STATE|RECORDING STATE} event with payload <code>error</code> if an error occurred during recording.
* @alias Skylink#startRecording
* @since 0.6.16
*/
startRecording(roomName) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return Recording.start(roomState);
}
return null;
}
/**
* @description Method that stops a recording session.
* <blockquote class="info">
* <ul>
* <li>
* Note that this feature requires MCU and recording to be enabled for the App Key provided in the
* {@link initOptions}. If recording feature is not available to be enabled in the {@link https://console.temasys.io|Temasys Developer Console},
* please contact us on our support portal {@link https://temasys.atlassian.net/servicedesk/customer/portals|here}.
* </li>
* <li>
* It is mandatory for the recording session to have elapsed for more than 4 minutes before calling <code>stopRecording</code> method.
* </li>
* </ul>
* </blockquote>
* @param {String} roomName - The room name.
* @return {Promise<String>} recordingId - The recording session id.
* @example
* Example 1: Stop the recording session
*
* skylink.stopRecording(roomName)
* .then(recordingId => {
* // do something
* })
* .catch(error => {
* // handle error
* });
* @fires {@link SkylinkEvents.event:RECORDING_STATE|RECORDING STATE} event with payload <code>state=STOP</code> if recording has stopped
* successfully.
* @fires {@link SkylinkEvents.event:RECORDING_STATE|RECORDING STATE} event with payload <code>error</code> if an error occurred during recording.
* @alias Skylink#stopRecording
* @since 0.6.16
*/
stopRecording(roomName) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return Recording.stop(roomState);
}
return null;
}
/**
* @description Method that locks a room.
* @param {String} roomName - The room name.
* @return {Boolean}
* @fires {@link SkylinkEvents.event:ROOM_LOCK|ROOM LOCK} event with payload parameters <code>isLocked=true</code> when the room is successfully locked.
* @example
* // add event listener to listen for room locked state when peer tries to join a locked room
* skylinkEventManager.addEventListener(SkylinkEvents.SYSTEM_ACTION, (evt) => {
* const { detail } = evt;
* if (detail.reason === SkylinkConstants.SYSTEM_ACTION.LOCKED') {
* // handle event
* }
* }
*
* // add event listener to listen for room locked/unlocked event after calling lockRoom method
* skylinkEventManager.addEventListener(SkylinkEvents.ROOM_LOCK, (evt) => {
* const { detail } = evt;
* if (detail.isLocked) {
* // handle room lock event
* } else {
* // handle room unlock event
* }
* }
*
* skylink.lockRoom(roomName);
* @alias Skylink#lockRoom
* @since 0.5.0
*/
lockRoom(roomName) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return Room.lockRoom(roomState);
}
return null;
}
/**
* @description Method that unlocks a room.
* @param {String} roomName - The room name.
* @return {Boolean}
* @fires {@link SkylinkEvents.event:ROOM_LOCK|ROOM LOCK} event with payload parameters <code>isLocked=false</code> when the room is successfully locked.
* @alias Skylink#unlockRoom
* @since 0.5.0
*/
unlockRoom(roomName) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return Room.unlockRoom(roomState);
}
return null;
}
/**
* @typedef {Object} recordingSessions
* @property {Object<string, Object>} #recordingId - The recording session keyed by recording id.
* @property {Boolean} #recordingId.active - The flag that indicates if the recording session is currently active.
* @property {String} #recordingId.state - The current recording state. [Rel: {@link SkylinkConstants.RECORDING_STATE|RECORDING_STATE}]
* @property {String} #recordingId.startedStateTime - The recording session started DateTime in
* {@link https://en.wikipedia.org/wiki/ISO_8601|ISO}.Note that this value may not be
* very accurate as this value is recorded when the start event is received.
* @property {String} #recordingId.endedDateTime - The recording session ended DateTime in
* {@link https://en.wikipedia.org/wiki/ISO_8601|ISO}.Note that this value may not be
* very accurate as this value is recorded when the stop event is received.
* Defined only after <code>state</code> has triggered <code>STOP</code>.
* @property {String} #recordingId.mixingDateTime - The recording session mixing completed DateTime in
* {@link https://en.wikipedia.org/wiki/ISO_8601|ISO}.Note that this value may not be
* very accurate as this value is recorded when the mixing completed event is received.
* Defined only when <code>state</code> is <code>LINK</code>.
* @property {String} #recordingId.links - The recording session links.
* Object signature matches the <code>link</code> parameter payload received in the
* {@link SkylinkEvents.event:RECORDING_STATE|RECORDING STATE} event event.
* @property {Error} #recordingId.error - The recording session error.
* Defined only when <code>state</code> is <code>ERROR</code>.
*/
/**
* Gets the list of current recording sessions since user has connected to the room.
* @description Method that retrieves the list of recording sessions.
* <blockquote class="info">
* Note that this feature requires MCU and recording to be enabled for the App Key provided in
* {@link initOptions}. If recording feature is not available to be enabled in the {@link https://console.temasys.io|Temasys Developer Console},
* please contact us on our support portal {@link https://temasys.atlassian.net/servicedesk/customer/portals|here}.
* </blockquote>
* @param {String} roomName - The room name.
* @return {recordingSessions|{}} The list of recording sessions.
* @example
* Example 1: Get recording sessions
*
* skylink.getRecordings(roomName);
* @alias Skylink#getRecordings
* @since 0.6.16
*/
getRecordings(roomName) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return Recording.getRecordings(roomState);
}
return null;
}
/**
* @description Method that mutes both <code>userMedia</code> [{@link Skylink#getUserMedia|getUserMedia}] stream and
* <code>screen</code> [{@link Skylink#shareScreen|shareScreen}] stream.
* @param {String} roomName - The room name.
* @param {JSON} options - The streams muting options.
* @param {Boolean} [options.audioMuted=true] - The flag if all streams audio
* tracks should be muted or not.
* @param {Boolean} [options.videoMuted=true] - The flag if all streams video
* tracks should be muted or not.
* @param {String} [streamId] - The id of the stream to mute.
* @return {null}
* @example
* Example 1: Mute both audio and video tracks in all streams
*
* skylink.muteStreams(roomName, {
* audioMuted: true,
* videoMuted: true
* });
* @example
* Example 2: Mute only audio tracks in all streams
*
* skylink.muteStreams(roomName, {
* audioMuted: true,
* videoMuted: false
* });
* @example
* Example 3: Mute only video tracks in all streams
*
* skylink.muteStreams(roomName, {
* audioMuted: false,
* videoMuted: true
* });
* @fires <b>On local peer:</b> {@link SkylinkEvents.event:LOCAL_MEDIA_MUTED|LOCAL MEDIA MUTED} event, {@link SkylinkEvents.event:STREAM_MUTED|STREAM MUTED} event, {@link SkylinkEvents.event:PEER_UPDATED|PEER UPDATED} event with payload parameters <code>isSelf=true</code> and <code>isAudio=true</code> if a local audio stream is muted or <code>isVideo</code> if local video stream is muted.
* @fires <b>On remote peer:</b> {@link SkylinkEvents.event:STREAM_MUTED|STREAM MUTED} event, {@link SkylinkEvents.event:PEER_UPDATED|PEER UPDATED} event with with parameter payload <code>isSelf=false</code> and <code>isAudio=true</code> if a remote audio stream is muted or <code>isVideo</code> if remote video stream is muted.
* @alias Skylink#muteStreams
* @since 0.5.7
*/
muteStreams(roomName, options = { audioMuted: true, videoMuted: true }, streamId) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return MediaStream.muteStreams(roomState, options, streamId);
}
return null;
}
/**
* @description Method that starts a RTMP session. [Beta]
* <blockquote class="info">
* Note that this feature requires MCU to be enabled for the App Key provided in the
* {@link initOptions}.
* </blockquote>
* @param {String} roomName - The room name.
* @param {String} streamId - The stream id to live stream for the session.
* @param {String} endpoint - The RTMP endpoint.
* @return {Promise<String>} rtmpId - The RTMP session id.
* @example
* Example 1: Start a rtmp session
*
* skylink.startRTMPSession(roomName, streamId, endpoint)
* .then(rtmpId => {
* // do something
* })
* .catch(error => {
* // handle error
* });
* @fires {@link SkylinkEvents.event:RTMP_STATE|RTMP STATE} event with parameter payload <code>state=START</code>.
* @alias Skylink#startRTMPSession
* @since 0.6.36
*/
startRTMPSession(roomName, streamId, endpoint) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return RTMP.startSession(roomState, streamId, endpoint);
}
return null;
}
/**
* @description Method that stops a RTMP session. [Beta]
* <blockquote class="info">
* Note that this feature requires MCU to be enabled for the App Key provided in {@link initOptions}.
* </blockquote>
* @param {String} roomName - The room name.
* @param {String} rtmpId - The RTMP session id.
* @return {Promise<String>}
* @example
* Example 1: Stop rtmp session
*
* skylink.stopRTMPSession(roomName, rtmpId)
* .then(rtmpId => {
* // do something
* })
* .catch(error => {
* // handle error
* });
* @fires {@link SkylinkEvents.event:RTMP_STATE|RTMP STATE} event with parameter payload <code>state=STOP</code>.
* @alias Skylink#stopRTMPSession
* @since 0.6.36
*/
stopRTMPSession(roomName, rtmpId) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return RTMP.stopSession(roomState, rtmpId);
}
return null;
}
/**
* @typedef {Object} streamSources
* @property {Object} audio - The list of audio input (microphone) and output (speakers) sources.
* @property {Array.<Object>} audio.input - The list of audio input (microphone) sources.
* @property {String} audio.input.deviceId The audio input source item device id.
* @property {String} audio.input.label The audio input source item device label name.
* @property {String} [audio.input.groupId] The audio input source item device physical device id.
* Note that there can be different <code>deviceId</code> due to differing sources but can share a
* <code>groupId</code> because it's the same device.
* @property {Array.<Object>} audio.output - The list of audio output (speakers) sources.
* Object signature matches <code>audio.input</code> format.
* @property {Object} video - The list of video input (camera) sources.
* @property {Array.<Object>} video.input - The list of video input (camera) sources.
* Object signature matches <code>audio.input</code> format.
*/
/**
* @description Method that returns the camera and microphone sources.
* @return {Promise.<streamSources>} outputSources
* @alias Skylink#getStreamSources
* @example
* Example 1: Get media sources before joinRoom - only available on Chrome browsers
*
* const audioInputDevices = [];
* const videoInputDevices = [];
*
* skylink.getStreamSources.then((sources) => {
* audioInputDevices = sources.audio.input;
* videoInputDevices = sources.video.input;
* }).catch((error) => // handle error);
*
* skylink.getUserMedia(roomName, {
* audio: {
* deviceId: audioInputDevices[0].deviceId,
* },
* video: {
* deviceId: videoInputDevices[0].deviceId,
* }
* }).then((streams) => // do something)
* .catch((error) => // handle error);
*/
getStreamSources() {
return MediaStream.getStreamSources();
}
/**
* @description Method that sends a new <code>userMedia</code> stream to all connected peers in a room.
* @param {String} roomName - The room name.
* @param {JSON|MediaStream|Array.<MediaStream>} options - The {@link Skylink#getUserMedia|getUserMedia} <code>options</code> parameter
* settings. The MediaStream to send to the remote peer or array of MediaStreams.
* - When provided as a <code>MediaStream</code> object, this configures the <code>options.audio</code> and
* <code>options.video</code> based on the tracks available in the <code>MediaStream</code> object.
* Object signature matches the <code>options</code> parameter in the
* <code>{@link Skylink#getUserMedia|getUserMedia}</code> method</a>.
* <blockquote class="info">
* Note that the <code>MediaStream</code> object should be obtained by using the {@link Skylink#getUserMedia|getUserMedia} method and NOT
* <code>navigator.mediaDevices.getUserMedia</code>. Using the latter may result in unintended side effects such as the {@link SkylinkEvents.event:ON_INCOMING_STREAM|ON INCOMING STREAM}
* event not triggering as expected.
* </blockquote>
* - If options are passed as argument into the method, it resolves with an array of <code>MediaStreams</code>. First item in array is
* <code>MediaStream</code> of kind audio and second item is <code>MediaStream</code> of kind video. Otherwise it resolves with the array or
* <code>MediaStream</code>.
* @return {Promise.<MediaStreams>}
* @example
* Example 1: Send new MediaStream with audio and video
*
* let sendStream = (roomName) => {
* const options = { audio: true, video: true };
*
* // Add listener to incomingStream event
* SkylinkEventManager.addEventListener(SkylinkConstants.EVENTS.ON_INCOMING_STREAM, (evt) => {
* const { detail } = evt;
* window.attachMediaStream(localVideoEl, detail.stream);
* })
*
* skylink.sendStream(roomName, options)
* // streams can also be obtained from resolved promise
* .then((streams) => {
* if (streams[0]) {
* window.attachMediaStream(audioEl, streams[0]); // first item in array is an audio stream
* }
* if (streams[1]) {
* window.attachMediaStream(videoEl, streams[1]); // second item in array is a video stream
* }
* })
* .catch((error) => { console.error(error) });
* }
*
* Example 2: Use pre-fetched media streams
*
* const prefetchedStreams = null;
* skylink.getUserMedia(null, {
* audio: { stereo: true },
* video: true,
* })
* .then((streams) => {
* prefetchedStream = streams
* });
*
* skylink.sendStream(roomName, prefetchedStreams)
* .catch((error) => { console.error(error) });
* }
*
* @fires {@link SkylinkEvents.event:MEDIA_ACCESS_SUCCESS|MEDIA ACCESS SUCCESS} event with parameter payload <code>isScreensharing=false</code> and
* <code>isAudioFallback=false</code> if <code>userMedia</code> <code>options</code> is passed into
* <code>sendStream</code> method.
* @fires {@link SkylinkEvents.event:ON_INCOMING_STREAM|ON INCOMING STREAM} event with parameter payload <code>isSelf=true</code> and
* <code>stream</code> as <code>userMedia</code> stream.
* @fires {@link SkylinkEvents.event:PEER_UPDATED|PEER UPDATED} event with parameter payload <code>isSelf=true</code>.
* @alias Skylink#sendStream
* @since 0.5.6
*/
sendStream(roomName, options) {
const roomState = getRoomStateByName(roomName);
return MediaStream.sendStream(roomState, options);
}
/**
* @typedef {Object.<String, Object>} streamsList
* @property {Object.<String, Object>} #peerId - Peer streams info keyed by peer id.
* @property {Boolean} #peerId.isSelf - The flag if the peer is local or remote.
* @property {Object} #peerId.streams - The peer streams.
* @property {Object} #peerId.streams.audio - The peer audio streams keyed by streamId.
* @property {MediaStream} #peerId.streams.audio#streamId - streams keyed by stream id.
* @property {Object} #peerId.streams.video - The peer video streams keyed by streamId.
* @property {MediaStream} #peerId.streams.video#streamId - streams keyed by stream id.
* @property {Object} #peerId.streams.screenShare - The peer screen share streams keyed by streamId.
* @property {MediaStream} #peerId.streams.screenShare#streamId - streams keyed by stream id.
*/
/**
* @description Method that returns the list of connected peers streams in the room both user media streams and screen share streams.
* @param {String} roomName - The room name.
* @param {Boolean} [includeSelf=true] - The flag if self streams are included.
* @return {JSON.<String, streamsList>} - The list of peer stream objects keyed by peer id.
* @example
* Example 1: Get the list of current peers streams in the same room
*
* const streams = skylink.getStreams("Room_1");
* @alias Skylink#getStreams
* @since 0.6.16
*/
getStreams(roomName, includeSelf = true) {
const roomState = getRoomStateByName(roomName);
if (roomState) {
return MediaStream.getStreams(roomState, includeSelf);
}
return null;
}
/**
* @description Method that generates an <a href="https://en.wikipedia.org/wiki/Universally_unique_identifier">UUID</a> (Unique ID).
* @return {String} Returns a generated UUID (Unique ID).
* @alias Skylink#generateUUID
* @since 0.5.9
*/
generateUUID() {
return generateUUID();
}
/**
* @description Method that stores a secret and secret id pair used for encrypting and decrypting messages.
* @param {String} roomName - The room name.
* @param {String} secret - A secret to use for encrypting and decrypting messages.
* @param {String} secretId - The id of the secret.
* @alias Skylink#setEncryptSecret
* @since 2.0.0
*/
setEncryptSecret(roomName = '', secret = '', secretId = '') {
const roomState = getRoomStateByName(roomName);
const encryption = new EncryptedMessaging(roomState);
return encryption.setEncryptSecret(secret, secretId);
}
/**
* @description Method that returns all the secret and secret id pairs.
* @param {String} roomName - The room name.
* @returns {Object|{}}
* @alias Skylink#getEncryptSecrets
* @since 2.0.0
*/
getEncryptSecrets(roomName = '') {
const roomState = getRoomStateByName(roomName);
const encryption = new EncryptedMessaging(roomState);
return encryption.getEncryptSecrets();
}
/**
* @description Method that deletes an encrypt secret.
* @param {String} roomName - The room name.
* @param {String} [secretId] - The id of the secret to be deleted. If no secret id is provided, all secrets will be deleted.
* @alias Skylink#deleteEncryptSecrets
* @since 2.0.0
*/
deleteEncryptSecrets(roomName = '', secretId = '') {
const roomState = getRoomStateByName(roomName);
const encryption = new EncryptedMessaging(roomState);
return encryption.deleteEncryptSecrets(secretId);
}
/**
* @description Method that sets the secret to be used in encrypting and decrypting messages.
* @param {String} roomName - The room name.
* @param {String} secretId - The id of the secret to be used for encrypting and decrypting messages.
* @alias Skylink#setSelectedSecret
* @since 2.0.0
*/
setSelectedSecret(roomName = '', secretId = '') {
const roomState = getRoomStateByName(roomName);
const encryption = new EncryptedMessaging(roomState);
encryption.setSelectedSecretId(secretId);
}
/**
* @description Method that returns the secret used in encrypting and decrypting messages.
* @param {String} roomName - The room name.
* @param {String} secretId - The id of the secret.
* @returns {String} secret - The secret used for encrypting and decrypting messages.
* @alias Skylink#getSelectedSecret
* @since 2.0.0
*/
getSelectedSecret(roomName, secretId) {
const roomState = getRoomStateByName(roomName);
const encryption = new EncryptedMessaging(roomState);
return encryption.getSelectedSecretId(secretId);
}
/**
* @description Method that overrides the persistent message feature configured at the key level.
* <blockquote class="info">
* Note that to set message persistence at the app level, the persistent message feature MUST be enabled at the key level in the Temasys
* Developers Console. Messages will also only be persisted if the messages are encrypted, are public messages and, are sent via the signaling
* server using the {@link Skylink#sendMessage|sendMessage} method.
* </blockquote>
* @param {String} roomName - The room name.
* @param {Boolean} isPersistent - The flag if messages should be persisted.
* @alias Skylink#setMessagePersistence
* @since 2.0.0
*/
setMessagePersistence(roomName, isPersistent) {
const roomState = getRoomStateByName(roomName);
const asyncMessaging = new AsyncMessaging(roomState);
return asyncMessaging.setMessagePersistence(isPersistent);
}
/**
* @description Method that retrieves the persistent message feature configured.
* @param {String} roomName - The room name.
* @returns {Boolean} isPersistent
* @alias Skylink#getMessagePersistence
* @since 2.0.0
*/
getMessagePersistence(roomName) {
const roomState = getRoomStateByName(roomName);
const asyncMessaging = new AsyncMessaging(roomState);
return asyncMessaging.getMessagePersistence();
}
/**
* @description Method that retrieves the sdk version.
* @alias Skylink#getSdkVersion
* @since 2.1.6
*/
getSdkVersion() {
return SDK_VERSION;
}
/**
* @typedef {Object.<String, Object>} dataTransferResult
* @property {Object} #peerId - Data transfer success or error result keyed by peer id.
* @property {transferInfo} [#peerId.success] - The success return object. Will not be present in the return object if the transfer fails.
* @property {Error|String} [#peerId.error] - The error return object. Will not be present in the return object if the transfer succeeds.
* @property {String} #peerId.transferType - The transfer type.
*/
/**
* @description Method that sends a Blob to all connected peers in the room.
* @param {String} roomName - The room name
* @param {Blob} data - The Blob object
* @param {String|Array} [peerId] - The peer ID or array of peer IDs. When not provided, it will start uploading data transfers with all peers in
* the room
* @param {Number} [timeout = 60] - The duration for which to wait for a response from the remote peer before terminating the transfer
* @return {Promise<dataTransferResult>} - Always resolves with success or error object.
* @example
* Example 1: Send a file
*
* // Add listener to incomingStream event
* SkylinkEventManager.addEventListener(SkylinkConstants.EVENTS.DATA_TRANSFER_STATE, (evt) => {
* const { state } = evt.detail;
*
* switch (state) {
* case SkylinkConstants.DATA_TRANSFER_STATE.UPLOAD_REQUEST:
* // Alert peer that a file transfer is requested
* // Record user response and call <code>respondBlobRequest</code>
* skylink.respondBlobRequest(config.defaultRoom, peerId, transferId, result)
* .then((result) => // handle success or error)
* .catch((err) => // handle error)
* break;
* case SkylinkConstants.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED:
* // Surface download link to user
* break;
* }
* })
*
* skylink.sendBlobData(roomName, data)
* .then((result) => {
* // always resolves with success or error object
* })
* .catch((error) => // handle error);
* }
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>USER_UPLOAD_REQUEST</code> on the local peer.
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>UPLOAD_REQUEST</code> on the remote peer.
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>UPLOAD_STARTED</code> when remote peer accepts data transfer.
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>REJECTED</code> when remote peer rejects data transfer.
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>UPLOADING</code> when data is in the process of being transferred.
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>UPLOAD_COMPLETED</code> when data transfer has completed.
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>ERROR</code> when data transfer timeout limit is reached.
* @alias Skylink#sendBlobData
* @since 2.0.0
*/
sendBlobData(roomName, data, peerId, timeout) {
const roomState = getRoomStateByName(roomName);
return DataTransfer.sendBlobData(roomState, data, peerId, timeout);
}
/**
* @description Method that responds to a <code>sendBlobData</code> request.
* @param {String} roomName - The room name.
* @param {String} peerId - The Peer Id.
* @param {String }transferId - The transfer Id.
* @param {Boolean} accept - The flag if the data transfer is accepted by the user.
* @return {Promise<dataTransferResult>} - Always resolves with success or error object.
*
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>DOWNLOAD_STARTED</code> when user accepts the data transfer request.
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>USER_REJECTED</code> when user rejects the data transfer request.
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>DOWNLOADING</code> when data is in the process of being transferred.
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>DOWNLOAD_COMPLETED</code> when data transfer has completed.
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>ERROR</code> when data transfer timeout limit is reached.
* @alias Skylink#respondBlobRequest
* @since 2.0.0
*/
respondBlobRequest(roomName, peerId, transferId, accept) {
const roomState = getRoomStateByName(roomName);
return DataTransfer.acceptDataTransfer(roomState, peerId, transferId, accept);
}
/**
* @description Method that cancels a data transfer
* @param {String} roomName - The room name.
* @param {String} peerId - The Peer Id.
* @param {String} transferId - The Transfer Id to cancel.
* @return {Promise<{peerId, transferId}|Error>}
*
* @fires {@link SkylinkEvents.event:DATA_TRANSFER_STATE|DATA TRANSFER STATE} event with <code>state</code> value as <code>CANCEL</code>.
* @alias Skylink#cancelBlobTransfer
* @since 2.0.0
*/
cancelBlobTransfer(roomName, peerId, transferId) {
const roomState = getRoomStateByName(roomName);
return DataTransfer.cancelBlobTransfer(roomState, peerId, transferId);
}
}
export default SkylinkPublicInterface;