rendered paste bodyIndex: apps/app_mixmonitor.c===================================================================--- apps/app_mixmonitor.c (revision 253530)+++ apps/app_mixmonitor.c (working copy)@@ -46,6 +46,7 @@ #include "asterisk/app.h" #include "asterisk/channel.h" #include "asterisk/autochan.h"+#include "asterisk/manager.h" /*** DOCUMENTATION <application name="MixMonitor" language="en_US">@@ -124,7 +125,41 @@ <ref type="application">MixMonitor</ref> </see-also> </application>- + <manager name="MuteMixMonitor" language="en_US">+ <synopsis>+ Mute a Mixmonitor recording.+ </synopsis>+ <syntax>+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />+ <parameter name="Channel" required="true">+ <para>Used to specify the channel to mute.</para>+ </parameter>+ <parameter name="Direction">+ <para>Which part of the recording to mute: read, write or both (from channel, to channel or both channels).</para>+ </parameter>+ </syntax>+ <description>+ <para>This action may be used to mute a MixMonitor recording.</para>+ </description>+ </manager>+ <manager name="UnmuteMixMonitor" language="en_US">+ <synopsis>+ Unmute a Mixmonitor recording.+ </synopsis>+ <syntax>+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />+ <parameter name="Channel" required="true">+ <para>Used to specify the channel to unmute.</para>+ </parameter>+ <parameter name="Direction">+ <para>Which part of the recording to unmute: read, write or both (from channel, to channel or both channels).</para>+ </parameter>+ </syntax>+ <description>+ <para>This action may be used to unmute a MixMonitor recording.</para>+ </description>+ </manager>+ ***/ #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0@@ -605,6 +640,75 @@ return CLI_SUCCESS; } +/*! \brief Mute / unmute a MixMonitor channel */+static int mute_mixmonitor(struct mansession *s, const struct message *m, int muteflag)+{+ struct ast_channel *c = NULL;++ const char *name = astman_get_header(m, "Channel");+ const char *id = astman_get_header(m, "ActionID");+ const char *direction = astman_get_header(m,"Direction");++ enum ast_audiohook_flags flag;++ if (ast_strlen_zero(direction)) {+ astman_send_error(s, m, "No direction specified. Must be read, write or both");+ return AMI_SUCCESS;+ }++ if (!strcasecmp(direction, "read")) {+ flag = AST_AUDIOHOOK_MUTE_READ;+ } else if (!strcasecmp(direction, "write")) {+ flag = AST_AUDIOHOOK_MUTE_WRITE;+ } else if (!strcasecmp(direction, "both")) {+ flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;+ } else {+ astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");+ return AMI_SUCCESS;+ }++ if (ast_strlen_zero(name)) {+ astman_send_error(s, m, "No channel specified");+ return AMI_SUCCESS;+ }++ c = ast_channel_get_by_name(name);++ if (!c) {+ astman_send_error(s, m, "No such channel");+ return AMI_SUCCESS;+ }++ if (!ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, muteflag)) {+ astman_send_error(s, m, "Cannot set mute flag");+ return AMI_SUCCESS;+ }++ astman_append(s, "Response: Success\r\n");++ if (!ast_strlen_zero(id)) {+ astman_append(s, "ActionID: %s\r\n", id);+ }++ astman_append(s, "\r\n");++ c = ast_channel_unref(c);++ return AMI_SUCCESS;+}++/*! \brief Unmute a MixMonitor channel */+static int manager_unmute_mixmonitor(struct mansession *s, const struct message *m)+{+ return mute_mixmonitor(s, m, 1);+}++/*! \brief Mute a MixMonitor channel */+static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)+{+ return mute_mixmonitor(s, m, 0);+}+ static struct ast_cli_entry cli_mixmonitor[] = { AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command") };@@ -616,6 +720,8 @@ ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); res = ast_unregister_application(stop_app); res |= ast_unregister_application(app);+ res |= ast_manager_unregister("MuteMixMonitor");+ res |= ast_manager_unregister("UnmuteMixMonitor"); return res; }@@ -627,6 +733,8 @@ ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); res = ast_register_application_xml(app, mixmonitor_exec); res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);+ res |= ast_manager_register_xml("UnmuteMixMonitor", 0, manager_unmute_mixmonitor);+ res |= ast_manager_register_xml("MuteMixMonitor", 0, manager_mute_mixmonitor); return res; }Index: include/asterisk/frame.h===================================================================--- include/asterisk/frame.h (revision 253530)+++ include/asterisk/frame.h (working copy)@@ -720,6 +720,11 @@ } } +/*!+ * \brief Clear all audio samples from an ast_frame.+ */+static inline void ast_frame_clear(struct ast_frame *frame);+ #if defined(__cplusplus) || defined(c_plusplus) } #endifIndex: include/asterisk/audiohook.h===================================================================--- include/asterisk/audiohook.h (revision 253530)+++ include/asterisk/audiohook.h (working copy)@@ -62,6 +62,8 @@ * slinfactories. We will flush the factories if they contain too many samples. */ AST_AUDIOHOOK_SMALL_QUEUE = (1 << 3),+ AST_AUDIOHOOK_MUTE_READ = (1 << 4), /*!< audiohook should be mute frames read */+ AST_AUDIOHOOK_MUTE_WRITE = (1 << 5), /*!< audiohook should be mute frames written */ }; #define AST_AUDIOHOOK_SYNC_TOLERANCE 100 /*< Tolerance in milliseconds for audiohooks synchronization */@@ -277,6 +279,16 @@ */ int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume); +/*! \brief Mute frames read from or written to a channel+ * \param chan Channel to muck with+ * \param source Type of audiohook+ * \param flag which flag to set / clear+ * \param clear set or clear+ * \retval 0 success+ * \retval -1 failure+ */+int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear);+ #if defined(__cplusplus) || defined(c_plusplus) } #endifIndex: main/frame.c===================================================================--- main/frame.c (revision 253530)+++ main/frame.c (working copy)@@ -1587,3 +1587,15 @@ return 0; }++int ast_frame_clear(struct ast_frame *frame)+{+ struct ast_frame *next;++ for (next = AST_LIST_NEXT(frame, frame_list);+ frame;+ frame = next, next = frame ? AST_LIST_NEXT(frame, frame_list) : NULL) {+ memset(frame->data.ptr, 0, frame->datalen);+ }+ return 0;+}Index: main/audiohook.c===================================================================--- main/audiohook.c (revision 253530)+++ main/audiohook.c (working copy)@@ -127,7 +127,12 @@ int our_factory_ms; int other_factory_samples; int other_factory_ms;+ int muteme = 0; + /* define buffer for zero data, and buffer to store original data in */+ void *mutedbuf = NULL;+ void *originalbuf = NULL;+ /* Update last feeding time to be current */ *rwtime = ast_tvnow(); @@ -151,6 +156,17 @@ ast_slinfactory_flush(other_factory); } + /* swap frame data for zeros if mute is required */+ if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) ||+ (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) ||+ (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE) == (AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE))) {+ muteme = 1;+ }++ if (muteme && frame->datalen > 0) {+ ast_frame_clear(frame);+ }+ /* Write frame out to respective factory */ ast_slinfactory_feed(factory, frame); @@ -1001,3 +1017,37 @@ return 0; }++/*! \brief Mute frames read from or written to a channel+ * \param chan Channel to muck with+ * \param source Type of audiohook+ * \param flag which flag to set / clear+ * \param clear set or clear+ * \return Returns 0 on success, -1 on failure+ */+int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)+{+ struct ast_audiohook *audiohook = NULL;++ ast_channel_lock(chan);++ /* Ensure the channel has audiohooks on it */+ if (!chan->audiohooks) {+ ast_channel_unlock(chan);+ return -1;+ }++ audiohook = find_audiohook_by_source(chan->audiohooks, source);++ if (audiohook) {+ if (clear) {+ ast_clear_flag(audiohook, flag);+ } else {+ ast_set_flag(audiohook, flag);+ }+ }++ ast_channel_unlock(chan);++ return (audiohook ? 0 : -1);+}Index: res/res_mutestream.c===================================================================--- res/res_mutestream.c (revision 253530)+++ res/res_mutestream.c (working copy)@@ -116,19 +116,6 @@ .destroy = destroy_callback }; -/*! \brief Wipe out all audio samples from an ast_frame. Clean it. */-static void ast_frame_clear(struct ast_frame *frame)-{- struct ast_frame *next;-- for (next = AST_LIST_NEXT(frame, frame_list);- frame;- frame = next, next = frame ? AST_LIST_NEXT(frame, frame_list) : NULL) {- memset(frame->data.ptr, 0, frame->datalen);- }-}-- /*! \brief The callback from the audiohook subsystem. We basically get a frame to have fun with */ static int mute_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction) {