6 changed files with 471 additions and 172 deletions
@ -1,162 +1,423 @@ |
|||||||
/* |
/* |
||||||
* Spreed WebRTC. |
* Spreed WebRTC. |
||||||
* Copyright (C) 2013-2014 struktur AG |
* Copyright (C) 2013-2015 struktur AG |
||||||
* |
* |
||||||
* This file is part of Spreed WebRTC. |
* This file is part of Spreed WebRTC. |
||||||
* |
* |
||||||
* This program is free software: you can redistribute it and/or modify |
* This file is a AMD wrapped version of the sdputils.js from the |
||||||
* it under the terms of the GNU Affero General Public License as published by |
* WebRTC apprtc example. https://github.com/webrtc/apprtc/blob/master/src
|
||||||
* the Free Software Foundation, either version 3 of the License, or |
|
||||||
* (at your option) any later version. |
|
||||||
* |
* |
||||||
* This program is distributed in the hope that it will be useful, |
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU Affero General Public License for more details. |
|
||||||
* |
* |
||||||
* You should have received a copy of the GNU Affero General Public License |
* Redistribution and use in source and binary forms, with or without |
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in |
||||||
|
* the documentation and/or other materials provided with the |
||||||
|
* distribution. |
||||||
|
* |
||||||
|
* * Neither the name of Google nor the names of its contributors may |
||||||
|
* be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
* |
* |
||||||
*/ |
*/ |
||||||
|
|
||||||
"use strict"; |
"use strict"; |
||||||
define([], function() { |
define([], function() { |
||||||
|
|
||||||
var Utils = function() {} |
function trace(text) { |
||||||
|
// noop
|
||||||
Utils.prototype.mergeConstraints = function(cons1, cons2) { |
} |
||||||
var merged = cons1; |
|
||||||
var name; |
function mergeConstraints(cons1, cons2) { |
||||||
for (name in cons2.mandatory) { |
if (!cons1 || !cons2) { |
||||||
if (cons2.mandatory.hasOwnProperty(name)) { |
return cons1 || cons2; |
||||||
merged.mandatory[name] = cons2.mandatory[name]; |
} |
||||||
} |
var merged = cons1; |
||||||
} |
for (var name in cons2.mandatory) { |
||||||
merged.optional.concat(cons2.optional); |
if (cons2.mandatory.hasOwnProperty(name)) { |
||||||
return merged; |
merged.mandatory[name] = cons2.mandatory[name]; |
||||||
}; |
} |
||||||
|
} |
||||||
Utils.prototype.extractSdp = function(sdpLine, pattern) { |
merged.optional = merged.optional.concat(cons2.optional); |
||||||
var result = sdpLine.match(pattern); |
return merged; |
||||||
return (result && result.length == 2) ? result[1] : null; |
} |
||||||
}; |
|
||||||
|
function iceCandidateType(candidateStr) { |
||||||
Utils.prototype.addStereo = function(sdp) { |
return candidateStr.split(' ')[7]; |
||||||
// Set Opus in Stereo.
|
} |
||||||
|
|
||||||
var sdpLines = sdp.split('\r\n'); |
function maybeSetOpusOptions(sdp, params) { |
||||||
var opusPayload = ""; |
// Set Opus in Stereo, if stereo is true, unset it, if stereo is false, and
|
||||||
var fmtpLineIndex = null; |
// do nothing if otherwise.
|
||||||
var i; |
if (params.opusStereo === 'true') { |
||||||
|
sdp = setCodecParam(sdp, 'opus/48000', 'stereo', '1'); |
||||||
// Find opus payload.
|
} else if (params.opusStereo === 'false') { |
||||||
for (i = 0; i < sdpLines.length; i++) { |
sdp = removeCodecParam(sdp, 'opus/48000', 'stereo'); |
||||||
if (sdpLines[i].search('opus/48000') !== -1) { |
} |
||||||
opusPayload = this.extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); |
|
||||||
break; |
// Set Opus FEC, if opusfec is true, unset it, if opusfec is false, and
|
||||||
} |
// do nothing if otherwise.
|
||||||
} |
if (params.opusFec === 'true') { |
||||||
|
sdp = setCodecParam(sdp, 'opus/48000', 'useinbandfec', '1'); |
||||||
// Find the payload in fmtp line.
|
} else if (params.opusFec === 'false') { |
||||||
for (i = 0; i < sdpLines.length; i++) { |
sdp = removeCodecParam(sdp, 'opus/48000', 'useinbandfec'); |
||||||
if (sdpLines[i].search('a=fmtp') !== -1) { |
} |
||||||
var payload = this.extractSdp(sdpLines[i], /a=fmtp:(\d+)/); |
|
||||||
if (payload === opusPayload) { |
// Set Opus maxplaybackrate, if requested.
|
||||||
fmtpLineIndex = i; |
if (params.opusMaxPbr) { |
||||||
break; |
sdp = setCodecParam( |
||||||
} |
sdp, 'opus/48000', 'maxplaybackrate', params.opusMaxPbr); |
||||||
} |
} |
||||||
} |
return sdp; |
||||||
// No fmtp line found.
|
} |
||||||
if (fmtpLineIndex === null) { |
|
||||||
console.log("Unable to add stereo (no fmtp line for opus payload)", opusPayload); |
function maybeSetAudioSendBitRate(sdp, params) { |
||||||
return sdp; |
if (!params.audioSendBitrate) { |
||||||
} |
return sdp; |
||||||
|
} |
||||||
// Append stereo=1 to fmtp line.
|
trace('Prefer audio send bitrate: ' + params.audioSendBitrate); |
||||||
sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat(' stereo=1'); |
return preferBitRate(sdp, params.audioSendBitrate, 'audio'); |
||||||
|
} |
||||||
sdp = sdpLines.join('\r\n'); |
|
||||||
console.log("Enabled opus stereo."); |
function maybeSetAudioReceiveBitRate(sdp, params) { |
||||||
return sdp; |
if (!params.audioRecvBitrate) { |
||||||
|
return sdp; |
||||||
}; |
} |
||||||
|
trace('Prefer audio receive bitrate: ' + params.audioRecvBitrate); |
||||||
Utils.prototype.preferOpus = function(sdp) { |
return preferBitRate(sdp, params.audioRecvBitrate, 'audio'); |
||||||
// Set Opus as the preferred codec in SDP if Opus is present.
|
} |
||||||
|
|
||||||
var sdpLines = sdp.split('\r\n'); |
function maybeSetVideoSendBitRate(sdp, params) { |
||||||
var mLineIndex = null; |
if (!params.videoSendBitrate) { |
||||||
var i; |
return sdp; |
||||||
|
} |
||||||
// Search for m line.
|
trace('Prefer video send bitrate: ' + params.videoSendBitrate); |
||||||
for (i = 0; i < sdpLines.length; i++) { |
return preferBitRate(sdp, params.videoSendBitrate, 'video'); |
||||||
if (sdpLines[i].search('m=audio') !== -1) { |
} |
||||||
mLineIndex = i; |
|
||||||
break; |
function maybeSetVideoReceiveBitRate(sdp, params) { |
||||||
} |
if (!params.videoRecvBitrate) { |
||||||
} |
return sdp; |
||||||
if (mLineIndex === null) { |
} |
||||||
return sdp; |
trace('Prefer video receive bitrate: ' + params.videoRecvBitrate); |
||||||
} |
return preferBitRate(sdp, params.videoRecvBitrate, 'video'); |
||||||
|
} |
||||||
// If Opus is available, set it as the default in m line.
|
|
||||||
for (i = 0; i < sdpLines.length; i++) { |
// Add a b=AS:bitrate line to the m=mediaType section.
|
||||||
if (sdpLines[i].search('opus/48000') !== -1) { |
function preferBitRate(sdp, bitrate, mediaType) { |
||||||
var opusPayload = this.extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); |
var sdpLines = sdp.split('\r\n'); |
||||||
if (opusPayload) { |
|
||||||
sdpLines[mLineIndex] = this.setDefaultCodec(sdpLines[mLineIndex], opusPayload); |
// Find m line for the given mediaType.
|
||||||
} |
var mLineIndex = findLine(sdpLines, 'm=', mediaType); |
||||||
break; |
if (mLineIndex === null) { |
||||||
} |
trace('Failed to add bandwidth line to sdp, as no m-line found'); |
||||||
} |
return sdp; |
||||||
|
} |
||||||
// Remove CN in m line and sdp.
|
|
||||||
sdpLines = this.removeCN(sdpLines, mLineIndex); |
// Find next m-line if any.
|
||||||
|
var nextMLineIndex = findLineInRange(sdpLines, mLineIndex + 1, -1, 'm='); |
||||||
sdp = sdpLines.join('\r\n'); |
if (nextMLineIndex === null) { |
||||||
return sdp; |
nextMLineIndex = sdpLines.length; |
||||||
|
} |
||||||
}; |
|
||||||
|
// Find c-line corresponding to the m-line.
|
||||||
Utils.prototype.setDefaultCodec = function(mLine, payload) { |
var cLineIndex = findLineInRange(sdpLines, mLineIndex + 1, |
||||||
// Set the selected codec to the first in m line.
|
nextMLineIndex, 'c='); |
||||||
var elements = mLine.split(' '); |
if (cLineIndex === null) { |
||||||
var newLine = []; |
trace('Failed to add bandwidth line to sdp, as no c-line found'); |
||||||
var index = 0; |
return sdp; |
||||||
for (var i = 0; i < elements.length; i++) { |
} |
||||||
// Format of media starts from the fourth.
|
|
||||||
if (index === 3) { |
// Check if bandwidth line already exists between c-line and next m-line.
|
||||||
newLine[index++] = payload; // Put target payload to the first.
|
var bLineIndex = findLineInRange(sdpLines, cLineIndex + 1, |
||||||
} |
nextMLineIndex, 'b=AS'); |
||||||
if (elements[i] !== payload) { |
if (bLineIndex) { |
||||||
newLine[index++] = elements[i]; |
sdpLines.splice(bLineIndex, 1); |
||||||
} |
} |
||||||
} |
|
||||||
return newLine.join(' '); |
// Create the b (bandwidth) sdp line.
|
||||||
}; |
var bwLine = 'b=AS:' + bitrate; |
||||||
|
// As per RFC 4566, the b line should follow after c-line.
|
||||||
Utils.prototype.removeCN = function(sdpLines, mLineIndex) { |
sdpLines.splice(cLineIndex + 1, 0, bwLine); |
||||||
// Strip CN from sdp before CN constraints is ready.
|
sdp = sdpLines.join('\r\n'); |
||||||
var mLineElements = sdpLines[mLineIndex].split(' '); |
return sdp; |
||||||
// Scan from end for the convenience of removing an item.
|
} |
||||||
for (var i = sdpLines.length - 1; i >= 0; i--) { |
|
||||||
var payload = this.extractSdp(sdpLines[i], /a=rtpmap:(\d+) CN\/\d+/i); |
// Add an a=fmtp: x-google-min-bitrate=kbps line, if videoSendInitialBitrate
|
||||||
if (payload) { |
// is specified. We'll also add a x-google-min-bitrate value, since the max
|
||||||
var cnPos = mLineElements.indexOf(payload); |
// must be >= the min.
|
||||||
if (cnPos !== -1) { |
function maybeSetVideoSendInitialBitRate(sdp, params) { |
||||||
// Remove CN payload from m line.
|
var initialBitrate = params.videoSendInitialBitrate; |
||||||
mLineElements.splice(cnPos, 1); |
if (!initialBitrate) { |
||||||
} |
return sdp; |
||||||
// Remove CN line in sdp
|
} |
||||||
sdpLines.splice(i, 1); |
|
||||||
} |
// Validate the initial bitrate value.
|
||||||
} |
var maxBitrate = initialBitrate; |
||||||
sdpLines[mLineIndex] = mLineElements.join(' '); |
var bitrate = params.videoSendBitrate; |
||||||
return sdpLines; |
if (bitrate) { |
||||||
}; |
if (initialBitrate > bitrate) { |
||||||
|
trace('Clamping initial bitrate to max bitrate of ' + |
||||||
var utils = new Utils(); |
bitrate + ' kbps.'); |
||||||
return utils; |
initialBitrate = bitrate; |
||||||
|
params.videoSendInitialBitrate = initialBitrate; |
||||||
|
} |
||||||
|
maxBitrate = bitrate; |
||||||
|
} |
||||||
|
|
||||||
|
var sdpLines = sdp.split('\r\n'); |
||||||
|
|
||||||
|
// Search for m line.
|
||||||
|
var mLineIndex = findLine(sdpLines, 'm=', 'video'); |
||||||
|
if (mLineIndex === null) { |
||||||
|
trace('Failed to find video m-line'); |
||||||
|
return sdp; |
||||||
|
} |
||||||
|
|
||||||
|
sdp = setCodecParam(sdp, 'VP8/90000', 'x-google-min-bitrate', |
||||||
|
params.videoSendInitialBitrate.toString()); |
||||||
|
sdp = setCodecParam(sdp, 'VP8/90000', 'x-google-max-bitrate', |
||||||
|
maxBitrate.toString()); |
||||||
|
|
||||||
|
return sdp; |
||||||
|
} |
||||||
|
|
||||||
|
// Promotes |audioSendCodec| to be the first in the m=audio line, if set.
|
||||||
|
function maybePreferAudioSendCodec(sdp, params) { |
||||||
|
return maybePreferCodec(sdp, 'audio', 'send', params.audioSendCodec); |
||||||
|
} |
||||||
|
|
||||||
|
// Promotes |audioRecvCodec| to be the first in the m=audio line, if set.
|
||||||
|
function maybePreferAudioReceiveCodec(sdp, params) { |
||||||
|
return maybePreferCodec(sdp, 'audio', 'receive', params.audioRecvCodec); |
||||||
|
} |
||||||
|
|
||||||
|
// Promotes |videoSendCodec| to be the first in the m=audio line, if set.
|
||||||
|
function maybePreferVideoSendCodec(sdp, params) { |
||||||
|
return maybePreferCodec(sdp, 'video', 'send', params.videoSendCodec); |
||||||
|
} |
||||||
|
|
||||||
|
// Promotes |videoRecvCodec| to be the first in the m=audio line, if set.
|
||||||
|
function maybePreferVideoReceiveCodec(sdp, params) { |
||||||
|
return maybePreferCodec(sdp, 'video', 'receive', params.videoRecvCodec); |
||||||
|
} |
||||||
|
|
||||||
|
// Sets |codec| as the default |type| codec if it's present.
|
||||||
|
// The format of |codec| is 'NAME/RATE', e.g. 'opus/48000'.
|
||||||
|
function maybePreferCodec(sdp, type, dir, codec) { |
||||||
|
var str = type + ' ' + dir + ' codec'; |
||||||
|
if (codec === '') { |
||||||
|
trace('No preference on ' + str + '.'); |
||||||
|
return sdp; |
||||||
|
} |
||||||
|
|
||||||
|
trace('Prefer ' + str + ': ' + codec); |
||||||
|
|
||||||
|
var sdpLines = sdp.split('\r\n'); |
||||||
|
|
||||||
|
// Search for m line.
|
||||||
|
var mLineIndex = findLine(sdpLines, 'm=', type); |
||||||
|
if (mLineIndex === null) { |
||||||
|
return sdp; |
||||||
|
} |
||||||
|
|
||||||
|
// If the codec is available, set it as the default in m line.
|
||||||
|
var payload = getCodecPayloadType(sdpLines, codec); |
||||||
|
if (payload) { |
||||||
|
sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex], payload); |
||||||
|
} |
||||||
|
|
||||||
|
sdp = sdpLines.join('\r\n'); |
||||||
|
return sdp; |
||||||
|
} |
||||||
|
|
||||||
|
// Set fmtp param to specific codec in SDP. If param does not exists, add it.
|
||||||
|
function setCodecParam(sdp, codec, param, value) { |
||||||
|
var sdpLines = sdp.split('\r\n'); |
||||||
|
|
||||||
|
var fmtpLineIndex = findFmtpLine(sdpLines, codec); |
||||||
|
|
||||||
|
var fmtpObj = {}; |
||||||
|
if (fmtpLineIndex === null) { |
||||||
|
var index = findLine(sdpLines, 'a=rtpmap', codec); |
||||||
|
if (index === null) { |
||||||
|
return sdp; |
||||||
|
} |
||||||
|
var payload = getCodecPayloadTypeFromLine(sdpLines[index]); |
||||||
|
fmtpObj.pt = payload.toString(); |
||||||
|
fmtpObj.params = {}; |
||||||
|
fmtpObj.params[param] = value; |
||||||
|
sdpLines.splice(index + 1, 0, writeFmtpLine(fmtpObj)); |
||||||
|
} else { |
||||||
|
fmtpObj = parseFmtpLine(sdpLines[fmtpLineIndex]); |
||||||
|
fmtpObj.params[param] = value; |
||||||
|
sdpLines[fmtpLineIndex] = writeFmtpLine(fmtpObj); |
||||||
|
} |
||||||
|
|
||||||
|
sdp = sdpLines.join('\r\n'); |
||||||
|
return sdp; |
||||||
|
} |
||||||
|
|
||||||
|
// Remove fmtp param if it exists.
|
||||||
|
function removeCodecParam(sdp, codec, param) { |
||||||
|
var sdpLines = sdp.split('\r\n'); |
||||||
|
|
||||||
|
var fmtpLineIndex = findFmtpLine(sdpLines, codec); |
||||||
|
if (fmtpLineIndex === null) { |
||||||
|
return sdp; |
||||||
|
} |
||||||
|
|
||||||
|
var map = parseFmtpLine(sdpLines[fmtpLineIndex]); |
||||||
|
delete map.params[param]; |
||||||
|
|
||||||
|
var newLine = writeFmtpLine(map); |
||||||
|
if (newLine === null) { |
||||||
|
sdpLines.splice(fmtpLineIndex, 1); |
||||||
|
} else { |
||||||
|
sdpLines[fmtpLineIndex] = newLine; |
||||||
|
} |
||||||
|
|
||||||
|
sdp = sdpLines.join('\r\n'); |
||||||
|
return sdp; |
||||||
|
} |
||||||
|
|
||||||
|
// Split an fmtp line into an object including 'pt' and 'params'.
|
||||||
|
function parseFmtpLine(fmtpLine) { |
||||||
|
var fmtpObj = {}; |
||||||
|
var spacePos = fmtpLine.indexOf(' '); |
||||||
|
var keyValues = fmtpLine.substring(spacePos + 1).split('; '); |
||||||
|
|
||||||
|
var pattern = new RegExp('a=fmtp:(\\d+)'); |
||||||
|
var result = fmtpLine.match(pattern); |
||||||
|
if (result && result.length === 2) { |
||||||
|
fmtpObj.pt = result[1]; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
var params = {}; |
||||||
|
for (var i = 0; i < keyValues.length; ++i) { |
||||||
|
var pair = keyValues[i].split('='); |
||||||
|
if (pair.length === 2) { |
||||||
|
params[pair[0]] = pair[1]; |
||||||
|
} |
||||||
|
} |
||||||
|
fmtpObj.params = params; |
||||||
|
|
||||||
|
return fmtpObj; |
||||||
|
} |
||||||
|
|
||||||
|
// Generate an fmtp line from an object including 'pt' and 'params'.
|
||||||
|
function writeFmtpLine(fmtpObj) { |
||||||
|
if (!fmtpObj.hasOwnProperty('pt') || !fmtpObj.hasOwnProperty('params')) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
var pt = fmtpObj.pt; |
||||||
|
var params = fmtpObj.params; |
||||||
|
var keyValues = []; |
||||||
|
var i = 0; |
||||||
|
for (var key in params) { |
||||||
|
if (params.hasOwnProperty(key)) { |
||||||
|
keyValues[i] = key + '=' + params[key]; |
||||||
|
++i; |
||||||
|
} |
||||||
|
} |
||||||
|
if (i === 0) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
return 'a=fmtp:' + pt.toString() + ' ' + keyValues.join('; '); |
||||||
|
} |
||||||
|
|
||||||
|
// Find fmtp attribute for |codec| in |sdpLines|.
|
||||||
|
function findFmtpLine(sdpLines, codec) { |
||||||
|
// Find payload of codec.
|
||||||
|
var payload = getCodecPayloadType(sdpLines, codec); |
||||||
|
// Find the payload in fmtp line.
|
||||||
|
return payload ? findLine(sdpLines, 'a=fmtp:' + payload.toString()) : null; |
||||||
|
} |
||||||
|
|
||||||
|
// Find the line in sdpLines that starts with |prefix|, and, if specified,
|
||||||
|
// contains |substr| (case-insensitive search).
|
||||||
|
function findLine(sdpLines, prefix, substr) { |
||||||
|
return findLineInRange(sdpLines, 0, -1, prefix, substr); |
||||||
|
} |
||||||
|
|
||||||
|
// Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix|
|
||||||
|
// and, if specified, contains |substr| (case-insensitive search).
|
||||||
|
function findLineInRange(sdpLines, startLine, endLine, prefix, substr) { |
||||||
|
var realEndLine = endLine !== -1 ? endLine : sdpLines.length; |
||||||
|
for (var i = startLine; i < realEndLine; ++i) { |
||||||
|
if (sdpLines[i].indexOf(prefix) === 0) { |
||||||
|
if (!substr || |
||||||
|
sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
// Gets the codec payload type from sdp lines.
|
||||||
|
function getCodecPayloadType(sdpLines, codec) { |
||||||
|
var index = findLine(sdpLines, 'a=rtpmap', codec); |
||||||
|
return index ? getCodecPayloadTypeFromLine(sdpLines[index]) : null; |
||||||
|
} |
||||||
|
|
||||||
|
// Gets the codec payload type from an a=rtpmap:X line.
|
||||||
|
function getCodecPayloadTypeFromLine(sdpLine) { |
||||||
|
var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+'); |
||||||
|
var result = sdpLine.match(pattern); |
||||||
|
return (result && result.length === 2) ? result[1] : null; |
||||||
|
} |
||||||
|
|
||||||
|
// Returns a new m= line with the specified codec as the first one.
|
||||||
|
function setDefaultCodec(mLine, payload) { |
||||||
|
var elements = mLine.split(' '); |
||||||
|
|
||||||
|
// Just copy the first three parameters; codec order starts on fourth.
|
||||||
|
var newLine = elements.slice(0, 3); |
||||||
|
|
||||||
|
// Put target payload first and copy in the rest.
|
||||||
|
newLine.push(payload); |
||||||
|
for (var i = 3; i < elements.length; i++) { |
||||||
|
if (elements[i] !== payload) { |
||||||
|
newLine.push(elements[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
return newLine.join(' '); |
||||||
|
} |
||||||
|
|
||||||
|
// Exported utils.
|
||||||
|
return { |
||||||
|
mergeConstraints: mergeConstraints, |
||||||
|
maybeSetOpusOptions: maybeSetOpusOptions, |
||||||
|
maybeSetAudioSendBitRate: maybeSetAudioSendBitRate, |
||||||
|
maybeSetAudioReceiveBitRate: maybeSetAudioReceiveBitRate, |
||||||
|
maybeSetVideoSendBitRate: maybeSetVideoSendBitRate, |
||||||
|
maybeSetVideoReceiveBitRate: maybeSetVideoReceiveBitRate, |
||||||
|
maybeSetVideoSendInitialBitRate: maybeSetVideoSendInitialBitRate, |
||||||
|
maybePreferAudioSendCodec: maybePreferAudioSendCodec, |
||||||
|
maybePreferAudioReceiveCodec: maybePreferAudioReceiveCodec, |
||||||
|
maybePreferVideoSendCodec: maybePreferVideoSendCodec, |
||||||
|
maybePreferVideoReceiveCodec: maybePreferVideoReceiveCodec |
||||||
|
} |
||||||
|
|
||||||
}); |
}); |
||||||
|
Loading…
Reference in new issue