- /**
- * <blockquote class="info">
- * Learn more about how ICE works in this
- * <a href="https://temasys.com.sg/ice-what-is-this-sorcery/">article here</a>.
- * </blockquote>
- * The list of Peer connection ICE connection states.
- * @attribute ICE_CONNECTION_STATE
- * @param {String} CHECKING <small>Value <code>"checking"</code></small>
- * The value of the state when Peer connection is checking for a suitable matching pair of
- * ICE candidates to establish ICE connection.
- * <small>Exchanging of ICE candidates happens during <a href="#event_candidateGenerationState">
- * <code>candidateGenerationState</code> event</a>.</small>
- * @param {String} CONNECTED <small>Value <code>"connected"</code></small>
- * The value of the state when Peer connection has found a suitable matching pair of
- * ICE candidates to establish ICE connection but is still checking for a better
- * suitable matching pair of ICE candidates for the best ICE connectivity.
- * <small>At this state, ICE connection is already established and audio, video and
- * data streaming has already started.</small>
- * @param {String} COMPLETED <small>Value <code>"completed"</code></small>
- * The value of the state when Peer connection has found the best suitable matching pair
- * of ICE candidates to establish ICE connection and checking has stopped.
- * <small>At this state, ICE connection is already established and audio, video and
- * data streaming has already started. This may happpen after <code>CONNECTED</code>.</small>
- * @param {String} FAILED <small>Value <code>"failed"</code></small>
- * The value of the state when Peer connection ICE connection has failed.
- * @param {String} DISCONNECTED <small>Value <code>"disconnected"</code></small>
- * The value of the state when Peer connection ICE connection is disconnected.
- * <small>At this state, the Peer connection may attempt to revive the ICE connection.
- * This may happen due to flaky network conditions.</small>
- * @param {String} CLOSED <small>Value <code>"closed"</code></small>
- * The value of the state when Peer connection ICE connection has closed.
- * <small>This happens when Peer connection is closed and no streaming can occur at this stage.</small>
- * @param {String} TRICKLE_FAILED <small>Value <code>"trickeFailed"</code></small>
- * The value of the state when Peer connection ICE connection has failed during trickle ICE.
- * <small>Trickle ICE is enabled in <a href="#method_init"><code>init()</code> method</a>
- * <code>enableIceTrickle</code> option.</small>
- * @type JSON
- * @readOnly
- * @for Skylink
- * @since 0.1.0
- */
- Skylink.prototype.ICE_CONNECTION_STATE = {
- STARTING: 'starting',
- CHECKING: 'checking',
- CONNECTED: 'connected',
- COMPLETED: 'completed',
- CLOSED: 'closed',
- FAILED: 'failed',
- TRICKLE_FAILED: 'trickleFailed',
- DISCONNECTED: 'disconnected'
- };
-
- /**
- * <blockquote class="info">
- * Note that configuring the protocol may not necessarily result in the desired network transports protocol
- * used in the actual TURN network traffic as it depends which protocol the browser selects and connects with.
- * This simply configures the TURN ICE server urls <code?transport=(protocol)</code> query option when constructing
- * the Peer connection. When all protocols are selected, the ICE servers urls are duplicated with all protocols.
- * </blockquote>
- * The list of TURN network transport protocols options when constructing Peer connections
- * configured in the <a href="#method_init"><code>init()</code> method</a>.
- * <small>Example <code>.urls</code> inital input: [<code>"turn:server.com?transport=tcp"</code>,
- * <code>"turn:server1.com:3478"</code>, <code>"turn:server.com?transport=udp"</code>]</small>
- * @attribute TURN_TRANSPORT
- * @param {String} TCP <small>Value <code>"tcp"</code></small>
- * The value of the option to configure using only TCP network transport protocol.
- * <small>Example <code>.urls</code> output: [<code>"turn:server.com?transport=tcp"</code>,
- * <code>"turn:server1.com:3478?transport=tcp"</code>]</small>
- * @param {String} UDP <small>Value <code>"udp"</code></small>
- * The value of the option to configure using only UDP network transport protocol.
- * <small>Example <code>.urls</code> output: [<code>"turn:server.com?transport=udp"</code>,
- * <code>"turn:server1.com:3478?transport=udp"</code>]</small>
- * @param {String} ANY <small>Value <code>"any"</code></small>
- * The value of the option to configure using any network transport protocols configured from the Signaling server.
- * <small>Example <code>.urls</code> output: [<code>"turn:server.com?transport=tcp"</code>,
- * <code>"turn:server1.com:3478"</code>, <code>"turn:server.com?transport=udp"</code>]</small>
- * @param {String} NONE <small>Value <code>"none"</code></small>
- * The value of the option to not configure using any network transport protocols.
- * <small>Example <code>.urls</code> output: [<code>"turn:server.com"</code>, <code>"turn:server1.com:3478"</code>]</small>
- * <small>Configuring this does not mean that no protocols will be used, but
- * rather removing <code>?transport=(protocol)</code> query option in
- * the TURN ICE server <code>.urls</code> when constructing the Peer connection.</small>
- * @param {String} ALL <small>Value <code>"all"</code></small>
- * The value of the option to configure using both TCP and UDP network transport protocols.
- * <small>Example <code>.urls</code> output: [<code>"turn:server.com?transport=tcp"</code>,
- * <code>"turn:server.com?transport=udp"</code>, <code>"turn:server1.com:3478?transport=tcp"</code>,
- * <code>"turn:server1.com:3478?transport=udp"</code>]</small>
- * @type JSON
- * @readOnly
- * @for Skylink
- * @since 0.5.4
- */
- Skylink.prototype.TURN_TRANSPORT = {
- UDP: 'udp',
- TCP: 'tcp',
- ANY: 'any',
- NONE: 'none',
- ALL: 'all'
- };
-
- /**
- * Function that filters and configures the ICE servers received from Signaling
- * based on the <code>init()</code> configuration and returns the updated
- * list of ICE servers to be used when constructing Peer connection.
- * @method _setIceServers
- * @private
- * @for Skylink
- * @since 0.5.4
- */
- Skylink.prototype._setIceServers = function(givenConfig) {
- var self = this;
- var givenIceServers = clone(givenConfig.iceServers);
- var iceServersList = {};
- var newIceServers = [];
- // TURN SSL config
- var useTURNSSLProtocol = false;
- var useTURNSSLPort = false;
-
-
-
- if (self._forceTURNSSL) {
- if (window.webrtcDetectedBrowser === 'chrome' ||
- window.webrtcDetectedBrowser === 'safari' ||
- window.webrtcDetectedBrowser === 'IE') {
- useTURNSSLProtocol = true;
- } else {
- useTURNSSLPort = true;
- }
- }
-
- log.log('TURN server connections SSL configuration', {
- useTURNSSLProtocol: useTURNSSLProtocol,
- useTURNSSLPort: useTURNSSLPort
- });
-
- var pushIceServer = function (username, credential, url, index) {
- if (!iceServersList[username]) {
- iceServersList[username] = {};
- }
-
- if (!iceServersList[username][credential]) {
- iceServersList[username][credential] = [];
- }
-
- if (iceServersList[username][credential].indexOf(url) === -1) {
- if (typeof index === 'number') {
- iceServersList[username][credential].splice(index, 0, url);
- } else {
- iceServersList[username][credential].push(url);
- }
- }
- };
-
- var i, serverItem;
-
- for (i = 0; i < givenIceServers.length; i++) {
- var server = givenIceServers[i];
-
- if (typeof server.url !== 'string') {
- log.warn('Ignoring ICE server provided at index ' + i, clone(server));
- continue;
- }
-
- if (server.url.indexOf('stun') === 0) {
- if (!self._enableSTUN) {
- log.warn('Ignoring STUN server provided at index ' + i, clone(server));
- continue;
- }
-
- if (!self._usePublicSTUN && server.url.indexOf('temasys') === -1) {
- log.warn('Ignoring public STUN server provided at index ' + i, clone(server));
- continue;
- }
-
- } else if (server.url.indexOf('turn') === 0) {
- if (!self._enableTURN) {
- log.warn('Ignoring TURN server provided at index ' + i, clone(server));
- continue;
- }
-
- if (server.url.indexOf(':443') === -1 && useTURNSSLPort) {
- log.log('Ignoring TURN Server (non-SSL port) provided at index ' + i, clone(server));
- continue;
- }
-
- if (useTURNSSLProtocol) {
- var parts = server.url.split(':');
- parts[0] = 'turns';
- server.url = parts.join(':');
- }
- }
-
- // parse "@" settings
- if (server.url.indexOf('@') > 0) {
- var protocolParts = server.url.split(':');
- var urlParts = protocolParts[1].split('@');
- server.username = urlParts[0];
- server.url = protocolParts[0] + ':' + urlParts[1];
-
- // add the ICE server port
- // Edge uses 3478 with ?transport=udp for now
- if (window.webrtcDetectedBrowser === 'edge') {
- server.url += ':3478';
- } else if (protocolParts[2]) {
- server.url += ':' + protocolParts[2];
- }
- }
-
- var username = typeof server.username === 'string' ? server.username : 'none';
- var credential = typeof server.credential === 'string' ? server.credential : 'none';
-
- if (server.url.indexOf('turn') === 0) {
- if (self._TURNTransport === self.TURN_TRANSPORT.ANY) {
- pushIceServer(username, credential, server.url);
-
- } else {
- var rawUrl = server.url;
-
- if (rawUrl.indexOf('?transport=') > 0) {
- rawUrl = rawUrl.split('?transport=')[0];
- }
-
- if (self._TURNTransport === self.TURN_TRANSPORT.NONE) {
- pushIceServer(username, credential, rawUrl);
- } else if (self._TURNTransport === self.TURN_TRANSPORT.UDP) {
- pushIceServer(username, credential, rawUrl + '?transport=udp');
- } else if (self._TURNTransport === self.TURN_TRANSPORT.TCP) {
- pushIceServer(username, credential, rawUrl + '?transport=tcp');
- } else if (self._TURNTransport === self.TURN_TRANSPORT.ALL) {
- pushIceServer(username, credential, rawUrl + '?transport=tcp');
- pushIceServer(username, credential, rawUrl + '?transport=udp');
- } else {
- log.warn('Invalid TURN transport option "' + self._TURNTransport +
- '". Ignoring TURN server at index' + i, clone(server));
- continue;
- }
- }
- } else {
- pushIceServer(username, credential, server.url);
- }
- }
-
- // add mozilla STUN for firefox
- if (self._enableSTUN && self._usePublicSTUN && window.webrtcDetectedBrowser === 'firefox') {
- pushIceServer('none', 'none', 'stun:stun.services.mozilla.com', 0);
- }
-
- var hasUrlsSupport = false;
-
- if (window.webrtcDetectedBrowser === 'chrome' && window.webrtcDetectedVersion > 34) {
- hasUrlsSupport = true;
- }
-
- if (window.webrtcDetectedBrowser === 'firefox' && window.webrtcDetectedVersion > 38) {
- hasUrlsSupport = true;
- }
-
- if (window.webrtcDetectedBrowser === 'opera' && window.webrtcDetectedVersion > 31) {
- hasUrlsSupport = true;
- }
-
- // plugin supports .urls
- if (window.webrtcDetectedBrowser === 'safari' || window.webrtcDetectedBrowser === 'IE') {
- hasUrlsSupport = true;
- }
-
- // bowser / edge
- if (['bowser', 'edge'].indexOf(window.webrtcDetectedBrowser) > -1) {
- hasUrlsSupport = true;
- }
-
- for (var serverUsername in iceServersList) {
- if (iceServersList.hasOwnProperty(serverUsername)) {
- for (var serverCred in iceServersList[serverUsername]) {
- if (iceServersList[serverUsername].hasOwnProperty(serverCred)) {
- if (hasUrlsSupport) {
- var urlsItem = {
- urls: iceServersList[serverUsername][serverCred]
- };
- if (serverUsername !== 'none') {
- urlsItem.username = serverUsername;
- }
- if (serverCred !== 'none') {
- urlsItem.credential = serverCred;
- }
-
- // Edge uses 1 url only for now
- if (window.webrtcDetectedBrowser === 'edge') {
- if (urlsItem.username && urlsItem.credential) {
- urlsItem.urls = [urlsItem.urls[0]];
- newIceServers.push(urlsItem);
- break;
- }
- } else {
- newIceServers.push(urlsItem);
- }
- } else {
- for (var j = 0; j < iceServersList[serverUsername][serverCred].length; j++) {
- var urlItem = {
- url: iceServersList[serverUsername][serverCred][j]
- };
- if (serverUsername !== 'none') {
- urlItem.username = serverUsername;
- }
- if (serverCred !== 'none') {
- urlItem.credential = serverCred;
- }
- newIceServers.push(urlItem);
- }
- }
- }
- }
- }
- }
-
- if (self._iceServer) {
- var nUsername = null, nCredential = null;
- for (i = 0; i < newIceServers.length; i++) {
- if (newIceServers[i].username) {
- nUsername = newIceServers[i].username;
- }
- if (newIceServers[i].credential) {
- nCredential = newIceServers[i].credential;
- }
- }
- newIceServers = [{
- urls: self._iceServer.urls,
- username: nUsername,
- credential: nCredential
- }];
- }
-
- log.log('Output iceServers configuration:', newIceServers);
-
- return {
- iceServers: newIceServers
- };
- };
-