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