Fixes desktop sharing when used with simulcast.
This commit is contained in:
parent
ee1c221e6d
commit
a0092b78ca
|
@ -11,8 +11,8 @@
|
|||
<meta itemprop="image" content="/images/jitsilogo.png"/>
|
||||
<script src="libs/jquery-2.1.1.min.js"></script>
|
||||
<script src="config.js?v=5"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
|
||||
<script src="simulcast.js?v=6"></script><!-- simulcast handling -->
|
||||
<script src="libs/strophe/strophe.jingle.adapter.js?v=2"></script><!-- strophe.jingle bundles -->
|
||||
<script src="simulcast.js?v=7"></script><!-- simulcast handling -->
|
||||
<script src="libs/strophe/strophe.jingle.adapter.js?v=3"></script><!-- strophe.jingle bundles -->
|
||||
<script src="libs/strophe/strophe.min.js?v=1"></script>
|
||||
<script src="libs/strophe/strophe.disco.min.js?v=1"></script>
|
||||
<script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>
|
||||
|
@ -22,7 +22,7 @@
|
|||
<script src="libs/strophe/strophe.jingle.sessionbase.js?v=1"></script>
|
||||
<script src="libs/strophe/strophe.jingle.session.js?v=2"></script>
|
||||
<script src="libs/strophe/strophe.util.js"></script>
|
||||
<script src="libs/colibri/colibri.focus.js?v=11"></script><!-- colibri focus implementation -->
|
||||
<script src="libs/colibri/colibri.focus.js?v=12"></script><!-- colibri focus implementation -->
|
||||
<script src="libs/colibri/colibri.session.js?v=1"></script>
|
||||
<script src="libs/jquery-ui.js"></script>
|
||||
<script src="libs/rayo.js?v=1"></script>
|
||||
|
|
|
@ -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,33 +910,36 @@ 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
|
||||
});
|
||||
|
||||
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' });
|
||||
|
@ -932,6 +951,14 @@ ColibriFocus.prototype.updateChannel = function (remoteSDP, participant) {
|
|||
}
|
||||
});
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -950,6 +977,7 @@ ColibriFocus.prototype.updateChannel = function (remoteSDP, participant) {
|
|||
change.up();
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var sctpmap = SDPUtil.find_line(remoteSDP.media[channel], 'a=sctpmap:');
|
||||
|
@ -960,8 +988,11 @@ ColibriFocus.prototype.updateChannel = function (remoteSDP, participant) {
|
|||
port: SDPUtil.parse_sctpmap(sctpmap)[0]
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -1036,6 +1118,16 @@ ColibriFocus.prototype.addSource = function (elem, fromJid) {
|
|||
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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -42,7 +42,7 @@ SDP.prototype.getMediaSsrcMap = function() {
|
|||
});
|
||||
}
|
||||
return media_ssrcs;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Returns <tt>true</tt> 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 <tt>otherSdp</tt>. 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;
|
||||
|
|
73
simulcast.js
73
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
|
||||
|
|
Loading…
Reference in New Issue