Asterisk - The Open Source Telephony Project  21.4.1
Data Structures | Macros | Typedefs | Functions | Variables
res_stasis.c File Reference

Stasis application support. More...

#include "asterisk.h"
#include "asterisk/astobj2.h"
#include "asterisk/callerid.h"
#include "asterisk/module.h"
#include "asterisk/stasis_app_impl.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_bridges.h"
#include "asterisk/stasis_endpoints.h"
#include "asterisk/stasis_message_router.h"
#include "asterisk/strings.h"
#include "stasis/app.h"
#include "stasis/control.h"
#include "stasis/messaging.h"
#include "stasis/stasis_bridge.h"
#include "asterisk/core_unreal.h"
#include "asterisk/musiconhold.h"
#include "asterisk/causes.h"
#include "asterisk/stringfields.h"
#include "asterisk/bridge_after.h"
#include "asterisk/format_cache.h"

Go to the source code of this file.

Data Structures

struct  event_sources
 
struct  replace_channel_store
 
struct  start_message_blob
 
struct  stasis_app_bridge_channel_wrapper
 

Macros

#define APPS_NUM_BUCKETS   127
 Number of buckets for the Stasis application hash table. Remember to keep it a prime number!
 
#define BRIDGES_NUM_BUCKETS   127
 Number of buckets for the Stasis bridges hash table. Remember to keep it a prime number!
 
#define CONTROLS_NUM_BUCKETS   127
 Number of buckets for the Stasis application hash table. Remember to keep it a prime number!
 
#define MAX_WAIT_MS   200
 

Typedefs

typedef enum stasis_app_subscribe_res(* app_subscription_handler) (struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
 

Functions

static void __reg_module (void)
 
static int __stasis_app_register (const char *app_name, stasis_app_cb handler, void *data, int all_events)
 
static void __unreg_module (void)
 
static int add_masquerade_store (struct ast_channel *chan)
 
static int app_compare (void *obj, void *arg, int flags)
 
static struct stasis_app_event_sourceapp_event_source_find (const char *uri)
 
static struct ast_jsonapp_event_sources_to_json (const struct stasis_app *app, struct ast_json *json)
 
char * app_get_replace_channel_app (struct ast_channel *chan)
 Get the app that the replacement channel will be controlled by. More...
 
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)
 
static int app_hash (const void *obj, const int flags)
 
int app_send_end_msg (struct stasis_app *app, struct ast_channel *chan)
 Send StasisEnd message to the listening app. More...
 
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. More...
 
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. More...
 
static enum stasis_app_subscribe_res app_subscribe (struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
 
static enum stasis_app_subscribe_res app_unsubscribe (struct stasis_app *app, const char *uri, struct stasis_app_event_source *event_source)
 
static int append_name (void *obj, void *arg, int flags)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static struct ast_bridgebridge_create_common (const char *type, const char *name, const char *id, int invisible)
 
static struct ast_channelbridge_moh_create (struct ast_bridge *bridge)
 
static int bridges_channel_compare (void *obj, void *arg, int flags)
 
static int bridges_channel_hash_fn (const void *obj, const int flags)
 
static int bridges_channel_sort_fn (const void *obj_left, const void *obj_right, const int flags)
 
static int bridges_compare (void *obj, void *arg, int flags)
 
static int bridges_hash (const void *obj, const int flags)
 
static int channel_id_sanitizer (const char *id)
 Sanitization callback for channel unique IDs.
 
static void channel_replaced_cb (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
 
static int channel_sanitizer (const struct ast_channel *chan)
 Sanitization callback for channels.
 
static int channel_snapshot_sanitizer (const struct ast_channel_snapshot *snapshot)
 Sanitization callback for channel snapshots.
 
static void channel_stolen_cb (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
 
static void cleanup (void)
 Clean up any old apps that we don't need any more.
 
static int cleanup_cb (void *obj, void *arg, int flags)
 
static int control_compare (void *obj, void *arg, int flags)
 
static int control_hash (const void *obj, const int flags)
 
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 container.
 
static struct stasis_appfind_app_by_name (const char *app_name)
 
static struct ast_channel_snapshotget_replace_channel_snapshot (struct ast_channel *chan)
 
static struct replace_channel_storeget_replace_channel_store (struct ast_channel *chan, int no_create)
 
static int has_masquerade_store (struct ast_channel *chan)
 
static int load_module (void)
 
static int masq_match_cb (void *obj, void *data, int flags)
 
static void * moh_channel_thread (void *data)
 
static void playback_after_bridge_cb (struct ast_channel *chan, void *data)
 
static void playback_after_bridge_cb_failed (enum ast_bridge_after_cb_reason reason, void *data)
 
static struct ast_channelprepare_bridge_moh_channel (void)
 
static void remove_bridge_playback (char *bridge_id)
 
static void remove_masquerade_store (struct ast_channel *chan)
 
static void remove_stasis_end_published (struct ast_channel *chan)
 
static void replace_channel_destroy (void *obj)
 
static int send_start_msg (struct stasis_app *app, struct ast_channel *chan, int argc, char *argv[])
 
static int send_start_msg_snapshots (struct ast_channel *chan, struct stasis_app *app, int argc, char *argv[], struct ast_channel_snapshot *snapshot, struct ast_channel_snapshot *replace_channel_snapshot)
 
static int set_internal_datastore (struct ast_channel *chan)
 
static void start_message_blob_dtor (void *obj)
 
static void stasis_app_bridge_channel_wrapper_destructor (void *obj)
 
struct ast_bridgestasis_app_bridge_create (const char *type, const char *name, const char *id)
 Create a bridge of the specified type. More...
 
struct ast_bridgestasis_app_bridge_create_invisible (const char *type, const char *name, const char *id)
 Create an invisible bridge of the specified type. More...
 
void stasis_app_bridge_destroy (const char *bridge_id)
 Destroy the bridge. More...
 
struct ast_bridgestasis_app_bridge_find_by_id (const char *bridge_id)
 Returns the bridge with the given id. More...
 
struct ast_channelstasis_app_bridge_moh_channel (struct ast_bridge *bridge)
 Finds or creates an announcer channel in a bridge that can play music on hold. More...
 
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. More...
 
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. More...
 
struct ast_channelstasis_app_bridge_playback_channel_find (struct ast_bridge *bridge)
 Finds an existing ARI playback channel in a bridge. More...
 
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. More...
 
int stasis_app_channel_is_internal (struct ast_channel *chan)
 Is this channel internal to Stasis? More...
 
int stasis_app_channel_is_stasis_end_published (struct ast_channel *chan)
 Has this channel had a StasisEnd published on it? More...
 
int stasis_app_channel_set_internal (struct ast_channel *chan)
 Mark this channel as being internal to Stasis. More...
 
void stasis_app_channel_set_stasis_end_published (struct ast_channel *chan)
 Indicate that this channel has had a StasisEnd published for it. More...
 
int stasis_app_channel_unreal_set_internal (struct ast_channel *chan)
 Mark this unreal channel and it's other half as being internal to Stasis. More...
 
struct stasis_app_controlstasis_app_control_create (struct ast_channel *chan)
 Creates a control handler for a channel that isn't in a stasis app. More...
 
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. More...
 
struct stasis_app_controlstasis_app_control_find_by_channel (const struct ast_channel *chan)
 Returns the handler for the given channel. More...
 
struct stasis_app_controlstasis_app_control_find_by_channel_id (const char *channel_id)
 Returns the handler for the channel with the given id. More...
 
void stasis_app_control_flush_queue (struct stasis_app_control *control)
 Flush the control command queue. More...
 
int stasis_app_control_is_done (struct stasis_app_control *control)
 Check if a control is marked as done. More...
 
int stasis_app_exec (struct ast_channel *chan, const char *app_name, int argc, char *argv[])
 Stasis dialplan application callback. More...
 
struct ao2_containerstasis_app_get_all (void)
 Gets the names of all registered Stasis applications. More...
 
struct stasis_appstasis_app_get_by_name (const char *name)
 Retrieve a handle to a Stasis application by its name. More...
 
struct stasis_message_sanitizerstasis_app_get_sanitizer (void)
 Get the Stasis message sanitizer for app_stasis applications. More...
 
struct ast_jsonstasis_app_object_to_json (struct stasis_app *app)
 Return the JSON representation of a Stasis application. More...
 
int stasis_app_register (const char *app_name, stasis_app_cb handler, void *data)
 Register a new Stasis application. More...
 
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. More...
 
void stasis_app_register_event_source (struct stasis_app_event_source *obj)
 Register an application event source. More...
 
int stasis_app_send (const char *app_name, struct ast_json *message)
 Send a message to the given Stasis application. More...
 
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. More...
 
enum stasis_app_subscribe_res stasis_app_subscribe_channel (const char *app_name, struct ast_channel *chan)
 Directly subscribe an application to a channel. More...
 
struct ast_jsonstasis_app_to_json (const char *app_name)
 Return the JSON representation of a Stasis application. More...
 
void stasis_app_unregister (const char *app_name)
 Unregister a Stasis application. More...
 
void stasis_app_unregister_event_source (struct stasis_app_event_source *obj)
 Unregister an application event source. More...
 
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. More...
 
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) More...
 
static struct ast_jsonstasis_end_to_json (struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (end_message_type,.to_json=stasis_end_to_json)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (start_message_type,.to_json=stasis_start_to_json)
 
static struct ast_jsonstasis_start_to_json (struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Stasis application support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load_pri = AST_MODPRI_APP_DEPEND - 1, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, }
 
struct ao2_containerapp_bridges
 
struct ao2_containerapp_bridges_moh
 
struct ao2_containerapp_bridges_playback
 
struct ao2_containerapp_controls
 
struct stasis_message_sanitizer app_sanitizer
 Sanitization callbacks for communication to Stasis applications. More...
 
struct ao2_containerapps_registry
 Stasis application container.
 
static const struct ast_module_infoast_module_info = &__mod_info
 
struct event_sources event_sources = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
static const struct ast_datastore_info masquerade_store_info
 
static const struct ast_datastore_info replace_channel_store_info
 
struct ast_datastore_info set_end_published_info
 
static const struct ast_datastore_info stasis_internal_channel_info
 

Detailed Description

Stasis application support.

Author
David M. Lee, II dlee@.nosp@m.digi.nosp@m.um.co.nosp@m.m

res_stasis.so brings together the various components of the Stasis application infrastructure.

First, there's the Stasis application handler, stasis_app_exec(). This is called by app_stasis.so to give control of a channel to the Stasis application code from the dialplan.

While a channel is in stasis_app_exec(), it has a stasis_app_control object, which may be used to control the channel.

To control the channel, commands may be sent to channel using stasis_app_send_command() and stasis_app_send_async_command().

Alongside this, applications may be registered/unregistered using stasis_app_register()/stasis_app_unregister(). While a channel is in Stasis, events received on the channel's topic are converted to JSON and forwarded to the stasis_app_cb. The application may also subscribe to the channel to continue to receive messages even after the channel has left Stasis, but it will not be able to control it.

Given all the stuff that comes together in this module, it's been broken up into several pieces that are in res/stasis/ and compiled into res_stasis.so.

Definition in file res_stasis.c.

Macro Definition Documentation

#define MAX_WAIT_MS   200

Time to wait for a frame in the application

Definition at line 77 of file res_stasis.c.

Referenced by stasis_app_exec().

Function Documentation

static int app_compare ( void *  obj,
void *  arg,
int  flags 
)
static

AO2 comparison function for app

Definition at line 208 of file res_stasis.c.

References CMP_MATCH, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, OBJ_SEARCH_PARTIAL_KEY, and stasis_app_name().

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 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application's name.
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
Search option field mask.
Definition: astobj2.h:1072
char* app_get_replace_channel_app ( struct ast_channel chan)

Get the app that the replacement channel will be controlled by.

Parameters
chanThe channel on which this will be set
Return values
NULLon error
Returns
the name of the controlling app (must be ast_free()d)

Definition at line 970 of file res_stasis.c.

971 {
972  struct replace_channel_store *replace = get_replace_channel_store(chan, 1);
973  char *replace_channel_app;
974 
975  if (!replace) {
976  return NULL;
977  }
978 
979  replace_channel_app = replace->app;
980  replace->app = NULL;
981 
982  return replace_channel_app;
983 }
static int app_hash ( const void *  obj,
const int  flags 
)
static

AO2 hash function for app

Definition at line 186 of file res_stasis.c.

References ast_str_hash(), OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and stasis_app_name().

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 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application's name.
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
Search option field mask.
Definition: astobj2.h:1072
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
int app_send_end_msg ( struct stasis_app app,
struct ast_channel chan 
)

Send StasisEnd message to the listening app.

Parameters
appThe app that owns the channel
chanThe channel for which the message is being sent
Return values
zeroon success
Returns
non-zero on failure

Definition at line 1086 of file res_stasis.c.

References app_unsubscribe_channel(), ast_app_get_topic(), ast_channel_blob_create(), ast_json_pack(), ast_json_timeval(), ast_json_unref(), ast_tvnow(), stasis_message_sanitizer::channel, stasis_app_get_sanitizer(), stasis_app_name(), and stasis_publish().

Referenced by stasis_app_exec().

1087 {
1089  struct ast_json *blob;
1090  struct stasis_message *msg;
1091 
1092  if (sanitize && sanitize->channel
1093  && sanitize->channel(chan)) {
1094  return 0;
1095  }
1096 
1097  blob = ast_json_pack("{s: s, s: o}",
1098  "app", stasis_app_name(app),
1099  "timestamp", ast_json_timeval(ast_tvnow(), NULL)
1100  );
1101  if (!blob) {
1102  ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n");
1103  return -1;
1104  }
1105 
1106  remove_masquerade_store(chan);
1107  app_unsubscribe_channel(app, chan);
1108  msg = ast_channel_blob_create(chan, end_message_type(), blob);
1109  if (msg) {
1110  stasis_publish(ast_app_get_topic(app), msg);
1111  }
1112  ao2_cleanup(msg);
1113  ast_json_unref(blob);
1114 
1115  return 0;
1116 }
struct stasis_topic * ast_app_get_topic(struct stasis_app *app)
Returns the stasis topic for an app.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int app_unsubscribe_channel(struct stasis_app *app, struct ast_channel *chan)
Cancel the subscription an app has for a channel.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
Definition: res_stasis.c:2271
Structure containing callbacks for Stasis message sanitization.
Definition: stasis.h:200
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application's name.
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
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:670
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.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1511
Abstract JSON element (object, array, string, int, ...).
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.

Parameters
chanThe channel on which this will be set
replace_appThe app that will be controlling this channel
Return values
zerosuccess
non-zerofailure

Definition at line 934 of file res_stasis.c.

References ast_strdup.

935 {
936  struct replace_channel_store *replace = get_replace_channel_store(chan, 0);
937 
938  if (!replace) {
939  return -1;
940  }
941 
942  ast_free(replace->app);
943  replace->app = NULL;
944 
945  if (replace_app) {
946  replace->app = ast_strdup(replace_app);
947  if (!replace->app) {
948  return -1;
949  }
950  }
951 
952  return 0;
953 }
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
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.

Parameters
chanThe channel on which this will be set
replace_snapshotThe snapshot of the channel that is being replaced
Return values
zerosuccess
non-zerofailure

Definition at line 922 of file res_stasis.c.

References ao2_replace.

923 {
924  struct replace_channel_store *replace = get_replace_channel_store(chan, 0);
925 
926  if (!replace) {
927  return -1;
928  }
929 
930  ao2_replace(replace->snapshot, replace_snapshot);
931  return 0;
932 }
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition: astobj2.h:501
static int bridges_channel_compare ( void *  obj,
void *  arg,
int  flags 
)
static

AO2 comparison function for bridges moh container

Definition at line 429 of file res_stasis.c.

References CMP_MATCH, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and OBJ_SEARCH_PARTIAL_KEY.

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 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
Search option field mask.
Definition: astobj2.h:1072
static int bridges_channel_hash_fn ( const void *  obj,
const int  flags 
)
static

AO2 hash function for the bridges moh container

Definition at line 462 of file res_stasis.c.

References ast_str_hash(), OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, and OBJ_SEARCH_OBJECT.

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 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
Search option field mask.
Definition: astobj2.h:1072
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
static int bridges_compare ( void *  obj,
void *  arg,
int  flags 
)
static

AO2 comparison function for bridges container

Definition at line 378 of file res_stasis.c.

References CMP_MATCH, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, OBJ_SEARCH_PARTIAL_KEY, and ast_bridge::uniqueid.

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 }
const ast_string_field uniqueid
Definition: bridge.h:401
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
Structure that contains information about a bridge.
Definition: bridge.h:349
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
Search option field mask.
Definition: astobj2.h:1072
static int bridges_hash ( const void *  obj,
const int  flags 
)
static

AO2 hash function for bridges container

Definition at line 356 of file res_stasis.c.

References ast_str_hash(), OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and ast_bridge::uniqueid.

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 }
const ast_string_field uniqueid
Definition: bridge.h:401
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
Structure that contains information about a bridge.
Definition: bridge.h:349
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
Search option field mask.
Definition: astobj2.h:1072
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
static int control_compare ( void *  obj,
void *  arg,
int  flags 
)
static

AO2 comparison function for stasis_app_control

Definition at line 270 of file res_stasis.c.

References CMP_MATCH, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, OBJ_SEARCH_PARTIAL_KEY, and stasis_app_control_get_channel_id().

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 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
const char * stasis_app_control_get_channel_id(const struct stasis_app_control *control)
Returns the uniqueid of the channel associated with this control.
Definition: control.c:1452
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
Search option field mask.
Definition: astobj2.h:1072
static int control_hash ( const void *  obj,
const int  flags 
)
static

AO2 hash function for stasis_app_control

Definition at line 248 of file res_stasis.c.

References ast_str_hash(), OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and stasis_app_control_get_channel_id().

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 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
const char * stasis_app_control_get_channel_id(const struct stasis_app_control *control)
Returns the uniqueid of the channel associated with this control.
Definition: control.c:1452
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
Search option field mask.
Definition: astobj2.h:1072
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
static void* moh_channel_thread ( void *  data)
static

Provides the moh channel with a thread so it can actually play its music

Definition at line 529 of file res_stasis.c.

References ao2_ref, ao2_unlink, ast_channel_get_by_name(), ast_hangup(), ast_moh_stop(), ast_read(), and ast_waitfor().

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 }
Main Channel structure associated with a channel.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7776
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
Data structure associated with a single frame of data.
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
static struct ast_channel* prepare_bridge_moh_channel ( void  )
static

Request a bridge MOH channel

Definition at line 510 of file res_stasis.c.

References ao2_ref, ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_slin, and ast_request().

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 }
Main Channel structure associated with a channel.
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6354
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
static void remove_bridge_playback ( char *  bridge_id)
static

Removes the bridge to playback channel link

Definition at line 673 of file res_stasis.c.

References ao2_ref, ao2_unlink, OBJ_SEARCH_KEY, OBJ_UNLINK, and stasis_app_control_find_by_channel_id().

674 {
675  struct stasis_app_bridge_channel_wrapper *wrapper;
676  struct stasis_app_control *control;
677 
678  wrapper = ao2_find(app_bridges_playback, bridge_id, OBJ_SEARCH_KEY | OBJ_UNLINK);
679 
680  if (wrapper) {
681  control = stasis_app_control_find_by_channel_id(wrapper->channel_id);
682  if (control) {
683  ao2_unlink(app_controls, control);
684  ao2_ref(control, -1);
685  }
686  ao2_ref(wrapper, -1);
687  }
688  ast_free(bridge_id);
689 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
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_create ( const char *  type,
const char *  name,
const char *  id 
)

Create a bridge of the specified type.

Parameters
typeThe type of bridge to be created
nameOptional name to give to the bridge
idOptional Unique ID to give to the bridge
Returns
New bridge.
Return values
NULLon error.

Definition at line 854 of file res_stasis.c.

Referenced by ast_ari_bridges_create(), and ast_ari_bridges_create_with_id().

855 {
856  return bridge_create_common(type, name, id, 0);
857 }
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.

Parameters
typeThe type of bridge to be created
nameOptional name to give to the bridge
idOptional Unique ID to give to the bridge
Returns
New bridge.
Return values
NULLon error.

Definition at line 859 of file res_stasis.c.

Referenced by get_dial_bridge().

860 {
861  return bridge_create_common(type, name, id, 1);
862 }
void stasis_app_bridge_destroy ( const char *  bridge_id)

Destroy the bridge.

Parameters
bridge_idUniqueid of bridge to be destroyed

Definition at line 864 of file res_stasis.c.

References ao2_unlink, ast_bridge_destroy(), and stasis_app_bridge_find_by_id().

Referenced by ast_ari_bridges_destroy().

865 {
866  struct ast_bridge *bridge = stasis_app_bridge_find_by_id(bridge_id);
867  if (!bridge) {
868  return;
869  }
870  ao2_unlink(app_bridges, bridge);
871  ast_bridge_destroy(bridge, 0);
872 }
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition: bridge.c:944
Structure that contains information about a bridge.
Definition: bridge.h:349
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
struct ast_bridge * stasis_app_bridge_find_by_id(const char *bridge_id)
Returns the bridge with the given id.
Definition: res_stasis.c:774
struct ast_bridge* stasis_app_bridge_find_by_id ( const char *  bridge_id)

Returns the bridge with the given id.

Parameters
bridge_idUniqueid of the bridge.
Returns
NULL bridge not created by a Stasis application, or bridge does not exist.
Pointer to bridge.

Definition at line 774 of file res_stasis.c.

References OBJ_SEARCH_KEY.

Referenced by find_bridge(), and stasis_app_bridge_destroy().

776 {
777  return ao2_find(app_bridges, bridge_id, OBJ_SEARCH_KEY);
778 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
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.

Parameters
bridgeBridge we want an MOH channel for
Returns
NULL if the music on hold channel fails to be created or join the bridge for any reason.
Pointer to the ;1 end of the announcer channel chain.

Definition at line 629 of file res_stasis.c.

References ao2_ref, ast_channel_get_by_name(), OBJ_NOLOCK, OBJ_SEARCH_KEY, and ast_bridge::uniqueid.

Referenced by ast_ari_bridges_start_moh().

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 }
Main Channel structure associated with a channel.
const ast_string_field uniqueid
Definition: bridge.h:401
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
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.

Parameters
bridgeBridge we want to stop the MOH on
Returns
-1 if no moh channel could be found and stopped
0 on success

Definition at line 649 of file res_stasis.c.

References ao2_ref, ast_channel_get_by_name(), ast_moh_stop(), ast_softhangup(), OBJ_SEARCH_KEY, OBJ_UNLINK, and ast_bridge::uniqueid.

Referenced by ast_ari_bridges_stop_moh().

650 {
651  struct stasis_app_bridge_channel_wrapper *moh_wrapper;
652  struct ast_channel *chan;
653 
654  moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_UNLINK);
655  if (!moh_wrapper) {
656  return -1;
657  }
658 
659  chan = ast_channel_get_by_name(moh_wrapper->channel_id);
660  ao2_ref(moh_wrapper, -1);
661  if (!chan) {
662  return -1;
663  }
664 
665  ast_moh_stop(chan);
666  ast_softhangup(chan, AST_CAUSE_NORMAL_CLEARING);
667  ao2_cleanup(chan);
668 
669  return 0;
670 }
Main Channel structure associated with a channel.
const ast_string_field uniqueid
Definition: bridge.h:401
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2471
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7776
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
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.

Parameters
bridgeBridge we are adding the playback channel for
chanChannel being added as a playback channel (must be ;1)
controlThe app control structure for the playback channel
Return values
-1failed to add channel for any reason
0on success

Definition at line 705 of file res_stasis.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_link, ast_bridge_set_after_callback(), ast_strdup, ast_string_field_init, ast_string_field_set, RAII_VAR, and ast_bridge::uniqueid.

708 {
709  RAII_VAR(struct stasis_app_bridge_channel_wrapper *, new_wrapper, NULL, ao2_cleanup);
710  char *bridge_id = ast_strdup(bridge->uniqueid);
711 
712  if (!bridge_id) {
713  return -1;
714  }
715 
717  playback_after_bridge_cb, playback_after_bridge_cb_failed, bridge_id)) {
718  ast_free(bridge_id);
719  return -1;
720  }
721 
722  new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
723  stasis_app_bridge_channel_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
724  if (!new_wrapper) {
725  return -1;
726  }
727 
728  if (ast_string_field_init(new_wrapper, 32)) {
729  return -1;
730  }
731 
732  ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
733  ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
734 
735  if (!ao2_link(app_bridges_playback, new_wrapper)) {
736  return -1;
737  }
738 
739  ao2_link(app_controls, control);
740  return 0;
741 }
const ast_string_field uniqueid
Definition: bridge.h:401
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data)
Setup an after bridge callback for when the channel leaves the bridging system.
Definition: bridge_after.c:251
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
struct ast_channel* stasis_app_bridge_playback_channel_find ( struct ast_bridge bridge)

Finds an existing ARI playback channel in a bridge.

Parameters
bridgeBridge we want to find the playback channel for
Returns
NULL if the playback channel can not be found for any reason.
Pointer to the ;1 end of the playback channel chain.

Definition at line 759 of file res_stasis.c.

References ao2_ref, ast_channel_get_by_name(), OBJ_SEARCH_KEY, and ast_bridge::uniqueid.

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 }
Main Channel structure associated with a channel.
const ast_string_field uniqueid
Definition: bridge.h:401
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
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.

Parameters
bridge_idThe unique ID of the bridge the playback channel is in.
controlThe app control structure for the playback channel

Definition at line 743 of file res_stasis.c.

References ao2_ref, ao2_unlink, OBJ_SEARCH_KEY, and OBJ_UNLINK.

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 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
int stasis_app_channel_is_internal ( struct ast_channel chan)

Is this channel internal to Stasis?

Parameters
chanThe channel to check.
Return values
0No
1Yes

Definition at line 2329 of file res_stasis.c.

References ast_channel_datastore_find().

2330 {
2331  struct ast_datastore *datastore;
2332  int res = 0;
2333 
2334  ast_channel_lock(chan);
2335  datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL);
2336  if (datastore) {
2337  res = 1;
2338  }
2339  ast_channel_unlock(chan);
2340 
2341  return res;
2342 }
Structure for a data store object.
Definition: datastore.h:64
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
int stasis_app_channel_is_stasis_end_published ( struct ast_channel chan)

Has this channel had a StasisEnd published on it?

Parameters
chanThe channel upon which the query rests.
Return values
0No
1Yes

Definition at line 1302 of file res_stasis.c.

References ast_channel_datastore_find().

Referenced by stasis_app_exec().

1303 {
1304  struct ast_datastore *datastore;
1305 
1306  ast_channel_lock(chan);
1307  datastore = ast_channel_datastore_find(chan, &set_end_published_info, NULL);
1308  ast_channel_unlock(chan);
1309 
1310  return datastore ? 1 : 0;
1311 }
Structure for a data store object.
Definition: datastore.h:64
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
int stasis_app_channel_set_internal ( struct ast_channel chan)

Mark this channel as being internal to Stasis.

Parameters
chanThe channel to mark.
Return values
zeroSuccess
non-zeroFailure

Definition at line 2318 of file res_stasis.c.

2319 {
2320  int res;
2321 
2322  ast_channel_lock(chan);
2323  res = set_internal_datastore(chan);
2324  ast_channel_unlock(chan);
2325 
2326  return res;
2327 }
void stasis_app_channel_set_stasis_end_published ( struct ast_channel chan)

Indicate that this channel has had a StasisEnd published for it.

Parameters
chanThe channel that is exiting Stasis.

Definition at line 1290 of file res_stasis.c.

References ast_channel_datastore_add().

1291 {
1292  struct ast_datastore *datastore;
1293 
1294  datastore = ast_datastore_alloc(&set_end_published_info, NULL);
1295  if (datastore) {
1296  ast_channel_lock(chan);
1297  ast_channel_datastore_add(chan, datastore);
1298  ast_channel_unlock(chan);
1299  }
1300 }
Structure for a data store object.
Definition: datastore.h:64
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
int stasis_app_channel_unreal_set_internal ( struct ast_channel chan)

Mark this unreal channel and it's other half as being internal to Stasis.

Parameters
chanThe channel to mark.
Return values
zeroSuccess
non-zeroFailure

Definition at line 2295 of file res_stasis.c.

References ao2_ref, ast_channel_unref, and ast_unreal_lock_all().

2296 {
2297  struct ast_channel *outchan = NULL, *outowner = NULL;
2298  int res = 0;
2299  struct ast_unreal_pvt *unreal_pvt = ast_channel_tech_pvt(chan);
2300 
2301  ao2_ref(unreal_pvt, +1);
2302  ast_unreal_lock_all(unreal_pvt, &outowner, &outchan);
2303  if (outowner) {
2304  res |= set_internal_datastore(outowner);
2305  ast_channel_unlock(outowner);
2306  ast_channel_unref(outowner);
2307  }
2308  if (outchan) {
2309  res |= set_internal_datastore(outchan);
2310  ast_channel_unlock(outchan);
2311  ast_channel_unref(outchan);
2312  }
2313  ao2_unlock(unreal_pvt);
2314  ao2_ref(unreal_pvt, -1);
2315  return res;
2316 }
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
The base pvt structure for local channel derivatives.
Definition: core_unreal.h:91
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
struct stasis_app_control* stasis_app_control_create ( struct ast_channel chan)

Creates a control handler for a channel that isn't in a stasis app.

Since
12.0.0
Parameters
chanChannel to create controller handle for
Returns
NULL on failure to create the handle
Pointer to res_stasis handler.

Definition at line 333 of file res_stasis.c.

References control_create().

Referenced by ast_ari_bridges_record().

334 {
335  return control_create(chan, NULL);
336 }
struct stasis_app_control * control_create(struct ast_channel *channel, struct stasis_app *app)
Create a control object.
Definition: control.c:129
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.

Since
12.0.0
Parameters
chanChannel to handle
controlControl object to execute

Definition at line 1253 of file res_stasis.c.

References control_command_count(), control_dispatch_all(), and control_is_done().

1254 {
1255  while (!control_is_done(control)) {
1256  int command_count;
1257  command_count = control_dispatch_all(control, chan);
1258 
1259  ao2_lock(control);
1260 
1261  if (control_command_count(control)) {
1262  /* If the command queue isn't empty, something added to the queue before it was locked. */
1263  ao2_unlock(control);
1264  continue;
1265  }
1266 
1267  if (command_count == 0 || ast_channel_fdno(chan) == -1) {
1268  control_mark_done(control);
1269  ao2_unlock(control);
1270  break;
1271  }
1272  ao2_unlock(control);
1273  }
1274 }
int control_command_count(struct stasis_app_control *control)
Returns the count of items in a control's command queue.
Definition: control.c:365
int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all commands enqueued to this control.
Definition: control.c:1517
int control_is_done(struct stasis_app_control *control)
Returns true if control_continue() has been called on this control.
Definition: control.c:370
struct stasis_app_control* stasis_app_control_find_by_channel ( const struct ast_channel chan)

Returns the handler for the given channel.

Parameters
chanChannel to handle.
Returns
NULL channel not in Stasis application.
Pointer to res_stasis handler.

Definition at line 338 of file res_stasis.c.

References stasis_app_control_find_by_channel_id().

Referenced by ari_bridges_play_found(), and bridge_timeout().

340 {
341  if (chan == NULL) {
342  return NULL;
343  }
344 
346  ast_channel_uniqueid(chan));
347 }
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 stasis_app_control* stasis_app_control_find_by_channel_id ( const char *  channel_id)

Returns the handler for the channel with the given id.

Parameters
channel_idUniqueid of the channel.
Returns
NULL channel not in Stasis application, or channel does not exist.
Pointer to res_stasis handler.

Definition at line 349 of file res_stasis.c.

References OBJ_SEARCH_KEY.

Referenced by find_channel_control(), find_control(), remove_bridge_playback(), and stasis_app_control_find_by_channel().

351 {
352  return ao2_find(app_controls, channel_id, OBJ_SEARCH_KEY);
353 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
void stasis_app_control_flush_queue ( struct stasis_app_control control)

Flush the control command queue.

Since
13.9.0
Parameters
controlControl object to flush command queue.

Definition at line 1281 of file res_stasis.c.

References control_flush_queue().

1282 {
1283  control_flush_queue(control);
1284 }
void control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: control.c:1504
int stasis_app_control_is_done ( struct stasis_app_control control)

Check if a control is marked as done.

Since
12.2.0
Parameters
controlWhich control object is being evaluated

Definition at line 1276 of file res_stasis.c.

References control_is_done().

Referenced by ari_bridges_play_found().

1277 {
1278  return control_is_done(control);
1279 }
int control_is_done(struct stasis_app_control *control)
Returns true if control_continue() has been called on this control.
Definition: control.c:370
int stasis_app_exec ( struct ast_channel chan,
const char *  app_name,
int  argc,
char *  argv[] 
)

Stasis dialplan application callback.

Control a channel using stasis_app.

Definition at line 1327 of file res_stasis.c.

References ao2_bump, ao2_link, ao2_ref, app_is_active(), app_send(), app_send_end_msg(), app_subscribe_bridge(), app_unsubscribe_bridge(), ast_bridge_depart(), ast_channel_clear_softhangup(), ast_channel_snapshot_get_latest(), ast_channel_snapshot_to_json(), ast_check_hangup(), AST_CONTROL_HANGUP, ast_debug, AST_FRAME_CONTROL, ast_frame_dtor(), ast_json_array_append(), ast_json_object_get(), ast_json_pack(), ast_json_string_create(), ast_json_timeval(), ast_json_unref(), ast_pbx_run_args(), ast_read(), AST_SOFTHANGUP_ASYNCGOTO, ast_tvnow(), ast_waitfor(), cleanup(), control_app(), control_create(), control_dispatch_all(), control_flush_queue(), control_is_done(), control_move_cleanup(), control_next_app(), control_next_app_args(), control_next_app_args_size(), control_prestart_dispatch_all(), control_set_app(), control_set_thread(), control_silence_stop_now(), control_unlink(), control_wait(), MAX_WAIT_MS, ast_pbx_args::no_hangup_chan, OBJ_SEARCH_KEY, RAII_VAR, stasis_app_channel_is_stasis_end_published(), stasis_app_get_bridge(), and stasis_app_name().

Referenced by app_exec().

1329 {
1330  RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1331  RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
1332  struct ast_bridge *bridge = NULL;
1333  int res = 0;
1334  int needs_depart;
1335 
1336  ast_assert(chan != NULL);
1337 
1338  /* Just in case there's a lingering indication that the channel has had a stasis
1339  * end published on it, remove that now.
1340  */
1341  remove_stasis_end_published(chan);
1342 
1343  if (!apps_registry) {
1344  return -1;
1345  }
1346 
1347  app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1348  if (!app) {
1349  ast_log(LOG_ERROR,
1350  "Stasis app '%s' not registered\n", app_name);
1351  return -1;
1352  }
1353  if (!app_is_active(app)) {
1354  ast_log(LOG_ERROR,
1355  "Stasis app '%s' not active\n", app_name);
1356  return -1;
1357  }
1358 
1359  control = control_create(chan, app);
1360  if (!control) {
1361  ast_log(LOG_ERROR, "Control allocation failed or Stasis app '%s' not registered\n", app_name);
1362  return -1;
1363  }
1364 
1365  if (!control_app(control)) {
1366  ast_log(LOG_ERROR, "Stasis app '%s' not registered\n", app_name);
1367  return -1;
1368  }
1369 
1370  if (!app_is_active(control_app(control))) {
1371  ast_log(LOG_ERROR, "Stasis app '%s' not active\n", app_name);
1372  return -1;
1373  }
1374  ao2_link(app_controls, control);
1375 
1376  if (add_masquerade_store(chan)) {
1377  ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1378  return -1;
1379  }
1380 
1381  res = send_start_msg(control_app(control), chan, argc, argv);
1382  if (res != 0) {
1383  ast_log(LOG_ERROR,
1384  "Error sending start message to '%s'\n", app_name);
1385  remove_masquerade_store(chan);
1386  return -1;
1387  }
1388 
1389  /* Pull queued prestart commands and execute */
1390  control_prestart_dispatch_all(control, chan);
1391 
1392  while (!control_is_done(control)) {
1393  RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
1394  int r;
1395  int command_count;
1396  RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup);
1397 
1398  /* Check to see if a bridge absorbed our hangup frame */
1399  if (ast_check_hangup_locked(chan)) {
1400  control_mark_done(control);
1401  break;
1402  }
1403 
1404  /* control->next_app is only modified within the control thread, so this is safe */
1405  if (control_next_app(control)) {
1406  struct stasis_app *next_app = ao2_find(apps_registry, control_next_app(control), OBJ_SEARCH_KEY);
1407 
1408  if (next_app && app_is_active(next_app)) {
1409  int idx;
1410  int next_argc;
1411  char **next_argv;
1412 
1413  /* If something goes wrong in this conditional, res will need to be non-zero
1414  * so that the code below the exec loop knows something went wrong during a move.
1415  */
1417  res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1418  if (res != 0) {
1419  ast_log(LOG_ERROR,
1420  "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1421  control_mark_done(control);
1422  ao2_ref(next_app, -1);
1423  break;
1424  }
1425  } else {
1426  remove_stasis_end_published(chan);
1427  }
1428 
1429  /* This will ao2_bump next_app, and unref the previous app by 1 */
1430  control_set_app(control, next_app);
1431 
1432  /* There's a chance that the previous application is ready for clean up, so go ahead
1433  * and do that now.
1434  */
1435  cleanup();
1436 
1437  /* We need to add another masquerade store, otherwise the leave message will
1438  * not show up for the correct application.
1439  */
1440  if (add_masquerade_store(chan)) {
1441  ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1442  res = -1;
1443  control_mark_done(control);
1444  ao2_ref(next_app, -1);
1445  break;
1446  }
1447 
1448  /* We MUST get the size before the list, as control_next_app_args steals the elements
1449  * from the string vector.
1450  */
1451  next_argc = control_next_app_args_size(control);
1452  next_argv = control_next_app_args(control);
1453 
1454  res = send_start_msg(control_app(control), chan, next_argc, next_argv);
1455 
1456  /* Even if res != 0, we still need to free the memory we got from control_argv */
1457  if (next_argv) {
1458  for (idx = 0; idx < next_argc; idx++) {
1459  ast_free(next_argv[idx]);
1460  }
1461  ast_free(next_argv);
1462  }
1463 
1464  if (res != 0) {
1465  ast_log(LOG_ERROR,
1466  "Error sending start message to '%s'\n", stasis_app_name(control_app(control)));
1467  remove_masquerade_store(chan);
1468  control_mark_done(control);
1469  ao2_ref(next_app, -1);
1470  break;
1471  }
1472 
1473  /* Done switching applications, free memory and clean up */
1474  control_move_cleanup(control);
1475  } else {
1476  /* If we can't switch applications, do nothing */
1477  struct ast_json *msg;
1478  RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1479 
1480  if (!next_app) {
1481  ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not registered\n",
1482  control_next_app(control));
1483  } else {
1484  ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not active\n",
1485  control_next_app(control));
1486  }
1487 
1488  snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
1489  if (!snapshot) {
1490  ast_log(LOG_ERROR, "Could not get channel shapshot for '%s'\n",
1491  ast_channel_name(chan));
1492  } else {
1493  struct ast_json *json_args;
1494  int next_argc = control_next_app_args_size(control);
1495  char **next_argv = control_next_app_args(control);
1496 
1497  msg = ast_json_pack("{s: s, s: o, s: o, s: s, s: []}",
1498  "type", "ApplicationMoveFailed",
1499  "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1500  "channel", ast_channel_snapshot_to_json(snapshot, NULL),
1501  "destination", control_next_app(control),
1502  "args");
1503  if (!msg) {
1504  ast_log(LOG_ERROR, "Failed to pack JSON for ApplicationMoveFailed message\n");
1505  } else {
1506  json_args = ast_json_object_get(msg, "args");
1507  if (!json_args) {
1508  ast_log(LOG_ERROR, "Could not get args json array");
1509  } else {
1510  int r = 0;
1511  int idx;
1512  for (idx = 0; idx < next_argc; ++idx) {
1513  r = ast_json_array_append(json_args,
1514  ast_json_string_create(next_argv[idx]));
1515  if (r != 0) {
1516  ast_log(LOG_ERROR, "Error appending to ApplicationMoveFailed message\n");
1517  break;
1518  }
1519  }
1520  if (r == 0) {
1521  app_send(control_app(control), msg);
1522  }
1523  }
1524  ast_json_unref(msg);
1525  }
1526  }
1527  }
1528  control_move_cleanup(control);
1529  ao2_cleanup(next_app);
1530  }
1531 
1532  last_bridge = bridge;
1533  bridge = ao2_bump(stasis_app_get_bridge(control));
1534 
1535  if (bridge != last_bridge) {
1536  if (last_bridge) {
1537  app_unsubscribe_bridge(control_app(control), last_bridge);
1538  }
1539  if (bridge) {
1540  app_subscribe_bridge(control_app(control), bridge);
1541  }
1542  }
1543 
1544  if (bridge) {
1545  /* Bridge/dial is handling channel frames */
1546  control_wait(control);
1547  control_dispatch_all(control, chan);
1548  continue;
1549  }
1550 
1551  /* Set this thread's id as the control thread id so that any
1552  new commands can signal out of this wait */
1553  control_set_thread(control, pthread_self());
1554  r = ast_waitfor(chan, MAX_WAIT_MS);
1555  control_set_thread(control, AST_PTHREADT_NULL);
1556 
1557  if (r < 0) {
1558  ast_debug(3, "%s: Poll error\n",
1559  ast_channel_uniqueid(chan));
1560  control_mark_done(control);
1561  break;
1562  }
1563 
1564  command_count = control_dispatch_all(control, chan);
1565 
1566  if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1567  /* Command drained the channel; wait for next frame */
1568  continue;
1569  }
1570 
1571  if (r == 0) {
1572  /* Timeout */
1573  continue;
1574  }
1575 
1576  f = ast_read(chan);
1577  if (!f) {
1578  /* Continue on in the dialplan */
1579  ast_debug(3, "%s: Hangup (no more frames)\n",
1580  ast_channel_uniqueid(chan));
1581  control_mark_done(control);
1582  break;
1583  }
1584 
1585  if (f->frametype == AST_FRAME_CONTROL) {
1586  if (f->subclass.integer == AST_CONTROL_HANGUP) {
1587  /* Continue on in the dialplan */
1588  ast_debug(3, "%s: Hangup\n",
1589  ast_channel_uniqueid(chan));
1590  control_mark_done(control);
1591  break;
1592  }
1593  }
1594  }
1595 
1596  ast_channel_lock(chan);
1597  needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1598  ast_channel_unlock(chan);
1599  if (needs_depart) {
1600  ast_bridge_depart(chan);
1601  }
1602 
1603  if (stasis_app_get_bridge(control)) {
1605  }
1606  ao2_cleanup(bridge);
1607 
1608  /* Only publish a stasis_end event if it hasn't already been published */
1609  if (!res && !stasis_app_channel_is_stasis_end_published(chan)) {
1610  /* A masquerade has occurred and this message will be wrong so it
1611  * has already been sent elsewhere. */
1612  res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1613  if (res != 0) {
1614  ast_log(LOG_ERROR,
1615  "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1616  return res;
1617  }
1618  } else {
1619  remove_stasis_end_published(chan);
1620  }
1621 
1622  control_flush_queue(control);
1623 
1624  /* Stop any lingering silence generator */
1625  control_silence_stop_now(control);
1626 
1627  /* There's an off chance that app is ready for cleanup. Go ahead
1628  * and clean up, just in case
1629  */
1630  cleanup();
1631 
1632  /* The control needs to be removed from the controls container in
1633  * case a new PBX is started and ends up coming back into Stasis.
1634  */
1635  control_unlink(control);
1636  control = NULL;
1637 
1638  if (!res && !ast_channel_pbx(chan)) {
1639  int chan_hungup;
1640 
1641  /* The ASYNCGOTO softhangup flag may have broken the channel out of
1642  * its bridge to run dialplan, so if there's no pbx on the channel
1643  * let it run dialplan here. Otherwise, it will run when this
1644  * application exits. */
1645  ast_channel_lock(chan);
1647  chan_hungup = ast_check_hangup(chan);
1648  ast_channel_unlock(chan);
1649 
1650  if (!chan_hungup) {
1651  struct ast_pbx_args pbx_args;
1652 
1653  memset(&pbx_args, 0, sizeof(pbx_args));
1654  pbx_args.no_hangup_chan = 1;
1655 
1656  res = ast_pbx_run_args(chan, &pbx_args);
1657  }
1658  }
1659 
1660  return res;
1661 }
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition: control.c:953
Options for ast_pbx_run()
Definition: pbx.h:407
char * control_next_app(struct stasis_app_control *control)
Returns the name of the application we are moving to.
Definition: control.c:1719
char ** control_next_app_args(struct stasis_app_control *control)
Returns the list of arguments to pass to the application we are moving to.
Definition: control.c:1732
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
void control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: control.c:1504
Structure representing a snapshot of channel state.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
struct stasis_app * control_app(struct stasis_app_control *control)
Returns the pointer (non-reffed) to the app associated with this control.
Definition: control.c:1585
int app_is_active(struct stasis_app *app)
Checks whether an app is active.
int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all commands enqueued to this control.
Definition: control.c:1517
int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
Add a bridge subscription to an existing channel subscription.
void ast_frame_dtor(struct ast_frame *frame)
NULL-safe wrapper for ast_frfree, good for RAII_VAR.
Definition: main/frame.c:187
int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
Send StasisEnd message to the listening app.
Definition: res_stasis.c:1086
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void control_set_thread(struct stasis_app_control *control, pthread_t threadid)
set the control's thread id
Definition: control.c:196
static void cleanup(void)
Clean up any old apps that we don't need any more.
Definition: res_stasis.c:327
int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan)
Has this channel had a StasisEnd published on it?
Definition: res_stasis.c:1302
void control_move_cleanup(struct stasis_app_control *control)
Free any memory that was allocated for switching applications via /channels/{channelId}/move.
Definition: control.c:1724
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2432
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
Definition: pbx.c:4735
int control_next_app_args_size(struct stasis_app_control *control)
Returns the number of arguments to be passed to the application we are moving to. ...
Definition: control.c:1737
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application's name.
#define ast_debug(level,...)
Log a DEBUG message.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:670
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:378
Structure that contains information about a bridge.
Definition: bridge.h:349
void app_send(struct stasis_app *app, struct ast_json *message)
Send a message to an application.
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridge.c:1906
struct stasis_app_control * control_create(struct ast_channel *channel, struct stasis_app *app)
Create a control object.
Definition: control.c:129
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
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
#define MAX_WAIT_MS
Definition: res_stasis.c:77
void control_set_app(struct stasis_app_control *control, struct stasis_app *app)
Set the application the control object belongs to.
Definition: control.c:1713
void control_silence_stop_now(struct stasis_app_control *control)
Stop playing silence to a channel right now.
Definition: control.c:859
int control_is_done(struct stasis_app_control *control)
Returns true if control_continue() has been called on this control.
Definition: control.c:370
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
int app_unsubscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
Cancel the bridge subscription for an application.
struct ao2_container * apps_registry
Stasis application container.
Definition: res_stasis.c:100
Data structure associated with a single frame of data.
Abstract JSON element (object, array, string, int, ...).
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.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
int control_prestart_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all queued prestart commands.
Definition: control.c:1557
void control_wait(struct stasis_app_control *control)
Blocks until control's command queue has a command available.
Definition: control.c:1537
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
struct ao2_container* stasis_app_get_all ( void  )

Gets the names of all registered Stasis applications.

Returns
ast_str_container of container names.
Return values
NULLon error.

Definition at line 1715 of file res_stasis.c.

References ao2_callback, ast_str_container_alloc, and OBJ_NODATA.

Referenced by ast_ari_applications_list(), and stasis_app_set_global_debug().

1716 {
1717  struct ao2_container *apps;
1718 
1719  if (!apps_registry) {
1720  return NULL;
1721  }
1722 
1723  apps = ast_str_container_alloc(1);
1724  if (!apps) {
1725  return NULL;
1726  }
1727 
1728  ao2_callback(apps_registry, OBJ_NODATA, append_name, apps);
1729 
1730  return apps;
1731 }
Registered applications container.
Definition: pbx_app.c:67
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1693
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
Definition: strings.h:1365
struct ao2_container * apps_registry
Stasis application container.
Definition: res_stasis.c:100
Generic container type.
struct stasis_app* stasis_app_get_by_name ( const char *  name)

Retrieve a handle to a Stasis application by its name.

Parameters
nameThe name of the registered Stasis application
Returns
stasis_app on success.
Return values
NULLon error.

Definition at line 1701 of file res_stasis.c.

Referenced by ast_ari_applications_filter(), stasis_app_event_allowed(), stasis_app_get_debug_by_name(), stasis_app_set_debug_by_name(), and stasis_app_set_global_debug().

1702 {
1703  return find_app_by_name(name);
1704 }
struct stasis_message_sanitizer* stasis_app_get_sanitizer ( void  )

Get the Stasis message sanitizer for app_stasis applications.

Return values
Thestasis message sanitizer

Definition at line 2271 of file res_stasis.c.

References app_sanitizer.

Referenced by app_send_end_msg(), ast_ari_bridges_create(), ast_ari_bridges_create_with_id(), ast_ari_bridges_get(), ast_ari_bridges_list(), ast_ari_channels_list(), ast_ari_endpoints_get(), ast_ari_endpoints_list(), and ast_ari_endpoints_list_by_tech().

2272 {
2273  return &app_sanitizer;
2274 }
struct stasis_message_sanitizer app_sanitizer
Sanitization callbacks for communication to Stasis applications.
Definition: res_stasis.c:2265
struct ast_json* stasis_app_object_to_json ( struct stasis_app app)

Return the JSON representation of a Stasis application.

Since
16.3.0
Parameters
appThe application.
Returns
JSON representation of app with given name.
Return values
NULLon error.

Definition at line 1873 of file res_stasis.c.

References app_to_json(), and stasis_app_event_filter_to_json().

Referenced by ast_ari_applications_filter(), and stasis_app_to_json().

1874 {
1875  if (!app) {
1876  return NULL;
1877  }
1878 
1880  app, app_event_sources_to_json(app, app_to_json(app)));
1881 }
struct ast_json * stasis_app_event_filter_to_json(struct stasis_app *app, struct ast_json *json)
Convert and add the app's event type filter(s) to the given json object.
struct ast_json * app_to_json(const struct stasis_app *app)
Create a JSON representation of a stasis_app.
int stasis_app_register ( const char *  app_name,
stasis_app_cb  handler,
void *  data 
)

Register a new Stasis application.

If an application is already registered with the given name, the old application is sent a 'replaced' message and unregistered.

Parameters
app_nameName of this application.
handlerCallback for application messages.
dataData blob to pass to the callback. Must be AO2 managed.
Returns
0 for success
-1 for error.

Definition at line 1784 of file res_stasis.c.

Referenced by event_session_alloc().

1785 {
1786  return __stasis_app_register(app_name, handler, data, 0);
1787 }
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
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.

If an application is already registered with the given name, the old application is sent a 'replaced' message and unregistered.

Parameters
app_nameName of this application.
handlerCallback for application messages.
dataData blob to pass to the callback. Must be AO2 managed.
Returns
0 for success
-1 for error.

Definition at line 1789 of file res_stasis.c.

Referenced by event_session_alloc().

1790 {
1791  return __stasis_app_register(app_name, handler, data, 1);
1792 }
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
void stasis_app_register_event_source ( struct stasis_app_event_source obj)

Register an application event source.

Parameters
objthe event source to register

Definition at line 1823 of file res_stasis.c.

References AST_LIST_INSERT_TAIL, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by stasis_app_register_event_sources().

1824 {
1826  AST_LIST_INSERT_TAIL(&event_sources, obj, next);
1828 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
int stasis_app_send ( const char *  app_name,
struct ast_json message 
)

Send a message to the given Stasis application.

The message given to the handler is a borrowed copy. If you want to keep a reference to it, you should use ao2_ref() to keep it around.

Parameters
app_nameName of the application to invoke.
messageMessage to send (borrowed reference)
Returns
0 for success.
-1 for error.

Definition at line 1663 of file res_stasis.c.

References ao2_ref, app_send(), and OBJ_SEARCH_KEY.

1664 {
1665  struct stasis_app *app;
1666 
1667  if (!apps_registry) {
1668  return -1;
1669  }
1670 
1671  app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1672  if (!app) {
1673  /* XXX We can do a better job handling late binding, queueing up
1674  * the call for a few seconds to wait for the app to register.
1675  */
1676  ast_log(LOG_WARNING,
1677  "Stasis app '%s' not registered\n", app_name);
1678  return -1;
1679  }
1680  app_send(app, message);
1681  ao2_ref(app, -1);
1682 
1683  return 0;
1684 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void app_send(struct stasis_app *app, struct ast_json *message)
Send a message to an application.
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
struct ao2_container * apps_registry
Stasis application container.
Definition: res_stasis.c:100
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.

Parameters
app_nameName of the application to subscribe.
event_source_urisURIs for the event sources to subscribe to.
event_sources_countArray size of event_source_uris.
jsonOptional output pointer for JSON representation of the app after adding the subscription.
Returns
stasis_app_subscribe_res return code.
Note
Do not hold any channel locks if subscribing to a channel.

Definition at line 2052 of file res_stasis.c.

Referenced by ast_ari_applications_subscribe().

2055 {
2056  return app_handle_subscriptions(
2057  app_name, event_source_uris, event_sources_count,
2058  json, app_subscribe);
2059 }
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
enum stasis_app_subscribe_res stasis_app_subscribe_channel ( const char *  app_name,
struct ast_channel chan 
)

Directly subscribe an application to a channel.

Parameters
app_nameName of the application to subscribe.
chanThe channel to subscribe to
Returns
stasis_app_subscribe_res return code.
Note
This method can be used when you already hold a channel and its lock. This bypasses the channel lookup that would normally be performed by stasis_app_subscribe.

Definition at line 1991 of file res_stasis.c.

References ao2_ref, app_subscribe_channel(), and ast_debug.

Referenced by ast_ari_channels_create().

1993 {
1994  struct stasis_app *app = find_app_by_name(app_name);
1995  int res;
1996 
1997  if (!app) {
1998  return STASIS_ASR_APP_NOT_FOUND;
1999  }
2000 
2001  ast_debug(3, "%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan));
2002 
2003  res = app_subscribe_channel(app, chan);
2004  ao2_ref(app, -1);
2005 
2006  if (res != 0) {
2007  ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
2008  app_name, ast_channel_uniqueid(chan));
2009  return STASIS_ASR_INTERNAL_ERROR;
2010  }
2011 
2012  return STASIS_ASR_OK;
2013 }
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ast_debug(level,...)
Log a DEBUG message.
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
int app_subscribe_channel(struct stasis_app *app, struct ast_channel *chan)
Subscribes an application to a channel.
struct ast_json* stasis_app_to_json ( const char *  app_name)

Return the JSON representation of a Stasis application.

Parameters
app_nameName of the application.
Returns
JSON representation of app with given name.
Return values
NULLon error.

Definition at line 1883 of file res_stasis.c.

References stasis_app_object_to_json().

Referenced by ast_ari_applications_get().

1884 {
1885  struct stasis_app *app = find_app_by_name(app_name);
1886  struct ast_json *json = stasis_app_object_to_json(app);
1887 
1888  ao2_cleanup(app);
1889 
1890  return json;
1891 }
struct ast_json * stasis_app_object_to_json(struct stasis_app *app)
Return the JSON representation of a Stasis application.
Definition: res_stasis.c:1873
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
Abstract JSON element (object, array, string, int, ...).
void stasis_app_unregister ( const char *  app_name)

Unregister a Stasis application.

Parameters
app_nameName of the application to unregister.

Definition at line 1794 of file res_stasis.c.

References ao2_ref, app_deactivate(), cleanup(), and OBJ_SEARCH_KEY.

Referenced by event_session_shutdown().

1795 {
1796  struct stasis_app *app;
1797 
1798  if (!app_name) {
1799  return;
1800  }
1801 
1802  if (!apps_registry) {
1803  return;
1804  }
1805 
1806  app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1807  if (!app) {
1808  ast_log(LOG_ERROR,
1809  "Stasis app '%s' not registered\n", app_name);
1810  return;
1811  }
1812 
1813  app_deactivate(app);
1814 
1815  /* There's a decent chance that app is ready for cleanup. Go ahead
1816  * and clean up, just in case
1817  */
1818  cleanup();
1819 
1820  ao2_ref(app, -1);
1821 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
void app_deactivate(struct stasis_app *app)
Deactivates an application.
static void cleanup(void)
Clean up any old apps that we don't need any more.
Definition: res_stasis.c:327
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
struct ao2_container * apps_registry
Stasis application container.
Definition: res_stasis.c:100
void stasis_app_unregister_event_source ( struct stasis_app_event_source obj)

Unregister an application event source.

Parameters
objthe event source to unregister

Definition at line 1830 of file res_stasis.c.

References AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by stasis_app_unregister_event_sources().

1831 {
1832  struct stasis_app_event_source *source;
1833 
1835  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&event_sources, source, next) {
1836  if (source == obj) {
1837  AST_RWLIST_REMOVE_CURRENT(next);
1838  break;
1839  }
1840  }
1841  AST_RWLIST_TRAVERSE_SAFE_END;
1843 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
Event source information and callbacks.
Definition: stasis_app.h:174
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
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.

Parameters
app_nameName of the application to subscribe.
event_source_urisURIs for the event sources to subscribe to.
event_sources_countArray size of event_source_uris.
jsonOptional output pointer for JSON representation of the app after adding the subscription.
Returns
stasis_app_subscribe_res return code.

Definition at line 2093 of file res_stasis.c.

Referenced by ast_ari_applications_unsubscribe().

2096 {
2097  return app_handle_subscriptions(
2098  app_name, event_source_uris, event_sources_count,
2099  json, app_unsubscribe);
2100 }
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
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)

Parameters
app_nameName of the application to generate event for/to.
event_nameName of the Userevent.
source_urisURIs for the source objects to attach to event.
sources_countArray size of source_uris.
json_variablesevent blob variables.
Returns
stasis_app_user_event_res return code.

Definition at line 2102 of file res_stasis.c.

References ao2_ref, ast_app_get_topic(), ast_begins_with(), ast_bridge_get_snapshot_by_uniqueid(), ast_channel_snapshot_get_latest(), ast_endpoint_latest_snapshot(), ast_json_object_set(), ast_json_pack(), ast_json_ref(), ast_json_string_create(), ast_json_unref(), ast_manager_get_topic(), ast_multi_object_blob_add(), ast_multi_object_blob_create(), ast_multi_user_event_type(), RAII_VAR, stasis_message_create(), stasis_publish(), STASIS_UMOS_BRIDGE, STASIS_UMOS_CHANNEL, and STASIS_UMOS_ENDPOINT.

Referenced by ast_ari_events_user_event().

2106 {
2107  RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
2108  struct ast_json *blob = NULL;
2109  struct ast_multi_object_blob *multi;
2110  struct stasis_message *message;
2111  enum stasis_app_user_event_res res = STASIS_APP_USER_INTERNAL_ERROR;
2112  int have_channel = 0;
2113  int i;
2114 
2115  if (!app) {
2116  ast_log(LOG_WARNING, "App %s not found\n", app_name);
2117  return STASIS_APP_USER_APP_NOT_FOUND;
2118  }
2119 
2120  if (!ast_multi_user_event_type()) {
2121  return res;
2122  }
2123 
2124  if (json_variables) {
2125  struct ast_json *json_value = ast_json_string_create(event_name);
2126 
2127  if (json_value && !ast_json_object_set(json_variables, "eventname", json_value)) {
2128  blob = ast_json_ref(json_variables);
2129  }
2130  } else {
2131  blob = ast_json_pack("{s: s}", "eventname", event_name);
2132  }
2133 
2134  if (!blob) {
2135  ast_log(LOG_ERROR, "Failed to initialize blob\n");
2136 
2137  return res;
2138  }
2139 
2140  multi = ast_multi_object_blob_create(blob);
2141  ast_json_unref(blob);
2142  if (!multi) {
2143  ast_log(LOG_ERROR, "Failed to initialize multi\n");
2144 
2145  return res;
2146  }
2147 
2148  for (i = 0; i < sources_count; ++i) {
2149  const char *uri = source_uris[i];
2150  void *snapshot=NULL;
2152 
2153  if (ast_begins_with(uri, "channel:")) {
2154  type = STASIS_UMOS_CHANNEL;
2155  snapshot = ast_channel_snapshot_get_latest(uri + 8);
2156  have_channel = 1;
2157  } else if (ast_begins_with(uri, "bridge:")) {
2158  type = STASIS_UMOS_BRIDGE;
2159  snapshot = ast_bridge_get_snapshot_by_uniqueid(uri + 7);
2160  } else if (ast_begins_with(uri, "endpoint:")) {
2161  type = STASIS_UMOS_ENDPOINT;
2162  snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL);
2163  } else {
2164  ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
2165  ao2_ref(multi, -1);
2166 
2167  return STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME;
2168  }
2169  if (!snapshot) {
2170  ast_log(LOG_ERROR, "Unable to get snapshot for %s\n", uri);
2171  ao2_ref(multi, -1);
2172 
2173  return STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND;
2174  }
2175  ast_multi_object_blob_add(multi, type, snapshot);
2176  }
2177 
2179  ao2_ref(multi, -1);
2180 
2181  if (!message) {
2182  ast_log(LOG_ERROR, "Unable to create stasis user event message\n");
2183  return res;
2184  }
2185 
2186  /*
2187  * Publishing to two different topics is normally to be avoided -- except
2188  * in this case both are final destinations with no forwards (only listeners).
2189  * The message has to be delivered to the application topic for ARI, but a
2190  * copy is also delivered directly to the manager for AMI if there is a channel.
2191  */
2192  stasis_publish(ast_app_get_topic(app), message);
2193 
2194  if (have_channel) {
2196  }
2197  ao2_ref(message, -1);
2198 
2199  return STASIS_APP_USER_OK;
2200 }
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_multi_object_blob * ast_multi_object_blob_create(struct ast_json *blob)
Create a stasis multi object blob.
Definition: stasis.c:1975
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *uniqueid)
Returns the current snapshot for the bridge.
struct ast_endpoint_snapshot * ast_endpoint_latest_snapshot(const char *tech, const char *resource)
Retrieve the most recent snapshot for the endpoint with the given name.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
A multi object blob data structure to carry user event stasis messages.
Definition: stasis.c:1950
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
stasis_user_multi_object_snapshot_type
Object type code for multi user object snapshots.
Definition: stasis.h:1353
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1511
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1880
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
struct stasis_message_type * ast_multi_user_event_type(void)
Message type for custom user defined events with multi object blobs.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
stasis_app_user_event_res
Return code for stasis_app_user_event.
Definition: stasis_app.h:255
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition: strings.h:97
Abstract JSON element (object, array, string, int, ...).
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

Variable Documentation

struct stasis_message_sanitizer app_sanitizer
Initial value:
= {
.channel_id = channel_id_sanitizer,
.channel_snapshot = channel_snapshot_sanitizer,
.channel = channel_sanitizer,
}
static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
Sanitization callback for channel snapshots.
Definition: res_stasis.c:2234
static int channel_id_sanitizer(const char *id)
Sanitization callback for channel unique IDs.
Definition: res_stasis.c:2252
static int channel_sanitizer(const struct ast_channel *chan)
Sanitization callback for channels.
Definition: res_stasis.c:2243

Sanitization callbacks for communication to Stasis applications.

Definition at line 2265 of file res_stasis.c.

Referenced by stasis_app_get_sanitizer().

const struct ast_datastore_info masquerade_store_info
static
Initial value:
= {
.type = "stasis-masquerade",
.chan_fixup = channel_stolen_cb,
.chan_breakdown = channel_replaced_cb,
}

Definition at line 1208 of file res_stasis.c.

const struct ast_datastore_info replace_channel_store_info
static
Initial value:
= {
.type = "replace-channel-store",
.destroy = replace_channel_destroy,
}

Definition at line 888 of file res_stasis.c.

struct ast_datastore_info set_end_published_info
Initial value:
= {
.type = "stasis_end_published",
}

Definition at line 1286 of file res_stasis.c.

const struct ast_datastore_info stasis_internal_channel_info
static
Initial value:
= {
.type = "stasis-internal-channel",
}

Definition at line 2276 of file res_stasis.c.