dcc029701c33cc2647e539e215854f27bab46115
[asterisk/asterisk.git] / res / stasis / control.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@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 Stasis application control support.
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include "asterisk/stasis_channels.h"
31
32 #include "command.h"
33 #include "control.h"
34 #include "asterisk/dial.h"
35 #include "asterisk/bridge.h"
36 #include "asterisk/bridge_basic.h"
37 #include "asterisk/frame.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/musiconhold.h"
40
41 struct stasis_app_control {
42         /*! Queue of commands to dispatch on the channel */
43         struct ao2_container *command_queue;
44         /*!
45          * When set, /c app_stasis should exit and continue in the dialplan.
46          */
47         int is_done:1;
48         /*!
49          * The associated channel.
50          * Be very careful with the threading associated w/ manipulating
51          * the channel.
52          */
53         struct ast_channel *channel;
54 };
55
56 struct stasis_app_control *control_create(struct ast_channel *channel)
57 {
58         struct stasis_app_control *control;
59
60         control = ao2_alloc(sizeof(*control), NULL);
61         if (!control) {
62                 return NULL;
63         }
64
65         control->command_queue = ao2_container_alloc_list(
66                 AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
67
68         if (!control->command_queue) {
69                 ao2_cleanup(control);
70                 return NULL;
71         }
72
73         control->channel = channel;
74
75         return control;
76 }
77
78 static struct stasis_app_command *exec_command(
79         struct stasis_app_control *control, stasis_app_command_cb command_fn,
80         void *data)
81 {
82         RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
83
84         command = command_create(command_fn, data);
85
86         if (!command) {
87                 return NULL;
88         }
89
90         /* command_queue is a thread safe list; no lock needed */
91         ao2_link(control->command_queue, command);
92
93         ao2_ref(command, +1);
94         return command;
95 }
96
97 struct stasis_app_control_dial_data {
98         char endpoint[AST_CHANNEL_NAME];
99         int timeout;
100 };
101
102 static void *app_control_dial(struct stasis_app_control *control,
103         struct ast_channel *chan, void *data)
104 {
105         RAII_VAR(struct ast_dial *, dial, ast_dial_create(), ast_dial_destroy);
106         RAII_VAR(struct stasis_app_control_dial_data *, dial_data, data, ast_free);
107         enum ast_dial_result res;
108         char *tech, *resource;
109
110         struct ast_channel *new_chan;
111         struct ast_bridge *bridge;
112
113         tech = dial_data->endpoint;
114         if (!(resource = strchr(tech, '/'))) {
115                 return NULL;
116         }
117         *resource++ = '\0';
118
119         if (!dial) {
120                 ast_log(LOG_ERROR, "Failed to create dialing structure.\n");
121                 return NULL;
122         }
123
124         if (ast_dial_append(dial, tech, resource) < 0) {
125                 ast_log(LOG_ERROR, "Failed to add %s/%s to dialing structure.\n", tech, resource);
126                 return NULL;
127         }
128
129         ast_dial_set_global_timeout(dial, dial_data->timeout);
130
131         res = ast_dial_run(dial, NULL, 0);
132
133         if (res != AST_DIAL_RESULT_ANSWERED || !(new_chan = ast_dial_answered_steal(dial))) {
134                 return NULL;
135         }
136
137         if (!(bridge = ast_bridge_basic_new())) {
138                 ast_log(LOG_ERROR, "Failed to create basic bridge.\n");
139                 return NULL;
140         }
141
142         ast_bridge_impart(bridge, new_chan, NULL, NULL, 1);
143         stasis_app_control_add_channel_to_bridge(control, bridge);
144
145         return NULL;
146 }
147
148 int stasis_app_control_dial(struct stasis_app_control *control, const char *endpoint, int timeout)
149 {
150         struct stasis_app_control_dial_data *dial_data;
151
152         if (!(dial_data = ast_calloc(1, sizeof(*dial_data)))) {
153                 return -1;
154         }
155
156         ast_copy_string(dial_data->endpoint, endpoint, sizeof(dial_data->endpoint));
157
158         if (timeout > 0) {
159                 dial_data->timeout = timeout * 1000;
160         } else if (timeout == -1) {
161                 dial_data->timeout = -1;
162         } else {
163                 dial_data->timeout = 30000;
164         }
165
166         stasis_app_send_command_async(control, app_control_dial, dial_data);
167
168         return 0;
169 }
170
171 int stasis_app_control_add_role(struct stasis_app_control *control, const char *role)
172 {
173         return ast_channel_add_bridge_role(control->channel, role);
174 }
175
176 void stasis_app_control_clear_roles(struct stasis_app_control *control)
177 {
178         ast_channel_clear_bridge_roles(control->channel);
179 }
180
181 int control_is_done(struct stasis_app_control *control)
182 {
183         /* Called from stasis_app_exec thread; no lock needed */
184         return control->is_done;
185 }
186
187 struct stasis_app_control_continue_data {
188         char context[AST_MAX_CONTEXT];
189         char extension[AST_MAX_EXTENSION];
190         int priority;
191 };
192
193 static void *app_control_continue(struct stasis_app_control *control,
194         struct ast_channel *chan, void *data)
195 {
196         RAII_VAR(struct stasis_app_control_continue_data *, continue_data, data, ast_free);
197
198         /* Called from stasis_app_exec thread; no lock needed */
199         ast_explicit_goto(control->channel, continue_data->context, continue_data->extension, continue_data->priority);
200
201         control->is_done = 1;
202
203         return NULL;
204 }
205
206 int stasis_app_control_continue(struct stasis_app_control *control, const char *context, const char *extension, int priority)
207 {
208         struct stasis_app_control_continue_data *continue_data;
209
210         if (!(continue_data = ast_calloc(1, sizeof(*continue_data)))) {
211                 return -1;
212         }
213         ast_copy_string(continue_data->context, S_OR(context, ""), sizeof(continue_data->context));
214         ast_copy_string(continue_data->extension, S_OR(extension, ""), sizeof(continue_data->extension));
215         if (priority > 0) {
216                 continue_data->priority = priority;
217         } else {
218                 continue_data->priority = -1;
219         }
220
221         stasis_app_send_command_async(control, app_control_continue, continue_data);
222
223         return 0;
224 }
225
226 struct stasis_app_control_mute_data {
227         enum ast_frame_type frametype;
228         unsigned int direction;
229 };
230
231 static void *app_control_mute(struct stasis_app_control *control,
232         struct ast_channel *chan, void *data)
233 {
234         RAII_VAR(struct stasis_app_control_mute_data *, mute_data, data, ast_free);
235         SCOPED_CHANNELLOCK(lockvar, chan);
236
237         ast_channel_suppress(control->channel, mute_data->direction, mute_data->frametype);
238
239         return NULL;
240 }
241
242 int stasis_app_control_mute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
243 {
244         struct stasis_app_control_mute_data *mute_data;
245
246         if (!(mute_data = ast_calloc(1, sizeof(*mute_data)))) {
247                 return -1;
248         }
249
250         mute_data->direction = direction;
251         mute_data->frametype = frametype;
252
253         stasis_app_send_command_async(control, app_control_mute, mute_data);
254
255         return 0;
256 }
257
258 static void *app_control_unmute(struct stasis_app_control *control,
259         struct ast_channel *chan, void *data)
260 {
261         RAII_VAR(struct stasis_app_control_mute_data *, mute_data, data, ast_free);
262         SCOPED_CHANNELLOCK(lockvar, chan);
263
264         ast_channel_unsuppress(control->channel, mute_data->direction, mute_data->frametype);
265
266         return NULL;
267 }
268
269 int stasis_app_control_unmute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
270 {
271         struct stasis_app_control_mute_data *mute_data;
272
273         if (!(mute_data = ast_calloc(1, sizeof(*mute_data)))) {
274                 return -1;
275         }
276
277         mute_data->direction = direction;
278         mute_data->frametype = frametype;
279
280         stasis_app_send_command_async(control, app_control_unmute, mute_data);
281
282         return 0;
283 }
284
285 char *stasis_app_control_get_channel_var(struct stasis_app_control *control, const char *variable)
286 {
287         RAII_VAR(struct ast_str *, tmp, ast_str_create(32), ast_free);
288         SCOPED_CHANNELLOCK(lockvar, control->channel);
289
290         if (!tmp) {
291                 return NULL;
292         }
293
294         if (variable[strlen(variable) - 1] == ')') {
295                 if (ast_func_read2(control->channel, variable, &tmp, 0)) {
296                         return NULL;
297                 }
298         } else {
299                 if (!ast_str_retrieve_variable(&tmp, 0, control->channel, NULL, variable)) {
300                         return NULL;
301                 }
302         }
303
304         return ast_strdup(ast_str_buffer(tmp));
305 }
306
307 int stasis_app_control_set_channel_var(struct stasis_app_control *control, const char *variable, const char *value)
308 {
309         return pbx_builtin_setvar_helper(control->channel, variable, value);
310 }
311
312 static void *app_control_hold(struct stasis_app_control *control,
313         struct ast_channel *chan, void *data)
314 {
315         ast_indicate(control->channel, AST_CONTROL_HOLD);
316
317         return NULL;
318 }
319
320 void stasis_app_control_hold(struct stasis_app_control *control)
321 {
322         stasis_app_send_command_async(control, app_control_hold, NULL);
323 }
324
325 static void *app_control_unhold(struct stasis_app_control *control,
326         struct ast_channel *chan, void *data)
327 {
328         ast_indicate(control->channel, AST_CONTROL_UNHOLD);
329
330         return NULL;
331 }
332
333 void stasis_app_control_unhold(struct stasis_app_control *control)
334 {
335         stasis_app_send_command_async(control, app_control_unhold, NULL);
336 }
337
338 static void *app_control_moh_start(struct stasis_app_control *control,
339         struct ast_channel *chan, void *data)
340 {
341         char *moh_class = data;
342
343         ast_moh_start(chan, moh_class, NULL);
344
345         ast_free(moh_class);
346         return NULL;
347 }
348
349 void stasis_app_control_moh_start(struct stasis_app_control *control, const char *moh_class)
350 {
351         char *data = NULL;
352
353         if (!ast_strlen_zero(moh_class)) {
354                 data = ast_strdup(moh_class);
355         }
356
357         stasis_app_send_command_async(control, app_control_moh_start, data);
358 }
359
360 static void *app_control_moh_stop(struct stasis_app_control *control,
361         struct ast_channel *chan, void *data)
362 {
363         ast_moh_stop(chan);
364         return NULL;
365 }
366
367 void stasis_app_control_moh_stop(struct stasis_app_control *control)
368 {
369         stasis_app_send_command_async(control, app_control_moh_stop, NULL);
370 }
371
372 struct ast_channel_snapshot *stasis_app_control_get_snapshot(
373         const struct stasis_app_control *control)
374 {
375         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
376         struct ast_channel_snapshot *snapshot;
377
378         msg = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(),
379                 stasis_app_control_get_channel_id(control));
380         if (!msg) {
381                 return NULL;
382         }
383
384         snapshot = stasis_message_data(msg);
385         ast_assert(snapshot != NULL);
386
387         ao2_ref(snapshot, +1);
388         return snapshot;
389 }
390
391 void *stasis_app_send_command(struct stasis_app_control *control,
392         stasis_app_command_cb command_fn, void *data)
393 {
394         RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
395
396         if (control == NULL) {
397                 return NULL;
398         }
399
400         command = exec_command(control, command_fn, data);
401         if (!command) {
402                 return NULL;
403         }
404
405         return command_join(command);
406 }
407
408 int stasis_app_send_command_async(struct stasis_app_control *control,
409         stasis_app_command_cb command_fn, void *data)
410 {
411         RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
412
413         if (control == NULL) {
414                 return -1;
415         }
416
417         command = exec_command(control, command_fn, data);
418         if (!command) {
419                 return -1;
420         }
421
422         return 0;
423 }
424
425 const char *stasis_app_control_get_channel_id(
426         const struct stasis_app_control *control)
427 {
428         return ast_channel_uniqueid(control->channel);
429 }
430
431 void stasis_app_control_publish(
432         struct stasis_app_control *control, struct stasis_message *message)
433 {
434         if (!control || !control->channel || !message) {
435                 return;
436         }
437         stasis_publish(ast_channel_topic(control->channel), message);
438 }
439
440 int stasis_app_control_queue_control(struct stasis_app_control *control,
441         enum ast_control_frame_type frame_type)
442 {
443         return ast_queue_control(control->channel, frame_type);
444 }
445
446 int control_dispatch_all(struct stasis_app_control *control,
447         struct ast_channel *chan)
448 {
449         int count = 0;
450         struct ao2_iterator i;
451         void *obj;
452
453         ast_assert(control->channel == chan);
454
455         i = ao2_iterator_init(control->command_queue, AO2_ITERATOR_UNLINK);
456
457         while ((obj = ao2_iterator_next(&i))) {
458                 RAII_VAR(struct stasis_app_command *, command, obj, ao2_cleanup);
459                 command_invoke(command, control, chan);
460                 ++count;
461         }
462
463         ao2_iterator_destroy(&i);
464         return count;
465 }
466
467 /* Must be defined here since it must operate on the channel outside of the queue */
468 int stasis_app_control_remove_channel_from_bridge(
469         struct stasis_app_control *control, struct ast_bridge *bridge)
470 {
471         return ast_bridge_remove(bridge, control->channel);
472 }