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