Fixes SSRC=1 issue. Renames VideoSSRCHack to LocalSSRCReplacement.
This commit is contained in:
parent
ab4c29eddc
commit
fb875423a9
|
@ -7,7 +7,7 @@ var async = require("async");
|
||||||
var transform = require("sdp-transform");
|
var transform = require("sdp-transform");
|
||||||
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
|
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
|
||||||
var RTCBrowserType = require("../RTC/RTCBrowserType");
|
var RTCBrowserType = require("../RTC/RTCBrowserType");
|
||||||
var VideoSSRCHack = require("./VideoSSRCHack");
|
var SSRCReplacement = require("./LocalSSRCReplacement");
|
||||||
|
|
||||||
// Jingle stuff
|
// Jingle stuff
|
||||||
function JingleSession(me, sid, connection, service, eventEmitter) {
|
function JingleSession(me, sid, connection, service, eventEmitter) {
|
||||||
|
@ -254,7 +254,7 @@ JingleSession.prototype.accept = function () {
|
||||||
//console.log('setLocalDescription success');
|
//console.log('setLocalDescription success');
|
||||||
self.setLocalDescription();
|
self.setLocalDescription();
|
||||||
|
|
||||||
VideoSSRCHack.processSessionInit(accept);
|
SSRCReplacement.processSessionInit(accept);
|
||||||
|
|
||||||
self.connection.sendIQ(accept,
|
self.connection.sendIQ(accept,
|
||||||
function () {
|
function () {
|
||||||
|
@ -348,7 +348,7 @@ JingleSession.prototype.sendIceCandidate = function (candidate) {
|
||||||
self.initiator == self.me ? 'initiator' : 'responder',
|
self.initiator == self.me ? 'initiator' : 'responder',
|
||||||
ssrc);
|
ssrc);
|
||||||
|
|
||||||
VideoSSRCHack.processSessionInit(init);
|
SSRCReplacement.processSessionInit(init);
|
||||||
|
|
||||||
self.connection.sendIQ(init,
|
self.connection.sendIQ(init,
|
||||||
function () {
|
function () {
|
||||||
|
@ -467,7 +467,7 @@ JingleSession.prototype.createdOffer = function (sdp) {
|
||||||
this.initiator == this.me ? 'initiator' : 'responder',
|
this.initiator == this.me ? 'initiator' : 'responder',
|
||||||
this.localStreamsSSRC);
|
this.localStreamsSSRC);
|
||||||
|
|
||||||
VideoSSRCHack.processSessionInit(init);
|
SSRCReplacement.processSessionInit(init);
|
||||||
|
|
||||||
self.connection.sendIQ(init,
|
self.connection.sendIQ(init,
|
||||||
function () {
|
function () {
|
||||||
|
@ -733,7 +733,7 @@ JingleSession.prototype.createdAnswer = function (sdp, provisional) {
|
||||||
self.initiator == self.me ? 'initiator' : 'responder',
|
self.initiator == self.me ? 'initiator' : 'responder',
|
||||||
ssrcs);
|
ssrcs);
|
||||||
|
|
||||||
VideoSSRCHack.processSessionInit(accept);
|
SSRCReplacement.processSessionInit(accept);
|
||||||
|
|
||||||
self.connection.sendIQ(accept,
|
self.connection.sendIQ(accept,
|
||||||
function () {
|
function () {
|
||||||
|
@ -1135,7 +1135,7 @@ JingleSession.prototype.notifyMySSRCUpdate = function (old_sdp, new_sdp) {
|
||||||
// Let 'source-remove' IQ through the hack and see if we're allowed to send
|
// Let 'source-remove' IQ through the hack and see if we're allowed to send
|
||||||
// it in the current form
|
// it in the current form
|
||||||
if (removed)
|
if (removed)
|
||||||
remove = VideoSSRCHack.processSourceRemove(remove);
|
remove = SSRCReplacement.processSourceRemove(remove);
|
||||||
|
|
||||||
if (removed && remove) {
|
if (removed && remove) {
|
||||||
console.info("Sending source-remove", remove);
|
console.info("Sending source-remove", remove);
|
||||||
|
@ -1166,7 +1166,7 @@ JingleSession.prototype.notifyMySSRCUpdate = function (old_sdp, new_sdp) {
|
||||||
// Let 'source-add' IQ through the hack and see if we're allowed to send
|
// Let 'source-add' IQ through the hack and see if we're allowed to send
|
||||||
// it in the current form
|
// it in the current form
|
||||||
if (added)
|
if (added)
|
||||||
add = VideoSSRCHack.processSourceAdd(add);
|
add = SSRCReplacement.processSourceAdd(add);
|
||||||
|
|
||||||
if (added && add) {
|
if (added && add) {
|
||||||
console.info("Sending source-add", add);
|
console.info("Sending source-add", add);
|
||||||
|
|
|
@ -1,8 +1,21 @@
|
||||||
/* global $ */
|
/* global $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The purpose of this hack is to re-use SSRC of first video stream ever created
|
Here we do modifications of local video SSRCs. There are 2 situations we have
|
||||||
for any video streams created later on. In order to do that this hack:
|
to handle:
|
||||||
|
|
||||||
|
1. We generate SSRC for local recvonly video stream. This is the case when we
|
||||||
|
have no local camera and it is not generated automatically, but SSRC=1 is
|
||||||
|
used implicitly. If that happens RTCP packets will be dropped by the JVB
|
||||||
|
and we won't be able to request video key frames correctly.
|
||||||
|
|
||||||
|
2. A hack to re-use SSRC of the first video stream for any new stream created
|
||||||
|
in future. It turned out that Chrome may keep on using the SSRC of removed
|
||||||
|
video stream in RTCP even though a new one has been created. So we just
|
||||||
|
want to avoid that by re-using it. Jingle 'source-remove'/'source-add'
|
||||||
|
notifications are blocked once first video SSRC is advertised to the focus.
|
||||||
|
|
||||||
|
What this hack does:
|
||||||
|
|
||||||
1. Stores the SSRC of the first video stream created by
|
1. Stores the SSRC of the first video stream created by
|
||||||
a) scanning Jingle session-accept/session-invite for existing video SSRC
|
a) scanning Jingle session-accept/session-invite for existing video SSRC
|
||||||
|
@ -33,6 +46,18 @@ var isEnabled = !RTCBrowserType.isFirefox();
|
||||||
*/
|
*/
|
||||||
var localVideoSSRC;
|
var localVideoSSRC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSRC used for recvonly video stream when we have no local camera.
|
||||||
|
* This is in order to tell Chrome what SSRC should be used in RTCP requests
|
||||||
|
* instead of 1.
|
||||||
|
*/
|
||||||
|
var localRecvOnlySSRC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cname for <tt>localRecvOnlySSRC</tt>
|
||||||
|
*/
|
||||||
|
var localRecvOnlyCName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method removes <source> element which describes <tt>localVideoSSRC</tt>
|
* Method removes <source> element which describes <tt>localVideoSSRC</tt>
|
||||||
* from given Jingle IQ.
|
* from given Jingle IQ.
|
||||||
|
@ -79,21 +104,41 @@ var storeLocalVideoSSRC = function (jingleIq) {
|
||||||
$(jingleIq.tree())
|
$(jingleIq.tree())
|
||||||
.find('>jingle>content[name="video"]>description>source');
|
.find('>jingle>content[name="video"]>description>source');
|
||||||
|
|
||||||
console.info('Video desc: ', videoSSRCs);
|
videoSSRCs.each(function (idx, ssrcElem) {
|
||||||
if (!videoSSRCs.length)
|
if (localVideoSSRC)
|
||||||
return;
|
return;
|
||||||
|
// We consider SSRC real only if it has msid attribute
|
||||||
var ssrc = videoSSRCs.attr('ssrc');
|
// recvonly streams in FF do not have it as well as local SSRCs
|
||||||
if (ssrc) {
|
// we generate for recvonly streams in Chrome
|
||||||
localVideoSSRC = ssrc;
|
var ssrSel = $(ssrcElem);
|
||||||
console.info(
|
var msid = ssrSel.find('>parameter[name="msid"]');
|
||||||
'Stored local video SSRC for future re-use: ' + localVideoSSRC);
|
if (msid.length) {
|
||||||
} else {
|
var ssrcVal = ssrSel.attr('ssrc');
|
||||||
console.error('No "ssrc" attribute present in <source> element');
|
if (ssrcVal) {
|
||||||
}
|
localVideoSSRC = ssrcVal;
|
||||||
|
console.info('Stored local video SSRC' +
|
||||||
|
' for future re-use: ' + localVideoSSRC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var LocalVideoSSRCHack = {
|
/**
|
||||||
|
* Generates new SSRC for local video recvonly stream.
|
||||||
|
* FIXME what about eventual SSRC collision ?
|
||||||
|
*/
|
||||||
|
function generateRecvonlySSRC() {
|
||||||
|
//
|
||||||
|
localRecvOnlySSRC =
|
||||||
|
Math.random().toString(10).substring(2, 11);
|
||||||
|
localRecvOnlyCName =
|
||||||
|
Math.random().toString(36).substring(2);
|
||||||
|
console.info(
|
||||||
|
"Generated local recvonly SSRC: " + localRecvOnlySSRC +
|
||||||
|
", cname: " + localRecvOnlyCName);
|
||||||
|
}
|
||||||
|
|
||||||
|
var LocalSSRCReplacement = {
|
||||||
/**
|
/**
|
||||||
* Method must be called before 'session-initiate' or 'session-invite' is
|
* Method must be called before 'session-initiate' or 'session-invite' is
|
||||||
* sent. Scans the IQ for local video SSRC and stores it if detected.
|
* sent. Scans the IQ for local video SSRC and stores it if detected.
|
||||||
|
@ -144,6 +189,25 @@ var LocalVideoSSRCHack = {
|
||||||
new RegExp('a=ssrc:' + newSSRC, 'g'),
|
new RegExp('a=ssrc:' + newSSRC, 'g'),
|
||||||
'a=ssrc:' + localVideoSSRC);
|
'a=ssrc:' + localVideoSSRC);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Make sure we have any SSRC for recvonly video stream
|
||||||
|
var sdp = new SDP(localDescription.sdp);
|
||||||
|
|
||||||
|
if (sdp.media[1] && sdp.media[1].indexOf('a=ssrc:') === -1 &&
|
||||||
|
sdp.media[1].indexOf('a=recvonly') !== -1) {
|
||||||
|
|
||||||
|
if (!localRecvOnlySSRC) {
|
||||||
|
generateRecvonlySSRC();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info('No SSRC in video recvonly stream' +
|
||||||
|
' - adding SSRC: ' + localRecvOnlySSRC);
|
||||||
|
|
||||||
|
sdp.media[1] += 'a=ssrc:' + localRecvOnlySSRC +
|
||||||
|
' cname:' + localRecvOnlyCName + '\r\n';
|
||||||
|
|
||||||
|
localDescription.sdp = sdp.session + sdp.media.join('');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return localDescription;
|
return localDescription;
|
||||||
},
|
},
|
||||||
|
@ -196,4 +260,4 @@ var LocalVideoSSRCHack = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = LocalVideoSSRCHack;
|
module.exports = LocalSSRCReplacement;
|
|
@ -1,7 +1,7 @@
|
||||||
var RTC = require('../RTC/RTC');
|
var RTC = require('../RTC/RTC');
|
||||||
var RTCBrowserType = require("../RTC/RTCBrowserType.js");
|
var RTCBrowserType = require("../RTC/RTCBrowserType.js");
|
||||||
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
|
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
|
||||||
var VideoSSRCHack = require("./VideoSSRCHack");
|
var SSRCReplacement = require("./LocalSSRCReplacement");
|
||||||
|
|
||||||
function TraceablePeerConnection(ice_config, constraints, session) {
|
function TraceablePeerConnection(ice_config, constraints, session) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -213,7 +213,7 @@ if (TraceablePeerConnection.prototype.__defineGetter__ !== undefined) {
|
||||||
function() {
|
function() {
|
||||||
var desc = this.peerconnection.localDescription;
|
var desc = this.peerconnection.localDescription;
|
||||||
|
|
||||||
desc = VideoSSRCHack.mungeLocalVideoSSRC(desc);
|
desc = SSRCReplacement.mungeLocalVideoSSRC(desc);
|
||||||
|
|
||||||
this.trace('getLocalDescription::preTransform', dumpSDP(desc));
|
this.trace('getLocalDescription::preTransform', dumpSDP(desc));
|
||||||
|
|
||||||
|
@ -372,7 +372,7 @@ TraceablePeerConnection.prototype.createOffer
|
||||||
self.trace('createOfferOnSuccess::postTransform (Plan B)', dumpSDP(offer));
|
self.trace('createOfferOnSuccess::postTransform (Plan B)', dumpSDP(offer));
|
||||||
}
|
}
|
||||||
|
|
||||||
offer = VideoSSRCHack.mungeLocalVideoSSRC(offer);
|
offer = SSRCReplacement.mungeLocalVideoSSRC(offer);
|
||||||
|
|
||||||
if (config.enableSimulcast && self.simulcast.isSupported()) {
|
if (config.enableSimulcast && self.simulcast.isSupported()) {
|
||||||
offer = self.simulcast.mungeLocalDescription(offer);
|
offer = self.simulcast.mungeLocalDescription(offer);
|
||||||
|
@ -402,7 +402,7 @@ TraceablePeerConnection.prototype.createAnswer
|
||||||
}
|
}
|
||||||
|
|
||||||
// munge local video SSRC
|
// munge local video SSRC
|
||||||
answer = VideoSSRCHack.mungeLocalVideoSSRC(answer);
|
answer = SSRCReplacement.mungeLocalVideoSSRC(answer);
|
||||||
|
|
||||||
if (config.enableSimulcast && self.simulcast.isSupported()) {
|
if (config.enableSimulcast && self.simulcast.isSupported()) {
|
||||||
answer = self.simulcast.mungeLocalDescription(answer);
|
answer = self.simulcast.mungeLocalDescription(answer);
|
||||||
|
|
Loading…
Reference in New Issue