Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
res_stasis.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2012 - 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 support.
22 *
23 * \author David M. Lee, II <dlee@digium.com>
24 *
25 * <code>res_stasis.so</code> brings together the various components of the
26 * Stasis application infrastructure.
27 *
28 * First, there's the Stasis application handler, stasis_app_exec(). This is
29 * called by <code>app_stasis.so</code> to give control of a channel to the
30 * Stasis application code from the dialplan.
31 *
32 * While a channel is in stasis_app_exec(), it has a \ref stasis_app_control
33 * object, which may be used to control the channel.
34 *
35 * To control the channel, commands may be sent to channel using
36 * stasis_app_send_command() and stasis_app_send_async_command().
37 *
38 * Alongside this, applications may be registered/unregistered using
39 * stasis_app_register()/stasis_app_unregister(). While a channel is in Stasis,
40 * events received on the channel's topic are converted to JSON and forwarded to
41 * the \ref stasis_app_cb. The application may also subscribe to the channel to
42 * continue to receive messages even after the channel has left Stasis, but it
43 * will not be able to control it.
44 *
45 * Given all the stuff that comes together in this module, it's been broken up
46 * into several pieces that are in <code>res/stasis/</code> and compiled into
47 * <code>res_stasis.so</code>.
48 */
49
50/*** MODULEINFO
51 <support_level>core</support_level>
52 ***/
53
54#include "asterisk.h"
55
56#include "asterisk/astobj2.h"
57#include "asterisk/callerid.h"
58#include "asterisk/module.h"
64#include "asterisk/strings.h"
65#include "stasis/app.h"
66#include "stasis/control.h"
67#include "stasis/messaging.h"
71#include "asterisk/causes.h"
75
76/*! Time to wait for a frame in the application */
77#define MAX_WAIT_MS 200
78
79/*!
80 * \brief Number of buckets for the Stasis application hash table. Remember to
81 * keep it a prime number!
82 */
83#define APPS_NUM_BUCKETS 127
84
85/*!
86 * \brief Number of buckets for the Stasis application hash table. Remember to
87 * keep it a prime number!
88 */
89#define CONTROLS_NUM_BUCKETS 127
90
91/*!
92 * \brief Number of buckets for the Stasis bridges hash table. Remember to
93 * keep it a prime number!
94 */
95#define BRIDGES_NUM_BUCKETS 127
96
97/*!
98 * \brief Stasis application container.
99 */
101
103
105
107
109
110/*!
111 * \internal \brief List of registered event sources.
112 */
114
116 const struct stasis_message_sanitizer *sanitize)
117{
119 struct ast_json *msg;
120
121 if (sanitize && sanitize->channel_snapshot &&
122 sanitize->channel_snapshot(payload->snapshot)) {
123 return NULL;
124 }
125
126 msg = ast_json_pack("{s: s, s: O, s: o}",
127 "type", "StasisEnd",
128 "timestamp", ast_json_object_get(payload->blob, "timestamp"),
129 "channel", ast_channel_snapshot_to_json(payload->snapshot, sanitize));
130 if (!msg) {
131 ast_log(LOG_ERROR, "Failed to pack JSON for StasisEnd message\n");
132 return NULL;
133 }
134
135 return msg;
136}
137
139 .to_json = stasis_end_to_json);
140
142 struct ast_channel_snapshot *channel; /*!< Channel that is entering Stasis() */
143 struct ast_channel_snapshot *replace_channel; /*!< Channel that is being replaced (optional) */
144 struct ast_json *blob; /*!< JSON blob containing timestamp and args */
145};
146
148 const struct stasis_message_sanitizer *sanitize)
149{
151 struct ast_json *msg;
152
153 if (sanitize && sanitize->channel_snapshot &&
154 sanitize->channel_snapshot(payload->channel)) {
155 return NULL;
156 }
157
158 msg = ast_json_pack("{s: s, s: O, s: O, s: o}",
159 "type", "StasisStart",
160 "timestamp", ast_json_object_get(payload->blob, "timestamp"),
161 "args", ast_json_object_get(payload->blob, "args"),
162 "channel", ast_channel_snapshot_to_json(payload->channel, NULL));
163 if (!msg) {
164 ast_log(LOG_ERROR, "Failed to pack JSON for StasisStart message\n");
165 return NULL;
166 }
167
168 if (payload->replace_channel) {
169 int res = ast_json_object_set(msg, "replace_channel",
171
172 if (res) {
173 ast_json_unref(msg);
174 ast_log(LOG_ERROR, "Failed to append JSON for StasisStart message\n");
175 return NULL;
176 }
177 }
178
179 return msg;
180}
181
183 .to_json = stasis_start_to_json);
184
185/*! AO2 hash function for \ref app */
186static int app_hash(const void *obj, const int flags)
187{
188 const struct stasis_app *app;
189 const char *key;
190
191 switch (flags & OBJ_SEARCH_MASK) {
192 case OBJ_SEARCH_KEY:
193 key = obj;
194 break;
196 app = obj;
197 key = stasis_app_name(app);
198 break;
199 default:
200 /* Hash can only work on something with a full key. */
201 ast_assert(0);
202 return 0;
203 }
204 return ast_str_hash(key);
205}
206
207/*! AO2 comparison function for \ref app */
208static int app_compare(void *obj, void *arg, int flags)
209{
210 const struct stasis_app *object_left = obj;
211 const struct stasis_app *object_right = arg;
212 const char *right_key = arg;
213 int cmp;
214
215 switch (flags & OBJ_SEARCH_MASK) {
217 right_key = stasis_app_name(object_right);
218 /* Fall through */
219 case OBJ_SEARCH_KEY:
220 cmp = strcmp(stasis_app_name(object_left), right_key);
221 break;
223 /*
224 * We could also use a partial key struct containing a length
225 * so strlen() does not get called for every comparison instead.
226 */
227 cmp = strncmp(stasis_app_name(object_left), right_key, strlen(right_key));
228 break;
229 default:
230 /*
231 * What arg points to is specific to this traversal callback
232 * and has no special meaning to astobj2.
233 */
234 cmp = 0;
235 break;
236 }
237 if (cmp) {
238 return 0;
239 }
240 /*
241 * At this point the traversal callback is identical to a sorted
242 * container.
243 */
244 return CMP_MATCH;
245}
246
247/*! AO2 hash function for \ref stasis_app_control */
248static int control_hash(const void *obj, const int flags)
249{
250 const struct stasis_app_control *control;
251 const char *key;
252
253 switch (flags & OBJ_SEARCH_MASK) {
254 case OBJ_SEARCH_KEY:
255 key = obj;
256 break;
258 control = obj;
260 break;
261 default:
262 /* Hash can only work on something with a full key. */
263 ast_assert(0);
264 return 0;
265 }
266 return ast_str_hash(key);
267}
268
269/*! AO2 comparison function for \ref stasis_app_control */
270static int control_compare(void *obj, void *arg, int flags)
271{
272 const struct stasis_app_control *object_left = obj;
273 const struct stasis_app_control *object_right = arg;
274 const char *right_key = arg;
275 int cmp;
276
277 switch (flags & OBJ_SEARCH_MASK) {
279 right_key = stasis_app_control_get_channel_id(object_right);
280 /* Fall through */
281 case OBJ_SEARCH_KEY:
282 cmp = strcmp(stasis_app_control_get_channel_id(object_left), right_key);
283 break;
285 /*
286 * We could also use a partial key struct containing a length
287 * so strlen() does not get called for every comparison instead.
288 */
289 cmp = strncmp(stasis_app_control_get_channel_id(object_left), right_key, strlen(right_key));
290 break;
291 default:
292 /*
293 * What arg points to is specific to this traversal callback
294 * and has no special meaning to astobj2.
295 */
296 cmp = 0;
297 break;
298 }
299 if (cmp) {
300 return 0;
301 }
302 /*
303 * At this point the traversal callback is identical to a sorted
304 * container.
305 */
306 return CMP_MATCH;
307}
308
309static int cleanup_cb(void *obj, void *arg, int flags)
310{
311 struct stasis_app *app = obj;
312
313 if (!app_is_finished(app)) {
314 return 0;
315 }
316
317 ast_verb(1, "Shutting down application '%s'\n", stasis_app_name(app));
319
320 return CMP_MATCH;
321
322}
323
324/*!
325 * \brief Clean up any old apps that we don't need any more.
326 */
327static void cleanup(void)
328{
331}
332
334{
335 return control_create(chan, NULL);
336}
337
339 const struct ast_channel *chan)
340{
341 if (chan == NULL) {
342 return NULL;
343 }
344
347}
348
350 const char *channel_id)
351{
352 return ao2_find(app_controls, channel_id, OBJ_SEARCH_KEY);
353}
354
355/*! AO2 hash function for bridges container */
356static int bridges_hash(const void *obj, const int flags)
357{
358 const struct ast_bridge *bridge;
359 const char *key;
360
361 switch (flags & OBJ_SEARCH_MASK) {
362 case OBJ_SEARCH_KEY:
363 key = obj;
364 break;
366 bridge = obj;
367 key = bridge->uniqueid;
368 break;
369 default:
370 /* Hash can only work on something with a full key. */
371 ast_assert(0);
372 return 0;
373 }
374 return ast_str_hash(key);
375}
376
377/*! AO2 comparison function for bridges container */
378static int bridges_compare(void *obj, void *arg, int flags)
379{
380 const struct ast_bridge *object_left = obj;
381 const struct ast_bridge *object_right = arg;
382 const char *right_key = arg;
383 int cmp;
384
385 switch (flags & OBJ_SEARCH_MASK) {
387 right_key = object_right->uniqueid;
388 /* Fall through */
389 case OBJ_SEARCH_KEY:
390 cmp = strcmp(object_left->uniqueid, right_key);
391 break;
393 /*
394 * We could also use a partial key struct containing a length
395 * so strlen() does not get called for every comparison instead.
396 */
397 cmp = strncmp(object_left->uniqueid, right_key, strlen(right_key));
398 break;
399 default:
400 /*
401 * What arg points to is specific to this traversal callback
402 * and has no special meaning to astobj2.
403 */
404 cmp = 0;
405 break;
406 }
407 if (cmp) {
408 return 0;
409 }
410 /*
411 * At this point the traversal callback is identical to a sorted
412 * container.
413 */
414 return CMP_MATCH;
415}
416
417/*! AO2 sort function for bridges container */
418static int bridges_sort (const void *left, const void *right, const int flags)
419{
420 const struct ast_bridge *object_left = left;
421 const struct ast_bridge *object_right = right;
422 const char *right_key = right;
423 int cmp;
424
425 switch (flags & OBJ_SEARCH_MASK) {
427 right_key = object_right->uniqueid;
428 /* Fall through */
429 case OBJ_SEARCH_KEY:
430 cmp = strcmp(object_left->uniqueid, right_key);
431 break;
433 cmp = strncmp(object_left->uniqueid, right_key, strlen(right_key));
434 break;
435 default:
436 ast_assert(0);
437 cmp = 0;
438 break;
439 }
440 return cmp;
441}
442
443/*!
444 * Used with app_bridges_moh and app_bridge_control, they provide links
445 * between bridges and channels used for ARI application purposes
446 */
451 );
452};
453
454/*! AO2 comparison function for bridges moh container */
455static int bridges_channel_compare(void *obj, void *arg, int flags)
456{
457 const struct stasis_app_bridge_channel_wrapper *object_left = obj;
458 const struct stasis_app_bridge_channel_wrapper *object_right = arg;
459 const char *right_key = arg;
460 int cmp;
461
462 switch (flags & OBJ_SEARCH_MASK) {
464 right_key = object_right->bridge_id;
465 case OBJ_SEARCH_KEY:
466 cmp = strcmp(object_left->bridge_id, right_key);
467 break;
469 cmp = strncmp(object_left->bridge_id, right_key, strlen(right_key));
470 break;
471 default:
472 cmp = 0;
473 break;
474 }
475 if (cmp) {
476 return 0;
477 }
478 return CMP_MATCH;
479}
480
482{
483 struct stasis_app_bridge_channel_wrapper *wrapper = obj;
485}
486
487/*! AO2 hash function for the bridges moh container */
488static int bridges_channel_hash_fn(const void *obj, const int flags)
489{
490 const struct stasis_app_bridge_channel_wrapper *wrapper;
491 const char *key;
492
493 switch (flags & OBJ_SEARCH_MASK) {
494 case OBJ_SEARCH_KEY:
495 key = obj;
496 break;
498 wrapper = obj;
499 key = wrapper->bridge_id;
500 break;
501 default:
502 /* Hash can only work on something with a full key. */
503 ast_assert(0);
504 return 0;
505 }
506 return ast_str_hash(key);
507}
508
509static int bridges_channel_sort_fn(const void *obj_left, const void *obj_right, const int flags)
510{
511 const struct stasis_app_bridge_channel_wrapper *left = obj_left;
512 const struct stasis_app_bridge_channel_wrapper *right = obj_right;
513 const char *right_key = obj_right;
514 int cmp;
515
516 switch (flags & OBJ_SEARCH_MASK) {
518 right_key = right->bridge_id;
519 /* Fall through */
520 case OBJ_SEARCH_KEY:
521 cmp = strcmp(left->bridge_id, right_key);
522 break;
524 cmp = strncmp(left->bridge_id, right_key, strlen(right_key));
525 break;
526 default:
527 /* Sort can only work on something with a full or partial key. */
528 ast_assert(0);
529 cmp = 0;
530 break;
531 }
532 return cmp;
533}
534
535/*! Request a bridge MOH channel */
537{
538 struct ast_channel *chan;
539 struct ast_format_cap *cap;
540
542 if (!cap) {
543 return NULL;
544 }
545
547
548 chan = ast_request("Announcer", cap, NULL, NULL, "ARI_MOH", NULL);
549 ao2_ref(cap, -1);
550
551 return chan;
552}
553
554/*! Provides the moh channel with a thread so it can actually play its music */
555static void *moh_channel_thread(void *data)
556{
557 struct stasis_app_bridge_channel_wrapper *moh_wrapper = data;
558 struct ast_channel *moh_channel = ast_channel_get_by_name(moh_wrapper->channel_id);
559 struct ast_frame *f;
560
561 if (!moh_channel) {
562 ao2_unlink(app_bridges_moh, moh_wrapper);
563 ao2_ref(moh_wrapper, -1);
564 return NULL;
565 }
566
567 /* Read and discard any frame coming from the stasis bridge. */
568 for (;;) {
569 if (ast_waitfor(moh_channel, -1) < 0) {
570 /* Error or hungup */
571 break;
572 }
573
574 f = ast_read(moh_channel);
575 if (!f) {
576 /* Hungup */
577 break;
578 }
579 ast_frfree(f);
580 }
581
582 ao2_unlink(app_bridges_moh, moh_wrapper);
583 ao2_ref(moh_wrapper, -1);
584
585 ast_moh_stop(moh_channel);
586 ast_hangup(moh_channel);
587
588 return NULL;
589}
590
591/*!
592 * \internal
593 * \brief Creates, pushes, and links a channel for playing music on hold to bridge
594 *
595 * \param bridge Which bridge this moh channel exists for
596 *
597 * \retval NULL if the channel could not be created, pushed, or linked
598 * \retval Reference to the channel on success
599 */
601{
602 struct stasis_app_bridge_channel_wrapper *new_wrapper;
603 struct ast_channel *chan;
604 pthread_t threadid;
605
607 if (!chan) {
608 return NULL;
609 }
610
612 ast_hangup(chan);
613 return NULL;
614 }
615
618 ast_hangup(chan);
619 return NULL;
620 }
621
622 new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
624 if (!new_wrapper) {
625 ast_hangup(chan);
626 return NULL;
627 }
628
630 || ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid)
631 || ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan))) {
632 ao2_ref(new_wrapper, -1);
633 ast_hangup(chan);
634 return NULL;
635 }
636
637 if (!ao2_link_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK)) {
638 ao2_ref(new_wrapper, -1);
639 ast_hangup(chan);
640 return NULL;
641 }
642
643 /* Pass the new_wrapper ref to moh_channel_thread() */
644 if (ast_pthread_create_detached(&threadid, NULL, moh_channel_thread, new_wrapper)) {
645 ast_log(LOG_ERROR, "Failed to create channel thread. Abandoning MOH channel creation.\n");
647 ao2_ref(new_wrapper, -1);
648 ast_hangup(chan);
649 return NULL;
650 }
651
652 return chan;
653}
654
656{
657 struct ast_channel *chan;
658 struct stasis_app_bridge_channel_wrapper *moh_wrapper;
659
661 moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_NOLOCK);
662 if (!moh_wrapper) {
663 chan = bridge_moh_create(bridge);
664 }
666
667 if (moh_wrapper) {
668 chan = ast_channel_get_by_name(moh_wrapper->channel_id);
669 ao2_ref(moh_wrapper, -1);
670 }
671
672 return chan;
673}
674
676{
677 struct stasis_app_bridge_channel_wrapper *moh_wrapper;
678 struct ast_channel *chan;
679
681 if (!moh_wrapper) {
682 return -1;
683 }
684
685 chan = ast_channel_get_by_name(moh_wrapper->channel_id);
686 ao2_ref(moh_wrapper, -1);
687 if (!chan) {
688 return -1;
689 }
690
691 ast_moh_stop(chan);
693 ao2_cleanup(chan);
694
695 return 0;
696}
697
698/*! Removes the bridge to playback channel link */
699static void remove_bridge_playback(char *bridge_id)
700{
701 struct stasis_app_bridge_channel_wrapper *wrapper;
702 struct stasis_app_control *control;
703
705
706 if (wrapper) {
708 if (control) {
709 ao2_unlink(app_controls, control);
710 ao2_ref(control, -1);
711 }
712 ao2_ref(wrapper, -1);
713 }
714 ast_free(bridge_id);
715}
716
718{
719 char *bridge_id = data;
720
721 remove_bridge_playback(bridge_id);
722}
723
724static void playback_after_bridge_cb(struct ast_channel *chan, void *data)
725{
726 char *bridge_id = data;
727
728 remove_bridge_playback(bridge_id);
729}
730
732 struct ast_channel *chan,
733 struct stasis_app_control *control)
734{
736 char *bridge_id = ast_strdup(bridge->uniqueid);
737
738 if (!bridge_id) {
739 return -1;
740 }
741
744 ast_free(bridge_id);
745 return -1;
746 }
747
748 new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
750 if (!new_wrapper) {
751 return -1;
752 }
753
754 if (ast_string_field_init(new_wrapper, 32)) {
755 return -1;
756 }
757
758 ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
759 ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
760
761 if (!ao2_link(app_bridges_playback, new_wrapper)) {
762 return -1;
763 }
764
765 ao2_link(app_controls, control);
766 return 0;
767}
768
770 struct stasis_app_control *control)
771{
772 struct stasis_app_bridge_channel_wrapper *wrapper;
773
775 if (wrapper) {
776 /* If wrapper is not found, then that means the after bridge callback has been
777 * called or is in progress. No need to unlink the control here since that has
778 * been done or is about to be done in the after bridge callback
779 */
780 ao2_unlink(app_controls, control);
781 ao2_ref(wrapper, -1);
782 }
783}
784
786{
787 struct stasis_app_bridge_channel_wrapper *playback_wrapper;
788 struct ast_channel *chan;
789
791 if (!playback_wrapper) {
792 return NULL;
793 }
794
795 chan = ast_channel_get_by_name(playback_wrapper->channel_id);
796 ao2_ref(playback_wrapper, -1);
797 return chan;
798}
799
801 const char *bridge_id)
802{
803 return ao2_find(app_bridges, bridge_id, OBJ_SEARCH_KEY);
804}
805
806
807/*!
808 * \brief In addition to running ao2_cleanup(), this function also removes the
809 * object from the app_controls container.
810 */
811static void control_unlink(struct stasis_app_control *control)
812{
813 if (!control) {
814 return;
815 }
816
817 ao2_unlink(app_controls, control);
818 ao2_cleanup(control);
819}
820
821static struct ast_bridge *bridge_create_common(const char *type, const char *name, const char *id, int invisible)
822{
823 struct ast_bridge *bridge;
824 char *requested_type, *requested_types = ast_strdupa(S_OR(type, "mixing"));
825 int capabilities = 0;
830 int send_sdp_label = 0;
831
832 ast_debug(1, "Creating bridge of type '%s' with name '%s' and id '%s'\n",
833 type, S_OR(name, "<unknown>"), S_OR(id, "<unknown>"));
834 if (invisible) {
836 }
837
838 if (!ast_strlen_zero(id)) {
839 bridge = stasis_app_bridge_find_by_id(id);
840 if (bridge) {
841 ast_log(LOG_WARNING, "Bridge with id '%s' already exists\n", id);
842 ao2_ref(bridge, -1);
843 return NULL;
844 }
845 }
846
847 while ((requested_type = strsep(&requested_types, ","))) {
848 requested_type = ast_strip(requested_type);
849
850 if (!strcmp(requested_type, "mixing")) {
851 capabilities |= STASIS_BRIDGE_MIXING_CAPABILITIES;
852 flags |= AST_BRIDGE_FLAG_SMART;
853 } else if (!strcmp(requested_type, "holding")) {
854 capabilities |= AST_BRIDGE_CAPABILITY_HOLDING;
855 } else if (!strcmp(requested_type, "dtmf_events") ||
856 !strcmp(requested_type, "proxy_media")) {
857 capabilities &= ~AST_BRIDGE_CAPABILITY_NATIVE;
858 } else if (!strcmp(requested_type, "video_sfu")) {
859 video_mode = AST_BRIDGE_VIDEO_MODE_SFU;
860 } else if (!strcmp(requested_type, "video_single")) {
862 } else if (!strcmp(requested_type, "sdp_label")) {
863 send_sdp_label = 1;
864 }
865 }
866
867 /* For an SFU video bridge we ensure it always remains in multimix for the best experience. */
868 if (video_mode == AST_BRIDGE_VIDEO_MODE_SFU) {
869 capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX;
870 flags &= ~AST_BRIDGE_FLAG_SMART;
871 }
872
873 if (!capabilities
874 /* Holding and mixing capabilities don't mix. */
875 || ((capabilities & AST_BRIDGE_CAPABILITY_HOLDING)
876 && (capabilities & (STASIS_BRIDGE_MIXING_CAPABILITIES)))) {
877 return NULL;
878 }
879
880 bridge = bridge_stasis_new(capabilities, flags, name, id, video_mode, send_sdp_label);
881 if (bridge) {
882 if (!ao2_link(app_bridges, bridge)) {
883 ast_bridge_destroy(bridge, 0);
884 bridge = NULL;
885 }
886 }
887
888 return bridge;
889}
890
891struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id)
892{
893 return bridge_create_common(type, name, id, 0);
894}
895
896struct ast_bridge *stasis_app_bridge_create_invisible(const char *type, const char *name, const char *id)
897{
898 return bridge_create_common(type, name, id, 1);
899}
900
901void stasis_app_bridge_destroy(const char *bridge_id)
902{
903 struct ast_bridge *bridge = stasis_app_bridge_find_by_id(bridge_id);
904 if (!bridge) {
905 return;
906 }
907 ast_debug(1, "Bridge " BRIDGE_PRINTF_SPEC ": destroying bridge\n",
908 BRIDGE_PRINTF_VARS(bridge));
909
910 ao2_unlink(app_bridges, bridge);
911 ast_debug(1, "Bridge " BRIDGE_PRINTF_SPEC ": unlinked from app_bridges. current refcount: %d\n",
912 BRIDGE_PRINTF_VARS(bridge), ao2_ref(bridge, 0));
913 ast_bridge_destroy(bridge, 0);
914}
915
918 char *app;
919};
920
921static void replace_channel_destroy(void *obj)
922{
923 struct replace_channel_store *replace = obj;
924
925 ao2_cleanup(replace->snapshot);
926 ast_free(replace->app);
928}
929
931 .type = "replace-channel-store",
932 .destroy = replace_channel_destroy,
933};
934
935static struct replace_channel_store *get_replace_channel_store(struct ast_channel *chan, int no_create)
936{
937 struct ast_datastore *datastore;
938 struct replace_channel_store *ret;
939
940 ast_channel_lock(chan);
942 if (!datastore && !no_create) {
944 if (datastore) {
945 ast_channel_datastore_add(chan, datastore);
946 }
947 }
948
949 if (!datastore) {
950 ast_channel_unlock(chan);
951 return NULL;
952 }
953
954 if (!datastore->data) {
955 datastore->data = ast_calloc(1, sizeof(struct replace_channel_store));
956 }
957
958 ret = datastore->data;
959 ast_channel_unlock(chan);
960
961 return ret;
962}
963
964int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot)
965{
967
968 if (!replace) {
969 return -1;
970 }
971
972 ao2_replace(replace->snapshot, replace_snapshot);
973 return 0;
974}
975
976int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app)
977{
979
980 if (!replace) {
981 return -1;
982 }
983
984 ast_free(replace->app);
985 replace->app = NULL;
986
987 if (replace_app) {
988 replace->app = ast_strdup(replace_app);
989 if (!replace->app) {
990 return -1;
991 }
992 }
993
994 return 0;
995}
996
998{
1000 struct ast_channel_snapshot *replace_channel_snapshot;
1001
1002 if (!replace) {
1003 return NULL;
1004 }
1005
1006 replace_channel_snapshot = replace->snapshot;
1007 replace->snapshot = NULL;
1008
1009 return replace_channel_snapshot;
1010}
1011
1013{
1015 char *replace_channel_app;
1016
1017 if (!replace) {
1018 return NULL;
1019 }
1020
1021 replace_channel_app = replace->app;
1022 replace->app = NULL;
1023
1024 return replace_channel_app;
1025}
1026
1027static void start_message_blob_dtor(void *obj)
1028{
1029 struct start_message_blob *payload = obj;
1030
1031 ao2_cleanup(payload->channel);
1032 ao2_cleanup(payload->replace_channel);
1033 ast_json_unref(payload->blob);
1034}
1035
1036static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app *app,
1037 int argc, char *argv[], struct ast_channel_snapshot *snapshot,
1038 struct ast_channel_snapshot *replace_channel_snapshot)
1039{
1040 struct ast_json *json_blob;
1041 struct ast_json *json_args;
1042 struct start_message_blob *payload;
1043 struct stasis_message *msg;
1044 int i;
1045
1046 if (app_subscribe_channel(app, chan)) {
1047 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
1049 return -1;
1050 }
1051
1052 payload = ao2_alloc(sizeof(*payload), start_message_blob_dtor);
1053 if (!payload) {
1054 ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
1055 return -1;
1056 }
1057
1058 payload->channel = ao2_bump(snapshot);
1059 payload->replace_channel = ao2_bump(replace_channel_snapshot);
1060
1061 json_blob = ast_json_pack("{s: s, s: o, s: []}",
1062 "app", stasis_app_name(app),
1063 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1064 "args");
1065 if (!json_blob) {
1066 ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
1067 ao2_ref(payload, -1);
1068 return -1;
1069 }
1070 payload->blob = json_blob;
1071
1072
1073 /* Append arguments to args array */
1074 json_args = ast_json_object_get(json_blob, "args");
1075 ast_assert(json_args != NULL);
1076 for (i = 0; i < argc; ++i) {
1077 int r = ast_json_array_append(json_args,
1078 ast_json_string_create(argv[i]));
1079 if (r != 0) {
1080 ast_log(LOG_ERROR, "Error appending to StasisStart message\n");
1081 ao2_ref(payload, -1);
1082 return -1;
1083 }
1084 }
1085
1086
1087 msg = stasis_message_create(start_message_type(), payload);
1088 ao2_ref(payload, -1);
1089 if (!msg) {
1090 ast_log(LOG_ERROR, "Error sending StasisStart message\n");
1091 return -1;
1092 }
1093
1094 if (replace_channel_snapshot) {
1095 app_unsubscribe_channel_id(app, replace_channel_snapshot->base->uniqueid);
1096 }
1098 ao2_ref(msg, -1);
1099 return 0;
1100}
1101
1102static int send_start_msg(struct stasis_app *app, struct ast_channel *chan,
1103 int argc, char *argv[])
1104{
1105 int ret = -1;
1106 struct ast_channel_snapshot *snapshot;
1107 struct ast_channel_snapshot *replace_channel_snapshot;
1108
1109 ast_assert(chan != NULL);
1110
1111 replace_channel_snapshot = get_replace_channel_snapshot(chan);
1112
1113 /* Set channel info */
1114 ast_channel_lock(chan);
1115 snapshot = ast_channel_snapshot_create(chan);
1116 ast_channel_unlock(chan);
1117 if (snapshot) {
1118 ret = send_start_msg_snapshots(chan, app, argc, argv, snapshot, replace_channel_snapshot);
1119 ao2_ref(snapshot, -1);
1120 }
1121 ao2_cleanup(replace_channel_snapshot);
1122
1123 return ret;
1124}
1125
1126static void remove_masquerade_store(struct ast_channel *chan);
1127
1128int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
1129{
1131 struct ast_json *blob;
1132 struct stasis_message *msg;
1133
1134 if (sanitize && sanitize->channel
1135 && sanitize->channel(chan)) {
1136 return 0;
1137 }
1138
1139 blob = ast_json_pack("{s: s, s: o}",
1140 "app", stasis_app_name(app),
1141 "timestamp", ast_json_timeval(ast_tvnow(), NULL)
1142 );
1143 if (!blob) {
1144 ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n");
1145 return -1;
1146 }
1147
1150 msg = ast_channel_blob_create(chan, end_message_type(), blob);
1151 if (msg) {
1153 }
1154 ao2_cleanup(msg);
1155 ast_json_unref(blob);
1156
1157 return 0;
1158}
1159
1160static int masq_match_cb(void *obj, void *data, int flags)
1161{
1162 struct stasis_app_control *control = obj;
1163 struct ast_channel *chan = data;
1164
1165 if (!strcmp(ast_channel_uniqueid(chan),
1167 return CMP_MATCH;
1168 }
1169
1170 return 0;
1171}
1172
1173static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1174{
1175 struct stasis_app_control *control;
1176
1177 /*
1178 * At this point, old_chan is the channel pointer that is in Stasis() and
1179 * has the unknown channel's name in it while new_chan is the channel pointer
1180 * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1181 * about.
1182 *
1183 * Find and unlink control since the channel has a new name/uniqueid
1184 * and its hash has changed. Since the channel is leaving stasis don't
1185 * bother putting it back into the container. Nobody is going to
1186 * remove it from the container later.
1187 */
1188 control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, old_chan);
1189 if (!control) {
1190 ast_log(LOG_ERROR, "Could not find control for masqueraded channel\n");
1191 return;
1192 }
1193
1194 /* send the StasisEnd message to the app */
1196 app_send_end_msg(control_app(control), new_chan);
1197
1198 /* remove the datastore */
1199 remove_masquerade_store(old_chan);
1200
1201 ao2_cleanup(control);
1202}
1203
1204static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1205{
1206 RAII_VAR(struct ast_channel_snapshot *, new_snapshot, NULL, ao2_cleanup);
1207 RAII_VAR(struct ast_channel_snapshot *, old_snapshot, NULL, ao2_cleanup);
1208 struct stasis_app_control *control;
1209
1210 /* At this point, new_chan is the channel pointer that is in Stasis() and
1211 * has the unknown channel's name in it while old_chan is the channel pointer
1212 * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1213 * about */
1214
1215 /* grab a snapshot for the channel that is jumping into Stasis() */
1216 new_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(new_chan));
1217 if (!new_snapshot) {
1218 ast_log(LOG_ERROR, "Could not get snapshot for masquerading channel\n");
1219 return;
1220 }
1221
1222 /* grab a snapshot for the channel that has been kicked out of Stasis() */
1223 old_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(old_chan));
1224 if (!old_snapshot) {
1225 ast_log(LOG_ERROR, "Could not get snapshot for masqueraded channel\n");
1226 return;
1227 }
1228
1229 /*
1230 * Find, unlink, and relink control since the channel has a new
1231 * name/uniqueid and its hash has changed.
1232 */
1233 control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, new_chan);
1234 if (!control) {
1235 ast_log(LOG_ERROR, "Could not find control for masquerading channel\n");
1236 return;
1237 }
1238 ao2_link(app_controls, control);
1239
1240
1241 /* send the StasisStart with replace_channel to the app */
1242 send_start_msg_snapshots(new_chan, control_app(control), 0, NULL, new_snapshot,
1243 old_snapshot);
1244 /* send the StasisEnd message to the app */
1245 app_send_end_msg(control_app(control), old_chan);
1246
1247 ao2_cleanup(control);
1248}
1249
1251 .type = "stasis-masquerade",
1252 .chan_fixup = channel_stolen_cb,
1253 .chan_breakdown = channel_replaced_cb,
1254};
1255
1256static int has_masquerade_store(struct ast_channel *chan)
1257{
1258 SCOPED_CHANNELLOCK(lock, chan);
1260}
1261
1262static int add_masquerade_store(struct ast_channel *chan)
1263{
1264 struct ast_datastore *datastore;
1265
1266 SCOPED_CHANNELLOCK(lock, chan);
1268 return 0;
1269 }
1270
1272 if (!datastore) {
1273 return -1;
1274 }
1275
1276 ast_channel_datastore_add(chan, datastore);
1277
1278 return 0;
1279}
1280
1281static void remove_masquerade_store(struct ast_channel *chan)
1282{
1283 struct ast_datastore *datastore;
1284
1285 SCOPED_CHANNELLOCK(lock, chan);
1287 if (!datastore) {
1288 return;
1289 }
1290
1291 ast_channel_datastore_remove(chan, datastore);
1292 ast_datastore_free(datastore);
1293}
1294
1296{
1297 while (!control_is_done(control)) {
1298 int command_count;
1299 command_count = control_dispatch_all(control, chan);
1300
1301 ao2_lock(control);
1302
1303 if (control_command_count(control)) {
1304 /* If the command queue isn't empty, something added to the queue before it was locked. */
1305 ao2_unlock(control);
1306 continue;
1307 }
1308
1309 if (command_count == 0 || ast_channel_fdno(chan) == -1) {
1310 control_mark_done(control);
1311 ao2_unlock(control);
1312 break;
1313 }
1314 ao2_unlock(control);
1315 }
1316}
1317
1319{
1320 return control_is_done(control);
1321}
1322
1324{
1325 control_flush_queue(control);
1326}
1327
1329 .type = "stasis_end_published",
1330};
1331
1333{
1334 struct ast_datastore *datastore;
1335
1337 if (datastore) {
1338 ast_channel_lock(chan);
1339 ast_channel_datastore_add(chan, datastore);
1340 ast_channel_unlock(chan);
1341 }
1342}
1343
1345{
1346 struct ast_datastore *datastore;
1347
1348 ast_channel_lock(chan);
1350 ast_channel_unlock(chan);
1351
1352 return datastore ? 1 : 0;
1353}
1354
1356{
1357 struct ast_datastore *datastore;
1358
1359 ast_channel_lock(chan);
1361 if (datastore) {
1362 ast_channel_datastore_remove(chan, datastore);
1363 ast_datastore_free(datastore);
1364 }
1365 ast_channel_unlock(chan);
1366}
1367
1368/*! \brief Stasis dialplan application callback */
1369int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
1370 char *argv[])
1371{
1372 RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1373 RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
1374 struct ast_bridge *bridge = NULL;
1375 int res = 0;
1376 int needs_depart;
1377
1378 ast_assert(chan != NULL);
1379
1380 /* Just in case there's a lingering indication that the channel has had a stasis
1381 * end published on it, remove that now.
1382 */
1384
1385 if (!apps_registry) {
1386 return -1;
1387 }
1388
1390 if (!app) {
1392 "Stasis app '%s' not registered\n", app_name);
1393 return -1;
1394 }
1395 if (!app_is_active(app)) {
1397 "Stasis app '%s' not active\n", app_name);
1398 return -1;
1399 }
1400
1401 control = control_create(chan, app);
1402 if (!control) {
1403 ast_log(LOG_ERROR, "Control allocation failed or Stasis app '%s' not registered\n", app_name);
1404 return -1;
1405 }
1406
1407 if (!control_app(control)) {
1408 ast_log(LOG_ERROR, "Stasis app '%s' not registered\n", app_name);
1409 return -1;
1410 }
1411
1412 if (!app_is_active(control_app(control))) {
1413 ast_log(LOG_ERROR, "Stasis app '%s' not active\n", app_name);
1414 return -1;
1415 }
1416 ao2_link(app_controls, control);
1417
1418 if (add_masquerade_store(chan)) {
1419 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1420 return -1;
1421 }
1422
1423 res = send_start_msg(control_app(control), chan, argc, argv);
1424 if (res != 0) {
1426 "Error sending start message to '%s'\n", app_name);
1428 return -1;
1429 }
1430
1431 /* Pull queued prestart commands and execute */
1432 control_prestart_dispatch_all(control, chan);
1433
1434 while (!control_is_done(control)) {
1435 RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
1436 int r;
1437 int command_count;
1438 RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup);
1439
1440 /* Check to see if a bridge absorbed our hangup frame */
1441 if (ast_check_hangup_locked(chan)) {
1442 control_mark_done(control);
1443 break;
1444 }
1445
1446 /* control->next_app is only modified within the control thread, so this is safe */
1447 if (control_next_app(control)) {
1448 struct stasis_app *next_app = ao2_find(apps_registry, control_next_app(control), OBJ_SEARCH_KEY);
1449
1450 if (next_app && app_is_active(next_app)) {
1451 int idx;
1452 int next_argc;
1453 char **next_argv;
1454
1455 /* If something goes wrong in this conditional, res will need to be non-zero
1456 * so that the code below the exec loop knows something went wrong during a move.
1457 */
1459 res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1460 if (res != 0) {
1462 "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1463 control_mark_done(control);
1464 ao2_ref(next_app, -1);
1465 break;
1466 }
1467 } else {
1469 }
1470
1471 /* This will ao2_bump next_app, and unref the previous app by 1 */
1472 control_set_app(control, next_app);
1473
1474 /* There's a chance that the previous application is ready for clean up, so go ahead
1475 * and do that now.
1476 */
1477 cleanup();
1478
1479 /* We need to add another masquerade store, otherwise the leave message will
1480 * not show up for the correct application.
1481 */
1482 if (add_masquerade_store(chan)) {
1483 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1484 res = -1;
1485 control_mark_done(control);
1486 ao2_ref(next_app, -1);
1487 break;
1488 }
1489
1490 /* We MUST get the size before the list, as control_next_app_args steals the elements
1491 * from the string vector.
1492 */
1493 next_argc = control_next_app_args_size(control);
1494 next_argv = control_next_app_args(control);
1495
1496 res = send_start_msg(control_app(control), chan, next_argc, next_argv);
1497
1498 /* Even if res != 0, we still need to free the memory we got from control_argv */
1499 if (next_argv) {
1500 for (idx = 0; idx < next_argc; idx++) {
1501 ast_free(next_argv[idx]);
1502 }
1503 ast_free(next_argv);
1504 }
1505
1506 if (res != 0) {
1508 "Error sending start message to '%s'\n", stasis_app_name(control_app(control)));
1510 control_mark_done(control);
1511 ao2_ref(next_app, -1);
1512 break;
1513 }
1514
1515 /* Done switching applications, free memory and clean up */
1516 control_move_cleanup(control);
1517 } else {
1518 /* If we can't switch applications, do nothing */
1519 struct ast_json *msg;
1520 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1521
1522 if (!next_app) {
1523 ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not registered\n",
1524 control_next_app(control));
1525 } else {
1526 ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not active\n",
1527 control_next_app(control));
1528 }
1529
1531 if (!snapshot) {
1532 ast_log(LOG_ERROR, "Could not get channel shapshot for '%s'\n",
1533 ast_channel_name(chan));
1534 } else {
1535 struct ast_json *json_args;
1536 int next_argc = control_next_app_args_size(control);
1537 char **next_argv = control_next_app_args(control);
1538
1539 msg = ast_json_pack("{s: s, s: o, s: o, s: s, s: []}",
1540 "type", "ApplicationMoveFailed",
1541 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1542 "channel", ast_channel_snapshot_to_json(snapshot, NULL),
1543 "destination", control_next_app(control),
1544 "args");
1545 if (!msg) {
1546 ast_log(LOG_ERROR, "Failed to pack JSON for ApplicationMoveFailed message\n");
1547 } else {
1548 json_args = ast_json_object_get(msg, "args");
1549 if (!json_args) {
1550 ast_log(LOG_ERROR, "Could not get args json array");
1551 } else {
1552 int r = 0;
1553 int idx;
1554 for (idx = 0; idx < next_argc; ++idx) {
1555 r = ast_json_array_append(json_args,
1556 ast_json_string_create(next_argv[idx]));
1557 if (r != 0) {
1558 ast_log(LOG_ERROR, "Error appending to ApplicationMoveFailed message\n");
1559 break;
1560 }
1561 }
1562 if (r == 0) {
1563 app_send(control_app(control), msg);
1564 }
1565 }
1566 ast_json_unref(msg);
1567 }
1568 }
1569 }
1570 control_move_cleanup(control);
1571 ao2_cleanup(next_app);
1572 }
1573
1574 last_bridge = bridge;
1575 bridge = ao2_bump(stasis_app_get_bridge(control));
1576
1577 if (bridge != last_bridge) {
1578 if (last_bridge) {
1579 app_unsubscribe_bridge(control_app(control), last_bridge);
1580 }
1581 if (bridge) {
1582 app_subscribe_bridge(control_app(control), bridge);
1583 }
1584 }
1585
1586 if (bridge) {
1587 /* Bridge/dial is handling channel frames */
1588 control_wait(control);
1589 control_dispatch_all(control, chan);
1590 continue;
1591 }
1592
1593 r = ast_waitfor(chan, MAX_WAIT_MS);
1594
1595 if (r < 0) {
1596 ast_debug(3, "%s: Poll error\n",
1597 ast_channel_uniqueid(chan));
1598 control_mark_done(control);
1599 break;
1600 }
1601
1602 command_count = control_dispatch_all(control, chan);
1603
1604 if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1605 /* Command drained the channel; wait for next frame */
1606 continue;
1607 }
1608
1609 if (r == 0) {
1610 /* Timeout */
1611 continue;
1612 }
1613
1614 f = ast_read(chan);
1615 if (!f) {
1616 /* Continue on in the dialplan */
1617 ast_debug(3, "%s: Hangup (no more frames)\n",
1618 ast_channel_uniqueid(chan));
1619 control_mark_done(control);
1620 break;
1621 }
1622
1623 if (f->frametype == AST_FRAME_CONTROL) {
1624 if (f->subclass.integer == AST_CONTROL_HANGUP) {
1625 /* Continue on in the dialplan */
1626 ast_debug(3, "%s: Hangup\n",
1627 ast_channel_uniqueid(chan));
1628 control_mark_done(control);
1629 break;
1630 }
1631 }
1632 }
1633
1634 ast_channel_lock(chan);
1635 needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1636 ast_channel_unlock(chan);
1637 if (needs_depart) {
1638 ast_bridge_depart(chan);
1639 }
1640
1641 if (stasis_app_get_bridge(control)) {
1643 }
1644 ao2_cleanup(bridge);
1645
1646 /* Only publish a stasis_end event if it hasn't already been published */
1647 if (!res && !stasis_app_channel_is_stasis_end_published(chan)) {
1648 /* A masquerade has occurred and this message will be wrong so it
1649 * has already been sent elsewhere. */
1650 res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1651 if (res != 0) {
1653 "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1654 return res;
1655 }
1656 } else {
1658 }
1659
1660 control_flush_queue(control);
1661
1662 /* Stop any lingering silence generator */
1663 control_silence_stop_now(control);
1664
1665 /* There's an off chance that app is ready for cleanup. Go ahead
1666 * and clean up, just in case
1667 */
1668 cleanup();
1669
1670 if (stasis_app_control_is_failed(control)) {
1671 res = -1;
1672 }
1673 /* The control needs to be removed from the controls container in
1674 * case a new PBX is started and ends up coming back into Stasis.
1675 */
1676 control_unlink(control);
1677 control = NULL;
1678
1679 if (!res && !ast_channel_pbx(chan)) {
1680 int chan_hungup;
1681
1682 /* The ASYNCGOTO softhangup flag may have broken the channel out of
1683 * its bridge to run dialplan, so if there's no pbx on the channel
1684 * let it run dialplan here. Otherwise, it will run when this
1685 * application exits. */
1686 ast_channel_lock(chan);
1688 chan_hungup = ast_check_hangup(chan);
1689 ast_channel_unlock(chan);
1690
1691 if (!chan_hungup) {
1692 struct ast_pbx_args pbx_args;
1693
1694 memset(&pbx_args, 0, sizeof(pbx_args));
1695 pbx_args.no_hangup_chan = 1;
1696
1697 res = ast_pbx_run_args(chan, &pbx_args);
1698 }
1699 }
1700
1701 return res;
1702}
1703
1704int stasis_app_send(const char *app_name, struct ast_json *message)
1705{
1706 struct stasis_app *app;
1707
1708 if (!apps_registry) {
1709 return -1;
1710 }
1711
1713 if (!app) {
1714 /* XXX We can do a better job handling late binding, queueing up
1715 * the call for a few seconds to wait for the app to register.
1716 */
1718 "Stasis app '%s' not registered\n", app_name);
1719 return -1;
1720 }
1722 ao2_ref(app, -1);
1723
1724 return 0;
1725}
1726
1727static struct stasis_app *find_app_by_name(const char *app_name)
1728{
1729 struct stasis_app *res = NULL;
1730
1731 if (!apps_registry) {
1732 return NULL;
1733 }
1734
1735 if (!ast_strlen_zero(app_name)) {
1737 }
1738
1739 return res;
1740}
1741
1743{
1744 return find_app_by_name(name);
1745}
1746
1748{
1750
1751 /*
1752 * It's safe to unref app here because we're not actually
1753 * using it or returning it.
1754 */
1756
1757 return app != NULL;
1758}
1759
1760static int append_name(void *obj, void *arg, int flags)
1761{
1762 struct stasis_app *app = obj;
1763 struct ao2_container *apps = arg;
1764
1766 return 0;
1767}
1768
1770{
1771 struct ao2_container *apps;
1772
1773 if (!apps_registry) {
1774 return NULL;
1775 }
1776
1778 if (!apps) {
1779 return NULL;
1780 }
1781
1783
1784 return apps;
1785}
1786
1787static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
1788{
1789 RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1790
1791 if (!apps_registry) {
1792 return -1;
1793 }
1794
1797 if (app) {
1798 /*
1799 * We need to unlock the apps_registry before calling app_update to
1800 * prevent the possibility of a deadlock with the session.
1801 */
1803 app_update(app, handler, data);
1804 cleanup();
1805 return 0;
1806 }
1807
1809 if (!app) {
1811 return -1;
1812 }
1813
1814 if (all_events) {
1815 struct stasis_app_event_source *source;
1816
1819 if (!source->subscribe) {
1820 continue;
1821 }
1822
1823 source->subscribe(app, NULL);
1824 }
1826 }
1828
1830
1831 /* We lazily clean up the apps_registry, because it's good enough to
1832 * prevent memory leaks, and we're lazy.
1833 */
1834 cleanup();
1835 return 0;
1836}
1837
1839{
1840 return __stasis_app_register(app_name, handler, data, 0);
1841}
1842
1844{
1845 return __stasis_app_register(app_name, handler, data, 1);
1846}
1847
1849{
1850 struct stasis_app *app;
1851 struct stasis_app_event_source *source;
1852 int res;
1853
1854 if (!app_name) {
1855 return;
1856 }
1857
1858 if (!apps_registry) {
1859 return;
1860 }
1861
1863 if (!app) {
1865 "Stasis app '%s' not registered\n", app_name);
1866 return;
1867 }
1868
1869 /* Unsubscribe from all event sources. */
1872 if (!source->unsubscribe || !source->is_subscribed
1873 || !source->is_subscribed(app, NULL)) {
1874 continue;
1875 }
1876
1877 res = source->unsubscribe(app, NULL);
1878 if (res) {
1879 ast_log(LOG_WARNING, "%s: Error unsubscribing from event source '%s'\n",
1880 app_name, source->scheme);
1881 }
1882 }
1884
1886
1887 /* There's a decent chance that app is ready for cleanup. Go ahead
1888 * and clean up, just in case
1889 */
1890 cleanup();
1891
1892 ao2_ref(app, -1);
1893}
1894
1896{
1900}
1901
1903{
1904 struct stasis_app_event_source *source;
1905
1908 if (source == obj) {
1910 break;
1911 }
1912 }
1915}
1916
1917/*!
1918 * \internal
1919 * \brief Convert event source data to JSON.
1920 *
1921 * Calls each event source that has a "to_json" handler allowing each
1922 * source to add data to the given JSON object.
1923 *
1924 * \param app application associated with the event source
1925 * \param json a json object to "fill"
1926 *
1927 * \retval The given json object.
1928 */
1930 const struct stasis_app *app, struct ast_json *json)
1931{
1932 struct stasis_app_event_source *source;
1933
1936 if (source->to_json) {
1937 source->to_json(app, json);
1938 }
1939 }
1941
1942 return json;
1943}
1944
1946{
1947 if (!app) {
1948 return NULL;
1949 }
1950
1953}
1954
1956{
1958 struct ast_json *json = stasis_app_object_to_json(app);
1959
1961
1962 return json;
1963}
1964
1965/*!
1966 * \internal
1967 * \brief Finds an event source that matches a uri scheme.
1968 *
1969 * Uri(s) should begin with a particular scheme that can be matched
1970 * against an event source.
1971 *
1972 * \param uri uri containing a scheme to match
1973 *
1974 * \retval an event source if found, NULL otherwise.
1975 */
1976static struct stasis_app_event_source *app_event_source_find(const char *uri)
1977{
1978 struct stasis_app_event_source *source;
1979
1982 if (ast_begins_with(uri, source->scheme)) {
1983 break;
1984 }
1985 }
1987
1988 return source;
1989}
1990
1991/*!
1992 * \internal
1993 * \brief Callback for subscription handling
1994 *
1995 * \param app [un]subscribing application
1996 * \param uri scheme:id of an event source
1997 * \param event_source being [un]subscribed [from]to
1998 *
1999 * \retval stasis_app_subscribe_res return code.
2000 */
2002 struct stasis_app *app, const char *uri,
2003 struct stasis_app_event_source *event_source);
2004
2005/*!
2006 * \internal
2007 * \brief Subscriptions handler for application [un]subscribing.
2008 *
2009 * \param app_name Name of the application to subscribe.
2010 * \param event_source_uris URIs for the event sources to subscribe to.
2011 * \param event_sources_count Array size of event_source_uris.
2012 * \param json Optional output pointer for JSON representation of the app
2013 * after adding the subscription.
2014 * \param handler [un]subscribe handler
2015 *
2016 * \retval stasis_app_subscribe_res return code.
2017 */
2019 const char *app_name, const char **event_source_uris,
2020 int event_sources_count, struct ast_json **json,
2022{
2024 int i;
2025
2027
2028 if (!app) {
2030 }
2031
2032 for (i = 0; i < event_sources_count; ++i) {
2033 const char *uri = event_source_uris[i];
2034 struct stasis_app_event_source *event_source;
2035 enum stasis_app_subscribe_res res;
2036
2037 event_source = app_event_source_find(uri);
2038 if (!event_source) {
2039 ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
2040 ao2_ref(app, -1);
2041
2043 }
2044
2045 res = handler(app, uri, event_source);
2046 if (res != STASIS_ASR_OK) {
2047 ao2_ref(app, -1);
2048
2049 return res;
2050 }
2051 }
2052
2053 if (json) {
2054 ast_debug(3, "%s: Successful; setting results\n", app_name);
2056 }
2057
2058 ao2_ref(app, -1);
2059
2060 return STASIS_ASR_OK;
2061}
2062
2064 struct ast_channel *chan)
2065{
2067 int res;
2068
2069 if (!app) {
2071 }
2072
2073 ast_debug(3, "%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan));
2074
2075 res = app_subscribe_channel(app, chan);
2076 ao2_ref(app, -1);
2077
2078 if (res != 0) {
2079 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
2082 }
2083
2084 return STASIS_ASR_OK;
2085}
2086
2087
2088/*!
2089 * \internal
2090 * \brief Subscribe an app to an event source.
2091 *
2092 * \param app subscribing application
2093 * \param uri scheme:id of an event source
2094 * \param event_source being subscribed to
2095 *
2096 * \retval stasis_app_subscribe_res return code.
2097 */
2099 struct stasis_app *app, const char *uri,
2100 struct stasis_app_event_source *event_source)
2101{
2102 const char *app_name = stasis_app_name(app);
2103 RAII_VAR(void *, obj, NULL, ao2_cleanup);
2104
2105 ast_debug(3, "%s: Checking %s\n", app_name, uri);
2106
2107 if (!ast_strlen_zero(uri + strlen(event_source->scheme)) &&
2108 (!event_source->find || (!(obj = event_source->find(app, uri + strlen(event_source->scheme)))))) {
2109 ast_log(LOG_WARNING, "Event source not found: %s\n", uri);
2111 }
2112
2113 ast_debug(3, "%s: Subscribing to %s\n", app_name, uri);
2114
2115 if (!event_source->subscribe || (event_source->subscribe(app, obj))) {
2116 ast_log(LOG_WARNING, "Error subscribing app '%s' to '%s'\n",
2117 app_name, uri);
2119 }
2120
2121 return STASIS_ASR_OK;
2122}
2123
2125 const char **event_source_uris, int event_sources_count,
2126 struct ast_json **json)
2127{
2129 app_name, event_source_uris, event_sources_count,
2130 json, app_subscribe);
2131}
2132
2133/*!
2134 * \internal
2135 * \brief Unsubscribe an app from an event source.
2136 *
2137 * \param app application to unsubscribe
2138 * \param uri scheme:id of an event source
2139 * \param event_source being unsubscribed from
2140 *
2141 * \retval stasis_app_subscribe_res return code.
2142 */
2144 struct stasis_app *app, const char *uri,
2145 struct stasis_app_event_source *event_source)
2146{
2147 const char *app_name = stasis_app_name(app);
2148 const char *id = uri + strlen(event_source->scheme);
2149
2150 if (!event_source->is_subscribed ||
2151 (!event_source->is_subscribed(app, id))) {
2153 }
2154
2155 ast_debug(3, "%s: Unsubscribing from %s\n", app_name, uri);
2156
2157 if (!event_source->unsubscribe || (event_source->unsubscribe(app, id))) {
2158 ast_log(LOG_WARNING, "Error unsubscribing app '%s' to '%s'\n",
2159 app_name, uri);
2160 return -1;
2161 }
2162 return 0;
2163}
2164
2166 const char **event_source_uris, int event_sources_count,
2167 struct ast_json **json)
2168{
2170 app_name, event_source_uris, event_sources_count,
2171 json, app_unsubscribe);
2172}
2173
2175 const char *event_name,
2176 const char **source_uris, int sources_count,
2177 struct ast_json *json_variables)
2178{
2180 struct ast_json *blob = NULL;
2181 struct ast_multi_object_blob *multi;
2182 struct stasis_message *message;
2184 int have_channel = 0;
2185 int i;
2186
2187 if (!app) {
2188 ast_log(LOG_WARNING, "App %s not found\n", app_name);
2190 }
2191
2193 return res;
2194 }
2195
2196 if (json_variables) {
2197 struct ast_json *json_value = ast_json_string_create(event_name);
2198
2199 if (json_value && !ast_json_object_set(json_variables, "eventname", json_value)) {
2200 blob = ast_json_ref(json_variables);
2201 }
2202 } else {
2203 blob = ast_json_pack("{s: s}", "eventname", event_name);
2204 }
2205
2206 if (!blob) {
2207 ast_log(LOG_ERROR, "Failed to initialize blob\n");
2208
2209 return res;
2210 }
2211
2212 multi = ast_multi_object_blob_create(blob);
2213 ast_json_unref(blob);
2214 if (!multi) {
2215 ast_log(LOG_ERROR, "Failed to initialize multi\n");
2216
2217 return res;
2218 }
2219
2220 for (i = 0; i < sources_count; ++i) {
2221 const char *uri = source_uris[i];
2222 void *snapshot=NULL;
2224
2225 if (ast_begins_with(uri, "channel:")) {
2227 snapshot = ast_channel_snapshot_get_latest(uri + 8);
2228 have_channel = 1;
2229 } else if (ast_begins_with(uri, "bridge:")) {
2231 snapshot = ast_bridge_get_snapshot_by_uniqueid(uri + 7);
2232 } else if (ast_begins_with(uri, "endpoint:")) {
2234 snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL);
2235 } else {
2236 ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
2237 ao2_ref(multi, -1);
2238
2240 }
2241 if (!snapshot) {
2242 ast_log(LOG_ERROR, "Unable to get snapshot for %s\n", uri);
2243 ao2_ref(multi, -1);
2244
2246 }
2247 ast_multi_object_blob_add(multi, type, snapshot);
2248 }
2249
2251 ao2_ref(multi, -1);
2252
2253 if (!message) {
2254 ast_log(LOG_ERROR, "Unable to create stasis user event message\n");
2255 return res;
2256 }
2257
2258 /*
2259 * Publishing to two different topics is normally to be avoided -- except
2260 * in this case both are final destinations with no forwards (only listeners).
2261 * The message has to be delivered to the application topic for ARI, but a
2262 * copy is also delivered directly to the manager for AMI if there is a channel.
2263 */
2265
2266 if (have_channel) {
2268 }
2269 ao2_ref(message, -1);
2270
2271 return STASIS_APP_USER_OK;
2272}
2273
2274static int unload_module(void)
2275{
2277
2279
2280 cleanup();
2281
2283
2286
2289
2291 app_bridges = NULL;
2292
2295
2298
2299 STASIS_MESSAGE_TYPE_CLEANUP(end_message_type);
2300 STASIS_MESSAGE_TYPE_CLEANUP(start_message_type);
2301
2302 return 0;
2303}
2304
2305/*! \brief Sanitization callback for channel snapshots */
2306static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
2307{
2308 if (!snapshot || !(snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL)) {
2309 return 0;
2310 }
2311 return 1;
2312}
2313
2314/*! \brief Sanitization callback for channels */
2315static int channel_sanitizer(const struct ast_channel *chan)
2316{
2317 if (!chan || !(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)) {
2318 return 0;
2319 }
2320 return 1;
2321}
2322
2323/*! \brief Sanitization callback for channel unique IDs */
2324static int channel_id_sanitizer(const char *id)
2325{
2326 struct ast_channel_snapshot *snapshot;
2327 int ret;
2328
2329 snapshot = ast_channel_snapshot_get_latest(id);
2330 ret = channel_snapshot_sanitizer(snapshot);
2331 ao2_cleanup(snapshot);
2332
2333 return ret;
2334}
2335
2336/*! \brief Sanitization callbacks for communication to Stasis applications */
2339 .channel_snapshot = channel_snapshot_sanitizer,
2340 .channel = channel_sanitizer,
2341};
2342
2344{
2345 return &app_sanitizer;
2346}
2347
2349 .type = "stasis-internal-channel",
2350};
2351
2352static int set_internal_datastore(struct ast_channel *chan)
2353{
2354 struct ast_datastore *datastore;
2355
2357 if (!datastore) {
2359 if (!datastore) {
2360 return -1;
2361 }
2362 ast_channel_datastore_add(chan, datastore);
2363 }
2364 return 0;
2365}
2366
2368{
2369 struct ast_channel *outchan = NULL, *outowner = NULL;
2370 int res = 0;
2371 struct ast_unreal_pvt *unreal_pvt = ast_channel_tech_pvt(chan);
2372
2373 ao2_ref(unreal_pvt, +1);
2374 ast_unreal_lock_all(unreal_pvt, &outowner, &outchan);
2375 if (outowner) {
2376 res |= set_internal_datastore(outowner);
2377 ast_channel_unlock(outowner);
2378 ast_channel_unref(outowner);
2379 }
2380 if (outchan) {
2381 res |= set_internal_datastore(outchan);
2382 ast_channel_unlock(outchan);
2383 ast_channel_unref(outchan);
2384 }
2385 ao2_unlock(unreal_pvt);
2386 ao2_ref(unreal_pvt, -1);
2387 return res;
2388}
2389
2391{
2392 int res;
2393
2397
2398 return res;
2399}
2400
2402{
2403 struct ast_datastore *datastore;
2404 int res = 0;
2405
2406 ast_channel_lock(chan);
2408 if (datastore) {
2409 res = 1;
2410 }
2411 ast_channel_unlock(chan);
2412
2413 return res;
2414}
2415
2416static int load_module(void)
2417{
2418 if (STASIS_MESSAGE_TYPE_INIT(start_message_type) != 0) {
2420 }
2421 if (STASIS_MESSAGE_TYPE_INIT(end_message_type) != 0) {
2423 }
2438 unload_module();
2440 }
2441
2442 if (messaging_init()) {
2443 unload_module();
2445 }
2446
2448
2450
2452}
2453
2455 .load_pri = AST_MODPRI_APP_DEPEND - 1,
2456 .support_level = AST_MODULE_SUPPORT_CORE,
2457 .load = load_module,
2458 .unload = unload_module,
static const char app[]
Definition: app_adsiprog.c:56
ast_mutex_t lock
Definition: app_sla.c:337
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition: astobj2.h:1600
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition: astobj2.h:501
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition: astobj2.h:1188
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridge.c:1975
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition: bridge.c:1009
@ AST_BRIDGE_CAPABILITY_MULTIMIX
Definition: bridge.h:98
@ AST_BRIDGE_CAPABILITY_HOLDING
Definition: bridge.h:90
ast_bridge_video_mode_type
Video source modes.
Definition: bridge.h:102
@ AST_BRIDGE_VIDEO_MODE_SINGLE_SRC
Definition: bridge.h:106
@ AST_BRIDGE_VIDEO_MODE_TALKER_SRC
Definition: bridge.h:109
@ AST_BRIDGE_VIDEO_MODE_SFU
Definition: bridge.h:113
#define BRIDGE_PRINTF_VARS(bridge)
Definition: bridge.h:80
#define BRIDGE_PRINTF_SPEC
Definition: bridge.h:79
After Bridge Execution API.
ast_bridge_after_cb_reason
Definition: bridge_after.h:37
int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data)
Setup an after bridge callback for when the channel leaves the bridging system.
Definition: bridge_after.c:251
@ AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY
@ AST_BRIDGE_FLAG_SWAP_INHIBIT_TO
@ AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO
@ AST_BRIDGE_FLAG_SMART
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
@ AST_BRIDGE_FLAG_INVISIBLE
@ AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE
@ AST_BRIDGE_CHANNEL_FLAG_LONELY
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
Internal Asterisk hangup causes.
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:106
static const char type[]
Definition: chan_ooh323.c:109
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2414
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2423
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2461
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2570
int ast_channel_fdno(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2970
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:991
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3190
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:459
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4274
struct ast_bridge_channel * ast_channel_internal_bridge_channel(const struct ast_channel *chan)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2500
#define AST_CHANNEL_NAME
Definition: channel.h:173
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3006
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1481
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6371
#define ast_channel_unlock(chan)
Definition: channel.h:2971
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2428
@ AST_SOFTHANGUP_ASYNCGOTO
Definition: channel.h:1146
struct stasis_app_control * control_create(struct ast_channel *channel, struct stasis_app *app)
Create a control object.
Definition: control.c:131
int control_prestart_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all queued prestart commands.
Definition: control.c:1565
void control_wait(struct stasis_app_control *control)
Blocks until control's command queue has a command available.
Definition: control.c:1545
char ** control_next_app_args(struct stasis_app_control *control)
Returns the list of arguments to pass to the application we are moving to.
Definition: control.c:1740
int control_is_done(struct stasis_app_control *control)
Returns true if control_continue() has been called on this control.
Definition: control.c:363
void control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: control.c:1512
int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all commands enqueued to this control.
Definition: control.c:1525
int control_next_app_args_size(struct stasis_app_control *control)
Returns the number of arguments to be passed to the application we are moving to.
Definition: control.c:1745
void control_set_app(struct stasis_app_control *control, struct stasis_app *app)
Set the application the control object belongs to.
Definition: control.c:1721
int control_command_count(struct stasis_app_control *control)
Returns the count of items in a control's command queue.
Definition: control.c:358
void control_silence_stop_now(struct stasis_app_control *control)
Stop playing silence to a channel right now.
Definition: control.c:863
char * control_next_app(struct stasis_app_control *control)
Returns the name of the application we are moving to.
Definition: control.c:1727
struct stasis_app * control_app(struct stasis_app_control *control)
Returns the pointer (non-reffed) to the app associated with this control.
Definition: control.c:1593
void control_move_cleanup(struct stasis_app_control *control)
Free any memory that was allocated for switching applications via /channels/{channelId}/move.
Definition: control.c:1732
void control_mark_done(struct stasis_app_control *control)
Definition: control.c:369
Internal API for the Stasis application controller.
Unreal channel derivative framework.
int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
Push the semi2 unreal channel into a bridge from either member of the unreal pair.
Definition: core_unreal.c:928
void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
Send an unreal pvt in with no locks held and get all locks.
Definition: core_unreal.c:47
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
Media Format Cache API.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
static const char name[]
Definition: format_mp3.c:68
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:980
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:454
void ast_multi_object_blob_add(struct ast_multi_object_blob *multi, enum stasis_user_multi_object_snapshot_type type, void *object)
Add an object to a multi object blob previously created.
Definition: stasis.c:2028
stasis_user_multi_object_snapshot_type
Object type code for multi user object snapshots.
Definition: stasis.h:1353
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.
struct ast_multi_object_blob * ast_multi_object_blob_create(struct ast_json *blob)
Create a stasis multi object blob.
Definition: stasis.c:2002
struct ast_endpoint_snapshot * ast_endpoint_latest_snapshot(const char *tech, const char *resource)
Retrieve the most recent snapshot for the endpoint with the given name.
struct stasis_message_type * ast_multi_user_event_type(void)
Message type for custom user defined events with multi object blobs.
struct stasis_message * ast_channel_blob_create(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Creates a ast_channel_blob message.
@ STASIS_UMOS_ENDPOINT
Definition: stasis.h:1356
@ STASIS_UMOS_BRIDGE
Definition: stasis.h:1355
@ STASIS_UMOS_CHANNEL
Definition: stasis.h:1354
void ast_frame_dtor(struct ast_frame *frame)
NULL-safe wrapper for ast_frfree, good for RAII_VAR.
Definition: main/frame.c:187
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_HANGUP
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:378
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:670
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:570
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
Definition: linkedlists.h:333
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition: lock.h:623
int messaging_init(void)
Initialize the messaging layer.
Definition: messaging.c:539
int messaging_cleanup(void)
Tidy up the messaging layer.
Definition: messaging.c:529
Stasis out-of-call text message support.
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:330
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_APP_DEPEND
Definition: module.h:342
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Music on hold handling.
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7797
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
Definition: pbx.c:4750
static struct apps apps
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
Add a bridge subscription to an existing channel subscription.
void app_update(struct stasis_app *app, stasis_app_cb handler, void *data)
Update the handler and data for a res_stasis application.
int app_unsubscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
Cancel the bridge subscription for an application.
void app_shutdown(struct stasis_app *app)
Tears down an application.
int app_unsubscribe_channel(struct stasis_app *app, struct ast_channel *chan)
Cancel the subscription an app has for a channel.
int app_subscribe_channel(struct stasis_app *app, struct ast_channel *chan)
Subscribes an application to a channel.
int app_is_finished(struct stasis_app *app)
Checks whether a deactivated app has no channels.
struct stasis_app * app_create(const char *name, stasis_app_cb handler, void *data, enum stasis_app_subscription_model subscription_model)
Create a res_stasis application.
int app_is_active(struct stasis_app *app)
Checks whether an app is active.
struct ast_json * app_to_json(const struct stasis_app *app)
Create a JSON representation of a stasis_app.
int app_unsubscribe_channel_id(struct stasis_app *app, const char *channel_id)
Cancel the subscription an app has for a channel.
void app_deactivate(struct stasis_app *app)
Deactivates an application.
void app_send(struct stasis_app *app, struct ast_json *message)
Send a message to an application.
Internal API for the Stasis application controller.
@ STASIS_APP_SUBSCRIBE_MANUAL
An application must manually subscribe to each resource that it cares about. This is the default appr...
@ STASIS_APP_SUBSCRIBE_ALL
An application is automatically subscribed to all resources in Asterisk, even if it does not control ...
void stasis_app_bridge_playback_channel_remove(char *bridge_id, struct stasis_app_control *control)
remove channel from list of ARI playback channels for bridges.
Definition: res_stasis.c:769
struct ast_json * stasis_app_object_to_json(struct stasis_app *app)
Return the JSON representation of a Stasis application.
Definition: res_stasis.c:1945
static int send_start_msg(struct stasis_app *app, struct ast_channel *chan, int argc, char *argv[])
Definition: res_stasis.c:1102
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
Definition: res_stasis.c:2343
static void stasis_app_bridge_channel_wrapper_destructor(void *obj)
Definition: res_stasis.c:481
int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app)
Set the app that the replacement channel will be controlled by.
Definition: res_stasis.c:976
static struct ast_channel_snapshot * get_replace_channel_snapshot(struct ast_channel *chan)
Definition: res_stasis.c:997
struct ao2_container * app_bridges_playback
Definition: res_stasis.c:108
static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
Definition: res_stasis.c:1204
STASIS_MESSAGE_TYPE_DEFN_LOCAL(end_message_type,.to_json=stasis_end_to_json)
static struct stasis_app * find_app_by_name(const char *app_name)
Definition: res_stasis.c:1727
#define BRIDGES_NUM_BUCKETS
Number of buckets for the Stasis bridges hash table. Remember to keep it a prime number!
Definition: res_stasis.c:95
int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot)
Set the snapshot of the channel that this channel will replace.
Definition: res_stasis.c:964
struct ast_bridge * stasis_app_bridge_create_invisible(const char *type, const char *name, const char *id)
Create an invisible bridge of the specified type.
Definition: res_stasis.c:896
int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, char *argv[])
Stasis dialplan application callback.
Definition: res_stasis.c:1369
int stasis_app_channel_is_internal(struct ast_channel *chan)
Is this channel internal to Stasis?
Definition: res_stasis.c:2401
static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
Definition: res_stasis.c:1173
static struct ast_channel * bridge_moh_create(struct ast_bridge *bridge)
Definition: res_stasis.c:600
int stasis_app_send(const char *app_name, struct ast_json *message)
Send a message to the given Stasis application.
Definition: res_stasis.c:1704
static const struct ast_datastore_info replace_channel_store_info
Definition: res_stasis.c:930
static int bridges_compare(void *obj, void *arg, int flags)
Definition: res_stasis.c:378
static void start_message_blob_dtor(void *obj)
Definition: res_stasis.c:1027
enum stasis_app_subscribe_res stasis_app_subscribe(const char *app_name, const char **event_source_uris, int event_sources_count, struct ast_json **json)
Subscribes an application to a list of event sources.
Definition: res_stasis.c:2124
static void playback_after_bridge_cb(struct ast_channel *chan, void *data)
Definition: res_stasis.c:724
int stasis_app_is_registered(const char *name)
Check if a Stasis application is registered.
Definition: res_stasis.c:1747
void stasis_app_channel_set_stasis_end_published(struct ast_channel *chan)
Indicate that this channel has had a StasisEnd published for it.
Definition: res_stasis.c:1332
void stasis_app_bridge_destroy(const char *bridge_id)
Destroy the bridge.
Definition: res_stasis.c:901
static int channel_sanitizer(const struct ast_channel *chan)
Sanitization callback for channels.
Definition: res_stasis.c:2315
struct ao2_container * app_controls
Definition: res_stasis.c:102
static void playback_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
Definition: res_stasis.c:717
struct ast_json * stasis_app_to_json(const char *app_name)
Return the JSON representation of a Stasis application.
Definition: res_stasis.c:1955
int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
Register a new Stasis application.
Definition: res_stasis.c:1838
static enum stasis_app_subscribe_res app_unsubscribe(struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
Definition: res_stasis.c:2143
static void replace_channel_destroy(void *obj)
Definition: res_stasis.c:921
static void remove_stasis_end_published(struct ast_channel *chan)
Definition: res_stasis.c:1355
static void cleanup(void)
Clean up any old apps that we don't need any more.
Definition: res_stasis.c:327
static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
Sanitization callback for channel snapshots.
Definition: res_stasis.c:2306
struct ao2_container * app_bridges_moh
Definition: res_stasis.c:106
int stasis_app_channel_set_internal(struct ast_channel *chan)
Mark this channel as being internal to Stasis.
Definition: res_stasis.c:2390
static int app_compare(void *obj, void *arg, int flags)
Definition: res_stasis.c:208
struct ast_bridge * stasis_app_bridge_find_by_id(const char *bridge_id)
Returns the bridge with the given id.
Definition: res_stasis.c:800
struct ast_bridge * stasis_app_bridge_create(const char *type, const char *name, const char *id)
Create a bridge of the specified type.
Definition: res_stasis.c:891
void stasis_app_unregister_event_source(struct stasis_app_event_source *obj)
Unregister an application event source.
Definition: res_stasis.c:1902
static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
Definition: res_stasis.c:1787
static int bridges_hash(const void *obj, const int flags)
Definition: res_stasis.c:356
static enum stasis_app_subscribe_res app_subscribe(struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
Definition: res_stasis.c:2098
static int app_hash(const void *obj, const int flags)
Definition: res_stasis.c:186
enum stasis_app_subscribe_res stasis_app_subscribe_channel(const char *app_name, struct ast_channel *chan)
Directly subscribe an application to a channel.
Definition: res_stasis.c:2063
void stasis_app_control_execute_until_exhausted(struct ast_channel *chan, struct stasis_app_control *control)
Act on a stasis app control queue until it is empty.
Definition: res_stasis.c:1295
static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app *app, int argc, char *argv[], struct ast_channel_snapshot *snapshot, struct ast_channel_snapshot *replace_channel_snapshot)
Definition: res_stasis.c:1036
static const struct ast_datastore_info stasis_internal_channel_info
Definition: res_stasis.c:2348
static int add_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1262
struct ao2_container * app_bridges
Definition: res_stasis.c:104
struct ast_channel * stasis_app_bridge_moh_channel(struct ast_bridge *bridge)
Finds or creates an announcer channel in a bridge that can play music on hold.
Definition: res_stasis.c:655
enum stasis_app_user_event_res stasis_app_user_event(const char *app_name, const char *event_name, const char **source_uris, int sources_count, struct ast_json *json_variables)
Generate a Userevent for stasis app (echo to AMI)
Definition: res_stasis.c:2174
#define APPS_NUM_BUCKETS
Number of buckets for the Stasis application hash table. Remember to keep it a prime number!
Definition: res_stasis.c:83
static int has_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1256
int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
Send StasisEnd message to the listening app.
Definition: res_stasis.c:1128
void stasis_app_control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: res_stasis.c:1323
static int control_hash(const void *obj, const int flags)
Definition: res_stasis.c:248
int stasis_app_channel_unreal_set_internal(struct ast_channel *chan)
Mark this unreal channel and it's other half as being internal to Stasis.
Definition: res_stasis.c:2367
static struct ast_channel * prepare_bridge_moh_channel(void)
Definition: res_stasis.c:536
static int set_internal_datastore(struct ast_channel *chan)
Definition: res_stasis.c:2352
#define CONTROLS_NUM_BUCKETS
Number of buckets for the Stasis application hash table. Remember to keep it a prime number!
Definition: res_stasis.c:89
static int append_name(void *obj, void *arg, int flags)
Definition: res_stasis.c:1760
int stasis_app_bridge_playback_channel_add(struct ast_bridge *bridge, struct ast_channel *chan, struct stasis_app_control *control)
Adds a channel to the list of ARI playback channels for bridges.
Definition: res_stasis.c:731
void stasis_app_unregister(const char *app_name)
Unregister a Stasis application and unsubscribe from all event sources.
Definition: res_stasis.c:1848
enum stasis_app_subscribe_res stasis_app_unsubscribe(const char *app_name, const char **event_source_uris, int event_sources_count, struct ast_json **json)
Unsubscribes an application from a list of event sources.
Definition: res_stasis.c:2165
enum stasis_app_subscribe_res(* app_subscription_handler)(struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
Definition: res_stasis.c:2001
struct stasis_message_sanitizer app_sanitizer
Sanitization callbacks for communication to Stasis applications.
Definition: res_stasis.c:2337
static enum stasis_app_subscribe_res app_handle_subscriptions(const char *app_name, const char **event_source_uris, int event_sources_count, struct ast_json **json, app_subscription_handler handler)
Definition: res_stasis.c:2018
struct stasis_app * stasis_app_get_by_name(const char *name)
Retrieve a handle to a Stasis application by its name.
Definition: res_stasis.c:1742
static struct ast_json * app_event_sources_to_json(const struct stasis_app *app, struct ast_json *json)
Definition: res_stasis.c:1929
static int bridges_sort(const void *left, const void *right, const int flags)
Definition: res_stasis.c:418
struct stasis_app_control * stasis_app_control_find_by_channel_id(const char *channel_id)
Returns the handler for the channel with the given id.
Definition: res_stasis.c:349
static const struct ast_datastore_info masquerade_store_info
Definition: res_stasis.c:1250
static int cleanup_cb(void *obj, void *arg, int flags)
Definition: res_stasis.c:309
static int bridges_channel_sort_fn(const void *obj_left, const void *obj_right, const int flags)
Definition: res_stasis.c:509
static void * moh_channel_thread(void *data)
Definition: res_stasis.c:555
void stasis_app_register_event_source(struct stasis_app_event_source *obj)
Register an application event source.
Definition: res_stasis.c:1895
struct ast_channel * stasis_app_bridge_playback_channel_find(struct ast_bridge *bridge)
Finds an existing ARI playback channel in a bridge.
Definition: res_stasis.c:785
struct ao2_container * stasis_app_get_all(void)
Gets the names of all registered Stasis applications.
Definition: res_stasis.c:1769
#define MAX_WAIT_MS
Definition: res_stasis.c:77
int stasis_app_control_is_done(struct stasis_app_control *control)
Check if a control is marked as done.
Definition: res_stasis.c:1318
static int bridges_channel_compare(void *obj, void *arg, int flags)
Definition: res_stasis.c:455
static int load_module(void)
Definition: res_stasis.c:2416
static void remove_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1281
static void remove_bridge_playback(char *bridge_id)
Definition: res_stasis.c:699
static int unload_module(void)
Definition: res_stasis.c:2274
static int masq_match_cb(void *obj, void *data, int flags)
Definition: res_stasis.c:1160
static struct ast_bridge * bridge_create_common(const char *type, const char *name, const char *id, int invisible)
Definition: res_stasis.c:821
struct ast_datastore_info set_end_published_info
Definition: res_stasis.c:1328
struct ao2_container * apps_registry
Stasis application container.
Definition: res_stasis.c:100
static struct stasis_app_event_source * app_event_source_find(const char *uri)
Definition: res_stasis.c:1976
static int channel_id_sanitizer(const char *id)
Sanitization callback for channel unique IDs.
Definition: res_stasis.c:2324
static void control_unlink(struct stasis_app_control *control)
In addition to running ao2_cleanup(), this function also removes the object from the app_controls con...
Definition: res_stasis.c:811
static struct replace_channel_store * get_replace_channel_store(struct ast_channel *chan, int no_create)
Definition: res_stasis.c:935
int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan)
Has this channel had a StasisEnd published on it?
Definition: res_stasis.c:1344
static struct ast_json * stasis_end_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
Definition: res_stasis.c:115
static int bridges_channel_hash_fn(const void *obj, const int flags)
Definition: res_stasis.c:488
struct stasis_app_control * stasis_app_control_find_by_channel(const struct ast_channel *chan)
Returns the handler for the given channel.
Definition: res_stasis.c:338
char * app_get_replace_channel_app(struct ast_channel *chan)
Get the app that the replacement channel will be controlled by.
Definition: res_stasis.c:1012
int stasis_app_register_all(const char *app_name, stasis_app_cb handler, void *data)
Register a new Stasis application that receives all Asterisk events.
Definition: res_stasis.c:1843
static struct ast_json * stasis_start_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
Definition: res_stasis.c:147
static int control_compare(void *obj, void *arg, int flags)
Definition: res_stasis.c:270
struct stasis_app_control * stasis_app_control_create(struct ast_channel *chan)
Creates a control handler for a channel that isn't in a stasis app.
Definition: res_stasis.c:333
int stasis_app_bridge_moh_stop(struct ast_bridge *bridge)
Breaks down MOH channels playing on the bridge created by stasis_app_bridge_moh_channel.
Definition: res_stasis.c:675
#define NULL
Definition: resample.c:96
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1538
const char * stasis_app_control_get_channel_id(const struct stasis_app_control *control)
Returns the uniqueid of the channel associated with this control.
Definition: control.c:1460
struct stasis_topic * ast_app_get_topic(struct stasis_app *app)
Returns the stasis topic for an app.
void stasis_app_unregister_event_sources(void)
Unregister core event sources.
int stasis_app_control_is_failed(const struct stasis_app_control *control)
Check if a control object is marked as "failed".
Definition: control.c:382
stasis_app_user_event_res
Return code for stasis_app_user_event.
Definition: stasis_app.h:265
@ STASIS_APP_USER_APP_NOT_FOUND
Definition: stasis_app.h:267
@ STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND
Definition: stasis_app.h:268
@ STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME
Definition: stasis_app.h:269
@ STASIS_APP_USER_OK
Definition: stasis_app.h:266
@ STASIS_APP_USER_INTERNAL_ERROR
Definition: stasis_app.h:271
struct ast_json * stasis_app_event_filter_to_json(struct stasis_app *app, struct ast_json *json)
Convert and add the app's event type filter(s) to the given json object.
void stasis_app_register_event_sources(void)
Register core event sources.
void(* stasis_app_cb)(void *data, const char *app_name, struct ast_json *message)
Callback for Stasis application handler.
Definition: stasis_app.h:67
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition: control.c:957
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application's name.
stasis_app_subscribe_res
Return code for stasis_app_[un]subscribe.
Definition: stasis_app.h:292
@ STASIS_ASR_OK
Definition: stasis_app.h:293
@ STASIS_ASR_EVENT_SOURCE_BAD_SCHEME
Definition: stasis_app.h:296
@ STASIS_ASR_INTERNAL_ERROR
Definition: stasis_app.h:297
@ STASIS_ASR_EVENT_SOURCE_NOT_FOUND
Definition: stasis_app.h:295
@ STASIS_ASR_APP_NOT_FOUND
Definition: stasis_app.h:294
void stasis_app_control_shutdown(void)
Let Stasis app internals shut down.
Definition: control.c:1710
Backend API for implementing components of res_stasis.
struct ast_bridge * bridge_stasis_new(uint32_t capabilities, unsigned int flags, const char *name, const char *id, enum ast_bridge_video_mode_type video_mode, unsigned int send_sdp_label)
void bridge_stasis_init(void)
Internal API for the Stasis bridge subclass.
#define STASIS_BRIDGE_MIXING_CAPABILITIES
Definition: stasis_bridge.h:39
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *bridge_id)
Returns the current snapshot for the bridge.
struct ast_json * ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_channel_snapshot.
Endpoint abstractions.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
Definition: strings.h:1365
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition: strings.h:97
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
Definition: strings.c:205
Generic container type.
Registered applications container.
Definition: pbx_app.c:68
Structure that contains information about a bridge.
Definition: bridge.h:353
const ast_string_field uniqueid
Definition: bridge.h:405
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
const ast_string_field uniqueid
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_base * base
Main Channel structure associated with a channel.
struct ast_bridge * bridge
const char * data
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Data structure associated with a single frame of data.
Abstract JSON element (object, array, string, int, ...).
A multi object blob data structure to carry user event stasis messages.
Definition: stasis.c:1977
Options for ast_pbx_run()
Definition: pbx.h:408
unsigned int no_hangup_chan
Definition: pbx.h:415
The base pvt structure for local channel derivatives.
Definition: core_unreal.h:91
struct ast_channel * chan
Definition: core_unreal.h:94
struct ast_channel_snapshot * snapshot
Definition: res_stasis.c:917
struct ast_channel_snapshot * replace_channel
Definition: res_stasis.c:143
struct ast_channel_snapshot * channel
Definition: res_stasis.c:142
struct ast_json * blob
Definition: res_stasis.c:144
const ast_string_field bridge_id
Definition: res_stasis.c:451
const ast_string_field channel_id
Definition: res_stasis.c:451
struct ast_bridge * bridge
Definition: control.c:67
Event source information and callbacks.
Definition: stasis_app.h:184
const char * scheme
The scheme to match against on [un]subscribes.
Definition: stasis_app.h:186
int(* unsubscribe)(struct stasis_app *app, const char *id)
Cancel the subscription an app has to an event source.
Definition: stasis_app.h:216
void(* to_json)(const struct stasis_app *app, struct ast_json *json)
Convert event source data to json.
Definition: stasis_app.h:234
struct stasis_app_event_source * next
Definition: stasis_app.h:237
void *(* find)(const struct stasis_app *app, const char *id)
Find an event source data object by the given id/name.
Definition: stasis_app.h:196
int(* is_subscribed)(struct stasis_app *app, const char *id)
Find an event source by the given id/name.
Definition: stasis_app.h:226
int(* subscribe)(struct stasis_app *app, void *obj)
Subscribe an application to an event source.
Definition: stasis_app.h:206
Structure containing callbacks for Stasis message sanitization.
Definition: stasis.h:200
int(* channel)(const struct ast_channel *chan)
Callback which determines whether a channel should be sanitized from a message based on the channel.
Definition: stasis.h:232
int(* channel_snapshot)(const struct ast_channel_snapshot *snapshot)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Definition: stasis.h:221
int(* channel_id)(const char *channel_id)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Definition: stasis.h:210
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:588
#define AST_UUID_STR_LEN
Definition: uuid.h:27