From 9b2453d7402ca6b72142e28c73b29a1fd010f01c Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Thu, 1 Jul 2021 10:27:48 +0200 Subject: [PATCH 1/5] Don't offer TWCC for VideoRoom subscribers --- plugins/janus_videoroom.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 9bc532958b..e3d69d5463 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -7695,15 +7695,6 @@ 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) - break; - twcc_ext_id++; - } offer = janus_sdp_generate_offer(s_name, answer->c_addr, JANUS_SDP_OA_AUDIO, participant->audio, JANUS_SDP_OA_AUDIO_CODEC, janus_audiocodec_name(participant->acodec), @@ -7723,8 +7714,6 @@ 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_DATA, participant->data, JANUS_SDP_OA_DONE); /* Is this room recorded, or are we recording this publisher already? */ From 679868487f5b0319f424402476366196cab4cbdc Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Thu, 1 Jul 2021 15:33:18 +0200 Subject: [PATCH 2/5] Negotiate and generate abs-send-time RTP extensions in some plugins --- fuzzers/rtp_fuzzer.c | 1 + ice.c | 21 +++++++++++++- ice.h | 4 +-- janus.c | 58 ++++++++++++++++++++++++++++++++++++--- plugins/janus_streaming.c | 2 ++ plugins/janus_videoroom.c | 10 +++++++ rtp.c | 31 +++++++++++++++++++++ rtp.h | 16 +++++++++++ 8 files changed, 136 insertions(+), 7 deletions(-) diff --git a/fuzzers/rtp_fuzzer.c b/fuzzers/rtp_fuzzer.c index 6f0941f730..be97ef0f84 100644 --- a/fuzzers/rtp_fuzzer.c +++ b/fuzzers/rtp_fuzzer.c @@ -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; diff --git a/ice.c b/ice.c index 8e8a68e147..e50d1a3ff2 100644 --- a/ice.c +++ b/ice.c @@ -4484,6 +4484,16 @@ 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 ntp_ts = janus_get_monotonic_time(); + int64_t abs24 = (ntp_ts >> 14) & 0x00ffffff; + uint32_t abs_ts = abs24; + 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++; @@ -4774,7 +4784,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; @@ -4784,6 +4795,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; diff --git a/ice.h b/ice.h index e919c6fcf8..fdb166a871 100644 --- a/ice.h +++ b/ice.h @@ -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 */ diff --git a/janus.c b/janus.c index 13907957d7..f31575ad47 100644 --- a/janus.c +++ b/janus.c @@ -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); @@ -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; @@ -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; @@ -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) @@ -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; @@ -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)) @@ -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; } @@ -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 */ diff --git a/plugins/janus_streaming.c b/plugins/janus_streaming.c index 8e8c03999f..18ef52e5c6 100644 --- a/plugins/janus_streaming.c +++ b/plugins/janus_streaming.c @@ -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) { diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index e3d69d5463..084ee0f2ae 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -7695,6 +7695,15 @@ static void *janus_videoroom_handler(void *data) { break; mid_ext_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; + abs_send_time_ext_id++; + } offer = janus_sdp_generate_offer(s_name, answer->c_addr, JANUS_SDP_OA_AUDIO, participant->audio, JANUS_SDP_OA_AUDIO_CODEC, janus_audiocodec_name(participant->acodec), @@ -7714,6 +7723,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_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? */ diff --git a/rtp.c b/rtp.c index 18c634a135..a9be083dbc 100644 --- a/rtp.c +++ b/rtp.c @@ -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) diff --git a/rtp.h b/rtp.h index 34a6705f9a..6c298b4a38 100644 --- a/rtp.h +++ b/rtp.h @@ -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 From f5712f4af2c943baaafa5b20ebaa42c234d7650c Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Thu, 1 Jul 2021 15:58:58 +0200 Subject: [PATCH 3/5] Use real time instead of monotonic time --- ice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ice.c b/ice.c index e50d1a3ff2..9d191d402e 100644 --- a/ice.c +++ b/ice.c @@ -4486,7 +4486,7 @@ static gboolean janus_ice_outgoing_traffic_handle(janus_ice_handle *handle, janu } /* Set the abs-send-time value, if needed */ if(video && stream->abs_send_time_ext_id > 0) { - int64_t ntp_ts = janus_get_monotonic_time(); + int64_t ntp_ts = janus_get_real_time(); int64_t abs24 = (ntp_ts >> 14) & 0x00ffffff; uint32_t abs_ts = abs24; if(janus_rtp_header_extension_set_abs_send_time(pkt->data, pkt->length, From ea927407e141cecd713f44d8ae73b7d5fbb84359 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Thu, 1 Jul 2021 16:13:27 +0200 Subject: [PATCH 4/5] Actually use NTP timestamp as a basis --- ice.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ice.c b/ice.c index 9d191d402e..ca1c52233f 100644 --- a/ice.c +++ b/ice.c @@ -4486,8 +4486,13 @@ static gboolean janus_ice_outgoing_traffic_handle(janus_ice_handle *handle, janu } /* Set the abs-send-time value, if needed */ if(video && stream->abs_send_time_ext_id > 0) { - int64_t ntp_ts = janus_get_real_time(); - int64_t abs24 = (ntp_ts >> 14) & 0x00ffffff; + struct timeval tv; + gettimeofday(&tv, NULL); + uint64_t s = tv.tv_sec + 2208988800u; + uint32_t u = tv.tv_usec; + uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6); + uint64_t ntp_ts = (s << 32) + f; + uint64_t abs24 = (ntp_ts >> 14) & 0x00ffffff; uint32_t abs_ts = abs24; if(janus_rtp_header_extension_set_abs_send_time(pkt->data, pkt->length, stream->abs_send_time_ext_id, abs_ts) < 0) { From 8db97b3ba9d648176342dc99a49c5f002ab78aec Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Thu, 1 Jul 2021 16:48:11 +0200 Subject: [PATCH 5/5] Calculate timestamp the way libwebrtc does, using the monotonic time --- ice.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/ice.c b/ice.c index ca1c52233f..b31e3c8d37 100644 --- a/ice.c +++ b/ice.c @@ -4486,14 +4486,8 @@ static gboolean janus_ice_outgoing_traffic_handle(janus_ice_handle *handle, janu } /* Set the abs-send-time value, if needed */ if(video && stream->abs_send_time_ext_id > 0) { - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t s = tv.tv_sec + 2208988800u; - uint32_t u = tv.tv_usec; - uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6); - uint64_t ntp_ts = (s << 32) + f; - uint64_t abs24 = (ntp_ts >> 14) & 0x00ffffff; - uint32_t abs_ts = abs24; + 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);