MT#63317 support bundle groups

Change-Id: Iff961283f77986c6df7147149e058286fbc91ca6
rfuchs/dtls-ice
Richard Fuchs 5 months ago
parent 16780ac17d
commit 1f91ce4c37

@ -2327,8 +2327,6 @@ static void media_update_media_id(struct call_media *media, struct stream_params
}
}
else {
// we already have a media ID, but re-invite offer did not specify
// one. we keep what we already have.
;
}
}
@ -2799,6 +2797,11 @@ static void __call_monologue_init_from_flags(struct call_monologue *ml, struct c
for (__auto_type ll = flags->groups_other.head; ll; ll = ll->next)
t_queue_push_tail(&ml->groups_other, call_str_dup(ll->data));
if (t_hash_table_is_set(flags->bundles))
ML_SET(ml, BUNDLE);
else
ML_CLEAR(ml, BUNDLE);
ml->sdp_session_uri = call_str_cpy(&flags->session_uri);
ml->sdp_session_email = call_str_cpy(&flags->session_email);
ml->sdp_session_phone = call_str_cpy(&flags->session_phone);
@ -3272,6 +3275,39 @@ static struct call_media * monologue_add_zero_media(struct call_monologue *sende
return sender_media;
}
__attribute__((nonnull(1, 2)))
static void monologue_bundle_accept(struct call_monologue *ml, sdp_ng_flags *flags) {
if (!ML_ISSET(ml, BUNDLE))
return;
if (!t_hash_table_is_set(flags->bundles))
return;
// iterate all medias and set up bundle groups as requested
for (unsigned int i = 0; i < ml->medias->len; i++) {
__auto_type media = ml->medias->pdata[i];
if (!media)
continue;
// set bundle group
media->bundle = NULL;
if (!media->media_id.len)
continue;
str *bundle_head = t_hash_table_lookup(flags->bundles, &media->media_id);
if (!bundle_head)
continue;
__auto_type bundle = media->bundle = t_hash_table_lookup(ml->media_ids, bundle_head);
if (!bundle) {
ilog(LOG_WARN, "Tagged media '" STR_FORMAT "' from BUNDLE group "
"doesn't exist",
STR_FMT(bundle_head));
continue;
}
}
}
/* called with call->master_lock held in W */
int monologue_offer_answer(struct call_monologue *monologues[2], sdp_streams_q *streams,
sdp_ng_flags *flags)
@ -3513,6 +3549,8 @@ int monologue_offer_answer(struct call_monologue *monologues[2], sdp_streams_q *
media_update_transcoding_flag(sender_media);
}
monologue_bundle_accept(sender_ml, flags);
// set ipv4/ipv6/mixed media stats
if (flags->opmode == OP_OFFER || flags->opmode == OP_ANSWER) {
statistics_update_ip46_inc_dec(receiver_ml->call, CMC_INCREMENT);

@ -2424,6 +2424,7 @@ RTPE_NG_FLAGS_SDP_ATTR_Q_PARAMS
RTPE_NG_FLAGS_STR_CASE_HT_PARAMS
#undef X
str_ht_destroy_ptr(&flags->bundles);
ng_sdp_attr_manipulations_free(flags->sdp_manipulations);
t_queue_clear_full(&flags->medias, ng_media_free);

@ -185,10 +185,14 @@ struct attribute_ssrc {
};
struct attribute_group {
str semantics_str;
enum {
GROUP_OTHER = 0,
GROUP_BUNDLE,
} semantics;
str_q bundle;
};
struct attribute_fingerprint {
@ -667,10 +671,20 @@ static void attr_insert(struct sdp_attributes *attrs, struct sdp_attribute *attr
static bool parse_attribute_group(struct sdp_attribute *output) {
output->attr = ATTR_GROUP;
output->group.semantics = GROUP_OTHER;
if (output->strs.value.len >= 7 && !strncmp(output->strs.value.s, "BUNDLE ", 7))
output->group.semantics = GROUP_BUNDLE;
PARSE_INIT;
if (!str_token_sep(&output->group.semantics_str, value_str, ' '))
return true;
if (str_cmp(&output->group.semantics_str, "BUNDLE"))
return true;
output->group.semantics = GROUP_BUNDLE;
str mid;
while (str_token_sep(&mid, value_str, ' '))
t_queue_push_tail(&output->group.bundle, str_slice_dup(&mid));
return true;
}
@ -1522,6 +1536,8 @@ error:
}
static void attr_free(struct sdp_attribute *p) {
if (p->attr == ATTR_GROUP)
t_queue_clear_full(&p->group.bundle, str_slice_free);
g_free(p);
}
static void free_attributes(struct sdp_attributes *a) {
@ -1911,6 +1927,39 @@ static void sdp_attr_append_other(sdp_attr_q *dst, struct sdp_attributes *src) {
sdp_attr_append(dst, attr_list_get_by_id(src, ATTR_OTHER));
}
static void sdp_bundle_group(sdp_ng_flags *flags, struct attribute_group *group) {
if (!group->bundle.head) {
ilog(LOG_WARN, "Empty BUNDLE group in SDP, ignoring");
return;
}
if (!t_hash_table_is_set(flags->bundles))
flags->bundles = str_ht_new();
str *first = group->bundle.head->data;
if (t_hash_table_lookup(flags->bundles, first)) {
ilog(LOG_WARN, "Tagged media section '" STR_FORMAT "' found in multiple BUNDLE groups, "
"ignoring BUNDLE group",
STR_FMT(first));
return;
}
// first entry points to itself
t_hash_table_insert(flags->bundles, first, first);
for (__auto_type kk = group->bundle.head->next; kk; kk = kk->next) {
str *mid = kk->data;
if (t_hash_table_lookup(flags->bundles, mid)) {
ilog(LOG_WARN, "Media section '" STR_FORMAT "' found in multiple BUNDLE groups",
STR_FMT(mid));
continue;
}
// the remaining entries point to the first one
t_hash_table_insert(flags->bundles, mid, first);
}
}
/* XXX split this function up */
bool sdp_streams(const sdp_sessions_q *sessions, sdp_streams_q *streams, sdp_ng_flags *flags) {
struct sdp_session *session;
@ -1944,7 +1993,10 @@ bool sdp_streams(const sdp_sessions_q *sessions, sdp_streams_q *streams, sdp_ng_
__auto_type attrs = attr_list_get_by_id(&session->attributes, ATTR_GROUP);
for (__auto_type ll = attrs ? attrs->head : NULL; ll; ll = ll->next) {
attr = ll->data;
t_queue_push_tail(&flags->groups_other, &attr->strs.value);
if (attr->group.semantics == GROUP_BUNDLE)
sdp_bundle_group(flags, &attr->group);
else
t_queue_push_tail(&flags->groups_other, &attr->strs.value);
}
if (rtpe_config.moh_prevent_double_hold) {
@ -3016,6 +3068,70 @@ static void sdp_out_add_timing(GString *out, struct call_monologue *monologue)
g_string_append(out, "\r\n");
}
TYPED_GHASHTABLE(bundle_ht, struct call_media, GString, g_direct_hash, g_direct_equal, NULL, NULL);
__attribute__((nonnull(1, 2)))
static void append_bundle_groups(GString *out, struct call_monologue *ml, sdp_ng_flags *flags) {
if (!ML_ISSET(ml, BUNDLE))
return;
g_auto(bundle_ht) ht = bundle_ht_new();
for (unsigned int i = 0; i < ml->medias->len; i++) {
__auto_type media = ml->medias->pdata[i];
if (!media)
continue;
if (!media->bundle)
continue;
if (!media->media_id.len)
continue;
if (!media->bundle->media_id.len)
continue;
__auto_type bundle_str = t_hash_table_lookup(ht, media->bundle);
if (!bundle_str) {
bundle_str = g_string_new("");
t_hash_table_insert(ht, media->bundle, bundle_str);
}
if (media == media->bundle) {
size_t orig_len = bundle_str->len;
// this *should* be the first one, but we blindly do a prepend anyway.
// in the common case this is just writing to an empty string.
g_string_prepend_len(bundle_str, media->media_id.s, media->media_id.len);
if (orig_len) // uncommon case: something else was there before, insert a space
g_string_insert_c(bundle_str, media->media_id.len, ' ');
}
else {
if (bundle_str->len != 0)
g_string_append_c(bundle_str, ' ');
g_string_append_len(bundle_str, media->media_id.s, media->media_id.len);
}
}
bundle_ht_iter iter;
t_hash_table_iter_init(&iter, ht);
GString *bundle_str;
while (t_hash_table_iter_next(&iter, NULL, &bundle_str)) {
__auto_type state = __attr_begin(out, flags, MT_UNKNOWN);
if (__attr_append(&state, "group"))
goto next;
if (__attr_append(&state, ":BUNDLE"))
goto next;
g_string_append_c(out, ' ');
if (__attr_append_str(&state, &STR_GS(bundle_str)))
goto next;
__attr_end(&state);
next:
g_string_free(bundle_str, TRUE);
}
}
__attribute__((nonnull(1, 2, 4, 5)))
static void sdp_out_add_other(GString *out, struct call_monologue *monologue,
struct call_monologue *source_ml,
@ -3039,6 +3155,8 @@ static void sdp_out_add_other(GString *out, struct call_monologue *monologue,
/* group */
if (source_ml && flags->ice_option == ICE_FORCE_RELAY) {
append_bundle_groups(out, source_ml, flags);
for (__auto_type ll = source_ml->groups_other.head; ll; ll = ll->next)
append_attr_to_gstring(out, "group", ll->data, flags, media->type_id);
}

@ -233,6 +233,7 @@ enum {
#define ML_FLAG_MOH_SENDRECV (1LL << 25)
#define ML_FLAG_MOH_ZEROCONN (1LL << 26)
#define ML_FLAG_FORCE_TRANSCODING (1LL << 27)
#define ML_FLAG_BUNDLE (1LL << 28)
/* call_t */
#define CALL_FLAG_IPV4_OFFER (1LL << 16)
@ -507,6 +508,7 @@ struct call_media {
str media_id;
str label;
struct call_media *bundle;
sdes_q sdes_in, sdes_out;
struct dtls_fingerprint fingerprint; /* as received */
const struct dtls_hash_func *fp_hash_func; /* outgoing */

@ -95,6 +95,7 @@ struct sdp_ng_flags {
str session_timing; /* t= line */
struct session_bandwidth session_bandwidth;
str_q groups_other; /* a=group:xxx */
str_ht bundles; // a=group:BUNDLE ...
str session_information; // i= line
str session_uri; // u= line
str session_email; // e= line

Loading…
Cancel
Save