ee4a69682b64070d9073e871b4356dd6a27bfd7b
[asterisk/asterisk.git] / bridges / bridge_builtin_features.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
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 Built in bridging features
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  *
25  * \ingroup bridges
26  */
27
28 /*** MODULEINFO
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41
42 #include "asterisk/module.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/bridge.h"
45 #include "asterisk/bridge_technology.h"
46 #include "asterisk/frame.h"
47 #include "asterisk/file.h"
48 #include "asterisk/app.h"
49 #include "asterisk/astobj2.h"
50 #include "asterisk/pbx.h"
51 #include "asterisk/parking.h"
52 #include "asterisk/features_config.h"
53 #include "asterisk/monitor.h"
54 #include "asterisk/mixmonitor.h"
55 #include "asterisk/audiohook.h"
56 #include "asterisk/causes.h"
57
58 enum set_touch_variables_res {
59         SET_TOUCH_SUCCESS,
60         SET_TOUCH_UNSET,
61         SET_TOUCH_ALLOC_FAILURE,
62 };
63
64 static void set_touch_variable(enum set_touch_variables_res *res, struct ast_channel *chan, const char *var_name, char **touch)
65 {
66         const char *c_touch;
67
68         if (*res == SET_TOUCH_ALLOC_FAILURE) {
69                 return;
70         }
71         c_touch = pbx_builtin_getvar_helper(chan, var_name);
72         if (!ast_strlen_zero(c_touch)) {
73                 *touch = ast_strdup(c_touch);
74                 if (!*touch) {
75                         *res = SET_TOUCH_ALLOC_FAILURE;
76                 } else {
77                         *res = SET_TOUCH_SUCCESS;
78                 }
79         }
80 }
81
82 static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan, int is_mixmonitor, char **touch_format, char **touch_monitor, char **touch_monitor_prefix)
83 {
84         enum set_touch_variables_res res = SET_TOUCH_UNSET;
85         const char *var_format;
86         const char *var_monitor;
87         const char *var_prefix;
88
89         SCOPED_CHANNELLOCK(lock, chan);
90
91         if (is_mixmonitor) {
92                 var_format = "TOUCH_MIXMONITOR_FORMAT";
93                 var_monitor = "TOUCH_MIXMONITOR";
94                 var_prefix = "TOUCH_MIXMONITOR_PREFIX";
95         } else {
96                 var_format = "TOUCH_MONITOR_FORMAT";
97                 var_monitor = "TOUCH_MONITOR";
98                 var_prefix = "TOUCH_MONITOR_PREFIX";
99         }
100         set_touch_variable(&res, chan, var_format, touch_format);
101         set_touch_variable(&res, chan, var_monitor, touch_monitor);
102         set_touch_variable(&res, chan, var_prefix, touch_monitor_prefix);
103
104         return res;
105 }
106
107 static void stop_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
108 {
109         ast_verb(3, "AutoMonitor used to stop recording call.\n");
110
111         ast_channel_lock(peer_chan);
112         if (ast_channel_monitor(peer_chan)) {
113                 if (ast_channel_monitor(peer_chan)->stop(peer_chan, 1)) {
114                         ast_verb(3, "Cannot stop AutoMonitor for %s\n", ast_channel_name(bridge_channel->chan));
115                         if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
116                                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
117                         }
118                         ast_channel_unlock(peer_chan);
119                         return;
120                 }
121         } else {
122                 /* Something else removed the Monitor before we got to it. */
123                 ast_channel_unlock(peer_chan);
124                 return;
125         }
126
127         ast_channel_unlock(peer_chan);
128
129         if (features_cfg && !(ast_strlen_zero(features_cfg->courtesytone))) {
130                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
131                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
132         }
133
134         if (!ast_strlen_zero(stop_message)) {
135                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
136                 ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
137         }
138 }
139
140 static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
141 {
142         char *touch_filename;
143         size_t len;
144         int x;
145         enum set_touch_variables_res set_touch_res;
146
147         RAII_VAR(char *, touch_format, NULL, ast_free);
148         RAII_VAR(char *, touch_monitor, NULL, ast_free);
149         RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
150
151         set_touch_res = set_touch_variables(bridge_channel->chan, 0, &touch_format,
152                 &touch_monitor, &touch_monitor_prefix);
153         switch (set_touch_res) {
154         case SET_TOUCH_SUCCESS:
155                 break;
156         case SET_TOUCH_UNSET:
157                 set_touch_res = set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor,
158                         &touch_monitor_prefix);
159                 if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
160                         return;
161                 }
162                 break;
163         case SET_TOUCH_ALLOC_FAILURE:
164                 return;
165         }
166
167         if (!ast_strlen_zero(touch_monitor)) {
168                 len = strlen(touch_monitor) + 50;
169                 touch_filename = ast_alloca(len);
170                 snprintf(touch_filename, len, "%s-%ld-%s",
171                         S_OR(touch_monitor_prefix, "auto"),
172                         (long) time(NULL),
173                         touch_monitor);
174         } else {
175                 char *caller_chan_id;
176                 char *peer_chan_id;
177
178                 caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
179                         ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
180                 peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
181                         ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
182                 len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
183                 touch_filename = ast_alloca(len);
184                 snprintf(touch_filename, len, "%s-%ld-%s-%s",
185                         S_OR(touch_monitor_prefix, "auto"),
186                         (long) time(NULL),
187                         caller_chan_id,
188                         peer_chan_id);
189         }
190
191         for (x = 0; x < strlen(touch_filename); x++) {
192                 if (touch_filename[x] == '/') {
193                         touch_filename[x] = '-';
194                 }
195         }
196
197         ast_verb(3, "AutoMonitor used to record call. Filename: %s\n", touch_filename);
198
199         if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT)) {
200                 ast_verb(3, "automon feature was tried by '%s' but monitor failed to start.\n",
201                         ast_channel_name(bridge_channel->chan));
202                 return;
203         }
204
205         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
206                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
207                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
208         }
209
210         if (!ast_strlen_zero(start_message)) {
211                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
212                 ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
213         }
214
215         pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
216 }
217
218 static int feature_automonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
219 {
220         const char *start_message;
221         const char *stop_message;
222         struct ast_bridge_features_automonitor *options = hook_pvt;
223         enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
224         int is_monitoring;
225
226         RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
227         RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
228
229         features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
230         ast_bridge_channel_lock_bridge(bridge_channel);
231         peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
232         ast_bridge_unlock(bridge_channel->bridge);
233
234         if (!peer_chan) {
235                 ast_verb(3, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n",
236                         ast_channel_name(bridge_channel->chan));
237                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
238                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
239                 }
240                 return 0;
241         }
242
243         ast_channel_lock(bridge_channel->chan);
244         start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
245                 "TOUCH_MONITOR_MESSAGE_START");
246         start_message = ast_strdupa(S_OR(start_message, ""));
247         stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
248                 "TOUCH_MONITOR_MESSAGE_STOP");
249         stop_message = ast_strdupa(S_OR(stop_message, ""));
250         ast_channel_unlock(bridge_channel->chan);
251
252         is_monitoring = ast_channel_monitor(peer_chan) != NULL;
253         switch (start_stop) {
254         case AUTO_MONITOR_TOGGLE:
255                 if (is_monitoring) {
256                         stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
257                 } else {
258                         start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
259                 }
260                 return 0;
261         case AUTO_MONITOR_START:
262                 if (!is_monitoring) {
263                         start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
264                         return 0;
265                 }
266                 ast_verb(3, "AutoMonitor already recording call.\n");
267                 break;
268         case AUTO_MONITOR_STOP:
269                 if (is_monitoring) {
270                         stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
271                         return 0;
272                 }
273                 ast_verb(3, "AutoMonitor already not recording call.\n");
274                 break;
275         }
276
277         /*
278          * Fake start/stop to invoker so will think it did something but
279          * was already in that mode.
280          */
281         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
282                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
283         }
284         if (is_monitoring) {
285                 if (!ast_strlen_zero(start_message)) {
286                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
287                 }
288         } else {
289                 if (!ast_strlen_zero(stop_message)) {
290                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
291                 }
292         }
293         return 0;
294 }
295
296 static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
297 {
298         ast_verb(3, "AutoMixMonitor used to stop recording call.\n");
299
300         if (ast_stop_mixmonitor(peer_chan, NULL)) {
301                 ast_verb(3, "Failed to stop Mixmonitor for %s.\n", ast_channel_name(bridge_channel->chan));
302                 if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
303                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
304                 }
305                 return;
306         }
307
308         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
309                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
310                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
311         }
312
313         if (!ast_strlen_zero(stop_message)) {
314                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
315                 ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
316         }
317 }
318
319 static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
320 {
321         char *touch_filename;
322         size_t len;
323         int x;
324         enum set_touch_variables_res set_touch_res;
325
326         RAII_VAR(char *, touch_format, NULL, ast_free);
327         RAII_VAR(char *, touch_monitor, NULL, ast_free);
328         RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
329
330         set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format,
331                 &touch_monitor, &touch_monitor_prefix);
332         switch (set_touch_res) {
333         case SET_TOUCH_SUCCESS:
334                 break;
335         case SET_TOUCH_UNSET:
336                 set_touch_res = set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor,
337                         &touch_monitor_prefix);
338                 if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
339                         return;
340                 }
341                 break;
342         case SET_TOUCH_ALLOC_FAILURE:
343                 return;
344         }
345
346         if (!ast_strlen_zero(touch_monitor)) {
347                 len = strlen(touch_monitor) + 50;
348                 touch_filename = ast_alloca(len);
349                 snprintf(touch_filename, len, "%s-%ld-%s.%s",
350                         S_OR(touch_monitor_prefix, "auto"),
351                         (long) time(NULL),
352                         touch_monitor,
353                         S_OR(touch_format, "wav"));
354         } else {
355                 char *caller_chan_id;
356                 char *peer_chan_id;
357
358                 caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
359                         ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
360                 peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
361                         ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
362                 len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
363                 touch_filename = ast_alloca(len);
364                 snprintf(touch_filename, len, "%s-%ld-%s-%s.%s",
365                         S_OR(touch_monitor_prefix, "auto"),
366                         (long) time(NULL),
367                         caller_chan_id,
368                         peer_chan_id,
369                         S_OR(touch_format, "wav"));
370         }
371
372         for (x = 0; x < strlen(touch_filename); x++) {
373                 if (touch_filename[x] == '/') {
374                         touch_filename[x] = '-';
375                 }
376         }
377
378         ast_verb(3, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);
379
380         if (ast_start_mixmonitor(peer_chan, touch_filename, "b")) {
381                 ast_verb(3, "automixmon feature was tried by '%s' but mixmonitor failed to start.\n",
382                         ast_channel_name(bridge_channel->chan));
383
384                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
385                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
386                 }
387                 return;
388         }
389
390         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
391                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
392                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
393         }
394
395         if (!ast_strlen_zero(start_message)) {
396                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
397                 ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
398         }
399
400         pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
401 }
402
403 static int feature_automixmonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
404 {
405         static const char *mixmonitor_spy_type = "MixMonitor";
406         const char *stop_message;
407         const char *start_message;
408         struct ast_bridge_features_automixmonitor *options = hook_pvt;
409         enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
410         int is_monitoring;
411
412         RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
413         RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
414
415         features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
416         ast_bridge_channel_lock_bridge(bridge_channel);
417         peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
418         ast_bridge_unlock(bridge_channel->bridge);
419
420         if (!peer_chan) {
421                 ast_verb(3, "Cannot do AutoMixMonitor for %s - cannot determine peer in bridge.\n",
422                         ast_channel_name(bridge_channel->chan));
423                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
424                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
425                 }
426                 return 0;
427         }
428
429         ast_channel_lock(bridge_channel->chan);
430         start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
431                 "TOUCH_MIXMONITOR_MESSAGE_START");
432         start_message = ast_strdupa(S_OR(start_message, ""));
433         stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
434                 "TOUCH_MIXMONITOR_MESSAGE_STOP");
435         stop_message = ast_strdupa(S_OR(stop_message, ""));
436         ast_channel_unlock(bridge_channel->chan);
437
438         is_monitoring =
439                 0 < ast_channel_audiohook_count_by_source(peer_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
440         switch (start_stop) {
441         case AUTO_MONITOR_TOGGLE:
442                 if (is_monitoring) {
443                         stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
444                 } else {
445                         start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
446                 }
447                 return 0;
448         case AUTO_MONITOR_START:
449                 if (!is_monitoring) {
450                         start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
451                         return 0;
452                 }
453                 ast_verb(3, "AutoMixMonitor already recording call.\n");
454                 break;
455         case AUTO_MONITOR_STOP:
456                 if (is_monitoring) {
457                         stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
458                         return 0;
459                 }
460                 ast_verb(3, "AutoMixMonitor already not recording call.\n");
461                 break;
462         }
463
464         /*
465          * Fake start/stop to invoker so will think it did something but
466          * was already in that mode.
467          */
468         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
469                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
470         }
471         if (is_monitoring) {
472                 if (!ast_strlen_zero(start_message)) {
473                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
474                 }
475         } else {
476                 if (!ast_strlen_zero(stop_message)) {
477                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
478                 }
479         }
480         return 0;
481 }
482
483 /*! \brief Internal built in feature for hangup */
484 static int feature_hangup(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
485 {
486         /*
487          * This is very simple, we simply change the state on the
488          * bridge_channel to force the channel out of the bridge and the
489          * core takes care of the rest.
490          */
491         ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
492                 AST_CAUSE_NORMAL_CLEARING);
493         return 0;
494 }
495
496 static int unload_module(void)
497 {
498         return 0;
499 }
500
501 static int load_module(void)
502 {
503         ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
504         ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMON, feature_automonitor, NULL);
505         ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMIXMON, feature_automixmonitor, NULL);
506
507         /* Bump up our reference count so we can't be unloaded */
508         ast_module_ref(ast_module_info->self);
509
510         return AST_MODULE_LOAD_SUCCESS;
511 }
512
513 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Built in bridging features");