diff --git a/CHANGES b/CHANGES index 2922c51befb586a8afaf8563e3d468769928a31f..1391f049f6fc9fcf25b6f184ab1449c5675fc57f 100644 --- a/CHANGES +++ b/CHANGES @@ -33,6 +33,9 @@ Application Changes * ChanSpy and ExtenSpy have a new option, 's' which suppresses speaking the technology name (e.g. SIP, IAX, etc) of the channel being spied on. * The Jack application now has a c() option to supply a custom client name. + * Chanspy has a new option, 'B', which can be used to "barge" on a call. This is + like the pre-existing whisper mode, except that the spy can also talk to the + participant on the bridged channel as well. SIP Changes ----------- diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 8450c927e9d96f772b619ab48e374b782f250eaf..4ef2f4e4f3addc9eb0e7a153f5e637e792d94cc8 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -148,6 +148,7 @@ enum { OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */ OPTION_ENFORCED = (1 << 9), /* Enforced mode */ OPTION_NOTECH = (1 << 10), /* Skip technology name playback */ + OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */ } chanspy_opt_flags; enum { @@ -161,6 +162,7 @@ enum { AST_APP_OPTIONS(spy_opts, { AST_APP_OPTION('q', OPTION_QUIET), AST_APP_OPTION('b', OPTION_BRIDGED), + AST_APP_OPTION('B', OPTION_BARGE), AST_APP_OPTION('w', OPTION_WHISPER), AST_APP_OPTION('W', OPTION_PRIVATE), AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME), @@ -177,6 +179,7 @@ struct chanspy_translation_helper { /* spy data */ struct ast_audiohook spy_audiohook; struct ast_audiohook whisper_audiohook; + struct ast_audiohook bridge_whisper_audiohook; int fd; int volfactor; }; @@ -230,7 +233,7 @@ static struct ast_generator spygen = { .generate = spy_generate, }; -static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook) +static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook) { int res = 0; struct ast_channel *peer = NULL; @@ -296,10 +299,15 @@ static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chansp return 0; } - if (ast_test_flag(flags, OPTION_WHISPER)) { + if (ast_test_flag(flags, OPTION_BARGE)) { + ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy"); + ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy"); + start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */ + start_spying(ast_bridged_channel(spyee), spyer_name, &csth.bridge_whisper_audiohook); + } else if (ast_test_flag(flags, OPTION_WHISPER)) { ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy"); - start_spying(spyee, spyer_name, &csth.whisper_audiohook); - } + start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */ + } ast_channel_unlock(spyee); spyee = NULL; @@ -338,7 +346,16 @@ static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chansp break; } - if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) { + if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) { + ast_audiohook_lock(&csth.whisper_audiohook); + ast_audiohook_lock(&csth.bridge_whisper_audiohook); + ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); + ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); + ast_audiohook_unlock(&csth.whisper_audiohook); + ast_audiohook_unlock(&csth.bridge_whisper_audiohook); + ast_frfree(f); + continue; + } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) { ast_audiohook_lock(&csth.whisper_audiohook); ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); ast_audiohook_unlock(&csth.whisper_audiohook); @@ -400,7 +417,16 @@ static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chansp else ast_deactivate_generator(chan); - if (ast_test_flag(flags, OPTION_WHISPER)) { + if (ast_test_flag(flags, OPTION_BARGE)) { + ast_audiohook_lock(&csth.whisper_audiohook); + ast_audiohook_detach(&csth.whisper_audiohook); + ast_audiohook_unlock(&csth.whisper_audiohook); + ast_audiohook_destroy(&csth.whisper_audiohook); + ast_audiohook_lock(&csth.bridge_whisper_audiohook); + ast_audiohook_detach(&csth.bridge_whisper_audiohook); + ast_audiohook_unlock(&csth.bridge_whisper_audiohook); + ast_audiohook_destroy(&csth.bridge_whisper_audiohook); + } else if (ast_test_flag(flags, OPTION_WHISPER)) { ast_audiohook_lock(&csth.whisper_audiohook); ast_audiohook_detach(&csth.whisper_audiohook); ast_audiohook_unlock(&csth.whisper_audiohook);