diff --git a/docs/rtpengine-recording.md b/docs/rtpengine-recording.md index 4dd138133..b537351fe 100644 --- a/docs/rtpengine-recording.md +++ b/docs/rtpengine-recording.md @@ -317,11 +317,20 @@ sufficient for a standard installation of rtpengine. - __\-\-tcp-send-to=__*IP*:*PORT* - __\-\-tcp-resample=__*INT* +- __\-\-tcp-mixed - __\-\-tls-send-to=__*IP*:*PORT* - __\-\-tls-resample=__*INT* +- __\-\-tls-mixed Send decoded audio over a TCP or TLS connection to the specified destination. - Audio is sent as raw mono 16-bit PCM in the given sample rate. + Audio is sent as raw 16-bit PCM in the given sample rate. + + By default one connection with one mono audio stream will be established + for each SSRC. If mixed mode is enabled, then similar to the mixed file + output one connection per call will be established instead, containing + audio mixed together from all captured SSRCs. The __mix-method__ setting is + honoured in the same way, so the audio will be either mono or mulit-channel + depending on the setting. Only one of these option combinations (TCP or TLS) can be active at the same time. diff --git a/recording-daemon/decoder.c b/recording-daemon/decoder.c index 06e3c7d80..2fa14ce89 100644 --- a/recording-daemon/decoder.c +++ b/recording-daemon/decoder.c @@ -115,6 +115,9 @@ static int decoder_got_frame(decoder_t *dec, AVFrame *frame, void *sp, void *dp) } } + if (metafile->forwarding_on) + sink_add(&deco->tls_mix_sink, frame, &dec->dest_format); + if (ssrc->tls_fwd) { dbg("SSRC %lx of stream #%lu has TLS forwarding stream", ssrc->ssrc, stream->id); if (!sink_add(&ssrc->tls_fwd->sink, frame, &ssrc->tls_fwd->format)) @@ -136,5 +139,6 @@ void decoder_free(decode_t *deco) { return; decoder_close(deco->dec); sink_close(&deco->mix_sink); + sink_close(&deco->tls_mix_sink); g_free(deco); } diff --git a/recording-daemon/main.c b/recording-daemon/main.c index afdffb124..6f10f483b 100644 --- a/recording-daemon/main.c +++ b/recording-daemon/main.c @@ -61,6 +61,7 @@ static char *tls_send_to = NULL; endpoint_t tls_send_to_ep; int tls_resample = 8000; bool tls_disable = false; +gboolean tls_mixed = false; char *notify_uri; gboolean notify_post; gboolean notify_nverify; @@ -225,6 +226,8 @@ static void options(int *argc, char ***argv) { { "tls-send-to", 0, 0, G_OPTION_ARG_STRING, &tls_send_to, "Where to send to (TLS destination)", "IP:PORT" }, { "tcp-resample", 0, 0, G_OPTION_ARG_INT, &tls_resample, "Sampling rate for TCP/TLS PCM output", "INT" }, { "tls-resample", 0, 0, G_OPTION_ARG_INT, &tls_resample, "Sampling rate for TCP/TLS PCM output", "INT" }, + { "tcp-mixed", 0, 0, G_OPTION_ARG_NONE, &tls_mixed, "Deliver mixed TCP/TLS PCM output", NULL }, + { "tls-mixed", 0, 0, G_OPTION_ARG_NONE, &tls_mixed, "Deliver mixed TCP/TLS PCM output", NULL }, { "notify-uri", 0, 0, G_OPTION_ARG_STRING, ¬ify_uri, "Notify destination for finished outputs","URI" }, { "notify-post", 0, 0, G_OPTION_ARG_NONE, ¬ify_post, "Use POST instead of GET", NULL }, { "notify-no-verify", 0, 0, G_OPTION_ARG_NONE, ¬ify_nverify,"Don't verify HTTPS peer certificate", NULL }, @@ -282,6 +285,9 @@ static void options(int *argc, char ***argv) { if (output_enabled || tls_send_to_ep.port) decoding_enabled = true; + if (!tls_send_to && !tcp_send_to) + tls_mixed = false; + if (!os_str || !strcmp(os_str, "file")) output_storage = OUTPUT_STORAGE_FILE; else if (!strcmp(os_str, "db")) diff --git a/recording-daemon/main.h b/recording-daemon/main.h index 1ddca8485..a0c1874f1 100644 --- a/recording-daemon/main.h +++ b/recording-daemon/main.h @@ -44,6 +44,7 @@ extern char *forward_to; extern endpoint_t tls_send_to_ep; extern int tls_resample; extern bool tls_disable; +extern gboolean tls_mixed; extern char *notify_uri; extern gboolean notify_post; extern gboolean notify_nverify; diff --git a/recording-daemon/metafile.c b/recording-daemon/metafile.c index 0403ca907..6aef12a3a 100644 --- a/recording-daemon/metafile.c +++ b/recording-daemon/metafile.c @@ -17,6 +17,7 @@ #include "db.h" #include "forward.h" #include "tag.h" +#include "tls_send.h" static pthread_mutex_t metafiles_lock = PTHREAD_MUTEX_INITIALIZER; static GHashTable *metafiles; @@ -27,6 +28,8 @@ static void meta_free(void *ptr) { dbg("freeing metafile info for %s%s%s", FMT_M(mf->name)); mix_destroy(mf->mix); + mix_destroy(mf->tls_mix); + tls_fwd_shutdown(&mf->mix_tls_fwd); db_close_call(mf); g_string_chunk_free(mf->gsc); // SSRCs first as they have linked outputs which need to be closed first @@ -90,9 +93,8 @@ static void meta_destroy(metafile_t *mf) { // mf is locked -static void meta_mix_output(metafile_t *mf) { - LOCK(&mf->mix_lock); - +// mix is locked +static void meta_mix_file_output(metafile_t *mf) { if (!output_enabled || !output_mixed || !mf->recording_on || !mf->random_tag) { mix_destroy(mf->mix); mf->mix = NULL; @@ -110,6 +112,37 @@ static void meta_mix_output(metafile_t *mf) { } +static void meta_mix_tls_output(metafile_t *mf) { + if (!tls_mixed) { + mix_destroy(mf->tls_mix); + mf->tls_mix = NULL; + tls_fwd_shutdown(&mf->mix_tls_fwd); + return; + } + + if (!mf->mix_tls_fwd) { + mix_destroy(mf->tls_mix); + mf->tls_mix = NULL; + } + + if (!tls_fwd_new(&mf->mix_tls_fwd)) + return; + if (!mf->tls_mix) + mf->tls_mix = mix_new(&mf->mix_lock, &mf->mix_tls_fwd->sink, mf->media_rec_slots); + + mf->mix_tls_fwd->metafile = mf; +} + + +// mf is locked +static void meta_mix_output(metafile_t *mf) { + LOCK(&mf->mix_lock); + + meta_mix_file_output(mf); + meta_mix_tls_output(mf); +} + + // mf is locked static void meta_stream_interface(metafile_t *mf, unsigned long snum, char *content) { db_do_call(mf); @@ -130,6 +163,7 @@ static void meta_stream_details(metafile_t *mf, unsigned long snum, char *conten mf->media_rec_slots = media_rec_slots; mix_set_channel_slots(mf->mix, media_rec_slots); + mix_set_channel_slots(mf->tls_mix, media_rec_slots); stream_details(mf, snum, tag, media_sdp_id, media_rec_slot-1); } diff --git a/recording-daemon/packet.c b/recording-daemon/packet.c index e08d25758..e59331e7e 100644 --- a/recording-daemon/packet.c +++ b/recording-daemon/packet.c @@ -127,6 +127,12 @@ static void packet_decode(ssrc_t *ssrc, packet_t *packet) { ssrc->decoders[payload_type]->mix_sink.add = mix_add; ssrc->decoders[payload_type]->mix_sink.config = mix_config; + sink_init(&ssrc->decoders[payload_type]->tls_mix_sink); + ssrc->decoders[payload_type]->tls_mix_sink.ssrc = ssrc; + ssrc->decoders[payload_type]->tls_mix_sink.mix = &mf->tls_mix; + ssrc->decoders[payload_type]->tls_mix_sink.add = mix_add; + ssrc->decoders[payload_type]->tls_mix_sink.config = mix_config; + pthread_mutex_unlock(&mf->mix_lock); if (!ssrc->decoders[payload_type]) { ilog(LOG_WARN, "Cannot decode RTP payload type %u (%s)", diff --git a/recording-daemon/tls_send.c b/recording-daemon/tls_send.c index 4a062d257..456b7a906 100644 --- a/recording-daemon/tls_send.c +++ b/recording-daemon/tls_send.c @@ -204,7 +204,7 @@ static bool tls_fwd_add(sink_t *sink, AVFrame *frame) { metafile_t *metafile = tls_fwd->metafile; tag_t *tag = NULL; - if (ssrc->stream) + if (ssrc && ssrc->stream) tag = tag_get(metafile, ssrc->stream->tag); if (tag && tag->metadata) { @@ -318,7 +318,7 @@ bool tls_fwd_new(tls_fwd_t **tlsp) { void tls_fwd_init(stream_t *stream, metafile_t *mf, ssrc_t *ssrc) { - if ((!stream->forwarding_on && !mf->forwarding_on) || !tls_send_to_ep.port) { + if ((!stream->forwarding_on && !mf->forwarding_on) || !tls_send_to_ep.port || tls_mixed) { tls_fwd_shutdown(&ssrc->tls_fwd); return; } diff --git a/recording-daemon/types.h b/recording-daemon/types.h index b658528a5..9bc69dd25 100644 --- a/recording-daemon/types.h +++ b/recording-daemon/types.h @@ -166,6 +166,9 @@ struct metafile_s { mix_t *mix; output_t *mix_out; + mix_t *tls_mix; + tls_fwd_t *mix_tls_fwd; + int forward_fd; int forward_count; int forward_failed; @@ -214,6 +217,7 @@ struct output_s { struct decode_s { decoder_t *dec; sink_t mix_sink; + sink_t tls_mix_sink; };