Skip to content

Commit

Permalink
Support for abs-send-time RTP extension (#2721)
Browse files Browse the repository at this point in the history
  • Loading branch information
lminiero committed Jul 28, 2021
1 parent a2f3714 commit 07fc09d
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 16 deletions.
1 change: 1 addition & 0 deletions fuzzers/rtp_fuzzer.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
janus_rtp_header_extension_parse_rid((char *)data, size, 1, sdes_item, sizeof(sdes_item));
janus_rtp_header_extension_parse_mid((char *)data, size, 1, sdes_item, sizeof(sdes_item));
janus_rtp_header_extension_parse_transport_wide_cc((char *)data, size, 1, &transport_seq_num);
janus_rtp_header_extension_parse_abs_sent_time((char *)data, size, 1, NULL);

/* Extract codec payload */
int plen = 0;
Expand Down
20 changes: 19 additions & 1 deletion ice.c
Original file line number Diff line number Diff line change
Expand Up @@ -4484,6 +4484,15 @@ static gboolean janus_ice_outgoing_traffic_handle(janus_ice_handle *handle, janu
/* ... but only if this isn't a retransmission (for those we already set it before) */
header->ssrc = htonl(video ? stream->video_ssrc : stream->audio_ssrc);
}
/* Set the abs-send-time value, if needed */
if(video && stream->abs_send_time_ext_id > 0) {
int64_t now = (((janus_get_monotonic_time()/1000) << 18) + 500) / 1000;
uint32_t abs_ts = (uint32_t)now & 0x00FFFFFF;
if(janus_rtp_header_extension_set_abs_send_time(pkt->data, pkt->length,
stream->abs_send_time_ext_id, abs_ts) < 0) {
JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error setting abs-send-time value...\n", handle->handle_id);
}
}
/* Set the transport-wide sequence number, if needed */
if(video && stream->transport_wide_cc_ext_id > 0) {
stream->transport_wide_cc_out_seq_num++;
Expand Down Expand Up @@ -4774,7 +4783,8 @@ void janus_ice_relay_rtp(janus_ice_handle *handle, janus_plugin_rtp *packet) {
int origext = header->extension;
header->extension = 0;
/* Add core and plugin extensions, if any */
if((packet->video && handle->stream->transport_wide_cc_ext_id > 0) || handle->stream->mid_ext_id > 0 ||
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)) {
header->extension = 1;
Expand All @@ -4784,6 +4794,14 @@ void janus_ice_relay_rtp(janus_ice_handle *handle, janus_plugin_rtp *packet) {
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;
}
/* 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;
Expand Down
4 changes: 2 additions & 2 deletions ice.h
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,8 @@ struct janus_ice_stream {
gint audiolevel_ext_id;
/*! \brief Video orientation extension ID */
gint videoorientation_ext_id;
/*! \brief Frame marking extension ID */
gint framemarking_ext_id;
/*! \brief Absolute Send Time ext ID */
gint abs_send_time_ext_id;
/*! \brief Whether we do transport wide cc for video */
gboolean do_transport_wide_cc;
/*! \brief Transport wide cc rtp ext ID */
Expand Down
58 changes: 54 additions & 4 deletions janus.c
Original file line number Diff line number Diff line change
Expand Up @@ -1490,6 +1490,34 @@ int janus_process_incoming_request(janus_request *request) {
janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE);
}
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;
GList *temp = parsed_sdp->m_lines;
while(temp) {
janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
GList *tempA = m->attributes;
while(tempA) {
janus_sdp_attribute *a = (janus_sdp_attribute *)tempA->data;
if(a->name && a->value && !strcasecmp(a->name, "extmap")) {
if(strstr(a->value, JANUS_RTP_EXTMAP_MID))
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_ABS_SEND_TIME))
do_abs_send_time = TRUE;
}
tempA = tempA->next;
}
temp = temp->next;
}
if(!do_mid && handle->stream)
handle->stream->mid_ext_id = 0;
if(!do_twcc && handle->stream) {
handle->stream->do_transport_wide_cc = FALSE;
handle->stream->transport_wide_cc_ext_id = 0;
}
if(!do_abs_send_time && handle->stream)
handle->stream->abs_send_time_ext_id = 0;
} else {
/* Check if the mid RTP extension is being negotiated */
handle->stream->mid_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_MID);
Expand All @@ -1500,6 +1528,8 @@ int janus_process_incoming_request(janus_request *request) {
handle->stream->audiolevel_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_AUDIO_LEVEL);
/* Check if the video orientation ID extension is being negotiated */
handle->stream->videoorientation_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION);
/* Check if the abs-send-time ID extension is being negotiated */
handle->stream->abs_send_time_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_ABS_SEND_TIME);
/* Check if transport wide CC is supported */
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;
Expand Down Expand Up @@ -1561,6 +1591,8 @@ int janus_process_incoming_request(janus_request *request) {
handle->stream->audiolevel_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_AUDIO_LEVEL);
/* Check if the video orientation ID extension is being negotiated */
handle->stream->videoorientation_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION);
/* Check if the abs-send-time ID extension is being negotiated */
handle->stream->abs_send_time_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_ABS_SEND_TIME);
/* Check if transport wide CC is supported */
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;
Expand Down Expand Up @@ -3049,6 +3081,8 @@ json_t *janus_admin_stream_summary(janus_ice_stream *stream) {
json_object_set_new(se, JANUS_RTP_EXTMAP_RID, json_integer(stream->rid_ext_id));
if(stream->ridrtx_ext_id > 0)
json_object_set_new(se, JANUS_RTP_EXTMAP_REPAIRED_RID, json_integer(stream->ridrtx_ext_id));
if(stream->abs_send_time_ext_id > 0)
json_object_set_new(se, JANUS_RTP_EXTMAP_ABS_SEND_TIME, json_integer(stream->abs_send_time_ext_id));
if(stream->transport_wide_cc_ext_id > 0)
json_object_set_new(se, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC, json_integer(stream->transport_wide_cc_ext_id));
if(stream->audiolevel_ext_id > 0)
Expand Down Expand Up @@ -3650,7 +3684,8 @@ 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, audiolevel_ext_id = 0, videoorientation_ext_id = 0;
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;
GList *temp = parsed_sdp->m_lines;
while(temp) {
janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
Expand All @@ -3662,6 +3697,8 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
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))
Expand All @@ -3684,26 +3721,33 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
ice_handle->stream->do_transport_wide_cc = transport_wide_cc_ext_id > 0 ? TRUE : FALSE;
ice_handle->stream->transport_wide_cc_ext_id = transport_wide_cc_ext_id;
}
if(ice_handle->stream && ice_handle->stream->abs_send_time_ext_id != abs_send_time_ext_id)
ice_handle->stream->abs_send_time_ext_id = abs_send_time_ext_id;
if(ice_handle->stream && ice_handle->stream->audiolevel_ext_id != audiolevel_ext_id)
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;
} else {
/* Check if the answer does contain the mid/rid/repaired-rid attributes */
gboolean do_mid = FALSE, do_rid = FALSE, do_repaired_rid = FALSE;
/* 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;
GList *temp = parsed_sdp->m_lines;
while(temp) {
janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
GList *tempA = m->attributes;
while(tempA) {
janus_sdp_attribute *a = (janus_sdp_attribute *)tempA->data;
if(a->name && a->value) {
if(a->name && a->value && !strcasecmp(a->name, "extmap")) {
if(strstr(a->value, JANUS_RTP_EXTMAP_MID))
do_mid = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_RID))
do_rid = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_REPAIRED_RID))
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_ABS_SEND_TIME))
do_abs_send_time = TRUE;
}
tempA = tempA->next;
}
Expand All @@ -3727,6 +3771,12 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
}
if(!do_repaired_rid && ice_handle->stream)
ice_handle->stream->ridrtx_ext_id = 0;
if(!do_twcc && ice_handle->stream) {
ice_handle->stream->do_transport_wide_cc = FALSE;
ice_handle->stream->transport_wide_cc_ext_id = 0;
}
if(!do_abs_send_time && ice_handle->stream)
ice_handle->stream->abs_send_time_ext_id = 0;
}
if(!updating && !janus_ice_is_full_trickle_enabled()) {
/* Wait for candidates-done callback */
Expand Down
2 changes: 2 additions & 0 deletions plugins/janus_streaming.c
Original file line number Diff line number Diff line change
Expand Up @@ -4957,6 +4957,8 @@ static void *janus_streaming_handler(void *data) {
g_strlcat(sdptemp, "a=sendonly\r\n", 2048);
g_snprintf(buffer, 512, "a=extmap:%d %s\r\n", 1, JANUS_RTP_EXTMAP_MID);
g_strlcat(sdptemp, buffer, 2048);
g_snprintf(buffer, 512, "a=extmap:%d %s\r\n", 2, JANUS_RTP_EXTMAP_ABS_SEND_TIME);
g_strlcat(sdptemp, buffer, 2048);
}
#ifdef HAVE_SCTP
if(mp->data && session->data) {
Expand Down
17 changes: 8 additions & 9 deletions plugins/janus_videoroom.c
Original file line number Diff line number Diff line change
Expand Up @@ -7708,14 +7708,14 @@ static void *janus_videoroom_handler(void *data) {
break;
mid_ext_id++;
}
int twcc_ext_id = 1;
while(twcc_ext_id < 15) {
if(twcc_ext_id != mid_ext_id &&
twcc_ext_id != participant->audio_level_extmap_id &&
twcc_ext_id != participant->video_orient_extmap_id &&
twcc_ext_id != participant->playout_delay_extmap_id)
int abs_send_time_ext_id = 1;
while(abs_send_time_ext_id < 15) {
if(abs_send_time_ext_id != mid_ext_id &&
abs_send_time_ext_id != participant->audio_level_extmap_id &&
abs_send_time_ext_id != participant->video_orient_extmap_id &&
abs_send_time_ext_id != participant->playout_delay_extmap_id)
break;
twcc_ext_id++;
abs_send_time_ext_id++;
}
offer = janus_sdp_generate_offer(s_name, answer->c_addr,
JANUS_SDP_OA_AUDIO, participant->audio,
Expand All @@ -7736,8 +7736,7 @@ static void *janus_videoroom_handler(void *data) {
participant->video_orient_extmap_id > 0 ? participant->video_orient_extmap_id : 0,
JANUS_SDP_OA_VIDEO_EXTENSION, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
participant->playout_delay_extmap_id > 0 ? participant->playout_delay_extmap_id : 0,
JANUS_SDP_OA_VIDEO_EXTENSION, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC,
videoroom->transport_wide_cc_ext ? twcc_ext_id : 0,
JANUS_SDP_OA_VIDEO_EXTENSION, JANUS_RTP_EXTMAP_ABS_SEND_TIME, abs_send_time_ext_id,
JANUS_SDP_OA_DATA, participant->data,
JANUS_SDP_OA_DONE);
/* Is this room recorded, or are we recording this publisher already? */
Expand Down
31 changes: 31 additions & 0 deletions rtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,37 @@ int janus_rtp_header_extension_parse_rid(char *buf, int len, int id,
return 0;
}

int janus_rtp_header_extension_parse_abs_sent_time(char *buf, int len, int id, uint32_t *abs_ts) {
char *ext = NULL;
if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0)
return -1;
/* a=extmap:4 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time */
if(ext == NULL)
return -2;
int val_len = (*ext & 0x0F) + 1;
if(val_len < 3 || val_len > len-(ext-buf)-1)
return -3;
uint32_t abs24 = 0;
memcpy(&abs24, ext+1, 3);
if(abs_ts)
*abs_ts = ntohl(abs24 << 8);
return 0;
}

int janus_rtp_header_extension_set_abs_send_time(char *buf, int len, int id, uint32_t abs_ts) {
char *ext = NULL;
if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0)
return -1;
if(ext == NULL)
return -2;
int val_len = (*ext & 0x0F) + 1;
if(val_len < 3 || val_len > len-(ext-buf)-1)
return -3;
uint32_t abs24 = htonl(abs_ts) >> 8;
memcpy(ext+1, &abs24, 3);
return 0;
}

int janus_rtp_header_extension_parse_transport_wide_cc(char *buf, int len, int id, uint16_t *transSeqNum) {
char *ext = NULL;
if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0)
Expand Down
16 changes: 16 additions & 0 deletions rtp.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,22 @@ int janus_rtp_header_extension_parse_mid(char *buf, int len, int id,
int janus_rtp_header_extension_parse_rid(char *buf, int len, int id,
char *sdes_item, int sdes_len);

/*! \brief Helper to parse an abs-send-time RTP extension (http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time)
* @param[in] buf The packet data
* @param[in] len The packet data length in bytes
* @param[in] id The extension ID to look for
* @param[out] abs_ts Variable where the parsed abs-send-time value will be stored
* @returns 0 if found, -1 otherwise */
int janus_rtp_header_extension_parse_abs_sent_time(char *buf, int len, int id, uint32_t *abs_ts);

/*! \brief Helper to set an abs-send-time RTP extension (http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time)
* @param[in] buf The packet data
* @param[in] len The packet data length in bytes
* @param[in] id The extension ID to look for
* @param[out] abs_ts Absolute Send Time value to set
* @returns 0 if found, -1 otherwise */
int janus_rtp_header_extension_set_abs_send_time(char *buf, int len, int id, uint32_t abs_ts);

/*! \brief Helper to parse a transport wide sequence number (https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01)
* @param[in] buf The packet data
* @param[in] len The packet data length in bytes
Expand Down

0 comments on commit 07fc09d

Please sign in to comment.