Index: 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
@@ -124,7 +125,41 @@
[MixMonitor]
-
+
+
+ Mute a Mixmonitor recording.
+
+
+
+
+ Used to specify the channel to mute.
+
+
+ Which part of the recording to mute: read, write or both (from channel, to channel or both channels).
+
+
+
+ This action may be used to mute a MixMonitor recording.
+
+
+
+
+ Unmute a Mixmonitor recording.
+
+
+
+
+ Used to specify the channel to unmute.
+
+
+ Which part of the recording to unmute: read, write or both (from channel, to channel or both channels).
+
+
+
+ This action may be used to unmute a MixMonitor recording.
+
+
+
***/
#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)
}
#endif
Index: 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)
}
#endif
Index: 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)
{