MT#57719 Move `monologue_subscribe_*` to media subs

Stop using the call subscriptions model in the
subscribe request/answer functionality and move to
the media subscriptions.

Change-Id: I8aab2b1b4cdf9a3c5a04172c395ca509295ce0a3
pull/1752/head
Donat Zenichev 2 years ago
parent b265477654
commit 85fc7ff70c

@ -2978,6 +2978,10 @@ void call_subscriptions_clear(GQueue *q) {
g_queue_clear_full(q, call_subscription_free);
}
void media_subscriptions_clear(GQueue *q) {
g_queue_clear_full(q, media_subscription_free);
}
static void __unsubscribe_media_link(struct call_media * which, GList * which_cm_link)
{
struct media_subscription * ms = which_cm_link->data;
@ -3440,11 +3444,6 @@ static int monologue_subscribe_request1(struct call_monologue *src_ml, struct ca
return -1;
}
__add_subscription(dst_ml, src_ml, idx_diff, &(struct sink_attrs) { .egress = !!flags->egress });
if (flags->rtcp_mirror)
__add_subscription(src_ml, dst_ml, rev_idx_diff,
&(struct sink_attrs) { .egress = !!flags->egress, .rtcp_only = true });
__update_init_subscribers(src_ml, NULL, NULL, flags->opmode);
__update_init_subscribers(dst_ml, NULL, NULL, flags->opmode);
@ -3452,23 +3451,28 @@ static int monologue_subscribe_request1(struct call_monologue *src_ml, struct ca
}
/* called with call->master_lock held in W */
__attribute__((nonnull(1, 2, 3)))
int monologue_subscribe_request(const GQueue *srcs, struct call_monologue *dst_ml,
int monologue_subscribe_request(const GQueue *srms, struct call_monologue *dst_ml,
struct sdp_ng_flags *flags)
{
__unsubscribe_from_all(dst_ml);
__unsubscribe_medias_from_all(dst_ml); /* analogy for media subscriptions */
unsigned int index = 1; /* running counter for output/dst medias */
__unsubscribe_medias_from_all(dst_ml);
__call_monologue_init_from_flags(dst_ml, flags);
unsigned int index = 1; // running counter for output/dst medias
for (GList *sl = srcs->head; sl; sl = sl->next) {
struct call_subscription *cs = sl->data;
struct call_monologue *src_ml = cs->monologue;
AUTO_CLEANUP(GQueue mls, g_queue_clear) = G_QUEUE_INIT; /* to avoid duplications */
for (GList *sl = srms->head; sl; sl = sl->next)
{
struct media_subscription *ms = sl->data;
struct call_monologue *src_ml = ms->monologue;
if (!src_ml)
continue;
int ret = monologue_subscribe_request1(src_ml, dst_ml, flags, &index);
if (ret)
return -1;
if (!g_queue_find(&mls, src_ml)) {
int ret = monologue_subscribe_request1(src_ml, dst_ml, flags, &index);
g_queue_push_tail(&mls, src_ml);
if (ret)
return -1;
}
}
return 0;
}
@ -3476,33 +3480,20 @@ int monologue_subscribe_request(const GQueue *srcs, struct call_monologue *dst_m
/* called with call->master_lock held in W */
__attribute__((nonnull(1, 2, 3)))
int monologue_subscribe_answer(struct call_monologue *dst_ml, struct sdp_ng_flags *flags, GQueue *streams) {
GList *src_ml_it = dst_ml->subscriptions.head;
unsigned int index = 1; // running counter for input/src medias
struct media_subscription *rev_ms = NULL;
for (GList *l = streams->head; l; l = l->next) {
if (!src_ml_it)
return -1;
struct stream_params *sp = l->data;
struct call_subscription *cs = src_ml_it->data; /* TODO: deprecate me */
struct call_monologue *src_ml = cs->monologue;
for (GList * l = streams->head; l; l = l->next)
{
struct stream_params * sp = l->data;
// grab the matching source ml:
// we need to move to the next one when we've reached the last media of
// the current source ml
if (index > src_ml->medias->len) {
src_ml_it = src_ml_it->next;
if (!src_ml_it)
return -1;
index = 1; // starts over at 1
cs = src_ml_it->data;
src_ml = cs->monologue;
}
/* set src_media based on subscription (assuming it is one-to-one) */
struct call_media * dst_media = __get_media(dst_ml, sp, flags, 0);
GList * src_ml_media_it = dst_media->media_subscriptions.head;
struct media_subscription * ms = src_ml_media_it->data;
struct call_media * src_media = ms->media;
struct call_media *dst_media = __get_media(dst_ml, sp, flags, 0);
struct call_media *src_media = __get_media(src_ml, sp, flags, index++);
if (!dst_media || !src_media)
continue;
rev_ms = call_get_media_subscription(src_media->media_subscribers_ht, dst_media);
if (rev_ms)
@ -3517,8 +3508,7 @@ int monologue_subscribe_answer(struct call_monologue *dst_ml, struct sdp_ng_flag
.allow_asymmetric = !!flags->allow_asymmetric_codecs);
codec_store_strip(&dst_media->codecs, &flags->codec_strip, flags->codec_except);
codec_store_offer(&dst_media->codecs, &flags->codec_offer, &sp->codecs);
}
else {
} else {
codec_store_populate(&dst_media->codecs, &sp->codecs, .answer_only = true,
.allow_asymmetric = !!flags->allow_asymmetric_codecs);
if (!codec_store_is_full_answer(&src_media->codecs, &dst_media->codecs))
@ -3539,20 +3529,30 @@ int monologue_subscribe_answer(struct call_monologue *dst_ml, struct sdp_ng_flag
MEDIA_CLEAR(dst_media, RECV);
bf_copy(&dst_media->media_flags, MEDIA_FLAG_SEND, &sp->sp_flags, SP_FLAG_RECV);
// XXX check answer SDP parameters
/* TODO: check answer SDP parameters */
MEDIA_SET(dst_media, INITIALIZED);
}
__update_init_subscribers(dst_ml, streams, flags, flags->opmode);
dialogue_unkernelize(dst_ml, "subscribe answer event");
for (GList *l = dst_ml->subscriptions.head; l; l = l->next) {
struct call_subscription *cs = l->data;
struct call_monologue *src_ml = cs->monologue;
set_monologue_flags_per_subscribers(src_ml);
__update_init_subscribers(src_ml, NULL, NULL, flags->opmode);
dialogue_unkernelize(src_ml, "subscribe answer event");
AUTO_CLEANUP(GQueue mls, g_queue_clear) = G_QUEUE_INIT; /* to avoid duplications */
for (int i = 0; i < dst_ml->medias->len; i++)
{
struct call_media * dst_media = dst_ml->medias->pdata[i];
if (!dst_media)
continue;
for (GList * sub = dst_media->media_subscriptions.head; sub; sub = sub->next)
{
struct media_subscription * ms = sub->data;
if (!g_queue_find(&mls, ms->monologue)) {
set_monologue_flags_per_subscribers(ms->monologue);
__update_init_subscribers(ms->monologue, NULL, NULL, flags->opmode);
dialogue_unkernelize(ms->monologue, "subscribe answer event");
g_queue_push_tail(&mls, ms->monologue);
}
}
}
return 0;

@ -2748,12 +2748,13 @@ static const char *media_block_match(struct call **call, struct call_monologue *
return NULL;
}
static void add_ml_to_sub_list(GQueue *q, struct call_monologue *ml) {
struct call_subscription *cs = g_slice_alloc0(sizeof(*cs));
cs->monologue = ml;
g_queue_push_tail(q, cs);
void add_media_to_sub_list(GQueue *q, struct call_media *media, struct call_monologue *ml) {
struct media_subscription *ms = g_slice_alloc0(sizeof(*ms));
ms->media = media;
ms->monologue = ml;
g_queue_push_tail(q, ms);
}
static const char *media_block_match_mult(struct call **call, GQueue *mls,
static const char *media_block_match_mult(struct call **call, GQueue *medias,
struct sdp_ng_flags *flags, bencode_item_t *input, enum call_opmode opmode)
{
call_ng_process_flags(flags, input, opmode);
@ -2765,38 +2766,54 @@ static const char *media_block_match_mult(struct call **call, GQueue *mls,
return "Unknown call-ID";
if (flags->all == ALL_ALL) {
// get and add all offer/answer mls
for (GList *l = (*call)->monologues.tail; l; l = l->prev) {
struct call_monologue *ml = l->data;
if (ml->tagtype != FROM_TAG && ml->tagtype != TO_TAG)
for (GList *l = (*call)->medias.head; l; l = l->next) {
struct call_media *media = l->data;
if (!media || (media->monologue->tagtype != FROM_TAG &&
media->monologue->tagtype != TO_TAG))
{
continue;
add_ml_to_sub_list(mls, ml);
}
add_media_to_sub_list(medias, media, media->monologue);
}
return NULL;
}
// is a single ml given?
/* is a single ml given? */
struct call_monologue *ml = NULL;
const char *err = media_block_match1(*call, &ml, flags);
if (err)
return err;
if (ml) {
add_ml_to_sub_list(mls, ml);
for (int i = 0; i < ml->medias->len; i++)
{
struct call_media * media = ml->medias->pdata[i];
if (!media)
continue;
add_media_to_sub_list(medias, media, ml);
}
return NULL;
}
// handle from-tag list
/* handle from-tag list */
for (GList *l = flags->from_tags.head; l; l = l->next) {
str *s = l->data;
struct call_monologue *mlf = call_get_monologue(*call, s);
if (!mlf)
if (!mlf) {
ilog(LOG_WARN, "Given from-tag " STR_FORMAT_M " not found", STR_FMT_M(s));
else
add_ml_to_sub_list(mls, mlf);
} else {
for (int i = 0; i < mlf->medias->len; i++)
{
struct call_media * media = mlf->medias->pdata[i];
if (!media)
continue;
add_media_to_sub_list(medias, media, mlf);
}
}
}
if (!mls->length)
return "No monologues matched";
if (!medias->length)
return "No medias found (no monologues matched)";
return NULL;
}
@ -3422,52 +3439,54 @@ const char *call_subscribe_request_ng(bencode_item_t *input, bencode_item_t *out
AUTO_CLEANUP(struct sdp_ng_flags flags, call_ng_free_flags);
char rand_buf[65];
AUTO_CLEANUP_NULL(struct call *call, call_unlock_release);
AUTO_CLEANUP(GQueue srcs, call_subscriptions_clear) = G_QUEUE_INIT;
AUTO_CLEANUP(GQueue srms, media_subscriptions_clear) = G_QUEUE_INIT;
AUTO_CLEANUP(str sdp_out, str_free_dup) = STR_NULL;
// get source monologue
err = media_block_match_mult(&call, &srcs, &flags, input, OP_REQUEST);
/* get source monologue */
err = media_block_match_mult(&call, &srms, &flags, input, OP_REQUEST);
if (err)
return err;
if (flags.sdp.len)
ilog(LOG_INFO, "Subscribe-request with SDP received - ignoring SDP");
if (!srcs.length)
return "No call participant specified";
if (!srms.length)
return "No call participants specified (no medias found)";
// special case with just one source: we can use the original SDP
/* special case with just one source: we can use the original SDP
* TODO: deprecate it, since initially added for monologue subscriptions.
*/
struct call_monologue *sdp_ml = NULL;
if (srcs.length == 1) {
struct call_subscription *cs = srcs.head->data;
sdp_ml = cs->monologue;
if (srms.length == 1) {
struct media_subscription *ms = srms.head->data;
sdp_ml = ms->monologue;
if (!sdp_ml->last_in_sdp.len || !sdp_ml->last_in_sdp_parsed.length)
sdp_ml = NULL;
}
// the `label=` option was possibly used above to select the from-tag --
// switch it out with `to-label=` or `set-label=` for monologue_subscribe_request
// below which sets the label based on `label` for a newly created monologue
/* the `label=` option was possibly used above to select the from-tag --
* switch it out with `to-label=` or `set-label=` for monologue_subscribe_request
* below which sets the label based on `label` for a newly created monologue */
flags.label = flags.to_label;
if (flags.set_label.len) // set-label takes priority
flags.label = flags.set_label;
// get destination monologue
/* get destination monologue */
if (!flags.to_tag.len) {
// generate one
/* generate one */
flags.to_tag = STR_CONST_INIT(rand_buf);
rand_hex_str(flags.to_tag.s, flags.to_tag.len / 2);
}
struct call_monologue *dest_ml = call_get_or_create_monologue(call, &flags.to_tag);
// rewrite SDP, or create new?
/* rewrite SDP, or create new? */
struct sdp_chopper *chopper = NULL;
if (sdp_ml) {
chopper = sdp_chopper_new(&sdp_ml->last_in_sdp);
bencode_buffer_destroy_add(output->buffer, (free_func_t) sdp_chopper_destroy, chopper);
}
int ret = monologue_subscribe_request(&srcs, dest_ml, &flags);
int ret = monologue_subscribe_request(&srms, dest_ml, &flags);
if (ret)
return "Failed to request subscription";
@ -3475,28 +3494,28 @@ const char *call_subscribe_request_ng(bencode_item_t *input, bencode_item_t *out
ret = sdp_replace(chopper, &sdp_ml->last_in_sdp_parsed, dest_ml, &flags);
if (ret)
return "Failed to rewrite SDP";
}
else {
// create new SDP
} else {
/* create new SDP */
ret = sdp_create(&sdp_out, dest_ml, &flags);
}
// place return output SDP
/* place return output SDP */
if (chopper) {
if (chopper->output->len)
bencode_dictionary_add_string_len(output, "sdp", chopper->output->str,
chopper->output->len);
}
else if (sdp_out.len) {
} else if (sdp_out.len) {
bencode_buffer_destroy_add(output->buffer, g_free, sdp_out.s);
bencode_dictionary_add_str(output, "sdp", &sdp_out);
sdp_out = STR_NULL; // ownership passed to output
sdp_out = STR_NULL; /* ownership passed to output */
}
// add single response ml tag if there's just one, but always add a list
if (srcs.length == 1) {
struct call_subscription *cs = srcs.head->data;
struct call_monologue *source_ml = cs->monologue;
/* add single response ml tag if there's just one, but always add a list
* TODO: deprecate it, since initially added for monologue subscriptions.
*/
if (srms.length == 1) {
struct media_subscription *ms = srms.head->data;
struct call_monologue *source_ml = ms->monologue;
bencode_dictionary_add_str_dup(output, "from-tag", &source_ml->tag);
}
bencode_item_t *tag_medias = NULL, *media_labels = NULL;
@ -3505,9 +3524,9 @@ const char *call_subscribe_request_ng(bencode_item_t *input, bencode_item_t *out
media_labels = bencode_dictionary_add_dictionary(output, "media-labels");
}
bencode_item_t *from_list = bencode_dictionary_add_list(output, "from-tags");
for (GList *l = srcs.head; l; l = l->next) {
struct call_subscription *cs = l->data;
struct call_monologue *source_ml = cs->monologue;
for (GList *l = srms.head; l; l = l->next) {
struct media_subscription *ms = l->data;
struct call_monologue *source_ml = ms->monologue;
bencode_list_add_str_dup(from_list, &source_ml->tag);
if (tag_medias) {
bencode_item_t *tag_label = bencode_list_add_dictionary(tag_medias);

@ -410,7 +410,7 @@ static void janus_publishers_list(JsonBuilder *builder, struct call *call, struc
// global janus_lock is held
static const char *janus_videoroom_join_sub(struct janus_handle *handle, struct janus_room *room, int *retcode,
uint64_t feed_id, struct call *call, GQueue *srcs)
uint64_t feed_id, struct call *call, GQueue *medias)
{
// does the feed actually exist? get the feed handle
*retcode = 512;
@ -428,10 +428,13 @@ static const char *janus_videoroom_join_sub(struct janus_handle *handle, struct
if (!source_ml)
return "Feed not found";
struct call_subscription *cs = g_slice_alloc0(sizeof(*cs));
cs->monologue = source_ml;
g_queue_push_tail(srcs, cs);
for (int i = 0; i < source_ml->medias->len; i++)
{
struct call_media * media = source_ml->medias->pdata[i];
if (!media)
continue;
add_media_to_sub_list(medias, media, source_ml);
}
return NULL;
}
@ -533,7 +536,7 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan
else {
// subscriber
AUTO_CLEANUP(GQueue srcs, call_subscriptions_clear) = G_QUEUE_INIT;
AUTO_CLEANUP(GQueue srms, media_subscriptions_clear) = G_QUEUE_INIT;
// get single feed ID if there is one
if (json_reader_read_member(reader, "feed")) {
@ -542,7 +545,7 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan
if (!feed_id)
return "JSON object contains invalid 'message.feed' key";
const char *ret = janus_videoroom_join_sub(handle, room, retcode, feed_id,
call, &srcs);
call, &srms);
if (ret)
return ret;
}
@ -576,7 +579,7 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan
if (!g_queue_find_custom(&ret_streams, &fid, g_int64_cmp)) {
const char *ret = janus_videoroom_join_sub(handle, room, retcode, fid,
call, &srcs);
call, &srms);
if (ret)
return ret;
@ -594,7 +597,7 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan
json_reader_end_member(reader);
*retcode = 456;
if (!srcs.length)
if (!srms.length)
return "No feeds to subscribe to given";
struct call_monologue *dest_ml = janus_get_monologue(handle->id, call,
@ -622,21 +625,12 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan
flags.rtcp_mux_demux = 1;
}
int ret = monologue_subscribe_request(&srcs, dest_ml, &flags);
int ret = monologue_subscribe_request(&srms, dest_ml, &flags);
if (ret)
return "Subscribe error";
// create SDP: if there's only one subscription, we can use the original
// SDP, otherwise we generate a new one
if (srcs.length == 1) {
struct call_subscription *cs = srcs.head->data;
struct call_monologue *source_ml = cs->monologue;
struct sdp_chopper *chopper = sdp_chopper_new(&source_ml->last_in_sdp);
ret = sdp_replace(chopper, &source_ml->last_in_sdp_parsed, dest_ml, &flags);
sdp_chopper_destroy_ret(chopper, jsep_sdp_out);
}
else
ret = sdp_create(jsep_sdp_out, dest_ml, &flags);
/* create SDP */
ret = sdp_create(jsep_sdp_out, dest_ml, &flags);
if (!dest_ml->janus_session)
dest_ml->janus_session = obj_get(session);
@ -645,6 +639,7 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan
if (ret)
return "Error generating SDP";
*jsep_type_out = "offer";
}

@ -745,7 +745,8 @@ void __add_sink_handler(GQueue *, struct packet_stream *, const struct sink_attr
void call_subscription_free(void *);
void call_subscriptions_clear(GQueue *q);
void media_subscription_free(void *);
void media_subscriptions_clear(GQueue *q);
struct call *call_get_or_create(const str *callid, bool exclusive);
struct call *call_get_opmode(const str *callid, enum call_opmode opmode);
@ -763,7 +764,7 @@ void codecs_offer_answer(struct call_media *media, struct call_media *other_medi
struct stream_params *sp,
struct sdp_ng_flags *flags);
int monologue_publish(struct call_monologue *ml, GQueue *streams, struct sdp_ng_flags *flags);
int monologue_subscribe_request(const GQueue *srcs, struct call_monologue *dst, struct sdp_ng_flags *);
int monologue_subscribe_request(const GQueue *srms, struct call_monologue *dst, struct sdp_ng_flags *);
int monologue_subscribe_answer(struct call_monologue *dst, struct sdp_ng_flags *,
GQueue *);
int monologue_unsubscribe(struct call_monologue *dst, struct sdp_ng_flags *);

@ -248,6 +248,8 @@ const char *call_subscribe_request_ng(bencode_item_t *, bencode_item_t *);
const char *call_subscribe_answer_ng(struct ng_buffer *, bencode_item_t *, bencode_item_t *);
const char *call_unsubscribe_ng(bencode_item_t *, bencode_item_t *);
void add_media_to_sub_list(GQueue *q, struct call_media *media, struct call_monologue *ml);
void save_last_sdp(struct call_monologue *ml, str *sdp, GQueue *parsed, GQueue *streams);
void call_ng_flags_init(struct sdp_ng_flags *out, enum call_opmode opmode);
void call_ng_free_flags(struct sdp_ng_flags *flags);

@ -577,11 +577,11 @@ class TestVideoroom(unittest.TestCase):
sdp,
re.compile(
"^v=0\r\n"
"o=x 123 123 IN IP4 203.0.113.3\r\n"
"c=IN IP4 203.0.113.1\r\n"
"s=foobar\r\n"
"o=- \d+ \d+ IN IP4 203.0.113.1\r\n"
"s=rtpengine.*?\r\n"
"t=0 0\r\n"
"m=audio \d+ UDP/TLS/RTP/SAVPF 8\r\n"
"c=IN IP4 203.0.113.1\r\n"
"a=mid:1\r\n"
"a=rtpmap:8 PCMA/8000\r\n"
"a=sendonly\r\n"
@ -865,11 +865,11 @@ class TestVideoroom(unittest.TestCase):
sdp,
re.compile(
"^v=0\r\n"
"o=x 123 123 IN IP4 203.0.113.3\r\n"
"c=IN IP4 203.0.113.1\r\n"
"s=foobar\r\n"
"o=- \d+ \d+ IN IP4 203.0.113.1\r\n"
"s=rtpengine.*?\r\n"
"t=0 0\r\n"
"m=audio \d+ UDP/TLS/RTP/SAVPF 8\r\n"
"c=IN IP4 203.0.113.1\r\n"
"a=mid:1\r\n"
"a=rtpmap:8 PCMA/8000\r\n"
"a=sendonly\r\n"
@ -1716,24 +1716,11 @@ class TestVideoroom(unittest.TestCase):
sdp,
re.compile(
"^v=0\r\n"
"o=- 3959345330719813235 2 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"o=- \d+ \d+ IN IP4 203.0.113.1\r\n"
"s=rtpengine.*?\r\n"
"t=0 0\r\n"
"a=extmap-allow-mixed\r\n"
"a=msid-semantic: WMS hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC\r\n"
"m=audio \d+ UDP/TLS/RTP/SAVPF 111\r\n"
"c=IN IP4 203.0.113.1\r\n"
"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n"
"a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n"
"a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n"
"a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\n"
"a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\n"
"a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\n"
"a=msid:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC 2de0f1b0-3a39-450e-9804-8305ec87452b\r\n"
"a=ssrc:677770262 cname:NMNDwVd66x2SfiO0\r\n"
"a=ssrc:677770262 msid:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC 2de0f1b0-3a39-450e-9804-8305ec87452b\r\n"
"a=ssrc:677770262 mslabel:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC\r\n"
"a=ssrc:677770262 label:2de0f1b0-3a39-450e-9804-8305ec87452b\r\n"
"a=mid:0\r\n"
"a=rtpmap:111 opus/48000/2\r\n"
"a=fmtp:111 useinbandfec=1; minptime=10\r\n"
@ -1750,28 +1737,6 @@ class TestVideoroom(unittest.TestCase):
"a=end-of-candidates\r\n"
"m=video \d+ UDP/TLS/RTP/SAVPF 96\r\n"
"c=IN IP4 203.0.113.1\r\n"
"a=extmap:14 urn:ietf:params:rtp-hdrext:toffset\r\n"
"a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n"
"a=extmap:13 urn:3gpp:video-orientation\r\n"
"a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n"
"a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\n"
"a=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\n"
"a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\n"
"a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space\r\n"
"a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\n"
"a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\n"
"a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\n"
"a=msid:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC 6d6ec7a7-e3d7-4c82-b03c-45e017713abd\r\n"
"a=rtcp-rsize\r\n"
"a=ssrc-group:FID 3005569364 2001490794\r\n"
"a=ssrc:3005569364 cname:NMNDwVd66x2SfiO0\r\n"
"a=ssrc:3005569364 msid:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC 6d6ec7a7-e3d7-4c82-b03c-45e017713abd\r\n"
"a=ssrc:3005569364 mslabel:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC\r\n"
"a=ssrc:3005569364 label:6d6ec7a7-e3d7-4c82-b03c-45e017713abd\r\n"
"a=ssrc:2001490794 cname:NMNDwVd66x2SfiO0\r\n"
"a=ssrc:2001490794 msid:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC 6d6ec7a7-e3d7-4c82-b03c-45e017713abd\r\n"
"a=ssrc:2001490794 mslabel:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC\r\n"
"a=ssrc:2001490794 label:6d6ec7a7-e3d7-4c82-b03c-45e017713abd\r\n"
"a=mid:1\r\n"
"a=rtpmap:96 VP8/90000\r\n"
"a=rtcp-fb:96 goog-remb\r\n"
@ -1983,11 +1948,11 @@ class TestVideoroom(unittest.TestCase):
sdp,
re.compile(
"^v=0\r\n"
"o=x 123 123 IN IP4 203.0.113.2\r\n"
"c=IN IP4 203.0.113.1\r\n"
"s=foobar\r\n"
"o=- \d+ \d+ IN IP4 203.0.113.1\r\n"
"s=rtpengine.*?\r\n"
"t=0 0\r\n"
"m=audio \d+ UDP/TLS/RTP/SAVPF 8\r\n"
"c=IN IP4 203.0.113.1\r\n"
"a=mid:audio\r\n"
"a=rtpmap:8 PCMA/8000\r\n"
"a=sendonly\r\n"
@ -3116,16 +3081,17 @@ class TestVideoroom(unittest.TestCase):
match_re = re.compile(
"^v=0\r\n"
"o=x 123 123 IN IP4 203.0.113.2\r\n"
"c=IN IP4 203.0.113.1\r\n"
"s=foobar\r\n"
"o=- \d+ \d+ IN IP4 203.0.113.1\r\n"
"s=rtpengine.*?\r\n"
"t=0 0\r\n"
"m=audio (\d+) RTP/AVP 96\r\n"
"c=IN IP4 203.0.113.1\r\n"
"a=mid:a\r\n"
"a=rtpmap:96 opus/48000/2\r\n"
"a=sendonly\r\n"
"a=rtcp:\d+\r\n"
"m=video (\d+) RTP/AVP 97\r\n"
"c=IN IP4 203.0.113.1\r\n"
"a=mid:v\r\n"
"a=rtpmap:97 VP9/90000\r\n"
"a=sendonly\r\n"

Loading…
Cancel
Save