diff --git a/daemon/call.c b/daemon/call.c index 9ec0b3f91..8a759c0d1 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2374,9 +2374,9 @@ static struct call_subscription *find_subscription(struct call_monologue *ml, st } -__attribute__((nonnull(1, 2, 3, 5))) +__attribute__((nonnull(1, 2, 3))) static void codecs_offer(struct call_media *media, struct call_media *other_media, - struct stream_params *sp, struct sdp_ng_flags *flags, struct call_subscription *dialogue[2]) + struct stream_params *sp, struct sdp_ng_flags *flags) { ilogs(codec, LOG_DEBUG, "Updating codecs for offerer " STR_FORMAT " #%u", STR_FMT(&other_media->monologue->tag), @@ -2439,13 +2439,15 @@ static void codecs_offer(struct call_media *media, struct call_media *other_medi codec_tracker_update(&media->codecs); // finally set up handlers again based on final results - codec_handlers_update(media, other_media, .flags = flags, .sp = sp, .sub = dialogue[1], - .allow_asymmetric = !!(flags && flags->allow_asymmetric_codecs)); + + codec_handlers_update(media, other_media, .flags = flags, .sp = sp, + .allow_asymmetric = !!(flags && flags->allow_asymmetric_codecs), + .reset_transcoding = true); } -__attribute__((nonnull(1, 2, 3, 4, 5))) +__attribute__((nonnull(1, 2, 3, 4))) static void codecs_answer(struct call_media *media, struct call_media *other_media, - struct stream_params *sp, struct sdp_ng_flags *flags, struct call_subscription *dialogue[2]) + struct stream_params *sp, struct sdp_ng_flags *flags) { ilogs(codec, LOG_DEBUG, "Updating codecs for answerer " STR_FORMAT " #%u", STR_FMT(&other_media->monologue->tag), @@ -2491,22 +2493,26 @@ static void codecs_answer(struct call_media *media, struct call_media *other_med codec_tracker_update(&other_media->codecs); // finally set up handlers again based on final results - codec_handlers_update(media, other_media, .flags = flags, .sp = sp, .sub = dialogue[1], - .allow_asymmetric = !!flags->allow_asymmetric_codecs); - codec_handlers_update(other_media, media, .sub = dialogue[0], - .allow_asymmetric = !!flags->allow_asymmetric_codecs); + + codec_handlers_update(media, other_media, .flags = flags, .sp = sp, + .allow_asymmetric = !!flags->allow_asymmetric_codecs, + .reset_transcoding = true); + codec_handlers_update(other_media, media, + .allow_asymmetric = !!flags->allow_asymmetric_codecs, + .reset_transcoding = true); // activate audio player if needed (not done by codec_handlers_update without `flags`) audio_player_activate(media); } void codecs_offer_answer(struct call_media *media, struct call_media *other_media, - struct stream_params *sp, struct sdp_ng_flags *flags, struct call_subscription *dialogue[2]) + struct stream_params *sp, + struct sdp_ng_flags *flags) { if (!flags || flags->opmode != OP_ANSWER) - codecs_offer(media, other_media, sp, flags, dialogue); + codecs_offer(media, other_media, sp, flags); else - codecs_answer(media, other_media, sp, flags, dialogue); + codecs_answer(media, other_media, sp, flags); } @@ -2769,13 +2775,13 @@ static void set_monologue_flags_per_subscribers(struct call_monologue *ml) { } /* called with call->master_lock held in W */ -int monologue_offer_answer(struct call_subscription *dialogue[2], GQueue *streams, +int monologue_offer_answer(struct call_monologue *monologues[2], GQueue *streams, struct sdp_ng_flags *flags) { struct call_media *media, *other_media; struct endpoint_map *em; - struct call_monologue *other_ml = dialogue[0]->monologue; - struct call_monologue *monologue = dialogue[1]->monologue; + struct call_monologue *other_ml = monologues[0]; + struct call_monologue *monologue = monologues[1]; unsigned int num_ports_this, num_ports_other; /* we must have a complete dialogue, even though the to-tag (monologue->tag) @@ -2785,6 +2791,9 @@ int monologue_offer_answer(struct call_subscription *dialogue[2], GQueue *stream return -1; } + /* required for updating the transcoding attrs of subscriber */ + struct call_subscription * cs = find_subscription(monologue, other_ml); + __call_monologue_init_from_flags(other_ml, flags); if (flags && flags->exclude_recording) { @@ -2794,7 +2803,8 @@ int monologue_offer_answer(struct call_subscription *dialogue[2], GQueue *stream __C_DBG("this="STR_FORMAT" other="STR_FORMAT, STR_FMT(&monologue->tag), STR_FMT(&other_ml->tag)); - dialogue[1]->attrs.transcoding = 0; + if (cs) + cs->attrs.transcoding = 0; for (GList *sp_iter = streams->head; sp_iter; sp_iter = sp_iter->next) { struct stream_params *sp = sp_iter->data; @@ -2814,7 +2824,7 @@ int monologue_offer_answer(struct call_subscription *dialogue[2], GQueue *stream __media_init_from_flags(other_media, media, sp, flags); - codecs_offer_answer(media, other_media, sp, flags, dialogue); + codecs_offer_answer(media, other_media, sp, flags); /* send and recv are from our POV */ bf_copy_same(&media->media_flags, &sp->sp_flags, @@ -3486,8 +3496,9 @@ int monologue_subscribe_answer(struct call_monologue *dst_ml, struct sdp_ng_flag codec_handlers_update(src_media, dst_media, .flags = flags, .allow_asymmetric = !!flags->allow_asymmetric_codecs); - codec_handlers_update(dst_media, src_media, .flags = flags, .sp = sp, .sub = rev_cs, - .allow_asymmetric = !!flags->allow_asymmetric_codecs); + codec_handlers_update(dst_media, src_media, .flags = flags, .sp = sp, + .allow_asymmetric = !!flags->allow_asymmetric_codecs, + .reset_transcoding = true); __dtls_logic(flags, dst_media, sp); @@ -4472,8 +4483,9 @@ static bool call_viabranch_intact_monologue(const str * viabranch, struct call_m * * `dialogue` must be initialised to zero. */ -static int call_get_monologue_new(struct call_subscription *dialogue[2], struct call *call, - const str *fromtag, const str *totag, +static int call_get_monologue_new(struct call_monologue *monologues[2], struct call *call, + const str *fromtag, + const str *totag, const str *viabranch) { struct call_monologue *ret, *os = NULL; /* ret - initial offer, os - other side */ @@ -4517,7 +4529,6 @@ static int call_get_monologue_new(struct call_subscription *dialogue[2], struct // use existing to-tag __monologue_unkernelize(csm, "dialogue association changed"); __subscribe_offer_answer_both_ways(ret, csm); - __offer_answer_get_subscriptions(ret, csm, dialogue); break; } break; // there should only be one @@ -4547,7 +4558,6 @@ static int call_get_monologue_new(struct call_subscription *dialogue[2], struct /* previously seen branch. use it */ __monologue_unkernelize(os, "dialogue/branch association changed"); __subscribe_offer_answer_both_ways(ret, os); - __offer_answer_get_subscriptions(ret, os, dialogue); goto ok_check_tag; } @@ -4557,7 +4567,6 @@ new_branch: __C_DBG("create new \"other side\" monologue for viabranch "STR_FORMAT, STR_FMT0(viabranch)); os = __monologue_create(call); __subscribe_offer_answer_both_ways(ret, os); - __offer_answer_get_subscriptions(ret, os, dialogue); __monologue_viabranch(os, viabranch); ok_check_tag: @@ -4576,7 +4585,8 @@ ok_check_tag: if (G_UNLIKELY(!os)) return -1; __tags_associate(ret, os); - __tags_get_subscriptions(ret, os, dialogue); + monologues[0] = ret; + monologues[1] = os; return 0; } @@ -4592,7 +4602,8 @@ ok_check_tag: * * `dialogue` must be initialised to zero. */ -static int call_get_dialogue(struct call_subscription *dialogue[2], struct call *call, const str *fromtag, +static int call_get_dialogue(struct call_monologue *monologues[2], struct call *call, + const str *fromtag, const str *totag, const str *viabranch) { @@ -4604,7 +4615,7 @@ static int call_get_dialogue(struct call_subscription *dialogue[2], struct call /* we start with the to-tag. if it's not known, we treat it as a branched offer */ tt = call_get_monologue(call, totag); if (!tt) - return call_get_monologue_new(dialogue, call, fromtag, totag, viabranch); + return call_get_monologue_new(monologues, call, fromtag, totag, viabranch); /* if the from-tag is known already, return that */ ft = call_get_monologue(call, fromtag); @@ -4659,32 +4670,35 @@ tag_setup: dialogue_unkernelize(ft, "dialogue signalling event"); dialogue_unkernelize(tt, "dialogue signalling event"); __subscribe_offer_answer_both_ways(ft, tt); - __offer_answer_get_subscriptions(ft, tt, dialogue); done: __monologue_unkernelize(ft, "dialogue signalling event"); dialogue_unkernelize(ft, "dialogue signalling event"); __tags_associate(ft, tt); - __tags_get_subscriptions(ft, tt, dialogue); + + /* just provide gotten dialogs, + * which have all needed information about subscribers/subscriptions */ + monologues[0] = ft; + monologues[1] = tt; + return 0; } /* fromtag and totag strictly correspond to the directionality of the message, not to the actual * SIP headers. IOW, the fromtag corresponds to the monologue sending this message, even if the * tag is actually from the TO header of the SIP message (as it would be in a 200 OK) */ -int call_get_mono_dialogue(struct call_subscription *dialogue[2], struct call *call, const str *fromtag, +int call_get_mono_dialogue(struct call_monologue *monologues[2], struct call *call, + const str *fromtag, const str *totag, const str *viabranch) { - dialogue[0] = dialogue[1] = NULL; + /* initial offer */ + if (!totag || !totag->s) + return call_get_monologue_new(monologues, call, fromtag, NULL, viabranch); - if (!totag || !totag->s) /* initial offer */ - return call_get_monologue_new(dialogue, call, fromtag, NULL, viabranch); - return call_get_dialogue(dialogue, call, fromtag, totag, viabranch); + return call_get_dialogue(monologues, call, fromtag, totag, viabranch); } - - static void media_stop(struct call_media *m) { if (!m) return; diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index c09e91893..05a372201 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -166,7 +166,7 @@ static str *call_update_lookup_udp(char **out, enum call_opmode opmode, const ch const endpoint_t *sin) { struct call *c; - struct call_subscription *dialogue[2]; + struct call_monologue *monologues[2]; /* subscriber lists of both monologues */ GQueue q = G_QUEUE_INIT; struct stream_params sp; str *ret; @@ -187,11 +187,11 @@ static str *call_update_lookup_udp(char **out, enum call_opmode opmode, const ch updated_created_from(c, addr, sin); - if (call_get_mono_dialogue(dialogue, c, &fromtag, &totag, NULL)) + if (call_get_mono_dialogue(monologues, c, &fromtag, &totag, NULL)) goto ml_fail; - struct call_monologue *from_ml = dialogue[0]->monologue; - struct call_monologue *to_ml = dialogue[1]->monologue; + struct call_monologue *from_ml = monologues[0]; + struct call_monologue *to_ml = monologues[1]; if (opmode == OP_OFFER) { from_ml->tagtype = FROM_TAG; @@ -203,7 +203,7 @@ static str *call_update_lookup_udp(char **out, enum call_opmode opmode, const ch goto addr_fail; g_queue_push_tail(&q, &sp); - i = monologue_offer_answer(dialogue, &q, NULL); + i = monologue_offer_answer(monologues, &q, NULL); g_queue_clear(&q); if (i) @@ -321,7 +321,7 @@ INLINE void call_unlock_release_update(struct call **c) { static str *call_request_lookup_tcp(char **out, enum call_opmode opmode) { struct call *c; - struct call_subscription *dialogue[2]; + struct call_monologue *monologues[2]; AUTO_CLEANUP(GQueue s, sdp_streams_free) = G_QUEUE_INIT; str *ret = NULL; GHashTable *infohash; @@ -350,14 +350,14 @@ static str *call_request_lookup_tcp(char **out, enum call_opmode opmode) { str_swap(&fromtag, &totag); } - if (call_get_mono_dialogue(dialogue, c, &fromtag, &totag, NULL)) { + if (call_get_mono_dialogue(monologues, c, &fromtag, &totag, NULL)) { ilog(LOG_WARNING, "Invalid dialogue association"); goto out2; } - if (monologue_offer_answer(dialogue, &s, NULL)) + if (monologue_offer_answer(monologues, &s, NULL)) goto out2; - ret = streams_print(dialogue[1]->monologue->medias, 1, s.length, NULL, SAF_TCP); + ret = streams_print(monologues[1]->medias, 1, s.length, NULL, SAF_TCP); out2: call_unlock_release_update(&c); @@ -1958,7 +1958,7 @@ static const char *call_offer_answer_ng(struct ng_buffer *ngbuf, bencode_item_t AUTO_CLEANUP(GQueue parsed, sdp_free) = G_QUEUE_INIT; AUTO_CLEANUP(GQueue streams, sdp_streams_free) = G_QUEUE_INIT; struct call *call; - struct call_subscription *dialogue[2]; + struct call_monologue * monologues[2]; int ret; AUTO_CLEANUP(struct sdp_ng_flags flags, call_ng_free_flags); struct sdp_chopper *chopper; @@ -2039,15 +2039,15 @@ static const char *call_offer_answer_ng(struct ng_buffer *ngbuf, bencode_item_t call_bencode_hold_ref(call, output); errstr = "Invalid dialogue association"; - if (call_get_mono_dialogue(dialogue, call, &flags.from_tag, &flags.to_tag, + if (call_get_mono_dialogue(monologues, call, &flags.from_tag, &flags.to_tag, flags.via_branch.s ? &flags.via_branch : NULL)) { rwlock_unlock_w(&call->master_lock); obj_put(call); goto out; } - struct call_monologue *from_ml = dialogue[0]->monologue; - struct call_monologue *to_ml = dialogue[1]->monologue; + struct call_monologue *from_ml = monologues[0]; + struct call_monologue *to_ml = monologues[1]; if (opmode == OP_OFFER) { from_ml->tagtype = FROM_TAG; @@ -2069,7 +2069,7 @@ static const char *call_offer_answer_ng(struct ng_buffer *ngbuf, bencode_item_t call->drop_traffic = 0; } - ret = monologue_offer_answer(dialogue, &streams, &flags); + ret = monologue_offer_answer(monologues, &streams, &flags); if (!ret) ret = sdp_replace(chopper, &parsed, to_ml, &flags); if (!ret) diff --git a/daemon/codec.c b/daemon/codec.c index d65cb31db..3d45655ed 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -995,16 +995,26 @@ static int __codec_handler_eq(const void *a, const void *b) { && h->sink == j->sink; } -// call must be locked in W +/** + * receiver - media / sink - other_media + * call must be locked in W + */ void __codec_handlers_update(struct call_media *receiver, struct call_media *sink, struct chu_args a) { + struct call_monologue *monologue = receiver->monologue; + struct call_monologue *other_monologue = sink->monologue; + + /* required for updating the transcoding attrs of subscriber */ + struct call_subscription * cs = call_get_call_subscription(monologue->subscribers_ht, other_monologue); + ilogs(codec, LOG_DEBUG, "Setting up codec handlers for " STR_FORMAT_M " #%u -> " STR_FORMAT_M " #%u", STR_FMT_M(&receiver->monologue->tag), receiver->index, STR_FMT_M(&sink->monologue->tag), sink->index); - if (a.sub) - a.sub->attrs.transcoding = 0; + if (a.reset_transcoding && cs) + cs->attrs.transcoding = 0; + MEDIA_CLEAR(receiver, GENERATOR); MEDIA_CLEAR(sink, GENERATOR); @@ -1016,8 +1026,8 @@ void __codec_handlers_update(struct call_media *receiver, struct call_media *sin // non-RTP protocol? if (proto_is(receiver->protocol, PROTO_UDPTL)) { if (codec_handler_udptl_update(receiver, sink, a.flags)) { - if (a.sub) - a.sub->attrs.transcoding = 1; + if (a.reset_transcoding && cs) + cs->attrs.transcoding = 1; return; } } @@ -1032,8 +1042,8 @@ void __codec_handlers_update(struct call_media *receiver, struct call_media *sin // should we transcode to a non-RTP protocol? if (proto_is_not_rtp(sink->protocol)) { if (codec_handler_non_rtp_update(receiver, sink, a.flags, a.sp)) { - if (a.sub) - a.sub->attrs.transcoding = 1; + if (a.reset_transcoding && cs) + cs->attrs.transcoding = 1; return; } } @@ -1369,8 +1379,8 @@ next: MEDIA_SET(sink, AUDIO_PLAYER); if (is_transcoding) { - if (a.sub) - a.sub->attrs.transcoding = 1; + if (a.reset_transcoding && cs) + cs->attrs.transcoding = 1; if (!use_audio_player) { // we have to translate RTCP packets diff --git a/daemon/redis.c b/daemon/redis.c index 65e15e606..4de5259c4 100644 --- a/daemon/redis.c +++ b/daemon/redis.c @@ -1861,7 +1861,7 @@ static int json_link_medias(struct call *c, struct redis_list *medias, continue; other_m->monologue = other_ml; if (other_m->index == med->index) { - codec_handlers_update(other_m, med, .sub = cs); + codec_handlers_update(other_m, med, .reset_transcoding = true); break; } } diff --git a/include/call.h b/include/call.h index ff6c72039..60d39fa1b 100644 --- a/include/call.h +++ b/include/call.h @@ -734,16 +734,18 @@ void call_subscriptions_clear(GQueue *q); struct call *call_get_or_create(const str *callid, bool foreign, bool exclusive); struct call *call_get_opmode(const str *callid, enum call_opmode opmode); void call_make_own_foreign(struct call *c, bool foreign); -int call_get_mono_dialogue(struct call_subscription *dialogue[2], struct call *call, const str *fromtag, +int call_get_mono_dialogue(struct call_monologue *monologues[2], struct call *call, + const str *fromtag, const str *totag, const str *viabranch); struct call_monologue *call_get_monologue(struct call *call, const str *fromtag); struct call_monologue *call_get_or_create_monologue(struct call *call, const str *fromtag); struct call *call_get(const str *callid); -int monologue_offer_answer(struct call_subscription *dialogue[2], GQueue *streams, struct sdp_ng_flags *flags); -__attribute__((nonnull(1, 2, 3, 5))) +int monologue_offer_answer(struct call_monologue *monologues[2], GQueue *streams, struct sdp_ng_flags *flags); +__attribute__((nonnull(1, 2, 3))) void codecs_offer_answer(struct call_media *media, struct call_media *other_media, - struct stream_params *sp, struct sdp_ng_flags *flags, struct call_subscription *dialogue[2]); + 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_answer(struct call_monologue *dst, struct sdp_ng_flags *, diff --git a/include/codec.h b/include/codec.h index 5de3b268a..4b3f3dd0e 100644 --- a/include/codec.h +++ b/include/codec.h @@ -1,7 +1,6 @@ #ifndef __CODEC_H__ #define __CODEC_H__ - #include #include #include @@ -172,8 +171,8 @@ void payload_type_clear(struct rtp_payload_type *p); struct chu_args { const struct sdp_ng_flags *flags; const struct stream_params *sp; - struct call_subscription *sub; bool allow_asymmetric; + bool reset_transcoding; }; #define codec_handlers_update(r, s, ...) \ __codec_handlers_update(r, s, (struct chu_args) {__VA_ARGS__}) diff --git a/t/test-transcode.c b/t/test-transcode.c index 18f20a1d2..c18f804b8 100644 --- a/t/test-transcode.c +++ b/t/test-transcode.c @@ -167,18 +167,16 @@ static void __sdp_pt_fmt(int num, str codec, int clockrate, int channels, str fu static void offer(void) { printf("offer\n"); flags.opmode = OP_OFFER; - struct call_subscription subs[2]; - struct call_subscription *subs_p[2] = {&subs[0], &subs[1]}; - codecs_offer_answer(media_B, media_A, &rtp_types_sp, &flags, subs_p); + + codecs_offer_answer(media_B, media_A, &rtp_types_sp, &flags); __init(); } static void answer(void) { printf("answer\n"); flags.opmode = OP_ANSWER; - struct call_subscription subs[2]; - struct call_subscription *subs_p[2] = {&subs[0], &subs[1]}; - codecs_offer_answer(media_A, media_B, &rtp_types_sp, &flags, subs_p); + + codecs_offer_answer(media_A, media_B, &rtp_types_sp, &flags); __init(); }