- /**
- * Stores the preferred sending Peer connection streaming audio codec.
- * @attribute _selectedAudioCodec
- * @type String
- * @default "auto"
- * @private
- * @for Skylink
- * @since 0.5.10
- */
- Skylink.prototype._selectedAudioCodec = 'auto';
-
- /**
- * Stores the preferred sending Peer connection streaming video codec.
- * @attribute _selectedVideoCodec
- * @type String
- * @default "auto"
- * @private
- * @for Skylink
- * @since 0.5.10
- */
- Skylink.prototype._selectedVideoCodec = 'auto';
-
- /**
- * Function that modifies the SessionDescription string to enable OPUS stereo.
- * @method _addSDPStereo
- * @private
- * @for Skylink
- * @since 0.5.10
- */
- Skylink.prototype._addSDPStereo = function(sdpLines) {
- var opusRtmpLineIndex = 0;
- var opusLineFound = false;
- var opusPayload = 0;
- var fmtpLineFound = false;
-
- var i, j;
- var line;
-
- for (i = 0; i < sdpLines.length; i += 1) {
- line = sdpLines[i];
-
- if (line.indexOf('a=rtpmap:') === 0) {
- var parts = line.split(' ');
-
- if (parts[1].indexOf('opus/48000/') === 0) {
- opusLineFound = true;
- opusPayload = parts[0].split(':')[1];
- opusRtmpLineIndex = i;
- break;
- }
- }
- }
-
- // if found
- if (opusLineFound) {
- log.debug([null, 'SDP', null, 'OPUS line is found. Enabling stereo']);
-
- // loop for fmtp payload
- for (j = 0; j < sdpLines.length; j += 1) {
- line = sdpLines[j];
-
- if (line.indexOf('a=fmtp:' + opusPayload) === 0) {
- fmtpLineFound = true;
- sdpLines[j] += '; stereo=1';
- break;
- }
- }
-
- // if line doesn't exists for an instance firefox
- if (!fmtpLineFound) {
- sdpLines.splice(opusRtmpLineIndex, 0, 'a=fmtp:' + opusPayload + ' stereo=1');
- }
- }
-
- return sdpLines;
- };
-
- /**
- * Function that modifies the SessionDescription string to set the video resolution.
- * This is not even supported in the specs, and we should re-evalute it to be removed.
- * @method _setSDPVideoResolution
- * @private
- * @for Skylink
- * @since 0.5.10
- */
- Skylink.prototype._setSDPVideoResolution = function(sdpLines){
- var video = this._streams.userMedia && this._streams.userMedia.settings.video;
- var frameRate = video.frameRate || 50;
- var resolution = {
- width: 320,
- height: 50
- }; //video.resolution || {};
-
- var videoLineFound = false;
- var videoLineIndex = 0;
- var fmtpPayloads = [];
-
- var i, j, k;
- var line;
-
- var sdpLineData = 'max-fr=' + frameRate +
- '; max-recv-width=320' + //(resolution.width ? resolution.width : 640) +
- '; max-recv-height=160'; //+ (resolution.height ? resolution.height : 480);
-
- for (i = 0; i < sdpLines.length; i += 1) {
- line = sdpLines[i];
-
- if (line.indexOf('a=video') === 0 || line.indexOf('m=video') === 0) {
- videoLineFound = true;
- videoLineIndex = i;
- fmtpPayloads = line.split(' ');
- fmtpPayloads.splice(0, 3);
- break;
- }
- }
-
- if (videoLineFound) {
- // loop for every video codec
- // ignore if not vp8 or h264
- for (j = 0; j < fmtpPayloads.length; j += 1) {
- var payload = fmtpPayloads[j];
- var rtpmapLineIndex = 0;
- var fmtpLineIndex = 0;
- var fmtpLineFound = false;
- var ignore = false;
-
- for (k = 0; k < sdpLines.length; k += 1) {
- line = sdpLines[k];
-
- if (line.indexOf('a=rtpmap:' + payload) === 0) {
- // for non h264 or vp8 codec, ignore. these are experimental codecs
- // that may not exists afterwards
- if (!(line.indexOf('VP8') > 0 || line.indexOf('H264') > 0)) {
- ignore = true;
- break;
- }
- rtpmapLineIndex = k;
- }
-
- if (line.indexOf('a=fmtp:' + payload) === 0) {
- fmtpLineFound = true;
- fmtpLineIndex = k;
- }
- }
-
- if (ignore) {
- continue;
- }
-
- if (fmtpLineFound) {
- sdpLines[fmtpLineIndex] += ';' + sdpLineData;
-
- } else {
- sdpLines.splice(rtpmapLineIndex + 1, 0, 'a=fmtp:' + payload + ' ' + sdpLineData);
- }
- }
-
- log.debug([null, 'SDP', null, 'Setting video resolution (broken)']);
- }
- return sdpLines;
- };
-
- /**
- * Function that modifies the SessionDescription string to set the sending bandwidth.
- * Setting this may not necessarily work in Firefox.
- * @method _setSDPBitrate
- * @private
- * @for Skylink
- * @since 0.5.10
- */
- Skylink.prototype._setSDPBitrate = function(sdpLines, settings) {
- // Find if user has audioStream
- var bandwidth = this._streamsBandwidthSettings;
-
- // Prevent setting of bandwidth audio if not configured
- if (typeof bandwidth.audio === 'number' && bandwidth.audio > 0) {
- var hasSetAudio = false;
-
- for (var i = 0; i < sdpLines.length; i += 1) {
- // set the audio bandwidth
- if (sdpLines[i].indexOf('m=audio') === 0) {
- //if (sdpLines[i].indexOf('a=audio') === 0 || sdpLines[i].indexOf('m=audio') === 0) {
- sdpLines.splice(i + 1, 0, window.webrtcDetectedBrowser === 'firefox' ?
- 'b=TIAS:' + (bandwidth.audio * 1024) : 'b=AS:' + bandwidth.audio);
-
- log.info([null, 'SDP', null, 'Setting maximum sending audio bandwidth bitrate @(index:' + i + ') -> '], bandwidth.audio);
- hasSetAudio = true;
- break;
- }
- }
-
- if (!hasSetAudio) {
- log.warn([null, 'SDP', null, 'Not setting maximum sending audio bandwidth bitrate as m=audio line is not found']);
- }
- } else {
- log.warn([null, 'SDP', null, 'Not setting maximum sending audio bandwidth bitrate and leaving to browser\'s defaults']);
- }
-
- // Prevent setting of bandwidth video if not configured
- if (typeof bandwidth.video === 'number' && bandwidth.video > 0) {
- var hasSetVideo = false;
-
- for (var j = 0; j < sdpLines.length; j += 1) {
- // set the video bandwidth
- if (sdpLines[j].indexOf('m=video') === 0) {
- //if (sdpLines[j].indexOf('a=video') === 0 || sdpLines[j].indexOf('m=video') === 0) {
- sdpLines.splice(j + 1, 0, window.webrtcDetectedBrowser === 'firefox' ?
- 'b=TIAS:' + (bandwidth.video * 1024) : 'b=AS:' + bandwidth.video);
-
- log.info([null, 'SDP', null, 'Setting maximum sending video bandwidth bitrate @(index:' + j + ') -> '], bandwidth.video);
- hasSetVideo = true;
- break;
- }
- }
-
- if (!hasSetVideo) {
- log.warn([null, 'SDP', null, 'Not setting maximum sending video bandwidth bitrate as m=video line is not found']);
- }
- } else {
- log.warn([null, 'SDP', null, 'Not setting maximum sending video bandwidth bitrate and leaving to browser\'s defaults']);
- }
-
- // Prevent setting of bandwidth data if not configured
- if (typeof bandwidth.data === 'number' && bandwidth.data > 0) {
- var hasSetData = false;
-
- for (var k = 0; k < sdpLines.length; k += 1) {
- // set the data bandwidth
- if (sdpLines[k].indexOf('m=application') === 0) {
- //if (sdpLines[k].indexOf('a=application') === 0 || sdpLines[k].indexOf('m=application') === 0) {
- sdpLines.splice(k + 1, 0, window.webrtcDetectedBrowser === 'firefox' ?
- 'b=TIAS:' + (bandwidth.data * 1024) : 'b=AS:' + bandwidth.data);
-
- log.info([null, 'SDP', null, 'Setting maximum sending data bandwidth bitrate @(index:' + k + ') -> '], bandwidth.data);
- hasSetData = true;
- break;
- }
- }
-
- if (!hasSetData) {
- log.warn([null, 'SDP', null, 'Not setting maximum sending data bandwidth bitrate as m=application line is not found']);
- }
- } else {
- log.warn([null, 'SDP', null, 'Not setting maximum sending data bandwidth bitrate and leaving to browser\'s defaults']);
- }
-
- return sdpLines;
- };
-
- /**
- * Function that modifies the SessionDescription string to set the preferred sending video codec.
- * @method _setSDPVideoCodec
- * @private
- * @for Skylink
- * @since 0.5.2
- */
- Skylink.prototype._setSDPVideoCodec = function(sdpLines) {
- log.log('Setting video codec', this._selectedVideoCodec);
- var codecFound = false;
- var payload = 0;
-
- var i, j;
- var line;
-
- for (i = 0; i < sdpLines.length; i += 1) {
- line = sdpLines[i];
-
- if (line.indexOf('a=rtpmap:') === 0) {
- if (line.indexOf(this._selectedVideoCodec) > 0) {
- codecFound = true;
- payload = line.split(':')[1].split(' ')[0];
- break;
- }
- }
- }
-
- if (codecFound) {
- for (j = 0; j < sdpLines.length; j += 1) {
- line = sdpLines[j];
-
- if (line.indexOf('m=video') === 0 || line.indexOf('a=video') === 0) {
- var parts = line.split(' ');
- var payloads = line.split(' ');
- payloads.splice(0, 3);
-
- var selectedPayloadIndex = payloads.indexOf(payload);
-
- if (selectedPayloadIndex === -1) {
- payloads.splice(0, 0, payload);
- } else {
- var first = payloads[0];
- payloads[0] = payload;
- payloads[selectedPayloadIndex] = first;
- }
- sdpLines[j] = parts[0] + ' ' + parts[1] + ' ' + parts[2] + ' ' + payloads.join(' ');
- break;
- }
- }
- }
- return sdpLines;
- };
-
- /**
- * Function that modifies the SessionDescription string to set the preferred sending audio codec.
- * @method _setSDPAudioCodec
- * @private
- * @for Skylink
- * @since 0.5.2
- */
- Skylink.prototype._setSDPAudioCodec = function(sdpLines) {
- log.log('Setting audio codec', this._selectedAudioCodec);
- var codecFound = false;
- var payload = 0;
-
- var i, j;
- var line;
-
- for (i = 0; i < sdpLines.length; i += 1) {
- line = sdpLines[i];
-
- if (line.indexOf('a=rtpmap:') === 0) {
- if (line.indexOf(this._selectedAudioCodec) > 0) {
- codecFound = true;
- payload = line.split(':')[1].split(' ')[0];
- }
- }
- }
-
- if (codecFound) {
- for (j = 0; j < sdpLines.length; j += 1) {
- line = sdpLines[j];
-
- if (line.indexOf('m=audio') === 0 || line.indexOf('a=audio') === 0) {
- var parts = line.split(' ');
- var payloads = line.split(' ');
- payloads.splice(0, 3);
-
- var selectedPayloadIndex = payloads.indexOf(payload);
-
- if (selectedPayloadIndex === -1) {
- payloads.splice(0, 0, payload);
- } else {
- var first = payloads[0];
- payloads[0] = payload;
- payloads[selectedPayloadIndex] = first;
- }
- sdpLines[j] = parts[0] + ' ' + parts[1] + ' ' + parts[2] + ' ' + payloads.join(' ');
- break;
- }
- }
- }
- return sdpLines;
- };
-
- /**
- * Function that modifies the SessionDescription string to remove the experimental H264 Firefox flag
- * that is breaking connections.
- * To evaluate removal of this change once we roll out H264 codec interop.
- * @method _removeSDPFirefoxH264Pref
- * @private
- * @for Skylink
- * @since 0.5.2
- */
- Skylink.prototype._removeSDPFirefoxH264Pref = function(sdpLines) {
- var invalidLineIndex = sdpLines.indexOf(
- 'a=fmtp:0 profile-level-id=0x42e00c;packetization-mode=1');
- if (invalidLineIndex > -1) {
- log.debug([null, 'SDP', null, 'Firefox H264 invalid pref found:'], invalidLineIndex);
- sdpLines.splice(invalidLineIndex, 1);
- }
- return sdpLines;
- };
-
- /**
- * Function that modifies the SessionDescription string to set with the correct MediaStream ID and
- * MediaStreamTrack IDs that is not provided from Firefox connection to Chromium connection.
- * @method _addSDPSsrcFirefoxAnswer
- * @private
- * @for Skylink
- * @since 0.6.6
- */
- Skylink.prototype._addSDPSsrcFirefoxAnswer = function (targetMid, sdp) {
- var self = this;
- var agent = self.getPeerInfo(targetMid).agent;
-
- var pc = self._peerConnections[targetMid];
-
- if (!pc) {
- log.error([targetMid, 'RTCSessionDesription', 'answer', 'Peer connection object ' +
- 'not found. Unable to parse answer session description for peer']);
- return;
- }
-
- var updatedSdp = sdp;
-
- // for this case, this is because firefox uses Unified Plan and Chrome uses
- // Plan B. we have to remodify this a bit to let the non-ff detect as new mediastream
- // as chrome/opera/safari detects it as default due to missing ssrc specified as used in plan B.
- if (window.webrtcDetectedBrowser === 'firefox' && agent.name !== 'firefox' &&
- //pc.remoteDescription.sdp.indexOf('a=msid-semantic: WMS *') === -1 &&
- updatedSdp.indexOf('a=msid-semantic:WMS *') > 0) {
- // start parsing
- var sdpLines = updatedSdp.split('\r\n');
- var streamId = '';
- var replaceSSRCSemantic = -1;
- var i;
- var trackId = '';
-
- var parseTracksSSRC = function (track) {
- for (i = 0, trackId = ''; i < sdpLines.length; i++) {
- if (!!trackId) {
- if (sdpLines[i].indexOf('a=ssrc:') === 0) {
- var ssrcId = sdpLines[i].split(':')[1].split(' ')[0];
- sdpLines.splice(i+1, 0, 'a=ssrc:' + ssrcId + ' msid:' + streamId + ' ' + trackId,
- 'a=ssrc:' + ssrcId + ' mslabel:default',
- 'a=ssrc:' + ssrcId + ' label:' + trackId);
- break;
- } else if (sdpLines[i].indexOf('a=mid:') === 0) {
- break;
- }
- } else if (sdpLines[i].indexOf('a=msid:') === 0) {
- if (i > 0 && sdpLines[i-1].indexOf('a=mid:' + track) === 0) {
- var parts = sdpLines[i].split(':')[1].split(' ');
-
- streamId = parts[0];
- trackId = parts[1];
- replaceSSRCSemantic = true;
- }
- }
- }
- };
-
- parseTracksSSRC('video');
- parseTracksSSRC('audio');
-
- /*if (replaceSSRCSemantic) {
- for (i = 0; i < sdpLines.length; i++) {
- if (sdpLines[i].indexOf('a=msid-semantic:WMS ') === 0) {
- var parts = sdpLines[i].split(' ');
- parts[parts.length - 1] = streamId;
- sdpLines[i] = parts.join(' ');
- break;
- }
- }
-
- }*/
- updatedSdp = sdpLines.join('\r\n');
-
- log.debug([targetMid, 'RTCSessionDesription', 'answer', 'Parsed remote description from firefox'], sdpLines);
- }
-
- return updatedSdp;
- };
-