From 57c490f817eacc0fa67e48c4e0573836ea3532a8 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 25 Mar 2024 08:26:08 -0400 Subject: [PATCH] MT#55283 Add output-mixed-per-media closes #1808 Change-Id: I70098382060b7522e7efd2fc8703ce526a61d461 --- daemon/call.c | 3 +++ daemon/recording.c | 6 +++--- daemon/sdp.c | 6 +++++- docs/rtpengine-recording.md | 4 ++++ include/call.h | 2 ++ recording-daemon/decoder.c | 2 +- recording-daemon/main.c | 2 ++ recording-daemon/main.h | 2 +- recording-daemon/metafile.c | 8 ++++---- recording-daemon/mix.c | 12 +++++++++++- recording-daemon/mix.h | 4 +--- recording-daemon/stream.c | 3 ++- recording-daemon/stream.h | 3 ++- recording-daemon/types.h | 1 + 14 files changed, 42 insertions(+), 16 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index b9af40ad6..d82e788ff 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2866,6 +2866,9 @@ int monologue_offer_answer(struct call_monologue *monologues[2], sdp_streams_q * * the dialogue */ media = __get_media(monologue, sp, flags, 0); other_media = __get_media(other_ml, sp, flags, 0); + media->media_sdp_id = sp->media_sdp_id; + other_media->media_sdp_id = sp->media_sdp_id; + /* OTHER is the side which has sent the message. SDP parameters in * "sp" are as advertised by OTHER side. The message will be sent to * THIS side. Parameters sent to THIS side may be overridden by diff --git a/daemon/recording.c b/daemon/recording.c index 9b76d991f..ea60ec894 100644 --- a/daemon/recording.c +++ b/daemon/recording.c @@ -946,9 +946,9 @@ static void setup_stream_proc(struct packet_stream *stream) { if (ML_ISSET(ml, NO_RECORDING)) return; - len = snprintf(buf, sizeof(buf), "TAG %u MEDIA %u TAG-MEDIA %u COMPONENT %u FLAGS %" PRIu64, - ml->unique_id, media->unique_id, media->index, stream->component, - atomic64_get_na(&stream->ps_flags)); + len = snprintf(buf, sizeof(buf), "TAG %u MEDIA %u TAG-MEDIA %u COMPONENT %u FLAGS %" PRIu64 " MEDIA-SDP-ID %i", + ml->unique_id, media->unique_id, media->index, stream->component, + atomic64_get_na(&stream->ps_flags), media->media_sdp_id); append_meta_chunk(recording, buf, len, "STREAM %u details", stream->unique_id); len = snprintf(buf, sizeof(buf), "tag-%u-media-%u-component-%u-%s-id-%u", diff --git a/daemon/sdp.c b/daemon/sdp.c index 336e731ea..1a0b99b51 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -137,6 +137,8 @@ struct sdp_media { struct sdp_attributes attributes; GQueue format_list; /* list of slice-alloc'd str objects */ enum media_type media_type_id; + int media_sdp_id; + unsigned int legacy_osrtp:1; }; @@ -1252,6 +1254,7 @@ int sdp_parse(str *body, sdp_sessions_q *sessions, const sdp_ng_flags *flags) { struct sdp_attributes *attrs; struct sdp_attribute *attr; str *adj_s; + int media_sdp_id = 0; b = body->s; end = str_end(body); @@ -1332,7 +1335,7 @@ new_session: t_queue_push_tail(&session->media_streams, media); media->s.s = b; media->rr = media->rs = -1; - + media->media_sdp_id = media_sdp_id++; break; case 'c': @@ -1810,6 +1813,7 @@ int sdp_streams(const sdp_sessions_q *sessions, sdp_streams_q *streams, sdp_ng_f sp = g_slice_alloc0(sizeof(*sp)); sp->index = ++num; codec_store_init(&sp->codecs, NULL); + sp->media_sdp_id = media->media_sdp_id; errstr = "No address info found for stream"; if (!flags->fragment diff --git a/docs/rtpengine-recording.md b/docs/rtpengine-recording.md index bad2837a7..7ab069f65 100644 --- a/docs/rtpengine-recording.md +++ b/docs/rtpengine-recording.md @@ -355,6 +355,10 @@ sufficient for a standard installation of rtpengine. Remove the local file if the HTTP request was successful. Note that this option is only useful if __\-\-notify-record__ is also enabled. +- __\-\-output-mixed-per-media__ + + Forces one channel per media instead of SSRC. Note that this + option is only useful if __\-\-output-mixed__ is also enabled. ## EXIT STATUS - __0__ diff --git a/include/call.h b/include/call.h index 9918a85b3..af2376a6a 100644 --- a/include/call.h +++ b/include/call.h @@ -396,6 +396,7 @@ struct stream_params { str media_id; struct t38_options t38_options; str tls_id; + int media_sdp_id; }; struct endpoint_map { @@ -549,6 +550,7 @@ struct call_media { // lists are append-only dtmf_event_q dtmf_recv; dtmf_event_q dtmf_send; + int media_sdp_id; #ifdef WITH_TRANSCODING encoder_callback_t encoder_callback; diff --git a/recording-daemon/decoder.c b/recording-daemon/decoder.c index d7c8413d5..715796a6a 100644 --- a/recording-daemon/decoder.c +++ b/recording-daemon/decoder.c @@ -115,7 +115,7 @@ static int decoder_got_frame(decoder_t *dec, AVFrame *frame, void *sp, void *dp) if (metafile->mix_out) { dbg("adding packet from stream #%lu to mix output", stream->id); if (G_UNLIKELY(deco->mixer_idx == (unsigned int) -1)) - deco->mixer_idx = mix_get_index(metafile->mix, ssrc); + deco->mixer_idx = mix_get_index(metafile->mix, ssrc, stream->media_sdp_id); format_t actual_format; if (output_config(metafile->mix_out, &dec->dest_format, &actual_format)) goto no_mix_out; diff --git a/recording-daemon/main.c b/recording-daemon/main.c index 1490cfea9..b6bdb0726 100644 --- a/recording-daemon/main.c +++ b/recording-daemon/main.c @@ -67,6 +67,7 @@ int notify_threads = 5; int notify_retries = 10; gboolean notify_record; gboolean notify_purge; +gboolean mix_output_per_media = 0; static GQueue threads = G_QUEUE_INIT; // only accessed from main thread @@ -225,6 +226,7 @@ static void options(int *argc, char ***argv) { { "notify-no-verify", 0, 0, G_OPTION_ARG_NONE, ¬ify_nverify,"Don't verify HTTPS peer certificate", NULL }, { "notify-concurrency", 0, 0, G_OPTION_ARG_INT, ¬ify_threads,"How many simultaneous requests", "INT" }, { "notify-retries", 0, 0, G_OPTION_ARG_INT, ¬ify_retries,"How many times to retry failed requesets","INT" }, + { "output-mixed-per-media",0,0, G_OPTION_ARG_NONE, &mix_output_per_media,"Mix participating sources into a single output", NULL }, #if CURL_AT_LEAST_VERSION(7,56,0) { "notify-record", 0, 0, G_OPTION_ARG_NONE, ¬ify_record, "Also attach recorded file to request", NULL }, { "notify-purge", 0, 0, G_OPTION_ARG_NONE, ¬ify_purge, "Remove the local file if notify success", NULL }, diff --git a/recording-daemon/main.h b/recording-daemon/main.h index 35b07c03f..ac2861eee 100644 --- a/recording-daemon/main.h +++ b/recording-daemon/main.h @@ -49,7 +49,7 @@ extern int notify_threads; extern int notify_retries; extern gboolean notify_record; extern gboolean notify_purge; - +extern gboolean mix_output_per_media; extern volatile int shutdown_flag; diff --git a/recording-daemon/metafile.c b/recording-daemon/metafile.c index c09170ea1..feafd8522 100644 --- a/recording-daemon/metafile.c +++ b/recording-daemon/metafile.c @@ -105,12 +105,12 @@ static void meta_stream_interface(metafile_t *mf, unsigned long snum, char *cont // mf is locked static void meta_stream_details(metafile_t *mf, unsigned long snum, char *content) { dbg("stream %lu details %s", snum, content); - unsigned int tag, media, tm, cmp; + unsigned int tag, media, tm, cmp, media_sdp_id; uint64_t flags; - if (sscanf_match(content, "TAG %u MEDIA %u TAG-MEDIA %u COMPONENT %u FLAGS %" PRIu64, - &tag, &media, &tm, &cmp, &flags) != 5) + if (sscanf_match(content, "TAG %u MEDIA %u TAG-MEDIA %u COMPONENT %u FLAGS %" PRIu64 " MEDIA-SDP-ID %i", + &tag, &media, &tm, &cmp, &flags, &media_sdp_id) != 6) return; - stream_details(mf, snum, tag); + stream_details(mf, snum, tag, media_sdp_id); } diff --git a/recording-daemon/mix.c b/recording-daemon/mix.c index 386ab6a4a..02d2c0e59 100644 --- a/recording-daemon/mix.c +++ b/recording-daemon/mix.c @@ -83,8 +83,15 @@ static void mix_input_reset(mix_t *mix, unsigned int idx) { } -unsigned int mix_get_index(mix_t *mix, void *ptr) { +unsigned int mix_get_index(mix_t *mix, void *ptr, unsigned int media_sdp_id) { unsigned int next = mix->next_idx++; + if (mix_output_per_media) { + next = media_sdp_id; + if (next >= mix_num_inputs) { + ilog(LOG_WARNING, "Error with mix_output_per_media sdp_label next %i is bigger than mix_num_inputs %i", next, mix_num_inputs ); + } + } + if (next < mix_num_inputs) { // must be unused mix->input_ref[next] = ptr; @@ -182,6 +189,8 @@ int mix_config(mix_t *mix, const format_t *format) { err = "failed to link abuffer to amix"; if (avfilter_link(mix->src_ctxs[i], 0, mix->amix_ctx, i)) goto err; + + } // sink @@ -198,6 +207,7 @@ int mix_config(mix_t *mix, const format_t *format) { if (avfilter_link(mix->amix_ctx, 0, mix->sink_ctx, 0)) goto err; + // finish up err = "failed to configure filter chain"; if (avfilter_graph_config(mix->graph, NULL)) diff --git a/recording-daemon/mix.h b/recording-daemon/mix.h index dcfebde51..35d7432a3 100644 --- a/recording-daemon/mix.h +++ b/recording-daemon/mix.h @@ -10,8 +10,6 @@ mix_t *mix_new(void); void mix_destroy(mix_t *mix); int mix_config(mix_t *, const format_t *format); int mix_add(mix_t *mix, AVFrame *frame, unsigned int idx, void *, output_t *output); -unsigned int mix_get_index(mix_t *, void *); - - +unsigned int mix_get_index(mix_t *, void *, unsigned int); #endif diff --git a/recording-daemon/stream.c b/recording-daemon/stream.c index 388a9abd4..0aa611dc6 100644 --- a/recording-daemon/stream.c +++ b/recording-daemon/stream.c @@ -138,9 +138,10 @@ void stream_open(metafile_t *mf, unsigned long id, char *name) { epoll_add(stream->fd, EPOLLIN, &stream->handler); } -void stream_details(metafile_t *mf, unsigned long id, unsigned int tag) { +void stream_details(metafile_t *mf, unsigned long id, unsigned int tag, unsigned int media_sdp_id) { stream_t *stream = stream_get(mf, id); stream->tag = tag; + stream->media_sdp_id = media_sdp_id; } void stream_forwarding_on(metafile_t *mf, unsigned long id, unsigned int on) { diff --git a/recording-daemon/stream.h b/recording-daemon/stream.h index 499c99eb6..e03f594f9 100644 --- a/recording-daemon/stream.h +++ b/recording-daemon/stream.h @@ -4,8 +4,9 @@ #include "types.h" void stream_open(metafile_t *mf, unsigned long id, char *name); -void stream_details(metafile_t *mf, unsigned long id, unsigned int tag); +void stream_details(metafile_t *mf, unsigned long id, unsigned int tag, unsigned int media_sdp_id); void stream_forwarding_on(metafile_t *mf, unsigned long id, unsigned int on); +void stream_sdp_label(metafile_t *mf, unsigned long id, unsigned long *label); void stream_close(stream_t *stream); void stream_free(stream_t *stream); diff --git a/recording-daemon/types.h b/recording-daemon/types.h index 99bb85e1a..7e3985443 100644 --- a/recording-daemon/types.h +++ b/recording-daemon/types.h @@ -57,6 +57,7 @@ struct stream_s { handler_t handler; unsigned int forwarding_on:1; double start_time; + unsigned int media_sdp_id; }; typedef struct stream_s stream_t;