Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
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 */
332
334{
335 return control_create(chan, NULL);
336}
337
339 const struct ast_channel *chan)
340{
341 if (chan == NULL) {
342 return NULL;
343 }
344
347}
348
350 const char *channel_id)
351{
352 return ao2_find(app_controls, channel_id, OBJ_SEARCH_KEY);
353}
354
355/*! AO2 hash function for bridges container */
356static int bridges_hash(const void *obj, const int flags)
357{
358 const struct ast_bridge *bridge;
359 const char *key;
360
361 switch (flags & OBJ_SEARCH_MASK) {
362 case OBJ_SEARCH_KEY:
363 key = obj;
364 break;
366 bridge = obj;
367 key = bridge->uniqueid;
368 break;
369 default:
370 /* Hash can only work on something with a full key. */
371 ast_assert(0);
372 return 0;
373 }
374 return ast_str_hash(key);
375}
376
377/*! AO2 comparison function for bridges container */
378static int bridges_compare(void *obj, void *arg, int flags)
379{
380 const struct ast_bridge *object_left = obj;
381 const struct ast_bridge *object_right = arg;
382 const char *right_key = arg;
383 int cmp;
384
385 switch (flags & OBJ_SEARCH_MASK) {
387 right_key = object_right->uniqueid;
388 /* Fall through */
389 case OBJ_SEARCH_KEY:
390 cmp = strcmp(object_left->uniqueid, right_key);
391 break;
393 /*
394 * We could also use a partial key struct containing a length
395 * so strlen() does not get called for every comparison instead.
396 */
397 cmp = strncmp(object_left->uniqueid, right_key, strlen(right_key));
398 break;
399 default:
400 /*
401 * What arg points to is specific to this traversal callback
402 * and has no special meaning to astobj2.
403 */
404 cmp = 0;
405 break;
406 }
407 if (cmp) {
408 return 0;
409 }
410 /*
411 * At this point the traversal callback is identical to a sorted
412 * container.
413 */
414 return CMP_MATCH;
415}
416
417/*! AO2 sort function for bridges container */
418static int bridges_sort (const void *left, const void *right, const int flags)
419{
420 const struct ast_bridge *object_left = left;
421 const struct ast_bridge *object_right = right;
422 const char *right_key = right;
423 int cmp;
424
425 switch (flags & OBJ_SEARCH_MASK) {
427 right_key = object_right->uniqueid;
428 /* Fall through */
429 case OBJ_SEARCH_KEY:
430 cmp = strcmp(object_left->uniqueid, right_key);
431 break;
433 cmp = strncmp(object_left->uniqueid, right_key, strlen(right_key));
434 break;
435 default:
436 ast_assert(0);
437 cmp = 0;
438 break;
439 }
440 return cmp;
441}
442
443/*!
444 * Used with app_bridges_moh and app_bridge_control, they provide links
445 * between bridges and channels used for ARI application purposes
446 */
453
454/*! AO2 comparison function for bridges moh container */
455static int bridges_channel_compare(void *obj, void *arg, int flags)
456{
457 const struct stasis_app_bridge_channel_wrapper *object_left = obj;
458 const struct stasis_app_bridge_channel_wrapper *object_right = arg;
459 const char *right_key = arg;
460 int cmp;
461
462 switch (flags & OBJ_SEARCH_MASK) {
464 right_key = object_right->bridge_id;
465 case OBJ_SEARCH_KEY:
466 cmp = strcmp(object_left->bridge_id, right_key);
467 break;
469 cmp = strncmp(object_left->bridge_id, right_key, strlen(right_key));
470 break;
471 default:
472 cmp = 0;
473 break;
474 }
475 if (cmp) {
476 return 0;
477 }
478 return CMP_MATCH;
479}
480
482{
483 struct stasis_app_bridge_channel_wrapper *wrapper = obj;
485}
486
487/*! AO2 hash function for the bridges moh container */
488static int bridges_channel_hash_fn(const void *obj, const int flags)
489{
490 const struct stasis_app_bridge_channel_wrapper *wrapper;
491 const char *key;
492
493 switch (flags & OBJ_SEARCH_MASK) {
494 case OBJ_SEARCH_KEY:
495 key = obj;
496 break;
498 wrapper = obj;
499 key = wrapper->bridge_id;
500 break;
501 default:
502 /* Hash can only work on something with a full key. */
503 ast_assert(0);
504 return 0;
505 }
506 return ast_str_hash(key);
507}
508
509static int bridges_channel_sort_fn(const void *obj_left, const void *obj_right, const int flags)
510{
511 const struct stasis_app_bridge_channel_wrapper *left = obj_left;
512 const struct stasis_app_bridge_channel_wrapper *right = obj_right;
513 const char *right_key = obj_right;
514 int cmp;
515
516 switch (flags & OBJ_SEARCH_MASK) {
518 right_key = right->bridge_id;
519 /* Fall through */
520 case OBJ_SEARCH_KEY:
521 cmp = strcmp(left->bridge_id, right_key);
522 break;
524 cmp = strncmp(left->bridge_id, right_key, strlen(right_key));
525 break;
526 default:
527 /* Sort can only work on something with a full or partial key. */
528 ast_assert(0);
529 cmp = 0;
530 break;
531 }
532 return cmp;
533}
534
535/*! Request a bridge MOH channel */
537{
538 struct ast_channel *chan;
539 struct ast_format_cap *cap;
540
542 if (!cap) {
543 return NULL;
544 }
545
547
548 chan = ast_request("Announcer", cap, NULL, NULL, "ARI_MOH", NULL);
549 ao2_ref(cap, -1);
550
551 return chan;
552}
553
554/*! Provides the moh channel with a thread so it can actually play its music */
555static void *moh_channel_thread(void *data)
556{
557 struct stasis_app_bridge_channel_wrapper *moh_wrapper = data;
558 struct ast_channel *moh_channel = ast_channel_get_by_name(moh_wrapper->channel_id);
559 struct ast_frame *f;
560
561 if (!moh_channel) {
562 ao2_unlink(app_bridges_moh, moh_wrapper);
563 ao2_ref(moh_wrapper, -1);
564 return NULL;
565 }
566
567 /* Read and discard any frame coming from the stasis bridge. */
568 for (;;) {
569 if (ast_waitfor(moh_channel, -1) < 0) {
570 /* Error or hungup */
571 break;
572 }
573
574 f = ast_read(moh_channel);
575 if (!f) {
576 /* Hungup */
577 break;
578 }
579 ast_frfree(f);
580 }
581
582 ao2_unlink(app_bridges_moh, moh_wrapper);
583 ao2_ref(moh_wrapper, -1);
584
585 ast_moh_stop(moh_channel);
586 ast_hangup(moh_channel);
587
588 return NULL;
589}
590
591/*!
592 * \internal
593 * \brief Creates, pushes, and links a channel for playing music on hold to bridge
594 *
595 * \param bridge Which bridge this moh channel exists for
596 *
597 * \retval NULL if the channel could not be created, pushed, or linked
598 * \retval Reference to the channel on success
599 */
601{
602 struct stasis_app_bridge_channel_wrapper *new_wrapper;
603 struct ast_channel *chan;
604 pthread_t threadid;
605
607 if (!chan) {
608 return NULL;
609 }
610
612 ast_hangup(chan);
613 return NULL;
614 }
615
618 ast_hangup(chan);
619 return NULL;
620 }
621
622 new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
624 if (!new_wrapper) {
625 ast_hangup(chan);
626 return NULL;
627 }
628
630 || ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid)
631 || ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan))) {
632 ao2_ref(new_wrapper, -1);
633 ast_hangup(chan);
634 return NULL;
635 }
636
637 if (!ao2_link_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK)) {
638 ao2_ref(new_wrapper, -1);
639 ast_hangup(chan);
640 return NULL;
641 }
642
643 /* Pass the new_wrapper ref to moh_channel_thread() */
644 if (ast_pthread_create_detached(&threadid, NULL, moh_channel_thread, new_wrapper)) {
645 ast_log(LOG_ERROR, "Failed to create channel thread. Abandoning MOH channel creation.\n");
647 ao2_ref(new_wrapper, -1);
648 ast_hangup(chan);
649 return NULL;
650 }
651
652 return chan;
653}
654
656{
657 struct ast_channel *chan;
658 struct stasis_app_bridge_channel_wrapper *moh_wrapper;
659
661 moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_NOLOCK);
662 if (!moh_wrapper) {
663 chan = bridge_moh_create(bridge);
664 }
666
667 if (moh_wrapper) {
668 chan = ast_channel_get_by_name(moh_wrapper->channel_id);
669 ao2_ref(moh_wrapper, -1);
670 }
671
672 return chan;
673}
674
676{
677 struct stasis_app_bridge_channel_wrapper *moh_wrapper;
678 struct ast_channel *chan;
679
681 if (!moh_wrapper) {
682 return -1;
683 }
684
685 chan = ast_channel_get_by_name(moh_wrapper->channel_id);
686 ao2_ref(moh_wrapper, -1);
687 if (!chan) {
688 return -1;
689 }
690
691 ast_moh_stop(chan);
693 ao2_cleanup(chan);
694
695 return 0;
696}
697
698/*! Removes the bridge to playback channel link */
699static void remove_bridge_playback(char *bridge_id)
700{
701 struct stasis_app_bridge_channel_wrapper *wrapper;
702 struct stasis_app_control *control;
703
705
706 if (wrapper) {
708 if (control) {
709 ao2_unlink(app_controls, control);
710 ao2_ref(control, -1);
711 }
712 ao2_ref(wrapper, -1);
713 }
714 ast_free(bridge_id);
715}
716
718 struct stasis_app_control *control)
719{
720 ast_assert(!ast_strlen_zero(bridge_id));
721 ao2_unlink(app_controls, control);
722}
723
725{
726 char *bridge_id = data;
727
728 remove_bridge_playback(bridge_id);
729}
730
731static void playback_after_bridge_cb(struct ast_channel *chan, void *data)
732{
733 char *bridge_id = data;
734
735 remove_bridge_playback(bridge_id);
736}
737
739 struct ast_channel *chan,
740 struct stasis_app_control *control)
741{
743 char *bridge_id = ast_strdup(bridge->uniqueid);
744
745 if (!bridge_id) {
746 return -1;
747 }
748
751 ast_free(bridge_id);
752 return -1;
753 }
754
755 new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
757 if (!new_wrapper) {
758 return -1;
759 }
760
761 if (ast_string_field_init(new_wrapper, 32)) {
762 return -1;
763 }
764
765 ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
766 ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
767
768 if (!ao2_link(app_bridges_playback, new_wrapper)) {
769 return -1;
770 }
771
772 ao2_link(app_controls, control);
773 return 0;
774}
775
777 struct stasis_app_control *control)
778{
779 struct stasis_app_bridge_channel_wrapper *wrapper;
780
782 if (wrapper) {
783 /* If wrapper is not found, then that means the after bridge callback has been
784 * called or is in progress. No need to unlink the control here since that has
785 * been done or is about to be done in the after bridge callback
786 */
788 ao2_ref(wrapper, -1);
789 }
790}
791
793{
794 struct stasis_app_bridge_channel_wrapper *playback_wrapper;
795 struct ast_channel *chan;
796
798 if (!playback_wrapper) {
799 return NULL;
800 }
801
802 chan = ast_channel_get_by_name(playback_wrapper->channel_id);
803 ao2_ref(playback_wrapper, -1);
804 return chan;
805}
806
808 const char *bridge_id)
809{
810 return ao2_find(app_bridges, bridge_id, OBJ_SEARCH_KEY);
811}
812
813
814/*!
815 * \brief In addition to running ao2_cleanup(), this function also removes the
816 * object from the app_controls container.
817 */
818static void control_unlink(struct stasis_app_control *control)
819{
820 if (!control) {
821 return;
822 }
823
824 ao2_unlink(app_controls, control);
825 ao2_cleanup(control);
826}
827
828static struct ast_bridge *bridge_create_common(const char *type, const char *name, const char *id, int invisible)
829{
830 struct ast_bridge *bridge;
831 char *requested_type, *requested_types = ast_strdupa(S_OR(type, "mixing"));
832 int capabilities = 0;
837 int send_sdp_label = 0;
838
839 ast_debug(1, "Creating bridge of type '%s' with name '%s' and id '%s'\n",
840 type, S_OR(name, "<unknown>"), S_OR(id, "<unknown>"));
841 if (invisible) {
843 }
844
845 if (!ast_strlen_zero(id)) {
846 bridge = stasis_app_bridge_find_by_id(id);
847 if (bridge) {
848 ast_log(LOG_WARNING, "Bridge with id '%s' already exists\n", id);
849 ao2_ref(bridge, -1);
850 return NULL;
851 }
852 }
853
854 while ((requested_type = strsep(&requested_types, ","))) {
855 requested_type = ast_strip(requested_type);
856
857 if (!strcmp(requested_type, "mixing")) {
858 capabilities |= STASIS_BRIDGE_MIXING_CAPABILITIES;
859 flags |= AST_BRIDGE_FLAG_SMART;
860 } else if (!strcmp(requested_type, "holding")) {
861 capabilities |= AST_BRIDGE_CAPABILITY_HOLDING;
862 } else if (!strcmp(requested_type, "dtmf_events") ||
863 !strcmp(requested_type, "proxy_media")) {
864 capabilities &= ~AST_BRIDGE_CAPABILITY_NATIVE;
865 } else if (!strcmp(requested_type, "video_sfu")) {
866 video_mode = AST_BRIDGE_VIDEO_MODE_SFU;
867 } else if (!strcmp(requested_type, "video_single")) {
869 } else if (!strcmp(requested_type, "sdp_label")) {
870 send_sdp_label = 1;
871 }
872 }
873
874 /* For an SFU video bridge we ensure it always remains in multimix for the best experience. */
875 if (video_mode == AST_BRIDGE_VIDEO_MODE_SFU) {
876 capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX;
877 flags &= ~AST_BRIDGE_FLAG_SMART;
878 }
879
880 if (!capabilities
881 /* Holding and mixing capabilities don't mix. */
882 || ((capabilities & AST_BRIDGE_CAPABILITY_HOLDING)
883 && (capabilities & (STASIS_BRIDGE_MIXING_CAPABILITIES)))) {
884 return NULL;
885 }
886
887 bridge = bridge_stasis_new(capabilities, flags, name, id, video_mode, send_sdp_label);
888 if (bridge) {
889 if (!ao2_link(app_bridges, bridge)) {
890 ast_bridge_destroy(bridge, 0);
891 bridge = NULL;
892 }
893 }
894
895 return bridge;
896}
897
898struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id)
899{
900 return bridge_create_common(type, name, id, 0);
901}
902
903struct ast_bridge *stasis_app_bridge_create_invisible(const char *type, const char *name, const char *id)
904{
905 return bridge_create_common(type, name, id, 1);
906}
907
908void stasis_app_bridge_destroy(const char *bridge_id)
909{
910 struct ast_bridge *bridge = stasis_app_bridge_find_by_id(bridge_id);
911 if (!bridge) {
912 return;
913 }
914 ast_debug(1, "Bridge " BRIDGE_PRINTF_SPEC ": destroying bridge\n",
915 BRIDGE_PRINTF_VARS(bridge));
916
917 ao2_unlink(app_bridges, bridge);
918 ast_debug(1, "Bridge " BRIDGE_PRINTF_SPEC ": unlinked from app_bridges. current refcount: %d\n",
919 BRIDGE_PRINTF_VARS(bridge), ao2_ref(bridge, 0));
920 ast_bridge_destroy(bridge, 0);
921}
922
923int stasis_app_bridge_set_var_reportable(const char *bridge_id, const char *variable,
924 const char *value, int report_events)
925{
926 RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_find_by_id(bridge_id), ao2_cleanup);
927
928 if (!bridge) {
929 return -1;
930 }
931
932 ast_bridge_lock(bridge);
933 if (ast_bridge_set_variable(bridge, variable, value, report_events)) {
934 ast_bridge_unlock(bridge);
935 return -1;
936 }
938 ast_bridge_unlock(bridge);
939
940 return 0;
941}
942
947
948static void replace_channel_destroy(void *obj)
949{
950 struct replace_channel_store *replace = obj;
951
952 ao2_cleanup(replace->snapshot);
953 ast_free(replace->app);
955}
956
958 .type = "replace-channel-store",
959 .destroy = replace_channel_destroy,
960};
961
962static struct replace_channel_store *get_replace_channel_store(struct ast_channel *chan, int no_create)
963{
964 struct ast_datastore *datastore;
965 struct replace_channel_store *ret;
966
967 ast_channel_lock(chan);
969 if (!datastore && !no_create) {
971 if (datastore) {
972 ast_channel_datastore_add(chan, datastore);
973 }
974 }
975
976 if (!datastore) {
977 ast_channel_unlock(chan);
978 return NULL;
979 }
980
981 if (!datastore->data) {
982 datastore->data = ast_calloc(1, sizeof(struct replace_channel_store));
983 }
984
985 ret = datastore->data;
986 ast_channel_unlock(chan);
987
988 return ret;
989}
990
991int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot)
992{
994
995 if (!replace) {
996 return -1;
997 }
998
999 ao2_replace(replace->snapshot, replace_snapshot);
1000 return 0;
1001}
1002
1003int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app)
1004{
1006
1007 if (!replace) {
1008 return -1;
1009 }
1010
1011 ast_free(replace->app);
1012 replace->app = NULL;
1013
1014 if (replace_app) {
1015 replace->app = ast_strdup(replace_app);
1016 if (!replace->app) {
1017 return -1;
1018 }
1019 }
1020
1021 return 0;
1022}
1023
1025{
1027 struct ast_channel_snapshot *replace_channel_snapshot;
1028
1029 if (!replace) {
1030 return NULL;
1031 }
1032
1033 replace_channel_snapshot = replace->snapshot;
1034 replace->snapshot = NULL;
1035
1036 return replace_channel_snapshot;
1037}
1038
1040{
1042 char *replace_channel_app;
1043
1044 if (!replace) {
1045 return NULL;
1046 }
1047
1048 replace_channel_app = replace->app;
1049 replace->app = NULL;
1050
1051 return replace_channel_app;
1052}
1053
1054static void start_message_blob_dtor(void *obj)
1055{
1056 struct start_message_blob *payload = obj;
1057
1058 ao2_cleanup(payload->channel);
1059 ao2_cleanup(payload->replace_channel);
1060 ast_json_unref(payload->blob);
1061}
1062
1063static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app *app,
1064 int argc, char *argv[], struct ast_channel_snapshot *snapshot,
1065 struct ast_channel_snapshot *replace_channel_snapshot)
1066{
1067 struct ast_json *json_blob;
1068 struct ast_json *json_args;
1069 struct start_message_blob *payload;
1070 struct stasis_message *msg;
1071 int i;
1072
1073 if (app_subscribe_channel(app, chan)) {
1074 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
1076 return -1;
1077 }
1078
1079 payload = ao2_alloc(sizeof(*payload), start_message_blob_dtor);
1080 if (!payload) {
1081 ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
1082 return -1;
1083 }
1084
1085 payload->channel = ao2_bump(snapshot);
1086 payload->replace_channel = ao2_bump(replace_channel_snapshot);
1087
1088 json_blob = ast_json_pack("{s: s, s: o, s: []}",
1089 "app", stasis_app_name(app),
1090 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1091 "args");
1092 if (!json_blob) {
1093 ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
1094 ao2_ref(payload, -1);
1095 return -1;
1096 }
1097 payload->blob = json_blob;
1098
1099
1100 /* Append arguments to args array */
1101 json_args = ast_json_object_get(json_blob, "args");
1102 ast_assert(json_args != NULL);
1103 for (i = 0; i < argc; ++i) {
1104 int r = ast_json_array_append(json_args,
1105 ast_json_string_create(argv[i]));
1106 if (r != 0) {
1107 ast_log(LOG_ERROR, "Error appending to StasisStart message\n");
1108 ao2_ref(payload, -1);
1109 return -1;
1110 }
1111 }
1112
1113
1114 msg = stasis_message_create(start_message_type(), payload);
1115 ao2_ref(payload, -1);
1116 if (!msg) {
1117 ast_log(LOG_ERROR, "Error sending StasisStart message\n");
1118 return -1;
1119 }
1120
1121 if (replace_channel_snapshot) {
1122 app_unsubscribe_channel_id(app, replace_channel_snapshot->base->uniqueid);
1123 }
1125 ao2_ref(msg, -1);
1126 return 0;
1127}
1128
1129static int send_start_msg(struct stasis_app *app, struct ast_channel *chan,
1130 int argc, char *argv[])
1131{
1132 int ret = -1;
1133 struct ast_channel_snapshot *snapshot;
1134 struct ast_channel_snapshot *replace_channel_snapshot;
1135
1136 ast_assert(chan != NULL);
1137
1138 replace_channel_snapshot = get_replace_channel_snapshot(chan);
1139
1140 /* Set channel info */
1141 ast_channel_lock(chan);
1142 snapshot = ast_channel_snapshot_create(chan);
1143 ast_channel_unlock(chan);
1144 if (snapshot) {
1145 ret = send_start_msg_snapshots(chan, app, argc, argv, snapshot, replace_channel_snapshot);
1146 ao2_ref(snapshot, -1);
1147 }
1148 ao2_cleanup(replace_channel_snapshot);
1149
1150 return ret;
1151}
1152
1153static void remove_masquerade_store(struct ast_channel *chan);
1154
1155int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
1156{
1158 struct ast_json *blob;
1159 struct stasis_message *msg;
1160
1161 if (sanitize && sanitize->channel
1162 && sanitize->channel(chan)) {
1163 return 0;
1164 }
1165
1166 blob = ast_json_pack("{s: s, s: o}",
1167 "app", stasis_app_name(app),
1168 "timestamp", ast_json_timeval(ast_tvnow(), NULL)
1169 );
1170 if (!blob) {
1171 ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n");
1172 return -1;
1173 }
1174
1177 msg = ast_channel_blob_create(chan, end_message_type(), blob);
1178 if (msg) {
1180 }
1181 ao2_cleanup(msg);
1182 ast_json_unref(blob);
1183
1184 return 0;
1185}
1186
1187static int masq_match_cb(void *obj, void *data, int flags)
1188{
1189 struct stasis_app_control *control = obj;
1190 struct ast_channel *chan = data;
1191
1192 if (!strcmp(ast_channel_uniqueid(chan),
1194 return CMP_MATCH;
1195 }
1196
1197 return 0;
1198}
1199
1200static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1201{
1202 struct stasis_app_control *control;
1203
1204 /*
1205 * At this point, old_chan is the channel pointer that is in Stasis() and
1206 * has the unknown channel's name in it while new_chan is the channel pointer
1207 * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1208 * about.
1209 *
1210 * Find and unlink control since the channel has a new name/uniqueid
1211 * and its hash has changed. Since the channel is leaving stasis don't
1212 * bother putting it back into the container. Nobody is going to
1213 * remove it from the container later.
1214 */
1215 control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, old_chan);
1216 if (!control) {
1217 ast_log(LOG_ERROR, "Could not find control for masqueraded channel\n");
1218 return;
1219 }
1220
1221 /* send the StasisEnd message to the app */
1223 app_send_end_msg(control_app(control), new_chan);
1224
1225 /* remove the datastore */
1226 remove_masquerade_store(old_chan);
1227
1228 ao2_cleanup(control);
1229}
1230
1231static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1232{
1233 RAII_VAR(struct ast_channel_snapshot *, new_snapshot, NULL, ao2_cleanup);
1234 RAII_VAR(struct ast_channel_snapshot *, old_snapshot, NULL, ao2_cleanup);
1235 struct stasis_app_control *control;
1236
1237 /* At this point, new_chan is the channel pointer that is in Stasis() and
1238 * has the unknown channel's name in it while old_chan is the channel pointer
1239 * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1240 * about */
1241
1242 /* grab a snapshot for the channel that is jumping into Stasis() */
1243 new_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(new_chan));
1244 if (!new_snapshot) {
1245 ast_log(LOG_ERROR, "Could not get snapshot for masquerading channel\n");
1246 return;
1247 }
1248
1249 /* grab a snapshot for the channel that has been kicked out of Stasis() */
1250 old_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(old_chan));
1251 if (!old_snapshot) {
1252 ast_log(LOG_ERROR, "Could not get snapshot for masqueraded channel\n");
1253 return;
1254 }
1255
1256 /*
1257 * Find, unlink, and relink control since the channel has a new
1258 * name/uniqueid and its hash has changed.
1259 */
1260 control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, new_chan);
1261 if (!control) {
1262 ast_log(LOG_ERROR, "Could not find control for masquerading channel\n");
1263 return;
1264 }
1265 ao2_link(app_controls, control);
1266
1267
1268 /* send the StasisStart with replace_channel to the app */
1269 send_start_msg_snapshots(new_chan, control_app(control), 0, NULL, new_snapshot,
1270 old_snapshot);
1271 /* send the StasisEnd message to the app */
1272 app_send_end_msg(control_app(control), old_chan);
1273
1274 ao2_cleanup(control);
1275}
1276
1278 .type = "stasis-masquerade",
1279 .chan_fixup = channel_stolen_cb,
1280 .chan_breakdown = channel_replaced_cb,
1281};
1282
1283static int has_masquerade_store(struct ast_channel *chan)
1284{
1285 SCOPED_CHANNELLOCK(lock, chan);
1287}
1288
1289static int add_masquerade_store(struct ast_channel *chan)
1290{
1291 struct ast_datastore *datastore;
1292
1293 SCOPED_CHANNELLOCK(lock, chan);
1295 return 0;
1296 }
1297
1299 if (!datastore) {
1300 return -1;
1301 }
1302
1303 ast_channel_datastore_add(chan, datastore);
1304
1305 return 0;
1306}
1307
1308static void remove_masquerade_store(struct ast_channel *chan)
1309{
1310 struct ast_datastore *datastore;
1311
1312 SCOPED_CHANNELLOCK(lock, chan);
1314 if (!datastore) {
1315 return;
1316 }
1317
1318 ast_channel_datastore_remove(chan, datastore);
1319 ast_datastore_free(datastore);
1320}
1321
1323{
1324 while (!control_is_done(control)) {
1325 int command_count;
1326 command_count = control_dispatch_all(control, chan);
1327
1328 ao2_lock(control);
1329
1330 if (control_command_count(control)) {
1331 /* If the command queue isn't empty, something added to the queue before it was locked. */
1332 ao2_unlock(control);
1333 continue;
1334 }
1335
1336 if (command_count == 0 || ast_channel_fdno(chan) == -1) {
1337 control_mark_done(control);
1338 ao2_unlock(control);
1339 break;
1340 }
1341 ao2_unlock(control);
1342 }
1343}
1344
1346{
1347 return control_is_done(control);
1348}
1349
1351{
1352 control_flush_queue(control);
1353}
1354
1356 .type = "stasis_end_published",
1357};
1358
1360{
1361 struct ast_datastore *datastore;
1362
1364 if (datastore) {
1365 ast_channel_lock(chan);
1366 ast_channel_datastore_add(chan, datastore);
1367 ast_channel_unlock(chan);
1368 }
1369}
1370
1372{
1373 struct ast_datastore *datastore;
1374
1375 ast_channel_lock(chan);
1377 ast_channel_unlock(chan);
1378
1379 return datastore ? 1 : 0;
1380}
1381
1383{
1384 struct ast_datastore *datastore;
1385
1386 ast_channel_lock(chan);
1388 if (datastore) {
1389 ast_channel_datastore_remove(chan, datastore);
1390 ast_datastore_free(datastore);
1391 }
1392 ast_channel_unlock(chan);
1393}
1394
1395/*! \brief Stasis dialplan application callback */
1396int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
1397 char *argv[])
1398{
1399 RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1400 RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
1401 struct ast_bridge *bridge = NULL;
1402 int res = 0;
1403 int needs_depart;
1404
1405 ast_assert(chan != NULL);
1406
1407 /* Just in case there's a lingering indication that the channel has had a stasis
1408 * end published on it, remove that now.
1409 */
1411
1412 if (!apps_registry) {
1413 return -1;
1414 }
1415
1417 if (!app) {
1419 "Stasis app '%s' not registered\n", app_name);
1420 return -1;
1421 }
1422 if (!app_is_active(app)) {
1424 "Stasis app '%s' not active\n", app_name);
1425 return -1;
1426 }
1427
1428 control = control_create(chan, app);
1429 if (!control) {
1430 ast_log(LOG_ERROR, "Control allocation failed or Stasis app '%s' not registered\n", app_name);
1431 return -1;
1432 }
1433
1434 if (!control_app(control)) {
1435 ast_log(LOG_ERROR, "Stasis app '%s' not registered\n", app_name);
1436 return -1;
1437 }
1438
1439 if (!app_is_active(control_app(control))) {
1440 ast_log(LOG_ERROR, "Stasis app '%s' not active\n", app_name);
1441 return -1;
1442 }
1443 ao2_link(app_controls, control);
1444
1445 if (add_masquerade_store(chan)) {
1446 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1447 return -1;
1448 }
1449
1450 res = send_start_msg(control_app(control), chan, argc, argv);
1451 if (res != 0) {
1453 "Error sending start message to '%s'\n", app_name);
1455 return -1;
1456 }
1457
1458 /* Pull queued prestart commands and execute */
1459 control_prestart_dispatch_all(control, chan);
1460
1461 while (!control_is_done(control)) {
1462 RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
1463 int r;
1464 int command_count;
1465 RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup);
1466
1467 /* Check to see if a bridge absorbed our hangup frame */
1468 if (ast_check_hangup_locked(chan)) {
1469 control_mark_done(control);
1470 break;
1471 }
1472
1473 /* control->next_app is only modified within the control thread, so this is safe */
1474 if (control_next_app(control)) {
1475 struct stasis_app *next_app = ao2_find(apps_registry, control_next_app(control), OBJ_SEARCH_KEY);
1476
1477 if (next_app && app_is_active(next_app)) {
1478 int idx;
1479 int next_argc;
1480 char **next_argv;
1481
1482 /* If something goes wrong in this conditional, res will need to be non-zero
1483 * so that the code below the exec loop knows something went wrong during a move.
1484 */
1486 res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1487 if (res != 0) {
1489 "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1490 control_mark_done(control);
1491 ao2_ref(next_app, -1);
1492 break;
1493 }
1494 } else {
1496 }
1497
1498 /* This will ao2_bump next_app, and unref the previous app by 1 */
1499 control_set_app(control, next_app);
1500
1501 /* There's a chance that the previous application is ready for clean up, so go ahead
1502 * and do that now.
1503 */
1504 cleanup();
1505
1506 /* We need to add another masquerade store, otherwise the leave message will
1507 * not show up for the correct application.
1508 */
1509 if (add_masquerade_store(chan)) {
1510 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1511 res = -1;
1512 control_mark_done(control);
1513 ao2_ref(next_app, -1);
1514 break;
1515 }
1516
1517 /* We MUST get the size before the list, as control_next_app_args steals the elements
1518 * from the string vector.
1519 */
1520 next_argc = control_next_app_args_size(control);
1521 next_argv = control_next_app_args(control);
1522
1523 res = send_start_msg(control_app(control), chan, next_argc, next_argv);
1524
1525 /* Even if res != 0, we still need to free the memory we got from control_argv */
1526 if (next_argv) {
1527 for (idx = 0; idx < next_argc; idx++) {
1528 ast_free(next_argv[idx]);
1529 }
1530 ast_free(next_argv);
1531 }
1532
1533 if (res != 0) {
1535 "Error sending start message to '%s'\n", stasis_app_name(control_app(control)));
1537 control_mark_done(control);
1538 ao2_ref(next_app, -1);
1539 break;
1540 }
1541
1542 /* Done switching applications, free memory and clean up */
1543 control_move_cleanup(control);
1544 } else {
1545 /* If we can't switch applications, do nothing */
1546 struct ast_json *msg;
1547 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1548
1549 if (!next_app) {
1550 ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not registered\n",
1551 control_next_app(control));
1552 } else {
1553 ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not active\n",
1554 control_next_app(control));
1555 }
1556
1558 if (!snapshot) {
1559 ast_log(LOG_ERROR, "Could not get channel shapshot for '%s'\n",
1560 ast_channel_name(chan));
1561 } else {
1562 struct ast_json *json_args;
1563 int next_argc = control_next_app_args_size(control);
1564 char **next_argv = control_next_app_args(control);
1565
1566 msg = ast_json_pack("{s: s, s: o, s: o, s: s, s: []}",
1567 "type", "ApplicationMoveFailed",
1568 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1569 "channel", ast_channel_snapshot_to_json(snapshot, NULL),
1570 "destination", control_next_app(control),
1571 "args");
1572 if (!msg) {
1573 ast_log(LOG_ERROR, "Failed to pack JSON for ApplicationMoveFailed message\n");
1574 } else {
1575 json_args = ast_json_object_get(msg, "args");
1576 if (!json_args) {
1577 ast_log(LOG_ERROR, "Could not get args json array");
1578 } else {
1579 int r = 0;
1580 int idx;
1581 for (idx = 0; idx < next_argc; ++idx) {
1582 r = ast_json_array_append(json_args,
1583 ast_json_string_create(next_argv[idx]));
1584 if (r != 0) {
1585 ast_log(LOG_ERROR, "Error appending to ApplicationMoveFailed message\n");
1586 break;
1587 }
1588 }
1589 if (r == 0) {
1590 app_send(control_app(control), msg);
1591 }
1592 }
1593 ast_json_unref(msg);
1594 }
1595 }
1596 }
1597 control_move_cleanup(control);
1598 ao2_cleanup(next_app);
1599 }
1600
1601 last_bridge = bridge;
1602 bridge = ao2_bump(stasis_app_get_bridge(control));
1603
1604 if (bridge != last_bridge) {
1605 if (last_bridge) {
1606 app_unsubscribe_bridge(control_app(control), last_bridge);
1607 }
1608 if (bridge) {
1609 app_subscribe_bridge(control_app(control), bridge);
1610 }
1611 }
1612
1613 if (bridge) {
1614 /* Bridge/dial is handling channel frames */
1615 control_wait(control);
1616 control_dispatch_all(control, chan);
1617 continue;
1618 }
1619
1620 r = ast_waitfor(chan, MAX_WAIT_MS);
1621
1622 if (r < 0) {
1623 ast_debug(3, "%s: Poll error\n",
1624 ast_channel_uniqueid(chan));
1625 control_mark_done(control);
1626 break;
1627 }
1628
1629 command_count = control_dispatch_all(control, chan);
1630
1631 if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1632 /* Command drained the channel; wait for next frame */
1633 continue;
1634 }
1635
1636 if (r == 0) {
1637 /* Timeout */
1638 continue;
1639 }
1640
1641 f = ast_read(chan);
1642 if (!f) {
1643 /* Continue on in the dialplan */
1644 ast_debug(3, "%s: Hangup (no more frames)\n",
1645 ast_channel_uniqueid(chan));
1646 control_mark_done(control);
1647 break;
1648 }
1649
1650 if (f->frametype == AST_FRAME_CONTROL) {
1651 if (f->subclass.integer == AST_CONTROL_HANGUP) {
1652 /* Continue on in the dialplan */
1653 ast_debug(3, "%s: Hangup\n",
1654 ast_channel_uniqueid(chan));
1655 control_mark_done(control);
1656 break;
1657 }
1658 }
1659 }
1660
1661 ast_channel_lock(chan);
1662 needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1663 ast_channel_unlock(chan);
1664 if (needs_depart) {
1665 ast_bridge_depart(chan);
1666 }
1667
1668 if (stasis_app_get_bridge(control)) {
1670 }
1671 ao2_cleanup(bridge);
1672
1673 /* Only publish a stasis_end event if it hasn't already been published */
1674 if (!res && !stasis_app_channel_is_stasis_end_published(chan)) {
1675 /* A masquerade has occurred and this message will be wrong so it
1676 * has already been sent elsewhere. */
1677 res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1678 if (res != 0) {
1680 "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1681 return res;
1682 }
1683 } else {
1685 }
1686
1687 control_flush_queue(control);
1688
1689 /* Stop any lingering silence generator */
1690 control_silence_stop_now(control);
1691
1692 /* There's an off chance that app is ready for cleanup. Go ahead
1693 * and clean up, just in case
1694 */
1695 cleanup();
1696
1697 if (stasis_app_control_is_failed(control)) {
1698 res = -1;
1699 }
1700 /* The control needs to be removed from the controls container in
1701 * case a new PBX is started and ends up coming back into Stasis.
1702 */
1703 control_unlink(control);
1704 control = NULL;
1705
1706 if (!res && !ast_channel_pbx(chan)) {
1707 int chan_hungup;
1708
1709 /* The ASYNCGOTO softhangup flag may have broken the channel out of
1710 * its bridge to run dialplan, so if there's no pbx on the channel
1711 * let it run dialplan here. Otherwise, it will run when this
1712 * application exits. */
1713 ast_channel_lock(chan);
1715 chan_hungup = ast_check_hangup(chan);
1716 ast_channel_unlock(chan);
1717
1718 if (!chan_hungup) {
1719 struct ast_pbx_args pbx_args;
1720
1721 memset(&pbx_args, 0, sizeof(pbx_args));
1722 pbx_args.no_hangup_chan = 1;
1723
1724 res = ast_pbx_run_args(chan, &pbx_args);
1725 }
1726 }
1727
1728 return res;
1729}
1730
1731int stasis_app_send(const char *app_name, struct ast_json *message)
1732{
1733 struct stasis_app *app;
1734
1735 if (!apps_registry) {
1736 return -1;
1737 }
1738
1740 if (!app) {
1741 /* XXX We can do a better job handling late binding, queueing up
1742 * the call for a few seconds to wait for the app to register.
1743 */
1745 "Stasis app '%s' not registered\n", app_name);
1746 return -1;
1747 }
1749 ao2_ref(app, -1);
1750
1751 return 0;
1752}
1753
1754static struct stasis_app *find_app_by_name(const char *app_name)
1755{
1756 struct stasis_app *res = NULL;
1757
1758 if (!apps_registry) {
1759 return NULL;
1760 }
1761
1762 if (!ast_strlen_zero(app_name)) {
1764 }
1765
1766 return res;
1767}
1768
1770{
1771 return find_app_by_name(name);
1772}
1773
1775{
1777
1778 /*
1779 * It's safe to unref app here because we're not actually
1780 * using it or returning it.
1781 */
1783
1784 return app != NULL;
1785}
1786
1787static int append_name(void *obj, void *arg, int flags)
1788{
1789 struct stasis_app *app = obj;
1790 struct ao2_container *apps = arg;
1791
1793 return 0;
1794}
1795
1797{
1798 struct ao2_container *apps;
1799
1800 if (!apps_registry) {
1801 return NULL;
1802 }
1803
1805 if (!apps) {
1806 return NULL;
1807 }
1808
1810
1811 return apps;
1812}
1813
1814static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
1815{
1816 RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1817
1818 if (!apps_registry) {
1819 return -1;
1820 }
1821
1824 if (app) {
1825 /*
1826 * We need to unlock the apps_registry before calling app_update to
1827 * prevent the possibility of a deadlock with the session.
1828 */
1830 app_update(app, handler, data);
1831 cleanup();
1832 return 0;
1833 }
1834
1836 if (!app) {
1838 return -1;
1839 }
1840
1841 if (all_events) {
1842 struct stasis_app_event_source *source;
1843
1846 if (!source->subscribe) {
1847 continue;
1848 }
1849
1850 source->subscribe(app, NULL);
1851 }
1853 }
1855
1857
1858 /* We lazily clean up the apps_registry, because it's good enough to
1859 * prevent memory leaks, and we're lazy.
1860 */
1861 cleanup();
1862 return 0;
1863}
1864
1866{
1867 return __stasis_app_register(app_name, handler, data, 0);
1868}
1869
1871{
1872 return __stasis_app_register(app_name, handler, data, 1);
1873}
1874
1876{
1877 struct stasis_app *app;
1878 struct stasis_app_event_source *source;
1879 int res;
1880
1881 if (!app_name) {
1882 return;
1883 }
1884
1885 if (!apps_registry) {
1886 return;
1887 }
1888
1890 if (!app) {
1892 "Stasis app '%s' not registered\n", app_name);
1893 return;
1894 }
1895
1896 /* Unsubscribe from all event sources. */
1899 if (!source->unsubscribe || !source->is_subscribed
1900 || !source->is_subscribed(app, NULL)) {
1901 continue;
1902 }
1903
1904 res = source->unsubscribe(app, NULL);
1905 if (res) {
1906 ast_log(LOG_WARNING, "%s: Error unsubscribing from event source '%s'\n",
1907 app_name, source->scheme);
1908 }
1909 }
1911
1913
1914 /* There's a decent chance that app is ready for cleanup. Go ahead
1915 * and clean up, just in case
1916 */
1917 cleanup();
1918
1919 ao2_ref(app, -1);
1920}
1921
1928
1930{
1931 struct stasis_app_event_source *source;
1932
1935 if (source == obj) {
1937 break;
1938 }
1939 }
1942}
1943
1944/*!
1945 * \internal
1946 * \brief Convert event source data to JSON.
1947 *
1948 * Calls each event source that has a "to_json" handler allowing each
1949 * source to add data to the given JSON object.
1950 *
1951 * \param app application associated with the event source
1952 * \param json a json object to "fill"
1953 *
1954 * \retval The given json object.
1955 */
1957 const struct stasis_app *app, struct ast_json *json)
1958{
1959 struct stasis_app_event_source *source;
1960
1963 if (source->to_json) {
1964 source->to_json(app, json);
1965 }
1966 }
1968
1969 return json;
1970}
1971
1973{
1974 if (!app) {
1975 return NULL;
1976 }
1977
1980}
1981
1983{
1985 struct ast_json *json = stasis_app_object_to_json(app);
1986
1988
1989 return json;
1990}
1991
1992/*!
1993 * \internal
1994 * \brief Finds an event source that matches a uri scheme.
1995 *
1996 * Uri(s) should begin with a particular scheme that can be matched
1997 * against an event source.
1998 *
1999 * \param uri uri containing a scheme to match
2000 *
2001 * \retval an event source if found, NULL otherwise.
2002 */
2003static struct stasis_app_event_source *app_event_source_find(const char *uri)
2004{
2005 struct stasis_app_event_source *source;
2006
2009 if (ast_begins_with(uri, source->scheme)) {
2010 break;
2011 }
2012 }
2014
2015 return source;
2016}
2017
2018/*!
2019 * \internal
2020 * \brief Callback for subscription handling
2021 *
2022 * \param app [un]subscribing application
2023 * \param uri scheme:id of an event source
2024 * \param event_source being [un]subscribed [from]to
2025 *
2026 * \retval stasis_app_subscribe_res return code.
2027 */
2029 struct stasis_app *app, const char *uri,
2030 struct stasis_app_event_source *event_source);
2031
2032/*!
2033 * \internal
2034 * \brief Subscriptions handler for application [un]subscribing.
2035 *
2036 * \param app_name Name of the application to subscribe.
2037 * \param event_source_uris URIs for the event sources to subscribe to.
2038 * \param event_sources_count Array size of event_source_uris.
2039 * \param json Optional output pointer for JSON representation of the app
2040 * after adding the subscription.
2041 * \param handler [un]subscribe handler
2042 *
2043 * \retval stasis_app_subscribe_res return code.
2044 */
2046 const char *app_name, const char **event_source_uris,
2047 int event_sources_count, struct ast_json **json,
2049{
2051 int i;
2052
2054
2055 if (!app) {
2057 }
2058
2059 for (i = 0; i < event_sources_count; ++i) {
2060 const char *uri = event_source_uris[i];
2061 struct stasis_app_event_source *event_source;
2062 enum stasis_app_subscribe_res res;
2063
2064 event_source = app_event_source_find(uri);
2065 if (!event_source) {
2066 ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
2067 ao2_ref(app, -1);
2068
2070 }
2071
2072 res = handler(app, uri, event_source);
2073 if (res != STASIS_ASR_OK) {
2074 ao2_ref(app, -1);
2075
2076 return res;
2077 }
2078 }
2079
2080 if (json) {
2081 ast_debug(3, "%s: Successful; setting results\n", app_name);
2083 }
2084
2085 ao2_ref(app, -1);
2086
2087 return STASIS_ASR_OK;
2088}
2089
2091 struct ast_channel *chan)
2092{
2094 int res;
2095
2096 if (!app) {
2098 }
2099
2100 ast_debug(3, "%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan));
2101
2102 res = app_subscribe_channel(app, chan);
2103 ao2_ref(app, -1);
2104
2105 if (res != 0) {
2106 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
2109 }
2110
2111 return STASIS_ASR_OK;
2112}
2113
2114
2115/*!
2116 * \internal
2117 * \brief Subscribe an app to an event source.
2118 *
2119 * \param app subscribing application
2120 * \param uri scheme:id of an event source
2121 * \param event_source being subscribed to
2122 *
2123 * \retval stasis_app_subscribe_res return code.
2124 */
2126 struct stasis_app *app, const char *uri,
2127 struct stasis_app_event_source *event_source)
2128{
2129 const char *app_name = stasis_app_name(app);
2130 RAII_VAR(void *, obj, NULL, ao2_cleanup);
2131
2132 ast_debug(3, "%s: Checking %s\n", app_name, uri);
2133
2134 if (!ast_strlen_zero(uri + strlen(event_source->scheme)) &&
2135 (!event_source->find || (!(obj = event_source->find(app, uri + strlen(event_source->scheme)))))) {
2136 ast_log(LOG_WARNING, "Event source not found: %s\n", uri);
2138 }
2139
2140 ast_debug(3, "%s: Subscribing to %s\n", app_name, uri);
2141
2142 if (!event_source->subscribe || (event_source->subscribe(app, obj))) {
2143 ast_log(LOG_WARNING, "Error subscribing app '%s' to '%s'\n",
2144 app_name, uri);
2146 }
2147
2148 return STASIS_ASR_OK;
2149}
2150
2152 const char **event_source_uris, int event_sources_count,
2153 struct ast_json **json)
2154{
2156 app_name, event_source_uris, event_sources_count,
2157 json, app_subscribe);
2158}
2159
2160/*!
2161 * \internal
2162 * \brief Unsubscribe an app from an event source.
2163 *
2164 * \param app application to unsubscribe
2165 * \param uri scheme:id of an event source
2166 * \param event_source being unsubscribed from
2167 *
2168 * \retval stasis_app_subscribe_res return code.
2169 */
2171 struct stasis_app *app, const char *uri,
2172 struct stasis_app_event_source *event_source)
2173{
2174 const char *app_name = stasis_app_name(app);
2175 const char *id = uri + strlen(event_source->scheme);
2176
2177 if (!event_source->is_subscribed ||
2178 (!event_source->is_subscribed(app, id))) {
2180 }
2181
2182 ast_debug(3, "%s: Unsubscribing from %s\n", app_name, uri);
2183
2184 if (!event_source->unsubscribe || (event_source->unsubscribe(app, id))) {
2185 ast_log(LOG_WARNING, "Error unsubscribing app '%s' to '%s'\n",
2186 app_name, uri);
2187 return -1;
2188 }
2189 return 0;
2190}
2191
2193 const char **event_source_uris, int event_sources_count,
2194 struct ast_json **json)
2195{
2197 app_name, event_source_uris, event_sources_count,
2198 json, app_unsubscribe);
2199}
2200
2202 const char *event_name,
2203 const char **source_uris, int sources_count,
2204 struct ast_json *json_variables)
2205{
2207 struct ast_json *blob = NULL;
2208 struct ast_multi_object_blob *multi;
2209 struct stasis_message *message;
2211 int have_channel = 0;
2212 int i;
2213
2214 if (!app) {
2215 ast_log(LOG_WARNING, "App %s not found\n", app_name);
2217 }
2218
2220 return res;
2221 }
2222
2223 if (json_variables) {
2224 struct ast_json *json_value = ast_json_string_create(event_name);
2225
2226 if (json_value && !ast_json_object_set(json_variables, "eventname", json_value)) {
2227 blob = ast_json_ref(json_variables);
2228 }
2229 } else {
2230 blob = ast_json_pack("{s: s}", "eventname", event_name);
2231 }
2232
2233 if (!blob) {
2234 ast_log(LOG_ERROR, "Failed to initialize blob\n");
2235
2236 return res;
2237 }
2238
2239 multi = ast_multi_object_blob_create(blob);
2240 ast_json_unref(blob);
2241 if (!multi) {
2242 ast_log(LOG_ERROR, "Failed to initialize multi\n");
2243
2244 return res;
2245 }
2246
2247 for (i = 0; i < sources_count; ++i) {
2248 const char *uri = source_uris[i];
2249 void *snapshot=NULL;
2251
2252 if (ast_begins_with(uri, "channel:")) {
2254 snapshot = ast_channel_snapshot_get_latest(uri + 8);
2255 have_channel = 1;
2256 } else if (ast_begins_with(uri, "bridge:")) {
2258 snapshot = ast_bridge_get_snapshot_by_uniqueid(uri + 7);
2259 } else if (ast_begins_with(uri, "endpoint:")) {
2261 snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL);
2262 } else {
2263 ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
2264 ao2_ref(multi, -1);
2265
2267 }
2268 if (!snapshot) {
2269 ast_log(LOG_ERROR, "Unable to get snapshot for %s\n", uri);
2270 ao2_ref(multi, -1);
2271
2273 }
2274 ast_multi_object_blob_add(multi, type, snapshot);
2275 }
2276
2278 ao2_ref(multi, -1);
2279
2280 if (!message) {
2281 ast_log(LOG_ERROR, "Unable to create stasis user event message\n");
2282 return res;
2283 }
2284
2285 /*
2286 * Publishing to two different topics is normally to be avoided -- except
2287 * in this case both are final destinations with no forwards (only listeners).
2288 * The message has to be delivered to the application topic for ARI, but a
2289 * copy is also delivered directly to the manager for AMI if there is a channel.
2290 */
2292
2293 if (have_channel) {
2295 }
2296 ao2_ref(message, -1);
2297
2298 return STASIS_APP_USER_OK;
2299}
2300
2301static int unload_module(void)
2302{
2304
2306
2307 cleanup();
2308
2310
2313
2316
2318 app_bridges = NULL;
2319
2322
2325
2326 STASIS_MESSAGE_TYPE_CLEANUP(end_message_type);
2327 STASIS_MESSAGE_TYPE_CLEANUP(start_message_type);
2328
2329 return 0;
2330}
2331
2332/*! \brief Sanitization callback for channel snapshots */
2333static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
2334{
2335 if (!snapshot || !(snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL)) {
2336 return 0;
2337 }
2338 return 1;
2339}
2340
2341/*! \brief Sanitization callback for channels */
2342static int channel_sanitizer(const struct ast_channel *chan)
2343{
2344 if (!chan || !(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)) {
2345 return 0;
2346 }
2347 return 1;
2348}
2349
2350/*! \brief Sanitization callback for channel unique IDs */
2351static int channel_id_sanitizer(const char *id)
2352{
2353 struct ast_channel_snapshot *snapshot;
2354 int ret;
2355
2356 snapshot = ast_channel_snapshot_get_latest(id);
2357 ret = channel_snapshot_sanitizer(snapshot);
2358 ao2_cleanup(snapshot);
2359
2360 return ret;
2361}
2362
2363/*! \brief Sanitization callbacks for communication to Stasis applications */
2369
2374
2376 .type = "stasis-internal-channel",
2377};
2378
2379static int set_internal_datastore(struct ast_channel *chan)
2380{
2381 struct ast_datastore *datastore;
2382
2384 if (!datastore) {
2386 if (!datastore) {
2387 return -1;
2388 }
2389 ast_channel_datastore_add(chan, datastore);
2390 }
2391 return 0;
2392}
2393
2395{
2396 struct ast_channel *outchan = NULL, *outowner = NULL;
2397 int res = 0;
2398 struct ast_unreal_pvt *unreal_pvt = ast_channel_tech_pvt(chan);
2399
2400 ao2_ref(unreal_pvt, +1);
2401 ast_unreal_lock_all(unreal_pvt, &outowner, &outchan);
2402 if (outowner) {
2403 res |= set_internal_datastore(outowner);
2404 ast_channel_unlock(outowner);
2405 ast_channel_unref(outowner);
2406 }
2407 if (outchan) {
2408 res |= set_internal_datastore(outchan);
2409 ast_channel_unlock(outchan);
2410 ast_channel_unref(outchan);
2411 }
2412 ao2_unlock(unreal_pvt);
2413 ao2_ref(unreal_pvt, -1);
2414 return res;
2415}
2416
2418{
2419 int res;
2420
2424
2425 return res;
2426}
2427
2429{
2430 struct ast_datastore *datastore;
2431 int res = 0;
2432
2433 ast_channel_lock(chan);
2435 if (datastore) {
2436 res = 1;
2437 }
2438 ast_channel_unlock(chan);
2439
2440 return res;
2441}
2442
2480
2482 .load_pri = AST_MODPRI_APP_DEPEND - 1,
2483 .support_level = AST_MODULE_SUPPORT_CORE,
2484 .load = load_module,
2485 .unload = unload_module,
static const char app[]
ast_mutex_t lock
Definition app_sla.c:337
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_log
Definition astobj2.c:42
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
@ CMP_MATCH
Definition astobj2.h:1027
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition astobj2.h:1578
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition astobj2.h:1600
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition astobj2.h:1554
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition astobj2.h:501
#define ao2_lock(a)
Definition astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1063
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition astobj2.h:1072
@ OBJ_MULTIPLE
Definition astobj2.h:1049
@ OBJ_UNLINK
Definition astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition astobj2.h:1188
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition bridge.c:2105
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition bridge.h:491
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition bridge.c:1029
@ AST_BRIDGE_CAPABILITY_MULTIMIX
Definition bridge.h:98
@ AST_BRIDGE_CAPABILITY_HOLDING
Definition bridge.h:90
ast_bridge_video_mode_type
Video source modes.
Definition bridge.h:102
@ AST_BRIDGE_VIDEO_MODE_SINGLE_SRC
Definition bridge.h:106
@ AST_BRIDGE_VIDEO_MODE_TALKER_SRC
Definition bridge.h:109
@ AST_BRIDGE_VIDEO_MODE_SFU
Definition bridge.h:113
#define ast_bridge_lock(bridge)
Lock the bridge.
Definition bridge.h:480
#define BRIDGE_PRINTF_VARS(bridge)
Definition bridge.h:80
int ast_bridge_set_variable(struct ast_bridge *bridge, const char *name, const char *value, int report_events)
Set a variable on the bridge.
Definition bridge.c:1341
#define BRIDGE_PRINTF_SPEC
Definition bridge.h:79
After Bridge Execution API.
ast_bridge_after_cb_reason
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.
@ 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[]
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2376
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition channel.c:2385
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition channel.c:2423
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2540
int ast_channel_fdno(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition channel.h:2983
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3166
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_check_hangup_locked(struct ast_channel *chan)
Definition channel.c:460
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4278
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1417
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:446
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition channel.c:2462
#define AST_CHANNEL_NAME
Definition channel.h:173
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3019
@ AST_SOFTHANGUP_ASYNCGOTO
Definition channel.h:1146
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition channel.h:991
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
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:2984
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:2390
struct stasis_app_control * control_create(struct ast_channel *channel, struct stasis_app *app)
Create a control object.
Definition control.c:131
int control_prestart_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all queued prestart commands.
Definition control.c:1598
void control_wait(struct stasis_app_control *control)
Blocks until control's command queue has a command available.
Definition control.c:1578
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:1773
int control_is_done(struct stasis_app_control *control)
Returns true if control_continue() has been called on this control.
Definition control.c:363
void control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition control.c:1545
int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all commands enqueued to this control.
Definition control.c:1558
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:1778
void control_set_app(struct stasis_app_control *control, struct stasis_app *app)
Set the application the control object belongs to.
Definition control.c:1754
int control_command_count(struct stasis_app_control *control)
Returns the count of items in a control's command queue.
Definition control.c:358
void control_silence_stop_now(struct stasis_app_control *control)
Stop playing silence to a channel right now.
Definition control.c:889
char * control_next_app(struct stasis_app_control *control)
Returns the name of the application we are moving to.
Definition control.c:1760
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:1626
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:1765
void control_mark_done(struct stasis_app_control *control)
Definition control.c:369
Internal API for the Stasis application controller.
Unreal channel derivative framework.
int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
Push the semi2 unreal channel into a bridge from either member of the unreal pair.
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.
@ 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)
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition manager.c:450
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:2213
stasis_user_multi_object_snapshot_type
Object type code for multi user object snapshots.
Definition stasis.h:1384
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:2187
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:1387
@ STASIS_UMOS_BRIDGE
Definition stasis.h:1386
@ STASIS_UMOS_CHANNEL
Definition stasis.h:1385
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
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition linkedlists.h:78
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
#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.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_RWLIST_TRAVERSE_SAFE_END
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition lock.h:626
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:7812
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:3295
const char * app_name(struct ast_app *app)
Definition pbx_app.c:475
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:776
struct ast_json * stasis_app_object_to_json(struct stasis_app *app)
Return the JSON representation of a Stasis application.
static int send_start_msg(struct stasis_app *app, struct ast_channel *chan, int argc, char *argv[])
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
static void stasis_app_bridge_channel_wrapper_destructor(void *obj)
Definition res_stasis.c:481
int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app)
Set the app that the replacement channel will be controlled by.
static struct ast_channel_snapshot * get_replace_channel_snapshot(struct ast_channel *chan)
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)
static struct stasis_app * find_app_by_name(const char *app_name)
#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:991
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:903
int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, char *argv[])
Stasis dialplan application callback.
int stasis_app_channel_is_internal(struct ast_channel *chan)
Is this channel internal to Stasis?
static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
static struct ast_channel * bridge_moh_create(struct ast_bridge *bridge)
Definition res_stasis.c:600
int stasis_app_send(const char *app_name, struct ast_json *message)
Send a message to the given Stasis application.
static const struct ast_datastore_info replace_channel_store_info
Definition res_stasis.c:957
static int bridges_compare(void *obj, void *arg, int flags)
Definition res_stasis.c:378
static void start_message_blob_dtor(void *obj)
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.
static void playback_after_bridge_cb(struct ast_channel *chan, void *data)
Definition res_stasis.c:731
int stasis_app_is_registered(const char *name)
Check if a Stasis application is registered.
void stasis_app_channel_set_stasis_end_published(struct ast_channel *chan)
Indicate that this channel has had a StasisEnd published for it.
void stasis_app_bridge_destroy(const char *bridge_id)
Destroy the bridge.
Definition res_stasis.c:908
static int channel_sanitizer(const struct ast_channel *chan)
Sanitization callback for channels.
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:724
struct ast_json * stasis_app_to_json(const char *app_name)
Return the JSON representation of a Stasis application.
int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
Register a new Stasis application.
static enum stasis_app_subscribe_res app_unsubscribe(struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
static void replace_channel_destroy(void *obj)
Definition res_stasis.c:948
static void remove_stasis_end_published(struct ast_channel *chan)
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.
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.
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:807
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:898
void stasis_app_unregister_event_source(struct stasis_app_event_source *obj)
Unregister an application event source.
static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
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)
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.
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.
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)
static const struct ast_datastore_info stasis_internal_channel_info
static int add_masquerade_store(struct ast_channel *chan)
struct ao2_container * app_bridges
Definition res_stasis.c:104
struct ast_channel * stasis_app_bridge_moh_channel(struct ast_bridge *bridge)
Finds or creates an announcer channel in a bridge that can play music on hold.
Definition res_stasis.c:655
enum stasis_app_user_event_res stasis_app_user_event(const char *app_name, const char *event_name, const char **source_uris, int sources_count, struct ast_json *json_variables)
Generate a Userevent for stasis app (echo to AMI)
void stasis_app_bridge_playback_channel_control_remove(const char *bridge_id, struct stasis_app_control *control)
Remove a bridge playback channel's control from the app controls list.
Definition res_stasis.c:717
#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)
int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
Send StasisEnd message to the listening app.
void stasis_app_control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
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.
static struct ast_channel * prepare_bridge_moh_channel(void)
Definition res_stasis.c:536
static int set_internal_datastore(struct ast_channel *chan)
#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)
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:738
void stasis_app_unregister(const char *app_name)
Unregister a Stasis application and unsubscribe from all event sources.
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.
enum stasis_app_subscribe_res(* app_subscription_handler)(struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
struct stasis_message_sanitizer app_sanitizer
Sanitization callbacks for communication to Stasis applications.
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)
struct stasis_app * stasis_app_get_by_name(const char *name)
Retrieve a handle to a Stasis application by its name.
int stasis_app_bridge_set_var_reportable(const char *bridge_id, const char *variable, const char *value, int report_events)
Set or clear a variable on a bridge and control ARI event reporting for it.
Definition res_stasis.c:923
static struct ast_json * app_event_sources_to_json(const struct stasis_app *app, struct ast_json *json)
static int bridges_sort(const void *left, const void *right, const int flags)
Definition res_stasis.c:418
struct stasis_app_control * stasis_app_control_find_by_channel_id(const char *channel_id)
Returns the handler for the channel with the given id.
Definition res_stasis.c:349
static const struct ast_datastore_info masquerade_store_info
static int cleanup_cb(void *obj, void *arg, int flags)
Definition res_stasis.c:309
static int bridges_channel_sort_fn(const void *obj_left, const void *obj_right, const int flags)
Definition res_stasis.c:509
static void * moh_channel_thread(void *data)
Definition res_stasis.c:555
void stasis_app_register_event_source(struct stasis_app_event_source *obj)
Register an application event source.
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:792
struct ao2_container * stasis_app_get_all(void)
Gets the names of all registered Stasis applications.
#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.
static int bridges_channel_compare(void *obj, void *arg, int flags)
Definition res_stasis.c:455
static int load_module(void)
static void remove_masquerade_store(struct ast_channel *chan)
static void remove_bridge_playback(char *bridge_id)
Definition res_stasis.c:699
static int unload_module(void)
static int masq_match_cb(void *obj, void *data, int flags)
static struct ast_bridge * bridge_create_common(const char *type, const char *name, const char *id, int invisible)
Definition res_stasis.c:828
struct ast_datastore_info set_end_published_info
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)
static int channel_id_sanitizer(const char *id)
Sanitization callback for channel unique IDs.
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:818
static struct replace_channel_store * get_replace_channel_store(struct ast_channel *chan, int no_create)
Definition res_stasis.c:962
int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan)
Has this channel had a StasisEnd published on it?
static struct ast_json * stasis_end_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
Definition res_stasis.c:115
static int bridges_channel_hash_fn(const void *obj, const int flags)
Definition res_stasis.c:488
struct stasis_app_control * stasis_app_control_find_by_channel(const struct ast_channel *chan)
Returns the handler for the given channel.
Definition res_stasis.c:338
char * app_get_replace_channel_app(struct ast_channel *chan)
Get the app that the replacement channel will be controlled by.
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.
static struct ast_json * stasis_start_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
Definition res_stasis.c:147
static int control_compare(void *obj, void *arg, int flags)
Definition res_stasis.c:270
struct stasis_app_control * stasis_app_control_create(struct ast_channel *chan)
Creates a control handler for a channel that isn't in a stasis app.
Definition res_stasis.c:333
int stasis_app_bridge_moh_stop(struct ast_bridge *bridge)
Breaks down MOH channels playing on the bridge created by stasis_app_bridge_moh_channel.
Definition res_stasis.c:675
#define NULL
Definition resample.c:96
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1546
#define STASIS_MESSAGE_TYPE_DEFN_LOCAL(name,...)
Boiler-plate messaging macro for defining local message types.
Definition stasis.h:1498
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1524
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:1589
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:1493
struct stasis_topic * ast_app_get_topic(struct stasis_app *app)
Returns the stasis topic for an app.
void stasis_app_unregister_event_sources(void)
Unregister core event sources.
int stasis_app_control_is_failed(const struct stasis_app_control *control)
Check if a control object is marked as "failed".
Definition control.c:382
stasis_app_user_event_res
Return code for stasis_app_user_event.
Definition stasis_app.h:265
@ STASIS_APP_USER_APP_NOT_FOUND
Definition stasis_app.h:267
@ STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND
Definition stasis_app.h:268
@ STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME
Definition stasis_app.h:269
@ STASIS_APP_USER_OK
Definition stasis_app.h:266
@ STASIS_APP_USER_INTERNAL_ERROR
Definition stasis_app.h:271
struct ast_json * stasis_app_event_filter_to_json(struct stasis_app *app, struct ast_json *json)
Convert and add the app's event type filter(s) to the given json object.
void stasis_app_register_event_sources(void)
Register core event sources.
void(* stasis_app_cb)(void *data, const char *app_name, struct ast_json *message)
Callback for Stasis application handler.
Definition stasis_app.h:67
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition control.c:983
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application's name.
stasis_app_subscribe_res
Return code for stasis_app_[un]subscribe.
Definition stasis_app.h:292
@ STASIS_ASR_OK
Definition stasis_app.h:293
@ STASIS_ASR_EVENT_SOURCE_BAD_SCHEME
Definition stasis_app.h:296
@ STASIS_ASR_INTERNAL_ERROR
Definition stasis_app.h:297
@ STASIS_ASR_EVENT_SOURCE_NOT_FOUND
Definition stasis_app.h:295
@ STASIS_ASR_APP_NOT_FOUND
Definition stasis_app.h:294
void stasis_app_control_shutdown(void)
Let Stasis app internals shut down.
Definition control.c:1743
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
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *bridge_id)
Returns the current snapshot for the bridge.
void ast_bridge_publish_state(struct ast_bridge *bridge)
Publish the state of a 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.
#define AST_STRING_FIELD(name)
Declare a string field.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
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:69
Structure that contains information about a bridge.
Definition bridge.h:355
const ast_string_field uniqueid
Definition bridge.h:407
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
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition channel.h:648
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:2162
Options for ast_pbx_run()
Definition pbx.h:409
unsigned int no_hangup_chan
Definition pbx.h:416
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:944
struct ast_channel_snapshot * replace_channel
Definition res_stasis.c:143
struct ast_channel_snapshot * channel
Definition res_stasis.c:142
struct ast_json * blob
Definition res_stasis.c:144
const ast_string_field bridge_id
Definition res_stasis.c:451
const ast_string_field channel_id
Definition res_stasis.c:451
struct ast_bridge * bridge
Definition control.c:67
Event source information and callbacks.
Definition stasis_app.h:184
const char * scheme
The scheme to match against on [un]subscribes.
Definition stasis_app.h:186
int(* unsubscribe)(struct stasis_app *app, const char *id)
Cancel the subscription an app has to an event source.
Definition stasis_app.h:216
void(* to_json)(const struct stasis_app *app, struct ast_json *json)
Convert event source data to json.
Definition stasis_app.h:234
struct stasis_app_event_source * next
Definition stasis_app.h:237
void *(* find)(const struct stasis_app *app, const char *id)
Find an event source data object by the given id/name.
Definition stasis_app.h:196
int(* is_subscribed)(struct stasis_app *app, const char *id)
Find an event source by the given id/name.
Definition stasis_app.h:226
int(* subscribe)(struct stasis_app *app, void *obj)
Subscribe an application to an event source.
Definition stasis_app.h:206
Structure containing callbacks for Stasis message sanitization.
Definition stasis.h:200
int(* channel)(const struct ast_channel *chan)
Callback which determines whether a channel should be sanitized from a message based on the channel.
Definition stasis.h:232
int(* channel_snapshot)(const struct ast_channel_snapshot *snapshot)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Definition stasis.h:221
int(* channel_id)(const char *channel_id)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Definition stasis.h:210
int value
Definition syslog.c:37
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:981
#define ast_assert(a)
Definition utils.h:779
#define ast_pthread_create_detached(a, b, c, d)
Definition utils.h:628
#define AST_UUID_STR_LEN
Definition uuid.h:27