@@ -144,6 +144,13 @@ subscriber can customize the playout delay of incoming video streams,
144
144
assuming the browser supports the RTP extension in the first place.
145
145
playoutdelay_ext = true
146
146
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
+
147
154
The following options are only valid for the 'rtsp' type:
148
155
url = RTSP stream URL
149
156
rtsp_user = RTSP authorization username, if needed
@@ -1050,7 +1057,8 @@ static struct janus_json_parameter rtp_parameters[] = {
1050
1057
{"srtpsuite" , JSON_INTEGER , JANUS_JSON_PARAM_POSITIVE },
1051
1058
{"srtpcrypto" , JSON_STRING , 0 },
1052
1059
{"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 }
1054
1062
};
1055
1063
static struct janus_json_parameter live_parameters [] = {
1056
1064
{"filename" , JSON_STRING , JANUS_JSON_PARAM_REQUIRED },
@@ -1340,6 +1348,8 @@ typedef struct janus_streaming_rtp_source {
1340
1348
gboolean e2ee ;
1341
1349
/* Whether the playout-delay extension should be negotiated or not for new subscribers */
1342
1350
gboolean playoutdelay_ext ;
1351
+ /* Extension header id in RTP source with abs-capture-time */
1352
+ int abscapturetime_src_ext_id ;
1343
1353
} janus_streaming_rtp_source ;
1344
1354
1345
1355
typedef enum janus_streaming_media {
@@ -1488,7 +1498,8 @@ janus_streaming_rtp_source_stream *janus_streaming_create_rtp_source_stream(
1488
1498
gboolean textdata , gboolean buffermsg );
1489
1499
janus_streaming_mountpoint * janus_streaming_create_rtp_source (
1490
1500
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 );
1492
1503
/* Helper to create a file/ondemand live source */
1493
1504
janus_streaming_mountpoint * janus_streaming_create_file_source (
1494
1505
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 {
1547
1558
gboolean e2ee ;
1548
1559
/* Whether the playout-delay extension should be negotiated */
1549
1560
gboolean playoutdelay_ext ;
1561
+ /* Extension header id in RTP source with abs-capture-time */
1562
+ int abscapturetime_src_ext_id ;
1550
1563
janus_mutex mutex ;
1551
1564
volatile gint dataready ;
1552
1565
volatile gint stopping ;
@@ -2094,6 +2107,7 @@ int janus_streaming_init(janus_callbacks *callback, const char *config_path) {
2094
2107
janus_config_item * scrypto = janus_config_get (config , cat , janus_config_type_item , "srtpcrypto" );
2095
2108
janus_config_item * e2ee = janus_config_get (config , cat , janus_config_type_item , "e2ee" );
2096
2109
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" );
2097
2111
gboolean is_private = priv && priv -> value && janus_is_true (priv -> value );
2098
2112
if (ssuite && ssuite -> value && atoi (ssuite -> value ) != 32 && atoi (ssuite -> value ) != 80 ) {
2099
2113
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) {
2110
2124
cl = cl -> next ;
2111
2125
continue ;
2112
2126
}
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
+ }
2113
2136
/* How are we adding media? */
2114
2137
if (media != NULL ) {
2115
2138
/* 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) {
2501
2524
(threads && threads -> value ) ? atoi (threads -> value ) : 0 ,
2502
2525
(rtpcollision && rtpcollision -> value ) ? atoi (rtpcollision -> value ) : 0 ,
2503
2526
(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 ) {
2505
2529
JANUS_LOG (LOG_ERR , "Error creating 'rtp' mountpoint '%s'...\n" , cat -> name );
2506
2530
cl = cl -> next ;
2507
2531
continue ;
@@ -2997,6 +3021,8 @@ json_t *janus_streaming_query_session(janus_plugin_session *handle) {
2997
3021
json_object_set_new (pd , "max-delay" , json_integer (s -> max_delay ));
2998
3022
json_object_set_new (info , "playout-delay" , pd );
2999
3023
}
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 ));
3000
3026
json_array_append_new (media , info );
3001
3027
temp = temp -> next ;
3002
3028
}
@@ -3394,6 +3420,16 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
3394
3420
json_t * scrypto = json_object_get (root , "srtpcrypto" );
3395
3421
json_t * e2ee = json_object_get (root , "e2ee" );
3396
3422
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
+ }
3397
3433
if (ssuite && json_integer_value (ssuite ) != 32 && json_integer_value (ssuite ) != 80 ) {
3398
3434
JANUS_LOG (LOG_ERR , "Can't add 'rtp' stream, invalid SRTP suite...\n" );
3399
3435
error_code = JANUS_STREAMING_ERROR_CANT_CREATE ;
@@ -3818,7 +3854,8 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
3818
3854
threads ? json_integer_value (threads ) : 0 ,
3819
3855
rtpcollision ? json_integer_value (rtpcollision ) : 0 ,
3820
3856
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 );
3822
3859
janus_mutex_lock (& mountpoints_mutex );
3823
3860
g_hash_table_remove (mountpoints_temp , string_ids ? (gpointer )mpid_str : (gpointer )& mpid );
3824
3861
janus_mutex_unlock (& mountpoints_mutex );
@@ -4176,6 +4213,10 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
4176
4213
janus_config_add (config , c , janus_config_item_create ("e2ee" , "true" ));
4177
4214
if (source -> playoutdelay_ext )
4178
4215
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
+ }
4179
4220
/* Iterate on all media streams */
4180
4221
janus_config_array * media = janus_config_array_create ("media" );
4181
4222
janus_config_add (config , c , media );
@@ -4575,6 +4616,10 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi
4575
4616
janus_config_add (config , c , janus_config_item_create ("e2ee" , "true" ));
4576
4617
if (source -> playoutdelay_ext )
4577
4618
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
+ }
4578
4623
/* Iterate on all media streams */
4579
4624
janus_config_array * media = janus_config_array_create ("media" );
4580
4625
janus_config_add (config , c , media );
@@ -6132,6 +6177,8 @@ static void *janus_streaming_handler(void *data) {
6132
6177
session -> e2ee = source -> e2ee ;
6133
6178
/* Also check if we have to offer the playout-delay extension */
6134
6179
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 ;
6135
6182
}
6136
6183
janus_refcount_increase (& session -> ref );
6137
6184
done :
@@ -6153,6 +6200,8 @@ static void *janus_streaming_handler(void *data) {
6153
6200
JANUS_SDP_OA_DIRECTION , JANUS_SDP_SENDONLY ,
6154
6201
JANUS_SDP_OA_EXTENSION , JANUS_RTP_EXTMAP_MID , janus_rtp_extension_id (JANUS_RTP_EXTMAP_MID ),
6155
6202
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 ),
6156
6205
JANUS_SDP_OA_EXTENSION , JANUS_RTP_EXTMAP_PLAYOUT_DELAY ,
6157
6206
(session -> playoutdelay_ext ? janus_rtp_extension_id (JANUS_RTP_EXTMAP_PLAYOUT_DELAY ) : 0 ),
6158
6207
JANUS_SDP_OA_DONE );
@@ -6176,6 +6225,8 @@ static void *janus_streaming_handler(void *data) {
6176
6225
JANUS_SDP_OA_DIRECTION , JANUS_SDP_SENDONLY ,
6177
6226
JANUS_SDP_OA_EXTENSION , JANUS_RTP_EXTMAP_MID , janus_rtp_extension_id (JANUS_RTP_EXTMAP_MID ),
6178
6227
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 ),
6179
6230
JANUS_SDP_OA_EXTENSION , JANUS_RTP_EXTMAP_PLAYOUT_DELAY ,
6180
6231
(session -> playoutdelay_ext ? janus_rtp_extension_id (JANUS_RTP_EXTMAP_PLAYOUT_DELAY ) : 0 ),
6181
6232
JANUS_SDP_OA_DONE );
@@ -6192,6 +6243,8 @@ static void *janus_streaming_handler(void *data) {
6192
6243
JANUS_SDP_OA_DIRECTION , JANUS_SDP_SENDONLY ,
6193
6244
JANUS_SDP_OA_EXTENSION , JANUS_RTP_EXTMAP_MID , janus_rtp_extension_id (JANUS_RTP_EXTMAP_MID ),
6194
6245
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 ),
6195
6248
JANUS_SDP_OA_EXTENSION , JANUS_RTP_EXTMAP_PLAYOUT_DELAY ,
6196
6249
(session -> playoutdelay_ext ? janus_rtp_extension_id (JANUS_RTP_EXTMAP_PLAYOUT_DELAY ) : 0 ),
6197
6250
JANUS_SDP_OA_DONE );
@@ -6386,6 +6439,7 @@ static void *janus_streaming_handler(void *data) {
6386
6439
JANUS_SDP_OA_DIRECTION , JANUS_SDP_SENDONLY ,
6387
6440
JANUS_SDP_OA_ACCEPT_EXTMAP , JANUS_RTP_EXTMAP_MID ,
6388
6441
JANUS_SDP_OA_ACCEPT_EXTMAP , JANUS_RTP_EXTMAP_ABS_SEND_TIME ,
6442
+ JANUS_SDP_OA_ACCEPT_EXTMAP , JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME ,
6389
6443
JANUS_SDP_OA_ACCEPT_EXTMAP , JANUS_RTP_EXTMAP_PLAYOUT_DELAY ,
6390
6444
JANUS_SDP_OA_DONE );
6391
6445
/* Done */
@@ -6461,6 +6515,8 @@ static void *janus_streaming_handler(void *data) {
6461
6515
session -> e2ee = source -> e2ee ;
6462
6516
/* Also check if we have to offer the playout-delay extension */
6463
6517
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 ;
6464
6520
/* Accept the m-line */
6465
6521
janus_sdp_generate_answer_mline (parsed_sdp , answer , m ,
6466
6522
JANUS_SDP_OA_MLINE , m -> type ,
@@ -6470,6 +6526,7 @@ static void *janus_streaming_handler(void *data) {
6470
6526
JANUS_SDP_OA_DIRECTION , JANUS_SDP_SENDONLY ,
6471
6527
JANUS_SDP_OA_ACCEPT_EXTMAP , JANUS_RTP_EXTMAP_MID ,
6472
6528
JANUS_SDP_OA_ACCEPT_EXTMAP , JANUS_RTP_EXTMAP_ABS_SEND_TIME ,
6529
+ JANUS_SDP_OA_ACCEPT_EXTMAP , JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME ,
6473
6530
JANUS_SDP_OA_ACCEPT_EXTMAP , JANUS_RTP_EXTMAP_PLAYOUT_DELAY ,
6474
6531
JANUS_SDP_OA_DONE );
6475
6532
/* Done */
@@ -7547,7 +7604,8 @@ janus_streaming_rtp_source_stream *janus_streaming_create_rtp_source_stream(
7547
7604
7548
7605
janus_streaming_mountpoint * janus_streaming_create_rtp_source (
7549
7606
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 ) {
7551
7609
char id_num [30 ];
7552
7610
if (!string_ids ) {
7553
7611
g_snprintf (id_num , sizeof (id_num ), "%" SCNu64 , id );
@@ -7673,6 +7731,7 @@ janus_streaming_mountpoint *janus_streaming_create_rtp_source(
7673
7731
live_rtp_source -> rtp_collision = rtp_collision ;
7674
7732
live_rtp_source -> e2ee = e2ee ;
7675
7733
live_rtp_source -> playoutdelay_ext = playoutdelay_ext ;
7734
+ live_rtp_source -> abscapturetime_src_ext_id = abscapturetime_src_ext_id ;
7676
7735
live_rtp -> source = live_rtp_source ;
7677
7736
live_rtp -> source_destroy = (GDestroyNotify ) janus_streaming_rtp_source_free ;
7678
7737
live_rtp -> viewers = NULL ;
@@ -10192,6 +10251,13 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data)
10192
10251
rtp .extensions .min_delay = s -> min_delay ;
10193
10252
rtp .extensions .max_delay = s -> max_delay ;
10194
10253
}
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
+ }
10195
10261
if (gateway != NULL )
10196
10262
gateway -> relay_rtp (session -> handle , & rtp );
10197
10263
if (override_mark_bit && !has_marker_bit ) {
@@ -10267,6 +10333,13 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data)
10267
10333
rtp .extensions .min_delay = s -> min_delay ;
10268
10334
rtp .extensions .max_delay = s -> max_delay ;
10269
10335
}
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
+ }
10270
10343
if (gateway != NULL )
10271
10344
gateway -> relay_rtp (session -> handle , & rtp );
10272
10345
/* 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)
10288
10361
rtp .extensions .min_delay = s -> min_delay ;
10289
10362
rtp .extensions .max_delay = s -> max_delay ;
10290
10363
}
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
+ }
10291
10371
if (gateway != NULL )
10292
10372
gateway -> relay_rtp (session -> handle , & rtp );
10293
10373
/* Restore the timestamp and sequence number to what the video source set them to */
0 commit comments