Skip to content

Commit

Permalink
Add support for abs-capture-time RTP extension (#3161)
Browse files Browse the repository at this point in the history
  • Loading branch information
lminiero committed Nov 16, 2023
1 parent f74b313 commit 271d319
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 22 deletions.
3 changes: 2 additions & 1 deletion fuzzers/rtp_fuzzer.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
janus_rtp_header_extension_parse_audio_level((char *)data, size, 1, NULL, NULL);
janus_rtp_header_extension_parse_playout_delay((char *)data, size, 1, NULL, NULL);
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);
janus_rtp_header_extension_parse_abs_send_time((char *)data, size, 1, NULL);
janus_rtp_header_extension_parse_abs_capture_time((char *)data, size, 1, NULL);
janus_rtp_header_extension_parse_video_orientation((char * )data, size, 1, &c, &f, &r1, &r0);
janus_rtp_header_extension_parse_dependency_desc((char *)data, size, 1, (uint8_t *)&dd, &sizedd);

Expand Down
32 changes: 30 additions & 2 deletions src/ice.c
Original file line number Diff line number Diff line change
Expand Up @@ -2876,6 +2876,13 @@ static void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint comp
memcpy(rtp.extensions.dd_content, dd, len);
}
}
if(pc->abs_capture_time_ext_id != -1) {
uint64_t abs_ts = 0;
if(janus_rtp_header_extension_parse_abs_capture_time(buf, buflen,
pc->abs_capture_time_ext_id, &abs_ts) == 0) {
rtp.extensions.abs_capture_ts = abs_ts;
}
}
/* 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 @@ -3877,7 +3884,7 @@ static void janus_ice_rtp_extension_update(janus_ice_handle *handle, janus_ice_p
totlen += plen;
/* We need to strip extensions, here, and add those that need to be there manually */
uint16_t extlen = 0;
char extensions[300];
char extensions[320];
uint16_t extbufsize = sizeof(extensions);
janus_rtp_header *header = (janus_rtp_header *)packet->data;
header->extension = 0;
Expand All @@ -3888,7 +3895,8 @@ static void janus_ice_rtp_extension_update(janus_ice_handle *handle, janus_ice_p
(!video && packet->extensions.audio_level > -1 && handle->pc->audiolevel_ext_id > 0) ||
(video && packet->extensions.video_rotation > -1 && handle->pc->videoorientation_ext_id > 0) ||
(video && packet->extensions.min_delay > -1 && packet->extensions.max_delay > -1 && handle->pc->playoutdelay_ext_id > 0) ||
(video && packet->extensions.dd_len > 0 && handle->pc->dependencydesc_ext_id > 0)) {
(video && packet->extensions.dd_len > 0 && handle->pc->dependencydesc_ext_id > 0) ||
(packet->extensions.abs_capture_ts > 0 && handle->pc->abs_capture_time_ext_id > 0)) {
/* Do we need 2-byte extemsions, or are 1-byte extensions fine? */
gboolean use_2byte = (video && packet->extensions.dd_len > 16 && handle->pc->dependencydesc_ext_id > 0);
/* Write the extension(s) */
Expand Down Expand Up @@ -4071,6 +4079,26 @@ static void janus_ice_rtp_extension_update(janus_ice_handle *handle, janus_ice_p
}
}
}
/* Check if we need to add the abs-capture-time extension */
if(packet->extensions.abs_capture_ts > 0 && handle->pc->abs_capture_time_ext_id > 0) {
uint64_t abs64 = htonll(packet->extensions.abs_capture_ts);
if(!use_2byte) {
*index = (handle->pc->abs_capture_time_ext_id << 4) + 15;
memcpy(index+1, &abs64, 8);
memset(index+9, 0, 8);
index += 17;
extlen += 17;
extbufsize -= 17;
} else {
*index = handle->pc->abs_capture_time_ext_id;
*(index+1) = 16;
memcpy(index+2, &abs64, 8);
memset(index+8, 0, 8);
index += 18;
extlen += 18;
extbufsize -= 18;
}
}
/* Calculate the whole length */
uint16_t words = extlen/4;
if(extlen%4 != 0)
Expand Down
2 changes: 2 additions & 0 deletions src/ice.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,8 @@ struct janus_ice_peerconnection {
gint dependencydesc_ext_id;
/*! \brief Absolute Send Time ext ID */
gint abs_send_time_ext_id;
/*! \brief Absolute Capture Time ext ID */
gint abs_capture_time_ext_id;
/*! \brief Whether we do transport wide cc */
gboolean do_transport_wide_cc;
/*! \brief Transport wide cc rtp ext ID */
Expand Down
32 changes: 27 additions & 5 deletions src/janus.c
Original file line number Diff line number Diff line change
Expand Up @@ -1591,11 +1591,12 @@ int janus_process_incoming_request(janus_request *request) {
janus_request_ice_handle_answer(handle, jsep_sdp);
/* Check if the answer does contain the mid/abs-send-time/twcc extmaps */
int mindex = 0;
gboolean do_mid = FALSE, do_twcc = FALSE, do_dd = FALSE, do_abs_send_time = FALSE;
gboolean do_mid = FALSE, do_twcc = FALSE, do_dd = FALSE, do_abs_send_time = FALSE, do_abs_capture_time = FALSE;
GList *temp = parsed_sdp->m_lines;
while(temp) {
janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
gboolean have_mid = FALSE, have_twcc = FALSE, have_dd = FALSE, have_abs_send_time = FALSE;
gboolean have_mid = FALSE, have_twcc = FALSE, have_dd = FALSE,
have_abs_send_time = FALSE, have_abs_capture_time = FALSE;
GList *tempA = m->attributes;
while(tempA) {
janus_sdp_attribute *a = (janus_sdp_attribute *)tempA->data;
Expand All @@ -1608,13 +1609,16 @@ int janus_process_incoming_request(janus_request *request) {
have_dd = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
have_abs_send_time = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME))
have_abs_capture_time = TRUE;
}
tempA = tempA->next;
}
do_mid = do_mid || have_mid;
do_twcc = do_twcc || have_twcc;
do_dd = do_dd || have_dd;
do_abs_send_time = do_abs_send_time || have_abs_send_time;
do_abs_capture_time = do_abs_capture_time || have_abs_capture_time;
mindex++;
temp = temp->next;
}
Expand All @@ -1628,6 +1632,8 @@ int janus_process_incoming_request(janus_request *request) {
handle->pc->dependencydesc_ext_id = 0;
if(!do_abs_send_time && handle->pc)
handle->pc->abs_send_time_ext_id = 0;
if(!do_abs_capture_time && handle->pc)
handle->pc->abs_capture_time_ext_id = 0;
} else {
/* Check if the mid RTP extension is being negotiated */
handle->pc->mid_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_MID);
Expand All @@ -1642,6 +1648,8 @@ int janus_process_incoming_request(janus_request *request) {
handle->pc->playoutdelay_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_PLAYOUT_DELAY);
/* Check if the abs-send-time ID extension is being negotiated */
handle->pc->abs_send_time_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_ABS_SEND_TIME);
/* Check if the abs-capture-time ID extension is being negotiated */
handle->pc->abs_capture_time_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_ABS_CAPTURE_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->pc->do_transport_wide_cc = transport_wide_cc_ext_id > 0 ? TRUE : FALSE;
Expand Down Expand Up @@ -1708,6 +1716,8 @@ int janus_process_incoming_request(janus_request *request) {
handle->pc->playoutdelay_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_PLAYOUT_DELAY);
/* Check if the abs-send-time ID extension is being negotiated */
handle->pc->abs_send_time_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_ABS_SEND_TIME);
/* Check if the abs-capture-time ID extension is being negotiated */
handle->pc->abs_capture_time_ext_id = janus_rtp_header_extension_get_id(jsep_sdp, JANUS_RTP_EXTMAP_ABS_CAPTURE_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->pc->do_transport_wide_cc = transport_wide_cc_ext_id > 0 ? TRUE : FALSE;
Expand Down Expand Up @@ -3256,6 +3266,8 @@ json_t *janus_admin_peerconnection_summary(janus_ice_peerconnection *pc) {
json_object_set_new(se, JANUS_RTP_EXTMAP_REPAIRED_RID, json_integer(pc->ridrtx_ext_id));
if(pc->abs_send_time_ext_id > 0)
json_object_set_new(se, JANUS_RTP_EXTMAP_ABS_SEND_TIME, json_integer(pc->abs_send_time_ext_id));
if(pc->abs_capture_time_ext_id > 0)
json_object_set_new(se, JANUS_RTP_EXTMAP_ABS_SEND_TIME, json_integer(pc->abs_capture_time_ext_id));
if(pc->transport_wide_cc_ext_id > 0)
json_object_set_new(se, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC, json_integer(pc->transport_wide_cc_ext_id));
if(pc->audiolevel_ext_id > 0)
Expand Down Expand Up @@ -3824,7 +3836,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 mindex = 0;
int mid_ext_id = 0, transport_wide_cc_ext_id = 0, abs_send_time_ext_id = 0,
int mid_ext_id = 0, transport_wide_cc_ext_id = 0, abs_send_time_ext_id = 0, abs_capture_time_ext_id = 0,
audiolevel_ext_id = 0, videoorientation_ext_id = 0, playoutdelay_ext_id = 0, dependencydesc_ext_id = 0;
GList *temp = parsed_sdp->m_lines;
while(temp) {
Expand All @@ -3842,6 +3854,8 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
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_ABS_CAPTURE_TIME))
abs_capture_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 Down Expand Up @@ -3878,6 +3892,8 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
}
if(ice_handle->pc && ice_handle->pc->abs_send_time_ext_id != abs_send_time_ext_id)
ice_handle->pc->abs_send_time_ext_id = abs_send_time_ext_id;
if(ice_handle->pc && ice_handle->pc->abs_capture_time_ext_id != abs_capture_time_ext_id)
ice_handle->pc->abs_capture_time_ext_id = abs_capture_time_ext_id;
if(ice_handle->pc && ice_handle->pc->audiolevel_ext_id != audiolevel_ext_id)
ice_handle->pc->audiolevel_ext_id = audiolevel_ext_id;
if(ice_handle->pc && ice_handle->pc->videoorientation_ext_id != videoorientation_ext_id)
Expand All @@ -3891,15 +3907,16 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
/* Check if the answer does contain the mid/rid/repaired-rid/abs-send-time/twcc extmaps */
int mindex = 0;
gboolean do_mid = FALSE, do_rid = FALSE, do_repaired_rid = FALSE,
do_dd = FALSE, do_twcc = FALSE, do_abs_send_time = FALSE;
do_dd = FALSE, do_twcc = FALSE, do_abs_send_time = FALSE, do_abs_capture_time = FALSE;
GList *temp = parsed_sdp->m_lines;
janus_mutex_lock(&ice_handle->mutex);
while(temp) {
janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
janus_ice_peerconnection_medium *medium = ice_handle->pc ?
g_hash_table_lookup(ice_handle->pc->media, GUINT_TO_POINTER(mindex)) : NULL;
gboolean have_mid = FALSE, have_rid = FALSE, have_repaired_rid = FALSE,
have_twcc = FALSE, have_dd = FALSE, have_abs_send_time = FALSE, have_msid = FALSE;
have_twcc = FALSE, have_dd = FALSE, have_abs_send_time = FALSE,
have_abs_capture_time = FALSE, have_msid = FALSE;
int opusred_pt = -1;
GList *tempA = m->attributes;
while(tempA) {
Expand Down Expand Up @@ -3945,6 +3962,8 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
do_dd = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
have_abs_send_time = TRUE;
else if(strstr(a->value, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME))
have_abs_capture_time = TRUE;
} else if(m->type == JANUS_SDP_AUDIO && medium != NULL && medium->opusred_pt > 0 &&
a->name && a->value && !strcasecmp(a->name, "rtpmap") && strstr(a->value, "red/48000/2")) {
opusred_pt = atoi(a->value);
Expand Down Expand Up @@ -3979,6 +3998,7 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
do_twcc = do_twcc || have_twcc;
do_dd = do_dd || have_dd;
do_abs_send_time = do_abs_send_time || have_abs_send_time;
do_abs_capture_time = do_abs_capture_time || have_abs_capture_time;
mindex++;
temp = temp->next;
}
Expand All @@ -3998,6 +4018,8 @@ json_t *janus_plugin_handle_sdp(janus_plugin_session *plugin_session, janus_plug
ice_handle->pc->dependencydesc_ext_id = 0;
if(!do_abs_send_time && ice_handle->pc)
ice_handle->pc->abs_send_time_ext_id = 0;
if(!do_abs_capture_time && ice_handle->pc)
ice_handle->pc->abs_capture_time_ext_id = 0;
janus_mutex_unlock(&ice_handle->mutex);
}
if(!updating && !janus_ice_is_full_trickle_enabled()) {
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/janus_echotest.c
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,8 @@ static void *janus_echotest_handler(void *data) {
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC,
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_DEPENDENCY_DESC,
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_ABS_SEND_TIME,
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME,
JANUS_SDP_OA_DONE);
temp = temp->next;
}
Expand Down
4 changes: 1 addition & 3 deletions src/plugins/janus_recordplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -778,8 +778,6 @@ static void janus_recordplay_message_free(janus_recordplay_message *msg) {
#define JANUS_RECORDPLAY_ERROR_RECORDING_EXISTS 420
#define JANUS_RECORDPLAY_ERROR_UNKNOWN_ERROR 499

#define ntohll(x) ((1==ntohl(1)) ? (x) : ((gint64)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))

/* Plugin implementation */
int janus_recordplay_init(janus_callbacks *callback, const char *config_path) {
if(g_atomic_int_get(&stopping)) {
Expand Down Expand Up @@ -2529,7 +2527,7 @@ janus_recordplay_frame_packet *janus_recordplay_get_frames(const char *dir, cons
JANUS_LOG(LOG_WARN, "Missing data timestamp header");
break;
}
when = ntohll(when);
when = ntohll((uint64_t)when);
offset += sizeof(gint64);
len -= sizeof(gint64);
/* Generate frame packet and insert in the ordered list */
Expand Down
4 changes: 3 additions & 1 deletion src/plugins/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ janus_plugin *create(void) {
* Janus instance or it will crash.
*
*/
#define JANUS_PLUGIN_API_VERSION 102
#define JANUS_PLUGIN_API_VERSION 103

/*! \brief Initialization of all plugin properties to NULL
*
Expand Down Expand Up @@ -575,6 +575,8 @@ struct janus_plugin_rtp_extensions {
uint8_t dd_len;
/*! \brief Dependency Descriptor content */
uint8_t dd_content[256];
/*! \brief Absolute Capture Time timestamp */
uint64_t abs_capture_ts;
};
/*! \brief Helper method to initialise/reset the RTP extensions field
* @note This is important because each of the supported extensions may
Expand Down
5 changes: 1 addition & 4 deletions src/postprocessing/janus-pp-rec.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,6 @@ Usage: janus-pp-rec [OPTIONS] source.mjr
#include "pp-srt.h"
#include "pp-binary.h"

#define htonll(x) ((1==htonl(1)) ? (x) : ((gint64)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((gint64)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))

int janus_log_level = 4;
gboolean janus_log_timestamps = FALSE;
gboolean janus_log_colors = TRUE;
Expand Down Expand Up @@ -836,7 +833,7 @@ int main(int argc, char *argv[]) {
JANUS_LOG(LOG_WARN, "Missing data timestamp header");
break;
}
when = ntohll(when);
when = ntohll((uint64_t)when);
offset += sizeof(gint64);
len -= sizeof(gint64);
/* Generate frame packet and insert in the ordered list */
Expand Down
5 changes: 1 addition & 4 deletions src/record.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@
#include "debug.h"
#include "utils.h"

#define htonll(x) ((1==htonl(1)) ? (x) : ((gint64)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((gint64)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))


/* Info header in the structured recording */
static const char *header = "MJR00002";
Expand Down Expand Up @@ -439,7 +436,7 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt
}
if(recorder->type == JANUS_RECORDER_DATA) {
/* If it's data, then we need to prepend timing related info, as it's not there by itself */
gint64 now = htonll(janus_get_real_time());
gint64 now = htonll((uint64_t)janus_get_real_time());
res = fwrite(&now, sizeof(gint64), 1, recorder->file);
if(res != 1) {
JANUS_LOG(LOG_WARN, "Couldn't write data timestamp in .mjr file (%zu != %zu, %s), expect issues post-processing\n",
Expand Down
35 changes: 34 additions & 1 deletion src/rtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ const char *janus_rtp_header_extension_get_from_id(const char *sdp, int id) {
return JANUS_RTP_EXTMAP_TOFFSET;
if(strstr(extension, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
return JANUS_RTP_EXTMAP_ABS_SEND_TIME;
if(strstr(extension, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME))
return JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME;
if(strstr(extension, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC))
return JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC;
if(strstr(extension, JANUS_RTP_EXTMAP_MID))
Expand Down Expand Up @@ -332,7 +334,7 @@ int janus_rtp_header_extension_parse_dependency_desc(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) {
int janus_rtp_header_extension_parse_abs_send_time(char *buf, int len, int id, uint32_t *abs_ts) {
char *ext = NULL;
uint8_t idlen = 0;
if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
Expand Down Expand Up @@ -363,6 +365,37 @@ int janus_rtp_header_extension_set_abs_send_time(char *buf, int len, int id, uin
return 0;
}

int janus_rtp_header_extension_parse_abs_capture_time(char *buf, int len, int id, uint64_t *abs_ts) {
char *ext = NULL;
uint8_t idlen = 0;
if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
return -1;
/* a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time */
if(ext == NULL)
return -2;
if(idlen < 8 || idlen > len-(ext-buf)-1)
return -3;
uint64_t abs64 = 0;
memcpy(&abs64, ext, 8);
if(abs_ts)
*abs_ts = ntohll(abs64);
return 0;
}

int janus_rtp_header_extension_set_abs_capture_time(char *buf, int len, int id, uint64_t abs_ts) {
char *ext = NULL;
uint8_t idlen = 0;
if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
return -1;
if(ext == NULL)
return -2;
if(idlen < 8 || idlen > len-(ext-buf)-1)
return -3;
uint64_t abs64 = htonll(abs_ts);
memcpy(ext, &abs64, 8);
return 0;
}

int janus_rtp_header_extension_parse_transport_wide_cc(char *buf, int len, int id, uint16_t *transSeqNum) {
char *ext = NULL;
uint8_t idlen = 0;
Expand Down
Loading

0 comments on commit 271d319

Please sign in to comment.