MT#57719 Add SDP session attributes print (subscribe)

Add handling of SDP session level attributes for:
- `monologue_subscribe_request()`
- `monologue_subscribe_answer()`

This will be used by `janus.c` related functionality.

Change-Id: I1c50b5b9da08e7d8cb2c98eb6995d8610386d6ed
pull/1752/head
Donat Zenichev 2 years ago
parent 37102a1fc8
commit 3c28cb325a

@ -50,7 +50,7 @@
#include "janus.h"
#include "dtmf.h"
#include "audio_player.h"
#include "sdp.h"
struct iterator_helper {
uint64_t count;
@ -3395,10 +3395,14 @@ int monologue_publish(struct call_monologue *ml, GQueue *streams, struct sdp_ng_
/* called with call->master_lock held in W */
__attribute__((nonnull(1, 2, 3, 4)))
static int monologue_subscribe_request1(struct call_monologue *src_ml, struct call_monologue *dst_ml,
struct sdp_ng_flags *flags, unsigned int *index)
struct sdp_ng_flags *flags, unsigned int *index, bool print_extra_sess_attrs)
{
unsigned int idx_diff = 0, rev_idx_diff = 0;
/* additional attributes to be carried for `sdp_create()` */
if (print_extra_sess_attrs)
sdp_copy_session_attributes(src_ml, dst_ml);
for (GList *l = src_ml->last_in_sdp_streams.head; l; l = l->next) {
struct stream_params *sp = l->data;
@ -3469,7 +3473,7 @@ 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 *srms, struct call_monologue *dst_ml,
struct sdp_ng_flags *flags)
struct sdp_ng_flags *flags, bool print_extra_sess_attrs)
{
unsigned int index = 1; /* running counter for output/dst medias */
@ -3485,7 +3489,7 @@ int monologue_subscribe_request(const GQueue *srms, struct call_monologue *dst_m
continue;
if (!g_queue_find(&mls, src_ml)) {
int ret = monologue_subscribe_request1(src_ml, dst_ml, flags, &index);
int ret = monologue_subscribe_request1(src_ml, dst_ml, flags, &index, print_extra_sess_attrs);
g_queue_push_tail(&mls, src_ml);
if (ret)
return -1;
@ -3496,8 +3500,11 @@ int monologue_subscribe_request(const GQueue *srms, 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) {
int monologue_subscribe_answer(struct call_monologue *dst_ml, struct sdp_ng_flags *flags, GQueue *streams,
bool print_extra_sess_attrs)
{
struct media_subscription *rev_ms = NULL;
AUTO_CLEANUP(GQueue attr_mls, g_queue_clear) = G_QUEUE_INIT; /* to avoid duplications */
for (GList * l = streams->head; l; l = l->next)
{
@ -3512,6 +3519,12 @@ int monologue_subscribe_answer(struct call_monologue *dst_ml, struct sdp_ng_flag
if (!dst_media || !src_media)
continue;
/* additional attributes to be carried for `sdp_create()` */
if (print_extra_sess_attrs && !g_queue_find(&attr_mls, ms->monologue)) {
sdp_copy_session_attributes(ms->monologue, dst_ml);
g_queue_push_tail(&attr_mls, ms->monologue);
}
rev_ms = call_get_media_subscription(src_media->media_subscribers_ht, dst_media);
if (rev_ms)
rev_ms->attrs.transcoding = 0;
@ -3987,6 +4000,7 @@ void __monologue_free(struct call_monologue *m) {
g_string_free(m->last_out_sdp, TRUE);
str_free_dup(&m->last_in_sdp);
sdp_free(&m->last_in_sdp_parsed);
g_queue_clear_full(&m->sdp_attributes, free);
sdp_streams_free(&m->last_in_sdp_streams);
g_hash_table_destroy(m->subscribers_ht);
g_hash_table_destroy(m->subscriptions_ht);

@ -3415,7 +3415,7 @@ const char *call_publish_ng(struct ng_buffer *ngbuf, bencode_item_t *input, benc
if (ret)
ilog(LOG_ERR, "Publish error"); // XXX close call? handle errors?
ret = sdp_create(&sdp_out, ml, &flags, true);
ret = sdp_create(&sdp_out, ml, &flags, false, true);
if (!ret) {
save_last_sdp(ml, &sdp_in, &parsed, &streams);
bencode_buffer_destroy_add(output->buffer, g_free, sdp_out.s);
@ -3486,7 +3486,7 @@ const char *call_subscribe_request_ng(bencode_item_t *input, bencode_item_t *out
bencode_buffer_destroy_add(output->buffer, (free_func_t) sdp_chopper_destroy, chopper);
}
int ret = monologue_subscribe_request(&srms, dest_ml, &flags);
int ret = monologue_subscribe_request(&srms, dest_ml, &flags, false);
if (ret)
return "Failed to request subscription";
@ -3496,7 +3496,7 @@ const char *call_subscribe_request_ng(bencode_item_t *input, bencode_item_t *out
return "Failed to rewrite SDP";
} else {
/* create new SDP */
ret = sdp_create(&sdp_out, dest_ml, &flags, false);
ret = sdp_create(&sdp_out, dest_ml, &flags, false, false);
}
/* place return output SDP */
@ -3600,7 +3600,7 @@ const char *call_subscribe_answer_ng(struct ng_buffer *ngbuf, bencode_item_t *in
if (sdp_streams(&parsed, &streams, &flags))
return "Incomplete SDP specification";
int ret = monologue_subscribe_answer(dest_ml, &flags, &streams);
int ret = monologue_subscribe_answer(dest_ml, &flags, &streams, false);
if (ret)
return "Failed to process subscription answer";

@ -625,12 +625,12 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan
flags.rtcp_mux_demux = 1;
}
int ret = monologue_subscribe_request(&srms, dest_ml, &flags);
int ret = monologue_subscribe_request(&srms, dest_ml, &flags, true);
if (ret)
return "Subscribe error";
/* create SDP */
ret = sdp_create(jsep_sdp_out, dest_ml, &flags, true);
ret = sdp_create(jsep_sdp_out, dest_ml, &flags, true, true);
if (!dest_ml->janus_session)
dest_ml->janus_session = obj_get(session);
@ -865,7 +865,7 @@ static const char *janus_videoroom_configure(struct websocket_message *wm, struc
// XXX check there's only one audio and one video stream?
AUTO_CLEANUP(str sdp_out, str_free_dup) = STR_NULL;
ret = sdp_create(&sdp_out, ml, &flags, true);
ret = sdp_create(&sdp_out, ml, &flags, true, true);
if (ret)
return "Publish error";
@ -985,7 +985,7 @@ static const char *janus_videoroom_start(struct websocket_message *wm, struct ja
if (!dest_ml)
return "Subscriber not found";
int ret = monologue_subscribe_answer(dest_ml, &flags, &streams);
int ret = monologue_subscribe_answer(dest_ml, &flags, &streams, true);
if (ret)
return "Failed to process subscription answer";

@ -1747,6 +1747,7 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl
const char *errstr;
unsigned int num = 0;
struct sdp_attribute *attr;
GQueue *attrs;
for (l = sessions->head; l; l = l->next) {
session = l->data;
@ -1793,7 +1794,7 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl
goto error;
/* a=crypto */
GQueue *attrs = attr_list_get_by_id(&media->attributes, ATTR_CRYPTO);
attrs = attr_list_get_by_id(&media->attributes, ATTR_CRYPTO);
for (GList *ll = attrs ? attrs->head : NULL; ll; ll = ll->next) {
attr = ll->data;
struct crypto_params_sdes *cps = g_slice_alloc0(sizeof(*cps));
@ -3051,6 +3052,18 @@ struct packet_stream *print_rtcp(GString *s, struct call_media *media, GList *rt
return ps_rtcp;
}
/* copy sdp session attributes to the correlated monologue, as a plain text objects (str) */
void sdp_copy_session_attributes(struct call_monologue * src, struct call_monologue * dst) {
struct sdp_attribute *attr;
struct sdp_session *src_session = src->last_in_sdp_parsed.head->data;
GQueue *src_attributes = attr_list_get_by_id(&src_session->attributes, ATTR_OTHER);
g_queue_clear_full(&dst->sdp_attributes, free);
for (GList *ll = src_attributes ? src_attributes->head : NULL; ll; ll = ll->next) {
attr = ll->data;
str * ret = str_dup(&attr->line_value);
g_queue_push_tail(&dst->sdp_attributes, ret);
}
}
static void print_sdp_session_section(GString *s, struct sdp_ng_flags *flags,
struct call_media *call_media)
{
@ -3406,10 +3419,11 @@ error:
}
int sdp_create(str *out, struct call_monologue *monologue, struct sdp_ng_flags *flags,
bool print_other_attrs)
bool print_other_sess_attrs, bool print_other_media_attrs)
{
const char *err = NULL;
GString *s = NULL;
GQueue * extra_sdp_attributes = &monologue->sdp_attributes;
err = "Need at least one media";
if (!monologue->medias->len)
@ -3440,6 +3454,15 @@ int sdp_create(str *out, struct call_monologue *monologue, struct sdp_ng_flags *
g_string_append_printf(s, "s=%s\r\n", rtpe_config.software_id);
g_string_append(s, "t=0 0\r\n");
if (print_other_sess_attrs) {
/* `sdp_session`, if `->attributes` given, print on the session level */
for (GList *l = extra_sdp_attributes->head; l; l = l->next)
{
str * attr_value = l->data;
append_attr_to_gstring(s, attr_value->s, NULL, flags, MT_UNKNOWN);
}
}
for (unsigned int i = 0; i < monologue->medias->len; i++) {
media = monologue->medias->pdata[i];
err = "Empty media stream";
@ -3470,7 +3493,7 @@ int sdp_create(str *out, struct call_monologue *monologue, struct sdp_ng_flags *
g_string_append_printf(s, "\r\nc=IN %s %s\r\n",
rtp_ps->selected_sfd->local_intf->advertised_address.addr.family->rfc_name,
sockaddr_print_buf(&rtp_ps->selected_sfd->local_intf->advertised_address.addr));
print_sdp_media_section(s, media, NULL, flags, rtp_ps_link, true, false, print_other_attrs);
print_sdp_media_section(s, media, NULL, flags, rtp_ps_link, true, false, print_other_media_attrs);
}
out->len = s->len;

@ -559,8 +559,8 @@ struct call_monologue {
unsigned long long sdp_session_id;
unsigned long long sdp_version;
str last_in_sdp;
GQueue last_in_sdp_parsed;
GQueue last_in_sdp_streams;
GQueue last_in_sdp_parsed; /* last parsed `sdp_session` */
GQueue last_in_sdp_streams; /* last parsed `stream_params` */
GString *last_out_sdp;
char *sdp_username;
char *sdp_session_name;
@ -582,6 +582,9 @@ struct call_monologue {
unsigned int block_dtmf_trigger_end_ms;
unsigned int dtmf_delay;
/* carry `sdp_session` attributes into resulting call monologue SDP */
GQueue sdp_attributes;
volatile unsigned int ml_flags;
};
@ -765,9 +768,10 @@ 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 *srms, struct call_monologue *dst, struct sdp_ng_flags *);
int monologue_subscribe_answer(struct call_monologue *dst, struct sdp_ng_flags *,
GQueue *);
int monologue_subscribe_request(const GQueue *srms, struct call_monologue *dst, struct sdp_ng_flags *flags,
bool print_extra_sess_attrs);
int monologue_subscribe_answer(struct call_monologue *dst, struct sdp_ng_flags *flags,
GQueue *streams, bool print_extra_sess_attrs);
int monologue_unsubscribe(struct call_monologue *dst, struct sdp_ng_flags *);
void monologue_destroy(struct call_monologue *ml);
int call_delete_branch_by_id(const str *callid, const str *branch,

@ -37,7 +37,7 @@ int sdp_replace(struct sdp_chopper *, GQueue *, struct call_monologue *, struct
bool print_other_attrs);
int sdp_is_duplicate(GQueue *sessions);
int sdp_create(str *out, struct call_monologue *, struct sdp_ng_flags *flags,
bool print_other_attrs);
bool print_other_sess_attrs, bool print_other_media_attrs);
const char *sdp_get_sendrecv(struct call_media *media);
int sdp_parse_candidate(struct ice_candidate *cand, const str *s); // returns -1, 0, 1
@ -46,6 +46,8 @@ struct sdp_chopper *sdp_chopper_new(str *input);
void sdp_chopper_destroy(struct sdp_chopper *chop);
void sdp_chopper_destroy_ret(struct sdp_chopper *chop, str *ret);
void sdp_copy_session_attributes(struct call_monologue * src, struct call_monologue * dst);
INLINE int is_trickle_ice_address(const struct endpoint *ep) {
if (is_addr_unspecified(&ep->address) && ep->port == 9)
return 1;

@ -1719,6 +1719,8 @@ class TestVideoroom(unittest.TestCase):
"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=mid:0\r\n"

Loading…
Cancel
Save