Wed Jan 8 2020 09:49:50

Asterisk developer's documentation


res_mutestream.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Olle E. Johansson
5  *
6  * Olle E. Johansson <oej@edvina.net>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief MUTESTREAM audiohooks
22  *
23  * \author Olle E. Johansson <oej@edvina.net>
24  *
25  * \ingroup functions
26  *
27  * \note This module only handles audio streams today, but can easily be appended to also
28  * zero out text streams if there's an application for it.
29  * When we know and understands what happens if we zero out video, we can do that too.
30  */
31 
32 /*** MODULEINFO
33  <support_level>core</support_level>
34  ***/
35 
36 #include "asterisk.h"
37 
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411313 $")
39 
40 //#include <time.h>
41 //#include <string.h>
42 //#include <stdio.h>
43 //#include <stdlib.h>
44 //#include <unistd.h>
45 //#include <errno.h>
46 
47 #include "asterisk/options.h"
48 #include "asterisk/logger.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/module.h"
51 #include "asterisk/config.h"
52 #include "asterisk/file.h"
53 #include "asterisk/pbx.h"
54 #include "asterisk/frame.h"
55 #include "asterisk/utils.h"
56 #include "asterisk/audiohook.h"
57 #include "asterisk/manager.h"
58 
59 /*** DOCUMENTATION
60  <function name="MUTEAUDIO" language="en_US">
61  <synopsis>
62  Muting audio streams in the channel
63  </synopsis>
64  <syntax>
65  <parameter name="direction" required="true">
66  <para>Must be one of </para>
67  <enumlist>
68  <enum name="in">
69  <para>Inbound stream (to the PBX)</para>
70  </enum>
71  <enum name="out">
72  <para>Outbound stream (from the PBX)</para>
73  </enum>
74  <enum name="all">
75  <para>Both streams</para>
76  </enum>
77  </enumlist>
78  </parameter>
79  </syntax>
80  <description>
81  <para>The MUTEAUDIO function can be used to mute inbound (to the PBX) or outbound audio in a call.
82  Example:
83  </para>
84  <para>
85  MUTEAUDIO(in)=on
86  MUTEAUDIO(in)=off
87  </para>
88  </description>
89  </function>
90  ***/
91 
92 
93 /*! Our own datastore */
97  int mute_read;
98 };
99 
100 
101 #define TRUE 1
102 #define FALSE 0
103 
104 /*! Datastore destroy audiohook callback */
105 static void destroy_callback(void *data)
106 {
107  struct mute_information *mute = data;
108 
109  /* Destroy the audiohook, and destroy ourselves */
111  ast_free(mute);
113 
114  return;
115 }
116 
117 /*! \brief Static structure for datastore information */
118 static const struct ast_datastore_info mute_datastore = {
119  .type = "mute",
120  .destroy = destroy_callback
121 };
122 
123 /*! \brief The callback from the audiohook subsystem. We basically get a frame to have fun with */
124 static int mute_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
125 {
126  struct ast_datastore *datastore = NULL;
127  struct mute_information *mute = NULL;
128 
129 
130  /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
131  if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
132  return 0;
133  }
134 
135  ast_channel_lock(chan);
136  /* Grab datastore which contains our mute information */
137  if (!(datastore = ast_channel_datastore_find(chan, &mute_datastore, NULL))) {
138  ast_channel_unlock(chan);
139  ast_debug(2, "Can't find any datastore to use. Bad. \n");
140  return 0;
141  }
142 
143  mute = datastore->data;
144 
145 
146  /* If this is audio then allow them to increase/decrease the gains */
147  if (frame->frametype == AST_FRAME_VOICE) {
148  ast_debug(2, "Audio frame - direction %s mute READ %s WRITE %s\n", direction == AST_AUDIOHOOK_DIRECTION_READ ? "read" : "write", mute->mute_read ? "on" : "off", mute->mute_write ? "on" : "off");
149 
150  /* Based on direction of frame grab the gain, and confirm it is applicable */
151  if ((direction == AST_AUDIOHOOK_DIRECTION_READ && mute->mute_read) || (direction == AST_AUDIOHOOK_DIRECTION_WRITE && mute->mute_write)) {
152  /* Ok, we just want to reset all audio in this frame. Keep NOTHING, thanks. */
153  ast_frame_clear(frame);
154  }
155  }
156  ast_channel_unlock(chan);
157 
158  return 0;
159 }
160 
161 /*! \brief Initialize mute hook on channel, but don't activate it
162  \pre Assumes that the channel is locked
163 */
164 static struct ast_datastore *initialize_mutehook(struct ast_channel *chan)
165 {
166  struct ast_datastore *datastore = NULL;
167  struct mute_information *mute = NULL;
168 
169  ast_debug(2, "Initializing new Mute Audiohook \n");
170 
171  /* Allocate a new datastore to hold the reference to this mute_datastore and audiohook information */
172  if (!(datastore = ast_datastore_alloc(&mute_datastore, NULL))) {
173  return NULL;
174  }
175 
176  if (!(mute = ast_calloc(1, sizeof(*mute)))) {
177  ast_datastore_free(datastore);
178  return NULL;
179  }
182  datastore->data = mute;
183  return datastore;
184 }
185 
186 /*! \brief Add or activate mute audiohook on channel
187  Assumes channel is locked
188 */
189 static int mute_add_audiohook(struct ast_channel *chan, struct mute_information *mute, struct ast_datastore *datastore)
190 {
191  /* Activate the settings */
192  ast_channel_datastore_add(chan, datastore);
193  if (ast_audiohook_attach(chan, &mute->audiohook)) {
194  ast_log(LOG_ERROR, "Failed to attach audiohook for muting channel %s\n", chan->name);
195  return -1;
196  }
198  ast_debug(2, "Initialized audiohook on channel %s\n", chan->name);
199  return 0;
200 }
201 
202 /*! \brief Mute dialplan function */
203 static int func_mute_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
204 {
205  struct ast_datastore *datastore = NULL;
206  struct mute_information *mute = NULL;
207  int is_new = 0;
208 
209  if (!chan) {
210  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
211  return -1;
212  }
213 
214  ast_channel_lock(chan);
215  if (!(datastore = ast_channel_datastore_find(chan, &mute_datastore, NULL))) {
216  if (!(datastore = initialize_mutehook(chan))) {
217  ast_channel_unlock(chan);
218  return 0;
219  }
220  is_new = 1;
221  }
222 
223  mute = datastore->data;
224 
225  if (!strcasecmp(data, "out")) {
226  mute->mute_write = ast_true(value);
227  ast_debug(1, "%s channel - outbound \n", ast_true(value) ? "Muting" : "Unmuting");
228  } else if (!strcasecmp(data, "in")) {
229  mute->mute_read = ast_true(value);
230  ast_debug(1, "%s channel - inbound \n", ast_true(value) ? "Muting" : "Unmuting");
231  } else if (!strcasecmp(data,"all")) {
232  mute->mute_write = mute->mute_read = ast_true(value);
233  }
234 
235  if (is_new) {
236  if (mute_add_audiohook(chan, mute, datastore)) {
237  /* Can't add audiohook - already printed error message */
238  ast_datastore_free(datastore);
239  ast_free(mute);
240  }
241  }
242  ast_channel_unlock(chan);
243 
244  return 0;
245 }
246 
247 /* Function for debugging - might be useful */
249  .name = "MUTEAUDIO",
250  .write = func_mute_write,
251 };
252 
253 static int manager_mutestream(struct mansession *s, const struct message *m)
254 {
255  const char *channel = astman_get_header(m, "Channel");
256  const char *id = astman_get_header(m,"ActionID");
257  const char *state = astman_get_header(m,"State");
258  const char *direction = astman_get_header(m,"Direction");
259  char id_text[256] = "";
260  struct ast_channel *c = NULL;
261  struct ast_datastore *datastore = NULL;
262  struct mute_information *mute = NULL;
263  int is_new = 0;
264  int turnon = TRUE;
265 
266  if (ast_strlen_zero(channel)) {
267  astman_send_error(s, m, "Channel not specified");
268  return 0;
269  }
270  if (ast_strlen_zero(state)) {
271  astman_send_error(s, m, "State not specified");
272  return 0;
273  }
274  if (ast_strlen_zero(direction)) {
275  astman_send_error(s, m, "Direction not specified");
276  return 0;
277  }
278  /* Ok, we have everything */
279  if (!ast_strlen_zero(id)) {
280  snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
281  }
282 
283  c = ast_channel_get_by_name(channel);
284  if (!c) {
285  astman_send_error(s, m, "No such channel");
286  return 0;
287  }
288 
289  ast_channel_lock(c);
290 
291  if (!(datastore = ast_channel_datastore_find(c, &mute_datastore, NULL))) {
292  if (!(datastore = initialize_mutehook(c))) {
295  return 0;
296  }
297  is_new = 1;
298  }
299  mute = datastore->data;
300  turnon = ast_true(state);
301 
302  if (!strcasecmp(direction, "in")) {
303  mute->mute_read = turnon;
304  } else if (!strcasecmp(direction, "out")) {
305  mute->mute_write = turnon;
306  } else if (!strcasecmp(direction, "all")) {
307  mute->mute_read = mute->mute_write = turnon;
308  }
309 
310  if (is_new) {
311  if (mute_add_audiohook(c, mute, datastore)) {
312  /* Can't add audiohook - already printed error message */
313  ast_datastore_free(datastore);
314  ast_free(mute);
315  }
316  }
319 
320  astman_append(s, "Response: Success\r\n"
321  "%s"
322  "\r\n\r\n", id_text);
323  return 0;
324 }
325 
326 
327 static const char mandescr_mutestream[] =
328 "Description: Mute an incoming or outbound audio stream in a channel.\n"
329 "Variables: \n"
330 " Channel: <name> The channel you want to mute.\n"
331 " Direction: in | out |all The stream you want to mute.\n"
332 " State: on | off Whether to turn mute on or off.\n"
333 " ActionID: <id> Optional action ID for this AMI transaction.\n";
334 
335 
336 static int load_module(void)
337 {
338  int res;
339  res = ast_custom_function_register(&mute_function);
340 
342  "Mute an audio stream", mandescr_mutestream);
343 
345 }
346 
347 static int unload_module(void)
348 {
349  ast_custom_function_unregister(&mute_function);
350  /* Unregister AMI actions */
351  ast_manager_unregister("MuteAudio");
352 
353  return 0;
354 }
355 
356 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mute audio stream resources");
const char * type
Definition: datastore.h:32
#define ast_channel_lock(chan)
Definition: channel.h:2466
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:2068
Asterisk main include file. File version handling, generic pbx functions.
struct ast_audiohook audiohook
void ast_module_unref(struct ast_module *)
Definition: loader.c:1312
int ast_frame_clear(struct ast_frame *frame)
Clear all audio samples from an ast_frame. The frame must be AST_FRAME_VOICE and AST_FORMAT_SLINEAR.
Definition: frame.c:1629
static struct ast_datastore * initialize_mutehook(struct ast_channel *chan)
Initialize mute hook on channel, but don&#39;t activate it.
static int mute_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
The callback from the audiohook subsystem. We basically get a frame to have fun with.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
static int load_module(void)
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source)
Initialize an audiohook structure.
Definition: audiohook.c:64
#define LOG_WARNING
Definition: logger.h:144
Audiohooks Architecture.
Structure for a data store type.
Definition: datastore.h:31
Configuration File Parser.
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:348
Structure for a data store object.
Definition: datastore.h:54
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2604
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int value
Definition: syslog.c:39
static void destroy_callback(void *data)
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:96
#define TRUE
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Definition: pbx.c:3814
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:65
static int mute
Definition: chan_alsa.c:135
Utility functions.
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:1860
ast_audiohook_manipulate_callback manipulate_callback
Definition: audiohook.h:116
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
static const char mandescr_mutestream[]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
struct ast_module * self
Definition: module.h:227
General Asterisk PBX channel definitions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
Data structure associated with a custom dialplan function.
Definition: pbx.h:95
Asterisk internal frame definitions.
int ast_manager_register2(const char *action, int authority, int(*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
Register a manager command with the manager interface.
Definition: manager.c:5469
static int mute_add_audiohook(struct ast_channel *chan, struct mute_information *mute, struct ast_datastore *datastore)
Add or activate mute audiohook on channel Assumes channel is locked.
Core PBX routines and definitions.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define LOG_ERROR
Definition: logger.h:155
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static struct ast_datastore_info mute_datastore
Static structure for datastore information.
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
Definition: datastore.c:98
#define ast_channel_unlock(chan)
Definition: channel.h:2467
#define ast_free(a)
Definition: astmm.h:97
ast_audiohook_direction
Definition: audiohook.h:49
Support for logging to various files, console and syslog Configuration in file logger.conf.
static int func_mute_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Mute dialplan function.
void * data
Definition: datastore.h:56
#define ast_calloc(a, b)
Definition: astmm.h:82
Data structure associated with a single frame of data.
Definition: frame.h:142
static int unload_module(void)
const char * name
Definition: pbx.h:96
enum ast_audiohook_status status
Definition: audiohook.h:107
enum ast_frame_type frametype
Definition: frame.h:144
static struct ast_custom_function mute_function
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1803
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:2130
Asterisk module definitions.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2590
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1164
int ast_manager_unregister(char *action)
Unregister a registered manager command.
Definition: manager.c:5355
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
static int manager_mutestream(struct mansession *s, const struct message *m)
struct ast_module * ast_module_ref(struct ast_module *)
Definition: loader.c:1300