mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 20:04:50 +00:00
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
This commit is contained in:
7
CHANGES
7
CHANGES
@@ -31,6 +31,13 @@ BridgeAdd
|
|||||||
* A new application in Asterisk, this will join the calling channel
|
* A new application in Asterisk, this will join the calling channel
|
||||||
to an existing bridge containing the named channel prefix.
|
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
|
ConfBridge
|
||||||
------------------
|
------------------
|
||||||
* Added the ability to pass options to MixMonitor when recording is used with
|
* Added the ability to pass options to MixMonitor when recording is used with
|
||||||
|
@@ -117,6 +117,10 @@ ASTERISK_REGISTER_FILE()
|
|||||||
either a single group or a colon-delimited list of groups, such
|
either a single group or a colon-delimited list of groups, such
|
||||||
as <literal>sales:support:accounting</literal>.</para></note>
|
as <literal>sales:support:accounting</literal>.</para></note>
|
||||||
</option>
|
</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="@">
|
<option name="n" argsep="@">
|
||||||
<para>Say the name of the person being spied on if that person has recorded
|
<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
|
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
|
either a single group or a colon-delimited list of groups, such
|
||||||
as <literal>sales:support:accounting</literal>.</para></note>
|
as <literal>sales:support:accounting</literal>.</para></note>
|
||||||
</option>
|
</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="@">
|
<option name="n" argsep="@">
|
||||||
<para>Say the name of the person being spied on if that person has recorded
|
<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
|
his/her name. If a context is specified, then that voicemail context will
|
||||||
@@ -386,6 +394,7 @@ enum {
|
|||||||
OPTION_STOP = (1 << 17),
|
OPTION_STOP = (1 << 17),
|
||||||
OPTION_EXITONHANGUP = (1 << 18), /* Hang up when the spied-on channel hangs up. */
|
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_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 {
|
enum {
|
||||||
@@ -407,6 +416,7 @@ AST_APP_OPTIONS(spy_opts, {
|
|||||||
AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED),
|
AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED),
|
||||||
AST_APP_OPTION('E', OPTION_EXITONHANGUP),
|
AST_APP_OPTION('E', OPTION_EXITONHANGUP),
|
||||||
AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
|
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_ARG('n', OPTION_NAME, OPT_ARG_NAME),
|
||||||
AST_APP_OPTION('o', OPTION_READONLY),
|
AST_APP_OPTION('o', OPTION_READONLY),
|
||||||
AST_APP_OPTION('q', OPTION_QUIET),
|
AST_APP_OPTION('q', OPTION_QUIET),
|
||||||
@@ -496,11 +506,17 @@ static struct ast_generator spygen = {
|
|||||||
.generate = spy_generate,
|
.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_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan));
|
||||||
|
if(!ast_test_flag(flags, OPTION_READONLY)) {
|
||||||
ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
|
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);
|
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,
|
static int attach_barge(struct ast_autochan *spyee_autochan,
|
||||||
struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook,
|
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;
|
int retval = 0;
|
||||||
struct ast_autochan *internal_bridge_autochan;
|
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);
|
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);
|
ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
|
||||||
retval = -1;
|
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);
|
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);
|
ast_audiohook_destroy(&csth.spy_audiohook);
|
||||||
return 0;
|
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);
|
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);
|
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
|
* be attached and we'll need to continue attempting to attach the barge
|
||||||
* audio hook. */
|
* audio hook. */
|
||||||
if (!bridge_connected && attach_barge(spyee_autochan, &spyee_bridge_autochan,
|
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;
|
bridge_connected = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,6 +45,7 @@ ASTERISK_REGISTER_FILE()
|
|||||||
|
|
||||||
#define AST_AUDIOHOOK_SYNC_TOLERANCE 100 /*!< Tolerance in milliseconds for audiohooks synchronization */
|
#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_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
|
#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_debug(1, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
|
||||||
ast_slinfactory_flush(factory);
|
ast_slinfactory_flush(factory);
|
||||||
ast_slinfactory_flush(other_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 */
|
/* swap frame data for zeros if mute is required */
|
||||||
|
Reference in New Issue
Block a user