[Pkg-voip-commits] [janus] 12/163: Initial experiments with VP8 temporal scalability
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 3d67fa8c3f231fb1fbe7286125bee2ce8f08950c
Author: Lorenzo Miniero <lminiero at gmail.com>
Date: Wed Jul 5 16:38:11 2017 +0200
Initial experiments with VP8 temporal scalability
---
html/devicetest.html | 19 +++++--
html/devicetest.js | 72 +++++++++++++++++++++------
html/echotest.html | 19 +++++--
html/echotest.js | 72 +++++++++++++++++++++------
html/videoroomtest.html | 45 ++---------------
plugins/janus_echotest.c | 126 +++++++++++++++++++++++++++++++++++------------
utils.c | 13 +++--
utils.h | 1 +
8 files changed, 255 insertions(+), 112 deletions(-)
diff --git a/html/devicetest.html b/html/devicetest.html
index de54a53..fb8a075 100644
--- a/html/devicetest.html
+++ b/html/devicetest.html
@@ -120,11 +120,20 @@
<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-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 id="simulcast" class="btn-group-vertical btn-group-vertical-xs pull-right hide">
+ <div class"row">
+ <div class="btn-group btn-group-xs" style="width: 100%">
+ <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"row">
+ <div class="btn-group btn-group-xs" style="width: 100%">
+ <button id="tl-2" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 2" style="width: 34%">TL 2</button>
+ <button id="tl-1" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 1" style="width: 33%">TL 1</button>
+ <button id="tl-0" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 0" style="width: 33%">TL 0</button>
+ </div>
</div>
</div>
<div class="btn-group btn-group-xs pull-right hide" id="output-devices">
diff --git a/html/devicetest.js b/html/devicetest.js
index f781a8b..52c372e 100644
--- a/html/devicetest.js
+++ b/html/devicetest.js
@@ -273,54 +273,95 @@ $(document).ready(function() {
}
}
// Is simulcast in place?
- var simulcast = msg["simulcast"];
- if(simulcast !== null && simulcast !== undefined) {
+ var substream = msg["substream"];
+ var temporal = msg["temporal"];
+ if((substream !== null && substream !== undefined) || (temporal !== null && temporal !== 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});
+ toastr.info("Switching simulcast substream, 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 }});
+ echotest.send({message: { substream: 0 }});
});
$('#sl-1').removeClass('btn-primary btn-success').addClass('btn-success')
.unbind('click').click(function() {
- toastr.info("Switching simulcast video, wait for it... (normal quality)", null, {timeOut: 2000});
+ toastr.info("Switching simulcast substream, 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 }});
+ echotest.send({message: { substream: 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});
+ toastr.info("Switching simulcast substream, 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 }});
+ echotest.send({message: { substream: 2 }});
+ });
+ $('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
+ .unbind('click').click(function() {
+ toastr.info("Capping simulcast temporal layer, wait for it... (lowest FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
+ echotest.send({message: { temporal: 0 }});
+ });
+ $('#tl-1').removeClass('btn-primary btn-success').addClass('btn-success')
+ .unbind('click').click(function() {
+ toastr.info("Capping simulcast temporal layer, wait for it... (medium FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ echotest.send({message: { temporal: 1 }});
+ });
+ $('#tl-2').removeClass('btn-primary btn-success').addClass('btn-success')
+ .unbind('click').click(function() {
+ toastr.info("Capping simulcast temporal layer, wait for it... (highest FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ echotest.send({message: { temporal: 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});
+ if(substream === 0) {
+ toastr.success("Switched simulcast substream! (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! (normal quality)", null, {timeOut: 2000});
+ } else if(substream === 1) {
+ toastr.success("Switched simulcast substream! (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});
+ } else if(substream === 2) {
+ toastr.success("Switched simulcast substream! (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');
}
+ if(temporal === 0) {
+ toastr.success("Capped simulcast temporal layer! (lowest FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
+ } else if(temporal === 1) {
+ toastr.success("Capped simulcast temporal layer! (medium FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ } else if(temporal === 2) {
+ toastr.success("Capped simulcast temporal layer! (highest FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ }
}
},
onlocalstream: function(stream) {
@@ -477,6 +518,9 @@ $(document).ready(function() {
$('#sl-0').unbind('click');
$('#sl-1').unbind('click');
$('#sl-2').unbind('click');
+ $('#tl-0').unbind('click');
+ $('#tl-1').unbind('click');
+ $('#tl-2').unbind('click');
}
});
},
diff --git a/html/echotest.html b/html/echotest.html
index 8542315..62b5f05 100644
--- a/html/echotest.html
+++ b/html/echotest.html
@@ -110,11 +110,20 @@
<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>
- <div id="simulcast" class="btn-group btn-group-xs pull-right hide">
- <div class="btn-group btn-group-xs">
- <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 id="simulcast" class="btn-group-vertical btn-group-vertical-xs pull-right hide">
+ <div class"row">
+ <div class="btn-group btn-group-xs" style="width: 100%">
+ <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"row">
+ <div class="btn-group btn-group-xs" style="width: 100%">
+ <button id="tl-2" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 2" style="width: 34%">TL 2</button>
+ <button id="tl-1" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 1" style="width: 33%">TL 1</button>
+ <button id="tl-0" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 0" style="width: 33%">TL 0</button>
+ </div>
</div>
</div>
</h3>
diff --git a/html/echotest.js b/html/echotest.js
index c6a2bd5..93a37de 100644
--- a/html/echotest.js
+++ b/html/echotest.js
@@ -198,54 +198,95 @@ $(document).ready(function() {
}
}
// Is simulcast in place?
- var simulcast = msg["simulcast"];
- if(simulcast !== null && simulcast !== undefined) {
+ var substream = msg["substream"];
+ var temporal = msg["temporal"];
+ if((substream !== null && substream !== undefined) || (temporal !== null && temporal !== 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});
+ toastr.info("Switching simulcast substream, 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 }});
+ echotest.send({message: { substream: 0 }});
});
$('#sl-1').removeClass('btn-primary btn-success').addClass('btn-success')
.unbind('click').click(function() {
- toastr.info("Switching simulcast video, wait for it... (normal quality)", null, {timeOut: 2000});
+ toastr.info("Switching simulcast substream, 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 }});
+ echotest.send({message: { substream: 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});
+ toastr.info("Switching simulcast substream, 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 }});
+ echotest.send({message: { substream: 2 }});
+ });
+ $('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
+ .unbind('click').click(function() {
+ toastr.info("Capping simulcast temporal layer, wait for it... (lowest FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
+ echotest.send({message: { temporal: 0 }});
+ });
+ $('#tl-1').removeClass('btn-primary btn-success').addClass('btn-success')
+ .unbind('click').click(function() {
+ toastr.info("Capping simulcast temporal layer, wait for it... (medium FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ echotest.send({message: { temporal: 1 }});
+ });
+ $('#tl-2').removeClass('btn-primary btn-success').addClass('btn-success')
+ .unbind('click').click(function() {
+ toastr.info("Capping simulcast temporal layer, wait for it... (highest FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ echotest.send({message: { temporal: 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});
+ if(substream === 0) {
+ toastr.success("Switched simulcast substream! (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! (normal quality)", null, {timeOut: 2000});
+ } else if(substream === 1) {
+ toastr.success("Switched simulcast substream! (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});
+ } else if(substream === 2) {
+ toastr.success("Switched simulcast substream! (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');
}
+ if(temporal === 0) {
+ toastr.success("Capped simulcast temporal layer! (lowest FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
+ } else if(temporal === 1) {
+ toastr.success("Capped simulcast temporal layer! (medium FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ } else if(temporal === 2) {
+ toastr.success("Capped simulcast temporal layer! (highest FPS)", null, {timeOut: 2000});
+ $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
+ $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-primary');
+ }
}
},
onlocalstream: function(stream) {
@@ -391,6 +432,9 @@ $(document).ready(function() {
$('#sl-0').unbind('click');
$('#sl-1').unbind('click');
$('#sl-2').unbind('click');
+ $('#tl-0').unbind('click');
+ $('#tl-1').unbind('click');
+ $('#tl-2').unbind('click');
}
});
},
diff --git a/html/videoroomtest.html b/html/videoroomtest.html
index 4ec8abf..67b5d4d 100644
--- a/html/videoroomtest.html
+++ b/html/videoroomtest.html
@@ -108,14 +108,7 @@
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
- <h3 class="panel-title">Remote Video #1 <span class="label label-info hide" id="remote1"></span>
- <div id="simulcast1" class="btn-group btn-group-xs pull-right hide">
- <div class="btn-group btn-group-xs">
- <button id="sl1-1" type="button" class="btn btn-primary" style="width: 50%">SL 1</button>
- <button id="sl1-0" type="button" class="btn btn-primary" style="width: 50%">SL 0</button>
- </div>
- </div>
- </h3>
+ <h3 class="panel-title">Remote Video #1 <span class="label label-info hide" id="remote1"></span></h3>
</div>
<div class="panel-body relative" id="videoremote1"></div>
</div>
@@ -123,14 +116,7 @@
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
- <h3 class="panel-title">Remote Video #2 <span class="label label-info hide" id="remote2"></span>
- <div id="simulcast2" class="btn-group btn-group-xs pull-right hide">
- <div class="btn-group btn-group-xs">
- <button id="sl2-1" type="button" class="btn btn-primary" style="width: 50%">SL 1</button>
- <button id="sl2-0" type="button" class="btn btn-primary" style="width: 50%">SL 0</button>
- </div>
- </div>
- </h3>
+ <h3 class="panel-title">Remote Video #2 <span class="label label-info hide" id="remote2"></span></h3>
</div>
<div class="panel-body relative" id="videoremote2"></div>
</div>
@@ -140,14 +126,7 @@
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
- <h3 class="panel-title">Remote Video #3 <span class="label label-info hide" id="remote3"></span>
- <div id="simulcast3" class="btn-group btn-group-xs pull-right hide">
- <div class="btn-group btn-group-xs">
- <button id="sl3-1" type="button" class="btn btn-primary" style="width: 50%">SL 1</button>
- <button id="sl3-0" type="button" class="btn btn-primary" style="width: 50%">SL 0</button>
- </div>
- </div>
- </h3>
+ <h3 class="panel-title">Remote Video #3 <span class="label label-info hide" id="remote3"></span></h3>
</div>
<div class="panel-body relative" id="videoremote3"></div>
</div>
@@ -155,14 +134,7 @@
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
- <h3 class="panel-title">Remote Video #4 <span class="label label-info hide" id="remote4"></span>
- <div id="simulcast4" class="btn-group btn-group-xs pull-right hide">
- <div class="btn-group btn-group-xs">
- <button id="sl4-1" type="button" class="btn btn-primary" style="width: 50%">SL 1</button>
- <button id="sl4-0" type="button" class="btn btn-primary" style="width: 50%">SL 0</button>
- </div>
- </div>
- </h3>
+ <h3 class="panel-title">Remote Video #4 <span class="label label-info hide" id="remote4"></span></h3>
</div>
<div class="panel-body relative" id="videoremote4"></div>
</div>
@@ -170,14 +142,7 @@
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
- <h3 class="panel-title">Remote Video #5 <span class="label label-info hide" id="remote5"></span>
- <div id="simulcast5" class="btn-group btn-group-xs pull-right hide">
- <div class="btn-group btn-group-xs">
- <button id="sl5-1" type="button" class="btn btn-primary" style="width: 50%">SL 1</button>
- <button id="sl5-0" type="button" class="btn btn-primary" style="width: 50%">SL 0</button>
- </div>
- </div>
- </h3>
+ <h3 class="panel-title">Remote Video #5 <span class="label label-info hide" id="remote5"></span></h3>
</div>
<div class="panel-body relative" id="videoremote5"></div>
</div>
diff --git a/plugins/janus_echotest.c b/plugins/janus_echotest.c
index b6042f2..4a4ce1e 100644
--- a/plugins/janus_echotest.c
+++ b/plugins/janus_echotest.c
@@ -190,8 +190,10 @@ typedef struct janus_echotest_session {
uint32_t ssrc[3]; /* Only needed in case VP8 simulcasting is involved */
int rtpmapid_extmap_id; /* Only needed in case Firefox's RID-based simulcasting is involved */
char *rid[3]; /* Only needed in case Firefox's RID-based simulcasting is involved */
- int simulcast; /* Which simulcast "layer" we should forward back */
- int simulcast_target; /* As above, but to handle transitions (e.g., wait for keyframe) */
+ int substream; /* Which simulcast substream we should forward back */
+ int substream_target; /* As above, but to handle transitions (e.g., wait for keyframe) */
+ int templayer; /* Which simulcast temporal layer we should forward back */
+ int templayer_target; /* As above, but to handle transitions (e.g., wait for keyframe) */
janus_vp8_simulcast_context simulcast_context;
janus_recorder *arc; /* The Janus recorder instance for this user's audio, if enabled */
janus_recorder *vrc[3]; /* The Janus recorder instance for this user's video, if enabled (there may be more if we're simulcasting) */
@@ -399,8 +401,10 @@ void janus_echotest_create_session(janus_plugin_session *handle, int *error) {
session->ssrc[0] = 0;
session->ssrc[1] = 0;
session->ssrc[2] = 0;
- session->simulcast = -1;
- session->simulcast_target = 0;
+ session->substream = -1;
+ session->substream_target = 0;
+ session->templayer = -1;
+ session->templayer_target = 0;
janus_vp8_simulcast_context_reset(&session->simulcast_context);
session->destroyed = 0;
g_atomic_int_set(&session->hangingup, 0);
@@ -451,8 +455,10 @@ json_t *janus_echotest_query_session(janus_plugin_session *handle) {
json_object_set_new(info, "bitrate", json_integer(session->bitrate));
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));
+ json_object_set_new(info, "substream", json_integer(session->substream));
+ json_object_set_new(info, "substream-target", json_integer(session->substream_target));
+ json_object_set_new(info, "temporal-layer", json_integer(session->templayer));
+ json_object_set_new(info, "temporal-layer-target", json_integer(session->templayer_target));
}
if(session->arc || session->vrc[0] || session->drc) {
json_t *recording = json_object();
@@ -549,20 +555,20 @@ void janus_echotest_incoming_rtp(janus_plugin_session *handle, int video, char *
if(payload == NULL)
return;
gboolean switched = FALSE;
- if(session->simulcast != session->simulcast_target) {
+ if(session->substream != session->substream_target) {
/* There has been a change: let's wait for a keyframe on the target */
- if(ssrc == session->ssrc[session->simulcast_target]) {
+ if(ssrc == session->ssrc[session->substream_target]) {
if(janus_vp8_is_keyframe(payload, plen)) {
uint32_t ssrc_old = 0;
- if(session->simulcast != -1)
- ssrc_old = session->ssrc[session->simulcast];
+ if(session->substream != -1)
+ ssrc_old = session->ssrc[session->substream];
JANUS_LOG(LOG_WARN, "Received keyframe on SSRC %"SCNu32", switching (was %"SCNu32")\n", ssrc, ssrc_old);
- session->simulcast = session->simulcast_target;
+ session->substream = session->substream_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));
+ json_object_set_new(event, "substream", json_integer(session->substream));
gateway->push_event(session->handle, &janus_echotest_plugin, NULL, event, NULL);
json_decref(event);
} else {
@@ -570,11 +576,38 @@ void janus_echotest_incoming_rtp(janus_plugin_session *handle, int video, char *
}
}
}
- if(ssrc != session->ssrc[session->simulcast]) {
+ if(ssrc != session->ssrc[session->substream]) {
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]);
+ ssrc, session->ssrc[session->substream]);
return;
}
+ /* Check if there's any temporal scalability to take into account */
+ uint16_t picid = 0;
+ uint8_t tlzi = 0;
+ uint8_t tid = 0;
+ uint8_t ybit = 0;
+ uint8_t keyidx = 0;
+ if(janus_vp8_parse_descriptor(payload, plen, &picid, &tlzi, &tid, &ybit, &keyidx) == 0) {
+ //~ JANUS_LOG(LOG_WARN, "%"SCNu16", %u, %u, %u, %u\n", picid, tlzi, tid, ybit, keyidx);
+ if(session->templayer != session->templayer_target) {
+ /* FIXME We should be smarter in deciding when to switch */
+ session->templayer = session->templayer_target;
+ /* Notify the user */
+ json_t *event = json_object();
+ json_object_set_new(event, "echotest", json_string("event"));
+ json_object_set_new(event, "temporal", json_integer(session->templayer));
+ gateway->push_event(session->handle, &janus_echotest_plugin, NULL, event, NULL);
+ json_decref(event);
+ }
+ if(tid > session->templayer) {
+ JANUS_LOG(LOG_HUGE, "Dropping packet (it's temporal layer %d, but we're capping at %d)\n",
+ tid, session->templayer);
+ /* We increase the base sequence number, or there will be gaps when delivering later */
+ session->context.v_base_seq++;
+ return;
+ }
+ }
+ /* If we got here, update the RTP header and send the packet */
janus_rtp_header_update(header, &session->context, TRUE, 4500);
janus_vp8_simulcast_descriptor_update(payload, plen, &session->simulcast_context, switched);
/* Send the frame back */
@@ -755,8 +788,10 @@ void janus_echotest_hangup_media(janus_plugin_session *handle) {
session->ssrc[0] = 0;
session->ssrc[1] = 0;
session->ssrc[2] = 0;
- session->simulcast = -1;
- session->simulcast_target = 0;
+ session->substream = -1;
+ session->substream_target = 0;
+ session->templayer = -1;
+ session->templayer_target = 0;
}
/* Thread to handle incoming messages */
@@ -815,7 +850,8 @@ static void *janus_echotest_handler(void *data) {
session->ssrc[0] = json_integer_value(json_object_get(msg_simulcast, "ssrc-0"));
session->ssrc[1] = json_integer_value(json_object_get(msg_simulcast, "ssrc-1"));
session->ssrc[2] = json_integer_value(json_object_get(msg_simulcast, "ssrc-2"));
- session->simulcast_target = 0; /* Let's start with low quality */
+ session->substream_target = 0; /* Let's start with low quality */
+ session->templayer_target = 2; /* Let's start with all temporal layers */
}
json_t *audio = json_object_get(root, "audio");
if(audio && !json_is_boolean(audio)) {
@@ -838,11 +874,18 @@ static void *janus_echotest_handler(void *data) {
g_snprintf(error_cause, 512, "Invalid value (bitrate should be a positive integer)");
goto error;
}
- json_t *simulcast = json_object_get(root, "simulcast");
- if(simulcast && (!json_is_integer(simulcast) || (json_integer_value(simulcast) < 0 && json_integer_value(simulcast) > 2))) {
- JANUS_LOG(LOG_ERR, "Invalid element (simulcast should be 0, 1 or 2)\n");
+ json_t *substream = json_object_get(root, "substream");
+ if(substream && (!json_is_integer(substream) || (json_integer_value(substream) < 0 && json_integer_value(substream) > 2))) {
+ JANUS_LOG(LOG_ERR, "Invalid element (substream should be 0, 1 or 2)\n");
error_code = JANUS_ECHOTEST_ERROR_INVALID_ELEMENT;
- g_snprintf(error_cause, 512, "Invalid value (simulcast should be 0, 1 or 2)");
+ g_snprintf(error_cause, 512, "Invalid value (substream should be 0, 1 or 2)");
+ goto error;
+ }
+ json_t *temporal = json_object_get(root, "temporal");
+ if(temporal && (!json_is_integer(temporal) || (json_integer_value(temporal) < 0 && json_integer_value(temporal) > 2))) {
+ JANUS_LOG(LOG_ERR, "Invalid element (temporal should be 0, 1 or 2)\n");
+ error_code = JANUS_ECHOTEST_ERROR_INVALID_ELEMENT;
+ g_snprintf(error_cause, 512, "Invalid value (temporal should be 0, 1 or 2)");
goto error;
}
json_t *record = json_object_get(root, "record");
@@ -893,20 +936,40 @@ static void *janus_echotest_handler(void *data) {
/* FIXME How should we handle a subsequent "no limit" bitrate? */
}
}
- if(simulcast) {
- session->simulcast_target = json_integer_value(simulcast);
+ if(substream) {
+ session->substream_target = json_integer_value(substream);
JANUS_LOG(LOG_VERB, "Setting video SSRC to let through (simulcast): %"SCNu32" (index %d, was %d)\n",
- session->ssrc[session->simulcast], session->simulcast_target, session->simulcast);
- if(session->simulcast_target == session->simulcast) {
+ session->ssrc[session->substream], session->substream_target, session->substream);
+ if(session->substream_target == session->substream) {
/* No need to do anything, we're already getting the right substream, so 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));
+ json_object_set_new(event, "substream", json_integer(session->substream));
gateway->push_event(session->handle, &janus_echotest_plugin, NULL, event, NULL);
json_decref(event);
} else {
/* We need to change substream, send a PLI */
- JANUS_LOG(LOG_VERB, "Simulcasting change, sending a PLI to kickstart it\n");
+ JANUS_LOG(LOG_VERB, "Simulcasting substream change, sending a PLI to kickstart it\n");
+ char buf[12];
+ memset(buf, 0, 12);
+ janus_rtcp_pli((char *)&buf, 12);
+ gateway->relay_rtcp(session->handle, 1, buf, 12);
+ }
+ }
+ if(temporal) {
+ session->templayer_target = json_integer_value(temporal);
+ JANUS_LOG(LOG_VERB, "Setting video temporal layer to let through (simulcast): %d (was %d)\n",
+ session->templayer_target, session->templayer);
+ if(session->templayer_target == session->templayer) {
+ /* No need to do anything, we're already getting the right temporal, so notify the user */
+ json_t *event = json_object();
+ json_object_set_new(event, "echotest", json_string("event"));
+ json_object_set_new(event, "temporal", json_integer(session->templayer));
+ gateway->push_event(session->handle, &janus_echotest_plugin, NULL, event, NULL);
+ json_decref(event);
+ } else {
+ /* We need to change temporal, send a PLI */
+ JANUS_LOG(LOG_VERB, "Simulcasting temporal layer change, sending a PLI to kickstart it\n");
char buf[12];
memset(buf, 0, 12);
janus_rtcp_pli((char *)&buf, 12);
@@ -1076,10 +1139,10 @@ static void *janus_echotest_handler(void *data) {
session->has_data = (strstr(msg_sdp, "DTLS/SCTP") != NULL);
}
- if(!audio && !video && !bitrate && !simulcast && !record && !msg_sdp) {
- JANUS_LOG(LOG_ERR, "No supported attributes (audio, video, bitrate, simulcast, record, jsep) found\n");
+ if(!audio && !video && !bitrate && !substream && !temporal && !record && !msg_sdp) {
+ JANUS_LOG(LOG_ERR, "No supported attributes (audio, video, bitrate, substream, temporal, record, jsep) found\n");
error_code = JANUS_ECHOTEST_ERROR_INVALID_ELEMENT;
- g_snprintf(error_cause, 512, "Message error: no supported attributes (audio, video, bitrate, simulcast, record, jsep) found");
+ g_snprintf(error_cause, 512, "Message error: no supported attributes (audio, video, bitrate, simulcast, temporal, record, jsep) found");
goto error;
}
@@ -1176,7 +1239,8 @@ static void *janus_echotest_handler(void *data) {
json_object_set_new(simulcast, "ssrc-0", json_integer(session->ssrc[0]));
json_object_set_new(simulcast, "ssrc-1", json_integer(session->ssrc[1]));
json_object_set_new(simulcast, "ssrc-2", json_integer(session->ssrc[2]));
- json_object_set_new(simulcast, "simulcast", json_integer(session->simulcast));
+ json_object_set_new(simulcast, "substream", json_integer(session->substream));
+ json_object_set_new(simulcast, "temporal-layer", json_integer(session->templayer));
json_object_set_new(info, "simulcast", simulcast);
}
if(session->arc || session->vrc[0]) {
diff --git a/utils.c b/utils.c
index f3500c2..705dde5 100644
--- a/utils.c
+++ b/utils.c
@@ -726,7 +726,7 @@ int janus_vp8_parse_descriptor(char *buffer, int len,
return 0;
}
-static int janus_vp8_replace_descriptor(char *buffer, int len, uint16_t picid) {
+static int janus_vp8_replace_descriptor(char *buffer, int len, uint16_t picid, uint8_t tl0picidx) {
if(!buffer || len < 0)
return -1;
uint8_t vp8pd = *buffer;
@@ -754,8 +754,9 @@ static int janus_vp8_replace_descriptor(char *buffer, int len, uint16_t picid) {
}
}
if(lbit) {
- /* FIXME Should we overwrite the TL0PICIDX octet? */
+ /* Overwrite the TL0PICIDX octet */
buffer++;
+ *buffer = tl0picidx;
}
if(tbit || kbit) {
/* Should we overwrite the TID/Y/KEYIDX octet? */
@@ -772,6 +773,9 @@ void janus_vp8_simulcast_context_reset(janus_vp8_simulcast_context *context) {
context->last_picid = 0;
context->base_picid = 0;
context->base_picid_prev = 0;
+ context->last_tlzi = 0;
+ context->base_tlzi = 0;
+ context->base_tlzi_prev = 0;
}
void janus_vp8_simulcast_descriptor_update(char *buffer, int len, janus_vp8_simulcast_context *context, gboolean switched) {
@@ -788,8 +792,11 @@ void janus_vp8_simulcast_descriptor_update(char *buffer, int len, janus_vp8_simu
if(switched) {
context->base_picid_prev = context->last_picid;
context->base_picid = picid;
+ context->base_tlzi_prev = context->last_tlzi;
+ context->base_tlzi = tlzi;
}
context->last_picid = (picid-context->base_picid)+context->base_picid_prev+1;
+ context->last_tlzi = (tlzi-context->base_tlzi)+context->base_tlzi_prev+1;
/* Overwrite the values in the VP8 payload descriptors with the ones we have */
- janus_vp8_replace_descriptor(buffer, len, context->last_picid);
+ janus_vp8_replace_descriptor(buffer, len, context->last_picid, context->last_tlzi);
}
diff --git a/utils.h b/utils.h
index 388374f..d19e764 100644
--- a/utils.h
+++ b/utils.h
@@ -241,6 +241,7 @@ gboolean janus_h264_is_keyframe(char* buffer, int len);
/*! \brief VP8 simulcasting context, in order to make sure SSRC changes result in coherent picid/temporal level increases */
typedef struct janus_vp8_simulcast_context {
uint16_t last_picid, base_picid, base_picid_prev;
+ uint8_t last_tlzi, base_tlzi, base_tlzi_prev;
} janus_vp8_simulcast_context;
/*! \brief Set (or reset) the context fields to their default values
--
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