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