Skip to content

Commit 2fa046b

Browse files
authored
Add support of abs-capture-time extension to Streaming plugin (#3291)
1 parent 9525ef6 commit 2fa046b

File tree

4 files changed

+102
-15
lines changed

4 files changed

+102
-15
lines changed

conf/janus.plugin.streaming.jcfg.sample.in

+7
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@
8383
# assuming the browser supports the RTP extension in the first place.
8484
# playoutdelay_ext = true
8585
#
86+
# To allow mountpoints to negotiate the abs-capture-time RTP extension,
87+
# you can set the 'abscapturetime_src_ext_id' property to value in range 1..14 inclusive: this way, any
88+
# subscriber can receive the abs-capture-time of incoming RTP streams,
89+
# assuming the browser supports the RTP extension in the first place.
90+
# Incoming RTP stream should provide abs-capture-time exactly in the same header id.
91+
# abscapturetime_src_ext_id = 1
92+
#
8693
# The following options are only valid for the 'rtsp' type:
8794
# url = RTSP stream URL (only for restreaming RTSP)
8895
# rtsp_user = RTSP authorization username (only if type=rtsp)

src/ice.c

+8-10
Original file line numberDiff line numberDiff line change
@@ -4103,20 +4103,18 @@ static void janus_ice_rtp_extension_update(janus_ice_handle *handle, janus_ice_p
41034103
if(packet->extensions.abs_capture_ts > 0 && handle->pc->abs_capture_time_ext_id > 0) {
41044104
uint64_t abs64 = htonll(packet->extensions.abs_capture_ts);
41054105
if(!use_2byte) {
4106-
*index = (handle->pc->abs_capture_time_ext_id << 4) + 15;
4106+
*index = (handle->pc->abs_capture_time_ext_id << 4) + 7;
41074107
memcpy(index+1, &abs64, 8);
4108-
memset(index+9, 0, 8);
4109-
index += 17;
4110-
extlen += 17;
4111-
extbufsize -= 17;
4108+
index += 9;
4109+
extlen += 9;
4110+
extbufsize -= 9;
41124111
} else {
41134112
*index = handle->pc->abs_capture_time_ext_id;
4114-
*(index+1) = 16;
4113+
*(index+1) = 8;
41154114
memcpy(index+2, &abs64, 8);
4116-
memset(index+8, 0, 8);
4117-
index += 18;
4118-
extlen += 18;
4119-
extbufsize -= 18;
4115+
index += 10;
4116+
extlen += 10;
4117+
extbufsize -= 10;
41204118
}
41214119
}
41224120
/* Calculate the whole length */

src/plugins/janus_streaming.c

+85-5
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ subscriber can customize the playout delay of incoming video streams,
144144
assuming the browser supports the RTP extension in the first place.
145145
playoutdelay_ext = true
146146
147+
To allow mountpoints to negotiate the abs-capture-time RTP extension,
148+
you can set the 'abscapturetime_src_ext_id' property to value in range 1..14 inclusive: this way, any
149+
subscriber can receive the abs-capture-time of incoming RTP streams,
150+
assuming the browser supports the RTP extension in the first place.
151+
Incoming RTP stream should provide abs-capture-time exactly in the same header id.
152+
abscapturetime_src_ext_id = 1
153+
147154
The following options are only valid for the 'rtsp' type:
148155
url = RTSP stream URL
149156
rtsp_user = RTSP authorization username, if needed
@@ -1050,7 +1057,8 @@ static struct janus_json_parameter rtp_parameters[] = {
10501057
{"srtpsuite", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
10511058
{"srtpcrypto", JSON_STRING, 0},
10521059
{"e2ee", JANUS_JSON_BOOL, 0},
1053-
{"playoutdelay_ext", JANUS_JSON_BOOL, 0}
1060+
{"playoutdelay_ext", JANUS_JSON_BOOL, 0},
1061+
{"abscapturetime_src_ext_id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
10541062
};
10551063
static struct janus_json_parameter live_parameters[] = {
10561064
{"filename", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
@@ -1340,6 +1348,8 @@ typedef struct janus_streaming_rtp_source {
13401348
gboolean e2ee;
13411349
/* Whether the playout-delay extension should be negotiated or not for new subscribers */
13421350
gboolean playoutdelay_ext;
1351+
/* Extension header id in RTP source with abs-capture-time */
1352+
int abscapturetime_src_ext_id;
13431353
} janus_streaming_rtp_source;
13441354

13451355
typedef enum janus_streaming_media {
@@ -1488,7 +1498,8 @@ janus_streaming_rtp_source_stream *janus_streaming_create_rtp_source_stream(
14881498
gboolean textdata, gboolean buffermsg);
14891499
janus_streaming_mountpoint *janus_streaming_create_rtp_source(
14901500
uint64_t id, char *id_str, char *name, char *desc, char *metadata,
1491-
GList *media, int srtpsuite, char *srtpcrypto, int threads, int rtp_collision, gboolean e2ee, gboolean playoutdelay_ext);
1501+
GList *media, int srtpsuite, char *srtpcrypto, int threads, int rtp_collision,
1502+
gboolean e2ee, gboolean playoutdelay_ext, int abscapturetime_src_ext_id);
14921503
/* Helper to create a file/ondemand live source */
14931504
janus_streaming_mountpoint *janus_streaming_create_file_source(
14941505
uint64_t id, char *id_str, char *name, char *desc, char *metadata, char *filename, gboolean live,
@@ -1547,6 +1558,8 @@ typedef struct janus_streaming_session {
15471558
gboolean e2ee;
15481559
/* Whether the playout-delay extension should be negotiated */
15491560
gboolean playoutdelay_ext;
1561+
/* Extension header id in RTP source with abs-capture-time */
1562+
int abscapturetime_src_ext_id;
15501563
janus_mutex mutex;
15511564
volatile gint dataready;
15521565
volatile gint stopping;
@@ -2094,6 +2107,7 @@ int janus_streaming_init(janus_callbacks *callback, const char *config_path) {
20942107
janus_config_item *scrypto = janus_config_get(config, cat, janus_config_type_item, "srtpcrypto");
20952108
janus_config_item *e2ee = janus_config_get(config, cat, janus_config_type_item, "e2ee");
20962109
janus_config_item *pd = janus_config_get(config, cat, janus_config_type_item, "playoutdelay_ext");
2110+
janus_config_item *abscaptime_src_id = janus_config_get(config, cat, janus_config_type_item, "abscapturetime_src_ext_id");
20972111
gboolean is_private = priv && priv->value && janus_is_true(priv->value);
20982112
if(ssuite && ssuite->value && atoi(ssuite->value) != 32 && atoi(ssuite->value) != 80) {
20992113
JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid SRTP suite...\n", cat->name);
@@ -2110,6 +2124,15 @@ int janus_streaming_init(janus_callbacks *callback, const char *config_path) {
21102124
cl = cl->next;
21112125
continue;
21122126
}
2127+
int abscaptime_src_id_int = 0;
2128+
if(abscaptime_src_id && abscaptime_src_id->value) {
2129+
abscaptime_src_id_int = atoi(abscaptime_src_id->value);
2130+
if(abscaptime_src_id_int < 0 || abscaptime_src_id_int > 14) {
2131+
JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid abscaptime_src_id configuration...\n", cat->name);
2132+
cl = cl->next;
2133+
continue;
2134+
}
2135+
}
21132136
/* How are we adding media? */
21142137
if(media != NULL) {
21152138
/* We're using the new media-based configuration, iterate on all media objects */
@@ -2501,7 +2524,8 @@ int janus_streaming_init(janus_callbacks *callback, const char *config_path) {
25012524
(threads && threads->value) ? atoi(threads->value) : 0,
25022525
(rtpcollision && rtpcollision->value) ? atoi(rtpcollision->value) : 0,
25032526
(e2ee && e2ee->value) ? janus_is_true(e2ee->value) : FALSE,
2504-
(pd && pd->value) ? janus_is_true(pd->value) : FALSE)) == NULL) {
2527+
(pd && pd->value) ? janus_is_true(pd->value) : FALSE,
2528+
abscaptime_src_id_int)) == NULL) {
25052529
JANUS_LOG(LOG_ERR, "Error creating 'rtp' mountpoint '%s'...\n", cat->name);
25062530
cl = cl->next;
25072531
continue;
@@ -2997,6 +3021,8 @@ json_t *janus_streaming_query_session(janus_plugin_session *handle) {
29973021
json_object_set_new(pd, "max-delay", json_integer(s->max_delay));
29983022
json_object_set_new(info, "playout-delay", pd);
29993023
}
3024+
if(session->abscapturetime_src_ext_id > 0)
3025+
json_object_set_new(info, "abs-capture-time-src-ext-id", json_integer(session->abscapturetime_src_ext_id));
30003026
json_array_append_new(media, info);
30013027
temp = temp->next;
30023028
}
@@ -3394,6 +3420,16 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
33943420
json_t *scrypto = json_object_get(root, "srtpcrypto");
33953421
json_t *e2ee = json_object_get(root, "e2ee");
33963422
json_t *pd = json_object_get(root, "playoutdelay_ext");
3423+
json_t *abscaptime_src_id = json_object_get(root, "abscapturetime_src_ext_id");
3424+
if(abscaptime_src_id && (json_integer_value(abscaptime_src_id) < 1 || json_integer_value(abscaptime_src_id) > 14)) {
3425+
JANUS_LOG(LOG_ERR, "Invalid element (abscaptime_src_id must be an integer between 1 and 14)\n");
3426+
error_code = JANUS_STREAMING_ERROR_INVALID_ELEMENT;
3427+
g_snprintf(error_cause, 512, "Invalid element (abscaptime_src_id must be an integer between 1 and 14)");
3428+
janus_mutex_lock(&mountpoints_mutex);
3429+
g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3430+
janus_mutex_unlock(&mountpoints_mutex);
3431+
goto prepare_response;
3432+
}
33973433
if(ssuite && json_integer_value(ssuite) != 32 && json_integer_value(ssuite) != 80) {
33983434
JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, invalid SRTP suite...\n");
33993435
error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
@@ -3818,7 +3854,8 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
38183854
threads ? json_integer_value(threads) : 0,
38193855
rtpcollision ? json_integer_value(rtpcollision) : 0,
38203856
e2ee ? json_is_true(e2ee) : FALSE,
3821-
pd ? json_is_true(pd) : FALSE);
3857+
pd ? json_is_true(pd) : FALSE,
3858+
abscaptime_src_id ? json_integer_value(abscaptime_src_id) : 0);
38223859
janus_mutex_lock(&mountpoints_mutex);
38233860
g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
38243861
janus_mutex_unlock(&mountpoints_mutex);
@@ -4176,6 +4213,10 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
41764213
janus_config_add(config, c, janus_config_item_create("e2ee", "true"));
41774214
if(source->playoutdelay_ext)
41784215
janus_config_add(config, c, janus_config_item_create("playoutdelay_ext", "true"));
4216+
if(source->abscapturetime_src_ext_id > 0) {
4217+
g_snprintf(value, BUFSIZ, "%d", source->abscapturetime_src_ext_id);
4218+
janus_config_add(config, c, janus_config_item_create("abscapturetime_src_ext_id", value));
4219+
}
41794220
/* Iterate on all media streams */
41804221
janus_config_array *media = janus_config_array_create("media");
41814222
janus_config_add(config, c, media);
@@ -4575,6 +4616,10 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
45754616
janus_config_add(config, c, janus_config_item_create("e2ee", "true"));
45764617
if(source->playoutdelay_ext)
45774618
janus_config_add(config, c, janus_config_item_create("playoutdelay_ext", "true"));
4619+
if(source->abscapturetime_src_ext_id > 0) {
4620+
g_snprintf(value, BUFSIZ, "%d", source->abscapturetime_src_ext_id);
4621+
janus_config_add(config, c, janus_config_item_create("abscapturetime_src_ext_id", value));
4622+
}
45784623
/* Iterate on all media streams */
45794624
janus_config_array *media = janus_config_array_create("media");
45804625
janus_config_add(config, c, media);
@@ -6132,6 +6177,8 @@ static void *janus_streaming_handler(void *data) {
61326177
session->e2ee = source->e2ee;
61336178
/* Also check if we have to offer the playout-delay extension */
61346179
session->playoutdelay_ext = source->playoutdelay_ext;
6180+
/* Also check if we have to offer the abs-capture-time extension */
6181+
session->abscapturetime_src_ext_id = source->abscapturetime_src_ext_id;
61356182
}
61366183
janus_refcount_increase(&session->ref);
61376184
done:
@@ -6153,6 +6200,8 @@ static void *janus_streaming_handler(void *data) {
61536200
JANUS_SDP_OA_DIRECTION, JANUS_SDP_SENDONLY,
61546201
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_MID, janus_rtp_extension_id(JANUS_RTP_EXTMAP_MID),
61556202
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_SEND_TIME, janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_SEND_TIME),
6203+
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME,
6204+
(session->abscapturetime_src_ext_id > 0 ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME) : 0),
61566205
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
61576206
(session->playoutdelay_ext ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_PLAYOUT_DELAY) : 0),
61586207
JANUS_SDP_OA_DONE);
@@ -6176,6 +6225,8 @@ static void *janus_streaming_handler(void *data) {
61766225
JANUS_SDP_OA_DIRECTION, JANUS_SDP_SENDONLY,
61776226
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_MID, janus_rtp_extension_id(JANUS_RTP_EXTMAP_MID),
61786227
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_SEND_TIME, janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_SEND_TIME),
6228+
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME,
6229+
(session->abscapturetime_src_ext_id > 0 ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME) : 0),
61796230
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
61806231
(session->playoutdelay_ext ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_PLAYOUT_DELAY) : 0),
61816232
JANUS_SDP_OA_DONE);
@@ -6192,6 +6243,8 @@ static void *janus_streaming_handler(void *data) {
61926243
JANUS_SDP_OA_DIRECTION, JANUS_SDP_SENDONLY,
61936244
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_MID, janus_rtp_extension_id(JANUS_RTP_EXTMAP_MID),
61946245
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_SEND_TIME, janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_SEND_TIME),
6246+
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME,
6247+
(session->abscapturetime_src_ext_id > 0 ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME) : 0),
61956248
JANUS_SDP_OA_EXTENSION, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
61966249
(session->playoutdelay_ext ? janus_rtp_extension_id(JANUS_RTP_EXTMAP_PLAYOUT_DELAY) : 0),
61976250
JANUS_SDP_OA_DONE);
@@ -6386,6 +6439,7 @@ static void *janus_streaming_handler(void *data) {
63866439
JANUS_SDP_OA_DIRECTION, JANUS_SDP_SENDONLY,
63876440
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_MID,
63886441
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_ABS_SEND_TIME,
6442+
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME,
63896443
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
63906444
JANUS_SDP_OA_DONE);
63916445
/* Done */
@@ -6461,6 +6515,8 @@ static void *janus_streaming_handler(void *data) {
64616515
session->e2ee = source->e2ee;
64626516
/* Also check if we have to offer the playout-delay extension */
64636517
session->playoutdelay_ext = source->playoutdelay_ext;
6518+
/* Also check if we have to offer the abs-capture-time extension */
6519+
session->abscapturetime_src_ext_id = source->abscapturetime_src_ext_id;
64646520
/* Accept the m-line */
64656521
janus_sdp_generate_answer_mline(parsed_sdp, answer, m,
64666522
JANUS_SDP_OA_MLINE, m->type,
@@ -6470,6 +6526,7 @@ static void *janus_streaming_handler(void *data) {
64706526
JANUS_SDP_OA_DIRECTION, JANUS_SDP_SENDONLY,
64716527
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_MID,
64726528
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_ABS_SEND_TIME,
6529+
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME,
64736530
JANUS_SDP_OA_ACCEPT_EXTMAP, JANUS_RTP_EXTMAP_PLAYOUT_DELAY,
64746531
JANUS_SDP_OA_DONE);
64756532
/* Done */
@@ -7547,7 +7604,8 @@ janus_streaming_rtp_source_stream *janus_streaming_create_rtp_source_stream(
75477604

75487605
janus_streaming_mountpoint *janus_streaming_create_rtp_source(
75497606
uint64_t id, char *id_str, char *name, char *desc, char *metadata,
7550-
GList *media, int srtpsuite, char *srtpcrypto, int threads, int rtp_collision, gboolean e2ee, gboolean playoutdelay_ext) {
7607+
GList *media, int srtpsuite, char *srtpcrypto, int threads, int rtp_collision,
7608+
gboolean e2ee, gboolean playoutdelay_ext, int abscapturetime_src_ext_id) {
75517609
char id_num[30];
75527610
if(!string_ids) {
75537611
g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id);
@@ -7673,6 +7731,7 @@ janus_streaming_mountpoint *janus_streaming_create_rtp_source(
76737731
live_rtp_source->rtp_collision = rtp_collision;
76747732
live_rtp_source->e2ee = e2ee;
76757733
live_rtp_source->playoutdelay_ext = playoutdelay_ext;
7734+
live_rtp_source->abscapturetime_src_ext_id = abscapturetime_src_ext_id;
76767735
live_rtp->source = live_rtp_source;
76777736
live_rtp->source_destroy = (GDestroyNotify) janus_streaming_rtp_source_free;
76787737
live_rtp->viewers = NULL;
@@ -10192,6 +10251,13 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data)
1019210251
rtp.extensions.min_delay = s->min_delay;
1019310252
rtp.extensions.max_delay = s->max_delay;
1019410253
}
10254+
if(session->abscapturetime_src_ext_id > 0) {
10255+
uint64_t abs_ts = 0;
10256+
if(janus_rtp_header_extension_parse_abs_capture_time((char *)packet->data, packet->length,
10257+
session->abscapturetime_src_ext_id, &abs_ts) == 0) {
10258+
rtp.extensions.abs_capture_ts = abs_ts;
10259+
}
10260+
}
1019510261
if(gateway != NULL)
1019610262
gateway->relay_rtp(session->handle, &rtp);
1019710263
if(override_mark_bit && !has_marker_bit) {
@@ -10267,6 +10333,13 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data)
1026710333
rtp.extensions.min_delay = s->min_delay;
1026810334
rtp.extensions.max_delay = s->max_delay;
1026910335
}
10336+
if(session->abscapturetime_src_ext_id > 0) {
10337+
uint64_t abs_ts = 0;
10338+
if(janus_rtp_header_extension_parse_abs_capture_time((char *)packet->data, packet->length,
10339+
session->abscapturetime_src_ext_id, &abs_ts) == 0) {
10340+
rtp.extensions.abs_capture_ts = abs_ts;
10341+
}
10342+
}
1027010343
if(gateway != NULL)
1027110344
gateway->relay_rtp(session->handle, &rtp);
1027210345
/* Restore the timestamp and sequence number to what the publisher set them to */
@@ -10288,6 +10361,13 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data)
1028810361
rtp.extensions.min_delay = s->min_delay;
1028910362
rtp.extensions.max_delay = s->max_delay;
1029010363
}
10364+
if(session->abscapturetime_src_ext_id > 0) {
10365+
uint64_t abs_ts = 0;
10366+
if(janus_rtp_header_extension_parse_abs_capture_time((char *)packet->data, packet->length,
10367+
session->abscapturetime_src_ext_id, &abs_ts) == 0) {
10368+
rtp.extensions.abs_capture_ts = abs_ts;
10369+
}
10370+
}
1029110371
if(gateway != NULL)
1029210372
gateway->relay_rtp(session->handle, &rtp);
1029310373
/* Restore the timestamp and sequence number to what the video source set them to */

src/rtp.c

+2
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,8 @@ int janus_rtp_extension_id(const char *type) {
504504
return 14;
505505
else if(!strcasecmp(type, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
506506
return 2;
507+
else if(!strcasecmp(type, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME))
508+
return 7;
507509
else if(!strcasecmp(type, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION))
508510
return 13;
509511
else if(!strcasecmp(type, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC))

0 commit comments

Comments
 (0)