Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for AV1-SVC Dependency Descriptor #2741

Merged
merged 14 commits into from
Jan 25, 2022
Merged
4 changes: 4 additions & 0 deletions html/echotest.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ var videoenabled = false;

var doSimulcast = (getQueryStringValue("simulcast") === "yes" || getQueryStringValue("simulcast") === "true");
var doSimulcast2 = (getQueryStringValue("simulcast2") === "yes" || getQueryStringValue("simulcast2") === "true");
var doSvc = getQueryStringValue("svc");
if(doSvc === "")
doSvc = null;
var acodec = (getQueryStringValue("acodec") !== "" ? getQueryStringValue("acodec") : null);
var vcodec = (getQueryStringValue("vcodec") !== "" ? getQueryStringValue("vcodec") : null);
var vprofile = (getQueryStringValue("vprofile") !== "" ? getQueryStringValue("vprofile") : null);
Expand Down Expand Up @@ -128,6 +131,7 @@ $(document).ready(function() {
// the following 'simulcast' property to pass to janus.js to true
simulcast: doSimulcast,
simulcast2: doSimulcast2,
svc: (vcodec === 'av1' && doSvc) ? doSvc : null,
customizeSdp: function(jsep) {
// If DTX is enabled, munge the SDP
if(doDtx) {
Expand Down
23 changes: 18 additions & 5 deletions html/janus.js
Original file line number Diff line number Diff line change
Expand Up @@ -1964,15 +1964,16 @@ function Janus(gatewayCallbacks) {
if(addTracks && stream) {
Janus.log('Adding local stream');
var simulcast2 = (callbacks.simulcast2 === true);
var svc = callbacks.svc;
stream.getTracks().forEach(function(track) {
Janus.log('Adding local track:', track);
var sender = null;
if(!simulcast2 || track.kind === 'audio') {
if((!simulcast2 && !svc) || track.kind === 'audio') {
sender = config.pc.addTrack(track, stream);
} else {
} else if(simulcast2) {
Janus.log('Enabling rid-based simulcasting:', track);
var maxBitrates = getMaxBitrates(callbacks.simulcastMaxBitrates);
var tr = config.pc.addTransceiver(track, {
let maxBitrates = getMaxBitrates(callbacks.simulcastMaxBitrates);
let tr = config.pc.addTransceiver(track, {
direction: "sendrecv",
streams: [stream],
sendEncodings: callbacks.sendEncodings || [
Expand All @@ -1983,6 +1984,17 @@ function Janus(gatewayCallbacks) {
});
if(tr)
sender = tr.sender;
} else {
Janus.log('Enabling SVC (' + svc + '):', track);
let tr = config.pc.addTransceiver(track, {
direction: "sendrecv",
streams: [stream],
sendEncodings: [
{ scalabilityMode: svc }
]
});
if(tr)
sender = tr.sender;
}
// Check if insertable streams are involved
if(sender && config.senderTransforms) {
Expand Down Expand Up @@ -2301,7 +2313,8 @@ function Janus(gatewayCallbacks) {
if(videoSupport && media) {
var simulcast = (callbacks.simulcast === true);
var simulcast2 = (callbacks.simulcast2 === true);
if((simulcast || simulcast2) && !jsep && !media.video)
var svc = callbacks.svc;
if((simulcast || simulcast2 || svc) && !jsep && !media.video)
media.video = "hires";
if(media.video && media.video != 'screen' && media.video != 'window') {
if(typeof media.video === 'object') {
Expand Down
119 changes: 95 additions & 24 deletions ice.c
Original file line number Diff line number Diff line change
Expand Up @@ -2727,6 +2727,16 @@ static void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint comp
rtp.extensions.video_flipped = f;
}
}
if(stream->dependencydesc_ext_id != -1) {
uint8_t dd[256];
int len = sizeof(dd);
if(janus_rtp_header_extension_parse_dependency_desc(buf, buflen,
stream->dependencydesc_ext_id, dd, &len) == 0 && len > 0) {
/* We copy the DD bytes as they are: it's up to plugins to parse it, if needed */
rtp.extensions.dd_len = len;
memcpy(rtp.extensions.dd_content, dd, len);
}
}
/* Pass the packet to the plugin */
janus_plugin *plugin = (janus_plugin *)handle->app;
if(plugin && plugin->incoming_rtp && handle->app_handle &&
Expand Down Expand Up @@ -4866,60 +4876,96 @@ void janus_ice_relay_rtp(janus_ice_handle *handle, janus_plugin_rtp *packet) {
totlen += plen;
/* We need to strip extensions, here, and add those that need to be there manually */
uint16_t extlen = 0;
char extensions[50];
char extensions[200];
janus_rtp_header *header = (janus_rtp_header *)packet->buffer;
int origext = header->extension;
header->extension = 0;
/* Add core and plugin extensions, if any */
if(handle->stream->mid_ext_id > 0 || (packet->video && handle->stream->abs_send_time_ext_id > 0) ||
(packet->video && handle->stream->transport_wide_cc_ext_id > 0) ||
(!packet->video && packet->extensions.audio_level != -1 && handle->stream->audiolevel_ext_id > 0) ||
(packet->video && packet->extensions.video_rotation != -1 && handle->stream->videoorientation_ext_id > 0)) {
(packet->video && packet->extensions.video_rotation != -1 && handle->stream->videoorientation_ext_id > 0) ||
(packet->video && packet->extensions.dd_len > 0 && handle->stream->dependencydesc_ext_id > 0)) {
/* Do we need 2-byte extemsions, or are 1-byte extensions fine? */
gboolean use_2byte = (packet->video && packet->extensions.dd_len > 16 && handle->stream->dependencydesc_ext_id > 0);
/* Write the extension(s) */
header->extension = 1;
memset(extensions, 0, sizeof(extensions));
janus_rtp_header_extension *extheader = (janus_rtp_header_extension *)extensions;
extheader->type = htons(0xBEDE);
extheader->type = htons(use_2byte ? 0x1000 : 0xBEDE);
extheader->length = 0;
/* Iterate on all extensions we need */
char *index = extensions + 4;
/* Check if we need to add the abs-send-time extension */
if(packet->video && handle->stream->abs_send_time_ext_id > 0) {
*index = (handle->stream->abs_send_time_ext_id << 4) + 2;
/* We'll actually set the value later, when sending the packet */
memset(index+1, 0, 3);
index += 4;
extlen += 4;
if(!use_2byte) {
*index = (handle->stream->abs_send_time_ext_id << 4) + 2;
memset(index+1, 0, 3);
index += 4;
extlen += 4;
} else {
*index = handle->stream->abs_send_time_ext_id;
*(index+1) = 3;
memset(index+2, 0, 3);
index += 5;
extlen += 5;
}
}
/* Check if we need to add the transport-wide CC extension */
if(packet->video && handle->stream->transport_wide_cc_ext_id > 0) {
*index = (handle->stream->transport_wide_cc_ext_id << 4) + 1;
/* We'll actually set the sequence number later, when sending the packet */
memset(index+1, 0, 2);
index += 3;
extlen += 3;
if(!use_2byte) {
*index = (handle->stream->transport_wide_cc_ext_id << 4) + 1;
memset(index+1, 0, 2);
index += 3;
extlen += 3;
} else {
*index = handle->stream->transport_wide_cc_ext_id;
*(index+1) = 2;
memset(index+2, 0, 2);
index += 4;
extlen += 4;
}
}
/* Check if we need to add the mid extension */
if(handle->stream->mid_ext_id > 0) {
char *mid = packet->video ? handle->video_mid : handle->audio_mid;
if(mid != NULL) {
size_t midlen = strlen(mid) & 0x0F;
*index = (handle->stream->mid_ext_id << 4) + (midlen ? midlen-1 : 0);
memcpy(index+1, mid, midlen);
index += (midlen + 1);
extlen += (midlen + 1);
if(!use_2byte) {
size_t midlen = strlen(mid) & 0x0F;
*index = (handle->stream->mid_ext_id << 4) + (midlen ? midlen-1 : 0);
memcpy(index+1, mid, midlen);
index += (midlen + 1);
extlen += (midlen + 1);
} else {
size_t midlen = strlen(mid);
*index = handle->stream->mid_ext_id;
*(index+1) = midlen;
memcpy(index+2, mid, midlen);
index += (midlen + 2);
extlen += (midlen + 2);
}
}
}
/* Check if the plugin (or source) included other extensions */
if(!packet->video && packet->extensions.audio_level != -1 && handle->stream->audiolevel_ext_id > 0) {
/* Add audio-level extension */
*index = (handle->stream->audiolevel_ext_id << 4);
*(index+1) = (packet->extensions.audio_level_vad << 7) + (packet->extensions.audio_level & 0x7F);
index += 2;
extlen += 2;
if(!use_2byte) {
*index = (handle->stream->audiolevel_ext_id << 4);
*(index+1) = (packet->extensions.audio_level_vad << 7) + (packet->extensions.audio_level & 0x7F);
index += 2;
extlen += 2;
} else {
*index = handle->stream->audiolevel_ext_id;
*(index+1) = 1;
*(index+2) = (packet->extensions.audio_level_vad << 7) + (packet->extensions.audio_level & 0x7F);
index += 3;
extlen += 3;
}
}
if(packet->video && packet->extensions.video_rotation != -1 && handle->stream->videoorientation_ext_id > 0) {
/* Add video-orientation extension */
*index = (handle->stream->videoorientation_ext_id << 4);
gboolean c = packet->extensions.video_back_camera,
f = packet->extensions.video_flipped, r1 = FALSE, r0 = FALSE;
switch(packet->extensions.video_rotation) {
Expand All @@ -4941,9 +4987,34 @@ void janus_ice_relay_rtp(janus_ice_handle *handle, janus_plugin_rtp *packet) {
r0 = FALSE;
break;
}
*(index+1) = (c<<3) + (f<<2) + (r1<<1) + r0;
index += 2;
extlen += 2;
if(!use_2byte) {
*index = (handle->stream->videoorientation_ext_id << 4);
*(index+1) = (c<<3) + (f<<2) + (r1<<1) + r0;
index += 2;
extlen += 2;
} else {
*index = handle->stream->videoorientation_ext_id;
*(index+1) = 1;
*(index+2) = (c<<3) + (f<<2) + (r1<<1) + r0;
index += 3;
extlen += 3;
}
}
if(packet->video && packet->extensions.dd_len > 0 && handle->stream->dependencydesc_ext_id > 0) {
/* Add dependency descriptor extension */
if(!use_2byte) {
*index = (handle->stream->dependencydesc_ext_id << 4) + (packet->extensions.dd_len-1);
index++;
memcpy(index, packet->extensions.dd_content, packet->extensions.dd_len);
index += packet->extensions.dd_len;
extlen += packet->extensions.dd_len + 1;
} else {
*index = handle->stream->dependencydesc_ext_id;
*(index+1) = packet->extensions.dd_len;
memcpy(index+2, packet->extensions.dd_content, packet->extensions.dd_len);
index += packet->extensions.dd_len + 2;
extlen += packet->extensions.dd_len + 2;
}
}
/* Calculate the whole length */
uint16_t words = extlen/4;
Expand Down
2 changes: 2 additions & 0 deletions ice.h
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,8 @@ struct janus_ice_stream {
gint audiolevel_ext_id;
/*! \brief Video orientation extension ID */
gint videoorientation_ext_id;
/*! \brief Dependency descriptor extension ID */
gint dependencydesc_ext_id;
/*! \brief Absolute Send Time ext ID */
gint abs_send_time_ext_id;
/*! \brief Whether we do transport wide cc for video */
Expand Down
61 changes: 37 additions & 24 deletions janus.c
Original file line number Diff line number Diff line change
Expand Up @@ -1520,7 +1520,7 @@ int janus_process_incoming_request(janus_request *request) {
}
janus_request_ice_handle_answer(handle, audio, video, data, jsep_sdp);
/* Check if the answer does contain the mid/abs-send-time/twcc extmaps */
gboolean do_mid = FALSE, do_twcc = FALSE, do_abs_send_time = FALSE;
gboolean do_mid = FALSE, do_twcc = FALSE, do_dd = TRUE, do_abs_send_time = FALSE;
GList *temp = parsed_sdp->m_lines;
while(temp) {
janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
Expand All @@ -1532,6 +1532,8 @@ int janus_process_incoming_request(janus_request *request) {
do_mid = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC))
do_twcc = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_DEPENDENCY_DESC))
do_dd = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
do_abs_send_time = TRUE;
}
Expand All @@ -1545,6 +1547,8 @@ int janus_process_incoming_request(janus_request *request) {
handle->stream->do_transport_wide_cc = FALSE;
handle->stream->transport_wide_cc_ext_id = 0;
}
if(!do_dd && handle->stream)
handle->stream->dependencydesc_ext_id = 0;
if(!do_abs_send_time && handle->stream)
handle->stream->abs_send_time_ext_id = 0;
} else {
Expand All @@ -1563,6 +1567,8 @@ int janus_process_incoming_request(janus_request *request) {
int transport_wide_cc_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC);
handle->stream->do_transport_wide_cc = transport_wide_cc_ext_id > 0 ? TRUE : FALSE;
handle->stream->transport_wide_cc_ext_id = transport_wide_cc_ext_id;
/* Check if the dependency descriptor ID extension is being negotiated */
handle->stream->dependencydesc_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_DEPENDENCY_DESC);
}
} else {
/* FIXME This is a renegotiation: we can currently only handle simple changes in media
Expand Down Expand Up @@ -1626,6 +1632,8 @@ int janus_process_incoming_request(janus_request *request) {
int transport_wide_cc_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC);
handle->stream->do_transport_wide_cc = transport_wide_cc_ext_id > 0 ? TRUE : FALSE;
handle->stream->transport_wide_cc_ext_id = transport_wide_cc_ext_id;
/* Check if the dependency descriptor ID extension is being negotiated */
handle->stream->dependencydesc_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_DEPENDENCY_DESC);
}
}
char *tmp = handle->remote_sdp;
Expand Down Expand Up @@ -3120,6 +3128,8 @@ json_t *janus_admin_stream_summary(janus_ice_stream *stream) {
json_object_set_new(se, JANUS_RTP_EXTMAP_AUDIO_LEVEL, json_integer(stream->audiolevel_ext_id));
if(stream->videoorientation_ext_id > 0)
json_object_set_new(se, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION, json_integer(stream->videoorientation_ext_id));
if(stream->dependencydesc_ext_id > 0)
json_object_set_new(se, JANUS_RTP_EXTMAP_DEPENDENCY_DESC, json_integer(stream->dependencydesc_ext_id));
json_object_set_new(s, "extensions", se);
json_t *bwe = json_object();
json_object_set_new(bwe, "twcc", stream->do_transport_wide_cc ? json_true() : json_false());
Expand Down Expand Up @@ -3718,7 +3728,7 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
}
/* Make sure we don't send the rid/repaired-rid attributes when offering ourselves */
int mid_ext_id = 0, transport_wide_cc_ext_id = 0, abs_send_time_ext_id = 0,
audiolevel_ext_id = 0, videoorientation_ext_id = 0;
audiolevel_ext_id = 0, videoorientation_ext_id = 0, dependencydesc_ext_id = 0;
int opusred_pt = 0;
GList *temp = parsed_sdp->m_lines;
while(temp) {
Expand All @@ -3727,27 +3737,24 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
while(tempA) {
janus_sdp_attribute *a = (janus_sdp_attribute *)tempA->data;
if(a->name && a->value) {
if(!strcasecmp(a->name, "extmap")) {
if(strstr(a->value, JANUS_RTP_EXTMAP_MID))
mid_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC))
transport_wide_cc_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
abs_send_time_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_AUDIO_LEVEL))
audiolevel_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION))
videoorientation_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_RID) ||
strstr(a->value, JANUS_RTP_EXTMAP_REPAIRED_RID)) {
m->attributes = g_list_remove(m->attributes, a);
tempA = m->attributes;
janus_sdp_attribute_destroy(a);
continue;
}
} else if(m->type == JANUS_SDP_AUDIO && !strcasecmp(a->name, "rtpmap") &&
strstr(a->value, "red/48000/2")) {
opusred_pt = atoi(a->value);
if(strstr(a->value, JANUS_RTP_EXTMAP_MID))
mid_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC))
transport_wide_cc_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
abs_send_time_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_AUDIO_LEVEL))
audiolevel_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION))
videoorientation_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_DEPENDENCY_DESC))
dependencydesc_ext_id = atoi(a->value);
else if(strstr(a->value, JANUS_RTP_EXTMAP_RID) ||
strstr(a->value, JANUS_RTP_EXTMAP_REPAIRED_RID)) {
m->attributes = g_list_remove(m->attributes, a);
tempA = m->attributes;
janus_sdp_attribute_destroy(a);
continue;
}
}
tempA = tempA->next;
Expand All @@ -3768,10 +3775,12 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
ice_handle->stream->audiolevel_ext_id = audiolevel_ext_id;
if(ice_handle->stream && ice_handle->stream->videoorientation_ext_id != videoorientation_ext_id)
ice_handle->stream->videoorientation_ext_id = videoorientation_ext_id;
if(ice_handle->stream && ice_handle->stream->dependencydesc_ext_id != dependencydesc_ext_id)
ice_handle->stream->dependencydesc_ext_id = dependencydesc_ext_id;
} else {
/* Check if the answer does contain the mid/rid/repaired-rid/abs-send-time/twcc extmaps */
gboolean do_mid = FALSE, do_rid = FALSE, do_repaired_rid = FALSE,
do_twcc = FALSE, do_abs_send_time = FALSE;
do_dd = FALSE, do_twcc = FALSE, do_abs_send_time = FALSE;
int opusred_pt = -1;
GList *temp = parsed_sdp->m_lines;
while(temp) {
Expand All @@ -3789,6 +3798,8 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
do_repaired_rid = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC))
do_twcc = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_DEPENDENCY_DESC))
do_dd = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
do_abs_send_time = TRUE;
} else if(m->type == JANUS_SDP_AUDIO && ice_handle->stream->opusred_pt > 0 &&
Expand Down Expand Up @@ -3825,6 +3836,8 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
ice_handle->stream->do_transport_wide_cc = FALSE;
ice_handle->stream->transport_wide_cc_ext_id = 0;
}
if(!do_dd && ice_handle->stream)
ice_handle->stream->dependencydesc_ext_id = 0;
if(!do_abs_send_time && ice_handle->stream)
ice_handle->stream->abs_send_time_ext_id = 0;
}
Expand Down
1 change: 1 addition & 0 deletions plugins/janus_echotest.c
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,7 @@ static void *janus_echotest_handler(void *data) {
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_AUDIO_LEVEL,
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION,
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC,
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_DEPENDENCY_DESC,
JANUS_SDP_OA_DONE);
/* If we ended up sendonly, switch to inactive (as we don't really send anything ourselves) */
janus_sdp_mline *m = janus_sdp_mline_find(answer, JANUS_SDP_AUDIO);
Expand Down
Loading