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