From 72817707104f1d564c75be5ecd9aa0ce01f38589 Mon Sep 17 00:00:00 2001 From: Jean Aunis <jean.aunis@prescom.fr> Date: Fri, 1 Apr 2016 14:50:30 +0200 Subject: [PATCH] app_chanspy: reduce audio loss on the spying channel. ChanSpy was creating its audiohook with the flags AST_AUDIOHOOK_TRIGGER_SYNC and AST_AUDIOHOOK_SMALL_QUEUE, which caused audio frames to be lost when queues grow too large or when read and write queues go out of sync. Now these flags are set conditionally: - AST_AUDIOHOOK_TRIGGER_SYNC is not set if the option "o" is set - a new option "l" is created: if set, AST_AUDIOHOOK_SMALL_QUEUE will not be set on the audiohook ASTERISK-25866 Change-Id: I9c7652f41d9fa72c8691e4e70ec4fd16b047a4dd --- CHANGES | 7 +++++++ apps/app_chanspy.c | 32 ++++++++++++++++++++++++-------- main/audiohook.c | 5 +++++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index e7f0656f57..56e6315701 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,13 @@ BridgeAdd * A new application in Asterisk, this will join the calling channel to an existing bridge containing the named channel prefix. +ChanSpy +------------------ + * Added the 'l' option, which forces ChanSpy's audiohook to use a long queue + to store the audio frames. This option is useful if audio loss is + experienced when using ChanSpy, but may introduce some delay in the audio + feed on the listening channel. + ConfBridge ------------------ * Added the ability to pass options to MixMonitor when recording is used with diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 5dbb0b8603..400eed11a2 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -117,6 +117,10 @@ ASTERISK_REGISTER_FILE() either a single group or a colon-delimited list of groups, such as <literal>sales:support:accounting</literal>.</para></note> </option> + <option name="l"> + <para>Allow usage of a long queue to store audio frames.</para> + <note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note> + </option> <option name="n" argsep="@"> <para>Say the name of the person being spied on if that person has recorded his/her name. If a context is specified, then that voicemail context will @@ -262,6 +266,10 @@ ASTERISK_REGISTER_FILE() either a single group or a colon-delimited list of groups, such as <literal>sales:support:accounting</literal>.</para></note> </option> + <option name="l"> + <para>Allow usage of a long queue to store audio frames.</para> + <note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note> + </option> <option name="n" argsep="@"> <para>Say the name of the person being spied on if that person has recorded his/her name. If a context is specified, then that voicemail context will @@ -386,6 +394,7 @@ enum { OPTION_STOP = (1 << 17), OPTION_EXITONHANGUP = (1 << 18), /* Hang up when the spied-on channel hangs up. */ OPTION_UNIQUEID = (1 << 19), /* The chanprefix is a channel uniqueid or fully specified channel name. */ + OPTION_LONG_QUEUE = (1 << 20), /* Allow usage of a long queue to store audio frames. */ }; enum { @@ -407,6 +416,7 @@ AST_APP_OPTIONS(spy_opts, { AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED), AST_APP_OPTION('E', OPTION_EXITONHANGUP), AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP), + AST_APP_OPTION('l', OPTION_LONG_QUEUE), AST_APP_OPTION_ARG('n', OPTION_NAME, OPT_ARG_NAME), AST_APP_OPTION('o', OPTION_READONLY), AST_APP_OPTION('q', OPTION_QUIET), @@ -496,11 +506,17 @@ static struct ast_generator spygen = { .generate = spy_generate, }; -static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook) +static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags) { ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan)); - - ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE); + if(!ast_test_flag(flags, OPTION_READONLY)) { + ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_MUTE_WRITE); + } + if(ast_test_flag(flags, OPTION_LONG_QUEUE)) { + ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n"); + } else { + ast_set_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE); + } return ast_audiohook_attach(autochan->chan, audiohook); } @@ -581,7 +597,7 @@ static void publish_chanspy_message(struct ast_channel *spyer, static int attach_barge(struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook, - const char *spyer_name, const char *name) + const char *spyer_name, const char *name, struct ast_flags *flags) { int retval = 0; struct ast_autochan *internal_bridge_autochan; @@ -599,7 +615,7 @@ static int attach_barge(struct ast_autochan *spyee_autochan, } ast_autochan_channel_lock(internal_bridge_autochan); - if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook)) { + if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) { ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name); retval = -1; } @@ -647,7 +663,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto */ ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0); - if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) { + if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook, flags)) { ast_audiohook_destroy(&csth.spy_audiohook); return 0; } @@ -658,7 +674,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto */ ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0); - if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) { + if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook, flags)) { ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name); } } @@ -710,7 +726,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto * be attached and we'll need to continue attempting to attach the barge * audio hook. */ if (!bridge_connected && attach_barge(spyee_autochan, &spyee_bridge_autochan, - &csth.bridge_whisper_audiohook, spyer_name, name) == 0) { + &csth.bridge_whisper_audiohook, spyer_name, name, flags) == 0) { bridge_connected = 1; } diff --git a/main/audiohook.c b/main/audiohook.c index e3089131e1..4a73fbd52e 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -45,6 +45,7 @@ ASTERISK_REGISTER_FILE() #define AST_AUDIOHOOK_SYNC_TOLERANCE 100 /*!< Tolerance in milliseconds for audiohooks synchronization */ #define AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE 100 /*!< When small queue is enabled, this is the maximum amount of audio that can remain queued at a time. */ +#define AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE 500 /*!< Otheriwise we still don't want the queue to grow indefinitely */ #define DEFAULT_INTERNAL_SAMPLE_RATE 8000 @@ -192,6 +193,10 @@ int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohoo ast_debug(1, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook); ast_slinfactory_flush(factory); ast_slinfactory_flush(other_factory); + } else if ((our_factory_ms > AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE) || (other_factory_ms > AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE)) { + ast_debug(1, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook); + ast_slinfactory_flush(factory); + ast_slinfactory_flush(other_factory); } /* swap frame data for zeros if mute is required */ -- GitLab