Browse Source

Bring back send stereo support by processing sdp correctly and disable AEC when sendStereo is true. The old stereo option is now always true.

pull/173/head
Simon Eisenmann 11 years ago
parent
commit
5401c566b5
  1. 5
      static/js/controllers/mediastreamcontroller.js
  2. 6
      static/js/directives/settings.js
  3. 29
      static/js/mediastream/peercall.js
  4. 555
      static/js/mediastream/utils.js
  5. 25
      static/js/mediastream/webrtc.js
  6. 23
      static/partials/settings.html

5
static/js/controllers/mediastreamcontroller.js

@ -140,7 +140,7 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder @@ -140,7 +140,7 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder
message: null,
settings: {
videoQuality: "high",
stereo: true,
sendStereo: false,
maxFrameRate: 20,
defaultRoom: "",
language: "",
@ -226,9 +226,6 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder @@ -226,9 +226,6 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder
}
mediaStream.webrtc.settings.pcConfig.iceServers = iceServers;
// Stereo.
mediaStream.webrtc.settings.stereo = settings.stereo;
// Refresh constraints.
constraints.refresh($scope.master.settings);

6
static/js/directives/settings.js

@ -248,6 +248,12 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t @@ -248,6 +248,12 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t
constraints.add("video", "maxFrameRate", parseInt(settings.maxFrameRate, 10), true);
}
// Disable AEC if stereo.
// https://github.com/webrtc/apprtc/issues/23
if (settings.sendStereo) {
constraints.add("audio", "echoCancellation", false);
}
} else {
// Other browsers constraints (there are none as of now.);

29
static/js/mediastream/peercall.js

@ -36,6 +36,7 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection @@ -36,6 +36,7 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection
this.pcConstraints = $.extend(true, {}, this.webrtc.settings.pcConstraints);
this.sdpConstraints = $.extend(true, {}, this.webrtc.settings.sdpConstraints);
this.offerConstraints = $.extend(true, {}, this.webrtc.settings.offerConstraints);
this.sdpParams = $.extend(true, {}, this.webrtc.settings.sdpParams);
this.peerconnection = null;
this.datachannels = {};
@ -84,8 +85,7 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection @@ -84,8 +85,7 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection
PeerCall.prototype.onCreateAnswerOffer = function(cb, sessionDescription) {
// Prefer Opus.
sessionDescription.sdp = utils.preferOpus(sessionDescription.sdp);
this.setLocalSdp(sessionDescription);
// Convert to object to allow custom property injection.
var sessionDescriptionObj = sessionDescription;
@ -128,6 +128,9 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection @@ -128,6 +128,9 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection
console.log("Got a remote description but not connected -> ignored.");
return;
}
this.setRemoteSdp(sessionDescription);
peerconnection.setRemoteDescription(sessionDescription, _.bind(function() {
console.log("Set remote session description.", sessionDescription, this);
if (cb) {
@ -155,6 +158,28 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection @@ -155,6 +158,28 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection
};
PeerCall.prototype.setLocalSdp = function(sessionDescription) {
var params = this.sdpParams;
sessionDescription.sdp = utils.maybePreferAudioReceiveCodec(sessionDescription.sdp, params);
sessionDescription.sdp = utils.maybePreferVideoReceiveCodec(sessionDescription.sdp, params);
sessionDescription.sdp = utils.maybeSetAudioReceiveBitRate(sessionDescription.sdp, params);
sessionDescription.sdp = utils.maybeSetVideoReceiveBitRate(sessionDescription.sdp, params);
};
PeerCall.prototype.setRemoteSdp = function(sessionDescription) {
var params = this.sdpParams;
sessionDescription.sdp = utils.maybeSetOpusOptions(sessionDescription.sdp, params);
sessionDescription.sdp = utils.maybePreferAudioSendCodec(sessionDescription.sdp, params);
sessionDescription.sdp = utils.maybePreferVideoSendCodec(sessionDescription.sdp, params);
sessionDescription.sdp = utils.maybeSetAudioSendBitRate(sessionDescription.sdp, params);
sessionDescription.sdp = utils.maybeSetVideoSendBitRate(sessionDescription.sdp, params);
sessionDescription.sdp = utils.maybeSetVideoSendInitialBitRate(sessionDescription.sdp, params);
};
PeerCall.prototype.onIceCandidate = function(event) {
if (event.candidate) {
//console.log("ice candidate", event.candidate);

555
static/js/mediastream/utils.js

@ -1,162 +1,423 @@ @@ -1,162 +1,423 @@
/*
* Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG
* Copyright (C) 2013-2015 struktur AG
*
* This file is part of Spreed WebRTC.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This file is a AMD wrapped version of the sdputils.js from the
* WebRTC apprtc example. https://github.com/webrtc/apprtc/blob/master/src
*
* This program is distributed in the hope that it will be useful,
* 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.
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* Redistribution and use in source and binary forms, with or without
* 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";
define([], function() {
var Utils = function() {}
Utils.prototype.mergeConstraints = function(cons1, cons2) {
var merged = cons1;
var name;
for (name in cons2.mandatory) {
if (cons2.mandatory.hasOwnProperty(name)) {
merged.mandatory[name] = cons2.mandatory[name];
}
}
merged.optional.concat(cons2.optional);
return merged;
};
Utils.prototype.extractSdp = function(sdpLine, pattern) {
var result = sdpLine.match(pattern);
return (result && result.length == 2) ? result[1] : null;
};
Utils.prototype.addStereo = function(sdp) {
// Set Opus in Stereo.
var sdpLines = sdp.split('\r\n');
var opusPayload = "";
var fmtpLineIndex = null;
var i;
// Find opus payload.
for (i = 0; i < sdpLines.length; i++) {
if (sdpLines[i].search('opus/48000') !== -1) {
opusPayload = this.extractSdp(sdpLines[i], /:(\d+) opus\/48000/i);
break;
}
}
// Find the payload in fmtp line.
for (i = 0; i < sdpLines.length; i++) {
if (sdpLines[i].search('a=fmtp') !== -1) {
var payload = this.extractSdp(sdpLines[i], /a=fmtp:(\d+)/);
if (payload === opusPayload) {
fmtpLineIndex = i;
break;
}
}
}
// No fmtp line found.
if (fmtpLineIndex === null) {
console.log("Unable to add stereo (no fmtp line for opus payload)", opusPayload);
return sdp;
}
// Append stereo=1 to fmtp line.
sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat(' stereo=1');
sdp = sdpLines.join('\r\n');
console.log("Enabled opus stereo.");
return sdp;
};
Utils.prototype.preferOpus = function(sdp) {
// Set Opus as the preferred codec in SDP if Opus is present.
var sdpLines = sdp.split('\r\n');
var mLineIndex = null;
var i;
// Search for m line.
for (i = 0; i < sdpLines.length; i++) {
if (sdpLines[i].search('m=audio') !== -1) {
mLineIndex = i;
break;
}
}
if (mLineIndex === null) {
return sdp;
}
// If Opus is available, set it as the default in m line.
for (i = 0; i < sdpLines.length; i++) {
if (sdpLines[i].search('opus/48000') !== -1) {
var opusPayload = this.extractSdp(sdpLines[i], /:(\d+) opus\/48000/i);
if (opusPayload) {
sdpLines[mLineIndex] = this.setDefaultCodec(sdpLines[mLineIndex], opusPayload);
}
break;
}
}
// Remove CN in m line and sdp.
sdpLines = this.removeCN(sdpLines, mLineIndex);
sdp = sdpLines.join('\r\n');
return sdp;
};
Utils.prototype.setDefaultCodec = function(mLine, payload) {
// Set the selected codec to the first in m line.
var elements = mLine.split(' ');
var newLine = [];
var index = 0;
for (var i = 0; i < elements.length; i++) {
// Format of media starts from the fourth.
if (index === 3) {
newLine[index++] = payload; // Put target payload to the first.
}
if (elements[i] !== payload) {
newLine[index++] = elements[i];
}
}
return newLine.join(' ');
};
Utils.prototype.removeCN = function(sdpLines, mLineIndex) {
// Strip CN from sdp before CN constraints is ready.
var mLineElements = sdpLines[mLineIndex].split(' ');
// 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);
if (payload) {
var cnPos = mLineElements.indexOf(payload);
if (cnPos !== -1) {
// Remove CN payload from m line.
mLineElements.splice(cnPos, 1);
}
// Remove CN line in sdp
sdpLines.splice(i, 1);
}
}
sdpLines[mLineIndex] = mLineElements.join(' ');
return sdpLines;
};
var utils = new Utils();
return utils;
function trace(text) {
// noop
}
function mergeConstraints(cons1, cons2) {
if (!cons1 || !cons2) {
return cons1 || cons2;
}
var merged = cons1;
for (var name in cons2.mandatory) {
if (cons2.mandatory.hasOwnProperty(name)) {
merged.mandatory[name] = cons2.mandatory[name];
}
}
merged.optional = merged.optional.concat(cons2.optional);
return merged;
}
function iceCandidateType(candidateStr) {
return candidateStr.split(' ')[7];
}
function maybeSetOpusOptions(sdp, params) {
// Set Opus in Stereo, if stereo is true, unset it, if stereo is false, and
// do nothing if otherwise.
if (params.opusStereo === 'true') {
sdp = setCodecParam(sdp, 'opus/48000', 'stereo', '1');
} else if (params.opusStereo === 'false') {
sdp = removeCodecParam(sdp, 'opus/48000', 'stereo');
}
// 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');
} else if (params.opusFec === 'false') {
sdp = removeCodecParam(sdp, 'opus/48000', 'useinbandfec');
}
// Set Opus maxplaybackrate, if requested.
if (params.opusMaxPbr) {
sdp = setCodecParam(
sdp, 'opus/48000', 'maxplaybackrate', params.opusMaxPbr);
}
return sdp;
}
function maybeSetAudioSendBitRate(sdp, params) {
if (!params.audioSendBitrate) {
return sdp;
}
trace('Prefer audio send bitrate: ' + params.audioSendBitrate);
return preferBitRate(sdp, params.audioSendBitrate, 'audio');
}
function maybeSetAudioReceiveBitRate(sdp, params) {
if (!params.audioRecvBitrate) {
return sdp;
}
trace('Prefer audio receive bitrate: ' + params.audioRecvBitrate);
return preferBitRate(sdp, params.audioRecvBitrate, 'audio');
}
function maybeSetVideoSendBitRate(sdp, params) {
if (!params.videoSendBitrate) {
return sdp;
}
trace('Prefer video send bitrate: ' + params.videoSendBitrate);
return preferBitRate(sdp, params.videoSendBitrate, 'video');
}
function maybeSetVideoReceiveBitRate(sdp, params) {
if (!params.videoRecvBitrate) {
return sdp;
}
trace('Prefer video receive bitrate: ' + params.videoRecvBitrate);
return preferBitRate(sdp, params.videoRecvBitrate, 'video');
}
// Add a b=AS:bitrate line to the m=mediaType section.
function preferBitRate(sdp, bitrate, mediaType) {
var sdpLines = sdp.split('\r\n');
// Find m line for the given mediaType.
var mLineIndex = findLine(sdpLines, 'm=', mediaType);
if (mLineIndex === null) {
trace('Failed to add bandwidth line to sdp, as no m-line found');
return sdp;
}
// Find next m-line if any.
var nextMLineIndex = findLineInRange(sdpLines, mLineIndex + 1, -1, 'm=');
if (nextMLineIndex === null) {
nextMLineIndex = sdpLines.length;
}
// Find c-line corresponding to the m-line.
var cLineIndex = findLineInRange(sdpLines, mLineIndex + 1,
nextMLineIndex, 'c=');
if (cLineIndex === null) {
trace('Failed to add bandwidth line to sdp, as no c-line found');
return sdp;
}
// Check if bandwidth line already exists between c-line and next m-line.
var bLineIndex = findLineInRange(sdpLines, cLineIndex + 1,
nextMLineIndex, 'b=AS');
if (bLineIndex) {
sdpLines.splice(bLineIndex, 1);
}
// Create the b (bandwidth) sdp line.
var bwLine = 'b=AS:' + bitrate;
// As per RFC 4566, the b line should follow after c-line.
sdpLines.splice(cLineIndex + 1, 0, bwLine);
sdp = sdpLines.join('\r\n');
return sdp;
}
// Add an a=fmtp: x-google-min-bitrate=kbps line, if videoSendInitialBitrate
// is specified. We'll also add a x-google-min-bitrate value, since the max
// must be >= the min.
function maybeSetVideoSendInitialBitRate(sdp, params) {
var initialBitrate = params.videoSendInitialBitrate;
if (!initialBitrate) {
return sdp;
}
// Validate the initial bitrate value.
var maxBitrate = initialBitrate;
var bitrate = params.videoSendBitrate;
if (bitrate) {
if (initialBitrate > bitrate) {
trace('Clamping initial bitrate to max bitrate of ' +
bitrate + ' kbps.');
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
}
});

25
static/js/mediastream/webrtc.js

@ -59,7 +59,6 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u @@ -59,7 +59,6 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u
// Settings.are cloned into peer call on call creation.
this.settings = {
stereo: false,
mediaConstraints: {
audio: true,
video: {
@ -76,6 +75,7 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u @@ -76,6 +75,7 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u
}]
},
pcConstraints: {
mandatory: {},
optional: []
},
// Set up audio and video regardless of what devices are present.
@ -83,7 +83,8 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u @@ -83,7 +83,8 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
}
},
optional: []
},
offerConstraints: {
mandatory: {},
@ -97,6 +98,20 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u @@ -97,6 +98,20 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u
mandatory: {}
}
}
},
// sdpParams values need to be strings.
sdpParams: {
//audioSendBitrate: ,
audioSendCodec: "opus/48000",
//audioRecvBitrate: ,
//audioRecvCodec: ,
//opusMaxPbr: ,
opusStereo: "true",
//videoSendBitrate: ,
//videoSendInitialBitrate: ,
videoSendCodec: "VP8/90000"
//videoRecvBitrate: ,
//videoRecvCodec
}
}
@ -228,9 +243,6 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u @@ -228,9 +243,6 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u
switch (type) {
case "Offer":
console.log("Offer process.");
if (this.settings.stereo) {
data.sdp = utils.addStereo(data.sdp);
}
targetcall = this.findTargetCall(from);
if (targetcall) {
// Hey we know this call.
@ -280,9 +292,6 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u @@ -280,9 +292,6 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u
return;
}
console.log("Answer process.");
if (this.settings.stereo) {
data.sdp = utils.addStereo(data.sdp);
}
// TODO(longsleep): In case of negotiation this could switch offer and answer
// and result in a offer sdp sent as answer data. We need to handle this.
targetcall.setRemoteDescription(new window.RTCSessionDescription(data), function() {

23
static/partials/settings.html

@ -130,17 +130,6 @@ @@ -130,17 +130,6 @@
<div>
<div class="form-group">
<label class="col-xs-4 control-label">{{_('Stereo audio')}}</label>
<div class="col-xs-8">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="user.settings.stereo"/>&nbsp;
</label>
</div>
</div>
</div>
<div class="form-group" ng-show="isChrome && supported.renderToAssociatedSink">
<label class="col-xs-4 control-label">{{_('Play audio on same device as selected microphone')}}</label>
<div class="col-xs-8">
@ -202,6 +191,18 @@ @@ -202,6 +191,18 @@
</div>
</div>
<div class="form-group" ng-show="isChrome">
<label class="col-xs-4 control-label">{{_('Send stereo audio')}}</label>
<div class="col-xs-8">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="user.settings.sendStereo"/>&nbsp;
</label>
</div>
<span class="help-block">{{_('Sending stereo audio disables echo cancellation. Enable only if you have a stereo microphone.')}}</span>
</div>
</div>
<div ng-show="user.settings.experimental.enabled">
<div class="form-group" ng-show="isChrome">

Loading…
Cancel
Save