ari: Add silence generator controls
[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_after.h"
37 #include "asterisk/bridge_basic.h"
38 #include "asterisk/frame.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/musiconhold.h"
41 #include "asterisk/app.h"
42
43 struct stasis_app_control {
44         ast_cond_t wait_cond;
45         /*! Queue of commands to dispatch on the channel */
46         struct ao2_container *command_queue;
47         /*!
48          * The associated channel.
49          * Be very careful with the threading associated w/ manipulating
50          * the channel.
51          */
52         struct ast_channel *channel;
53         /*!
54          * When a channel is in a bridge, the bridge that it is in.
55          */
56         struct ast_bridge *bridge;
57         /*!
58          * Holding place for channel's PBX while imparted to a bridge.
59          */
60         struct ast_pbx *pbx;
61         /*!
62          * Silence generator, when silence is being generated.
63          */
64         struct ast_silence_generator *silgen;
65         /*!
66          * When set, /c app_stasis should exit and continue in the dialplan.
67          */
68         int is_done:1;
69 };
70
71 static void control_dtor(void *obj)
72 {
73         struct stasis_app_control *control = obj;
74
75         /* We may have a lingering silence generator; free it */
76         ast_channel_stop_silence_generator(control->channel, control->silgen);
77         control->silgen = NULL;
78
79         ao2_cleanup(control->command_queue);
80         ast_cond_destroy(&control->wait_cond);
81 }
82
83 struct stasis_app_control *control_create(struct ast_channel *channel)
84 {
85         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
86         int res;
87
88         control = ao2_alloc(sizeof(*control), control_dtor);
89         if (!control) {
90                 return NULL;
91         }
92
93         res = ast_cond_init(&control->wait_cond, NULL);
94         if (res != 0) {
95                 ast_log(LOG_ERROR, "Error initializing ast_cond_t: %s\n",
96                         strerror(errno));
97                 return NULL;
98         }
99
100         control->command_queue = ao2_container_alloc_list(
101                 AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
102
103         if (!control->command_queue) {
104                 return NULL;
105         }
106
107         control->channel = channel;
108
109         ao2_ref(control, +1);
110         return control;
111 }
112
113 static void *noop_cb(struct stasis_app_control *control,
114         struct ast_channel *chan, void *data)
115 {
116         return NULL;
117 }
118
119
120 static struct stasis_app_command *exec_command(
121         struct stasis_app_control *control, stasis_app_command_cb command_fn,
122         void *data)
123 {
124         RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
125
126         command_fn = command_fn ? : noop_cb;
127
128         command = command_create(command_fn, data);
129         if (!command) {
130                 return NULL;
131         }
132
133         ao2_lock(control->command_queue);
134         ao2_link_flags(control->command_queue, command, OBJ_NOLOCK);
135         ast_cond_signal(&control->wait_cond);
136         ao2_unlock(control->command_queue);
137
138         ao2_ref(command, +1);
139         return command;
140 }
141
142 struct stasis_app_control_dial_data {
143         char endpoint[AST_CHANNEL_NAME];
144         int timeout;
145 };
146
147 static void *app_control_add_channel_to_bridge(
148         struct stasis_app_control *control,
149         struct ast_channel *chan, void *data);
150
151 static void *app_control_dial(struct stasis_app_control *control,
152         struct ast_channel *chan, void *data)
153 {
154         RAII_VAR(struct ast_dial *, dial, ast_dial_create(), ast_dial_destroy);
155         RAII_VAR(struct stasis_app_control_dial_data *, dial_data, data, ast_free);
156         enum ast_dial_result res;
157         char *tech, *resource;
158         struct ast_channel *new_chan;
159         RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
160
161         tech = dial_data->endpoint;
162         if (!(resource = strchr(tech, '/'))) {
163                 return NULL;
164         }
165         *resource++ = '\0';
166
167         if (!dial) {
168                 ast_log(LOG_ERROR, "Failed to create dialing structure.\n");
169                 return NULL;
170         }
171
172         if (ast_dial_append(dial, tech, resource) < 0) {
173                 ast_log(LOG_ERROR, "Failed to add %s/%s to dialing structure.\n", tech, resource);
174                 return NULL;
175         }
176
177         ast_dial_set_global_timeout(dial, dial_data->timeout);
178
179         res = ast_dial_run(dial, NULL, 0);
180         if (res != AST_DIAL_RESULT_ANSWERED || !(new_chan = ast_dial_answered_steal(dial))) {
181                 return NULL;
182         }
183
184         if (!(bridge = ast_bridge_basic_new())) {
185                 ast_log(LOG_ERROR, "Failed to create basic bridge.\n");
186                 return NULL;
187         }
188
189         if (ast_bridge_impart(bridge, new_chan, NULL, NULL,
190                 AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
191                 ast_hangup(new_chan);
192         } else {
193                 app_control_add_channel_to_bridge(control, chan, bridge);
194         }
195
196         return NULL;
197 }
198
199 int stasis_app_control_dial(struct stasis_app_control *control, const char *endpoint, const char *exten, const char *context,
200                             int timeout)
201 {
202         struct stasis_app_control_dial_data *dial_data;
203
204         if (!(dial_data = ast_calloc(1, sizeof(*dial_data)))) {
205                 return -1;
206         }
207
208         if (!ast_strlen_zero(endpoint)) {
209                 ast_copy_string(dial_data->endpoint, endpoint, sizeof(dial_data->endpoint));
210         } else if (!ast_strlen_zero(exten) && !ast_strlen_zero(context)) {
211                 snprintf(dial_data->endpoint, sizeof(dial_data->endpoint), "Local/%s@%s", exten, context);
212         } else {
213                 return -1;
214         }
215
216         if (timeout > 0) {
217                 dial_data->timeout = timeout * 1000;
218         } else if (timeout == -1) {
219                 dial_data->timeout = -1;
220         } else {
221                 dial_data->timeout = 30000;
222         }
223
224         stasis_app_send_command_async(control, app_control_dial, dial_data);
225
226         return 0;
227 }
228
229 int stasis_app_control_add_role(struct stasis_app_control *control, const char *role)
230 {
231         return ast_channel_add_bridge_role(control->channel, role);
232 }
233
234 void stasis_app_control_clear_roles(struct stasis_app_control *control)
235 {
236         ast_channel_clear_bridge_roles(control->channel);
237 }
238
239 int control_is_done(struct stasis_app_control *control)
240 {
241         /* Called from stasis_app_exec thread; no lock needed */
242         return control->is_done;
243 }
244
245 struct stasis_app_control_continue_data {
246         char context[AST_MAX_CONTEXT];
247         char extension[AST_MAX_EXTENSION];
248         int priority;
249 };
250
251 static void *app_control_continue(struct stasis_app_control *control,
252         struct ast_channel *chan, void *data)
253 {
254         RAII_VAR(struct stasis_app_control_continue_data *, continue_data, data, ast_free);
255
256         ast_assert(control->channel != NULL);
257
258         /* If we're in a Stasis bridge, depart it before going back to the
259          * dialplan */
260         if (stasis_app_get_bridge(control)) {
261                 ast_bridge_depart(control->channel);
262         }
263
264         /* Called from stasis_app_exec thread; no lock needed */
265         ast_explicit_goto(control->channel, continue_data->context, continue_data->extension, continue_data->priority);
266
267         control->is_done = 1;
268
269         return NULL;
270 }
271
272 int stasis_app_control_continue(struct stasis_app_control *control, const char *context, const char *extension, int priority)
273 {
274         struct stasis_app_control_continue_data *continue_data;
275
276         if (!(continue_data = ast_calloc(1, sizeof(*continue_data)))) {
277                 return -1;
278         }
279         ast_copy_string(continue_data->context, S_OR(context, ""), sizeof(continue_data->context));
280         ast_copy_string(continue_data->extension, S_OR(extension, ""), sizeof(continue_data->extension));
281         if (priority > 0) {
282                 continue_data->priority = priority;
283         } else {
284                 continue_data->priority = -1;
285         }
286
287         stasis_app_send_command_async(control, app_control_continue, continue_data);
288
289         return 0;
290 }
291
292 struct stasis_app_control_dtmf_data {
293         int before;
294         int between;
295         unsigned int duration;
296         int after;
297         char dtmf[];
298 };
299
300 static void *app_control_dtmf(struct stasis_app_control *control,
301         struct ast_channel *chan, void *data)
302 {
303         RAII_VAR(struct stasis_app_control_dtmf_data *, dtmf_data, data, ast_free);
304
305         if (dtmf_data->before) {
306                 ast_safe_sleep(chan, dtmf_data->before);
307         }
308
309         ast_dtmf_stream(chan, NULL, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);
310
311         if (dtmf_data->after) {
312                 ast_safe_sleep(chan, dtmf_data->after);
313         }
314
315         return NULL;
316 }
317
318 int stasis_app_control_dtmf(struct stasis_app_control *control, const char *dtmf, int before, int between, unsigned int duration, int after)
319 {
320         struct stasis_app_control_dtmf_data *dtmf_data;
321
322         if (!(dtmf_data = ast_calloc(1, sizeof(*dtmf_data) + strlen(dtmf) + 1))) {
323                 return -1;
324         }
325
326         dtmf_data->before = before;
327         dtmf_data->between = between;
328         dtmf_data->duration = duration;
329         dtmf_data->after = after;
330         strcpy(dtmf_data->dtmf, dtmf);
331
332         stasis_app_send_command_async(control, app_control_dtmf, dtmf_data);
333
334         return 0;
335 }
336
337 static void *app_control_ring(struct stasis_app_control *control,
338         struct ast_channel *chan, void *data)
339 {
340         ast_indicate(control->channel, AST_CONTROL_RINGING);
341
342         return NULL;
343 }
344
345 int stasis_app_control_ring(struct stasis_app_control *control)
346 {
347         stasis_app_send_command_async(control, app_control_ring, NULL);
348
349         return 0;
350 }
351
352 static void *app_control_ring_stop(struct stasis_app_control *control,
353         struct ast_channel *chan, void *data)
354 {
355         ast_indicate(control->channel, -1);
356
357         return NULL;
358 }
359
360 int stasis_app_control_ring_stop(struct stasis_app_control *control)
361 {
362         stasis_app_send_command_async(control, app_control_ring_stop, NULL);
363
364         return 0;
365 }
366
367 struct stasis_app_control_mute_data {
368         enum ast_frame_type frametype;
369         unsigned int direction;
370 };
371
372 static void *app_control_mute(struct stasis_app_control *control,
373         struct ast_channel *chan, void *data)
374 {
375         RAII_VAR(struct stasis_app_control_mute_data *, mute_data, data, ast_free);
376         SCOPED_CHANNELLOCK(lockvar, chan);
377
378         ast_channel_suppress(control->channel, mute_data->direction, mute_data->frametype);
379
380         return NULL;
381 }
382
383 int stasis_app_control_mute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
384 {
385         struct stasis_app_control_mute_data *mute_data;
386
387         if (!(mute_data = ast_calloc(1, sizeof(*mute_data)))) {
388                 return -1;
389         }
390
391         mute_data->direction = direction;
392         mute_data->frametype = frametype;
393
394         stasis_app_send_command_async(control, app_control_mute, mute_data);
395
396         return 0;
397 }
398
399 static void *app_control_unmute(struct stasis_app_control *control,
400         struct ast_channel *chan, void *data)
401 {
402         RAII_VAR(struct stasis_app_control_mute_data *, mute_data, data, ast_free);
403         SCOPED_CHANNELLOCK(lockvar, chan);
404
405         ast_channel_unsuppress(control->channel, mute_data->direction, mute_data->frametype);
406
407         return NULL;
408 }
409
410 int stasis_app_control_unmute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
411 {
412         struct stasis_app_control_mute_data *mute_data;
413
414         if (!(mute_data = ast_calloc(1, sizeof(*mute_data)))) {
415                 return -1;
416         }
417
418         mute_data->direction = direction;
419         mute_data->frametype = frametype;
420
421         stasis_app_send_command_async(control, app_control_unmute, mute_data);
422
423         return 0;
424 }
425
426 char *stasis_app_control_get_channel_var(struct stasis_app_control *control, const char *variable)
427 {
428         RAII_VAR(struct ast_str *, tmp, ast_str_create(32), ast_free);
429         SCOPED_CHANNELLOCK(lockvar, control->channel);
430
431         if (!tmp) {
432                 return NULL;
433         }
434
435         if (variable[strlen(variable) - 1] == ')') {
436                 if (ast_func_read2(control->channel, variable, &tmp, 0)) {
437                         return NULL;
438                 }
439         } else {
440                 if (!ast_str_retrieve_variable(&tmp, 0, control->channel, NULL, variable)) {
441                         return NULL;
442                 }
443         }
444
445         return ast_strdup(ast_str_buffer(tmp));
446 }
447
448 int stasis_app_control_set_channel_var(struct stasis_app_control *control, const char *variable, const char *value)
449 {
450         return pbx_builtin_setvar_helper(control->channel, variable, value);
451 }
452
453 static void *app_control_hold(struct stasis_app_control *control,
454         struct ast_channel *chan, void *data)
455 {
456         ast_indicate(control->channel, AST_CONTROL_HOLD);
457
458         return NULL;
459 }
460
461 void stasis_app_control_hold(struct stasis_app_control *control)
462 {
463         stasis_app_send_command_async(control, app_control_hold, NULL);
464 }
465
466 static void *app_control_unhold(struct stasis_app_control *control,
467         struct ast_channel *chan, void *data)
468 {
469         ast_indicate(control->channel, AST_CONTROL_UNHOLD);
470
471         return NULL;
472 }
473
474 void stasis_app_control_unhold(struct stasis_app_control *control)
475 {
476         stasis_app_send_command_async(control, app_control_unhold, NULL);
477 }
478
479 static void *app_control_moh_start(struct stasis_app_control *control,
480         struct ast_channel *chan, void *data)
481 {
482         char *moh_class = data;
483
484         ast_moh_start(chan, moh_class, NULL);
485
486         ast_free(moh_class);
487         return NULL;
488 }
489
490 void stasis_app_control_moh_start(struct stasis_app_control *control, const char *moh_class)
491 {
492         char *data = NULL;
493
494         if (!ast_strlen_zero(moh_class)) {
495                 data = ast_strdup(moh_class);
496         }
497
498         stasis_app_send_command_async(control, app_control_moh_start, data);
499 }
500
501 static void *app_control_moh_stop(struct stasis_app_control *control,
502         struct ast_channel *chan, void *data)
503 {
504         ast_moh_stop(chan);
505         return NULL;
506 }
507
508 void stasis_app_control_moh_stop(struct stasis_app_control *control)
509 {
510         stasis_app_send_command_async(control, app_control_moh_stop, NULL);
511 }
512
513 static void *app_control_silence_start(struct stasis_app_control *control,
514         struct ast_channel *chan, void *data)
515 {
516         if (control->silgen) {
517                 /* We have a silence generator, but it may have been implicitly
518                  * disabled by media actions (music on hold, playing media,
519                  * etc.) Just stop it and restart a new one.
520                  */
521                 ast_channel_stop_silence_generator(
522                         control->channel, control->silgen);
523         }
524
525         ast_debug(3, "%s: Starting silence generator\n",
526                 stasis_app_control_get_channel_id(control));
527         control->silgen = ast_channel_start_silence_generator(control->channel);
528
529         if (!control->silgen) {
530                 ast_log(LOG_WARNING,
531                         "%s: Failed to start silence generator.\n",
532                         stasis_app_control_get_channel_id(control));
533         }
534
535         return NULL;
536 }
537
538 void stasis_app_control_silence_start(struct stasis_app_control *control)
539 {
540         stasis_app_send_command_async(control, app_control_silence_start, NULL);
541 }
542
543 static void *app_control_silence_stop(struct stasis_app_control *control,
544         struct ast_channel *chan, void *data)
545 {
546         if (control->silgen) {
547                 ast_debug(3, "%s: Stopping silence generator\n",
548                         stasis_app_control_get_channel_id(control));
549                 ast_channel_stop_silence_generator(
550                         control->channel, control->silgen);
551                 control->silgen = NULL;
552         }
553
554         return NULL;
555 }
556
557 void stasis_app_control_silence_stop(struct stasis_app_control *control)
558 {
559         stasis_app_send_command_async(control, app_control_silence_stop, NULL);
560 }
561
562 struct ast_channel_snapshot *stasis_app_control_get_snapshot(
563         const struct stasis_app_control *control)
564 {
565         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
566         struct ast_channel_snapshot *snapshot;
567
568         msg = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(),
569                 stasis_app_control_get_channel_id(control));
570         if (!msg) {
571                 return NULL;
572         }
573
574         snapshot = stasis_message_data(msg);
575         ast_assert(snapshot != NULL);
576
577         ao2_ref(snapshot, +1);
578         return snapshot;
579 }
580
581 void *stasis_app_send_command(struct stasis_app_control *control,
582         stasis_app_command_cb command_fn, void *data)
583 {
584         RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
585
586         if (control == NULL) {
587                 return NULL;
588         }
589
590         command = exec_command(control, command_fn, data);
591         if (!command) {
592                 return NULL;
593         }
594
595         return command_join(command);
596 }
597
598 int stasis_app_send_command_async(struct stasis_app_control *control,
599         stasis_app_command_cb command_fn, void *data)
600 {
601         RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
602
603         if (control == NULL) {
604                 return -1;
605         }
606
607         command = exec_command(control, command_fn, data);
608         if (!command) {
609                 return -1;
610         }
611
612         return 0;
613 }
614
615 struct ast_bridge *stasis_app_get_bridge(struct stasis_app_control *control)
616 {
617         if (!control) {
618                 return NULL;
619         } else {
620                 SCOPED_AO2LOCK(lock, control);
621                 return control->bridge;
622         }
623 }
624
625 static void *bridge_channel_depart(struct stasis_app_control *control,
626         struct ast_channel *chan, void *data)
627 {
628         RAII_VAR(struct ast_bridge_channel *, bridge_channel, data, ao2_cleanup);
629
630         {
631                 SCOPED_CHANNELLOCK(lock, chan);
632
633                 if (bridge_channel != ast_channel_internal_bridge_channel(chan)) {
634                         ast_debug(3, "%s: Channel is no longer in departable state\n",
635                                 ast_channel_uniqueid(chan));
636                         return NULL;
637                 }
638         }
639
640         ast_debug(3, "%s: Channel departing bridge\n",
641                 ast_channel_uniqueid(chan));
642
643         ast_bridge_depart(chan);
644
645         return NULL;
646 }
647
648 static void bridge_after_cb(struct ast_channel *chan, void *data)
649 {
650         struct stasis_app_control *control = data;
651         SCOPED_AO2LOCK(lock, control);
652         struct ast_bridge_channel *bridge_channel;
653
654         ast_debug(3, "%s, %s: Channel leaving bridge\n",
655                 ast_channel_uniqueid(chan), control->bridge->uniqueid);
656
657         ast_assert(chan == control->channel);
658
659         /* Restore the channel's PBX */
660         ast_channel_pbx_set(control->channel, control->pbx);
661         control->pbx = NULL;
662
663         /* No longer in the bridge */
664         control->bridge = NULL;
665
666         /* Get the bridge channel so we don't depart from the wrong bridge */
667         ast_channel_lock(chan);
668         bridge_channel = ast_channel_get_bridge_channel(chan);
669         ast_channel_unlock(chan);
670
671         /* Depart this channel from the bridge using the command queue if possible */
672         if (stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel)) {
673                 ao2_cleanup(bridge_channel);
674         }
675 }
676
677 static void bridge_after_cb_failed(enum ast_bridge_after_cb_reason reason,
678         void *data)
679 {
680         struct stasis_app_control *control = data;
681
682         bridge_after_cb(control->channel, data);
683
684         ast_debug(3, "  reason: %s\n",
685                 ast_bridge_after_cb_reason_string(reason));
686 }
687
688 static int OK = 0;
689 static int FAIL = -1;
690
691 static void *app_control_add_channel_to_bridge(
692         struct stasis_app_control *control,
693         struct ast_channel *chan, void *data)
694 {
695         struct ast_bridge *bridge = data;
696         int res;
697
698         if (!control || !bridge) {
699                 return NULL;
700         }
701
702         ast_debug(3, "%s: Adding to bridge %s\n",
703                 stasis_app_control_get_channel_id(control),
704                 bridge->uniqueid);
705
706         ast_assert(chan != NULL);
707
708         /* Depart whatever Stasis bridge we're currently in. */
709         if (stasis_app_get_bridge(control)) {
710                 /* Note that it looks like there's a race condition here, since
711                  * we don't have control locked. But this happens from the
712                  * control callback thread, so there won't be any other
713                  * concurrent attempts to bridge.
714                  */
715                 ast_bridge_depart(chan);
716         }
717
718
719         res = ast_bridge_set_after_callback(chan, bridge_after_cb,
720                 bridge_after_cb_failed, control);
721         if (res != 0) {
722                 ast_log(LOG_ERROR, "Error setting after-bridge callback\n");
723                 return &FAIL;
724         }
725
726         {
727                 /* pbx and bridge are modified by the bridging impart thread.
728                  * It shouldn't happen concurrently, but we still need to lock
729                  * for the memory fence.
730                  */
731                 SCOPED_AO2LOCK(lock, control);
732
733                 /* Save off the channel's PBX */
734                 ast_assert(control->pbx == NULL);
735                 if (!control->pbx) {
736                         control->pbx = ast_channel_pbx(chan);
737                         ast_channel_pbx_set(chan, NULL);
738                 }
739
740                 res = ast_bridge_impart(bridge,
741                         chan,
742                         NULL, /* swap channel */
743                         NULL, /* features */
744                         AST_BRIDGE_IMPART_CHAN_DEPARTABLE);
745                 if (res != 0) {
746                         ast_log(LOG_ERROR, "Error adding channel to bridge\n");
747                         ast_channel_pbx_set(chan, control->pbx);
748                         control->pbx = NULL;
749                         return &FAIL;
750                 }
751
752                 ast_assert(stasis_app_get_bridge(control) == NULL);
753                 control->bridge = bridge;
754         }
755         return &OK;
756 }
757
758 int stasis_app_control_add_channel_to_bridge(
759         struct stasis_app_control *control, struct ast_bridge *bridge)
760 {
761         int *res;
762         ast_debug(3, "%s: Sending channel add_to_bridge command\n",
763                         stasis_app_control_get_channel_id(control));
764         res = stasis_app_send_command(control,
765                 app_control_add_channel_to_bridge, bridge);
766         return *res;
767 }
768
769 static void *app_control_remove_channel_from_bridge(
770         struct stasis_app_control *control,
771         struct ast_channel *chan, void *data)
772 {
773         struct ast_bridge *bridge = data;
774
775         if (!control) {
776                 return &FAIL;
777         }
778
779         /* We should only depart from our own bridge */
780         ast_debug(3, "%s: Departing bridge %s\n",
781                 stasis_app_control_get_channel_id(control),
782                 bridge->uniqueid);
783
784         if (bridge != stasis_app_get_bridge(control)) {
785                 ast_log(LOG_WARNING, "%s: Not in bridge %s; not removing\n",
786                         stasis_app_control_get_channel_id(control),
787                         bridge->uniqueid);
788                 return &FAIL;
789         }
790
791         ast_bridge_depart(chan);
792         return &OK;
793 }
794
795 int stasis_app_control_remove_channel_from_bridge(
796         struct stasis_app_control *control, struct ast_bridge *bridge)
797 {
798         int *res;
799         ast_debug(3, "%s: Sending channel remove_from_bridge command\n",
800                         stasis_app_control_get_channel_id(control));
801         res = stasis_app_send_command(control,
802                 app_control_remove_channel_from_bridge, bridge);
803         return *res;
804 }
805
806 const char *stasis_app_control_get_channel_id(
807         const struct stasis_app_control *control)
808 {
809         return ast_channel_uniqueid(control->channel);
810 }
811
812 void stasis_app_control_publish(
813         struct stasis_app_control *control, struct stasis_message *message)
814 {
815         if (!control || !control->channel || !message) {
816                 return;
817         }
818         stasis_publish(ast_channel_topic(control->channel), message);
819 }
820
821 int stasis_app_control_queue_control(struct stasis_app_control *control,
822         enum ast_control_frame_type frame_type)
823 {
824         return ast_queue_control(control->channel, frame_type);
825 }
826
827 int control_dispatch_all(struct stasis_app_control *control,
828         struct ast_channel *chan)
829 {
830         int count = 0;
831         struct ao2_iterator i;
832         void *obj;
833
834         ast_assert(control->channel == chan);
835
836         i = ao2_iterator_init(control->command_queue, AO2_ITERATOR_UNLINK);
837
838         while ((obj = ao2_iterator_next(&i))) {
839                 RAII_VAR(struct stasis_app_command *, command, obj, ao2_cleanup);
840                 command_invoke(command, control, chan);
841                 ++count;
842         }
843
844         ao2_iterator_destroy(&i);
845         return count;
846 }
847
848 void control_wait(struct stasis_app_control *control)
849 {
850         if (!control) {
851                 return;
852         }
853
854         ast_assert(control->command_queue != NULL);
855
856         ao2_lock(control->command_queue);
857         while (ao2_container_count(control->command_queue) == 0) {
858                 int res = ast_cond_wait(&control->wait_cond,
859                         ao2_object_get_lockaddr(control->command_queue));
860                 if (res < 0) {
861                         ast_log(LOG_ERROR, "Error waiting on command queue\n");
862                         break;
863                 }
864         }
865         ao2_unlock(control->command_queue);
866 }