Skip to content

Commit e57e28d

Browse files
authored
Initial support for VP9 and AV1 simulcast (and fix for broken AV1/SVC) (#3218)
1 parent 6d2dd1b commit e57e28d

14 files changed

+316
-135
lines changed

html/echotest.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ $(document).ready(function() {
203203
if((substream !== null && substream !== undefined) || (temporal !== null && temporal !== undefined)) {
204204
if(!simulcastStarted) {
205205
simulcastStarted = true;
206-
addSimulcastSvcButtons(msg["videocodec"] === "vp8");
206+
addSimulcastSvcButtons(msg["videocodec"] === "vp8" || msg["videocodec"] === "vp9" || msg["videocodec"] === "av1");
207207
}
208208
// We just received notice that there's been a switch, update the buttons
209209
updateSimulcastSvcButtons(substream, temporal);

html/janus.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -2497,9 +2497,9 @@ function Janus(gatewayCallbacks) {
24972497
direction: 'sendrecv',
24982498
streams: [config.myStream],
24992499
sendEncodings: track.sendEncodings || [
2500-
{ rid: 'h', active: true, maxBitrate: maxBitrates.high },
2501-
{ rid: 'm', active: true, maxBitrate: maxBitrates.medium, scaleResolutionDownBy: 2 },
2502-
{ rid: 'l', active: true, maxBitrate: maxBitrates.low, scaleResolutionDownBy: 4 }
2500+
{ rid: 'h', active: true, scalabilityMode: 'L1T2', maxBitrate: maxBitrates.high },
2501+
{ rid: 'm', active: true, scalabilityMode: 'L1T2', maxBitrate: maxBitrates.medium, scaleResolutionDownBy: 2 },
2502+
{ rid: 'l', active: true, scalabilityMode: 'L1T2', maxBitrate: maxBitrates.low, scaleResolutionDownBy: 4 }
25032503
]
25042504
});
25052505
} else {

src/plugins/duktape/janus-sdp.js

+2
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ JANUSSDP.generateAnswer = function(offer, options) {
399399
answer.push({ type: "a", name: a.name, value: value });
400400
} else if(options.enableAudioLevel !== false && a.value.indexOf("urn:ietf:params:rtp-hdrext:ssrc-audio-level") !== -1) {
401401
answer.push({ type: "a", name: a.name, value: value });
402+
} else if(options.enableAudioLevel !== false && a.value.indexOf("dependency-descriptor-rtp-header-extension") !== -1) {
403+
answer.push({ type: "a", name: a.name, value: value });
402404
}
403405
}
404406
} else {

src/plugins/janus_duktape.c

+3-10
Original file line numberDiff line numberDiff line change
@@ -619,10 +619,6 @@ static duk_ret_t janus_duktape_method_pushevent(duk_context *ctx) {
619619
janus_sdp_find_first_codec(parsed_sdp, JANUS_SDP_VIDEO, -1, &vcodec);
620620
if(vcodec)
621621
session->vcodec = janus_videocodec_from_name(vcodec);
622-
if(session->vcodec != JANUS_VIDEOCODEC_VP8 && session->vcodec != JANUS_VIDEOCODEC_H264) {
623-
/* VP8 r H.264 were not negotiated, if simulcasting was enabled then disable it here */
624-
janus_rtp_simulcasting_cleanup(&session->rid_extmap_id, session->ssrc, session->rid, &session->rid_mutex);
625-
}
626622
}
627623
janus_sdp_destroy(parsed_sdp);
628624
/* Send asynchronously */
@@ -2250,10 +2246,6 @@ struct janus_plugin_result *janus_duktape_handle_message(janus_plugin_session *h
22502246
janus_sdp_find_first_codec(parsed_sdp, JANUS_SDP_VIDEO, -1, &vcodec);
22512247
if(vcodec)
22522248
session->vcodec = janus_videocodec_from_name(vcodec);
2253-
if(session->vcodec != JANUS_VIDEOCODEC_VP8 && session->vcodec != JANUS_VIDEOCODEC_H264) {
2254-
/* VP8 r H.264 were not negotiated, if simulcasting was enabled then disable it here */
2255-
janus_rtp_simulcasting_cleanup(&session->rid_extmap_id, session->ssrc, session->rid, &session->rid_mutex);
2256-
}
22572249
janus_sdp_destroy(parsed_sdp);
22582250
}
22592251
if(json_is_true(json_object_get(jsep, "e2ee")))
@@ -2469,7 +2461,7 @@ void janus_duktape_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *
24692461
} else {
24702462
/* We're simulcasting, save the best video quality */
24712463
gboolean save = janus_rtp_simulcasting_context_process_rtp(&session->rec_simctx,
2472-
buf, len, session->ssrc, session->rid, session->vcodec, &session->rec_ctx, &session->rid_mutex);
2464+
buf, len, NULL, 0, session->ssrc, session->rid, session->vcodec, &session->rec_ctx, &session->rid_mutex);
24732465
if(save) {
24742466
uint32_t seq_number = ntohs(rtp->seq_number);
24752467
uint32_t timestamp = ntohl(rtp->timestamp);
@@ -2791,7 +2783,8 @@ static void janus_duktape_relay_rtp_packet(gpointer data, gpointer user_data) {
27912783
return;
27922784
/* Process this packet: don't relay if it's not the SSRC/layer we wanted to handle */
27932785
gboolean relay = janus_rtp_simulcasting_context_process_rtp(&session->sim_context,
2794-
(char *)packet->data, packet->length, packet->ssrc, NULL, sender->vcodec, &session->vrtpctx, NULL);
2786+
(char *)packet->data, packet->length, packet->extensions.dd_content, packet->extensions.dd_len,
2787+
packet->ssrc, NULL, sender->vcodec, &session->vrtpctx, NULL);
27952788
if(session->sim_context.need_pli && sender->handle) {
27962789
/* Send a PLI */
27972790
JANUS_LOG(LOG_VERB, "We need a PLI for the simulcast context\n");

src/plugins/janus_echotest.c

+4-7
Original file line numberDiff line numberDiff line change
@@ -624,11 +624,12 @@ void janus_echotest_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp
624624
if(simulcast) {
625625
/* Process this simulcast packet: don't relay if it's not the SSRC/layer we wanted to handle */
626626
relay = janus_rtp_simulcasting_context_process_rtp(&session->sim_context,
627-
buf, len, session->ssrc, session->rid, session->vcodec, &session->context, &session->rid_mutex);
627+
buf, len, packet->extensions.dd_content, packet->extensions.dd_len,
628+
session->ssrc, session->rid, session->vcodec, &session->context, &session->rid_mutex);
628629
} else {
629630
/* Process this SVC packet: don't relay if it's not the layer we wanted to handle */
630631
relay = janus_rtp_svc_context_process_rtp(&session->svc_context,
631-
buf, len, session->vcodec, NULL, &session->context);
632+
buf, len, packet->extensions.dd_content, packet->extensions.dd_len, session->vcodec, NULL, &session->context);
632633
}
633634
if(session->sim_context.need_pli || session->svc_context.need_pli) {
634635
/* Send a PLI */
@@ -1088,7 +1089,7 @@ static void *janus_echotest_handler(void *data) {
10881089
session->sim_context.templayer_target = json_integer_value(temporal);
10891090
JANUS_LOG(LOG_VERB, "Setting video temporal layer to let through (simulcast): %d (was %d)\n",
10901091
session->sim_context.templayer_target, session->sim_context.templayer);
1091-
if(session->vcodec == JANUS_VIDEOCODEC_VP8 && session->sim_context.templayer_target == session->sim_context.templayer) {
1092+
if(session->sim_context.templayer_target == session->sim_context.templayer) {
10921093
/* No need to do anything, we're already getting the right temporal, so notify the user */
10931094
json_t *event = json_object();
10941095
json_object_set_new(event, "echotest", json_string("event"));
@@ -1280,10 +1281,6 @@ static void *janus_echotest_handler(void *data) {
12801281
session->vcodec = janus_videocodec_from_name(vcodec);
12811282
session->has_audio = session->acodec != JANUS_AUDIOCODEC_NONE;
12821283
session->has_video = session->vcodec != JANUS_VIDEOCODEC_NONE;
1283-
if(session->vcodec != JANUS_VIDEOCODEC_VP8 && session->vcodec != JANUS_VIDEOCODEC_H264) {
1284-
/* VP8 r H.264 were not negotiated, if simulcasting was enabled then disable it here */
1285-
janus_rtp_simulcasting_cleanup(NULL, session->ssrc, session->rid, &session->rid_mutex);
1286-
}
12871284
g_free(session->vfmtp);
12881285
session->vfmtp = NULL;
12891286
if(session->has_video) {

src/plugins/janus_lua.c

+3-10
Original file line numberDiff line numberDiff line change
@@ -547,10 +547,6 @@ static int janus_lua_method_pushevent(lua_State *s) {
547547
janus_sdp_find_first_codec(parsed_sdp, JANUS_SDP_VIDEO, -1, &vcodec);
548548
if(vcodec)
549549
session->vcodec = janus_videocodec_from_name(vcodec);
550-
if(session->vcodec != JANUS_VIDEOCODEC_VP8 && session->vcodec != JANUS_VIDEOCODEC_H264) {
551-
/* VP8 r H.264 were not negotiated, if simulcasting was enabled then disable it here */
552-
janus_rtp_simulcasting_cleanup(&session->rid_extmap_id, session->ssrc, session->rid, &session->rid_mutex);
553-
}
554550
}
555551
janus_sdp_destroy(parsed_sdp);
556552
/* Send asynchronously */
@@ -1936,10 +1932,6 @@ struct janus_plugin_result *janus_lua_handle_message(janus_plugin_session *handl
19361932
janus_sdp_find_first_codec(parsed_sdp, JANUS_SDP_VIDEO, -1, &vcodec);
19371933
if(vcodec)
19381934
session->vcodec = janus_videocodec_from_name(vcodec);
1939-
if(session->vcodec != JANUS_VIDEOCODEC_VP8 && session->vcodec != JANUS_VIDEOCODEC_H264) {
1940-
/* VP8 r H.264 were not negotiated, if simulcasting was enabled then disable it here */
1941-
janus_rtp_simulcasting_cleanup(&session->rid_extmap_id, session->ssrc, session->rid, &session->rid_mutex);
1942-
}
19431935
janus_sdp_destroy(parsed_sdp);
19441936
}
19451937
if(json_is_true(json_object_get(jsep, "e2ee")))
@@ -2127,7 +2119,7 @@ void janus_lua_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *rtp_
21272119
} else {
21282120
/* We're simulcasting, save the best video quality */
21292121
gboolean save = janus_rtp_simulcasting_context_process_rtp(&session->rec_simctx,
2130-
buf, len, session->ssrc, session->rid, session->vcodec, &session->rec_ctx, &session->rid_mutex);
2122+
buf, len, NULL, 0, session->ssrc, session->rid, session->vcodec, &session->rec_ctx, &session->rid_mutex);
21312123
if(save) {
21322124
uint32_t seq_number = ntohs(rtp->seq_number);
21332125
uint32_t timestamp = ntohl(rtp->timestamp);
@@ -2421,7 +2413,8 @@ static void janus_lua_relay_rtp_packet(gpointer data, gpointer user_data) {
24212413
return;
24222414
/* Process this packet: don't relay if it's not the SSRC/layer we wanted to handle */
24232415
gboolean relay = janus_rtp_simulcasting_context_process_rtp(&session->sim_context,
2424-
(char *)packet->data, packet->length, packet->ssrc, NULL, sender->vcodec, &session->vrtpctx, NULL);
2416+
(char *)packet->data, packet->length, packet->extensions.dd_content, packet->extensions.dd_len,
2417+
packet->ssrc, NULL, sender->vcodec, &session->vrtpctx, NULL);
24252418
if(session->sim_context.need_pli && sender->handle) {
24262419
/* Send a PLI */
24272420
JANUS_LOG(LOG_VERB, "We need a PLI for the simulcast context\n");

src/plugins/janus_recordplay.c

+2-5
Original file line numberDiff line numberDiff line change
@@ -1304,7 +1304,8 @@ void janus_recordplay_incoming_rtp(janus_plugin_session *handle, janus_plugin_rt
13041304
uint32_t ssrc = ntohl(header->ssrc);
13051305
/* Process this packet: don't save if it's not the SSRC/layer we wanted to handle */
13061306
gboolean save = janus_rtp_simulcasting_context_process_rtp(&session->sim_context,
1307-
buf, len, session->ssrc, session->rid, session->recording->vcodec, &session->context, &session->rid_mutex);
1307+
buf, len, NULL, 0, session->ssrc, session->rid, session->recording->vcodec,
1308+
&session->context, &session->rid_mutex);
13081309
if(session->sim_context.need_pli) {
13091310
/* Send a PLI */
13101311
JANUS_LOG(LOG_VERB, "We need a PLI for the simulcast context\n");
@@ -1879,10 +1880,6 @@ static void *janus_recordplay_handler(void *data) {
18791880
janus_mutex_unlock(&session->rid_mutex);
18801881
session->sim_context.substream_target = 2; /* Let's aim for the highest quality */
18811882
session->sim_context.templayer_target = 2; /* Let's aim for all temporal layers */
1882-
if(rec->vcodec != JANUS_VIDEOCODEC_VP8 && rec->vcodec != JANUS_VIDEOCODEC_H264) {
1883-
/* VP8 r H.264 were not negotiated, if simulcasting was enabled then disable it here */
1884-
janus_rtp_simulcasting_cleanup(NULL, session->ssrc, session->rid, &session->rid_mutex);
1885-
}
18861883
/* FIXME We're stopping at the first item, there may be more */
18871884
break;
18881885
}

src/plugins/janus_streaming.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -10030,7 +10030,8 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data)
1003010030
return;
1003110031
/* Process this packet: don't relay if it's not the SSRC/layer we wanted to handle */
1003210032
gboolean relay = janus_rtp_simulcasting_context_process_rtp(&s->sim_context,
10033-
(char *)packet->data, packet->length, packet->ssrc, NULL, packet->codec, &s->context, NULL);
10033+
(char *)packet->data, packet->length, NULL, 0,
10034+
packet->ssrc, NULL, packet->codec, &s->context, NULL);
1003410035
if(!relay) {
1003510036
/* Did a lot of time pass before we could relay a packet? */
1003610037
gint64 now = janus_get_monotonic_time();

src/plugins/janus_videocall.c

+5-4
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,8 @@ void janus_videocall_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp
778778
/* Process this packet: don't relay if it's not the SSRC/layer we wanted to handle
779779
* The caveat is that the targets in OUR simulcast context are the PEER's targets */
780780
gboolean relay = janus_rtp_simulcasting_context_process_rtp(&peer->sim_context,
781-
buf, len, session->ssrc, session->rid, session->vcodec, &peer->context, &session->rid_mutex);
781+
buf, len, packet->extensions.dd_content, packet->extensions.dd_len,
782+
session->ssrc, session->rid, session->vcodec, &peer->context, &session->rid_mutex);
782783
/* Do we need to drop this? */
783784
if(!relay)
784785
return;
@@ -1374,7 +1375,7 @@ static void *janus_videocall_handler(void *data) {
13741375
session->has_data = (strstr(msg_sdp, "DTLS/SCTP") != NULL);
13751376
/* Check if this user will simulcast */
13761377
json_t *msg_simulcast = json_object_get(msg->jsep, "simulcast");
1377-
if(msg_simulcast && janus_get_codec_pt(msg_sdp, "vp8") > 0) {
1378+
if(msg_simulcast) {
13781379
JANUS_LOG(LOG_VERB, "VideoCall callee (%s) cannot do simulcast.\n", session->username);
13791380
} else {
13801381
janus_rtp_simulcasting_cleanup(NULL, session->ssrc, session->rid, &session->rid_mutex);
@@ -1533,7 +1534,7 @@ static void *janus_videocall_handler(void *data) {
15331534
session->sim_context.templayer_target = json_integer_value(temporal);
15341535
JANUS_LOG(LOG_VERB, "Setting video temporal layer to let through (simulcast): %d (was %d)\n",
15351536
session->sim_context.templayer_target, session->sim_context.templayer);
1536-
if(session->vcodec == JANUS_VIDEOCODEC_VP8 && session->sim_context.templayer_target == session->sim_context.templayer) {
1537+
if(session->sim_context.templayer_target == session->sim_context.templayer) {
15371538
/* No need to do anything, we're already getting the right temporal, so notify the user */
15381539
json_t *event = json_object();
15391540
json_object_set_new(event, "videocall", json_string("event"));
@@ -1569,7 +1570,7 @@ static void *janus_videocall_handler(void *data) {
15691570
session->has_data = (strstr(msg_sdp, "DTLS/SCTP") != NULL);
15701571
/* Check if this user will simulcast */
15711572
json_t *msg_simulcast = json_object_get(msg->jsep, "simulcast");
1572-
if(msg_simulcast && janus_get_codec_pt(msg_sdp, "vp8") > 0) {
1573+
if(msg_simulcast) {
15731574
JANUS_LOG(LOG_VERB, "VideoCall callee (%s) cannot do simulcast.\n", session->username);
15741575
} else {
15751576
janus_rtp_simulcasting_cleanup(NULL, session->ssrc, session->rid, &session->rid_mutex);

0 commit comments

Comments
 (0)