Asterisk - The Open Source Telephony Project GIT-master-7988d11
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
927
928static void replace_channel_destroy(void *obj)
929{
930 struct replace_channel_store *replace = obj;
931
932 ao2_cleanup(replace->snapshot);
933 ast_free(replace->app);
935}
936
938 .type = "replace-channel-store",
939 .destroy = replace_channel_destroy,
940};
941
942static struct replace_channel_store *get_replace_channel_store(struct ast_channel *chan, int no_create)
943{
944 struct ast_datastore *datastore;
945 struct replace_channel_store *ret;
946
947 ast_channel_lock(chan);
949 if (!datastore && !no_create) {
951 if (datastore) {
952 ast_channel_datastore_add(chan, datastore);
953 }
954 }
955
956 if (!datastore) {
957 ast_channel_unlock(chan);
958 return NULL;
959 }
960
961 if (!datastore->data) {
962 datastore->data = ast_calloc(1, sizeof(struct replace_channel_store));
963 }
964
965 ret = datastore->data;
966 ast_channel_unlock(chan);
967
968 return ret;
969}
970
971int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot)
972{
974
975 if (!replace) {
976 return -1;
977 }
978
979 ao2_replace(replace->snapshot, replace_snapshot);
980 return 0;
981}
982
983int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app)
984{
986
987 if (!replace) {
988 return -1;
989 }
990
991 ast_free(replace->app);
992 replace->app = NULL;
993
994 if (replace_app) {
995 replace->app = ast_strdup(replace_app);
996 if (!replace->app) {
997 return -1;
998 }
999 }
1000
1001 return 0;
1002}
1003
1005{
1007 struct ast_channel_snapshot *replace_channel_snapshot;
1008
1009 if (!replace) {
1010 return NULL;
1011 }
1012
1013 replace_channel_snapshot = replace->snapshot;
1014 replace->snapshot = NULL;
1015
1016 return replace_channel_snapshot;
1017}
1018
1020{
1022 char *replace_channel_app;
1023
1024 if (!replace) {
1025 return NULL;
1026 }
1027
1028 replace_channel_app = replace->app;
1029 replace->app = NULL;
1030
1031 return replace_channel_app;
1032}
1033
1034static void start_message_blob_dtor(void *obj)
1035{
1036 struct start_message_blob *payload = obj;
1037
1038 ao2_cleanup(payload->channel);
1039 ao2_cleanup(payload->replace_channel);
1040 ast_json_unref(payload->blob);
1041}
1042
1043static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app *app,
1044 int argc, char *argv[], struct ast_channel_snapshot *snapshot,
1045 struct ast_channel_snapshot *replace_channel_snapshot)
1046{
1047 struct ast_json *json_blob;
1048 struct ast_json *json_args;
1049 struct start_message_blob *payload;
1050 struct stasis_message *msg;
1051 int i;
1052
1053 if (app_subscribe_channel(app, chan)) {
1054 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
1056 return -1;
1057 }
1058
1059 payload = ao2_alloc(sizeof(*payload), start_message_blob_dtor);
1060 if (!payload) {
1061 ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
1062 return -1;
1063 }
1064
1065 payload->channel = ao2_bump(snapshot);
1066 payload->replace_channel = ao2_bump(replace_channel_snapshot);
1067
1068 json_blob = ast_json_pack("{s: s, s: o, s: []}",
1069 "app", stasis_app_name(app),
1070 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1071 "args");
1072 if (!json_blob) {
1073 ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
1074 ao2_ref(payload, -1);
1075 return -1;
1076 }
1077 payload->blob = json_blob;
1078
1079
1080 /* Append arguments to args array */
1081 json_args = ast_json_object_get(json_blob, "args");
1082 ast_assert(json_args != NULL);
1083 for (i = 0; i < argc; ++i) {
1084 int r = ast_json_array_append(json_args,
1085 ast_json_string_create(argv[i]));
1086 if (r != 0) {
1087 ast_log(LOG_ERROR, "Error appending to StasisStart message\n");
1088 ao2_ref(payload, -1);
1089 return -1;
1090 }
1091 }
1092
1093
1094 msg = stasis_message_create(start_message_type(), payload);
1095 ao2_ref(payload, -1);
1096 if (!msg) {
1097 ast_log(LOG_ERROR, "Error sending StasisStart message\n");
1098 return -1;
1099 }
1100
1101 if (replace_channel_snapshot) {
1102 app_unsubscribe_channel_id(app, replace_channel_snapshot->base->uniqueid);
1103 }
1105 ao2_ref(msg, -1);
1106 return 0;
1107}
1108
1109static int send_start_msg(struct stasis_app *app, struct ast_channel *chan,
1110 int argc, char *argv[])
1111{
1112 int ret = -1;
1113 struct ast_channel_snapshot *snapshot;
1114 struct ast_channel_snapshot *replace_channel_snapshot;
1115
1116 ast_assert(chan != NULL);
1117
1118 replace_channel_snapshot = get_replace_channel_snapshot(chan);
1119
1120 /* Set channel info */
1121 ast_channel_lock(chan);
1122 snapshot = ast_channel_snapshot_create(chan);
1123 ast_channel_unlock(chan);
1124 if (snapshot) {
1125 ret = send_start_msg_snapshots(chan, app, argc, argv, snapshot, replace_channel_snapshot);
1126 ao2_ref(snapshot, -1);
1127 }
1128 ao2_cleanup(replace_channel_snapshot);
1129
1130 return ret;
1131}
1132
1133static void remove_masquerade_store(struct ast_channel *chan);
1134
1135int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
1136{
1138 struct ast_json *blob;
1139 struct stasis_message *msg;
1140
1141 if (sanitize && sanitize->channel
1142 && sanitize->channel(chan)) {
1143 return 0;
1144 }
1145
1146 blob = ast_json_pack("{s: s, s: o}",
1147 "app", stasis_app_name(app),
1148 "timestamp", ast_json_timeval(ast_tvnow(), NULL)
1149 );
1150 if (!blob) {
1151 ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n");
1152 return -1;
1153 }
1154
1157 msg = ast_channel_blob_create(chan, end_message_type(), blob);
1158 if (msg) {
1160 }
1161 ao2_cleanup(msg);
1162 ast_json_unref(blob);
1163
1164 return 0;
1165}
1166
1167static int masq_match_cb(void *obj, void *data, int flags)
1168{
1169 struct stasis_app_control *control = obj;
1170 struct ast_channel *chan = data;
1171
1172 if (!strcmp(ast_channel_uniqueid(chan),
1174 return CMP_MATCH;
1175 }
1176
1177 return 0;
1178}
1179
1180static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1181{
1182 struct stasis_app_control *control;
1183
1184 /*
1185 * At this point, old_chan is the channel pointer that is in Stasis() and
1186 * has the unknown channel's name in it while new_chan is the channel pointer
1187 * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1188 * about.
1189 *
1190 * Find and unlink control since the channel has a new name/uniqueid
1191 * and its hash has changed. Since the channel is leaving stasis don't
1192 * bother putting it back into the container. Nobody is going to
1193 * remove it from the container later.
1194 */
1195 control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, old_chan);
1196 if (!control) {
1197 ast_log(LOG_ERROR, "Could not find control for masqueraded channel\n");
1198 return;
1199 }
1200
1201 /* send the StasisEnd message to the app */
1203 app_send_end_msg(control_app(control), new_chan);
1204
1205 /* remove the datastore */
1206 remove_masquerade_store(old_chan);
1207
1208 ao2_cleanup(control);
1209}
1210
1211static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1212{
1213 RAII_VAR(struct ast_channel_snapshot *, new_snapshot, NULL, ao2_cleanup);
1214 RAII_VAR(struct ast_channel_snapshot *, old_snapshot, NULL, ao2_cleanup);
1215 struct stasis_app_control *control;
1216
1217 /* At this point, new_chan is the channel pointer that is in Stasis() and
1218 * has the unknown channel's name in it while old_chan is the channel pointer
1219 * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1220 * about */
1221
1222 /* grab a snapshot for the channel that is jumping into Stasis() */
1223 new_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(new_chan));
1224 if (!new_snapshot) {
1225 ast_log(LOG_ERROR, "Could not get snapshot for masquerading channel\n");
1226 return;
1227 }
1228
1229 /* grab a snapshot for the channel that has been kicked out of Stasis() */
1230 old_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(old_chan));
1231 if (!old_snapshot) {
1232 ast_log(LOG_ERROR, "Could not get snapshot for masqueraded channel\n");
1233 return;
1234 }
1235
1236 /*
1237 * Find, unlink, and relink control since the channel has a new
1238 * name/uniqueid and its hash has changed.
1239 */
1240 control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, new_chan);
1241 if (!control) {
1242 ast_log(LOG_ERROR, "Could not find control for masquerading channel\n");
1243 return;
1244 }
1245 ao2_link(app_controls, control);
1246
1247
1248 /* send the StasisStart with replace_channel to the app */
1249 send_start_msg_snapshots(new_chan, control_app(control), 0, NULL, new_snapshot,
1250 old_snapshot);
1251 /* send the StasisEnd message to the app */
1252 app_send_end_msg(control_app(control), old_chan);
1253
1254 ao2_cleanup(control);
1255}
1256
1258 .type = "stasis-masquerade",
1259 .chan_fixup = channel_stolen_cb,
1260 .chan_breakdown = channel_replaced_cb,
1261};
1262
1263static int has_masquerade_store(struct ast_channel *chan)
1264{
1265 SCOPED_CHANNELLOCK(lock, chan);
1267}
1268
1269static int add_masquerade_store(struct ast_channel *chan)
1270{
1271 struct ast_datastore *datastore;
1272
1273 SCOPED_CHANNELLOCK(lock, chan);
1275 return 0;
1276 }
1277
1279 if (!datastore) {
1280 return -1;
1281 }
1282
1283 ast_channel_datastore_add(chan, datastore);
1284
1285 return 0;
1286}
1287
1288static void remove_masquerade_store(struct ast_channel *chan)
1289{
1290 struct ast_datastore *datastore;
1291
1292 SCOPED_CHANNELLOCK(lock, chan);
1294 if (!datastore) {
1295 return;
1296 }
1297
1298 ast_channel_datastore_remove(chan, datastore);
1299 ast_datastore_free(datastore);
1300}
1301
1303{
1304 while (!control_is_done(control)) {
1305 int command_count;
1306 command_count = control_dispatch_all(control, chan);
1307
1308 ao2_lock(control);
1309
1310 if (control_command_count(control)) {
1311 /* If the command queue isn't empty, something added to the queue before it was locked. */
1312 ao2_unlock(control);
1313 continue;
1314 }
1315
1316 if (command_count == 0 || ast_channel_fdno(chan) == -1) {
1317 control_mark_done(control);
1318 ao2_unlock(control);
1319 break;
1320 }
1321 ao2_unlock(control);
1322 }
1323}
1324
1326{
1327 return control_is_done(control);
1328}
1329
1331{
1332 control_flush_queue(control);
1333}
1334
1336 .type = "stasis_end_published",
1337};
1338
1340{
1341 struct ast_datastore *datastore;
1342
1344 if (datastore) {
1345 ast_channel_lock(chan);
1346 ast_channel_datastore_add(chan, datastore);
1347 ast_channel_unlock(chan);
1348 }
1349}
1350
1352{
1353 struct ast_datastore *datastore;
1354
1355 ast_channel_lock(chan);
1357 ast_channel_unlock(chan);
1358
1359 return datastore ? 1 : 0;
1360}
1361
1363{
1364 struct ast_datastore *datastore;
1365
1366 ast_channel_lock(chan);
1368 if (datastore) {
1369 ast_channel_datastore_remove(chan, datastore);
1370 ast_datastore_free(datastore);
1371 }
1372 ast_channel_unlock(chan);
1373}
1374
1375/*! \brief Stasis dialplan application callback */
1376int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
1377 char *argv[])
1378{
1379 RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1380 RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
1381 struct ast_bridge *bridge = NULL;
1382 int res = 0;
1383 int needs_depart;
1384
1385 ast_assert(chan != NULL);
1386
1387 /* Just in case there's a lingering indication that the channel has had a stasis
1388 * end published on it, remove that now.
1389 */
1391
1392 if (!apps_registry) {
1393 return -1;
1394 }
1395
1397 if (!app) {
1399 "Stasis app '%s' not registered\n", app_name);
1400 return -1;
1401 }
1402 if (!app_is_active(app)) {
1404 "Stasis app '%s' not active\n", app_name);
1405 return -1;
1406 }
1407
1408 control = control_create(chan, app);
1409 if (!control) {
1410 ast_log(LOG_ERROR, "Control allocation failed or Stasis app '%s' not registered\n", app_name);
1411 return -1;
1412 }
1413
1414 if (!control_app(control)) {
1415 ast_log(LOG_ERROR, "Stasis app '%s' not registered\n", app_name);
1416 return -1;
1417 }
1418
1419 if (!app_is_active(control_app(control))) {
1420 ast_log(LOG_ERROR, "Stasis app '%s' not active\n", app_name);
1421 return -1;
1422 }
1423 ao2_link(app_controls, control);
1424
1425 if (add_masquerade_store(chan)) {
1426 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1427 return -1;
1428 }
1429
1430 res = send_start_msg(control_app(control), chan, argc, argv);
1431 if (res != 0) {
1433 "Error sending start message to '%s'\n", app_name);
1435 return -1;
1436 }
1437
1438 /* Pull queued prestart commands and execute */
1439 control_prestart_dispatch_all(control, chan);
1440
1441 while (!control_is_done(control)) {
1442 RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
1443 int r;
1444 int command_count;
1445 RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup);
1446
1447 /* Check to see if a bridge absorbed our hangup frame */
1448 if (ast_check_hangup_locked(chan)) {
1449 control_mark_done(control);
1450 break;
1451 }
1452
1453 /* control->next_app is only modified within the control thread, so this is safe */
1454 if (control_next_app(control)) {
1455 struct stasis_app *next_app = ao2_find(apps_registry, control_next_app(control), OBJ_SEARCH_KEY);
1456
1457 if (next_app && app_is_active(next_app)) {
1458 int idx;
1459 int next_argc;
1460 char **next_argv;
1461
1462 /* If something goes wrong in this conditional, res will need to be non-zero
1463 * so that the code below the exec loop knows something went wrong during a move.
1464 */
1466 res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1467 if (res != 0) {
1469 "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1470 control_mark_done(control);
1471 ao2_ref(next_app, -1);
1472 break;
1473 }
1474 } else {
1476 }
1477
1478 /* This will ao2_bump next_app, and unref the previous app by 1 */
1479 control_set_app(control, next_app);
1480
1481 /* There's a chance that the previous application is ready for clean up, so go ahead
1482 * and do that now.
1483 */
1484 cleanup();
1485
1486 /* We need to add another masquerade store, otherwise the leave message will
1487 * not show up for the correct application.
1488 */
1489 if (add_masquerade_store(chan)) {
1490 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1491 res = -1;
1492 control_mark_done(control);
1493 ao2_ref(next_app, -1);
1494 break;
1495 }
1496
1497 /* We MUST get the size before the list, as control_next_app_args steals the elements
1498 * from the string vector.
1499 */
1500 next_argc = control_next_app_args_size(control);
1501 next_argv = control_next_app_args(control);
1502
1503 res = send_start_msg(control_app(control), chan, next_argc, next_argv);
1504
1505 /* Even if res != 0, we still need to free the memory we got from control_argv */
1506 if (next_argv) {
1507 for (idx = 0; idx < next_argc; idx++) {
1508 ast_free(next_argv[idx]);
1509 }
1510 ast_free(next_argv);
1511 }
1512
1513 if (res != 0) {
1515 "Error sending start message to '%s'\n", stasis_app_name(control_app(control)));
1517 control_mark_done(control);
1518 ao2_ref(next_app, -1);
1519 break;
1520 }
1521
1522 /* Done switching applications, free memory and clean up */
1523 control_move_cleanup(control);
1524 } else {
1525 /* If we can't switch applications, do nothing */
1526 struct ast_json *msg;
1527 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1528
1529 if (!next_app) {
1530 ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not registered\n",
1531 control_next_app(control));
1532 } else {
1533 ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not active\n",
1534 control_next_app(control));
1535 }
1536
1538 if (!snapshot) {
1539 ast_log(LOG_ERROR, "Could not get channel shapshot for '%s'\n",
1540 ast_channel_name(chan));
1541 } else {
1542 struct ast_json *json_args;
1543 int next_argc = control_next_app_args_size(control);
1544 char **next_argv = control_next_app_args(control);
1545
1546 msg = ast_json_pack("{s: s, s: o, s: o, s: s, s: []}",
1547 "type", "ApplicationMoveFailed",
1548 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1549 "channel", ast_channel_snapshot_to_json(snapshot, NULL),
1550 "destination", control_next_app(control),
1551 "args");
1552 if (!msg) {
1553 ast_log(LOG_ERROR, "Failed to pack JSON for ApplicationMoveFailed message\n");
1554 } else {
1555 json_args = ast_json_object_get(msg, "args");
1556 if (!json_args) {
1557 ast_log(LOG_ERROR, "Could not get args json array");
1558 } else {
1559 int r = 0;
1560 int idx;
1561 for (idx = 0; idx < next_argc; ++idx) {
1562 r = ast_json_array_append(json_args,
1563 ast_json_string_create(next_argv[idx]));
1564 if (r != 0) {
1565 ast_log(LOG_ERROR, "Error appending to ApplicationMoveFailed message\n");
1566 break;
1567 }
1568 }
1569 if (r == 0) {
1570 app_send(control_app(control), msg);
1571 }
1572 }
1573 ast_json_unref(msg);
1574 }
1575 }
1576 }
1577 control_move_cleanup(control);
1578 ao2_cleanup(next_app);
1579 }
1580
1581 last_bridge = bridge;
1582 bridge = ao2_bump(stasis_app_get_bridge(control));
1583
1584 if (bridge != last_bridge) {
1585 if (last_bridge) {
1586 app_unsubscribe_bridge(control_app(control), last_bridge);
1587 }
1588 if (bridge) {
1589 app_subscribe_bridge(control_app(control), bridge);
1590 }
1591 }
1592
1593 if (bridge) {
1594 /* Bridge/dial is handling channel frames */
1595 control_wait(control);
1596 control_dispatch_all(control, chan);
1597 continue;
1598 }
1599
1600 r = ast_waitfor(chan, MAX_WAIT_MS);
1601
1602 if (r < 0) {
1603 ast_debug(3, "%s: Poll error\n",
1604 ast_channel_uniqueid(chan));
1605 control_mark_done(control);
1606 break;
1607 }
1608
1609 command_count = control_dispatch_all(control, chan);
1610
1611 if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1612 /* Command drained the channel; wait for next frame */
1613 continue;
1614 }
1615
1616 if (r == 0) {
1617 /* Timeout */
1618 continue;
1619 }
1620
1621 f = ast_read(chan);
1622 if (!f) {
1623 /* Continue on in the dialplan */
1624 ast_debug(3, "%s: Hangup (no more frames)\n",
1625 ast_channel_uniqueid(chan));
1626 control_mark_done(control);
1627 break;
1628 }
1629
1630 if (f->frametype == AST_FRAME_CONTROL) {
1631 if (f->subclass.integer == AST_CONTROL_HANGUP) {
1632 /* Continue on in the dialplan */
1633 ast_debug(3, "%s: Hangup\n",
1634 ast_channel_uniqueid(chan));
1635 control_mark_done(control);
1636 break;
1637 }
1638 }
1639 }
1640
1641 ast_channel_lock(chan);
1642 needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1643 ast_channel_unlock(chan);
1644 if (needs_depart) {
1645 ast_bridge_depart(chan);
1646 }
1647
1648 if (stasis_app_get_bridge(control)) {
1650 }
1651 ao2_cleanup(bridge);
1652
1653 /* Only publish a stasis_end event if it hasn't already been published */
1654 if (!res && !stasis_app_channel_is_stasis_end_published(chan)) {
1655 /* A masquerade has occurred and this message will be wrong so it
1656 * has already been sent elsewhere. */
1657 res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1658 if (res != 0) {
1660 "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1661 return res;
1662 }
1663 } else {
1665 }
1666
1667 control_flush_queue(control);
1668
1669 /* Stop any lingering silence generator */
1670 control_silence_stop_now(control);
1671
1672 /* There's an off chance that app is ready for cleanup. Go ahead
1673 * and clean up, just in case
1674 */
1675 cleanup();
1676
1677 if (stasis_app_control_is_failed(control)) {
1678 res = -1;
1679 }
1680 /* The control needs to be removed from the controls container in
1681 * case a new PBX is started and ends up coming back into Stasis.
1682 */
1683 control_unlink(control);
1684 control = NULL;
1685
1686 if (!res && !ast_channel_pbx(chan)) {
1687 int chan_hungup;
1688
1689 /* The ASYNCGOTO softhangup flag may have broken the channel out of
1690 * its bridge to run dialplan, so if there's no pbx on the channel
1691 * let it run dialplan here. Otherwise, it will run when this
1692 * application exits. */
1693 ast_channel_lock(chan);
1695 chan_hungup = ast_check_hangup(chan);
1696 ast_channel_unlock(chan);
1697
1698 if (!chan_hungup) {
1699 struct ast_pbx_args pbx_args;
1700
1701 memset(&pbx_args, 0, sizeof(pbx_args));
1702 pbx_args.no_hangup_chan = 1;
1703
1704 res = ast_pbx_run_args(chan, &pbx_args);
1705 }
1706 }
1707
1708 return res;
1709}
1710
1711int stasis_app_send(const char *app_name, struct ast_json *message)
1712{
1713 struct stasis_app *app;
1714
1715 if (!apps_registry) {
1716 return -1;
1717 }
1718
1720 if (!app) {
1721 /* XXX We can do a better job handling late binding, queueing up
1722 * the call for a few seconds to wait for the app to register.
1723 */
1725 "Stasis app '%s' not registered\n", app_name);
1726 return -1;
1727 }
1729 ao2_ref(app, -1);
1730
1731 return 0;
1732}
1733
1734static struct stasis_app *find_app_by_name(const char *app_name)
1735{
1736 struct stasis_app *res = NULL;
1737
1738 if (!apps_registry) {
1739 return NULL;
1740 }
1741
1742 if (!ast_strlen_zero(app_name)) {
1744 }
1745
1746 return res;
1747}
1748
1750{
1751 return find_app_by_name(name);
1752}
1753
1755{
1757
1758 /*
1759 * It's safe to unref app here because we're not actually
1760 * using it or returning it.
1761 */
1763
1764 return app != NULL;
1765}
1766
1767static int append_name(void *obj, void *arg, int flags)
1768{
1769 struct stasis_app *app = obj;
1770 struct ao2_container *apps = arg;
1771
1773 return 0;
1774}
1775
1777{
1778 struct ao2_container *apps;
1779
1780 if (!apps_registry) {
1781 return NULL;
1782 }
1783
1785 if (!apps) {
1786 return NULL;
1787 }
1788
1790
1791 return apps;
1792}
1793
1794static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
1795{
1796 RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1797
1798 if (!apps_registry) {
1799 return -1;
1800 }
1801
1804 if (app) {
1805 /*
1806 * We need to unlock the apps_registry before calling app_update to
1807 * prevent the possibility of a deadlock with the session.
1808 */
1810 app_update(app, handler, data);
1811 cleanup();
1812 return 0;
1813 }
1814
1816 if (!app) {
1818 return -1;
1819 }
1820
1821 if (all_events) {
1822 struct stasis_app_event_source *source;
1823
1826 if (!source->subscribe) {
1827 continue;
1828 }
1829
1830 source->subscribe(app, NULL);
1831 }
1833 }
1835
1837
1838 /* We lazily clean up the apps_registry, because it's good enough to
1839 * prevent memory leaks, and we're lazy.
1840 */
1841 cleanup();
1842 return 0;
1843}
1844
1846{
1847 return __stasis_app_register(app_name, handler, data, 0);
1848}
1849
1851{
1852 return __stasis_app_register(app_name, handler, data, 1);
1853}
1854
1856{
1857 struct stasis_app *app;
1858 struct stasis_app_event_source *source;
1859 int res;
1860
1861 if (!app_name) {
1862 return;
1863 }
1864
1865 if (!apps_registry) {
1866 return;
1867 }
1868
1870 if (!app) {
1872 "Stasis app '%s' not registered\n", app_name);
1873 return;
1874 }
1875
1876 /* Unsubscribe from all event sources. */
1879 if (!source->unsubscribe || !source->is_subscribed
1880 || !source->is_subscribed(app, NULL)) {
1881 continue;
1882 }
1883
1884 res = source->unsubscribe(app, NULL);
1885 if (res) {
1886 ast_log(LOG_WARNING, "%s: Error unsubscribing from event source '%s'\n",
1887 app_name, source->scheme);
1888 }
1889 }
1891
1893
1894 /* There's a decent chance that app is ready for cleanup. Go ahead
1895 * and clean up, just in case
1896 */
1897 cleanup();
1898
1899 ao2_ref(app, -1);
1900}
1901
1908
1910{
1911 struct stasis_app_event_source *source;
1912
1915 if (source == obj) {
1917 break;
1918 }
1919 }
1922}
1923
1924/*!
1925 * \internal
1926 * \brief Convert event source data to JSON.
1927 *
1928 * Calls each event source that has a "to_json" handler allowing each
1929 * source to add data to the given JSON object.
1930 *
1931 * \param app application associated with the event source
1932 * \param json a json object to "fill"
1933 *
1934 * \retval The given json object.
1935 */
1937 const struct stasis_app *app, struct ast_json *json)
1938{
1939 struct stasis_app_event_source *source;
1940
1943 if (source->to_json) {
1944 source->to_json(app, json);
1945 }
1946 }
1948
1949 return json;
1950}
1951
1953{
1954 if (!app) {
1955 return NULL;
1956 }
1957
1960}
1961
1963{
1965 struct ast_json *json = stasis_app_object_to_json(app);
1966
1968
1969 return json;
1970}
1971
1972/*!
1973 * \internal
1974 * \brief Finds an event source that matches a uri scheme.
1975 *
1976 * Uri(s) should begin with a particular scheme that can be matched
1977 * against an event source.
1978 *
1979 * \param uri uri containing a scheme to match
1980 *
1981 * \retval an event source if found, NULL otherwise.
1982 */
1983static struct stasis_app_event_source *app_event_source_find(const char *uri)
1984{
1985 struct stasis_app_event_source *source;
1986
1989 if (ast_begins_with(uri, source->scheme)) {
1990 break;
1991 }
1992 }
1994
1995 return source;
1996}
1997
1998/*!
1999 * \internal
2000 * \brief Callback for subscription handling
2001 *
2002 * \param app [un]subscribing application
2003 * \param uri scheme:id of an event source
2004 * \param event_source being [un]subscribed [from]to
2005 *
2006 * \retval stasis_app_subscribe_res return code.
2007 */
2009 struct stasis_app *app, const char *uri,
2010 struct stasis_app_event_source *event_source);
2011
2012/*!
2013 * \internal
2014 * \brief Subscriptions handler for application [un]subscribing.
2015 *
2016 * \param app_name Name of the application to subscribe.
2017 * \param event_source_uris URIs for the event sources to subscribe to.
2018 * \param event_sources_count Array size of event_source_uris.
2019 * \param json Optional output pointer for JSON representation of the app
2020 * after adding the subscription.
2021 * \param handler [un]subscribe handler
2022 *
2023 * \retval stasis_app_subscribe_res return code.
2024 */
2026 const char *app_name, const char **event_source_uris,
2027 int event_sources_count, struct ast_json **json,
2029{
2031 int i;
2032
2034
2035 if (!app) {
2037 }
2038
2039 for (i = 0; i < event_sources_count; ++i) {
2040 const char *uri = event_source_uris[i];
2041 struct stasis_app_event_source *event_source;
2042 enum stasis_app_subscribe_res res;
2043
2044 event_source = app_event_source_find(uri);
2045 if (!event_source) {
2046 ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
2047 ao2_ref(app, -1);
2048
2050 }
2051
2052 res = handler(app, uri, event_source);
2053 if (res != STASIS_ASR_OK) {
2054 ao2_ref(app, -1);
2055
2056 return res;
2057 }
2058 }
2059
2060 if (json) {
2061 ast_debug(3, "%s: Successful; setting results\n", app_name);
2063 }
2064
2065 ao2_ref(app, -1);
2066
2067 return STASIS_ASR_OK;
2068}
2069
2071 struct ast_channel *chan)
2072{
2074 int res;
2075
2076 if (!app) {
2078 }
2079
2080 ast_debug(3, "%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan));
2081
2082 res = app_subscribe_channel(app, chan);
2083 ao2_ref(app, -1);
2084
2085 if (res != 0) {
2086 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
2089 }
2090
2091 return STASIS_ASR_OK;
2092}
2093
2094
2095/*!
2096 * \internal
2097 * \brief Subscribe an app to an event source.
2098 *
2099 * \param app subscribing application
2100 * \param uri scheme:id of an event source
2101 * \param event_source being subscribed to
2102 *
2103 * \retval stasis_app_subscribe_res return code.
2104 */
2106 struct stasis_app *app, const char *uri,
2107 struct stasis_app_event_source *event_source)
2108{
2109 const char *app_name = stasis_app_name(app);
2110 RAII_VAR(void *, obj, NULL, ao2_cleanup);
2111
2112 ast_debug(3, "%s: Checking %s\n", app_name, uri);
2113
2114 if (!ast_strlen_zero(uri + strlen(event_source->scheme)) &&
2115 (!event_source->find || (!(obj = event_source->find(app, uri + strlen(event_source->scheme)))))) {
2116 ast_log(LOG_WARNING, "Event source not found: %s\n", uri);
2118 }
2119
2120 ast_debug(3, "%s: Subscribing to %s\n", app_name, uri);
2121
2122 if (!event_source->subscribe || (event_source->subscribe(app, obj))) {
2123 ast_log(LOG_WARNING, "Error subscribing app '%s' to '%s'\n",
2124 app_name, uri);
2126 }
2127
2128 return STASIS_ASR_OK;
2129}
2130
2132 const char **event_source_uris, int event_sources_count,
2133 struct ast_json **json)
2134{
2136 app_name, event_source_uris, event_sources_count,
2137 json, app_subscribe);
2138}
2139
2140/*!
2141 * \internal
2142 * \brief Unsubscribe an app from an event source.
2143 *
2144 * \param app application to unsubscribe
2145 * \param uri scheme:id of an event source
2146 * \param event_source being unsubscribed from
2147 *
2148 * \retval stasis_app_subscribe_res return code.
2149 */
2151 struct stasis_app *app, const char *uri,
2152 struct stasis_app_event_source *event_source)
2153{
2154 const char *app_name = stasis_app_name(app);
2155 const char *id = uri + strlen(event_source->scheme);
2156
2157 if (!event_source->is_subscribed ||
2158 (!event_source->is_subscribed(app, id))) {
2160 }
2161
2162 ast_debug(3, "%s: Unsubscribing from %s\n", app_name, uri);
2163
2164 if (!event_source->unsubscribe || (event_source->unsubscribe(app, id))) {
2165 ast_log(LOG_WARNING, "Error unsubscribing app '%s' to '%s'\n",
2166 app_name, uri);
2167 return -1;
2168 }
2169 return 0;
2170}
2171
2173 const char **event_source_uris, int event_sources_count,
2174 struct ast_json **json)
2175{
2177 app_name, event_source_uris, event_sources_count,
2178 json, app_unsubscribe);
2179}
2180
2182 const char *event_name,
2183 const char **source_uris, int sources_count,
2184 struct ast_json *json_variables)
2185{
2187 struct ast_json *blob = NULL;
2188 struct ast_multi_object_blob *multi;
2189 struct stasis_message *message;
2191 int have_channel = 0;
2192 int i;
2193
2194 if (!app) {
2195 ast_log(LOG_WARNING, "App %s not found\n", app_name);
2197 }
2198
2200 return res;
2201 }
2202
2203 if (json_variables) {
2204 struct ast_json *json_value = ast_json_string_create(event_name);
2205
2206 if (json_value && !ast_json_object_set(json_variables, "eventname", json_value)) {
2207 blob = ast_json_ref(json_variables);
2208 }
2209 } else {
2210 blob = ast_json_pack("{s: s}", "eventname", event_name);
2211 }
2212
2213 if (!blob) {
2214 ast_log(LOG_ERROR, "Failed to initialize blob\n");
2215
2216 return res;
2217 }
2218
2219 multi = ast_multi_object_blob_create(blob);
2220 ast_json_unref(blob);
2221 if (!multi) {
2222 ast_log(LOG_ERROR, "Failed to initialize multi\n");
2223
2224 return res;
2225 }
2226
2227 for (i = 0; i < sources_count; ++i) {
2228 const char *uri = source_uris[i];
2229 void *snapshot=NULL;
2231
2232 if (ast_begins_with(uri, "channel:")) {
2234 snapshot = ast_channel_snapshot_get_latest(uri + 8);
2235 have_channel = 1;
2236 } else if (ast_begins_with(uri, "bridge:")) {
2238 snapshot = ast_bridge_get_snapshot_by_uniqueid(uri + 7);
2239 } else if (ast_begins_with(uri, "endpoint:")) {
2241 snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL);
2242 } else {
2243 ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
2244 ao2_ref(multi, -1);
2245
2247 }
2248 if (!snapshot) {
2249 ast_log(LOG_ERROR, "Unable to get snapshot for %s\n", uri);
2250 ao2_ref(multi, -1);
2251
2253 }
2254 ast_multi_object_blob_add(multi, type, snapshot);
2255 }
2256
2258 ao2_ref(multi, -1);
2259
2260 if (!message) {
2261 ast_log(LOG_ERROR, "Unable to create stasis user event message\n");
2262 return res;
2263 }
2264
2265 /*
2266 * Publishing to two different topics is normally to be avoided -- except
2267 * in this case both are final destinations with no forwards (only listeners).
2268 * The message has to be delivered to the application topic for ARI, but a
2269 * copy is also delivered directly to the manager for AMI if there is a channel.
2270 */
2272
2273 if (have_channel) {
2275 }
2276 ao2_ref(message, -1);
2277
2278 return STASIS_APP_USER_OK;
2279}
2280
2281static int unload_module(void)
2282{
2284
2286
2287 cleanup();
2288
2290
2293
2296
2298 app_bridges = NULL;
2299
2302
2305
2306 STASIS_MESSAGE_TYPE_CLEANUP(end_message_type);
2307 STASIS_MESSAGE_TYPE_CLEANUP(start_message_type);
2308
2309 return 0;
2310}
2311
2312/*! \brief Sanitization callback for channel snapshots */
2313static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
2314{
2315 if (!snapshot || !(snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL)) {
2316 return 0;
2317 }
2318 return 1;
2319}
2320
2321/*! \brief Sanitization callback for channels */
2322static int channel_sanitizer(const struct ast_channel *chan)
2323{
2324 if (!chan || !(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)) {
2325 return 0;
2326 }
2327 return 1;
2328}
2329
2330/*! \brief Sanitization callback for channel unique IDs */
2331static int channel_id_sanitizer(const char *id)
2332{
2333 struct ast_channel_snapshot *snapshot;
2334 int ret;
2335
2336 snapshot = ast_channel_snapshot_get_latest(id);
2337 ret = channel_snapshot_sanitizer(snapshot);
2338 ao2_cleanup(snapshot);
2339
2340 return ret;
2341}
2342
2343/*! \brief Sanitization callbacks for communication to Stasis applications */
2349
2354
2356 .type = "stasis-internal-channel",
2357};
2358
2359static int set_internal_datastore(struct ast_channel *chan)
2360{
2361 struct ast_datastore *datastore;
2362
2364 if (!datastore) {
2366 if (!datastore) {
2367 return -1;
2368 }
2369 ast_channel_datastore_add(chan, datastore);
2370 }
2371 return 0;
2372}
2373
2375{
2376 struct ast_channel *outchan = NULL, *outowner = NULL;
2377 int res = 0;
2378 struct ast_unreal_pvt *unreal_pvt = ast_channel_tech_pvt(chan);
2379
2380 ao2_ref(unreal_pvt, +1);
2381 ast_unreal_lock_all(unreal_pvt, &outowner, &outchan);
2382 if (outowner) {
2383 res |= set_internal_datastore(outowner);
2384 ast_channel_unlock(outowner);
2385 ast_channel_unref(outowner);
2386 }
2387 if (outchan) {
2388 res |= set_internal_datastore(outchan);
2389 ast_channel_unlock(outchan);
2390 ast_channel_unref(outchan);
2391 }
2392 ao2_unlock(unreal_pvt);
2393 ao2_ref(unreal_pvt, -1);
2394 return res;
2395}
2396
2398{
2399 int res;
2400
2404
2405 return res;
2406}
2407
2409{
2410 struct ast_datastore *datastore;
2411 int res = 0;
2412
2413 ast_channel_lock(chan);
2415 if (datastore) {
2416 res = 1;
2417 }
2418 ast_channel_unlock(chan);
2419
2420 return res;
2421}
2422
2460
2462 .load_pri = AST_MODPRI_APP_DEPEND - 1,
2463 .support_level = AST_MODULE_SUPPORT_CORE,
2464 .load = load_module,
2465 .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:1975
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition bridge.c:1009
@ AST_BRIDGE_CAPABILITY_MULTIMIX
Definition bridge.h:98
@ AST_BRIDGE_CAPABILITY_HOLDING
Definition bridge.h:90
ast_bridge_video_mode_type
Video source modes.
Definition bridge.h:102
@ AST_BRIDGE_VIDEO_MODE_SINGLE_SRC
Definition bridge.h:106
@ AST_BRIDGE_VIDEO_MODE_TALKER_SRC
Definition bridge.h:109
@ AST_BRIDGE_VIDEO_MODE_SFU
Definition bridge.h:113
#define BRIDGE_PRINTF_VARS(bridge)
Definition bridge.h:80
#define BRIDGE_PRINTF_SPEC
Definition bridge.h:79
After Bridge Execution API.
ast_bridge_after_cb_reason
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:2574
int ast_channel_fdno(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition channel.h:2989
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3200
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:4312
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)
@ AST_SOFTHANGUP_ASYNCGOTO
Definition channel.h:1146
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:3025
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:6411
#define ast_channel_unlock(chan)
Definition channel.h:2990
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition channel.h:991
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:1587
void control_wait(struct stasis_app_control *control)
Blocks until control's command queue has a command available.
Definition control.c:1567
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:1762
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:1534
int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all commands enqueued to this control.
Definition control.c:1547
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:1767
void control_set_app(struct stasis_app_control *control, struct stasis_app *app)
Set the application the control object belongs to.
Definition control.c:1743
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:878
char * control_next_app(struct stasis_app_control *control)
Returns the name of the application we are moving to.
Definition control.c:1749
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:1615
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:1754
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:2202
stasis_user_multi_object_snapshot_type
Object type code for multi user object snapshots.
Definition stasis.h:1353
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.
struct ast_multi_object_blob * ast_multi_object_blob_create(struct ast_json *blob)
Create a stasis multi object blob.
Definition stasis.c:2176
struct ast_endpoint_snapshot * ast_endpoint_latest_snapshot(const char *tech, const char *resource)
Retrieve the most recent snapshot for the endpoint with the given name.
struct stasis_message_type * ast_multi_user_event_type(void)
Message type for custom user defined events with multi object blobs.
struct stasis_message * ast_channel_blob_create(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Creates a ast_channel_blob message.
@ STASIS_UMOS_ENDPOINT
Definition stasis.h:1356
@ STASIS_UMOS_BRIDGE
Definition stasis.h:1355
@ STASIS_UMOS_CHANNEL
Definition stasis.h:1354
void ast_frame_dtor(struct ast_frame *frame)
NULL-safe wrapper for ast_frfree, good for RAII_VAR.
Definition main/frame.c:187
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_HANGUP
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition json.c:278
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition json.c:378
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition json.c:670
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition json.c:67
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition json.c:414
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition json.c:407
#define AST_RWLIST_REMOVE_CURRENT
#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:7850
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:4771
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.
Definition res_stasis.c:983
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:971
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:937
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:928
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.
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:942
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:1515
#define STASIS_MESSAGE_TYPE_DEFN_LOCAL(name,...)
Boiler-plate messaging macro for defining local message types.
Definition stasis.h:1467
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1578
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:1482
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:972
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:1732
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.
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:353
const ast_string_field uniqueid
Definition bridge.h:405
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
const ast_string_field uniqueid
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_base * base
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:2151
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:924
struct ast_channel_snapshot * replace_channel
Definition res_stasis.c:143
struct ast_channel_snapshot * channel
Definition res_stasis.c:142
struct ast_json * blob
Definition res_stasis.c:144
const ast_string_field bridge_id
Definition res_stasis.c:451
const ast_string_field channel_id
Definition res_stasis.c:451
struct ast_bridge * bridge
Definition control.c:67
Event source information and callbacks.
Definition stasis_app.h:184
const char * scheme
The scheme to match against on [un]subscribes.
Definition stasis_app.h:186
int(* unsubscribe)(struct stasis_app *app, const char *id)
Cancel the subscription an app has to an event source.
Definition stasis_app.h:216
void(* to_json)(const struct stasis_app *app, struct ast_json *json)
Convert event source data to json.
Definition stasis_app.h:234
struct stasis_app_event_source * next
Definition stasis_app.h:237
void *(* find)(const struct stasis_app *app, const char *id)
Find an event source data object by the given id/name.
Definition stasis_app.h:196
int(* is_subscribed)(struct stasis_app *app, const char *id)
Find an event source by the given id/name.
Definition stasis_app.h:226
int(* subscribe)(struct stasis_app *app, void *obj)
Subscribe an application to an event source.
Definition stasis_app.h:206
Structure containing callbacks for Stasis message sanitization.
Definition stasis.h:200
int(* channel)(const struct ast_channel *chan)
Callback which determines whether a channel should be sanitized from a message based on the channel.
Definition stasis.h:232
int(* channel_snapshot)(const struct ast_channel_snapshot *snapshot)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Definition stasis.h:221
int(* channel_id)(const char *channel_id)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Definition stasis.h:210
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition test_ari.c:59
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h: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