[Pkg-voip-commits] [janus] 08/163: Several simulcast related fixes (third substream, REMB, etc.)
Jonas Smedegaard
dr at jones.dk
Sat Oct 28 01:22:03 UTC 2017
This is an automated email from the git hooks/post-receive script.
js pushed a commit to annotated tag debian/0.2.5-1
in repository janus.
commit 460a64319542c49620d3a056d7188dc85cd46bc0
Merge: 3e01d6e cad85c9
Author: Lorenzo Miniero <lminiero at gmail.com>
Date: Wed Jun 28 20:34:24 2017 +0200
Several simulcast related fixes (third substream, REMB, etc.)
dtls.c | 23 +++---
html/admin.js | 199 ++++++++++++++++++++++++++++++++++++++++++-----
html/devicetest.html | 5 +-
html/devicetest.js | 27 +++++--
html/echotest.html | 5 +-
html/echotest.js | 28 ++++++-
html/janus.js | 124 ++++++++++-------------------
html/janus.nojquery.js | 108 +++++++------------------
html/siptest.js | 21 ++++-
html/videocalltest.js | 3 +-
html/videoroomtest.js | 3 +-
ice.c | 170 +++++++++++++++++++++++++++++++---------
ice.h | 6 +-
janus.c | 4 +
plugins/janus_echotest.c | 85 ++++++++++++--------
plugins/janus_sip.c | 148 ++++++++++++++++++++++-------------
rtcp.c | 25 ++++--
rtcp.h | 12 ++-
sdp-utils.c | 2 -
19 files changed, 661 insertions(+), 337 deletions(-)
diff --cc html/devicetest.html
index 798a54c,8872892..de54a53
--- a/html/devicetest.html
+++ b/html/devicetest.html
@@@ -120,12 -118,6 +120,13 @@@
<h3 class="panel-title">Remote Stream
<span class="label label-primary hide" id="curres"></span>
<span class="label label-info hide" id="curbitrate"></span>
+ <div id="simulcast" class="btn-group btn-group-xs pull-right hide">
+ <div class="btn-group btn-group-xs">
- <button id="sl-1" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to higher quality" style="width: 50%">SL 1</button>
- <button id="sl-0" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to lower quality" style="width: 50%">SL 0</button>
++ <button id="sl-2" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to higher quality" style="width: 33%">SL 2</button>
++ <button id="sl-1" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to normal quality" style="width: 33%">SL 1</button>
++ <button id="sl-0" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to lower quality" style="width: 34%">SL 0</button>
+ </div>
+ </div>
<div class="btn-group btn-group-xs pull-right hide" id="output-devices">
<div class="btn-group btn-group-xs">
<button id="outputdeviceset" autocomplete="off" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
diff --cc html/devicetest.js
index 07f5f8c,9d0ab12..9383910
--- a/html/devicetest.js
+++ b/html/devicetest.js
@@@ -267,39 -261,6 +265,56 @@@ $(document).ready(function()
$('#outputdeviceset').html('Output device<span class="caret"></span>');
}
}
+ // Is simulcast in place?
+ var simulcast = msg["simulcast"];
+ if(simulcast !== null && simulcast !== undefined) {
+ if(!simulcastStarted) {
+ simulcastStarted = true;
+ $('#simulcast').removeClass('hide');
+ // Enable the VP8 simulcast selection buttons
+ $('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
+ .unbind('click').click(function() {
+ toastr.info("Switching simulcast video, wait for it... (lower quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
+ echotest.send({message: { simulcast: 0}});
+ });
+ $('#sl-1').removeClass('btn-primary btn-success').addClass('btn-success')
+ .unbind('click').click(function() {
- toastr.info("Switching simulcast video, wait for it... (higher quality)", null, {timeOut: 2000});
++ toastr.info("Switching simulcast video, wait for it... (normal quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
+ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ echotest.send({message: { simulcast: 1}});
+ });
++ $('#sl-2').removeClass('btn-primary btn-success').addClass('btn-success')
++ .unbind('click').click(function() {
++ toastr.info("Switching simulcast video, wait for it... (higher quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
++ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
++ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
++ echotest.send({message: { simulcast: 1}});
++ });
+ }
+ // We just received notice that there's been a switch, update the buttons
+ if(simulcast === 0) {
+ toastr.success("Switched simulcast video! (lower quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
+ } else if(simulcast === 1) {
- toastr.success("Switched simulcast video! (higher quality)", null, {timeOut: 2000});
++ toastr.success("Switched simulcast video! (normal quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
+ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
++ } else if(simulcast === 2) {
++ toastr.success("Switched simulcast video! (higher quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
++ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
++ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ }
+ }
},
onlocalstream: function(stream) {
Janus.debug(" ::: Got a local stream :::");
@@@ -449,10 -411,6 +465,11 @@@
$('#datasend').val('').attr('disabled', true);
$('#datarecv').val('');
$('#outputdeviceset').html('Output device<span class="caret"></span>');
+ simulcastStarted = false;
+ $('#simulcast').addClass('hide');
+ $('#sl-0').unbind('click');
+ $('#sl-1').unbind('click');
++ $('#sl-2').unbind('click');
}
});
},
diff --cc html/echotest.html
index f9e576a,8308399..8542315
--- a/html/echotest.html
+++ b/html/echotest.html
@@@ -109,14 -104,7 +109,15 @@@
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
- <h3 class="panel-title">Remote Stream <span class="label label-primary hide" id="curres"></span> <span class="label label-info hide" id="curbitrate"></span></h3>
+ <h3 class="panel-title">Remote Stream <span class="label label-primary hide" id="curres"></span> <span class="label label-info hide" id="curbitrate"></span>
+ <div id="simulcast" class="btn-group btn-group-xs pull-right hide">
+ <div class="btn-group btn-group-xs">
- <button id="sl-1" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to higher quality" style="width: 50%">SL 1</button>
- <button id="sl-0" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to lower quality" style="width: 50%">SL 0</button>
++ <button id="sl-2" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to higher quality" style="width: 33%">SL 2</button>
++ <button id="sl-1" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to normal quality" style="width: 33%">SL 1</button>
++ <button id="sl-0" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to lower quality" style="width: 34%">SL 0</button>
+ </div>
+ </div>
+ </h3>
</div>
<div class="panel-body" id="videoright"></div>
</div>
diff --cc html/echotest.js
index c98b866,1e2201e..9d53c6d
--- a/html/echotest.js
+++ b/html/echotest.js
@@@ -189,39 -185,6 +189,56 @@@ $(document).ready(function()
$('#curres').hide();
}
}
+ // Is simulcast in place?
+ var simulcast = msg["simulcast"];
+ if(simulcast !== null && simulcast !== undefined) {
+ if(!simulcastStarted) {
+ simulcastStarted = true;
+ $('#simulcast').removeClass('hide');
+ // Enable the VP8 simulcast selection buttons
+ $('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
+ .unbind('click').click(function() {
+ toastr.info("Switching simulcast video, wait for it... (lower quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
+ echotest.send({message: { simulcast: 0}});
+ });
+ $('#sl-1').removeClass('btn-primary btn-success').addClass('btn-success')
+ .unbind('click').click(function() {
- toastr.info("Switching simulcast video, wait for it... (higher quality)", null, {timeOut: 2000});
++ toastr.info("Switching simulcast video, wait for it... (normal quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
+ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ echotest.send({message: { simulcast: 1}});
+ });
++ $('#sl-2').removeClass('btn-primary btn-success').addClass('btn-success')
++ .unbind('click').click(function() {
++ toastr.info("Switching simulcast video, wait for it... (higher quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
++ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
++ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
++ echotest.send({message: { simulcast: 2}});
++ });
+ }
+ // We just received notice that there's been a switch, update the buttons
+ if(simulcast === 0) {
+ toastr.success("Switched simulcast video! (lower quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
+ } else if(simulcast === 1) {
- toastr.success("Switched simulcast video! (higher quality)", null, {timeOut: 2000});
++ toastr.success("Switched simulcast video! (normal quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
+ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
++ } else if(simulcast === 2) {
++ toastr.success("Switched simulcast video! (higher quality)", null, {timeOut: 2000});
++ $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
++ $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
++ $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ }
+ }
},
onlocalstream: function(stream) {
Janus.debug(" ::: Got a local stream :::");
@@@ -361,6 -325,6 +379,10 @@@
$('#curbitrate').hide();
$('#curres').hide();
$('#datasend').attr('disabled', true);
++ $('#simulcast').addClass('hide');
++ $('#sl-0').unbind('click');
++ $('#sl-1').unbind('click');
++ $('#sl-2').unbind('click');
}
});
},
diff --cc html/janus.js
index 46d1e54,5f642e2..79e512e
--- a/html/janus.js
+++ b/html/janus.js
@@@ -1402,6 -1403,6 +1403,9 @@@ function Janus(gatewayCallbacks)
}
var videoSupport = isVideoSendEnabled(media);
if(videoSupport === true && media != undefined && media != null) {
++ var simulcast = callbacks.simulcast === true ? true : false;
++ if(simulcast && !jsep && (media.video === undefined || media.video === false))
++ media.video = "hires";
if(media.video && media.video != 'screen' && media.video != 'window') {
var width = 0;
var height = 0, maxHeight = 0;
@@@ -1731,8 -1732,7 +1735,12 @@@
return;
}
var config = pluginHandle.webrtcStuff;
- Janus.log("Creating offer (iceDone=" + config.iceDone + ")");
+ var simulcast = callbacks.simulcast === true ? true : false;
- Janus.log("Creating offer (iceDone=" + config.iceDone + ", simulcast=" + simulcast + ")");
++ if(!simulcast) {
++ Janus.log("Creating offer (iceDone=" + config.iceDone + ")");
++ } else {
++ Janus.log("Creating offer (iceDone=" + config.iceDone + ", simulcast=" + simulcast + ")");
++ }
// https://code.google.com/p/webrtc/issues/detail?id=3508
var mediaConstraints = null;
if(adapter.browserDetails.browser == "firefox" || adapter.browserDetails.browser == "edge") {
@@@ -1749,129 -1749,11 +1757,129 @@@
};
}
Janus.debug(mediaConstraints);
+ // Check if this is Firefox and we've been asked to do simulcasting
+ if(simulcast && adapter.browserDetails.browser === "firefox") {
+ // FIXME Based on https://gist.github.com/voluntas/088bc3cc62094730647b
+ Janus.log("Enabling Simulcasting for Firefox (RID)");
+ var sender = config.pc.getSenders()[1];
+ Janus.log(sender);
+ var parameters = sender.getParameters();
+ Janus.log(parameters);
+ sender.setParameters({encodings: [
+ { rid: "high", active: true, priority: "high", maxBitrate: 2000000 },
- { rid: "medium", active: true, priority: "medium", maxBitrate: 200000 }
++ { rid: "medium", active: true, priority: "medium", maxBitrate: 400000 },
++ { rid: "low", active: true, priority: "medium", maxBitrate: 200000 }
+ ]});
+ }
config.pc.createOffer(
function(offer) {
Janus.debug(offer);
if(config.mySdp === null || config.mySdp === undefined) {
Janus.log("Setting local description");
+ if(simulcast) {
+ // This SDP munging only works with Chrome
+ if(adapter.browserDetails.browser === "chrome") {
+ Janus.log("Enabling Simulcasting for Chrome (SDP munging)");
+ // Let's munge the SDP to add the attributes for enabling simulcasting
+ // (based on https://gist.github.com/ggarber/a19b4c33510028b9c657)
+ var lines = offer.sdp.split("\r\n");
+ var video = false;
+ var ssrc = [ -1 ], ssrc_fid = -1;
+ var cname = null, msid = null, mslabel = null, label = null;
+ var insertAt = -1;
+ for(var i=0; i<lines.length; i++) {
+ var mline = lines[i].match(/m=(\w+) */);
+ if(mline) {
+ var medium = mline[1];
+ if(medium === "video") {
+ // New video m-line: make sure it's the first one
+ if(ssrc[0] < 0) {
+ video = true;
+ } else {
+ // We're done, let's add the new attributes here
+ insertAt = i;
+ break;
+ }
+ } else {
+ // New non-video m-line: do we have what we were looking for?
+ if(ssrc[0] > -1) {
+ // We're done, let's add the new attributes here
+ insertAt = i;
+ break;
+ }
+ }
+ continue;
+ }
+ var fid = lines[i].match(/a=ssrc-group:FID (\d+) (\d+)/);
+ if(fid) {
+ ssrc[0] = fid[1];
+ ssrc_fid = fid[2];
+ lines.splice(i, 1); i--;
+ continue;
+ }
+ if(ssrc[0]) {
+ var match = lines[i].match('a=ssrc:' + ssrc[0] + ' cname:(.+)')
+ if(match) {
+ cname = match[1];
+ }
+ match = lines[i].match('a=ssrc:' + ssrc[0] + ' msid:(.+)')
+ if(match) {
+ msid = match[1];
+ }
+ match = lines[i].match('a=ssrc:' + ssrc[0] + ' mslabel:(.+)')
+ if(match) {
+ mslabel = match[1];
+ }
+ match = lines[i].match('a=ssrc:' + ssrc + ' label:(.+)')
+ if(match) {
+ label = match[1];
+ }
+ if(lines[i].indexOf('a=ssrc:' + ssrc_fid) === 0) {
+ lines.splice(i, 1); i--;
+ continue;
+ }
+ if(lines[i].indexOf('a=ssrc:' + ssrc[0]) === 0) {
+ lines.splice(i, 1); i--;
+ continue;
+ }
+ }
+ if(lines[i].length == 0) {
+ lines.splice(i, 1); i--;
+ continue;
+ }
+ }
+ if(insertAt < 0) {
+ // Append at the end
+ insertAt = lines.length-1;
+ }
+ // Generate a couple of SSRCs
+ ssrc[1] = Math.floor(Math.random()*0xFFFFFFFF);
+ ssrc[2] = Math.floor(Math.random()*0xFFFFFFFF);
+ // Add attributes to the SDP
- lines.splice(insertAt, 0, 'a=ssrc-group:SIM ' + ssrc[0] + ' ' + ssrc[1] + ' ' + ssrc[2]);
- insertAt++;
+ for(var i=0; i<ssrc.length; i++) {
+ if(cname) {
+ lines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' cname:' + cname);
+ insertAt++;
+ }
+ if(msid) {
+ lines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' msid:' + msid);
+ insertAt++;
+ }
+ if(mslabel) {
+ lines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' mslabel:' + msid);
+ insertAt++;
+ }
+ if(label) {
+ lines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' label:' + msid);
+ insertAt++;
+ }
+ }
++ lines.splice(insertAt, 0, 'a=ssrc-group:SIM ' + ssrc[0] + ' ' + ssrc[1] + ' ' + ssrc[2]);
+ offer.sdp = lines.join("\r\n");
+ } else if(adapter.browserDetails.browser !== "firefox") {
+ Janus.warn("simulcast=true, but this is not Chrome nor Firefox, ignoring");
+ }
+ }
config.mySdp = offer.sdp;
config.pc.setLocalDescription(offer);
}
diff --cc ice.c
index 49afd90,600be4f..141f810
--- a/ice.c
+++ b/ice.c
@@@ -2193,7 -2241,7 +2260,19 @@@ void janus_ice_cb_nice_recv(NiceAgent *
} else {
/* Check the remote SSRC, compare it to what we have */
guint32 rtcp_ssrc = janus_rtcp_get_sender_ssrc(buf, len);
-- video = (stream->video_ssrc_peer == rtcp_ssrc ? 1 : 0);
++ if(rtcp_ssrc == stream->audio_ssrc_peer) {
++ video = 0;
++ } else if(rtcp_ssrc == stream->video_ssrc_peer) {
++ video = 1;
++ } else {
++ /* If we're simulcasting, let's compare to the other SSRCs too */
++ if((stream->video_ssrc_peer_sim_1 && rtcp_ssrc == stream->video_ssrc_peer_sim_1) ||
++ (stream->video_ssrc_peer_sim_1 && rtcp_ssrc == stream->video_ssrc_peer_sim_1)) {
++ /* FIXME RTCP for simulcasting SSRC, let's drop it for now... */
++ JANUS_LOG(LOG_HUGE, "Dropping RTCP packet for SSRC %"SCNu32"\n", rtcp_ssrc);
++ return;
++ }
++ }
JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (remote SSRC: video=%"SCNu32", audio=%"SCNu32", got %"SCNu32")\n",
handle->handle_id, video ? "video" : "audio", stream->video_ssrc_peer, stream->audio_ssrc_peer, rtcp_ssrc);
}
@@@ -3601,6 -3654,6 +3690,17 @@@ void *janus_ice_send_thread(void *data
}
/* Append REMB */
memcpy(rtcpbuf+rrlen, pkt->data, pkt->length);
++ /* If we're simulcasting, set the extra SSRCs (the first one will be set by janus_rtcp_fix_ssrc) */
++ if(stream->video_ssrc_peer_sim_1 && pkt->length >= 28) {
++ rtcp_fb *rtcpfb = (rtcp_fb *)(rtcpbuf+rrlen);
++ rtcp_remb *remb = (rtcp_remb *)rtcpfb->fci;
++ remb->ssrc[1] = htonl(stream->video_ssrc_peer_sim_1);
++ JANUS_LOG(LOG_WARN, "Setting SSRC #2 in REMB: %"SCNu32"\n", stream->video_ssrc_peer_sim_1);
++ if(stream->video_ssrc_peer_sim_2 && pkt->length >= 32) {
++ remb->ssrc[2] = htonl(stream->video_ssrc_peer_sim_2);
++ JANUS_LOG(LOG_WARN, "Setting SSRC #3 in REMB: %"SCNu32"\n", stream->video_ssrc_peer_sim_2);
++ }
++ }
/* Free old packet and update */
char *prev_data = pkt->data;
pkt->data = rtcpbuf;
diff --cc plugins/janus_echotest.c
index 34ea725,7fbb3d1..dd36c1e
--- a/plugins/janus_echotest.c
+++ b/plugins/janus_echotest.c
@@@ -449,9 -434,7 +449,12 @@@ json_t *janus_echotest_query_session(ja
json_object_set_new(info, "audio_active", session->audio_active ? json_true() : json_false());
json_object_set_new(info, "video_active", session->video_active ? json_true() : json_false());
json_object_set_new(info, "bitrate", json_integer(session->bitrate));
- if(session->ssrc[0] != 0)
- if(session->arc || session->vrc || session->drc) {
++ if(session->ssrc[0] != 0) {
+ json_object_set_new(info, "simulcast", json_true());
++ json_object_set_new(info, "simulcast-level", json_integer(session->simulcast));
++ json_object_set_new(info, "simulcast-target", json_integer(session->simulcast_target));
++ }
+ if(session->arc || session->vrc[0] || session->drc) {
json_t *recording = json_object();
if(session->arc && session->arc->filename)
json_object_set_new(recording, "audio", json_string(session->arc->filename));
@@@ -515,74 -494,11 +518,77 @@@ void janus_echotest_incoming_rtp(janus_
}
if(session->destroyed)
return;
- if((!video && session->audio_active) || (video && session->video_active)) {
+ if(video && session->video_active && session->rtpmapid_extmap_id != -1) {
+ /* FIXME Experiments with Firefox simulcasting */
+ rtp_header *header = (rtp_header *)buf;
+ uint32_t seq_number = ntohs(header->seq_number);
+ uint32_t timestamp = ntohl(header->timestamp);
+ uint32_t ssrc = ntohl(header->ssrc);
+ char sdes_item[16];
+ if(janus_rtp_header_extension_parse_rtp_stream_id(buf, len, session->rtpmapid_extmap_id, sdes_item, sizeof(sdes_item)) == 0) {
- JANUS_LOG(LOG_DBG, "%"SCNu32"/%"SCNu16"/%"SCNu32": RTP stream ID extension: %s\n", ssrc, seq_number, timestamp, sdes_item);
++ JANUS_LOG(LOG_DBG, "%"SCNu32"/%"SCNu16"/%"SCNu32"/%d: RTP stream ID extension: %s\n",
++ ssrc, seq_number, timestamp, header->padding, sdes_item);
+ }
+ }
+ if(video && session->video_active && session->ssrc[0] != 0) {
+ /* Handle simulcast: don't relay if it's not the SSRC we wanted to handle */
+ rtp_header *header = (rtp_header *)buf;
+ uint32_t seq_number = ntohs(header->seq_number);
+ uint32_t timestamp = ntohl(header->timestamp);
+ uint32_t ssrc = ntohl(header->ssrc);
/* Save the frame if we're recording */
- janus_recorder_save_frame(video ? session->vrc : session->arc, buf, len);
+ if(ssrc == session->ssrc[0])
+ janus_recorder_save_frame(session->vrc[0], buf, len);
+ else if(ssrc == session->ssrc[1])
+ janus_recorder_save_frame(session->vrc[1], buf, len);
+ else if(ssrc == session->ssrc[2])
+ janus_recorder_save_frame(session->vrc[2], buf, len);
+ /* Access the packet payload */
+ int plen = 0;
+ char *payload = janus_rtp_payload(buf, len, &plen);
+ if(payload == NULL)
+ return;
+ gboolean switched = FALSE;
+ if(session->simulcast != session->simulcast_target) {
+ /* There has been a change: let's wait for a keyframe on the target */
+ if(ssrc == session->ssrc[session->simulcast_target]) {
+ if(janus_vp8_is_keyframe(payload, plen)) {
- JANUS_LOG(LOG_WARN, "Received keyframe on SSRC %"SCNu32", switching (was %"SCNu32")\n",
- ssrc, session->ssrc[session->simulcast]);
++ uint32_t ssrc_old = 0;
++ if(session->simulcast != -1)
++ ssrc_old = session->ssrc[session->simulcast];
++ JANUS_LOG(LOG_WARN, "Received keyframe on SSRC %"SCNu32", switching (was %"SCNu32")\n", ssrc, ssrc_old);
+ session->simulcast = session->simulcast_target;
+ switched = TRUE;
+ /* Notify the user */
+ json_t *event = json_object();
+ json_object_set_new(event, "echotest", json_string("event"));
+ json_object_set_new(event, "simulcast", json_integer(session->simulcast));
+ gateway->push_event(session->handle, &janus_echotest_plugin, NULL, event, NULL);
+ json_decref(event);
+ } else {
+ JANUS_LOG(LOG_WARN, "Not a keyframe on SSRC %"SCNu32" yet, waiting before switching\n", ssrc);
+ }
+ }
+ }
+ if(ssrc != session->ssrc[session->simulcast]) {
+ JANUS_LOG(LOG_HUGE, "Dropping packet (it's from SSRC %"SCNu32", but we're only relaying SSRC %"SCNu32" now\n",
+ ssrc, session->ssrc[session->simulcast]);
+ return;
+ }
+ janus_rtp_header_update(header, &session->context, TRUE, 4500);
+ janus_vp8_simulcast_descriptor_update(payload, plen, &session->simulcast_context, switched);
/* Send the frame back */
gateway->relay_rtp(handle, video, buf, len);
+ /* Restore header or core statistics will be messed up */
+ header->timestamp = htonl(timestamp);
+ header->seq_number = htons(seq_number);
+ } else {
+ if((!video && session->audio_active) || (video && session->video_active)) {
+ /* Save the frame if we're recording */
+ janus_recorder_save_frame(video ? session->vrc[0] : session->arc, buf, len);
+ /* Send the frame back */
+ gateway->relay_rtp(handle, video, buf, len);
+ }
}
}
}
@@@ -664,9 -580,9 +670,14 @@@ void janus_echotest_slow_link(janus_plu
JANUS_LOG(LOG_WARN, "Getting a lot of NACKs (slow %s) for %s, forcing a lower REMB: %"SCNu64"\n",
uplink ? "uplink" : "downlink", video ? "video" : "audio", session->bitrate);
/* ... and send a new REMB back */
-- char rtcpbuf[24];
-- janus_rtcp_remb((char *)(&rtcpbuf), 24, session->bitrate);
-- gateway->relay_rtcp(handle, 1, rtcpbuf, 24);
++ char rtcpbuf[32];
++ int numssrc = 1;
++ if(session->ssrc[1])
++ numssrc++;
++ if(session->ssrc[2])
++ numssrc++;
++ int remblen = janus_rtcp_remb_ssrcs((char *)(&rtcpbuf), sizeof(rtcpbuf), session->bitrate, numssrc);
++ gateway->relay_rtcp(handle, 1, rtcpbuf, remblen);
/* As a last thing, notify the user about this */
json_t *event = json_object();
json_object_set_new(event, "echotest", json_string("event"));
@@@ -870,11 -754,11 +881,15 @@@ static void *janus_echotest_handler(voi
JANUS_LOG(LOG_VERB, "Setting video bitrate: %"SCNu64"\n", session->bitrate);
if(session->bitrate > 0) {
/* FIXME Generate a new REMB (especially useful for Firefox, which doesn't send any we can cap later) */
-- char buf[24];
-- memset(buf, 0, 24);
-- janus_rtcp_remb((char *)&buf, 24, session->bitrate);
++ char rtcpbuf[32];
++ int numssrc = 1;
++ if(session->ssrc[1])
++ numssrc++;
++ if(session->ssrc[2])
++ numssrc++;
++ int remblen = janus_rtcp_remb_ssrcs((char *)(&rtcpbuf), sizeof(rtcpbuf), session->bitrate, numssrc);
JANUS_LOG(LOG_VERB, "Sending REMB\n");
-- gateway->relay_rtcp(session->handle, 1, buf, 24);
++ gateway->relay_rtcp(session->handle, 1, rtcpbuf, remblen);
/* FIXME How should we handle a subsequent "no limit" bitrate? */
}
}
@@@ -967,21 -828,6 +982,25 @@@
/* FIXME We should notify the fact the recorder could not be created */
JANUS_LOG(LOG_ERR, "Couldn't open an video recording file for this EchoTest user!\n");
}
+ if(session->ssrc[0] != 0) {
+ /* Create recordings for the other layers as well */
- g_snprintf(filename, 255, "%s-video-sim1", recording_base);
- session->vrc[1] = janus_recorder_create(NULL, "vp8", filename);
- if(session->vrc[1] == NULL) {
- /* FIXME We should notify the fact the recorder could not be created */
- JANUS_LOG(LOG_ERR, "Couldn't open an video recording file (simulcasting #1) for this EchoTest user!\n");
++ if(session->ssrc[1] != 0) {
++ g_snprintf(filename, 255, "%s-video-sim1", recording_base);
++ session->vrc[1] = janus_recorder_create(NULL, "vp8", filename);
++ if(session->vrc[1] == NULL) {
++ /* FIXME We should notify the fact the recorder could not be created */
++ JANUS_LOG(LOG_ERR, "Couldn't open an video recording file (simulcasting #1) for this EchoTest user!\n");
++ }
+ }
- g_snprintf(filename, 255, "%s-video-sim2", recording_base);
- session->vrc[2] = janus_recorder_create(NULL, "vp8", filename);
- if(session->vrc[2] == NULL) {
- /* FIXME We should notify the fact the recorder could not be created */
- JANUS_LOG(LOG_ERR, "Couldn't open an video recording file (simulcasting #2) for this EchoTest user!\n");
++ if(session->ssrc[2] != 0) {
++ g_snprintf(filename, 255, "%s-video-sim2", recording_base);
++ session->vrc[2] = janus_recorder_create(NULL, "vp8", filename);
++ if(session->vrc[2] == NULL) {
++ /* FIXME We should notify the fact the recorder could not be created */
++ JANUS_LOG(LOG_ERR, "Couldn't open an video recording file (simulcasting #2) for this EchoTest user!\n");
++ }
+ }
+ }
} else {
/* Build a filename */
g_snprintf(filename, 255, "echotest-%p-%"SCNi64"-video", session, now);
@@@ -990,21 -836,6 +1009,25 @@@
/* FIXME We should notify the fact the recorder could not be created */
JANUS_LOG(LOG_ERR, "Couldn't open an video recording file for this EchoTest user!\n");
}
+ if(session->ssrc[0] != 0) {
+ /* Create recordings for the other layers as well */
- g_snprintf(filename, 255, "echotest-%p-%"SCNi64"-video-sim1", session, now);
- session->vrc[1] = janus_recorder_create(NULL, "vp8", filename);
- if(session->vrc[1] == NULL) {
- /* FIXME We should notify the fact the recorder could not be created */
- JANUS_LOG(LOG_ERR, "Couldn't open an video recording file (simulcasting #1) for this EchoTest user!\n");
++ if(session->ssrc[1] != 0) {
++ g_snprintf(filename, 255, "echotest-%p-%"SCNi64"-video-sim1", session, now);
++ session->vrc[1] = janus_recorder_create(NULL, "vp8", filename);
++ if(session->vrc[1] == NULL) {
++ /* FIXME We should notify the fact the recorder could not be created */
++ JANUS_LOG(LOG_ERR, "Couldn't open an video recording file (simulcasting #1) for this EchoTest user!\n");
++ }
+ }
- g_snprintf(filename, 255, "echotest-%p-%"SCNi64"-video-sim2", session, now);
- session->vrc[2] = janus_recorder_create(NULL, "vp8", filename);
- if(session->vrc[2] == NULL) {
- /* FIXME We should notify the fact the recorder could not be created */
- JANUS_LOG(LOG_ERR, "Couldn't open an video recording file (simulcasting #2) for this EchoTest user!\n");
++ if(session->ssrc[2] != 0) {
++ g_snprintf(filename, 255, "echotest-%p-%"SCNi64"-video-sim2", session, now);
++ session->vrc[2] = janus_recorder_create(NULL, "vp8", filename);
++ if(session->vrc[2] == NULL) {
++ /* FIXME We should notify the fact the recorder could not be created */
++ JANUS_LOG(LOG_ERR, "Couldn't open an video recording file (simulcasting #2) for this EchoTest user!\n");
++ }
+ }
+ }
}
/* Send a PLI */
JANUS_LOG(LOG_VERB, "Recording video, sending a PLI to kickstart it\n");
diff --cc rtcp.c
index 5dd445a,5dd445a..5236d11
--- a/rtcp.c
+++ b/rtcp.c
@@@ -335,8 -335,8 +335,13 @@@ int janus_rtcp_fix_ssrc(rtcp_context *c
brMantissa += (_ptrRTCPData[2] << 8);
brMantissa += (_ptrRTCPData[3]);
uint64_t bitRate = brMantissa << brExp;
-- JANUS_LOG(LOG_HUGE, " -- -- -- REMB: %u * 2^%u = %"SCNu64" (%d SSRCs, %u)\n",
-- brMantissa, brExp, bitRate, numssrc, ntohl(remb->ssrc[0]));
++ if(numssrc == 1) {
++ JANUS_LOG(LOG_HUGE, " -- -- -- REMB: %u * 2^%u = %"SCNu64" (%d SSRCs, %u)\n",
++ brMantissa, brExp, bitRate, numssrc, ntohl(remb->ssrc[0]));
++ } else {
++ JANUS_LOG(LOG_WARN, " -- -- -- REMB: %u * 2^%u = %"SCNu64" (%d SSRCs, %u, %u, %u)\n",
++ brMantissa, brExp, bitRate, numssrc, ntohl(remb->ssrc[0]), ntohl(remb->ssrc[1]), ntohl(remb->ssrc[2]));
++ }
} else {
JANUS_LOG(LOG_HUGE, " #%d AFB ?? -- PSFB (206)\n", pno);
}
@@@ -871,7 -871,7 +876,15 @@@ int janus_rtcp_sdes(char *packet, int l
/* Generate a new REMB message */
int janus_rtcp_remb(char *packet, int len, uint64_t bitrate) {
-- if(packet == NULL || len != 24)
++ /* By default we assume a single SSRC will be set */
++ return janus_rtcp_remb_ssrcs(packet, len, bitrate, 1);
++}
++
++int janus_rtcp_remb_ssrcs(char *packet, int len, uint64_t bitrate, uint8_t numssrc) {
++ if(packet == NULL || numssrc == 0)
++ return -1;
++ int min_len = 20 + numssrc*4;
++ if(len < min_len)
return -1;
memset(packet, 0, len);
rtcp_header *rtcp = (rtcp_header *)packet;
@@@ -879,7 -879,7 +892,7 @@@
rtcp->version = 2;
rtcp->type = RTCP_PSFB;
rtcp->rc = 15;
-- rtcp->length = htons((len/4)-1);
++ rtcp->length = htons((min_len/4)-1);
/* Now set REMB stuff */
rtcp_fb *rtcpfb = (rtcp_fb *)rtcp;
rtcp_remb *remb = (rtcp_remb *)rtcpfb->fci;
@@@ -901,12 -901,12 +914,12 @@@
/* FIXME From rtcp_sender.cc */
unsigned char *_ptrRTCPData = (unsigned char *)remb;
_ptrRTCPData += 4; /* Skip unique identifier */
-- _ptrRTCPData[0] = (uint8_t)(1); /* Just one SSRC */
++ _ptrRTCPData[0] = numssrc;
_ptrRTCPData[1] = (uint8_t)((newbrexp << 2) + ((newbrmantissa >> 16) & 0x03));
_ptrRTCPData[2] = (uint8_t)(newbrmantissa >> 8);
_ptrRTCPData[3] = (uint8_t)(newbrmantissa);
JANUS_LOG(LOG_HUGE, "[REMB] bitrate=%"SCNu64" (%d bytes)\n", bitrate, 4*(ntohs(rtcp->length)+1));
-- return 24;
++ return min_len;
}
/* Generate a new FIR message */
diff --cc rtcp.h
index 284aac7,284aac7..84ecc2a
--- a/rtcp.h
+++ b/rtcp.h
@@@ -154,8 -154,8 +154,8 @@@ typedef struct rtcp_rem
char id[4];
/*! \brief Num SSRC, Br Exp, Br Mantissa (bit mask) */
uint32_t bitrate;
-- /*! \brief SSRC feedback */
-- uint32_t ssrc[1];
++ /*! \brief SSRC feedback (we expect at max three SSRCs in there) */
++ uint32_t ssrc[3];
} rtcp_remb;
@@@ -367,6 -367,6 +367,14 @@@ int janus_rtcp_sdes(char *packet, int l
* @returns The message data length in bytes, if successful, -1 on errors */
int janus_rtcp_remb(char *packet, int len, uint64_t bitrate);
++/*! \brief Method to generate a new RTCP REMB message to cap the reported bitrate, but for more SSRCs
++ * @param[in] packet The buffer data (MUST be at least 24 chars)
++ * @param[in] len The message data length in bytes (MUST be 24)
++ * @param[in] bitrate The bitrate to report (e.g., 128000)
++ * @param[in] numssrc The number of SSRCs to include in the request
++ * @returns The message data length in bytes, if successful, -1 on errors */
++int janus_rtcp_remb_ssrcs(char *packet, int len, uint64_t bitrate, uint8_t numssrc);
++
/*! \brief Method to generate a new RTCP FIR message to request a key frame
* @param[in] packet The buffer data (MUST be at least 20 chars)
* @param[in] len The message data length in bytes (MUST be 20)
diff --cc sdp-utils.c
index f9a5325,f9a5325..30acf96
--- a/sdp-utils.c
+++ b/sdp-utils.c
@@@ -1156,8 -1156,8 +1156,6 @@@ janus_sdp *janus_sdp_generate_answer(ja
am->fmts = g_list_append(am->fmts, g_strdup(fmt_str));
fmt = fmt->next;
}
-- janus_sdp_attribute *aa = janus_sdp_attribute_create("sctmap", "5000 webrtc-datachannel 16");
-- am->attributes = g_list_append(am->attributes, aa);
}
temp = temp->next;
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/janus.git
More information about the Pkg-voip-commits
mailing list