Update libs/app.bundle.js.
This commit is contained in:
parent
ee6fd63c25
commit
777422c87d
|
@ -19,7 +19,7 @@
|
|||
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
|
||||
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
|
||||
<script src="interface_config.js?v=5"></script>
|
||||
<script src="libs/app.bundle.js?v=67"></script>
|
||||
<script src="libs/app.bundle.js?v=68"></script>
|
||||
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
|
||||
<link rel="stylesheet" href="css/font.css?v=7"/>
|
||||
<link rel="stylesheet" href="css/toastr.css?v=1">
|
||||
|
|
|
@ -705,28 +705,26 @@ var eventEmitter = new EventEmitter();
|
|||
function getMediaStreamUsage()
|
||||
{
|
||||
var result = {
|
||||
audio: 1,
|
||||
video: 1
|
||||
audio: true,
|
||||
video: true
|
||||
};
|
||||
if( config.startAudioMuted === true)
|
||||
result.audio = 0;
|
||||
if( config.startVideoMuted === true)
|
||||
result.video = 0;
|
||||
|
||||
/** There are some issues with the desktop sharing
|
||||
* when this property is enabled.
|
||||
* WARNING: We must change the implementation to start video/audio if we
|
||||
* receive from the focus that the peer is not muted.
|
||||
|
||||
if(result.audio > 0 && result.video > 0)
|
||||
return result;
|
||||
var isSecureConnection = window.location.protocol == "https:";
|
||||
|
||||
if(config.disableEarlyMediaPermissionRequests || !isSecureConnection)
|
||||
{
|
||||
if(result.audio === 0)
|
||||
result.audio = -1;
|
||||
if(result.video === 0)
|
||||
result.video = -1;
|
||||
}**/
|
||||
result = {
|
||||
audio: false,
|
||||
video: false
|
||||
};
|
||||
|
||||
}
|
||||
**/
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -1276,7 +1274,9 @@ RTCUtils.prototype.setAvailableDevices = function (um, available) {
|
|||
* We ask for audio and video combined stream in order to get permissions and
|
||||
* not to ask twice.
|
||||
*/
|
||||
RTCUtils.prototype.obtainAudioAndVideoPermissions = function(devices, callback, usageOptions) {
|
||||
RTCUtils.prototype.obtainAudioAndVideoPermissions =
|
||||
function(devices, callback, usageOptions)
|
||||
{
|
||||
var self = this;
|
||||
// Get AV
|
||||
|
||||
|
@ -1297,7 +1297,7 @@ RTCUtils.prototype.obtainAudioAndVideoPermissions = function(devices, callback,
|
|||
for(var i = 0; i < devices.length; i++)
|
||||
{
|
||||
var device = devices[i];
|
||||
if(usageOptions[device] !== -1)
|
||||
if(usageOptions[device] === true)
|
||||
newDevices.push(device);
|
||||
}
|
||||
else
|
||||
|
@ -1431,11 +1431,12 @@ RTCUtils.prototype.handleLocalStream = function(stream, usageOptions)
|
|||
videoStream = stream.videoStream;
|
||||
}
|
||||
|
||||
var audioMuted = (usageOptions && usageOptions.audio != 1),
|
||||
videoMuted = (usageOptions && usageOptions.video != 1);
|
||||
var audioMuted = (usageOptions && usageOptions.audio === false),
|
||||
videoMuted = (usageOptions && usageOptions.video === false);
|
||||
|
||||
var audioGUM = (!usageOptions || usageOptions.audio !== false),
|
||||
videoGUM = (!usageOptions || usageOptions.video !== false);
|
||||
|
||||
var audioGUM = (!usageOptions || usageOptions.audio != -1),
|
||||
videoGUM = (!usageOptions || usageOptions.video != -1);
|
||||
|
||||
this.service.createLocalStream(audioStream, "audio", null, null,
|
||||
audioMuted, audioGUM);
|
||||
|
@ -1505,10 +1506,8 @@ var roomName = null;
|
|||
|
||||
function notifyForInitialMute()
|
||||
{
|
||||
if(config.startAudioMuted || config.startVideoMuted)
|
||||
{
|
||||
messageHandler.notify(null, "notify.mutedTitle", "connected", "notify.muted", null, {timeOut: 120000});
|
||||
}
|
||||
messageHandler.notify(null, "notify.mutedTitle", "connected",
|
||||
"notify.muted", null, {timeOut: 120000});
|
||||
}
|
||||
|
||||
function setupPrezi()
|
||||
|
@ -1725,6 +1724,9 @@ function registerListeners() {
|
|||
|
||||
APP.members.addListener(MemberEvents.DTMF_SUPPORT_CHANGED,
|
||||
onDtmfSupportChanged);
|
||||
APP.xmpp.addListener(XMPPEvents.START_MUTED, function (audio, video) {
|
||||
SettingsMenu.setStartMuted(audio, video);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -1879,8 +1881,6 @@ UI.start = function (init) {
|
|||
|
||||
SettingsMenu.init();
|
||||
|
||||
notifyForInitialMute();
|
||||
|
||||
};
|
||||
|
||||
function chatAddError(errorMessage, originalText)
|
||||
|
@ -1956,6 +1956,7 @@ function onLocalRoleChanged(jid, info, pres, isModerator)
|
|||
console.info("My role changed, new role: " + info.role);
|
||||
onModeratorStatusChanged(isModerator);
|
||||
VideoLayout.showModeratorIndicator();
|
||||
SettingsMenu.onRoleChanged();
|
||||
|
||||
if (isModerator) {
|
||||
Authentication.closeAuthenticationWindow();
|
||||
|
@ -2200,6 +2201,12 @@ UI.getRoomName = function () {
|
|||
return roomName;
|
||||
};
|
||||
|
||||
UI.setInitialMuteFromFocus = function (muteAudio, muteVideo) {
|
||||
if(muteAudio || muteVideo) notifyForInitialMute();
|
||||
if(muteAudio) UI.setAudioMuted(true);
|
||||
if(muteVideo) UI.setVideoMute(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes/unmutes the local video.
|
||||
*/
|
||||
|
@ -5090,7 +5097,7 @@ function generateLanguagesSelectBox()
|
|||
var SettingsMenu = {
|
||||
|
||||
init: function () {
|
||||
$("#updateSettings").before(generateLanguagesSelectBox());
|
||||
$("#startMutedOptions").before(generateLanguagesSelectBox());
|
||||
APP.translation.translateElement($("#languages_selectbox"));
|
||||
$('#settingsmenu>input').keyup(function(event){
|
||||
if(event.keyCode === 13) {//enter
|
||||
|
@ -5098,11 +5105,36 @@ var SettingsMenu = {
|
|||
}
|
||||
});
|
||||
|
||||
if(APP.xmpp.isModerator())
|
||||
{
|
||||
$("#startMutedOptions").css("display", "block");
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#startMutedOptions").css("display", "none");
|
||||
}
|
||||
|
||||
$("#updateSettings").click(function () {
|
||||
SettingsMenu.update();
|
||||
});
|
||||
},
|
||||
|
||||
onRoleChanged: function () {
|
||||
if(APP.xmpp.isModerator())
|
||||
{
|
||||
$("#startMutedOptions").css("display", "block");
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#startMutedOptions").css("display", "none");
|
||||
}
|
||||
},
|
||||
|
||||
setStartMuted: function (audio, video) {
|
||||
$("#startAudioMuted").attr("checked", audio);
|
||||
$("#startVideoMuted").attr("checked", video);
|
||||
},
|
||||
|
||||
update: function() {
|
||||
var newDisplayName = UIUtil.escapeHtml($('#setDisplayName').get(0).value);
|
||||
var newEmail = UIUtil.escapeHtml($('#setEmail').get(0).value);
|
||||
|
@ -5119,6 +5151,10 @@ var SettingsMenu = {
|
|||
APP.xmpp.addToPresence("email", newEmail);
|
||||
var email = Settings.setEmail(newEmail);
|
||||
|
||||
var startAudioMuted = ($("#startAudioMuted").is(":checked"));
|
||||
var startVideoMuted = ($("#startVideoMuted").is(":checked"));
|
||||
APP.xmpp.addToPresence("startMuted",
|
||||
[startAudioMuted, startVideoMuted]);
|
||||
|
||||
Avatar.setUserAvatar(APP.xmpp.myJid(), email);
|
||||
},
|
||||
|
@ -15638,6 +15674,20 @@ var Moderator = {
|
|||
{ name: 'openSctp', value: config.openSctp})
|
||||
.up();
|
||||
}
|
||||
if(config.startAudioMuted !== undefined)
|
||||
{
|
||||
elem.c(
|
||||
'property',
|
||||
{ name: 'startAudioMuted', value: config.startAudioMuted})
|
||||
.up();
|
||||
}
|
||||
if(config.startVideoMuted !== undefined)
|
||||
{
|
||||
elem.c(
|
||||
'property',
|
||||
{ name: 'startVideoMuted', value: config.startVideoMuted})
|
||||
.up();
|
||||
}
|
||||
elem.up();
|
||||
return elem;
|
||||
},
|
||||
|
@ -16187,6 +16237,13 @@ module.exports = function(XMPP, eventEmitter) {
|
|||
$(document).trigger('videomuted.muc', [from, videoMuted.text()]);
|
||||
}
|
||||
|
||||
var startMuted = $(pres).find('>startmuted');
|
||||
if (startMuted.length)
|
||||
{
|
||||
eventEmitter.emit(XMPPEvents.START_MUTED,
|
||||
startMuted.attr("audio") === "true", startMuted.attr("video") === "true");
|
||||
}
|
||||
|
||||
var devices = $(pres).find('>devices');
|
||||
if(devices.length)
|
||||
{
|
||||
|
@ -16541,6 +16598,15 @@ module.exports = function(XMPP, eventEmitter) {
|
|||
|| 'sendrecv' }
|
||||
).up();
|
||||
}
|
||||
pres.up();
|
||||
}
|
||||
|
||||
if(this.presMap["startMuted"] !== undefined)
|
||||
{
|
||||
pres.c("startmuted", {audio: this.presMap["startMuted"].audio,
|
||||
video: this.presMap["startMuted"].video,
|
||||
xmlns: "http://jitsi.org/jitmeet/start-muted"});
|
||||
delete this.presMap["startMuted"];
|
||||
}
|
||||
|
||||
pres.up();
|
||||
|
@ -16621,6 +16687,9 @@ module.exports = function(XMPP, eventEmitter) {
|
|||
addUserIdToPresence: function (userId) {
|
||||
this.presMap['userId'] = userId;
|
||||
},
|
||||
addStartMutedToPresence: function (audio, video) {
|
||||
this.presMap["startMuted"] = {audio: audio, video: video};
|
||||
},
|
||||
isModerator: function () {
|
||||
return this.role === 'moderator';
|
||||
},
|
||||
|
@ -16808,6 +16877,14 @@ module.exports = function(XMPP, eventEmitter)
|
|||
// see http://xmpp.org/extensions/xep-0166.html#concepts-session
|
||||
switch (action) {
|
||||
case 'session-initiate':
|
||||
var startMuted = $(iq).find('jingle>startmuted');
|
||||
if(startMuted && startMuted.length > 0)
|
||||
{
|
||||
var audioMuted = startMuted.attr("audio");
|
||||
var videoMuted = startMuted.attr("video");
|
||||
APP.UI.setInitialMuteFromFocus((audioMuted === "true"),
|
||||
(videoMuted === "true"));
|
||||
}
|
||||
sess = new JingleSession(
|
||||
$(iq).attr('to'), $(iq).find('jingle').attr('sid'),
|
||||
this.connection, XMPP);
|
||||
|
@ -17450,8 +17527,13 @@ function registerListeners() {
|
|||
});
|
||||
}
|
||||
|
||||
function setupEvents() {
|
||||
$(window).bind('beforeunload', function () {
|
||||
var unload = (function () {
|
||||
var unloaded = false;
|
||||
|
||||
return function () {
|
||||
if (unloaded) { return; }
|
||||
unloaded = true;
|
||||
|
||||
if (connection && connection.connected) {
|
||||
// ensure signout
|
||||
$.ajax({
|
||||
|
@ -17460,10 +17542,10 @@ function setupEvents() {
|
|||
async: false,
|
||||
cache: false,
|
||||
contentType: 'application/xml',
|
||||
data: "<body rid='" + (connection.rid || connection._proto.rid)
|
||||
+ "' xmlns='http://jabber.org/protocol/httpbind' sid='"
|
||||
+ (connection.sid || connection._proto.sid)
|
||||
+ "' type='terminate'>" +
|
||||
data: "<body rid='" + (connection.rid || connection._proto.rid) +
|
||||
"' xmlns='http://jabber.org/protocol/httpbind' sid='" +
|
||||
(connection.sid || connection._proto.sid) +
|
||||
"' type='terminate'>" +
|
||||
"<presence xmlns='jabber:client' type='unavailable'/>" +
|
||||
"</body>",
|
||||
success: function (data) {
|
||||
|
@ -17477,7 +17559,24 @@ function setupEvents() {
|
|||
});
|
||||
}
|
||||
XMPP.disposeConference(true);
|
||||
});
|
||||
};
|
||||
})();
|
||||
|
||||
function setupEvents() {
|
||||
// In recent versions of FF the 'beforeunload' event is not fired when the
|
||||
// window or the tab is closed. It is only fired when we leave the page
|
||||
// (change URL). If this participant doesn't unload properly, then it
|
||||
// becomes a ghost for the rest of the participants that stay in the
|
||||
// conference. Thankfully handling the 'unload' event in addition to the
|
||||
// 'beforeunload' event seems to garante the execution of the 'unload'
|
||||
// method at least once.
|
||||
//
|
||||
// The 'unload' method can safely be run multiple times, it will actually do
|
||||
// something only the first time that it's run, so we're don't have to worry
|
||||
// about browsers that fire both events.
|
||||
|
||||
$(window).bind('beforeunload', unload);
|
||||
$(window).bind('unload', unload);
|
||||
}
|
||||
|
||||
var XMPP = {
|
||||
|
@ -17741,6 +17840,12 @@ var XMPP = {
|
|||
case "devices":
|
||||
connection.emuc.addDevicesToPresence(value);
|
||||
break;
|
||||
case "startMuted":
|
||||
if(!Moderator.isModerator())
|
||||
return;
|
||||
connection.emuc.addStartMutedToPresence(value[0],
|
||||
value[1]);
|
||||
break;
|
||||
default :
|
||||
console.log("Unknown tag for presence: " + name);
|
||||
return;
|
||||
|
@ -28054,6 +28159,8 @@ module.exports = function arrayEquals(array) {
|
|||
exports.Interop = require('./interop');
|
||||
|
||||
},{"./interop":88}],88:[function(require,module,exports){
|
||||
"use strict";
|
||||
|
||||
var transform = require('./transform');
|
||||
var arrayEquals = require('./array-equals');
|
||||
|
||||
|
@ -28122,46 +28229,47 @@ Interop.prototype.toPlanB = function(desc) {
|
|||
session.media = [];
|
||||
|
||||
// Associative array that maps channel types to channel objects for fast
|
||||
// access to channel objects by their type, e.g. channels['audio']->channel
|
||||
// access to channel objects by their type, e.g. type2bl['audio']->channel
|
||||
// obj.
|
||||
var channels = {};
|
||||
var type2bl = {};
|
||||
|
||||
// Used to build the group:BUNDLE value after the channels construction
|
||||
// loop.
|
||||
var types = [];
|
||||
|
||||
// Implode the Unified Plan m-lines/tracks into Plan B "channels".
|
||||
media.forEach(function(mLine) {
|
||||
// Implode the Unified Plan m-lines/tracks into Plan B channels.
|
||||
media.forEach(function(unifiedLine) {
|
||||
|
||||
// rtcp-mux is required in the Plan B SDP.
|
||||
if (typeof mLine.rtcpMux !== 'string' ||
|
||||
mLine.rtcpMux !== 'rtcp-mux') {
|
||||
if ((typeof unifiedLine.rtcpMux !== 'string' ||
|
||||
unifiedLine.rtcpMux !== 'rtcp-mux') &&
|
||||
unifiedLine.direction !== 'inactive') {
|
||||
throw new Error('Cannot convert to Plan B because m-lines ' +
|
||||
'without the rtcp-mux attribute were found.');
|
||||
}
|
||||
|
||||
// If we don't have a channel for this mLine.type, then use this mLine
|
||||
// If we don't have a channel for this unifiedLine.type, then use this unifiedLine
|
||||
// as the channel basis.
|
||||
if (typeof channels[mLine.type] === 'undefined') {
|
||||
channels[mLine.type] = mLine;
|
||||
if (typeof type2bl[unifiedLine.type] === 'undefined') {
|
||||
type2bl[unifiedLine.type] = unifiedLine;
|
||||
}
|
||||
|
||||
// Add sources to the channel and handle a=msid.
|
||||
if (typeof mLine.sources === 'object') {
|
||||
Object.keys(mLine.sources).forEach(function(ssrc) {
|
||||
if (typeof channels[mLine.type].sources !== 'object')
|
||||
channels[mLine.type].sources = {};
|
||||
if (typeof unifiedLine.sources === 'object') {
|
||||
Object.keys(unifiedLine.sources).forEach(function(ssrc) {
|
||||
if (typeof type2bl[unifiedLine.type].sources !== 'object')
|
||||
type2bl[unifiedLine.type].sources = {};
|
||||
|
||||
// Assign the sources to the channel.
|
||||
channels[mLine.type].sources[ssrc] = mLine.sources[ssrc];
|
||||
type2bl[unifiedLine.type].sources[ssrc] = unifiedLine.sources[ssrc];
|
||||
|
||||
if (typeof mLine.msid !== 'undefined') {
|
||||
if (typeof unifiedLine.msid !== 'undefined') {
|
||||
// In Plan B the msid is an SSRC attribute. Also, we don't
|
||||
// care about the obsolete label and mslabel attributes.
|
||||
//
|
||||
// Note that it is not guaranteed that the mLine will have
|
||||
// Note that it is not guaranteed that the unifiedLine will have
|
||||
// an msid. recvonly channels in particular don't have one.
|
||||
channels[mLine.type].sources[ssrc].msid = mLine.msid;
|
||||
type2bl[unifiedLine.type].sources[ssrc].msid = unifiedLine.msid;
|
||||
}
|
||||
// NOTE ssrcs in ssrc groups will share msids, as
|
||||
// draft-uberti-rtcweb-plan-00 mandates.
|
||||
|
@ -28169,39 +28277,39 @@ Interop.prototype.toPlanB = function(desc) {
|
|||
}
|
||||
|
||||
// Add ssrc groups to the channel.
|
||||
if (typeof mLine.ssrcGroups !== 'undefined' &&
|
||||
Array.isArray(mLine.ssrcGroups)) {
|
||||
if (typeof unifiedLine.ssrcGroups !== 'undefined' &&
|
||||
Array.isArray(unifiedLine.ssrcGroups)) {
|
||||
|
||||
// Create the ssrcGroups array, if it's not defined.
|
||||
if (typeof channel.ssrcGroups === 'undefined' ||
|
||||
!Array.isArray(channel.ssrcGroups)) {
|
||||
channel.ssrcGroups = [];
|
||||
if (typeof type2bl[unifiedLine.type].ssrcGroups === 'undefined' ||
|
||||
!Array.isArray(type2bl[unifiedLine.type].ssrcGroups)) {
|
||||
type2bl[unifiedLine.type].ssrcGroups = [];
|
||||
}
|
||||
|
||||
channel.ssrcGroups = channel.ssrcGroups.concat(mLine.ssrcGroups);
|
||||
type2bl[unifiedLine.type].ssrcGroups = type2bl[unifiedLine.type].ssrcGroups.concat(unifiedLine.ssrcGroups);
|
||||
}
|
||||
|
||||
if (channels[mLine.type] === mLine) {
|
||||
if (type2bl[unifiedLine.type] === unifiedLine) {
|
||||
// Copy ICE related stuff from the principal media line.
|
||||
mLine.candidates = media[0].candidates;
|
||||
mLine.iceUfrag = media[0].iceUfrag;
|
||||
mLine.icePwd = media[0].icePwd;
|
||||
mLine.fingerprint = media[0].fingerprint;
|
||||
unifiedLine.candidates = media[0].candidates;
|
||||
unifiedLine.iceUfrag = media[0].iceUfrag;
|
||||
unifiedLine.icePwd = media[0].icePwd;
|
||||
unifiedLine.fingerprint = media[0].fingerprint;
|
||||
|
||||
// Plan B mids are in ['audio', 'video', 'data']
|
||||
mLine.mid = mLine.type;
|
||||
unifiedLine.mid = unifiedLine.type;
|
||||
|
||||
// Plan B doesn't support/need the bundle-only attribute.
|
||||
delete mLine.bundleOnly;
|
||||
delete unifiedLine.bundleOnly;
|
||||
|
||||
// In Plan B the msid is an SSRC attribute.
|
||||
delete mLine.msid;
|
||||
delete unifiedLine.msid;
|
||||
|
||||
// Used to build the group:BUNDLE value after this loop.
|
||||
types.push(mLine.type);
|
||||
types.push(unifiedLine.type);
|
||||
|
||||
// Add the channel to the new media array.
|
||||
session.media.push(mLine);
|
||||
session.media.push(unifiedLine);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -28317,34 +28425,35 @@ Interop.prototype.toUnifiedPlan = function(desc) {
|
|||
|
||||
// A helper map that sends mids to m-line objects. We use it later to
|
||||
// rebuild the Unified Plan style session.media array.
|
||||
var mid2ml = {};
|
||||
session.media.forEach(function(channel) {
|
||||
if (typeof channel.rtcpMux !== 'string' ||
|
||||
channel.rtcpMux !== 'rtcp-mux') {
|
||||
var mid2ul = {};
|
||||
session.media.forEach(function(bLine) {
|
||||
if ((typeof bLine.rtcpMux !== 'string' ||
|
||||
bLine.rtcpMux !== 'rtcp-mux') &&
|
||||
bLine.direction !== 'inactive') {
|
||||
throw new Error("Cannot convert to Unified Plan because m-lines " +
|
||||
"without the rtcp-mux attribute were found.");
|
||||
}
|
||||
|
||||
// With rtcp-mux and bundle all the channels should have the same ICE
|
||||
// stuff.
|
||||
var sources = channel.sources;
|
||||
var ssrcGroups = channel.ssrcGroups;
|
||||
var candidates = channel.candidates;
|
||||
var iceUfrag = channel.iceUfrag;
|
||||
var icePwd = channel.icePwd;
|
||||
var fingerprint = channel.fingerprint;
|
||||
var port = channel.port;
|
||||
var sources = bLine.sources;
|
||||
var ssrcGroups = bLine.ssrcGroups;
|
||||
var candidates = bLine.candidates;
|
||||
var iceUfrag = bLine.iceUfrag;
|
||||
var icePwd = bLine.icePwd;
|
||||
var fingerprint = bLine.fingerprint;
|
||||
var port = bLine.port;
|
||||
|
||||
// We'll use the "channel" object as a prototype for each new "mLine"
|
||||
// We'll use the "bLine" object as a prototype for each new "mLine"
|
||||
// that we create, but first we need to clean it up a bit.
|
||||
delete channel.sources;
|
||||
delete channel.ssrcGroups;
|
||||
delete channel.candidates;
|
||||
delete channel.iceUfrag;
|
||||
delete channel.icePwd;
|
||||
delete channel.fingerprint;
|
||||
delete channel.port;
|
||||
delete channel.mid;
|
||||
delete bLine.sources;
|
||||
delete bLine.ssrcGroups;
|
||||
delete bLine.candidates;
|
||||
delete bLine.iceUfrag;
|
||||
delete bLine.icePwd;
|
||||
delete bLine.fingerprint;
|
||||
delete bLine.port;
|
||||
delete bLine.mid;
|
||||
|
||||
// inverted ssrc group map
|
||||
var ssrc2group = {};
|
||||
|
@ -28378,11 +28487,11 @@ Interop.prototype.toUnifiedPlan = function(desc) {
|
|||
// Explode the Plan B channel sources with one m-line per source.
|
||||
Object.keys(sources).forEach(function(ssrc) {
|
||||
|
||||
// The m-line for this SSRC. We either create it from scratch
|
||||
// or, if it's a grouped SSRC, we re-use a related mline. In
|
||||
// other words, if the source is grouped with another source,
|
||||
// put the two together in the same m-line.
|
||||
var mLine;
|
||||
// The (unified) m-line for this SSRC. We either create it from
|
||||
// scratch or, if it's a grouped SSRC, we re-use a related
|
||||
// mline. In other words, if the source is grouped with another
|
||||
// source, put the two together in the same m-line.
|
||||
var unifiedLine;
|
||||
if (typeof ssrc2group[ssrc] !== 'undefined' &&
|
||||
Array.isArray(ssrc2group[ssrc])) {
|
||||
ssrc2group[ssrc].some(function (ssrcGroup) {
|
||||
|
@ -28390,21 +28499,21 @@ Interop.prototype.toUnifiedPlan = function(desc) {
|
|||
// again here.
|
||||
return ssrcGroup.ssrcs.some(function (related) {
|
||||
if (typeof ssrc2ml[related] === 'object') {
|
||||
mLine = ssrc2ml[related];
|
||||
unifiedLine = ssrc2ml[related];
|
||||
return true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof mLine === 'object') {
|
||||
if (typeof unifiedLine === 'object') {
|
||||
// the m-line already exists. Just add the source.
|
||||
mLine.sources[ssrc] = sources[ssrc];
|
||||
unifiedLine.sources[ssrc] = sources[ssrc];
|
||||
delete sources[ssrc].msid;
|
||||
} else {
|
||||
// Use the "channel" as a prototype for the "mLine".
|
||||
mLine = Object.create(channel);
|
||||
ssrc2ml[ssrc] = mLine;
|
||||
// Use the "bLine" as a prototype for the "unifiedLine".
|
||||
unifiedLine = Object.create(bLine);
|
||||
ssrc2ml[ssrc] = unifiedLine;
|
||||
|
||||
if (typeof sources[ssrc].msid !== 'undefined') {
|
||||
// Assign the msid of the source to the m-line. Note
|
||||
|
@ -28412,14 +28521,14 @@ Interop.prototype.toUnifiedPlan = function(desc) {
|
|||
// msid. In particular "recvonly" sources don't have an
|
||||
// msid. Note that "recvonly" is a term only defined
|
||||
// for m-lines.
|
||||
mLine.msid = sources[ssrc].msid;
|
||||
unifiedLine.msid = sources[ssrc].msid;
|
||||
delete sources[ssrc].msid;
|
||||
}
|
||||
|
||||
// We assign one SSRC per media line.
|
||||
mLine.sources = {};
|
||||
mLine.sources[ssrc] = sources[ssrc];
|
||||
mLine.ssrcGroups = ssrc2group[ssrc];
|
||||
unifiedLine.sources = {};
|
||||
unifiedLine.sources[ssrc] = sources[ssrc];
|
||||
unifiedLine.ssrcGroups = ssrc2group[ssrc];
|
||||
|
||||
// Use the cached Unified Plan SDP (if it exists) to assign
|
||||
// SSRCs to mids.
|
||||
|
@ -28431,14 +28540,14 @@ Interop.prototype.toUnifiedPlan = function(desc) {
|
|||
if (typeof m.sources === 'object') {
|
||||
Object.keys(m.sources).forEach(function (s) {
|
||||
if (s === ssrc) {
|
||||
mLine.mid = m.mid;
|
||||
unifiedLine.mid = m.mid;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof mLine.mid === 'undefined') {
|
||||
if (typeof unifiedLine.mid === 'undefined') {
|
||||
|
||||
// If this is an SSRC that we see for the first time
|
||||
// assign it a new mid. This is typically the case when
|
||||
|
@ -28451,23 +28560,23 @@ Interop.prototype.toUnifiedPlan = function(desc) {
|
|||
//
|
||||
// Because FF generates answers in Unified Plan style,
|
||||
// we MUST already have a cached answer with all the
|
||||
// local SSRCs mapped to some mLine/mid.
|
||||
// local SSRCs mapped to some m-line/mid.
|
||||
|
||||
if (desc.type === 'answer') {
|
||||
throw new Error("An unmapped SSRC was found.");
|
||||
}
|
||||
|
||||
mLine.mid = [channel.type, '-', ssrc].join('');
|
||||
unifiedLine.mid = [bLine.type, '-', ssrc].join('');
|
||||
}
|
||||
|
||||
// Include the candidates in the 1st media line.
|
||||
mLine.candidates = candidates;
|
||||
mLine.iceUfrag = iceUfrag;
|
||||
mLine.icePwd = icePwd;
|
||||
mLine.fingerprint = fingerprint;
|
||||
mLine.port = port;
|
||||
unifiedLine.candidates = candidates;
|
||||
unifiedLine.iceUfrag = iceUfrag;
|
||||
unifiedLine.icePwd = icePwd;
|
||||
unifiedLine.fingerprint = fingerprint;
|
||||
unifiedLine.port = port;
|
||||
|
||||
mid2ml[mLine.mid] = mLine;
|
||||
mid2ul[unifiedLine.mid] = unifiedLine;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -28481,71 +28590,57 @@ Interop.prototype.toUnifiedPlan = function(desc) {
|
|||
if (desc.type === 'answer') {
|
||||
|
||||
// The media lines in the answer must match the media lines in the
|
||||
// offer. The order is important too. Here we use the cached offer to
|
||||
// find the m-lines that are missing (from the converted answer), and
|
||||
// use the cached answer to complete the converted answer.
|
||||
// offer. The order is important too. Here we assume that Firefox is the
|
||||
// answerer, so we merely have to use the reconstructed (unified) answer
|
||||
// to update the cached (unified) answer accordingly.
|
||||
//
|
||||
// In the general case, one would have to use the cached (unified) offer
|
||||
// to find the m-lines that are missing from the reconstructed answer,
|
||||
// potentially grabbing them from the cached (unified) answer. One has
|
||||
// to be carefull with this approach because inactive m-lines do not
|
||||
// always have an mid, making it tricky (impossible?) to find where
|
||||
// exactly and which m-lines are missing from the reconstructed answer.
|
||||
|
||||
if (typeof this.cache['offer'] === 'undefined') {
|
||||
throw new Error("An answer is being processed but we couldn't " +
|
||||
"find a cached offer.");
|
||||
}
|
||||
for (var i = 0; i < cached.media.length; i++) {
|
||||
var unifiedLine = cached.media[i];
|
||||
|
||||
var cachedOffer = transform.parse(this.cache['offer']);
|
||||
if (typeof mid2ul[unifiedLine.mid] === 'undefined') {
|
||||
|
||||
if (typeof cachedOffer === 'undefined' ||
|
||||
typeof cachedOffer.media === 'undefined' ||
|
||||
!Array.isArray(cachedOffer.media)) {
|
||||
// FIXME(gp) is this really a problem in the general case?
|
||||
throw new Error("The cached offer has no media.");
|
||||
}
|
||||
|
||||
cachedOffer.media.forEach(function(mo) {
|
||||
|
||||
var mLine;
|
||||
cached.media.some(function(ma) {
|
||||
if (mo.mid == ma.mid) {
|
||||
if (typeof mid2ml[mo.mid] === 'undefined') {
|
||||
|
||||
// This is either an m-line containing a remote
|
||||
// track only, or an m-line containing a remote
|
||||
// The mid isn't in the reconstructed (unified) answer.
|
||||
// This is either a (unified) m-line containing a remote
|
||||
// track only, or a (unified) m-line containing a remote
|
||||
// track and a local track that has been removed.
|
||||
// In either case, it MUST exist in the cached
|
||||
// answer.
|
||||
// (unified) answer.
|
||||
//
|
||||
// In case this is a removed local track, clean-up
|
||||
// the m-line and make sure it's 'recvonly'.
|
||||
// the (unified) m-line and make sure it's 'recvonly' or
|
||||
// 'inactive'.
|
||||
|
||||
// TODO sendonly -> inactive makes more sense.
|
||||
delete ma.msid;
|
||||
delete ma.sources;
|
||||
delete ma.ssrcGroups;
|
||||
if (!ma.direction
|
||||
|| ma.direction === 'sendonly'
|
||||
|| ma.direction === 'sendrecv')
|
||||
ma.direction = 'recvonly';
|
||||
delete unifiedLine.msid;
|
||||
delete unifiedLine.sources;
|
||||
delete unifiedLine.ssrcGroups;
|
||||
if (!unifiedLine.direction
|
||||
|| unifiedLine.direction === 'sendrecv')
|
||||
unifiedLine.direction = 'recvonly';
|
||||
if (!unifiedLine.direction
|
||||
|| unifiedLine.direction === 'sendonly')
|
||||
unifiedLine.direction = 'inactive';
|
||||
} else {
|
||||
// This is an m-line/channel that contains a local
|
||||
// track (sendrecv or sendonly channel) or it's a
|
||||
// This is an (unified) m-line/channel that contains a local
|
||||
// track (sendrecv or sendonly channel) or it's a unified
|
||||
// recvonly m-line/channel. In either case, since we're
|
||||
// going from PlanB -> Unified Plan this m-line MUST
|
||||
// exist in the cached answer.
|
||||
}
|
||||
|
||||
// assign the found object.
|
||||
mLine = ma;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
session.media.push(unifiedLine);
|
||||
|
||||
if (typeof mLine === 'undefined') {
|
||||
throw new Error("The cached offer contains an m-line that " +
|
||||
"doesn't exist neither in the cached answer nor in " +
|
||||
"the converted answer.");
|
||||
if (typeof unifiedLine.mid === 'string') {
|
||||
// inactive lines don't/may not have an mid.
|
||||
mids.push(unifiedLine.mid);
|
||||
}
|
||||
}
|
||||
|
||||
session.media.push(mLine);
|
||||
mids.push(mLine.mid);
|
||||
});
|
||||
} else {
|
||||
|
||||
// SDP offer/answer (and the JSEP spec) forbids removing an m-section
|
||||
|
@ -28559,41 +28654,48 @@ Interop.prototype.toUnifiedPlan = function(desc) {
|
|||
if (typeof cached !== 'undefined' &&
|
||||
typeof cached.media !== 'undefined' &&
|
||||
Array.isArray(cached.media)) {
|
||||
cached.media.forEach(function(pm) {
|
||||
mids.push(pm.mid);
|
||||
if (typeof mid2ml[pm.mid] !== 'undefined') {
|
||||
session.media.push(mid2ml[pm.mid]);
|
||||
cached.media.forEach(function(unifiedLine) {
|
||||
mids.push(unifiedLine.mid);
|
||||
if (typeof mid2ul[unifiedLine.mid] !== 'undefined') {
|
||||
session.media.push(mid2ul[unifiedLine.mid]);
|
||||
} else {
|
||||
delete pm.msid;
|
||||
delete pm.sources;
|
||||
delete pm.ssrcGroups;
|
||||
pm.direction = 'recvonly';
|
||||
session.media.push(pm);
|
||||
delete unifiedLine.msid;
|
||||
delete unifiedLine.sources;
|
||||
delete unifiedLine.ssrcGroups;
|
||||
if (!unifiedLine.direction
|
||||
|| unifiedLine.direction === 'sendrecv')
|
||||
unifiedLine.direction = 'recvonly';
|
||||
if (!unifiedLine.direction
|
||||
|| unifiedLine.direction === 'sendonly')
|
||||
unifiedLine.direction = 'inactive';
|
||||
session.media.push(unifiedLine);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add all the remaining (new) m-lines of the transformed SDP.
|
||||
Object.keys(mid2ml).forEach(function(mid) {
|
||||
Object.keys(mid2ul).forEach(function(mid) {
|
||||
if (mids.indexOf(mid) === -1) {
|
||||
mids.push(mid);
|
||||
if (typeof mid2ml[mid].msid === 'undefined') {
|
||||
if (typeof mid2ul[mid].direction === 'recvonly') {
|
||||
// This is a remote recvonly channel. Add its SSRC to the
|
||||
// sendrecv channel.
|
||||
// TODO(gp) what if there is no sendrecv channel?
|
||||
session.media.some(function (ml) {
|
||||
if (ml.direction === 'sendrecv' && ml.type == mid2ml[mid].type) {
|
||||
// appropriate sendrecv or sendonly channel.
|
||||
// TODO(gp) what if we don't have sendrecv/sendonly channel?
|
||||
session.media.some(function (unifiedLine) {
|
||||
if ((unifiedLine.direction === 'sendrecv' ||
|
||||
unifiedLine.direction === 'sendonly') &&
|
||||
unifiedLine.type === mid2ul[mid].type) {
|
||||
|
||||
// this shouldn't have any ssrc-groups
|
||||
Object.keys(mid2ml[mid].sources).forEach(function (ssrc) {
|
||||
ml.sources[ssrc] = mid2ml[mid].sources[ssrc];
|
||||
// mid2ul[mid] shouldn't have any ssrc-groups
|
||||
Object.keys(mid2ul[mid].sources).forEach(function (ssrc) {
|
||||
unifiedLine.sources[ssrc] = mid2ul[mid].sources[ssrc];
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
session.media.push(mid2ml[mid]);
|
||||
session.media.push(mid2ul[mid]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -29388,7 +29490,8 @@ var XMPPEvents = {
|
|||
AUTHENTICATION_REQUIRED: "xmpp.authentication_required",
|
||||
CHAT_ERROR_RECEIVED: "xmpp.chat_error_received",
|
||||
ETHERPAD: "xmpp.etherpad",
|
||||
DEVICE_AVAILABLE: "xmpp.device_available"
|
||||
DEVICE_AVAILABLE: "xmpp.device_available",
|
||||
START_MUTED: "xmpp.start_muted"
|
||||
};
|
||||
module.exports = XMPPEvents;
|
||||
},{}],106:[function(require,module,exports){
|
||||
|
|
Loading…
Reference in New Issue