Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
24  *
25  * <code>res_stasis.so</code> brings together the various components of the
26  * Stasis application infrastructure.
27  *
28  * First, there's the Stasis application handler, stasis_app_exec(). This is
29  * called by <code>app_stasis.so</code> to give control of a channel to the
30  * Stasis application code from the dialplan.
31  *
32  * While a channel is in stasis_app_exec(), it has a \ref stasis_app_control
33  * object, which may be used to control the channel.
34  *
35  * To control the channel, commands may be sent to channel using
36  * stasis_app_send_command() and stasis_app_send_async_command().
37  *
38  * Alongside this, applications may be registered/unregistered using
39  * stasis_app_register()/stasis_app_unregister(). While a channel is in Stasis,
40  * events received on the channel's topic are converted to JSON and forwarded to
41  * the \ref stasis_app_cb. The application may also subscribe to the channel to
42  * continue to receive messages even after the channel has left Stasis, but it
43  * will not be able to control it.
44  *
45  * Given all the stuff that comes together in this module, it's been broken up
46  * into several pieces that are in <code>res/stasis/</code> and compiled into
47  * <code>res_stasis.so</code>.
48  */
49 
50 /*** MODULEINFO
51  <support_level>core</support_level>
52  ***/
53 
54 #include "asterisk.h"
55 
56 #include "asterisk/astobj2.h"
57 #include "asterisk/callerid.h"
58 #include "asterisk/module.h"
64 #include "asterisk/strings.h"
65 #include "stasis/app.h"
66 #include "stasis/control.h"
67 #include "stasis/messaging.h"
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 
103 
105 
107 
109 
110 /*!
111  * \internal \brief List of registered event sources.
112  */
114 
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 
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 
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),
598  if (!new_wrapper) {
599  ast_hangup(chan);
600  return NULL;
601  }
602 
604  || ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid)
605  || ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan))) {
606  ao2_ref(new_wrapper, -1);
607  ast_hangup(chan);
608  return NULL;
609  }
610 
611  if (!ao2_link_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK)) {
612  ao2_ref(new_wrapper, -1);
613  ast_hangup(chan);
614  return NULL;
615  }
616 
617  /* Pass the new_wrapper ref to moh_channel_thread() */
618  if (ast_pthread_create_detached(&threadid, NULL, moh_channel_thread, new_wrapper)) {
619  ast_log(LOG_ERROR, "Failed to create channel thread. Abandoning MOH channel creation.\n");
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);
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) {
682  if (control) {
683  ao2_unlink(app_controls, control);
684  ao2_ref(control, -1);
685  }
686  ao2_ref(wrapper, -1);
687  }
688  ast_free(bridge_id);
689 }
690 
692 {
693  char *bridge_id = data;
694 
695  remove_bridge_playback(bridge_id);
696 }
697 
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 {
710  char *bridge_id = ast_strdup(bridge->uniqueid);
711 
712  if (!bridge_id) {
713  return -1;
714  }
715 
718  ast_free(bridge_id);
719  return -1;
720  }
721 
722  new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
724  if (!new_wrapper) {
725  return -1;
726  }
727 
728  if (ast_string_field_init(new_wrapper, 32)) {
729  return -1;
730  }
731 
732  ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
733  ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
734 
735  if (!ao2_link(app_bridges_playback, new_wrapper)) {
736  return -1;
737  }
738 
739  ao2_link(app_controls, control);
740  return 0;
741 }
742 
744  struct stasis_app_control *control)
745 {
746  struct stasis_app_bridge_channel_wrapper *wrapper;
747 
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 
805  if (invisible) {
806  flags |= AST_BRIDGE_FLAG_INVISIBLE;
807  }
808 
809  while ((requested_type = strsep(&requested_types, ","))) {
810  requested_type = ast_strip(requested_type);
811 
812  if (!strcmp(requested_type, "mixing")) {
813  capabilities |= STASIS_BRIDGE_MIXING_CAPABILITIES;
814  flags |= AST_BRIDGE_FLAG_SMART;
815  } else if (!strcmp(requested_type, "holding")) {
816  capabilities |= AST_BRIDGE_CAPABILITY_HOLDING;
817  } else if (!strcmp(requested_type, "dtmf_events") ||
818  !strcmp(requested_type, "proxy_media")) {
819  capabilities &= ~AST_BRIDGE_CAPABILITY_NATIVE;
820  } else if (!strcmp(requested_type, "video_sfu")) {
821  video_mode = AST_BRIDGE_VIDEO_MODE_SFU;
822  } else if (!strcmp(requested_type, "video_single")) {
824  }
825  }
826 
827  /* For an SFU video bridge we ensure it always remains in multimix for the best experience. */
828  if (video_mode == AST_BRIDGE_VIDEO_MODE_SFU) {
829  capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX;
830  flags &= ~AST_BRIDGE_FLAG_SMART;
831  }
832 
833  if (!capabilities
834  /* Holding and mixing capabilities don't mix. */
835  || ((capabilities & AST_BRIDGE_CAPABILITY_HOLDING)
836  && (capabilities & (STASIS_BRIDGE_MIXING_CAPABILITIES)))) {
837  return NULL;
838  }
839 
840  bridge = bridge_stasis_new(capabilities, flags, name, id, video_mode);
841  if (bridge) {
842  if (!ao2_link(app_bridges, bridge)) {
843  ast_bridge_destroy(bridge, 0);
844  bridge = NULL;
845  }
846  }
847 
848  return bridge;
849 }
850 
851 struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id)
852 {
853  return bridge_create_common(type, name, id, 0);
854 }
855 
856 struct ast_bridge *stasis_app_bridge_create_invisible(const char *type, const char *name, const char *id)
857 {
858  return bridge_create_common(type, name, id, 1);
859 }
860 
861 void stasis_app_bridge_destroy(const char *bridge_id)
862 {
863  struct ast_bridge *bridge = stasis_app_bridge_find_by_id(bridge_id);
864  if (!bridge) {
865  return;
866  }
867  ao2_unlink(app_bridges, bridge);
868  ast_bridge_destroy(bridge, 0);
869 }
870 
873  char *app;
874 };
875 
876 static void replace_channel_destroy(void *obj)
877 {
878  struct replace_channel_store *replace = obj;
879 
880  ao2_cleanup(replace->snapshot);
881  ast_free(replace->app);
882  ast_free(replace);
883 }
884 
886  .type = "replace-channel-store",
887  .destroy = replace_channel_destroy,
888 };
889 
890 static struct replace_channel_store *get_replace_channel_store(struct ast_channel *chan, int no_create)
891 {
892  struct ast_datastore *datastore;
893  struct replace_channel_store *ret;
894 
895  ast_channel_lock(chan);
896  datastore = ast_channel_datastore_find(chan, &replace_channel_store_info, NULL);
897  if (!datastore && !no_create) {
898  datastore = ast_datastore_alloc(&replace_channel_store_info, NULL);
899  if (datastore) {
900  ast_channel_datastore_add(chan, datastore);
901  }
902  }
903 
904  if (!datastore) {
905  ast_channel_unlock(chan);
906  return NULL;
907  }
908 
909  if (!datastore->data) {
910  datastore->data = ast_calloc(1, sizeof(struct replace_channel_store));
911  }
912 
913  ret = datastore->data;
914  ast_channel_unlock(chan);
915 
916  return ret;
917 }
918 
919 int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot)
920 {
922 
923  if (!replace) {
924  return -1;
925  }
926 
927  ao2_replace(replace->snapshot, replace_snapshot);
928  return 0;
929 }
930 
931 int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app)
932 {
934 
935  if (!replace) {
936  return -1;
937  }
938 
939  ast_free(replace->app);
940  replace->app = NULL;
941 
942  if (replace_app) {
943  replace->app = ast_strdup(replace_app);
944  if (!replace->app) {
945  return -1;
946  }
947  }
948 
949  return 0;
950 }
951 
953 {
955  struct ast_channel_snapshot *replace_channel_snapshot;
956 
957  if (!replace) {
958  return NULL;
959  }
960 
961  replace_channel_snapshot = replace->snapshot;
962  replace->snapshot = NULL;
963 
964  return replace_channel_snapshot;
965 }
966 
968 {
970  char *replace_channel_app;
971 
972  if (!replace) {
973  return NULL;
974  }
975 
976  replace_channel_app = replace->app;
977  replace->app = NULL;
978 
979  return replace_channel_app;
980 }
981 
982 static void start_message_blob_dtor(void *obj)
983 {
984  struct start_message_blob *payload = obj;
985 
986  ao2_cleanup(payload->channel);
987  ao2_cleanup(payload->replace_channel);
988  ast_json_unref(payload->blob);
989 }
990 
991 static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app *app,
992  int argc, char *argv[], struct ast_channel_snapshot *snapshot,
993  struct ast_channel_snapshot *replace_channel_snapshot)
994 {
995  struct ast_json *json_blob;
996  struct ast_json *json_args;
997  struct start_message_blob *payload;
998  struct stasis_message *msg;
999  int i;
1000 
1001  if (app_subscribe_channel(app, chan)) {
1002  ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
1003  stasis_app_name(app), ast_channel_name(chan));
1004  return -1;
1005  }
1006 
1007  payload = ao2_alloc(sizeof(*payload), start_message_blob_dtor);
1008  if (!payload) {
1009  ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
1010  return -1;
1011  }
1012 
1013  payload->channel = ao2_bump(snapshot);
1014  payload->replace_channel = ao2_bump(replace_channel_snapshot);
1015 
1016  json_blob = ast_json_pack("{s: s, s: o, s: []}",
1017  "app", stasis_app_name(app),
1018  "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1019  "args");
1020  if (!json_blob) {
1021  ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
1022  ao2_ref(payload, -1);
1023  return -1;
1024  }
1025  payload->blob = json_blob;
1026 
1027 
1028  /* Append arguments to args array */
1029  json_args = ast_json_object_get(json_blob, "args");
1030  ast_assert(json_args != NULL);
1031  for (i = 0; i < argc; ++i) {
1032  int r = ast_json_array_append(json_args,
1033  ast_json_string_create(argv[i]));
1034  if (r != 0) {
1035  ast_log(LOG_ERROR, "Error appending to StasisStart message\n");
1036  ao2_ref(payload, -1);
1037  return -1;
1038  }
1039  }
1040 
1041 
1042  msg = stasis_message_create(start_message_type(), payload);
1043  ao2_ref(payload, -1);
1044  if (!msg) {
1045  ast_log(LOG_ERROR, "Error sending StasisStart message\n");
1046  return -1;
1047  }
1048 
1049  if (replace_channel_snapshot) {
1050  app_unsubscribe_channel_id(app, replace_channel_snapshot->base->uniqueid);
1051  }
1052  stasis_publish(ast_app_get_topic(app), msg);
1053  ao2_ref(msg, -1);
1054  return 0;
1055 }
1056 
1057 static int send_start_msg(struct stasis_app *app, struct ast_channel *chan,
1058  int argc, char *argv[])
1059 {
1060  int ret = -1;
1061  struct ast_channel_snapshot *snapshot;
1062  struct ast_channel_snapshot *replace_channel_snapshot;
1063 
1064  ast_assert(chan != NULL);
1065 
1066  replace_channel_snapshot = get_replace_channel_snapshot(chan);
1067 
1068  /* Set channel info */
1069  ast_channel_lock(chan);
1070  snapshot = ast_channel_snapshot_create(chan);
1071  ast_channel_unlock(chan);
1072  if (snapshot) {
1073  ret = send_start_msg_snapshots(chan, app, argc, argv, snapshot, replace_channel_snapshot);
1074  ao2_ref(snapshot, -1);
1075  }
1076  ao2_cleanup(replace_channel_snapshot);
1077 
1078  return ret;
1079 }
1080 
1081 static void remove_masquerade_store(struct ast_channel *chan);
1082 
1083 int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
1084 {
1086  struct ast_json *blob;
1087  struct stasis_message *msg;
1088 
1089  if (sanitize && sanitize->channel
1090  && sanitize->channel(chan)) {
1091  return 0;
1092  }
1093 
1094  blob = ast_json_pack("{s: s, s: o}",
1095  "app", stasis_app_name(app),
1096  "timestamp", ast_json_timeval(ast_tvnow(), NULL)
1097  );
1098  if (!blob) {
1099  ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n");
1100  return -1;
1101  }
1102 
1104  app_unsubscribe_channel(app, chan);
1105  msg = ast_channel_blob_create(chan, end_message_type(), blob);
1106  if (msg) {
1107  stasis_publish(ast_app_get_topic(app), msg);
1108  }
1109  ao2_cleanup(msg);
1110  ast_json_unref(blob);
1111 
1112  return 0;
1113 }
1114 
1115 static int masq_match_cb(void *obj, void *data, int flags)
1116 {
1117  struct stasis_app_control *control = obj;
1118  struct ast_channel *chan = data;
1119 
1120  if (!strcmp(ast_channel_uniqueid(chan),
1122  return CMP_MATCH;
1123  }
1124 
1125  return 0;
1126 }
1127 
1128 static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1129 {
1130  struct stasis_app_control *control;
1131 
1132  /*
1133  * At this point, old_chan is the channel pointer that is in Stasis() and
1134  * has the unknown channel's name in it while new_chan is the channel pointer
1135  * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1136  * about.
1137  *
1138  * Find and unlink control since the channel has a new name/uniqueid
1139  * and its hash has changed. Since the channel is leaving stasis don't
1140  * bother putting it back into the container. Nobody is going to
1141  * remove it from the container later.
1142  */
1143  control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, old_chan);
1144  if (!control) {
1145  ast_log(LOG_ERROR, "Could not find control for masqueraded channel\n");
1146  return;
1147  }
1148 
1149  /* send the StasisEnd message to the app */
1151  app_send_end_msg(control_app(control), new_chan);
1152 
1153  /* remove the datastore */
1154  remove_masquerade_store(old_chan);
1155 
1156  ao2_cleanup(control);
1157 }
1158 
1159 static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1160 {
1161  RAII_VAR(struct ast_channel_snapshot *, new_snapshot, NULL, ao2_cleanup);
1162  RAII_VAR(struct ast_channel_snapshot *, old_snapshot, NULL, ao2_cleanup);
1163  struct stasis_app_control *control;
1164 
1165  /* At this point, new_chan is the channel pointer that is in Stasis() and
1166  * has the unknown channel's name in it while old_chan is the channel pointer
1167  * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1168  * about */
1169 
1170  /* grab a snapshot for the channel that is jumping into Stasis() */
1171  new_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(new_chan));
1172  if (!new_snapshot) {
1173  ast_log(LOG_ERROR, "Could not get snapshot for masquerading channel\n");
1174  return;
1175  }
1176 
1177  /* grab a snapshot for the channel that has been kicked out of Stasis() */
1178  old_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(old_chan));
1179  if (!old_snapshot) {
1180  ast_log(LOG_ERROR, "Could not get snapshot for masqueraded channel\n");
1181  return;
1182  }
1183 
1184  /*
1185  * Find, unlink, and relink control since the channel has a new
1186  * name/uniqueid and its hash has changed.
1187  */
1188  control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, new_chan);
1189  if (!control) {
1190  ast_log(LOG_ERROR, "Could not find control for masquerading channel\n");
1191  return;
1192  }
1193  ao2_link(app_controls, control);
1194 
1195 
1196  /* send the StasisStart with replace_channel to the app */
1197  send_start_msg_snapshots(new_chan, control_app(control), 0, NULL, new_snapshot,
1198  old_snapshot);
1199  /* send the StasisEnd message to the app */
1200  app_send_end_msg(control_app(control), old_chan);
1201 
1202  ao2_cleanup(control);
1203 }
1204 
1206  .type = "stasis-masqerade",
1207  .chan_fixup = channel_stolen_cb,
1208  .chan_breakdown = channel_replaced_cb,
1209 };
1210 
1211 static int has_masquerade_store(struct ast_channel *chan)
1212 {
1213  SCOPED_CHANNELLOCK(lock, chan);
1214  return !!ast_channel_datastore_find(chan, &masquerade_store_info, NULL);
1215 }
1216 
1217 static int add_masquerade_store(struct ast_channel *chan)
1218 {
1219  struct ast_datastore *datastore;
1220 
1221  SCOPED_CHANNELLOCK(lock, chan);
1222  if (ast_channel_datastore_find(chan, &masquerade_store_info, NULL)) {
1223  return 0;
1224  }
1225 
1226  datastore = ast_datastore_alloc(&masquerade_store_info, NULL);
1227  if (!datastore) {
1228  return -1;
1229  }
1230 
1231  ast_channel_datastore_add(chan, datastore);
1232 
1233  return 0;
1234 }
1235 
1236 static void remove_masquerade_store(struct ast_channel *chan)
1237 {
1238  struct ast_datastore *datastore;
1239 
1240  SCOPED_CHANNELLOCK(lock, chan);
1241  datastore = ast_channel_datastore_find(chan, &masquerade_store_info, NULL);
1242  if (!datastore) {
1243  return;
1244  }
1245 
1246  ast_channel_datastore_remove(chan, datastore);
1247  ast_datastore_free(datastore);
1248 }
1249 
1251 {
1252  while (!control_is_done(control)) {
1253  int command_count;
1254  command_count = control_dispatch_all(control, chan);
1255 
1256  ao2_lock(control);
1257 
1258  if (control_command_count(control)) {
1259  /* If the command queue isn't empty, something added to the queue before it was locked. */
1260  ao2_unlock(control);
1261  continue;
1262  }
1263 
1264  if (command_count == 0 || ast_channel_fdno(chan) == -1) {
1265  control_mark_done(control);
1266  ao2_unlock(control);
1267  break;
1268  }
1269  ao2_unlock(control);
1270  }
1271 }
1272 
1274 {
1275  return control_is_done(control);
1276 }
1277 
1279 {
1280  control_flush_queue(control);
1281 }
1282 
1284  .type = "stasis_end_published",
1285 };
1286 
1288 {
1289  struct ast_datastore *datastore;
1290 
1291  datastore = ast_datastore_alloc(&set_end_published_info, NULL);
1292  if (datastore) {
1293  ast_channel_lock(chan);
1294  ast_channel_datastore_add(chan, datastore);
1295  ast_channel_unlock(chan);
1296  }
1297 }
1298 
1300 {
1301  struct ast_datastore *datastore;
1302 
1303  ast_channel_lock(chan);
1304  datastore = ast_channel_datastore_find(chan, &set_end_published_info, NULL);
1305  ast_channel_unlock(chan);
1306 
1307  return datastore ? 1 : 0;
1308 }
1309 
1310 static void remove_stasis_end_published(struct ast_channel *chan)
1311 {
1312  struct ast_datastore *datastore;
1313 
1314  ast_channel_lock(chan);
1315  datastore = ast_channel_datastore_find(chan, &set_end_published_info, NULL);
1316  if (datastore) {
1317  ast_channel_datastore_remove(chan, datastore);
1318  ast_datastore_free(datastore);
1319  }
1320  ast_channel_unlock(chan);
1321 }
1322 
1323 /*! /brief Stasis dialplan application callback */
1324 int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
1325  char *argv[])
1326 {
1327  RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1328  RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
1329  struct ast_bridge *bridge = NULL;
1330  int res = 0;
1331  int needs_depart;
1332 
1333  ast_assert(chan != NULL);
1334 
1335  /* Just in case there's a lingering indication that the channel has had a stasis
1336  * end published on it, remove that now.
1337  */
1339 
1340  if (!apps_registry) {
1341  return -1;
1342  }
1343 
1344  app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1345  if (!app) {
1347  "Stasis app '%s' not registered\n", app_name);
1348  return -1;
1349  }
1350  if (!app_is_active(app)) {
1352  "Stasis app '%s' not active\n", app_name);
1353  return -1;
1354  }
1355 
1356  control = control_create(chan, app);
1357  if (!control) {
1358  ast_log(LOG_ERROR, "Control allocation failed or Stasis app '%s' not registered\n", app_name);
1359  return -1;
1360  }
1361 
1362  if (!control_app(control)) {
1363  ast_log(LOG_ERROR, "Stasis app '%s' not registered\n", app_name);
1364  return -1;
1365  }
1366 
1367  if (!app_is_active(control_app(control))) {
1368  ast_log(LOG_ERROR, "Stasis app '%s' not active\n", app_name);
1369  return -1;
1370  }
1371  ao2_link(app_controls, control);
1372 
1373  if (add_masquerade_store(chan)) {
1374  ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1375  return -1;
1376  }
1377 
1378  res = send_start_msg(control_app(control), chan, argc, argv);
1379  if (res != 0) {
1381  "Error sending start message to '%s'\n", app_name);
1383  return -1;
1384  }
1385 
1386  /* Pull queued prestart commands and execute */
1387  control_prestart_dispatch_all(control, chan);
1388 
1389  while (!control_is_done(control)) {
1390  RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
1391  int r;
1392  int command_count;
1393  RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup);
1394 
1395  /* Check to see if a bridge absorbed our hangup frame */
1396  if (ast_check_hangup_locked(chan)) {
1397  control_mark_done(control);
1398  break;
1399  }
1400 
1401  /* control->next_app is only modified within the control thread, so this is safe */
1402  if (control_next_app(control)) {
1403  struct stasis_app *next_app = ao2_find(apps_registry, control_next_app(control), OBJ_SEARCH_KEY);
1404 
1405  if (next_app && app_is_active(next_app)) {
1406  int idx;
1407  int next_argc;
1408  char **next_argv;
1409 
1410  /* If something goes wrong in this conditional, res will need to be non-zero
1411  * so that the code below the exec loop knows something went wrong during a move.
1412  */
1414  res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1415  if (res != 0) {
1417  "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1418  control_mark_done(control);
1419  ao2_ref(next_app, -1);
1420  break;
1421  }
1422  } else {
1424  }
1425 
1426  /* This will ao2_bump next_app, and unref the previous app by 1 */
1427  control_set_app(control, next_app);
1428 
1429  /* There's a chance that the previous application is ready for clean up, so go ahead
1430  * and do that now.
1431  */
1432  cleanup();
1433 
1434  /* We need to add another masquerade store, otherwise the leave message will
1435  * not show up for the correct application.
1436  */
1437  if (add_masquerade_store(chan)) {
1438  ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1439  res = -1;
1440  control_mark_done(control);
1441  ao2_ref(next_app, -1);
1442  break;
1443  }
1444 
1445  /* We MUST get the size before the list, as control_next_app_args steals the elements
1446  * from the string vector.
1447  */
1448  next_argc = control_next_app_args_size(control);
1449  next_argv = control_next_app_args(control);
1450 
1451  res = send_start_msg(control_app(control), chan, next_argc, next_argv);
1452 
1453  /* Even if res != 0, we still need to free the memory we got from control_argv */
1454  if (next_argv) {
1455  for (idx = 0; idx < next_argc; idx++) {
1456  ast_free(next_argv[idx]);
1457  }
1458  ast_free(next_argv);
1459  }
1460 
1461  if (res != 0) {
1463  "Error sending start message to '%s'\n", stasis_app_name(control_app(control)));
1465  control_mark_done(control);
1466  ao2_ref(next_app, -1);
1467  break;
1468  }
1469 
1470  /* Done switching applications, free memory and clean up */
1471  control_move_cleanup(control);
1472  } else {
1473  /* If we can't switch applications, do nothing */
1474  struct ast_json *msg;
1475  RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1476 
1477  if (!next_app) {
1478  ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not registered\n",
1479  control_next_app(control));
1480  } else {
1481  ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not active\n",
1482  control_next_app(control));
1483  }
1484 
1486  if (!snapshot) {
1487  ast_log(LOG_ERROR, "Could not get channel shapshot for '%s'\n",
1488  ast_channel_name(chan));
1489  } else {
1490  struct ast_json *json_args;
1491  int next_argc = control_next_app_args_size(control);
1492  char **next_argv = control_next_app_args(control);
1493 
1494  msg = ast_json_pack("{s: s, s: o, s: o, s: s, s: []}",
1495  "type", "ApplicationMoveFailed",
1496  "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1497  "channel", ast_channel_snapshot_to_json(snapshot, NULL),
1498  "destination", control_next_app(control),
1499  "args");
1500  if (!msg) {
1501  ast_log(LOG_ERROR, "Failed to pack JSON for ApplicationMoveFailed message\n");
1502  } else {
1503  json_args = ast_json_object_get(msg, "args");
1504  if (!json_args) {
1505  ast_log(LOG_ERROR, "Could not get args json array");
1506  } else {
1507  int r = 0;
1508  int idx;
1509  for (idx = 0; idx < next_argc; ++idx) {
1510  r = ast_json_array_append(json_args,
1511  ast_json_string_create(next_argv[idx]));
1512  if (r != 0) {
1513  ast_log(LOG_ERROR, "Error appending to ApplicationMoveFailed message\n");
1514  break;
1515  }
1516  }
1517  if (r == 0) {
1518  app_send(control_app(control), msg);
1519  }
1520  }
1521  ast_json_unref(msg);
1522  }
1523  }
1524  }
1525  control_move_cleanup(control);
1526  ao2_cleanup(next_app);
1527  }
1528 
1529  last_bridge = bridge;
1530  bridge = ao2_bump(stasis_app_get_bridge(control));
1531 
1532  if (bridge != last_bridge) {
1533  if (last_bridge) {
1534  app_unsubscribe_bridge(control_app(control), last_bridge);
1535  }
1536  if (bridge) {
1537  app_subscribe_bridge(control_app(control), bridge);
1538  }
1539  }
1540 
1541  if (bridge) {
1542  /* Bridge/dial is handling channel frames */
1543  control_wait(control);
1544  control_dispatch_all(control, chan);
1545  continue;
1546  }
1547 
1548  r = ast_waitfor(chan, MAX_WAIT_MS);
1549 
1550  if (r < 0) {
1551  ast_debug(3, "%s: Poll error\n",
1552  ast_channel_uniqueid(chan));
1553  control_mark_done(control);
1554  break;
1555  }
1556 
1557  command_count = control_dispatch_all(control, chan);
1558 
1559  if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1560  /* Command drained the channel; wait for next frame */
1561  continue;
1562  }
1563 
1564  if (r == 0) {
1565  /* Timeout */
1566  continue;
1567  }
1568 
1569  f = ast_read(chan);
1570  if (!f) {
1571  /* Continue on in the dialplan */
1572  ast_debug(3, "%s: Hangup (no more frames)\n",
1573  ast_channel_uniqueid(chan));
1574  control_mark_done(control);
1575  break;
1576  }
1577 
1578  if (f->frametype == AST_FRAME_CONTROL) {
1579  if (f->subclass.integer == AST_CONTROL_HANGUP) {
1580  /* Continue on in the dialplan */
1581  ast_debug(3, "%s: Hangup\n",
1582  ast_channel_uniqueid(chan));
1583  control_mark_done(control);
1584  break;
1585  }
1586  }
1587  }
1588 
1589  ast_channel_lock(chan);
1590  needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1591  ast_channel_unlock(chan);
1592  if (needs_depart) {
1593  ast_bridge_depart(chan);
1594  }
1595 
1596  if (stasis_app_get_bridge(control)) {
1598  }
1599  ao2_cleanup(bridge);
1600 
1601  /* Only publish a stasis_end event if it hasn't already been published */
1602  if (!res && !stasis_app_channel_is_stasis_end_published(chan)) {
1603  /* A masquerade has occurred and this message will be wrong so it
1604  * has already been sent elsewhere. */
1605  res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1606  if (res != 0) {
1608  "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1609  return res;
1610  }
1611  } else {
1613  }
1614 
1615  control_flush_queue(control);
1616 
1617  /* Stop any lingering silence generator */
1618  control_silence_stop_now(control);
1619 
1620  /* There's an off chance that app is ready for cleanup. Go ahead
1621  * and clean up, just in case
1622  */
1623  cleanup();
1624 
1625  /* The control needs to be removed from the controls container in
1626  * case a new PBX is started and ends up coming back into Stasis.
1627  */
1628  control_unlink(control);
1629  control = NULL;
1630 
1631  if (!res && !ast_channel_pbx(chan)) {
1632  int chan_hungup;
1633 
1634  /* The ASYNCGOTO softhangup flag may have broken the channel out of
1635  * its bridge to run dialplan, so if there's no pbx on the channel
1636  * let it run dialplan here. Otherwise, it will run when this
1637  * application exits. */
1638  ast_channel_lock(chan);
1640  chan_hungup = ast_check_hangup(chan);
1641  ast_channel_unlock(chan);
1642 
1643  if (!chan_hungup) {
1644  struct ast_pbx_args pbx_args;
1645 
1646  memset(&pbx_args, 0, sizeof(pbx_args));
1647  pbx_args.no_hangup_chan = 1;
1648 
1649  res = ast_pbx_run_args(chan, &pbx_args);
1650  }
1651  }
1652 
1653  return res;
1654 }
1655 
1656 int stasis_app_send(const char *app_name, struct ast_json *message)
1657 {
1658  struct stasis_app *app;
1659 
1660  if (!apps_registry) {
1661  return -1;
1662  }
1663 
1664  app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1665  if (!app) {
1666  /* XXX We can do a better job handling late binding, queueing up
1667  * the call for a few seconds to wait for the app to register.
1668  */
1670  "Stasis app '%s' not registered\n", app_name);
1671  return -1;
1672  }
1673  app_send(app, message);
1674  ao2_ref(app, -1);
1675 
1676  return 0;
1677 }
1678 
1679 static struct stasis_app *find_app_by_name(const char *app_name)
1680 {
1681  struct stasis_app *res = NULL;
1682 
1683  if (!apps_registry) {
1684  return NULL;
1685  }
1686 
1687  if (!ast_strlen_zero(app_name)) {
1688  res = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1689  }
1690 
1691  return res;
1692 }
1693 
1695 {
1696  return find_app_by_name(name);
1697 }
1698 
1699 static int append_name(void *obj, void *arg, int flags)
1700 {
1701  struct stasis_app *app = obj;
1702  struct ao2_container *apps = arg;
1703 
1705  return 0;
1706 }
1707 
1709 {
1710  struct ao2_container *apps;
1711 
1712  if (!apps_registry) {
1713  return NULL;
1714  }
1715 
1716  apps = ast_str_container_alloc(1);
1717  if (!apps) {
1718  return NULL;
1719  }
1720 
1721  ao2_callback(apps_registry, OBJ_NODATA, append_name, apps);
1722 
1723  return apps;
1724 }
1725 
1726 static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
1727 {
1728  RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1729 
1730  if (!apps_registry) {
1731  return -1;
1732  }
1733 
1734  ao2_lock(apps_registry);
1735  app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
1736  if (app) {
1737  /*
1738  * We need to unlock the apps_registry before calling app_update to
1739  * prevent the possibility of a deadlock with the session.
1740  */
1741  ao2_unlock(apps_registry);
1742  app_update(app, handler, data);
1743  cleanup();
1744  return 0;
1745  }
1746 
1747  app = app_create(app_name, handler, data, all_events ? STASIS_APP_SUBSCRIBE_ALL : STASIS_APP_SUBSCRIBE_MANUAL);
1748  if (!app) {
1749  ao2_unlock(apps_registry);
1750  return -1;
1751  }
1752 
1753  if (all_events) {
1754  struct stasis_app_event_source *source;
1755 
1757  AST_LIST_TRAVERSE(&event_sources, source, next) {
1758  if (!source->subscribe) {
1759  continue;
1760  }
1761 
1762  source->subscribe(app, NULL);
1763  }
1765  }
1766  ao2_link_flags(apps_registry, app, OBJ_NOLOCK);
1767 
1768  ao2_unlock(apps_registry);
1769 
1770  /* We lazily clean up the apps_registry, because it's good enough to
1771  * prevent memory leaks, and we're lazy.
1772  */
1773  cleanup();
1774  return 0;
1775 }
1776 
1777 int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
1778 {
1779  return __stasis_app_register(app_name, handler, data, 0);
1780 }
1781 
1783 {
1784  return __stasis_app_register(app_name, handler, data, 1);
1785 }
1786 
1788 {
1789  struct stasis_app *app;
1790 
1791  if (!app_name) {
1792  return;
1793  }
1794 
1795  if (!apps_registry) {
1796  return;
1797  }
1798 
1799  app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1800  if (!app) {
1802  "Stasis app '%s' not registered\n", app_name);
1803  return;
1804  }
1805 
1806  app_deactivate(app);
1807 
1808  /* There's a decent chance that app is ready for cleanup. Go ahead
1809  * and clean up, just in case
1810  */
1811  cleanup();
1812 
1813  ao2_ref(app, -1);
1814 }
1815 
1817 {
1819  AST_LIST_INSERT_TAIL(&event_sources, obj, next);
1821 }
1822 
1824 {
1825  struct stasis_app_event_source *source;
1826 
1829  if (source == obj) {
1831  break;
1832  }
1833  }
1836 }
1837 
1838 /*!
1839  * \internal
1840  * \brief Convert event source data to JSON.
1841  *
1842  * Calls each event source that has a "to_json" handler allowing each
1843  * source to add data to the given JSON object.
1844  *
1845  * \param app application associated with the event source
1846  * \param json a json object to "fill"
1847  *
1848  * \retval The given json object.
1849  */
1851  const struct stasis_app *app, struct ast_json *json)
1852 {
1853  struct stasis_app_event_source *source;
1854 
1856  AST_LIST_TRAVERSE(&event_sources, source, next) {
1857  if (source->to_json) {
1858  source->to_json(app, json);
1859  }
1860  }
1862 
1863  return json;
1864 }
1865 
1867 {
1868  if (!app) {
1869  return NULL;
1870  }
1871 
1873  app, app_event_sources_to_json(app, app_to_json(app)));
1874 }
1875 
1877 {
1878  struct stasis_app *app = find_app_by_name(app_name);
1879  struct ast_json *json = stasis_app_object_to_json(app);
1880 
1881  ao2_cleanup(app);
1882 
1883  return json;
1884 }
1885 
1886 /*!
1887  * \internal
1888  * \brief Finds an event source that matches a uri scheme.
1889  *
1890  * Uri(s) should begin with a particular scheme that can be matched
1891  * against an event source.
1892  *
1893  * \param uri uri containing a scheme to match
1894  *
1895  * \retval an event source if found, NULL otherwise.
1896  */
1897 static struct stasis_app_event_source *app_event_source_find(const char *uri)
1898 {
1899  struct stasis_app_event_source *source;
1900 
1902  AST_LIST_TRAVERSE(&event_sources, source, next) {
1903  if (ast_begins_with(uri, source->scheme)) {
1904  break;
1905  }
1906  }
1908 
1909  return source;
1910 }
1911 
1912 /*!
1913  * \internal
1914  * \brief Callback for subscription handling
1915  *
1916  * \param app [un]subscribing application
1917  * \param uri scheme:id of an event source
1918  * \param event_source being [un]subscribed [from]to
1919  *
1920  * \retval stasis_app_subscribe_res return code.
1921  */
1923  struct stasis_app *app, const char *uri,
1924  struct stasis_app_event_source *event_source);
1925 
1926 /*!
1927  * \internal
1928  * \brief Subscriptions handler for application [un]subscribing.
1929  *
1930  * \param app_name Name of the application to subscribe.
1931  * \param event_source_uris URIs for the event sources to subscribe to.
1932  * \param event_sources_count Array size of event_source_uris.
1933  * \param json Optional output pointer for JSON representation of the app
1934  * after adding the subscription.
1935  * \param handler [un]subscribe handler
1936  *
1937  * \retval stasis_app_subscribe_res return code.
1938  */
1940  const char *app_name, const char **event_source_uris,
1941  int event_sources_count, struct ast_json **json,
1943 {
1944  struct stasis_app *app = find_app_by_name(app_name);
1945  int i;
1946 
1947  ast_assert(handler != NULL);
1948 
1949  if (!app) {
1950  return STASIS_ASR_APP_NOT_FOUND;
1951  }
1952 
1953  for (i = 0; i < event_sources_count; ++i) {
1954  const char *uri = event_source_uris[i];
1955  struct stasis_app_event_source *event_source;
1956  enum stasis_app_subscribe_res res;
1957 
1958  event_source = app_event_source_find(uri);
1959  if (!event_source) {
1960  ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
1961  ao2_ref(app, -1);
1962 
1964  }
1965 
1966  res = handler(app, uri, event_source);
1967  if (res != STASIS_ASR_OK) {
1968  ao2_ref(app, -1);
1969 
1970  return res;
1971  }
1972  }
1973 
1974  if (json) {
1975  ast_debug(3, "%s: Successful; setting results\n", app_name);
1976  *json = stasis_app_object_to_json(app);
1977  }
1978 
1979  ao2_ref(app, -1);
1980 
1981  return STASIS_ASR_OK;
1982 }
1983 
1985  struct ast_channel *chan)
1986 {
1987  struct stasis_app *app = find_app_by_name(app_name);
1988  int res;
1989 
1990  if (!app) {
1991  return STASIS_ASR_APP_NOT_FOUND;
1992  }
1993 
1994  ast_debug(3, "%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan));
1995 
1996  res = app_subscribe_channel(app, chan);
1997  ao2_ref(app, -1);
1998 
1999  if (res != 0) {
2000  ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
2001  app_name, ast_channel_uniqueid(chan));
2003  }
2004 
2005  return STASIS_ASR_OK;
2006 }
2007 
2008 
2009 /*!
2010  * \internal
2011  * \brief Subscribe an app to an event source.
2012  *
2013  * \param app subscribing application
2014  * \param uri scheme:id of an event source
2015  * \param event_source being subscribed to
2016  *
2017  * \retval stasis_app_subscribe_res return code.
2018  */
2020  struct stasis_app *app, const char *uri,
2021  struct stasis_app_event_source *event_source)
2022 {
2023  const char *app_name = stasis_app_name(app);
2024  RAII_VAR(void *, obj, NULL, ao2_cleanup);
2025 
2026  ast_debug(3, "%s: Checking %s\n", app_name, uri);
2027 
2028  if (!ast_strlen_zero(uri + strlen(event_source->scheme)) &&
2029  (!event_source->find || (!(obj = event_source->find(app, uri + strlen(event_source->scheme)))))) {
2030  ast_log(LOG_WARNING, "Event source not found: %s\n", uri);
2032  }
2033 
2034  ast_debug(3, "%s: Subscribing to %s\n", app_name, uri);
2035 
2036  if (!event_source->subscribe || (event_source->subscribe(app, obj))) {
2037  ast_log(LOG_WARNING, "Error subscribing app '%s' to '%s'\n",
2038  app_name, uri);
2040  }
2041 
2042  return STASIS_ASR_OK;
2043 }
2044 
2046  const char **event_source_uris, int event_sources_count,
2047  struct ast_json **json)
2048 {
2049  return app_handle_subscriptions(
2050  app_name, event_source_uris, event_sources_count,
2051  json, app_subscribe);
2052 }
2053 
2054 /*!
2055  * \internal
2056  * \brief Unsubscribe an app from an event source.
2057  *
2058  * \param app application to unsubscribe
2059  * \param uri scheme:id of an event source
2060  * \param event_source being unsubscribed from
2061  *
2062  * \retval stasis_app_subscribe_res return code.
2063  */
2065  struct stasis_app *app, const char *uri,
2066  struct stasis_app_event_source *event_source)
2067 {
2068  const char *app_name = stasis_app_name(app);
2069  const char *id = uri + strlen(event_source->scheme);
2070 
2071  if (!event_source->is_subscribed ||
2072  (!event_source->is_subscribed(app, id))) {
2074  }
2075 
2076  ast_debug(3, "%s: Unsubscribing from %s\n", app_name, uri);
2077 
2078  if (!event_source->unsubscribe || (event_source->unsubscribe(app, id))) {
2079  ast_log(LOG_WARNING, "Error unsubscribing app '%s' to '%s'\n",
2080  app_name, uri);
2081  return -1;
2082  }
2083  return 0;
2084 }
2085 
2087  const char **event_source_uris, int event_sources_count,
2088  struct ast_json **json)
2089 {
2090  return app_handle_subscriptions(
2091  app_name, event_source_uris, event_sources_count,
2092  json, app_unsubscribe);
2093 }
2094 
2096  const char *event_name,
2097  const char **source_uris, int sources_count,
2098  struct ast_json *json_variables)
2099 {
2100  RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
2101  struct ast_json *blob = NULL;
2102  struct ast_multi_object_blob *multi;
2103  struct stasis_message *message;
2105  int have_channel = 0;
2106  int i;
2107 
2108  if (!app) {
2109  ast_log(LOG_WARNING, "App %s not found\n", app_name);
2111  }
2112 
2113  if (!ast_multi_user_event_type()) {
2114  return res;
2115  }
2116 
2117  if (json_variables) {
2118  struct ast_json *json_value = ast_json_string_create(event_name);
2119 
2120  if (json_value && !ast_json_object_set(json_variables, "eventname", json_value)) {
2121  blob = ast_json_ref(json_variables);
2122  }
2123  } else {
2124  blob = ast_json_pack("{s: s}", "eventname", event_name);
2125  }
2126 
2127  if (!blob) {
2128  ast_log(LOG_ERROR, "Failed to initialize blob\n");
2129 
2130  return res;
2131  }
2132 
2133  multi = ast_multi_object_blob_create(blob);
2134  ast_json_unref(blob);
2135  if (!multi) {
2136  ast_log(LOG_ERROR, "Failed to initialize multi\n");
2137 
2138  return res;
2139  }
2140 
2141  for (i = 0; i < sources_count; ++i) {
2142  const char *uri = source_uris[i];
2143  void *snapshot=NULL;
2145 
2146  if (ast_begins_with(uri, "channel:")) {
2147  type = STASIS_UMOS_CHANNEL;
2148  snapshot = ast_channel_snapshot_get_latest(uri + 8);
2149  have_channel = 1;
2150  } else if (ast_begins_with(uri, "bridge:")) {
2151  type = STASIS_UMOS_BRIDGE;
2152  snapshot = ast_bridge_get_snapshot_by_uniqueid(uri + 7);
2153  } else if (ast_begins_with(uri, "endpoint:")) {
2154  type = STASIS_UMOS_ENDPOINT;
2155  snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL);
2156  } else {
2157  ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
2158  ao2_ref(multi, -1);
2159 
2161  }
2162  if (!snapshot) {
2163  ast_log(LOG_ERROR, "Unable to get snapshot for %s\n", uri);
2164  ao2_ref(multi, -1);
2165 
2167  }
2168  ast_multi_object_blob_add(multi, type, snapshot);
2169  }
2170 
2172  ao2_ref(multi, -1);
2173 
2174  if (!message) {
2175  ast_log(LOG_ERROR, "Unable to create stasis user event message\n");
2176  return res;
2177  }
2178 
2179  /*
2180  * Publishing to two different topics is normally to be avoided -- except
2181  * in this case both are final destinations with no forwards (only listeners).
2182  * The message has to be delivered to the application topic for ARI, but a
2183  * copy is also delivered directly to the manager for AMI if there is a channel.
2184  */
2185  stasis_publish(ast_app_get_topic(app), message);
2186 
2187  if (have_channel) {
2189  }
2190  ao2_ref(message, -1);
2191 
2192  return STASIS_APP_USER_OK;
2193 }
2194 
2195 static int unload_module(void)
2196 {
2198 
2200 
2201  cleanup();
2202 
2204 
2205  ao2_cleanup(apps_registry);
2206  apps_registry = NULL;
2207 
2208  ao2_cleanup(app_controls);
2209  app_controls = NULL;
2210 
2211  ao2_cleanup(app_bridges);
2212  app_bridges = NULL;
2213 
2214  ao2_cleanup(app_bridges_moh);
2215  app_bridges_moh = NULL;
2216 
2217  ao2_cleanup(app_bridges_playback);
2218  app_bridges_playback = NULL;
2219 
2220  STASIS_MESSAGE_TYPE_CLEANUP(end_message_type);
2221  STASIS_MESSAGE_TYPE_CLEANUP(start_message_type);
2222 
2223  return 0;
2224 }
2225 
2226 /* \brief Sanitization callback for channel snapshots */
2227 static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
2228 {
2229  if (!snapshot || !(snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL)) {
2230  return 0;
2231  }
2232  return 1;
2233 }
2234 
2235 /* \brief Sanitization callback for channels */
2236 static int channel_sanitizer(const struct ast_channel *chan)
2237 {
2238  if (!chan || !(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)) {
2239  return 0;
2240  }
2241  return 1;
2242 }
2243 
2244 /* \brief Sanitization callback for channel unique IDs */
2245 static int channel_id_sanitizer(const char *id)
2246 {
2247  struct ast_channel_snapshot *snapshot;
2248  int ret;
2249 
2250  snapshot = ast_channel_snapshot_get_latest(id);
2251  ret = channel_snapshot_sanitizer(snapshot);
2252  ao2_cleanup(snapshot);
2253 
2254  return ret;
2255 }
2256 
2257 /* \brief Sanitization callbacks for communication to Stasis applications */
2260  .channel_snapshot = channel_snapshot_sanitizer,
2261  .channel = channel_sanitizer,
2262 };
2263 
2265 {
2266  return &app_sanitizer;
2267 }
2268 
2270  .type = "stasis-internal-channel",
2271 };
2272 
2273 static int set_internal_datastore(struct ast_channel *chan)
2274 {
2275  struct ast_datastore *datastore;
2276 
2277  datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL);
2278  if (!datastore) {
2279  datastore = ast_datastore_alloc(&stasis_internal_channel_info, NULL);
2280  if (!datastore) {
2281  return -1;
2282  }
2283  ast_channel_datastore_add(chan, datastore);
2284  }
2285  return 0;
2286 }
2287 
2289 {
2290  struct ast_channel *outchan = NULL, *outowner = NULL;
2291  int res = 0;
2292  struct ast_unreal_pvt *unreal_pvt = ast_channel_tech_pvt(chan);
2293 
2294  ao2_ref(unreal_pvt, +1);
2295  ast_unreal_lock_all(unreal_pvt, &outowner, &outchan);
2296  if (outowner) {
2297  res |= set_internal_datastore(outowner);
2298  ast_channel_unlock(outowner);
2299  ast_channel_unref(outowner);
2300  }
2301  if (outchan) {
2302  res |= set_internal_datastore(outchan);
2303  ast_channel_unlock(outchan);
2304  ast_channel_unref(outchan);
2305  }
2306  ao2_unlock(unreal_pvt);
2307  ao2_ref(unreal_pvt, -1);
2308  return res;
2309 }
2310 
2312 {
2313  int res;
2314 
2315  ast_channel_lock(chan);
2316  res = set_internal_datastore(chan);
2317  ast_channel_unlock(chan);
2318 
2319  return res;
2320 }
2321 
2323 {
2324  struct ast_datastore *datastore;
2325  int res = 0;
2326 
2327  ast_channel_lock(chan);
2328  datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL);
2329  if (datastore) {
2330  res = 1;
2331  }
2332  ast_channel_unlock(chan);
2333 
2334  return res;
2335 }
2336 
2337 static int load_module(void)
2338 {
2339  if (STASIS_MESSAGE_TYPE_INIT(start_message_type) != 0) {
2340  return AST_MODULE_LOAD_DECLINE;
2341  }
2342  if (STASIS_MESSAGE_TYPE_INIT(end_message_type) != 0) {
2343  return AST_MODULE_LOAD_DECLINE;
2344  }
2351  app_bridges_moh = ao2_container_alloc_hash(
2354  app_bridges_playback = ao2_container_alloc_hash(
2357  if (!apps_registry || !app_controls || !app_bridges || !app_bridges_moh || !app_bridges_playback) {
2358  unload_module();
2359  return AST_MODULE_LOAD_DECLINE;
2360  }
2361 
2362  if (messaging_init()) {
2363  unload_module();
2364  return AST_MODULE_LOAD_DECLINE;
2365  }
2366 
2368 
2370 
2371  return AST_MODULE_LOAD_SUCCESS;
2372 }
2373 
2375  .load_pri = AST_MODPRI_APP_DEPEND - 1,
2376  .support_level = AST_MODULE_SUPPORT_CORE,
2377  .load = load_module,
2378  .unload = unload_module,
2379 );
const char * type
Definition: datastore.h:32
static int bridges_channel_hash_fn(const void *obj, const int flags)
Definition: res_stasis.c:462
static const char type[]
Definition: chan_ooh323.c:109
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition: control.c:931
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:931
Options for ast_pbx_run()
Definition: pbx.h:391
#define ast_channel_lock(chan)
Definition: channel.h:2945
char * control_next_app(struct stasis_app_control *control)
Returns the name of the application we are moving to.
Definition: control.c:1697
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:1777
struct ast_channel_snapshot * snapshot
Definition: res_stasis.c:872
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:1866
static void playback_after_bridge_cb(struct ast_channel *chan, void *data)
Definition: res_stasis.c:698
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:1710
static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
Definition: res_stasis.c:2227
struct ast_channel_snapshot_base * base
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:1656
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:1250
const ast_string_field uniqueid
Definition: bridge.h:409
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:851
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:591
static struct ast_channel_snapshot * get_replace_channel_snapshot(struct ast_channel *chan)
Definition: res_stasis.c:952
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
#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:332
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
int stasis_app_control_is_done(struct stasis_app_control *control)
Check if a control is marked as done.
Definition: res_stasis.c:1273
#define AST_UUID_STR_LEN
Definition: uuid.h:27
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:563
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
Registered applications container.
Definition: pbx_app.c:67
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
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&#39;s...
Definition: stasis.h:221
static int bridges_compare(void *obj, void *arg, int flags)
Definition: res_stasis.c:378
static struct stasis_app_event_source * app_event_source_find(const char *uri)
Definition: res_stasis.c:1897
int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, char *argv[])
Control a channel using stasis_app.
Definition: res_stasis.c:1324
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
static int unload_module(void)
Definition: res_stasis.c:2195
struct ast_json * blob
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1501
struct ast_channel_snapshot * snapshot
const char * scheme
The scheme to match against on [un]subscribes.
Definition: stasis_app.h:176
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
int(* channel_id)(const char *channel_id)
Callback which determines whether a channel should be sanitized from a message based on the channel&#39;s...
Definition: stasis.h:210
void control_mark_done(struct stasis_app_control *control)
Definition: control.c:354
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:459
#define LOG_WARNING
Definition: logger.h:274
static int control_compare(void *obj, void *arg, int flags)
Definition: res_stasis.c:270
static int load_module(void)
Definition: res_stasis.c:2337
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
static int channel_id_sanitizer(const char *id)
Definition: res_stasis.c:2245
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 ao2_container * app_bridges_moh
Definition: res_stasis.c:106
struct stasis_app_control * stasis_app_control_create(struct ast_channel *chan)
Creates a control handler for a channel that isn&#39;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:2095
void control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: control.c:1482
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
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:1984
#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:1876
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
Definition: strings.h:1312
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
int stasis_app_channel_is_internal(struct ast_channel *chan)
Is this channel internal to Stasis?
Definition: res_stasis.c:2322
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1523
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
Structure for a data store type.
Definition: datastore.h:31
static struct ast_channel * bridge_moh_create(struct ast_bridge *bridge)
Definition: res_stasis.c:574
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:970
static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
Definition: res_stasis.c:1726
STASIS_MESSAGE_TYPE_DEFN_LOCAL(end_message_type,.to_json=stasis_end_to_json)
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:919
const ast_string_field uniqueid
static int has_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1211
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:150
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_assert(a)
Definition: utils.h:695
#define ao2_link_flags(container, obj, flags)
Definition: astobj2.h:1572
static void remove_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1236
#define ao2_unlock(a)
Definition: astobj2.h:730
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:1782
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
Structure for a data store object.
Definition: datastore.h:68
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:2404
#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
struct ast_datastore_info set_end_published_info
Definition: res_stasis.c:1283
#define NULL
Definition: resample.c:96
const char * data
static struct apps apps
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
Definition: res_stasis.c:2264
int control_command_count(struct stasis_app_control *control)
Returns the count of items in a control&#39;s command queue.
Definition: control.c:343
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
struct ao2_container * app_bridges
Definition: res_stasis.c:104
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:1563
const ast_string_field bridge_id
Definition: res_stasis.c:425
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:259
#define ast_verb(level,...)
Definition: logger.h:463
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
static struct ast_bridge * bridge_create_common(const char *type, const char *name, const char *id, int invisible)
Definition: res_stasis.c:795
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:1694
int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all commands enqueued to this control.
Definition: control.c:1495
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:404
Blob of data associated with a channel.
static int control_hash(const void *obj, const int flags)
Definition: res_stasis.c:248
#define ast_strlen_zero(foo)
Definition: strings.h:52
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:6444
void ast_frame_dtor(struct ast_frame *frame)
NULL-safe wrapper for ast_frfree, good for RAII_VAR.
Definition: main/frame.c:187
struct ao2_container * app_controls
Definition: res_stasis.c:102
static int cleanup_cb(void *obj, void *arg, int flags)
Definition: res_stasis.c:309
int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
Send StasisEnd message to the listening app.
Definition: res_stasis.c:1083
ast_bridge_after_cb_reason
Definition: bridge_after.h:37
#define ao2_bump(obj)
Definition: astobj2.h:491
static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app *app, int argc, char *argv[], struct ast_channel_snapshot *snapshot, struct ast_channel_snapshot *replace_channel_snapshot)
Definition: res_stasis.c:991
void(* to_json)(const struct stasis_app *app, struct ast_json *json)
Convert event source data to json.
Definition: stasis_app.h:224
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static void cleanup(void)
Clean up any old apps that we don&#39;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:1120
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:1299
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:1702
int(* unsubscribe)(struct stasis_app *app, const char *id)
Cancel the subscription an app has to an event source.
Definition: stasis_app.h:206
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:617
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2437
#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:911
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:268
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
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:1708
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:4739
ast_mutex_t lock
Definition: app_meetme.c:1091
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:1715
void stasis_app_control_shutdown(void)
Let Stasis app internals shut down.
Definition: control.c:1680
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:105
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application&#39;s name.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
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
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2476
#define ao2_lock(a)
Definition: astobj2.h:718
static struct ast_json * stasis_end_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
Definition: res_stasis.c:115
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:569
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
struct ast_bridge_channel * ast_channel_internal_bridge_channel(const struct ast_channel *chan)
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
stasis_user_multi_object_snapshot_type
Object type code for multi user object snapshots.
Definition: stasis.h:1357
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.
void stasis_app_register_event_source(struct stasis_app_event_source *obj)
Register an application event source.
Definition: res_stasis.c:1816
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:972
struct ast_json * stasis_app_event_filter_to_json(struct stasis_app *app, struct ast_json *json)
Convert and add the app&#39;s event type filter(s) to the given json object.
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
Internal API for the Stasis application controller.
int app_is_finished(struct stasis_app *app)
Checks whether a deactivated app has no channels.
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
static const struct ast_datastore_info stasis_internal_channel_info
Definition: res_stasis.c:2269
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:649
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:544
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:368
#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
int ast_channel_fdno(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
Structure that contains information about a bridge.
Definition: bridge.h:357
static int send_start_msg(struct stasis_app *app, struct ast_channel *chan, int argc, char *argv[])
Definition: res_stasis.c:1057
struct stasis_message_sanitizer app_sanitizer
Definition: res_stasis.c:2258
Backend API for implementing components of res_stasis.
void app_send(struct stasis_app *app, struct ast_json *message)
Send a message to the given application.
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
struct ao2_container * app_bridges_playback
Definition: res_stasis.c:108
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:2086
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:1430
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:1287
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
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.
static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
Definition: res_stasis.c:1128
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:1787
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridge.c:1952
The base pvt structure for local channel derivatives.
Definition: core_unreal.h:91
static const struct ast_datastore_info replace_channel_store_info
Definition: res_stasis.c:885
struct stasis_app_control * control_create(struct ast_channel *channel, struct stasis_app *app)
Create a control object.
Definition: control.c:123
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static const struct ast_datastore_info masquerade_store_info
Definition: res_stasis.c:1205
const ast_string_field channel_id
Definition: res_stasis.c:425
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.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2946
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.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
#define STASIS_BRIDGE_MIXING_CAPABILITIES
Definition: stasis_bridge.h:39
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
int stasis_app_channel_unreal_set_internal(struct ast_channel *chan)
Mark this unreal channel and it&#39;s other half as being internal to Stasis.
Definition: res_stasis.c:2288
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define AST_CHANNEL_NAME
Definition: channel.h:172
void stasis_app_control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: res_stasis.c:1278
struct ast_bridge * bridge
Definition: control.c:64
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
int stasis_app_channel_set_internal(struct ast_channel *chan)
Mark this channel as being internal to Stasis.
Definition: res_stasis.c:2311
static int append_name(void *obj, void *arg, int flags)
Definition: res_stasis.c:1699
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
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
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:1691
static void playback_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
Definition: res_stasis.c:691
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1720
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:861
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
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:790
void control_silence_stop_now(struct stasis_app_control *control)
Stop playing silence to a channel right now.
Definition: control.c:837
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:348
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:70
enum stasis_app_subscribe_res(* app_subscription_handler)(struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
Definition: res_stasis.c:1922
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
struct stasis_app_control * stasis_app_control_find_by_channel(const struct ast_channel *chan)
Returns the handler for the given channel.
Definition: res_stasis.c:338
char * strsep(char **str, const char *delims)
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
static int bridges_channel_sort_fn(const void *obj_left, const void *obj_right, const int flags)
Definition: res_stasis.c:483
#define ao2_replace(dst, src)
Definition: astobj2.h:517
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
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...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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:397
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:79
const char * ast_channel_name(const struct ast_channel *chan)
static int set_internal_datastore(struct ast_channel *chan)
Definition: res_stasis.c:2273
void app_update(struct stasis_app *app, stasis_app_cb handler, void *data)
Update the handler and data for a res_stasis application.
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
#define ast_frfree(fr)
static int masq_match_cb(void *obj, void *data, int flags)
Definition: res_stasis.c:1115
static int app_hash(const void *obj, const int flags)
Definition: res_stasis.c:186
struct stasis_app_event_source * next
Definition: stasis_app.h:227
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:2045
Stasis out-of-call text message support.
Data structure associated with a single frame of data.
#define ao2_unlink_flags(container, obj, flags)
Definition: astobj2.h:1622
Internal Asterisk hangup causes.
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Definition: strings.h:94
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
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
Reject objects with duplicate keys in container.
Definition: astobj2.h:1192
static void remove_bridge_playback(char *bridge_id)
Definition: res_stasis.c:673
void bridge_stasis_init(void)
static int add_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1217
Generic container type.
static struct ast_channel * prepare_bridge_moh_channel(void)
Definition: res_stasis.c:510
static struct stasis_app * find_app_by_name(const char *app_name)
Definition: res_stasis.c:1679
Search option field mask.
Definition: astobj2.h:1076
static struct ast_json * app_event_sources_to_json(const struct stasis_app *app, struct ast_json *json)
Definition: res_stasis.c:1850
void stasis_app_unregister_event_sources(void)
Unregister core event sources.
static enum stasis_app_subscribe_res app_subscribe(struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
Definition: res_stasis.c:2019
int(* is_subscribed)(struct stasis_app *app, const char *id)
Find an event source by the given id/name.
Definition: stasis_app.h:216
static void start_message_blob_dtor(void *obj)
Definition: res_stasis.c:982
#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
static const char app[]
Definition: app_mysql.c:62
static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
Definition: res_stasis.c:1159
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:398
static enum stasis_app_subscribe_res app_handle_subscriptions(const char *app_name, const char **event_source_uris, int event_sources_count, struct ast_json **json, app_subscription_handler handler)
Definition: res_stasis.c:1939
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
static void remove_stasis_end_published(struct ast_channel *chan)
Definition: res_stasis.c:1310
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
Endpoint abstractions.
void stasis_app_unregister_event_source(struct stasis_app_event_source *obj)
Unregister an application event source.
Definition: res_stasis.c:1823
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
static enum stasis_app_subscribe_res app_unsubscribe(struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
Definition: res_stasis.c:2064
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:967
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399
static void stasis_app_bridge_channel_wrapper_destructor(void *obj)
Definition: res_stasis.c:455
int(* subscribe)(struct stasis_app *app, void *obj)
Subscribe an application to an event source.
Definition: stasis_app.h:196
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:616
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:206
int control_prestart_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all queued prestart commands.
Definition: control.c:1535
struct ast_bridge * bridge_stasis_new(uint32_t capabilities, unsigned int flags, const char *name, const char *id, enum ast_bridge_video_mode_type video_mode)
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
static struct ast_json * stasis_start_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
Definition: res_stasis.c:147
static struct replace_channel_store * get_replace_channel_store(struct ast_channel *chan, int no_create)
Definition: res_stasis.c:890
static void replace_channel_destroy(void *obj)
Definition: res_stasis.c:876
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *bridge_id)
Returns the current snapshot for the bridge.
Media Format Cache API.
static int channel_sanitizer(const struct ast_channel *chan)
Definition: res_stasis.c:2236
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
void control_wait(struct stasis_app_control *control)
Blocks until control&#39;s command queue has a command available.
Definition: control.c:1515
#define ao2_link(container, obj)
Definition: astobj2.h:1549
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:856