Merge "ARI: Run 'make ari-stubs'"
[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         <use type="module">res_monitor</use>
30         <support_level>core</support_level>
31  ***/
32
33 #include "asterisk.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40
41 #include "asterisk/module.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/bridge.h"
44 #include "asterisk/bridge_technology.h"
45 #include "asterisk/frame.h"
46 #include "asterisk/file.h"
47 #include "asterisk/app.h"
48 #include "asterisk/astobj2.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/parking.h"
51 #include "asterisk/features_config.h"
52 #include "asterisk/monitor.h"
53 #include "asterisk/mixmonitor.h"
54 #include "asterisk/audiohook.h"
55 #include "asterisk/causes.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(4, "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(4, "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(4, "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, NULL)) {
199                 ast_verb(4, "AutoMonitor feature was tried by '%s' but monitor failed to start.\n",
200                         ast_channel_name(bridge_channel->chan));
201                 return;
202         }
203
204         ast_monitor_setjoinfiles(peer_chan, 1);
205
206         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
207                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
208                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
209         }
210
211         if (!ast_strlen_zero(start_message)) {
212                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
213                 ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
214         }
215
216         pbx_builtin_setvar_helper(bridge_channel->chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
217         pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
218 }
219
220 static int feature_automonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
221 {
222         const char *start_message;
223         const char *stop_message;
224         struct ast_bridge_features_automonitor *options = hook_pvt;
225         enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
226         int is_monitoring;
227
228         RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
229         RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
230
231         ast_channel_lock(bridge_channel->chan);
232         features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
233         ast_channel_unlock(bridge_channel->chan);
234         ast_bridge_channel_lock_bridge(bridge_channel);
235         peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
236         ast_bridge_unlock(bridge_channel->bridge);
237
238         if (!peer_chan) {
239                 ast_verb(4, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n",
240                         ast_channel_name(bridge_channel->chan));
241                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
242                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
243                 }
244                 return 0;
245         }
246
247         ast_channel_lock(bridge_channel->chan);
248         start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
249                 "TOUCH_MONITOR_MESSAGE_START");
250         start_message = ast_strdupa(S_OR(start_message, ""));
251         stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
252                 "TOUCH_MONITOR_MESSAGE_STOP");
253         stop_message = ast_strdupa(S_OR(stop_message, ""));
254         ast_channel_unlock(bridge_channel->chan);
255
256         is_monitoring = ast_channel_monitor(peer_chan) != NULL;
257         switch (start_stop) {
258         case AUTO_MONITOR_TOGGLE:
259                 if (is_monitoring) {
260                         stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
261                 } else {
262                         start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
263                 }
264                 return 0;
265         case AUTO_MONITOR_START:
266                 if (!is_monitoring) {
267                         start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
268                         return 0;
269                 }
270                 ast_verb(4, "AutoMonitor already recording call.\n");
271                 break;
272         case AUTO_MONITOR_STOP:
273                 if (is_monitoring) {
274                         stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
275                         return 0;
276                 }
277                 ast_verb(4, "AutoMonitor already stopped on call.\n");
278                 break;
279         }
280
281         /*
282          * Fake start/stop to invoker so will think it did something but
283          * was already in that mode.
284          */
285         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
286                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
287         }
288         if (is_monitoring) {
289                 if (!ast_strlen_zero(start_message)) {
290                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
291                 }
292         } else {
293                 if (!ast_strlen_zero(stop_message)) {
294                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
295                 }
296         }
297         return 0;
298 }
299
300 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)
301 {
302         ast_verb(4, "AutoMixMonitor used to stop recording call.\n");
303
304         if (ast_stop_mixmonitor(peer_chan, NULL)) {
305                 ast_verb(4, "Failed to stop AutoMixMonitor for %s.\n", ast_channel_name(bridge_channel->chan));
306                 if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
307                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
308                 }
309                 return;
310         }
311
312         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
313                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
314                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
315         }
316
317         if (!ast_strlen_zero(stop_message)) {
318                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
319                 ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
320         }
321 }
322
323 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)
324 {
325         char *touch_filename;
326         size_t len;
327         int x;
328         enum set_touch_variables_res set_touch_res;
329
330         RAII_VAR(char *, touch_format, NULL, ast_free);
331         RAII_VAR(char *, touch_monitor, NULL, ast_free);
332         RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
333
334         set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format,
335                 &touch_monitor, &touch_monitor_prefix);
336         switch (set_touch_res) {
337         case SET_TOUCH_SUCCESS:
338                 break;
339         case SET_TOUCH_UNSET:
340                 set_touch_res = set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor,
341                         &touch_monitor_prefix);
342                 if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
343                         return;
344                 }
345                 break;
346         case SET_TOUCH_ALLOC_FAILURE:
347                 return;
348         }
349
350         if (!ast_strlen_zero(touch_monitor)) {
351                 len = strlen(touch_monitor) + 50;
352                 touch_filename = ast_alloca(len);
353                 snprintf(touch_filename, len, "%s-%ld-%s.%s",
354                         S_OR(touch_monitor_prefix, "auto"),
355                         (long) time(NULL),
356                         touch_monitor,
357                         S_OR(touch_format, "wav"));
358         } else {
359                 char *caller_chan_id;
360                 char *peer_chan_id;
361
362                 caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
363                         ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
364                 peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
365                         ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
366                 len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
367                 touch_filename = ast_alloca(len);
368                 snprintf(touch_filename, len, "%s-%ld-%s-%s.%s",
369                         S_OR(touch_monitor_prefix, "auto"),
370                         (long) time(NULL),
371                         caller_chan_id,
372                         peer_chan_id,
373                         S_OR(touch_format, "wav"));
374         }
375
376         for (x = 0; x < strlen(touch_filename); x++) {
377                 if (touch_filename[x] == '/') {
378                         touch_filename[x] = '-';
379                 }
380         }
381
382         ast_verb(4, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);
383
384         if (ast_start_mixmonitor(peer_chan, touch_filename, "b")) {
385                 ast_verb(4, "AutoMixMonitor feature was tried by '%s' but MixMonitor failed to start.\n",
386                         ast_channel_name(bridge_channel->chan));
387
388                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
389                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
390                 }
391                 return;
392         }
393
394         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
395                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
396                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
397         }
398
399         if (!ast_strlen_zero(start_message)) {
400                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
401                 ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
402         }
403
404         pbx_builtin_setvar_helper(bridge_channel->chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
405         pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
406 }
407
408 static int feature_automixmonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
409 {
410         static const char *mixmonitor_spy_type = "MixMonitor";
411         const char *stop_message;
412         const char *start_message;
413         struct ast_bridge_features_automixmonitor *options = hook_pvt;
414         enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
415         int is_monitoring;
416
417         RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
418         RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
419
420         ast_channel_lock(bridge_channel->chan);
421         features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
422         ast_channel_unlock(bridge_channel->chan);
423         ast_bridge_channel_lock_bridge(bridge_channel);
424         peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
425         ast_bridge_unlock(bridge_channel->bridge);
426
427         if (!peer_chan) {
428                 ast_verb(4, "Cannot start AutoMixMonitor for %s - cannot determine peer in bridge.\n",
429                         ast_channel_name(bridge_channel->chan));
430                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
431                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
432                 }
433                 return 0;
434         }
435
436         ast_channel_lock(bridge_channel->chan);
437         start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
438                 "TOUCH_MIXMONITOR_MESSAGE_START");
439         start_message = ast_strdupa(S_OR(start_message, ""));
440         stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
441                 "TOUCH_MIXMONITOR_MESSAGE_STOP");
442         stop_message = ast_strdupa(S_OR(stop_message, ""));
443         ast_channel_unlock(bridge_channel->chan);
444
445         is_monitoring =
446                 0 < ast_channel_audiohook_count_by_source(peer_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
447         switch (start_stop) {
448         case AUTO_MONITOR_TOGGLE:
449                 if (is_monitoring) {
450                         stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
451                 } else {
452                         start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
453                 }
454                 return 0;
455         case AUTO_MONITOR_START:
456                 if (!is_monitoring) {
457                         start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
458                         return 0;
459                 }
460                 ast_verb(4, "AutoMixMonitor already recording call.\n");
461                 break;
462         case AUTO_MONITOR_STOP:
463                 if (is_monitoring) {
464                         stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
465                         return 0;
466                 }
467                 ast_verb(4, "AutoMixMonitor already stopped on call.\n");
468                 break;
469         }
470
471         /*
472          * Fake start/stop to invoker so will think it did something but
473          * was already in that mode.
474          */
475         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
476                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
477         }
478         if (is_monitoring) {
479                 if (!ast_strlen_zero(start_message)) {
480                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
481                 }
482         } else {
483                 if (!ast_strlen_zero(stop_message)) {
484                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
485                 }
486         }
487         return 0;
488 }
489
490 /*! \brief Internal built in feature for hangup */
491 static int feature_hangup(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
492 {
493         /*
494          * This is very simple, we simply change the state on the
495          * bridge_channel to force the channel out of the bridge and the
496          * core takes care of the rest.
497          */
498         ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
499                 AST_CAUSE_NORMAL_CLEARING);
500         return 0;
501 }
502
503 static int unload_module(void)
504 {
505         ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_HANGUP);
506         ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_AUTOMON);
507         ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_AUTOMIXMON);
508
509         return 0;
510 }
511
512 static int load_module(void)
513 {
514         ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
515         ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMON, feature_automonitor, NULL);
516         ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMIXMON, feature_automixmonitor, NULL);
517
518         /* This module cannot be unloaded until shutdown */
519         ast_module_shutdown_ref(ast_module_info->self);
520
521         return AST_MODULE_LOAD_SUCCESS;
522 }
523
524 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Built in bridging features",
525         .support_level = AST_MODULE_SUPPORT_CORE,
526         .load = load_module,
527         .unload = unload_module,
528         .optional_modules = "res_monitor",
529 );