Asterisk - The Open Source Telephony Project GIT-master-f36a736
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/*!
418 * Used with app_bridges_moh and app_bridge_control, they provide links
419 * between bridges and channels used for ARI application purposes
420 */
425 );
426};
427
428/*! AO2 comparison function for bridges moh container */
429static int bridges_channel_compare(void *obj, void *arg, int flags)
430{
431 const struct stasis_app_bridge_channel_wrapper *object_left = obj;
432 const struct stasis_app_bridge_channel_wrapper *object_right = arg;
433 const char *right_key = arg;
434 int cmp;
435
436 switch (flags & OBJ_SEARCH_MASK) {
438 right_key = object_right->bridge_id;
439 case OBJ_SEARCH_KEY:
440 cmp = strcmp(object_left->bridge_id, right_key);
441 break;
443 cmp = strncmp(object_left->bridge_id, right_key, strlen(right_key));
444 break;
445 default:
446 cmp = 0;
447 break;
448 }
449 if (cmp) {
450 return 0;
451 }
452 return CMP_MATCH;
453}
454
456{
457 struct stasis_app_bridge_channel_wrapper *wrapper = obj;
459}
460
461/*! AO2 hash function for the bridges moh container */
462static int bridges_channel_hash_fn(const void *obj, const int flags)
463{
464 const struct stasis_app_bridge_channel_wrapper *wrapper;
465 const char *key;
466
467 switch (flags & OBJ_SEARCH_MASK) {
468 case OBJ_SEARCH_KEY:
469 key = obj;
470 break;
472 wrapper = obj;
473 key = wrapper->bridge_id;
474 break;
475 default:
476 /* Hash can only work on something with a full key. */
477 ast_assert(0);
478 return 0;
479 }
480 return ast_str_hash(key);
481}
482
483static int bridges_channel_sort_fn(const void *obj_left, const void *obj_right, const int flags)
484{
485 const struct stasis_app_bridge_channel_wrapper *left = obj_left;
486 const struct stasis_app_bridge_channel_wrapper *right = obj_right;
487 const char *right_key = obj_right;
488 int cmp;
489
490 switch (flags & OBJ_SEARCH_MASK) {
492 right_key = right->bridge_id;
493 /* Fall through */
494 case OBJ_SEARCH_KEY:
495 cmp = strcmp(left->bridge_id, right_key);
496 break;
498 cmp = strncmp(left->bridge_id, right_key, strlen(right_key));
499 break;
500 default:
501 /* Sort can only work on something with a full or partial key. */
502 ast_assert(0);
503 cmp = 0;
504 break;
505 }
506 return cmp;
507}
508
509/*! Request a bridge MOH channel */
511{
512 struct ast_channel *chan;
513 struct ast_format_cap *cap;
514
516 if (!cap) {
517 return NULL;
518 }
519
521
522 chan = ast_request("Announcer", cap, NULL, NULL, "ARI_MOH", NULL);
523 ao2_ref(cap, -1);
524
525 return chan;
526}
527
528/*! Provides the moh channel with a thread so it can actually play its music */
529static void *moh_channel_thread(void *data)
530{
531 struct stasis_app_bridge_channel_wrapper *moh_wrapper = data;
532 struct ast_channel *moh_channel = ast_channel_get_by_name(moh_wrapper->channel_id);
533 struct ast_frame *f;
534
535 if (!moh_channel) {
536 ao2_unlink(app_bridges_moh, moh_wrapper);
537 ao2_ref(moh_wrapper, -1);
538 return NULL;
539 }
540
541 /* Read and discard any frame coming from the stasis bridge. */
542 for (;;) {
543 if (ast_waitfor(moh_channel, -1) < 0) {
544 /* Error or hungup */
545 break;
546 }
547
548 f = ast_read(moh_channel);
549 if (!f) {
550 /* Hungup */
551 break;
552 }
553 ast_frfree(f);
554 }
555
556 ao2_unlink(app_bridges_moh, moh_wrapper);
557 ao2_ref(moh_wrapper, -1);
558
559 ast_moh_stop(moh_channel);
560 ast_hangup(moh_channel);
561
562 return NULL;
563}
564
565/*!
566 * \internal
567 * \brief Creates, pushes, and links a channel for playing music on hold to bridge
568 *
569 * \param bridge Which bridge this moh channel exists for
570 *
571 * \retval NULL if the channel could not be created, pushed, or linked
572 * \retval Reference to the channel on success
573 */
575{
576 struct stasis_app_bridge_channel_wrapper *new_wrapper;
577 struct ast_channel *chan;
578 pthread_t threadid;
579
581 if (!chan) {
582 return NULL;
583 }
584
586 ast_hangup(chan);
587 return NULL;
588 }
589
592 ast_hangup(chan);
593 return NULL;
594 }
595
596 new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
598 if (!new_wrapper) {
599 ast_hangup(chan);
600 return NULL;
601 }
602
604 || ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid)
605 || ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan))) {
606 ao2_ref(new_wrapper, -1);
607 ast_hangup(chan);
608 return NULL;
609 }
610
611 if (!ao2_link_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK)) {
612 ao2_ref(new_wrapper, -1);
613 ast_hangup(chan);
614 return NULL;
615 }
616
617 /* Pass the new_wrapper ref to moh_channel_thread() */
618 if (ast_pthread_create_detached(&threadid, NULL, moh_channel_thread, new_wrapper)) {
619 ast_log(LOG_ERROR, "Failed to create channel thread. Abandoning MOH channel creation.\n");
621 ao2_ref(new_wrapper, -1);
622 ast_hangup(chan);
623 return NULL;
624 }
625
626 return chan;
627}
628
630{
631 struct ast_channel *chan;
632 struct stasis_app_bridge_channel_wrapper *moh_wrapper;
633
635 moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_NOLOCK);
636 if (!moh_wrapper) {
637 chan = bridge_moh_create(bridge);
638 }
640
641 if (moh_wrapper) {
642 chan = ast_channel_get_by_name(moh_wrapper->channel_id);
643 ao2_ref(moh_wrapper, -1);
644 }
645
646 return chan;
647}
648
650{
651 struct stasis_app_bridge_channel_wrapper *moh_wrapper;
652 struct ast_channel *chan;
653
655 if (!moh_wrapper) {
656 return -1;
657 }
658
659 chan = ast_channel_get_by_name(moh_wrapper->channel_id);
660 ao2_ref(moh_wrapper, -1);
661 if (!chan) {
662 return -1;
663 }
664
665 ast_moh_stop(chan);
667 ao2_cleanup(chan);
668
669 return 0;
670}
671
672/*! Removes the bridge to playback channel link */
673static void remove_bridge_playback(char *bridge_id)
674{
675 struct stasis_app_bridge_channel_wrapper *wrapper;
676 struct stasis_app_control *control;
677
679
680 if (wrapper) {
682 if (control) {
683 ao2_unlink(app_controls, control);
684 ao2_ref(control, -1);
685 }
686 ao2_ref(wrapper, -1);
687 }
688 ast_free(bridge_id);
689}
690
692{
693 char *bridge_id = data;
694
695 remove_bridge_playback(bridge_id);
696}
697
698static void playback_after_bridge_cb(struct ast_channel *chan, void *data)
699{
700 char *bridge_id = data;
701
702 remove_bridge_playback(bridge_id);
703}
704
706 struct ast_channel *chan,
707 struct stasis_app_control *control)
708{
710 char *bridge_id = ast_strdup(bridge->uniqueid);
711
712 if (!bridge_id) {
713 return -1;
714 }
715
718 ast_free(bridge_id);
719 return -1;
720 }
721
722 new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
724 if (!new_wrapper) {
725 return -1;
726 }
727
728 if (ast_string_field_init(new_wrapper, 32)) {
729 return -1;
730 }
731
732 ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
733 ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
734
735 if (!ao2_link(app_bridges_playback, new_wrapper)) {
736 return -1;
737 }
738
739 ao2_link(app_controls, control);
740 return 0;
741}
742
744 struct stasis_app_control *control)
745{
746 struct stasis_app_bridge_channel_wrapper *wrapper;
747
749 if (wrapper) {
750 /* If wrapper is not found, then that means the after bridge callback has been
751 * called or is in progress. No need to unlink the control here since that has
752 * been done or is about to be done in the after bridge callback
753 */
754 ao2_unlink(app_controls, control);
755 ao2_ref(wrapper, -1);
756 }
757}
758
760{
761 struct stasis_app_bridge_channel_wrapper *playback_wrapper;
762 struct ast_channel *chan;
763
765 if (!playback_wrapper) {
766 return NULL;
767 }
768
769 chan = ast_channel_get_by_name(playback_wrapper->channel_id);
770 ao2_ref(playback_wrapper, -1);
771 return chan;
772}
773
775 const char *bridge_id)
776{
777 return ao2_find(app_bridges, bridge_id, OBJ_SEARCH_KEY);
778}
779
780
781/*!
782 * \brief In addition to running ao2_cleanup(), this function also removes the
783 * object from the app_controls container.
784 */
785static void control_unlink(struct stasis_app_control *control)
786{
787 if (!control) {
788 return;
789 }
790
791 ao2_unlink(app_controls, control);
792 ao2_cleanup(control);
793}
794
795static struct ast_bridge *bridge_create_common(const char *type, const char *name, const char *id, int invisible)
796{
797 struct ast_bridge *bridge;
798 char *requested_type, *requested_types = ast_strdupa(S_OR(type, "mixing"));
799 int capabilities = 0;
804 int send_sdp_label = 0;
805
806 if (invisible) {
808 }
809
810 while ((requested_type = strsep(&requested_types, ","))) {
811 requested_type = ast_strip(requested_type);
812
813 if (!strcmp(requested_type, "mixing")) {
814 capabilities |= STASIS_BRIDGE_MIXING_CAPABILITIES;
815 flags |= AST_BRIDGE_FLAG_SMART;
816 } else if (!strcmp(requested_type, "holding")) {
817 capabilities |= AST_BRIDGE_CAPABILITY_HOLDING;
818 } else if (!strcmp(requested_type, "dtmf_events") ||
819 !strcmp(requested_type, "proxy_media")) {
820 capabilities &= ~AST_BRIDGE_CAPABILITY_NATIVE;
821 } else if (!strcmp(requested_type, "video_sfu")) {
822 video_mode = AST_BRIDGE_VIDEO_MODE_SFU;
823 } else if (!strcmp(requested_type, "video_single")) {
825 } else if (!strcmp(requested_type, "sdp_label")) {
826 send_sdp_label = 1;
827 }
828 }
829
830 /* For an SFU video bridge we ensure it always remains in multimix for the best experience. */
831 if (video_mode == AST_BRIDGE_VIDEO_MODE_SFU) {
832 capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX;
833 flags &= ~AST_BRIDGE_FLAG_SMART;
834 }
835
836 if (!capabilities
837 /* Holding and mixing capabilities don't mix. */
838 || ((capabilities & AST_BRIDGE_CAPABILITY_HOLDING)
839 && (capabilities & (STASIS_BRIDGE_MIXING_CAPABILITIES)))) {
840 return NULL;
841 }
842
843 bridge = bridge_stasis_new(capabilities, flags, name, id, video_mode, send_sdp_label);
844 if (bridge) {
845 if (!ao2_link(app_bridges, bridge)) {
846 ast_bridge_destroy(bridge, 0);
847 bridge = NULL;
848 }
849 }
850
851 return bridge;
852}
853
854struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id)
855{
856 return bridge_create_common(type, name, id, 0);
857}
858
859struct ast_bridge *stasis_app_bridge_create_invisible(const char *type, const char *name, const char *id)
860{
861 return bridge_create_common(type, name, id, 1);
862}
863
864void stasis_app_bridge_destroy(const char *bridge_id)
865{
866 struct ast_bridge *bridge = stasis_app_bridge_find_by_id(bridge_id);
867 if (!bridge) {
868 return;
869 }
870 ao2_unlink(app_bridges, bridge);
871 ast_bridge_destroy(bridge, 0);
872}
873
876 char *app;
877};
878
879static void replace_channel_destroy(void *obj)
880{
881 struct replace_channel_store *replace = obj;
882
883 ao2_cleanup(replace->snapshot);
884 ast_free(replace->app);
886}
887
889 .type = "replace-channel-store",
890 .destroy = replace_channel_destroy,
891};
892
893static struct replace_channel_store *get_replace_channel_store(struct ast_channel *chan, int no_create)
894{
895 struct ast_datastore *datastore;
896 struct replace_channel_store *ret;
897
898 ast_channel_lock(chan);
900 if (!datastore && !no_create) {
902 if (datastore) {
903 ast_channel_datastore_add(chan, datastore);
904 }
905 }
906
907 if (!datastore) {
908 ast_channel_unlock(chan);
909 return NULL;
910 }
911
912 if (!datastore->data) {
913 datastore->data = ast_calloc(1, sizeof(struct replace_channel_store));
914 }
915
916 ret = datastore->data;
917 ast_channel_unlock(chan);
918
919 return ret;
920}
921
922int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot)
923{
925
926 if (!replace) {
927 return -1;
928 }
929
930 ao2_replace(replace->snapshot, replace_snapshot);
931 return 0;
932}
933
934int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app)
935{
937
938 if (!replace) {
939 return -1;
940 }
941
942 ast_free(replace->app);
943 replace->app = NULL;
944
945 if (replace_app) {
946 replace->app = ast_strdup(replace_app);
947 if (!replace->app) {
948 return -1;
949 }
950 }
951
952 return 0;
953}
954
956{
958 struct ast_channel_snapshot *replace_channel_snapshot;
959
960 if (!replace) {
961 return NULL;
962 }
963
964 replace_channel_snapshot = replace->snapshot;
965 replace->snapshot = NULL;
966
967 return replace_channel_snapshot;
968}
969
971{
973 char *replace_channel_app;
974
975 if (!replace) {
976 return NULL;
977 }
978
979 replace_channel_app = replace->app;
980 replace->app = NULL;
981
982 return replace_channel_app;
983}
984
985static void start_message_blob_dtor(void *obj)
986{
987 struct start_message_blob *payload = obj;
988
989 ao2_cleanup(payload->channel);
991 ast_json_unref(payload->blob);
992}
993
994static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app *app,
995 int argc, char *argv[], struct ast_channel_snapshot *snapshot,
996 struct ast_channel_snapshot *replace_channel_snapshot)
997{
998 struct ast_json *json_blob;
999 struct ast_json *json_args;
1000 struct start_message_blob *payload;
1001 struct stasis_message *msg;
1002 int i;
1003
1004 if (app_subscribe_channel(app, chan)) {
1005 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
1007 return -1;
1008 }
1009
1010 payload = ao2_alloc(sizeof(*payload), start_message_blob_dtor);
1011 if (!payload) {
1012 ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
1013 return -1;
1014 }
1015
1016 payload->channel = ao2_bump(snapshot);
1017 payload->replace_channel = ao2_bump(replace_channel_snapshot);
1018
1019 json_blob = ast_json_pack("{s: s, s: o, s: []}",
1020 "app", stasis_app_name(app),
1021 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1022 "args");
1023 if (!json_blob) {
1024 ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
1025 ao2_ref(payload, -1);
1026 return -1;
1027 }
1028 payload->blob = json_blob;
1029
1030
1031 /* Append arguments to args array */
1032 json_args = ast_json_object_get(json_blob, "args");
1033 ast_assert(json_args != NULL);
1034 for (i = 0; i < argc; ++i) {
1035 int r = ast_json_array_append(json_args,
1036 ast_json_string_create(argv[i]));
1037 if (r != 0) {
1038 ast_log(LOG_ERROR, "Error appending to StasisStart message\n");
1039 ao2_ref(payload, -1);
1040 return -1;
1041 }
1042 }
1043
1044
1045 msg = stasis_message_create(start_message_type(), payload);
1046 ao2_ref(payload, -1);
1047 if (!msg) {
1048 ast_log(LOG_ERROR, "Error sending StasisStart message\n");
1049 return -1;
1050 }
1051
1052 if (replace_channel_snapshot) {
1053 app_unsubscribe_channel_id(app, replace_channel_snapshot->base->uniqueid);
1054 }
1056 ao2_ref(msg, -1);
1057 return 0;
1058}
1059
1060static int send_start_msg(struct stasis_app *app, struct ast_channel *chan,
1061 int argc, char *argv[])
1062{
1063 int ret = -1;
1064 struct ast_channel_snapshot *snapshot;
1065 struct ast_channel_snapshot *replace_channel_snapshot;
1066
1067 ast_assert(chan != NULL);
1068
1069 replace_channel_snapshot = get_replace_channel_snapshot(chan);
1070
1071 /* Set channel info */
1072 ast_channel_lock(chan);
1073 snapshot = ast_channel_snapshot_create(chan);
1074 ast_channel_unlock(chan);
1075 if (snapshot) {
1076 ret = send_start_msg_snapshots(chan, app, argc, argv, snapshot, replace_channel_snapshot);
1077 ao2_ref(snapshot, -1);
1078 }
1079 ao2_cleanup(replace_channel_snapshot);
1080
1081 return ret;
1082}
1083
1084static void remove_masquerade_store(struct ast_channel *chan);
1085
1086int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
1087{
1089 struct ast_json *blob;
1090 struct stasis_message *msg;
1091
1092 if (sanitize && sanitize->channel
1093 && sanitize->channel(chan)) {
1094 return 0;
1095 }
1096
1097 blob = ast_json_pack("{s: s, s: o}",
1098 "app", stasis_app_name(app),
1099 "timestamp", ast_json_timeval(ast_tvnow(), NULL)
1100 );
1101 if (!blob) {
1102 ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n");
1103 return -1;
1104 }
1105
1108 msg = ast_channel_blob_create(chan, end_message_type(), blob);
1109 if (msg) {
1111 }
1112 ao2_cleanup(msg);
1113 ast_json_unref(blob);
1114
1115 return 0;
1116}
1117
1118static int masq_match_cb(void *obj, void *data, int flags)
1119{
1120 struct stasis_app_control *control = obj;
1121 struct ast_channel *chan = data;
1122
1123 if (!strcmp(ast_channel_uniqueid(chan),
1125 return CMP_MATCH;
1126 }
1127
1128 return 0;
1129}
1130
1131static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1132{
1133 struct stasis_app_control *control;
1134
1135 /*
1136 * At this point, old_chan is the channel pointer that is in Stasis() and
1137 * has the unknown channel's name in it while new_chan is the channel pointer
1138 * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1139 * about.
1140 *
1141 * Find and unlink control since the channel has a new name/uniqueid
1142 * and its hash has changed. Since the channel is leaving stasis don't
1143 * bother putting it back into the container. Nobody is going to
1144 * remove it from the container later.
1145 */
1146 control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, old_chan);
1147 if (!control) {
1148 ast_log(LOG_ERROR, "Could not find control for masqueraded channel\n");
1149 return;
1150 }
1151
1152 /* send the StasisEnd message to the app */
1154 app_send_end_msg(control_app(control), new_chan);
1155
1156 /* remove the datastore */
1157 remove_masquerade_store(old_chan);
1158
1159 ao2_cleanup(control);
1160}
1161
1162static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1163{
1164 RAII_VAR(struct ast_channel_snapshot *, new_snapshot, NULL, ao2_cleanup);
1165 RAII_VAR(struct ast_channel_snapshot *, old_snapshot, NULL, ao2_cleanup);
1166 struct stasis_app_control *control;
1167
1168 /* At this point, new_chan is the channel pointer that is in Stasis() and
1169 * has the unknown channel's name in it while old_chan is the channel pointer
1170 * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1171 * about */
1172
1173 /* grab a snapshot for the channel that is jumping into Stasis() */
1174 new_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(new_chan));
1175 if (!new_snapshot) {
1176 ast_log(LOG_ERROR, "Could not get snapshot for masquerading channel\n");
1177 return;
1178 }
1179
1180 /* grab a snapshot for the channel that has been kicked out of Stasis() */
1181 old_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(old_chan));
1182 if (!old_snapshot) {
1183 ast_log(LOG_ERROR, "Could not get snapshot for masqueraded channel\n");
1184 return;
1185 }
1186
1187 /*
1188 * Find, unlink, and relink control since the channel has a new
1189 * name/uniqueid and its hash has changed.
1190 */
1191 control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, new_chan);
1192 if (!control) {
1193 ast_log(LOG_ERROR, "Could not find control for masquerading channel\n");
1194 return;
1195 }
1196 ao2_link(app_controls, control);
1197
1198
1199 /* send the StasisStart with replace_channel to the app */
1200 send_start_msg_snapshots(new_chan, control_app(control), 0, NULL, new_snapshot,
1201 old_snapshot);
1202 /* send the StasisEnd message to the app */
1203 app_send_end_msg(control_app(control), old_chan);
1204
1205 ao2_cleanup(control);
1206}
1207
1209 .type = "stasis-masquerade",
1210 .chan_fixup = channel_stolen_cb,
1211 .chan_breakdown = channel_replaced_cb,
1212};
1213
1214static int has_masquerade_store(struct ast_channel *chan)
1215{
1216 SCOPED_CHANNELLOCK(lock, chan);
1218}
1219
1220static int add_masquerade_store(struct ast_channel *chan)
1221{
1222 struct ast_datastore *datastore;
1223
1224 SCOPED_CHANNELLOCK(lock, chan);
1226 return 0;
1227 }
1228
1230 if (!datastore) {
1231 return -1;
1232 }
1233
1234 ast_channel_datastore_add(chan, datastore);
1235
1236 return 0;
1237}
1238
1239static void remove_masquerade_store(struct ast_channel *chan)
1240{
1241 struct ast_datastore *datastore;
1242
1243 SCOPED_CHANNELLOCK(lock, chan);
1245 if (!datastore) {
1246 return;
1247 }
1248
1249 ast_channel_datastore_remove(chan, datastore);
1250 ast_datastore_free(datastore);
1251}
1252
1254{
1255 while (!control_is_done(control)) {
1256 int command_count;
1257 command_count = control_dispatch_all(control, chan);
1258
1259 ao2_lock(control);
1260
1261 if (control_command_count(control)) {
1262 /* If the command queue isn't empty, something added to the queue before it was locked. */
1263 ao2_unlock(control);
1264 continue;
1265 }
1266
1267 if (command_count == 0 || ast_channel_fdno(chan) == -1) {
1268 control_mark_done(control);
1269 ao2_unlock(control);
1270 break;
1271 }
1272 ao2_unlock(control);
1273 }
1274}
1275
1277{
1278 return control_is_done(control);
1279}
1280
1282{
1283 control_flush_queue(control);
1284}
1285
1287 .type = "stasis_end_published",
1288};
1289
1291{
1292 struct ast_datastore *datastore;
1293
1295 if (datastore) {
1296 ast_channel_lock(chan);
1297 ast_channel_datastore_add(chan, datastore);
1298 ast_channel_unlock(chan);
1299 }
1300}
1301
1303{
1304 struct ast_datastore *datastore;
1305
1306 ast_channel_lock(chan);
1308 ast_channel_unlock(chan);
1309
1310 return datastore ? 1 : 0;
1311}
1312
1314{
1315 struct ast_datastore *datastore;
1316
1317 ast_channel_lock(chan);
1319 if (datastore) {
1320 ast_channel_datastore_remove(chan, datastore);
1321 ast_datastore_free(datastore);
1322 }
1323 ast_channel_unlock(chan);
1324}
1325
1326/*! \brief Stasis dialplan application callback */
1327int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
1328 char *argv[])
1329{
1330 RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1331 RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
1332 struct ast_bridge *bridge = NULL;
1333 int res = 0;
1334 int needs_depart;
1335
1336 ast_assert(chan != NULL);
1337
1338 /* Just in case there's a lingering indication that the channel has had a stasis
1339 * end published on it, remove that now.
1340 */
1342
1343 if (!apps_registry) {
1344 return -1;
1345 }
1346
1348 if (!app) {
1350 "Stasis app '%s' not registered\n", app_name);
1351 return -1;
1352 }
1353 if (!app_is_active(app)) {
1355 "Stasis app '%s' not active\n", app_name);
1356 return -1;
1357 }
1358
1359 control = control_create(chan, app);
1360 if (!control) {
1361 ast_log(LOG_ERROR, "Control allocation failed or Stasis app '%s' not registered\n", app_name);
1362 return -1;
1363 }
1364
1365 if (!control_app(control)) {
1366 ast_log(LOG_ERROR, "Stasis app '%s' not registered\n", app_name);
1367 return -1;
1368 }
1369
1370 if (!app_is_active(control_app(control))) {
1371 ast_log(LOG_ERROR, "Stasis app '%s' not active\n", app_name);
1372 return -1;
1373 }
1374 ao2_link(app_controls, control);
1375
1376 if (add_masquerade_store(chan)) {
1377 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1378 return -1;
1379 }
1380
1381 res = send_start_msg(control_app(control), chan, argc, argv);
1382 if (res != 0) {
1384 "Error sending start message to '%s'\n", app_name);
1386 return -1;
1387 }
1388
1389 /* Pull queued prestart commands and execute */
1390 control_prestart_dispatch_all(control, chan);
1391
1392 while (!control_is_done(control)) {
1393 RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
1394 int r;
1395 int command_count;
1396 RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup);
1397
1398 /* Check to see if a bridge absorbed our hangup frame */
1399 if (ast_check_hangup_locked(chan)) {
1400 control_mark_done(control);
1401 break;
1402 }
1403
1404 /* control->next_app is only modified within the control thread, so this is safe */
1405 if (control_next_app(control)) {
1406 struct stasis_app *next_app = ao2_find(apps_registry, control_next_app(control), OBJ_SEARCH_KEY);
1407
1408 if (next_app && app_is_active(next_app)) {
1409 int idx;
1410 int next_argc;
1411 char **next_argv;
1412
1413 /* If something goes wrong in this conditional, res will need to be non-zero
1414 * so that the code below the exec loop knows something went wrong during a move.
1415 */
1417 res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1418 if (res != 0) {
1420 "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1421 control_mark_done(control);
1422 ao2_ref(next_app, -1);
1423 break;
1424 }
1425 } else {
1427 }
1428
1429 /* This will ao2_bump next_app, and unref the previous app by 1 */
1430 control_set_app(control, next_app);
1431
1432 /* There's a chance that the previous application is ready for clean up, so go ahead
1433 * and do that now.
1434 */
1435 cleanup();
1436
1437 /* We need to add another masquerade store, otherwise the leave message will
1438 * not show up for the correct application.
1439 */
1440 if (add_masquerade_store(chan)) {
1441 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1442 res = -1;
1443 control_mark_done(control);
1444 ao2_ref(next_app, -1);
1445 break;
1446 }
1447
1448 /* We MUST get the size before the list, as control_next_app_args steals the elements
1449 * from the string vector.
1450 */
1451 next_argc = control_next_app_args_size(control);
1452 next_argv = control_next_app_args(control);
1453
1454 res = send_start_msg(control_app(control), chan, next_argc, next_argv);
1455
1456 /* Even if res != 0, we still need to free the memory we got from control_argv */
1457 if (next_argv) {
1458 for (idx = 0; idx < next_argc; idx++) {
1459 ast_free(next_argv[idx]);
1460 }
1461 ast_free(next_argv);
1462 }
1463
1464 if (res != 0) {
1466 "Error sending start message to '%s'\n", stasis_app_name(control_app(control)));
1468 control_mark_done(control);
1469 ao2_ref(next_app, -1);
1470 break;
1471 }
1472
1473 /* Done switching applications, free memory and clean up */
1474 control_move_cleanup(control);
1475 } else {
1476 /* If we can't switch applications, do nothing */
1477 struct ast_json *msg;
1478 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1479
1480 if (!next_app) {
1481 ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not registered\n",
1482 control_next_app(control));
1483 } else {
1484 ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not active\n",
1485 control_next_app(control));
1486 }
1487
1489 if (!snapshot) {
1490 ast_log(LOG_ERROR, "Could not get channel shapshot for '%s'\n",
1491 ast_channel_name(chan));
1492 } else {
1493 struct ast_json *json_args;
1494 int next_argc = control_next_app_args_size(control);
1495 char **next_argv = control_next_app_args(control);
1496
1497 msg = ast_json_pack("{s: s, s: o, s: o, s: s, s: []}",
1498 "type", "ApplicationMoveFailed",
1499 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1500 "channel", ast_channel_snapshot_to_json(snapshot, NULL),
1501 "destination", control_next_app(control),
1502 "args");
1503 if (!msg) {
1504 ast_log(LOG_ERROR, "Failed to pack JSON for ApplicationMoveFailed message\n");
1505 } else {
1506 json_args = ast_json_object_get(msg, "args");
1507 if (!json_args) {
1508 ast_log(LOG_ERROR, "Could not get args json array");
1509 } else {
1510 int r = 0;
1511 int idx;
1512 for (idx = 0; idx < next_argc; ++idx) {
1513 r = ast_json_array_append(json_args,
1514 ast_json_string_create(next_argv[idx]));
1515 if (r != 0) {
1516 ast_log(LOG_ERROR, "Error appending to ApplicationMoveFailed message\n");
1517 break;
1518 }
1519 }
1520 if (r == 0) {
1521 app_send(control_app(control), msg);
1522 }
1523 }
1524 ast_json_unref(msg);
1525 }
1526 }
1527 }
1528 control_move_cleanup(control);
1529 ao2_cleanup(next_app);
1530 }
1531
1532 last_bridge = bridge;
1533 bridge = ao2_bump(stasis_app_get_bridge(control));
1534
1535 if (bridge != last_bridge) {
1536 if (last_bridge) {
1537 app_unsubscribe_bridge(control_app(control), last_bridge);
1538 }
1539 if (bridge) {
1540 app_subscribe_bridge(control_app(control), bridge);
1541 }
1542 }
1543
1544 if (bridge) {
1545 /* Bridge/dial is handling channel frames */
1546 control_wait(control);
1547 control_dispatch_all(control, chan);
1548 continue;
1549 }
1550
1551 r = ast_waitfor(chan, MAX_WAIT_MS);
1552
1553 if (r < 0) {
1554 ast_debug(3, "%s: Poll error\n",
1555 ast_channel_uniqueid(chan));
1556 control_mark_done(control);
1557 break;
1558 }
1559
1560 command_count = control_dispatch_all(control, chan);
1561
1562 if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1563 /* Command drained the channel; wait for next frame */
1564 continue;
1565 }
1566
1567 if (r == 0) {
1568 /* Timeout */
1569 continue;
1570 }
1571
1572 f = ast_read(chan);
1573 if (!f) {
1574 /* Continue on in the dialplan */
1575 ast_debug(3, "%s: Hangup (no more frames)\n",
1576 ast_channel_uniqueid(chan));
1577 control_mark_done(control);
1578 break;
1579 }
1580
1581 if (f->frametype == AST_FRAME_CONTROL) {
1582 if (f->subclass.integer == AST_CONTROL_HANGUP) {
1583 /* Continue on in the dialplan */
1584 ast_debug(3, "%s: Hangup\n",
1585 ast_channel_uniqueid(chan));
1586 control_mark_done(control);
1587 break;
1588 }
1589 }
1590 }
1591
1592 ast_channel_lock(chan);
1593 needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1594 ast_channel_unlock(chan);
1595 if (needs_depart) {
1596 ast_bridge_depart(chan);
1597 }
1598
1599 if (stasis_app_get_bridge(control)) {
1601 }
1602 ao2_cleanup(bridge);
1603
1604 /* Only publish a stasis_end event if it hasn't already been published */
1605 if (!res && !stasis_app_channel_is_stasis_end_published(chan)) {
1606 /* A masquerade has occurred and this message will be wrong so it
1607 * has already been sent elsewhere. */
1608 res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1609 if (res != 0) {
1611 "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1612 return res;
1613 }
1614 } else {
1616 }
1617
1618 control_flush_queue(control);
1619
1620 /* Stop any lingering silence generator */
1621 control_silence_stop_now(control);
1622
1623 /* There's an off chance that app is ready for cleanup. Go ahead
1624 * and clean up, just in case
1625 */
1626 cleanup();
1627
1628 /* The control needs to be removed from the controls container in
1629 * case a new PBX is started and ends up coming back into Stasis.
1630 */
1631 control_unlink(control);
1632 control = NULL;
1633
1634 if (!res && !ast_channel_pbx(chan)) {
1635 int chan_hungup;
1636
1637 /* The ASYNCGOTO softhangup flag may have broken the channel out of
1638 * its bridge to run dialplan, so if there's no pbx on the channel
1639 * let it run dialplan here. Otherwise, it will run when this
1640 * application exits. */
1641 ast_channel_lock(chan);
1643 chan_hungup = ast_check_hangup(chan);
1644 ast_channel_unlock(chan);
1645
1646 if (!chan_hungup) {
1647 struct ast_pbx_args pbx_args;
1648
1649 memset(&pbx_args, 0, sizeof(pbx_args));
1650 pbx_args.no_hangup_chan = 1;
1651
1652 res = ast_pbx_run_args(chan, &pbx_args);
1653 }
1654 }
1655
1656 return res;
1657}
1658
1659int stasis_app_send(const char *app_name, struct ast_json *message)
1660{
1661 struct stasis_app *app;
1662
1663 if (!apps_registry) {
1664 return -1;
1665 }
1666
1668 if (!app) {
1669 /* XXX We can do a better job handling late binding, queueing up
1670 * the call for a few seconds to wait for the app to register.
1671 */
1673 "Stasis app '%s' not registered\n", app_name);
1674 return -1;
1675 }
1677 ao2_ref(app, -1);
1678
1679 return 0;
1680}
1681
1682static struct stasis_app *find_app_by_name(const char *app_name)
1683{
1684 struct stasis_app *res = NULL;
1685
1686 if (!apps_registry) {
1687 return NULL;
1688 }
1689
1690 if (!ast_strlen_zero(app_name)) {
1692 }
1693
1694 return res;
1695}
1696
1698{
1699 return find_app_by_name(name);
1700}
1701
1702static int append_name(void *obj, void *arg, int flags)
1703{
1704 struct stasis_app *app = obj;
1705 struct ao2_container *apps = arg;
1706
1708 return 0;
1709}
1710
1712{
1713 struct ao2_container *apps;
1714
1715 if (!apps_registry) {
1716 return NULL;
1717 }
1718
1720 if (!apps) {
1721 return NULL;
1722 }
1723
1725
1726 return apps;
1727}
1728
1729static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
1730{
1731 RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1732
1733 if (!apps_registry) {
1734 return -1;
1735 }
1736
1739 if (app) {
1740 /*
1741 * We need to unlock the apps_registry before calling app_update to
1742 * prevent the possibility of a deadlock with the session.
1743 */
1745 app_update(app, handler, data);
1746 cleanup();
1747 return 0;
1748 }
1749
1751 if (!app) {
1753 return -1;
1754 }
1755
1756 if (all_events) {
1757 struct stasis_app_event_source *source;
1758
1761 if (!source->subscribe) {
1762 continue;
1763 }
1764
1765 source->subscribe(app, NULL);
1766 }
1768 }
1770
1772
1773 /* We lazily clean up the apps_registry, because it's good enough to
1774 * prevent memory leaks, and we're lazy.
1775 */
1776 cleanup();
1777 return 0;
1778}
1779
1781{
1782 return __stasis_app_register(app_name, handler, data, 0);
1783}
1784
1786{
1787 return __stasis_app_register(app_name, handler, data, 1);
1788}
1789
1791{
1792 struct stasis_app *app;
1793
1794 if (!app_name) {
1795 return;
1796 }
1797
1798 if (!apps_registry) {
1799 return;
1800 }
1801
1803 if (!app) {
1805 "Stasis app '%s' not registered\n", app_name);
1806 return;
1807 }
1808
1810
1811 /* There's a decent chance that app is ready for cleanup. Go ahead
1812 * and clean up, just in case
1813 */
1814 cleanup();
1815
1816 ao2_ref(app, -1);
1817}
1818
1820{
1824}
1825
1827{
1828 struct stasis_app_event_source *source;
1829
1832 if (source == obj) {
1834 break;
1835 }
1836 }
1839}
1840
1841/*!
1842 * \internal
1843 * \brief Convert event source data to JSON.
1844 *
1845 * Calls each event source that has a "to_json" handler allowing each
1846 * source to add data to the given JSON object.
1847 *
1848 * \param app application associated with the event source
1849 * \param json a json object to "fill"
1850 *
1851 * \retval The given json object.
1852 */
1854 const struct stasis_app *app, struct ast_json *json)
1855{
1856 struct stasis_app_event_source *source;
1857
1860 if (source->to_json) {
1861 source->to_json(app, json);
1862 }
1863 }
1865
1866 return json;
1867}
1868
1870{
1871 if (!app) {
1872 return NULL;
1873 }
1874
1877}
1878
1880{
1882 struct ast_json *json = stasis_app_object_to_json(app);
1883
1885
1886 return json;
1887}
1888
1889/*!
1890 * \internal
1891 * \brief Finds an event source that matches a uri scheme.
1892 *
1893 * Uri(s) should begin with a particular scheme that can be matched
1894 * against an event source.
1895 *
1896 * \param uri uri containing a scheme to match
1897 *
1898 * \retval an event source if found, NULL otherwise.
1899 */
1900static struct stasis_app_event_source *app_event_source_find(const char *uri)
1901{
1902 struct stasis_app_event_source *source;
1903
1906 if (ast_begins_with(uri, source->scheme)) {
1907 break;
1908 }
1909 }
1911
1912 return source;
1913}
1914
1915/*!
1916 * \internal
1917 * \brief Callback for subscription handling
1918 *
1919 * \param app [un]subscribing application
1920 * \param uri scheme:id of an event source
1921 * \param event_source being [un]subscribed [from]to
1922 *
1923 * \retval stasis_app_subscribe_res return code.
1924 */
1926 struct stasis_app *app, const char *uri,
1927 struct stasis_app_event_source *event_source);
1928
1929/*!
1930 * \internal
1931 * \brief Subscriptions handler for application [un]subscribing.
1932 *
1933 * \param app_name Name of the application to subscribe.
1934 * \param event_source_uris URIs for the event sources to subscribe to.
1935 * \param event_sources_count Array size of event_source_uris.
1936 * \param json Optional output pointer for JSON representation of the app
1937 * after adding the subscription.
1938 * \param handler [un]subscribe handler
1939 *
1940 * \retval stasis_app_subscribe_res return code.
1941 */
1943 const char *app_name, const char **event_source_uris,
1944 int event_sources_count, struct ast_json **json,
1946{
1948 int i;
1949
1951
1952 if (!app) {
1954 }
1955
1956 for (i = 0; i < event_sources_count; ++i) {
1957 const char *uri = event_source_uris[i];
1958 struct stasis_app_event_source *event_source;
1959 enum stasis_app_subscribe_res res;
1960
1961 event_source = app_event_source_find(uri);
1962 if (!event_source) {
1963 ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
1964 ao2_ref(app, -1);
1965
1967 }
1968
1969 res = handler(app, uri, event_source);
1970 if (res != STASIS_ASR_OK) {
1971 ao2_ref(app, -1);
1972
1973 return res;
1974 }
1975 }
1976
1977 if (json) {
1978 ast_debug(3, "%s: Successful; setting results\n", app_name);
1980 }
1981
1982 ao2_ref(app, -1);
1983
1984 return STASIS_ASR_OK;
1985}
1986
1988 struct ast_channel *chan)
1989{
1991 int res;
1992
1993 if (!app) {
1995 }
1996
1997 ast_debug(3, "%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan));
1998
1999 res = app_subscribe_channel(app, chan);
2000 ao2_ref(app, -1);
2001
2002 if (res != 0) {
2003 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
2006 }
2007
2008 return STASIS_ASR_OK;
2009}
2010
2011
2012/*!
2013 * \internal
2014 * \brief Subscribe an app to an event source.
2015 *
2016 * \param app subscribing application
2017 * \param uri scheme:id of an event source
2018 * \param event_source being subscribed to
2019 *
2020 * \retval stasis_app_subscribe_res return code.
2021 */
2023 struct stasis_app *app, const char *uri,
2024 struct stasis_app_event_source *event_source)
2025{
2026 const char *app_name = stasis_app_name(app);
2027 RAII_VAR(void *, obj, NULL, ao2_cleanup);
2028
2029 ast_debug(3, "%s: Checking %s\n", app_name, uri);
2030
2031 if (!ast_strlen_zero(uri + strlen(event_source->scheme)) &&
2032 (!event_source->find || (!(obj = event_source->find(app, uri + strlen(event_source->scheme)))))) {
2033 ast_log(LOG_WARNING, "Event source not found: %s\n", uri);
2035 }
2036
2037 ast_debug(3, "%s: Subscribing to %s\n", app_name, uri);
2038
2039 if (!event_source->subscribe || (event_source->subscribe(app, obj))) {
2040 ast_log(LOG_WARNING, "Error subscribing app '%s' to '%s'\n",
2041 app_name, uri);
2043 }
2044
2045 return STASIS_ASR_OK;
2046}
2047
2049 const char **event_source_uris, int event_sources_count,
2050 struct ast_json **json)
2051{
2053 app_name, event_source_uris, event_sources_count,
2054 json, app_subscribe);
2055}
2056
2057/*!
2058 * \internal
2059 * \brief Unsubscribe an app from an event source.
2060 *
2061 * \param app application to unsubscribe
2062 * \param uri scheme:id of an event source
2063 * \param event_source being unsubscribed from
2064 *
2065 * \retval stasis_app_subscribe_res return code.
2066 */
2068 struct stasis_app *app, const char *uri,
2069 struct stasis_app_event_source *event_source)
2070{
2071 const char *app_name = stasis_app_name(app);
2072 const char *id = uri + strlen(event_source->scheme);
2073
2074 if (!event_source->is_subscribed ||
2075 (!event_source->is_subscribed(app, id))) {
2077 }
2078
2079 ast_debug(3, "%s: Unsubscribing from %s\n", app_name, uri);
2080
2081 if (!event_source->unsubscribe || (event_source->unsubscribe(app, id))) {
2082 ast_log(LOG_WARNING, "Error unsubscribing app '%s' to '%s'\n",
2083 app_name, uri);
2084 return -1;
2085 }
2086 return 0;
2087}
2088
2090 const char **event_source_uris, int event_sources_count,
2091 struct ast_json **json)
2092{
2094 app_name, event_source_uris, event_sources_count,
2095 json, app_unsubscribe);
2096}
2097
2099 const char *event_name,
2100 const char **source_uris, int sources_count,
2101 struct ast_json *json_variables)
2102{
2104 struct ast_json *blob = NULL;
2105 struct ast_multi_object_blob *multi;
2106 struct stasis_message *message;
2108 int have_channel = 0;
2109 int i;
2110
2111 if (!app) {
2112 ast_log(LOG_WARNING, "App %s not found\n", app_name);
2114 }
2115
2117 return res;
2118 }
2119
2120 if (json_variables) {
2121 struct ast_json *json_value = ast_json_string_create(event_name);
2122
2123 if (json_value && !ast_json_object_set(json_variables, "eventname", json_value)) {
2124 blob = ast_json_ref(json_variables);
2125 }
2126 } else {
2127 blob = ast_json_pack("{s: s}", "eventname", event_name);
2128 }
2129
2130 if (!blob) {
2131 ast_log(LOG_ERROR, "Failed to initialize blob\n");
2132
2133 return res;
2134 }
2135
2136 multi = ast_multi_object_blob_create(blob);
2137 ast_json_unref(blob);
2138 if (!multi) {
2139 ast_log(LOG_ERROR, "Failed to initialize multi\n");
2140
2141 return res;
2142 }
2143
2144 for (i = 0; i < sources_count; ++i) {
2145 const char *uri = source_uris[i];
2146 void *snapshot=NULL;
2148
2149 if (ast_begins_with(uri, "channel:")) {
2151 snapshot = ast_channel_snapshot_get_latest(uri + 8);
2152 have_channel = 1;
2153 } else if (ast_begins_with(uri, "bridge:")) {
2155 snapshot = ast_bridge_get_snapshot_by_uniqueid(uri + 7);
2156 } else if (ast_begins_with(uri, "endpoint:")) {
2158 snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL);
2159 } else {
2160 ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
2161 ao2_ref(multi, -1);
2162
2164 }
2165 if (!snapshot) {
2166 ast_log(LOG_ERROR, "Unable to get snapshot for %s\n", uri);
2167 ao2_ref(multi, -1);
2168
2170 }
2171 ast_multi_object_blob_add(multi, type, snapshot);
2172 }
2173
2175 ao2_ref(multi, -1);
2176
2177 if (!message) {
2178 ast_log(LOG_ERROR, "Unable to create stasis user event message\n");
2179 return res;
2180 }
2181
2182 /*
2183 * Publishing to two different topics is normally to be avoided -- except
2184 * in this case both are final destinations with no forwards (only listeners).
2185 * The message has to be delivered to the application topic for ARI, but a
2186 * copy is also delivered directly to the manager for AMI if there is a channel.
2187 */
2189
2190 if (have_channel) {
2192 }
2193 ao2_ref(message, -1);
2194
2195 return STASIS_APP_USER_OK;
2196}
2197
2198static int unload_module(void)
2199{
2201
2203
2204 cleanup();
2205
2207
2210
2213
2215 app_bridges = NULL;
2216
2219
2222
2223 STASIS_MESSAGE_TYPE_CLEANUP(end_message_type);
2224 STASIS_MESSAGE_TYPE_CLEANUP(start_message_type);
2225
2226 return 0;
2227}
2228
2229/*! \brief Sanitization callback for channel snapshots */
2230static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
2231{
2232 if (!snapshot || !(snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL)) {
2233 return 0;
2234 }
2235 return 1;
2236}
2237
2238/*! \brief Sanitization callback for channels */
2239static int channel_sanitizer(const struct ast_channel *chan)
2240{
2241 if (!chan || !(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)) {
2242 return 0;
2243 }
2244 return 1;
2245}
2246
2247/*! \brief Sanitization callback for channel unique IDs */
2248static int channel_id_sanitizer(const char *id)
2249{
2250 struct ast_channel_snapshot *snapshot;
2251 int ret;
2252
2253 snapshot = ast_channel_snapshot_get_latest(id);
2254 ret = channel_snapshot_sanitizer(snapshot);
2255 ao2_cleanup(snapshot);
2256
2257 return ret;
2258}
2259
2260/*! \brief Sanitization callbacks for communication to Stasis applications */
2263 .channel_snapshot = channel_snapshot_sanitizer,
2264 .channel = channel_sanitizer,
2265};
2266
2268{
2269 return &app_sanitizer;
2270}
2271
2273 .type = "stasis-internal-channel",
2274};
2275
2276static int set_internal_datastore(struct ast_channel *chan)
2277{
2278 struct ast_datastore *datastore;
2279
2281 if (!datastore) {
2283 if (!datastore) {
2284 return -1;
2285 }
2286 ast_channel_datastore_add(chan, datastore);
2287 }
2288 return 0;
2289}
2290
2292{
2293 struct ast_channel *outchan = NULL, *outowner = NULL;
2294 int res = 0;
2295 struct ast_unreal_pvt *unreal_pvt = ast_channel_tech_pvt(chan);
2296
2297 ao2_ref(unreal_pvt, +1);
2298 ast_unreal_lock_all(unreal_pvt, &outowner, &outchan);
2299 if (outowner) {
2300 res |= set_internal_datastore(outowner);
2301 ast_channel_unlock(outowner);
2302 ast_channel_unref(outowner);
2303 }
2304 if (outchan) {
2305 res |= set_internal_datastore(outchan);
2306 ast_channel_unlock(outchan);
2307 ast_channel_unref(outchan);
2308 }
2309 ao2_unlock(unreal_pvt);
2310 ao2_ref(unreal_pvt, -1);
2311 return res;
2312}
2313
2315{
2316 int res;
2317
2321
2322 return res;
2323}
2324
2326{
2327 struct ast_datastore *datastore;
2328 int res = 0;
2329
2330 ast_channel_lock(chan);
2332 if (datastore) {
2333 res = 1;
2334 }
2335 ast_channel_unlock(chan);
2336
2337 return res;
2338}
2339
2340static int load_module(void)
2341{
2342 if (STASIS_MESSAGE_TYPE_INIT(start_message_type) != 0) {
2344 }
2345 if (STASIS_MESSAGE_TYPE_INIT(end_message_type) != 0) {
2347 }
2361 unload_module();
2363 }
2364
2365 if (messaging_init()) {
2366 unload_module();
2368 }
2369
2371
2373
2375}
2376
2378 .load_pri = AST_MODPRI_APP_DEPEND - 1,
2379 .support_level = AST_MODULE_SUPPORT_CORE,
2380 .load = load_module,
2381 .unload = unload_module,
static const char app[]
Definition: app_adsiprog.c:56
ast_mutex_t lock
Definition: app_sla.c:331
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:1906
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition: bridge.c:944
@ AST_BRIDGE_CAPABILITY_MULTIMIX
Definition: bridge.h:94
@ AST_BRIDGE_CAPABILITY_HOLDING
Definition: bridge.h:86
ast_bridge_video_mode_type
Video source modes.
Definition: bridge.h:98
@ AST_BRIDGE_VIDEO_MODE_SINGLE_SRC
Definition: bridge.h:102
@ AST_BRIDGE_VIDEO_MODE_TALKER_SRC
Definition: bridge.h:105
@ AST_BRIDGE_VIDEO_MODE_SFU
Definition: bridge.h:109
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)
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:991
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:2404
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2413
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2451
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2560
int ast_channel_fdno(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2968
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3181
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:4276
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:2490
#define AST_CHANNEL_NAME
Definition: channel.h:173
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3004
@ AST_SOFTHANGUP_ASYNCGOTO
Definition: channel.h:1146
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:1473
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:6373
#define ast_channel_unlock(chan)
Definition: channel.h:2969
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:2418
struct stasis_app_control * control_create(struct ast_channel *channel, struct stasis_app *app)
Create a control object.
Definition: control.c:125
int control_prestart_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all queued prestart commands.
Definition: control.c:1544
void control_wait(struct stasis_app_control *control)
Blocks until control's command queue has a command available.
Definition: control.c:1524
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:1719
int control_is_done(struct stasis_app_control *control)
Returns true if control_continue() has been called on this control.
Definition: control.c:357
void control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: control.c:1491
int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all commands enqueued to this control.
Definition: control.c:1504
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:1724
void control_set_app(struct stasis_app_control *control, struct stasis_app *app)
Set the application the control object belongs to.
Definition: control.c:1700
int control_command_count(struct stasis_app_control *control)
Returns the count of items in a control's command queue.
Definition: control.c:352
void control_silence_stop_now(struct stasis_app_control *control)
Stop playing silence to a channel right now.
Definition: control.c:846
char * control_next_app(struct stasis_app_control *control)
Returns the name of the application we are moving to.
Definition: control.c:1706
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:1572
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:1711
void control_mark_done(struct stasis_app_control *control)
Definition: control.c:363
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:888
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:453
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:2002
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:1976
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
char * strsep(char **str, const char *delims)
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:619
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:7798
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:4735
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:743
struct ast_json * stasis_app_object_to_json(struct stasis_app *app)
Return the JSON representation of a Stasis application.
Definition: res_stasis.c:1869
static int send_start_msg(struct stasis_app *app, struct ast_channel *chan, int argc, char *argv[])
Definition: res_stasis.c:1060
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
Definition: res_stasis.c:2267
static void stasis_app_bridge_channel_wrapper_destructor(void *obj)
Definition: res_stasis.c:455
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:934
static struct ast_channel_snapshot * get_replace_channel_snapshot(struct ast_channel *chan)
Definition: res_stasis.c:955
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:1162
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:1682
#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:922
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:859
int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, char *argv[])
Stasis dialplan application callback.
Definition: res_stasis.c:1327
int stasis_app_channel_is_internal(struct ast_channel *chan)
Is this channel internal to Stasis?
Definition: res_stasis.c:2325
static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
Definition: res_stasis.c:1131
static struct ast_channel * bridge_moh_create(struct ast_bridge *bridge)
Definition: res_stasis.c:574
int stasis_app_send(const char *app_name, struct ast_json *message)
Send a message to the given Stasis application.
Definition: res_stasis.c:1659
static const struct ast_datastore_info replace_channel_store_info
Definition: res_stasis.c:888
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:985
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:2048
static void playback_after_bridge_cb(struct ast_channel *chan, void *data)
Definition: res_stasis.c:698
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:1290
void stasis_app_bridge_destroy(const char *bridge_id)
Destroy the bridge.
Definition: res_stasis.c:864
static int channel_sanitizer(const struct ast_channel *chan)
Sanitization callback for channels.
Definition: res_stasis.c:2239
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:691
struct ast_json * stasis_app_to_json(const char *app_name)
Return the JSON representation of a Stasis application.
Definition: res_stasis.c:1879
int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
Register a new Stasis application.
Definition: res_stasis.c:1780
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:2067
static void replace_channel_destroy(void *obj)
Definition: res_stasis.c:879
static void remove_stasis_end_published(struct ast_channel *chan)
Definition: res_stasis.c:1313
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:2230
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:2314
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:774
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:854
void stasis_app_unregister_event_source(struct stasis_app_event_source *obj)
Unregister an application event source.
Definition: res_stasis.c:1826
static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
Definition: res_stasis.c:1729
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:2022
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:1987
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:1253
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:994
static const struct ast_datastore_info stasis_internal_channel_info
Definition: res_stasis.c:2272
static int add_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1220
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:629
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:2098
#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:1214
int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
Send StasisEnd message to the listening app.
Definition: res_stasis.c:1086
void stasis_app_control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: res_stasis.c:1281
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:2291
static struct ast_channel * prepare_bridge_moh_channel(void)
Definition: res_stasis.c:510
static int set_internal_datastore(struct ast_channel *chan)
Definition: res_stasis.c:2276
#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:1702
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:705
void stasis_app_unregister(const char *app_name)
Unregister a Stasis application.
Definition: res_stasis.c:1790
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:2089
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:1925
struct stasis_message_sanitizer app_sanitizer
Sanitization callbacks for communication to Stasis applications.
Definition: res_stasis.c:2261
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:1942
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:1697
static struct ast_json * app_event_sources_to_json(const struct stasis_app *app, struct ast_json *json)
Definition: res_stasis.c:1853
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:1208
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:483
static void * moh_channel_thread(void *data)
Definition: res_stasis.c:529
void stasis_app_register_event_source(struct stasis_app_event_source *obj)
Register an application event source.
Definition: res_stasis.c:1819
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:759
struct ao2_container * stasis_app_get_all(void)
Gets the names of all registered Stasis applications.
Definition: res_stasis.c:1711
#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:1276
static int bridges_channel_compare(void *obj, void *arg, int flags)
Definition: res_stasis.c:429
static int load_module(void)
Definition: res_stasis.c:2340
static void remove_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1239
static void remove_bridge_playback(char *bridge_id)
Definition: res_stasis.c:673
static int unload_module(void)
Definition: res_stasis.c:2198
static int masq_match_cb(void *obj, void *data, int flags)
Definition: res_stasis.c:1118
static struct ast_bridge * bridge_create_common(const char *type, const char *name, const char *id, int invisible)
Definition: res_stasis.c:795
struct ast_datastore_info set_end_published_info
Definition: res_stasis.c:1286
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:1900
static int channel_id_sanitizer(const char *id)
Sanitization callback for channel unique IDs.
Definition: res_stasis.c:2248
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:785
static struct replace_channel_store * get_replace_channel_store(struct ast_channel *chan, int no_create)
Definition: res_stasis.c:893
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:1302
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:462
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:970
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:1785
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:649
#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:1512
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:1439
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.
stasis_app_user_event_res
Return code for stasis_app_user_event.
Definition: stasis_app.h:255
@ STASIS_APP_USER_APP_NOT_FOUND
Definition: stasis_app.h:257
@ STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND
Definition: stasis_app.h:258
@ STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME
Definition: stasis_app.h:259
@ STASIS_APP_USER_OK
Definition: stasis_app.h:256
@ STASIS_APP_USER_INTERNAL_ERROR
Definition: stasis_app.h:261
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:940
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:282
@ STASIS_ASR_OK
Definition: stasis_app.h:283
@ STASIS_ASR_EVENT_SOURCE_BAD_SCHEME
Definition: stasis_app.h:286
@ STASIS_ASR_INTERNAL_ERROR
Definition: stasis_app.h:287
@ STASIS_ASR_EVENT_SOURCE_NOT_FOUND
Definition: stasis_app.h:285
@ STASIS_ASR_APP_NOT_FOUND
Definition: stasis_app.h:284
void stasis_app_control_shutdown(void)
Let Stasis app internals shut down.
Definition: control.c:1689
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:67
Structure that contains information about a bridge.
Definition: bridge.h:349
const ast_string_field uniqueid
Definition: bridge.h:401
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:1951
Options for ast_pbx_run()
Definition: pbx.h:407
unsigned int no_hangup_chan
Definition: pbx.h:414
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:875
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:425
const ast_string_field channel_id
Definition: res_stasis.c:425
struct ast_bridge * bridge
Definition: control.c:66
Event source information and callbacks.
Definition: stasis_app.h:174
const char * scheme
The scheme to match against on [un]subscribes.
Definition: stasis_app.h:176
int(* unsubscribe)(struct stasis_app *app, const char *id)
Cancel the subscription an app has to an event source.
Definition: stasis_app.h:206
void(* to_json)(const struct stasis_app *app, struct ast_json *json)
Convert event source data to json.
Definition: stasis_app.h:224
struct stasis_app_event_source * next
Definition: stasis_app.h:227
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:186
int(* is_subscribed)(struct stasis_app *app, const char *id)
Find an event source by the given id/name.
Definition: stasis_app.h:216
int(* subscribe)(struct stasis_app *app, void *obj)
Subscribe an application to an event source.
Definition: stasis_app.h:196
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