diff --git a/index.html b/index.html
index ec31263ac..ebd29b67d 100644
--- a/index.html
+++ b/index.html
@@ -11,8 +11,8 @@
-
-
+
+
@@ -22,7 +22,7 @@
-
+
diff --git a/libs/colibri/colibri.focus.js b/libs/colibri/colibri.focus.js
index 87b92ab1b..46c761203 100644
--- a/libs/colibri/colibri.focus.js
+++ b/libs/colibri/colibri.focus.js
@@ -551,82 +551,8 @@ ColibriFocus.prototype.createdConference = function (result) {
console.log('setLocalDescription succeeded.');
// make sure our presence is updated
$(document).trigger('setLocalDescription.jingle', [self.sid]);
- var elem = $iq({to: self.bridgejid, type: 'get'});
- elem.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: self.confid});
var localSDP = new SDP(self.peerconnection.localDescription.sdp);
- localSDP.media.forEach(function (media, channel) {
- var name = SDPUtil.parse_mid(SDPUtil.find_line(media, 'a=mid:'));
- elem.c('content', {name: name});
- var mline = SDPUtil.parse_mline(media.split('\r\n')[0]);
- if (name !== 'data')
- {
- elem.c('channel', {
- initiator: 'true',
- expire: self.channelExpire,
- id: self.mychannel[channel].attr('id'),
- endpoint: self.myMucResource
- });
-
- // signal (through COLIBRI) to the bridge
- // the SSRC groups of the participant
- // that plays the role of the focus
- var ssrc_group_lines = SDPUtil.find_lines(media, 'a=ssrc-group:');
- var idx = 0;
- ssrc_group_lines.forEach(function(line) {
- idx = line.indexOf(' ');
- var semantics = line.substr(0, idx).substr(13);
- var ssrcs = line.substr(14 + semantics.length).split(' ');
- if (ssrcs.length != 0) {
- elem.c('ssrc-group', { semantics: semantics, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
- ssrcs.forEach(function(ssrc) {
- elem.c('source', { ssrc: ssrc })
- .up();
- });
- elem.up();
- }
- });
- // FIXME: should reuse code from .toJingle
- for (var j = 0; j < mline.fmt.length; j++)
- {
- var rtpmap = SDPUtil.find_line(media, 'a=rtpmap:' + mline.fmt[j]);
- if (rtpmap)
- {
- elem.c('payload-type', SDPUtil.parse_rtpmap(rtpmap));
- elem.up();
- }
- }
- }
- else
- {
- var sctpmap = SDPUtil.find_line(media, 'a=sctpmap:' + mline.fmt[0]);
- var sctpPort = SDPUtil.parse_sctpmap(sctpmap)[0];
- elem.c("sctpconnection",
- {
- initiator: 'true',
- expire: self.channelExpire,
- id: self.mychannel[channel].attr('id'),
- endpoint: self.myMucResource,
- port: sctpPort
- }
- );
- }
-
- localSDP.TransportToJingle(channel, elem);
-
- elem.up(); // end of channel
- elem.up(); // end of content
- });
-
- self.connection.sendIQ(elem,
- function (result) {
- // ...
- },
- function (error) {
- console.error(
- "ERROR sending colibri message",
- error, elem);
- }
- );
+ self.updateLocalChannel(localSDP);
// now initiate sessions
for (var i = 0; i < numparticipants; i++) {
@@ -659,6 +585,96 @@ ColibriFocus.prototype.createdConference = function (result) {
};
+ColibriFocus.prototype.updateLocalChannel = function(localSDP, parts) {
+ var self = this;
+ var elem = $iq({to: self.bridgejid, type: 'get'});
+ elem.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: self.confid});
+ localSDP.media.forEach(function (media, channel) {
+ var name = SDPUtil.parse_mid(SDPUtil.find_line(media, 'a=mid:'));
+ elem.c('content', {name: name});
+ var mline = SDPUtil.parse_mline(media.split('\r\n')[0]);
+ if (name !== 'data') {
+ elem.c('channel', {
+ initiator: 'true',
+ expire: self.channelExpire,
+ id: self.mychannel[channel].attr('id'),
+ endpoint: self.myMucResource
+ });
+
+ if (!parts || parts.indexOf('sources') !== -1) {
+ // signal (through COLIBRI) to the bridge
+ // the SSRC groups of the participant
+ // that plays the role of the focus
+ var ssrc_group_lines = SDPUtil.find_lines(media, 'a=ssrc-group:');
+ var idx = 0;
+ var hasSIM = false;
+ ssrc_group_lines.forEach(function (line) {
+ idx = line.indexOf(' ');
+ var semantics = line.substr(0, idx).substr(13);
+ var ssrcs = line.substr(14 + semantics.length).split(' ');
+ if (ssrcs.length != 0) {
+ elem.c('ssrc-group', { semantics: semantics, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
+ ssrcs.forEach(function (ssrc) {
+ elem.c('source', { ssrc: ssrc })
+ .up();
+ });
+ elem.up();
+ }
+ });
+
+ if (!hasSIM && name == 'video') {
+ // disable simulcast with an empty ssrc-group element.
+ elem.c('ssrc-group', { semantics: 'SIM', xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
+ elem.up();
+ }
+ }
+
+ if (!parts || parts.indexOf('payload-type') !== -1) {
+ // FIXME: should reuse code from .toJingle
+ for (var j = 0; j < mline.fmt.length; j++) {
+ var rtpmap = SDPUtil.find_line(media, 'a=rtpmap:' + mline.fmt[j]);
+ if (rtpmap) {
+ elem.c('payload-type', SDPUtil.parse_rtpmap(rtpmap));
+ elem.up();
+ }
+ }
+ }
+ }
+ else
+ {
+ var sctpmap = SDPUtil.find_line(media, 'a=sctpmap:' + mline.fmt[0]);
+ var sctpPort = SDPUtil.parse_sctpmap(sctpmap)[0];
+ elem.c("sctpconnection",
+ {
+ initiator: 'true',
+ expire: self.channelExpire,
+ id: self.mychannel[channel].attr('id'),
+ endpoint: self.myMucResource,
+ port: sctpPort
+ }
+ );
+ }
+
+ if (!parts || parts.indexOf('transport') !== -1) {
+ localSDP.TransportToJingle(channel, elem);
+ }
+
+ elem.up(); // end of channel
+ elem.up(); // end of content
+ });
+
+ self.connection.sendIQ(elem,
+ function (result) {
+ // ...
+ },
+ function (error) {
+ console.error(
+ "ERROR sending colibri message",
+ error, elem);
+ }
+ );
+};
+
// send a session-initiate to a new participant
ColibriFocus.prototype.initiate = function (peer, isInitiator) {
var participant = this.peers.indexOf(peer);
@@ -894,61 +910,73 @@ ColibriFocus.prototype.addNewParticipant = function (peer) {
};
// update the channel description (payload-types + dtls fp) for a participant
-ColibriFocus.prototype.updateChannel = function (remoteSDP, participant) {
+ColibriFocus.prototype.updateRemoteChannel = function (remoteSDP, participant, parts) {
console.log('change allocation for', this.confid);
var self = this;
var change = $iq({to: this.bridgejid, type: 'set'});
change.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: this.confid});
- for (channel = 0; channel < this.channels[participant].length; channel++)
- {
+ for (channel = 0; channel < this.channels[participant].length; channel++) {
if (!remoteSDP.media[channel])
continue;
var name = SDPUtil.parse_mid(SDPUtil.find_line(remoteSDP.media[channel], 'a=mid:'));
change.c('content', {name: name});
- if (name !== 'data')
- {
+ if (name !== 'data') {
change.c('channel', {
id: $(this.channels[participant][channel]).attr('id'),
endpoint: $(this.channels[participant][channel]).attr('endpoint'),
expire: self.channelExpire
});
- // signal (throught COLIBRI) to the bridge the SSRC groups of this
- // participant
- var ssrc_group_lines = SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc-group:');
- var idx = 0;
- ssrc_group_lines.forEach(function(line) {
- idx = line.indexOf(' ');
- var semantics = line.substr(0, idx).substr(13);
- var ssrcs = line.substr(14 + semantics.length).split(' ');
- if (ssrcs.length != 0) {
- change.c('ssrc-group', { semantics: semantics, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
- ssrcs.forEach(function(ssrc) {
- change.c('source', { ssrc: ssrc })
- .up();
- });
+ if (!parts || parts.indexOf('sources') !== -1) {
+ // signal (throught COLIBRI) to the bridge the SSRC groups of this
+ // participant
+ var ssrc_group_lines = SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc-group:');
+ var idx = 0;
+ var hasSIM = false;
+ ssrc_group_lines.forEach(function (line) {
+ idx = line.indexOf(' ');
+ var semantics = line.substr(0, idx).substr(13);
+ if (semantics == 'SIM') {
+ hasSIM = true;
+ }
+ var ssrcs = line.substr(14 + semantics.length).split(' ');
+ if (ssrcs.length != 0) {
+ change.c('ssrc-group', { semantics: semantics, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
+ ssrcs.forEach(function (ssrc) {
+ change.c('source', { ssrc: ssrc })
+ .up();
+ });
+ change.up();
+ }
+ });
+
+ if (!hasSIM && name == 'video') {
+ // disable simulcast with an empty ssrc-group element.
+ change.c('ssrc-group', { semantics: 'SIM', xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
change.up();
}
- });
+ }
- var rtpmap = SDPUtil.find_lines(remoteSDP.media[channel], 'a=rtpmap:');
- rtpmap.forEach(function (val) {
- // TODO: too much copy-paste
- var rtpmap = SDPUtil.parse_rtpmap(val);
- change.c('payload-type', rtpmap);
- //
- // put any 'a=fmtp:' + mline.fmt[j] lines into
- /*
- if (SDPUtil.find_line(remoteSDP.media[channel], 'a=fmtp:' + rtpmap.id)) {
- tmp = SDPUtil.parse_fmtp(SDPUtil.find_line(remoteSDP.media[channel], 'a=fmtp:' + rtpmap.id));
- for (var k = 0; k < tmp.length; k++) {
- change.c('parameter', tmp[k]).up();
- }
- }
- */
- change.up();
- });
+ if (!parts || parts.indexOf('payload-type') !== -1) {
+ var rtpmap = SDPUtil.find_lines(remoteSDP.media[channel], 'a=rtpmap:');
+ rtpmap.forEach(function (val) {
+ // TODO: too much copy-paste
+ var rtpmap = SDPUtil.parse_rtpmap(val);
+ change.c('payload-type', rtpmap);
+ //
+ // put any 'a=fmtp:' + mline.fmt[j] lines into
+ /*
+ if (SDPUtil.find_line(remoteSDP.media[channel], 'a=fmtp:' + rtpmap.id)) {
+ tmp = SDPUtil.parse_fmtp(SDPUtil.find_line(remoteSDP.media[channel], 'a=fmtp:' + rtpmap.id));
+ for (var k = 0; k < tmp.length; k++) {
+ change.c('parameter', tmp[k]).up();
+ }
+ }
+ */
+ change.up();
+ });
+ }
}
else
{
@@ -960,8 +988,11 @@ ColibriFocus.prototype.updateChannel = function (remoteSDP, participant) {
port: SDPUtil.parse_sctpmap(sctpmap)[0]
});
}
- // now add transport
- remoteSDP.TransportToJingle(channel, change);
+
+ if (!parts || parts.indexOf('transport') !== -1) {
+ // now add transport
+ remoteSDP.TransportToJingle(channel, change);
+ }
change.up(); // end of channel/sctpconnection
change.up(); // end of content
@@ -976,6 +1007,57 @@ ColibriFocus.prototype.updateChannel = function (remoteSDP, participant) {
);
};
+/**
+ * Switches video streams.
+ * @param new_stream new stream that will be used as video of this session.
+ * @param oldStream old video stream of this session.
+ * @param success_callback callback executed after successful stream switch.
+ */
+ColibriFocus.prototype.switchStreams = function (new_stream, oldStream, success_callback) {
+
+ var self = this;
+
+ // Stop the stream to trigger onended event for old stream
+ oldStream.stop();
+
+ // Remember SDP to figure out added/removed SSRCs
+ var oldSdp = null;
+ if(self.peerconnection) {
+ if(self.peerconnection.localDescription) {
+ oldSdp = new SDP(self.peerconnection.localDescription.sdp);
+ }
+ self.peerconnection.removeStream(oldStream);
+ self.peerconnection.addStream(new_stream);
+ }
+
+ self.connection.jingle.localVideo = new_stream;
+
+ self.connection.jingle.localStreams = [];
+ self.connection.jingle.localStreams.push(self.connection.jingle.localAudio);
+ self.connection.jingle.localStreams.push(self.connection.jingle.localVideo);
+
+ // Conference is not active
+ if(!oldSdp || !self.peerconnection) {
+ success_callback();
+ return;
+ }
+
+ self.peerconnection.switchstreams = true;
+ self.modifySources(function() {
+ console.log('modify sources done');
+
+ var newSdp = new SDP(self.peerconnection.localDescription.sdp);
+
+ // change allocation on bridge
+ self.updateLocalChannel(newSdp, ['sources']);
+
+ console.log("SDPs", oldSdp, newSdp);
+ self.notifyMySSRCUpdate(oldSdp, newSdp);
+
+ success_callback();
+ });
+};
+
// tell everyone about a new participants a=ssrc lines (isadd is true)
// or a leaving participants a=ssrc lines
ColibriFocus.prototype.sendSSRCUpdate = function (sdpMediaSsrcs, fromJid, isadd) {
@@ -1010,7 +1092,7 @@ ColibriFocus.prototype.addSource = function (elem, fromJid) {
// FIXME: dirty waiting
if (!this.peerconnection.localDescription)
{
- console.warn("addSource - localDescription not ready yet")
+ console.warn("addSource - localDescription not ready yet");
setTimeout(function() { self.addSource(elem, fromJid); }, 200);
return;
}
@@ -1031,11 +1113,21 @@ ColibriFocus.prototype.addSource = function (elem, fromJid) {
});
var oldRemoteSdp = new SDP(this.peerconnection.remoteDescription.sdp);
- this.modifySources(function(){
+ this.modifySources(function() {
// Notify other participants about added ssrc
var remoteSDP = new SDP(self.peerconnection.remoteDescription.sdp);
var newSSRCs = oldRemoteSdp.getNewMedia(remoteSDP);
self.sendSSRCUpdate(newSSRCs, fromJid, true);
+ // change allocation on bridge
+ if (peerSsrc[1] /* video */) {
+ // If the remote peer has changed its video sources, then we need to
+ // update the bridge with this information, in order for the
+ // simulcast manager of the remote peer to update its layers, and
+ // any associated receivers to adjust to the change.
+ var videoSDP = new SDP(['v=0', 'm=audio', 'a=mid:audio', peerSsrc[0]].join('\r\n') + ['m=video', 'a=mid:video', peerSsrc[1]].join('\r\n'));
+ var participant = self.peers.indexOf(fromJid);
+ self.updateRemoteChannel(videoSDP, participant, ['sources']);
+ }
});
};
@@ -1073,6 +1165,16 @@ ColibriFocus.prototype.removeSource = function (elem, fromJid) {
var remoteSDP = new SDP(self.peerconnection.remoteDescription.sdp);
var removedSSRCs = remoteSDP.getNewMedia(oldSDP);
self.sendSSRCUpdate(removedSSRCs, fromJid, false);
+ // change allocation on bridge
+ if (peerSsrc[1] /* video */) {
+ // If the remote peer has changed its video sources, then we need to
+ // update the bridge with this information, in order for the
+ // simulcast manager of the remote peer to update its layers, and
+ // any associated receivers to adjust to the change.
+ var videoSDP = new SDP(['v=0', 'm=audio', 'a=mid:audio', peerSsrc[0]].join('\r\n') + ['m=video', 'a=mid:video', peerSsrc[1]].join('\r\n'));
+ var participant = self.peers.indexOf(fromJid);
+ self.updateRemoteChannel(videoSDP, participant, ['sources']);
+ }
});
};
@@ -1084,7 +1186,7 @@ ColibriFocus.prototype.setRemoteDescription = function (session, elem, desctype)
remoteSDP.fromJingle(elem);
// ACT 1: change allocation on bridge
- this.updateChannel(remoteSDP, participant);
+ this.updateRemoteChannel(remoteSDP, participant);
// ACT 2: tell anyone else about the new SSRCs
this.sendSSRCUpdate(remoteSDP.getMediaSsrcMap(), session.peerjid, true);
diff --git a/libs/strophe/strophe.jingle.adapter.js b/libs/strophe/strophe.jingle.adapter.js
index f36cb1752..d0f4847f6 100644
--- a/libs/strophe/strophe.jingle.adapter.js
+++ b/libs/strophe/strophe.jingle.adapter.js
@@ -140,11 +140,13 @@ if (TraceablePeerConnection.prototype.__defineGetter__ !== undefined) {
TraceablePeerConnection.prototype.addStream = function (stream) {
this.trace('addStream', stream.id);
+ simulcast.resetSender();
this.peerconnection.addStream(stream);
};
TraceablePeerConnection.prototype.removeStream = function (stream) {
this.trace('removeStream', stream.id);
+ simulcast.resetSender();
this.peerconnection.removeStream(stream);
};
@@ -204,7 +206,7 @@ TraceablePeerConnection.prototype.enqueueAddSsrc = function(channel, ssrcLines)
this.addssrc[channel] = '';
}
this.addssrc[channel] += ssrcLines;
-}
+};
TraceablePeerConnection.prototype.addSource = function (elem) {
console.log('addssrc', new Date().getTime());
@@ -260,7 +262,7 @@ TraceablePeerConnection.prototype.enqueueRemoveSsrc = function(channel, ssrcLine
this.removessrc[channel] = '';
}
this.removessrc[channel] += ssrcLines;
-}
+};
TraceablePeerConnection.prototype.removeSource = function (elem) {
console.log('removessrc', new Date().getTime());
diff --git a/libs/strophe/strophe.jingle.sdp.js b/libs/strophe/strophe.jingle.sdp.js
index af99e30e2..a185aebb5 100644
--- a/libs/strophe/strophe.jingle.sdp.js
+++ b/libs/strophe/strophe.jingle.sdp.js
@@ -42,7 +42,7 @@ SDP.prototype.getMediaSsrcMap = function() {
});
}
return media_ssrcs;
-}
+};
/**
* Returns true if this SDP contains given SSRC.
* @param ssrc the ssrc to check.
@@ -59,7 +59,8 @@ SDP.prototype.containsSSRC = function(ssrc) {
}
});
return contains;
-}
+};
+
/**
* Returns map of MediaChannel that contains only media not contained in otherSdp. Mapped by channel idx.
* @param otherSdp the other SDP to check ssrc with.
@@ -89,7 +90,7 @@ SDP.prototype.getNewMedia = function(otherSdp) {
}
}
return true;
- };
+ }
var myMedia = this.getMediaSsrcMap();
var othersMedia = otherSdp.getMediaSsrcMap();
@@ -111,7 +112,7 @@ SDP.prototype.getNewMedia = function(otherSdp) {
}
newMedia[channelNum].ssrcs[ssrc] = othersChannel.ssrcs[ssrc];
}
- })
+ });
// Look for new ssrc groups across the channels
othersChannel.ssrcGroups.forEach(function(otherSsrcGroup){
@@ -120,7 +121,7 @@ SDP.prototype.getNewMedia = function(otherSdp) {
var matched = false;
for (var i = 0; i < myChannel.ssrcGroups.length; i++) {
var mySsrcGroup = myChannel.ssrcGroups[i];
- if (otherSsrcGroup.semantics == mySsrcGroup
+ if (otherSsrcGroup.semantics == mySsrcGroup.semantics
&& arrayEquals.apply(otherSsrcGroup.ssrcs, [mySsrcGroup.ssrcs])) {
matched = true;
@@ -140,7 +141,8 @@ SDP.prototype.getNewMedia = function(otherSdp) {
});
});
return newMedia;
-}
+};
+
// remove iSAC and CN from SDP
SDP.prototype.mangle = function () {
var i, j, mline, lines, rtpmap, newdesc;
diff --git a/simulcast.js b/simulcast.js
index 7bccfe226..860b9fa43 100644
--- a/simulcast.js
+++ b/simulcast.js
@@ -490,7 +490,6 @@ function SimulcastSender() {
this.logger = new SimulcastLogger('SimulcastSender', 1);
}
-SimulcastSender.prototype._localVideoSourceCache = '';
SimulcastSender.prototype.displayedLocalVideoStream = null;
SimulcastSender.prototype._generateGuid = (function () {
@@ -506,14 +505,6 @@ SimulcastSender.prototype._generateGuid = (function () {
};
}());
-SimulcastSender.prototype._cacheLocalVideoSources = function (lines) {
- this._localVideoSourceCache = this.simulcastUtils._getVideoSources(lines);
-};
-
-SimulcastSender.prototype._restoreLocalVideoSources = function (lines) {
- this.simulcastUtils._replaceVideoSources(lines, this._localVideoSourceCache);
-};
-
// Returns a random integer between min (included) and max (excluded)
// Using Math.round() gives a non-uniform distribution!
SimulcastSender.prototype._generateRandomSSRC = function () {
@@ -521,7 +512,37 @@ SimulcastSender.prototype._generateRandomSSRC = function () {
return Math.floor(Math.random() * (max - min)) + min;
};
-SimulcastSender.prototype._appendSimulcastGroup = function (lines) {
+SimulcastSender.prototype.getLocalVideoStream = function () {
+ return (this.displayedLocalVideoStream != null)
+ ? this.displayedLocalVideoStream
+ // in case we have no simulcast at all, i.e. we didn't perform the GUM
+ : connection.jingle.localVideo;
+};
+
+function NativeSimulcastSender() {
+ SimulcastSender.call(this); // call the super constructor.
+}
+
+NativeSimulcastSender.prototype = Object.create(SimulcastSender.prototype);
+
+NativeSimulcastSender.prototype._localExplosionMap = {};
+NativeSimulcastSender.prototype._isUsingScreenStream = false;
+NativeSimulcastSender.prototype._localVideoSourceCache = '';
+
+NativeSimulcastSender.prototype.reset = function () {
+ this._localExplosionMap = {};
+ this._isUsingScreenStream = isUsingScreenStream;
+};
+
+NativeSimulcastSender.prototype._cacheLocalVideoSources = function (lines) {
+ this._localVideoSourceCache = this.simulcastUtils._getVideoSources(lines);
+};
+
+NativeSimulcastSender.prototype._restoreLocalVideoSources = function (lines) {
+ this.simulcastUtils._replaceVideoSources(lines, this._localVideoSourceCache);
+};
+
+NativeSimulcastSender.prototype._appendSimulcastGroup = function (lines) {
var videoSources, ssrcGroup, simSSRC, numOfSubs = 2, i, sb, msid;
this.logger.info('Appending simulcast group...');
@@ -557,7 +578,7 @@ SimulcastSender.prototype._appendSimulcastGroup = function (lines) {
};
// Does the actual patching.
-SimulcastSender.prototype._ensureSimulcastGroup = function (lines) {
+NativeSimulcastSender.prototype._ensureSimulcastGroup = function (lines) {
this.logger.info('Ensuring simulcast group...');
@@ -571,21 +592,6 @@ SimulcastSender.prototype._ensureSimulcastGroup = function (lines) {
}
};
-SimulcastSender.prototype.getLocalVideoStream = function () {
- return (this.displayedLocalVideoStream != null)
- ? this.displayedLocalVideoStream
- // in case we have no simulcast at all, i.e. we didn't perform the GUM
- : connection.jingle.localVideo;
-};
-
-function NativeSimulcastSender() {
- SimulcastSender.call(this); // call the super constructor.
-}
-
-NativeSimulcastSender.prototype = Object.create(SimulcastSender.prototype);
-
-NativeSimulcastSender.prototype._localExplosionMap = {};
-
/**
* Produces a single stream with multiple tracks for local video sources.
*
@@ -658,7 +664,7 @@ NativeSimulcastSender.prototype.getUserMedia = function (constraints, success, e
NativeSimulcastSender.prototype.reverseTransformLocalDescription = function (desc) {
var sb;
- if (!desc || desc == null) {
+ if (!desc || desc == null || this._isUsingScreenStream) {
return desc;
}
@@ -686,6 +692,10 @@ NativeSimulcastSender.prototype.reverseTransformLocalDescription = function (des
*/
NativeSimulcastSender.prototype.transformAnswer = function (desc) {
+ if (!desc || desc == null || this._isUsingScreenStream) {
+ return desc;
+ }
+
var sb = desc.sdp.split('\r\n');
// Even if we have enabled native simulcasting previously
@@ -734,7 +744,8 @@ SimulcastReceiver.prototype.transformRemoteDescription = function (desc) {
this._updateRemoteMaps(sb);
this._cacheRemoteVideoSources(sb);
- // NOTE(gp) this needs to be called after updateRemoteMaps because we need the simulcast group in the _updateRemoteMaps() method.
+ // NOTE(gp) this needs to be called after updateRemoteMaps because we
+ // need the simulcast group in the _updateRemoteMaps() method.
this.simulcastUtils._removeSimulcastGroup(sb);
if (desc.sdp.indexOf('a=ssrc-group:SIM') !== -1) {
@@ -1189,6 +1200,12 @@ SimulcastManager.prototype._setLocalVideoStreamEnabled = function(ssrc, enabled)
this.simulcastSender._setLocalVideoStreamEnabled(ssrc, enabled);
};
+SimulcastManager.prototype.resetSender = function() {
+ if (typeof this.simulcastSender.reset === 'function'){
+ this.simulcastSender.reset();
+ }
+};
+
/**
*
* @constructor