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

Add support of abs-capture-time extension to streaming plugin and forwarding of it's value from rtp source #3291

Merged
merged 1 commit into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions conf/janus.plugin.streaming.jcfg.sample.in
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@
# assuming the browser supports the RTP extension in the first place.
# playoutdelay_ext = true
#
# To allow mountpoints to negotiate the abs-capture-time RTP extension,
# you can set the 'abscapturetime_src_ext_id' property to value in range 1..14 inclusive: this way, any
# subscriber can receive the abs-capture-time of incoming RTP streams,
# assuming the browser supports the RTP extension in the first place.
# Incoming RTP stream should provide abs-capture-time exactly in the same header id.
# abscapturetime_src_ext_id = 1
IbrayevRamil marked this conversation as resolved.
Show resolved Hide resolved
#
# The following options are only valid for the 'rtsp' type:
# url = RTSP stream URL (only for restreaming RTSP)
# rtsp_user = RTSP authorization username (only if type=rtsp)
Expand Down
18 changes: 8 additions & 10 deletions src/ice.c
Original file line number Diff line number Diff line change
Expand Up @@ -4103,20 +4103,18 @@ static void janus_ice_rtp_extension_update(janus_ice_handle *handle, janus_ice_p
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;
*index = (handle->pc->abs_capture_time_ext_id << 4) + 7;
memcpy(index+1, &abs64, 8);
memset(index+9, 0, 8);
index += 17;
extlen += 17;
extbufsize -= 17;
index += 9;
extlen += 9;
extbufsize -= 9;
} else {
*index = handle->pc->abs_capture_time_ext_id;
*(index+1) = 16;
*(index+1) = 8;
memcpy(index+2, &abs64, 8);
memset(index+8, 0, 8);
index += 18;
extlen += 18;
extbufsize -= 18;
index += 10;
extlen += 10;
extbufsize -= 10;
}
}
/* Calculate the whole length */
Expand Down
90 changes: 85 additions & 5 deletions src/plugins/janus_streaming.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ subscriber can customize the playout delay of incoming video streams,
assuming the browser supports the RTP extension in the first place.
playoutdelay_ext = true

To allow mountpoints to negotiate the abs-capture-time RTP extension,
you can set the 'abscapturetime_src_ext_id' property to value in range 1..14 inclusive: this way, any
subscriber can receive the abs-capture-time of incoming RTP streams,
assuming the browser supports the RTP extension in the first place.
Incoming RTP stream should provide abs-capture-time exactly in the same header id.
abscapturetime_src_ext_id = 1

The following options are only valid for the 'rtsp' type:
url = RTSP stream URL
rtsp_user = RTSP authorization username, if needed
Expand Down Expand Up @@ -1050,7 +1057,8 @@ static struct janus_json_parameter rtp_parameters[] = {
{"srtpsuite", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
{"srtpcrypto", JSON_STRING, 0},
{"e2ee", JANUS_JSON_BOOL, 0},
{"playoutdelay_ext", JANUS_JSON_BOOL, 0}
{"playoutdelay_ext", JANUS_JSON_BOOL, 0},
{"abscapturetime_src_ext_id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
};
static struct janus_json_parameter live_parameters[] = {
{"filename", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
Expand Down Expand Up @@ -1340,6 +1348,8 @@ typedef struct janus_streaming_rtp_source {
gboolean e2ee;
/* Whether the playout-delay extension should be negotiated or not for new subscribers */
gboolean playoutdelay_ext;
/* Extension header id in RTP source with abs-capture-time */
int abscapturetime_src_ext_id;
} janus_streaming_rtp_source;

typedef enum janus_streaming_media {
Expand Down Expand Up @@ -1488,7 +1498,8 @@ janus_streaming_rtp_source_stream *janus_streaming_create_rtp_source_stream(
gboolean textdata, gboolean buffermsg);
janus_streaming_mountpoint *janus_streaming_create_rtp_source(
uint64_t id, char *id_str, char *name, char *desc, char *metadata,
GList *media, int srtpsuite, char *srtpcrypto, int threads, int rtp_collision, gboolean e2ee, gboolean playoutdelay_ext);
GList *media, int srtpsuite, char *srtpcrypto, int threads, int rtp_collision,
gboolean e2ee, gboolean playoutdelay_ext, int abscapturetime_src_ext_id);
/* Helper to create a file/ondemand live source */
janus_streaming_mountpoint *janus_streaming_create_file_source(
uint64_t id, char *id_str, char *name, char *desc, char *metadata, char *filename, gboolean live,
Expand Down Expand Up @@ -1547,6 +1558,8 @@ typedef struct janus_streaming_session {
gboolean e2ee;
/* Whether the playout-delay extension should be negotiated */
gboolean playoutdelay_ext;
/* Extension header id in RTP source with abs-capture-time */
int abscapturetime_src_ext_id;
janus_mutex mutex;
volatile gint dataready;
volatile gint stopping;
Expand Down Expand Up @@ -2094,6 +2107,7 @@ int janus_streaming_init(janus_callbacks *callback, const char *config_path) {
janus_config_item *scrypto = janus_config_get(config, cat, janus_config_type_item, "srtpcrypto");
janus_config_item *e2ee = janus_config_get(config, cat, janus_config_type_item, "e2ee");
janus_config_item *pd = janus_config_get(config, cat, janus_config_type_item, "playoutdelay_ext");
janus_config_item *abscaptime_src_id = janus_config_get(config, cat, janus_config_type_item, "abscapturetime_src_ext_id");
gboolean is_private = priv && priv->value && janus_is_true(priv->value);
if(ssuite && ssuite->value && atoi(ssuite->value) != 32 && atoi(ssuite->value) != 80) {
JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid SRTP suite...\n", cat->name);
Expand All @@ -2110,6 +2124,15 @@ int janus_streaming_init(janus_callbacks *callback, const char *config_path) {
cl = cl->next;
continue;
}
int abscaptime_src_id_int = 0;
if(abscaptime_src_id && abscaptime_src_id->value) {
abscaptime_src_id_int = atoi(abscaptime_src_id->value);
if(abscaptime_src_id_int < 0 || abscaptime_src_id_int > 14) {
JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid abscaptime_src_id configuration...\n", cat->name);
cl = cl->next;
continue;
}
}
/* How are we adding media? */
if(media != NULL) {
/* We're using the new media-based configuration, iterate on all media objects */
Expand Down Expand Up @@ -2501,7 +2524,8 @@ int janus_streaming_init(janus_callbacks *callback, const char *config_path) {
(threads && threads->value) ? atoi(threads->value) : 0,
(rtpcollision && rtpcollision->value) ? atoi(rtpcollision->value) : 0,
(e2ee && e2ee->value) ? janus_is_true(e2ee->value) : FALSE,
(pd && pd->value) ? janus_is_true(pd->value) : FALSE)) == NULL) {
(pd && pd->value) ? janus_is_true(pd->value) : FALSE,
abscaptime_src_id_int)) == NULL) {
JANUS_LOG(LOG_ERR, "Error creating 'rtp' mountpoint '%s'...\n", cat->name);
cl = cl->next;
continue;
Expand Down Expand Up @@ -2997,6 +3021,8 @@ json_t *janus_streaming_query_session(janus_plugin_session *handle) {
json_object_set_new(pd, "max-delay", json_integer(s->max_delay));
json_object_set_new(info, "playout-delay", pd);
}
if(session->abscapturetime_src_ext_id > 0)
json_object_set_new(info, "abs-capture-time-src-ext-id", json_integer(session->abscapturetime_src_ext_id));
json_array_append_new(media, info);
temp = temp->next;
}
Expand Down Expand Up @@ -3394,6 +3420,16 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
json_t *scrypto = json_object_get(root, "srtpcrypto");
json_t *e2ee = json_object_get(root, "e2ee");
json_t *pd = json_object_get(root, "playoutdelay_ext");
json_t *abscaptime_src_id = json_object_get(root, "abscapturetime_src_ext_id");
IbrayevRamil marked this conversation as resolved.
Show resolved Hide resolved
if(abscaptime_src_id && (json_integer_value(abscaptime_src_id) < 1 || json_integer_value(abscaptime_src_id) > 14)) {
JANUS_LOG(LOG_ERR, "Invalid element (abscaptime_src_id must be an integer between 1 and 14)\n");
error_code = JANUS_STREAMING_ERROR_INVALID_ELEMENT;
g_snprintf(error_cause, 512, "Invalid element (abscaptime_src_id must be an integer between 1 and 14)");
janus_mutex_lock(&mountpoints_mutex);
g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
janus_mutex_unlock(&mountpoints_mutex);
goto prepare_response;
}
if(ssuite && json_integer_value(ssuite) != 32 && json_integer_value(ssuite) != 80) {
JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, invalid SRTP suite...\n");
error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
Expand Down Expand Up @@ -3818,7 +3854,8 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
threads ? json_integer_value(threads) : 0,
rtpcollision ? json_integer_value(rtpcollision) : 0,
e2ee ? json_is_true(e2ee) : FALSE,
pd ? json_is_true(pd) : FALSE);
pd ? json_is_true(pd) : FALSE,
abscaptime_src_id ? json_integer_value(abscaptime_src_id) : 0);
janus_mutex_lock(&mountpoints_mutex);
g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
janus_mutex_unlock(&mountpoints_mutex);
Expand Down Expand Up @@ -4176,6 +4213,10 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
janus_config_add(config, c, janus_config_item_create("e2ee", "true"));
if(source->playoutdelay_ext)
janus_config_add(config, c, janus_config_item_create("playoutdelay_ext", "true"));
if(source->abscapturetime_src_ext_id > 0) {
g_snprintf(value, BUFSIZ, "%d", source->abscapturetime_src_ext_id);
janus_config_add(config, c, janus_config_item_create("abscapturetime_src_ext_id", value));
}
/* Iterate on all media streams */
janus_config_array *media = janus_config_array_create("media");
janus_config_add(config, c, media);
Expand Down Expand Up @@ -4575,6 +4616,10 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
janus_config_add(config, c, janus_config_item_create("e2ee", "true"));
if(source->playoutdelay_ext)
janus_config_add(config, c, janus_config_item_create("playoutdelay_ext", "true"));
if(source->abscapturetime_src_ext_id > 0) {
g_snprintf(value, BUFSIZ, "%d", source->abscapturetime_src_ext_id);
janus_config_add(config, c, janus_config_item_create("abscapturetime_src_ext_id", value));
}
/* Iterate on all media streams */
janus_config_array *media = janus_config_array_create("media");
janus_config_add(config, c, media);
Expand Down Expand Up @@ -6132,6 +6177,8 @@ static void *janus_streaming_handler(void *data) {
session->e2ee = source->e2ee;
/* Also check if we have to offer the playout-delay extension */
session->playoutdelay_ext = source->playoutdelay_ext;
/* Also check if we have to offer the abs-capture-time extension */
session->abscapturetime_src_ext_id = source->abscapturetime_src_ext_id;
}
janus_refcount_increase(&session->ref);
done:
Expand All @@ -6153,6 +6200,8 @@ static void *janus_streaming_handler(void *data) {
JANUS_SDP_OA_DIRECTION, JANUS_SDP_SENDONLY,
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_MID, janus_rtp_extension_id(JANUS_RTP_EXTMAP_MID),
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_SEND_TIME, janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_SEND_TIME),
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME,
(session->abscapturetime_src_ext_id > 0 ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME) : 0),
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
(session->playoutdelay_ext ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_PLAYOUT_DELAY) : 0),
JANUS_SDP_OA_DONE);
Expand All @@ -6176,6 +6225,8 @@ static void *janus_streaming_handler(void *data) {
JANUS_SDP_OA_DIRECTION, JANUS_SDP_SENDONLY,
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_MID, janus_rtp_extension_id(JANUS_RTP_EXTMAP_MID),
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_SEND_TIME, janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_SEND_TIME),
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME,
(session->abscapturetime_src_ext_id > 0 ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME) : 0),
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
(session->playoutdelay_ext ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_PLAYOUT_DELAY) : 0),
JANUS_SDP_OA_DONE);
Expand All @@ -6192,6 +6243,8 @@ static void *janus_streaming_handler(void *data) {
JANUS_SDP_OA_DIRECTION, JANUS_SDP_SENDONLY,
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_MID, janus_rtp_extension_id(JANUS_RTP_EXTMAP_MID),
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_SEND_TIME, janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_SEND_TIME),
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME,
(session->abscapturetime_src_ext_id > 0 ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME) : 0),
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
(session->playoutdelay_ext ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_PLAYOUT_DELAY) : 0),
JANUS_SDP_OA_DONE);
Expand Down Expand Up @@ -6386,6 +6439,7 @@ static void *janus_streaming_handler(void *data) {
JANUS_SDP_OA_DIRECTION, JANUS_SDP_SENDONLY,
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_MID,
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_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
JANUS_SDP_OA_DONE);
/* Done */
Expand Down Expand Up @@ -6461,6 +6515,8 @@ static void *janus_streaming_handler(void *data) {
session->e2ee = source->e2ee;
/* Also check if we have to offer the playout-delay extension */
session->playoutdelay_ext = source->playoutdelay_ext;
/* Also check if we have to offer the abs-capture-time extension */
session->abscapturetime_src_ext_id = source->abscapturetime_src_ext_id;
/* Accept the m-line */
janus_sdp_generate_answer_mline(parsed_sdp, answer, m,
JANUS_SDP_OA_MLINE, m->type,
Expand All @@ -6470,6 +6526,7 @@ static void *janus_streaming_handler(void *data) {
JANUS_SDP_OA_DIRECTION, JANUS_SDP_SENDONLY,
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_MID,
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_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
JANUS_SDP_OA_DONE);
/* Done */
Expand Down Expand Up @@ -7547,7 +7604,8 @@ janus_streaming_rtp_source_stream *janus_streaming_create_rtp_source_stream(

janus_streaming_mountpoint *janus_streaming_create_rtp_source(
uint64_t id, char *id_str, char *name, char *desc, char *metadata,
GList *media, int srtpsuite, char *srtpcrypto, int threads, int rtp_collision, gboolean e2ee, gboolean playoutdelay_ext) {
GList *media, int srtpsuite, char *srtpcrypto, int threads, int rtp_collision,
gboolean e2ee, gboolean playoutdelay_ext, int abscapturetime_src_ext_id) {
char id_num[30];
if(!string_ids) {
g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id);
Expand Down Expand Up @@ -7673,6 +7731,7 @@ janus_streaming_mountpoint *janus_streaming_create_rtp_source(
live_rtp_source->rtp_collision = rtp_collision;
live_rtp_source->e2ee = e2ee;
live_rtp_source->playoutdelay_ext = playoutdelay_ext;
live_rtp_source->abscapturetime_src_ext_id = abscapturetime_src_ext_id;
live_rtp->source = live_rtp_source;
live_rtp->source_destroy = (GDestroyNotify) janus_streaming_rtp_source_free;
live_rtp->viewers = NULL;
Expand Down Expand Up @@ -10192,6 +10251,13 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data)
rtp.extensions.min_delay = s->min_delay;
rtp.extensions.max_delay = s->max_delay;
}
if(session->abscapturetime_src_ext_id > 0) {
uint64_t abs_ts = 0;
if(janus_rtp_header_extension_parse_abs_capture_time((char *)packet->data, packet->length,
session->abscapturetime_src_ext_id, &abs_ts) == 0) {
rtp.extensions.abs_capture_ts = abs_ts;
}
}
if(gateway != NULL)
gateway->relay_rtp(session->handle, &rtp);
if(override_mark_bit && !has_marker_bit) {
Expand Down Expand Up @@ -10267,6 +10333,13 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data)
rtp.extensions.min_delay = s->min_delay;
rtp.extensions.max_delay = s->max_delay;
}
if(session->abscapturetime_src_ext_id > 0) {
uint64_t abs_ts = 0;
if(janus_rtp_header_extension_parse_abs_capture_time((char *)packet->data, packet->length,
session->abscapturetime_src_ext_id, &abs_ts) == 0) {
rtp.extensions.abs_capture_ts = abs_ts;
}
}
if(gateway != NULL)
gateway->relay_rtp(session->handle, &rtp);
/* Restore the timestamp and sequence number to what the publisher set them to */
Expand All @@ -10288,6 +10361,13 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data)
rtp.extensions.min_delay = s->min_delay;
rtp.extensions.max_delay = s->max_delay;
}
if(session->abscapturetime_src_ext_id > 0) {
uint64_t abs_ts = 0;
if(janus_rtp_header_extension_parse_abs_capture_time((char *)packet->data, packet->length,
session->abscapturetime_src_ext_id, &abs_ts) == 0) {
rtp.extensions.abs_capture_ts = abs_ts;
}
}
if(gateway != NULL)
gateway->relay_rtp(session->handle, &rtp);
/* Restore the timestamp and sequence number to what the video source set them to */
Expand Down
2 changes: 2 additions & 0 deletions src/rtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,8 @@ int janus_rtp_extension_id(const char *type) {
return 14;
else if(!strcasecmp(type, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
return 2;
else if(!strcasecmp(type, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME))
return 7;
else if(!strcasecmp(type, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION))
return 13;
else if(!strcasecmp(type, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC))
Expand Down