60 #include "asterisk/stasis_channels.h"
61 #include "asterisk/stasis_bridges.h"
63 #include "asterisk/stasis_message_router.h"
77 #define MAX_WAIT_MS 200
83 #define APPS_NUM_BUCKETS 127
89 #define CONTROLS_NUM_BUCKETS 127
95 #define BRIDGES_NUM_BUCKETS 127
131 ast_log(LOG_ERROR,
"Failed to pack JSON for StasisEnd message\n");
139 .to_json = stasis_end_to_json);
159 "type",
"StasisStart",
164 ast_log(LOG_ERROR,
"Failed to pack JSON for StasisStart message\n");
174 ast_log(LOG_ERROR,
"Failed to append JSON for StasisStart message\n");
183 .to_json = stasis_start_to_json);
186 static int app_hash(
const void *obj,
const int flags)
212 const char *right_key = arg;
227 cmp = strncmp(
stasis_app_name(object_left), right_key, strlen(right_key));
274 const char *right_key = arg;
309 static int cleanup_cb(
void *obj,
void *arg,
int flags)
346 ast_channel_uniqueid(chan));
350 const char *channel_id)
382 const char *right_key = arg;
390 cmp = strcmp(object_left->
uniqueid, right_key);
397 cmp = strncmp(object_left->
uniqueid, right_key, strlen(right_key));
433 const char *right_key = arg;
438 right_key = object_right->bridge_id;
440 cmp = strcmp(object_left->bridge_id, right_key);
443 cmp = strncmp(object_left->bridge_id, right_key, strlen(right_key));
455 static void stasis_app_bridge_channel_wrapper_destructor(
void *obj)
473 key = wrapper->bridge_id;
483 static int bridges_channel_sort_fn(
const void *obj_left,
const void *obj_right,
const int flags)
487 const char *right_key = obj_right;
492 right_key = right->bridge_id;
495 cmp = strcmp(left->bridge_id, right_key);
498 cmp = strncmp(left->bridge_id, right_key, strlen(right_key));
522 chan =
ast_request(
"Announcer", cap, NULL, NULL,
"ARI_MOH", NULL);
596 new_wrapper = ao2_alloc_options(
sizeof(*new_wrapper),
619 ast_log(LOG_ERROR,
"Failed to create channel thread. Abandoning MOH channel creation.\n");
634 ao2_lock(app_bridges_moh);
637 chan = bridge_moh_create(bridge);
639 ao2_unlock(app_bridges_moh);
693 char *bridge_id = data;
698 static void playback_after_bridge_cb(
struct ast_channel *chan,
void *data)
700 char *bridge_id = data;
717 playback_after_bridge_cb, playback_after_bridge_cb_failed, bridge_id)) {
722 new_wrapper = ao2_alloc_options(
sizeof(*new_wrapper),
735 if (!
ao2_link(app_bridges_playback, new_wrapper)) {
765 if (!playback_wrapper) {
775 const char *bridge_id)
792 ao2_cleanup(control);
795 static struct ast_bridge *bridge_create_common(
const char *type,
const char *
name,
const char *
id,
int invisible)
798 char *requested_type, *requested_types =
ast_strdupa(
S_OR(type,
"mixing"));
799 int capabilities = 0;
804 int send_sdp_label = 0;
810 while ((requested_type = strsep(&requested_types,
","))) {
811 requested_type =
ast_strip(requested_type);
813 if (!strcmp(requested_type,
"mixing")) {
816 }
else if (!strcmp(requested_type,
"holding")) {
818 }
else if (!strcmp(requested_type,
"dtmf_events") ||
819 !strcmp(requested_type,
"proxy_media")) {
821 }
else if (!strcmp(requested_type,
"video_sfu")) {
823 }
else if (!strcmp(requested_type,
"video_single")) {
825 }
else if (!strcmp(requested_type,
"sdp_label")) {
843 bridge = bridge_stasis_new(capabilities, flags, name,
id, video_mode, send_sdp_label);
845 if (!
ao2_link(app_bridges, bridge)) {
856 return bridge_create_common(type, name,
id, 0);
861 return bridge_create_common(type, name,
id, 1);
879 static void replace_channel_destroy(
void *obj)
883 ao2_cleanup(replace->snapshot);
884 ast_free(replace->app);
889 .
type =
"replace-channel-store",
890 .destroy = replace_channel_destroy,
898 ast_channel_lock(chan);
900 if (!datastore && !no_create) {
901 datastore = ast_datastore_alloc(&replace_channel_store_info, NULL);
908 ast_channel_unlock(chan);
912 if (!datastore->
data) {
916 ret = datastore->
data;
917 ast_channel_unlock(chan);
942 ast_free(replace->app);
964 replace_channel_snapshot = replace->snapshot;
965 replace->snapshot = NULL;
967 return replace_channel_snapshot;
973 char *replace_channel_app;
979 replace_channel_app = replace->app;
982 return replace_channel_app;
985 static void start_message_blob_dtor(
void *obj)
1005 ast_log(LOG_ERROR,
"Error subscribing app '%s' to channel '%s'\n",
1010 payload = ao2_alloc(
sizeof(*payload), start_message_blob_dtor);
1012 ast_log(LOG_ERROR,
"Error packing JSON for StasisStart message\n");
1024 ast_log(LOG_ERROR,
"Error packing JSON for StasisStart message\n");
1028 payload->
blob = json_blob;
1033 ast_assert(json_args != NULL);
1034 for (i = 0; i < argc; ++i) {
1038 ast_log(LOG_ERROR,
"Error appending to StasisStart message\n");
1048 ast_log(LOG_ERROR,
"Error sending StasisStart message\n");
1052 if (replace_channel_snapshot) {
1061 int argc,
char *argv[])
1067 ast_assert(chan != NULL);
1069 replace_channel_snapshot = get_replace_channel_snapshot(chan);
1072 ast_channel_lock(chan);
1074 ast_channel_unlock(chan);
1076 ret = send_start_msg_snapshots(chan, app, argc, argv, snapshot, replace_channel_snapshot);
1079 ao2_cleanup(replace_channel_snapshot);
1084 static void remove_masquerade_store(
struct ast_channel *chan);
1092 if (sanitize && sanitize->
channel
1102 ast_log(LOG_ERROR,
"Error packing JSON for StasisEnd message\n");
1106 remove_masquerade_store(chan);
1118 static int masq_match_cb(
void *obj,
void *
data,
int flags)
1123 if (!strcmp(ast_channel_uniqueid(chan),
1148 ast_log(LOG_ERROR,
"Could not find control for masqueraded channel\n");
1157 remove_masquerade_store(old_chan);
1159 ao2_cleanup(control);
1175 if (!new_snapshot) {
1176 ast_log(LOG_ERROR,
"Could not get snapshot for masquerading channel\n");
1182 if (!old_snapshot) {
1183 ast_log(LOG_ERROR,
"Could not get snapshot for masqueraded channel\n");
1193 ast_log(LOG_ERROR,
"Could not find control for masquerading channel\n");
1200 send_start_msg_snapshots(new_chan,
control_app(control), 0, NULL, new_snapshot,
1205 ao2_cleanup(control);
1209 .
type =
"stasis-masquerade",
1210 .chan_fixup = channel_stolen_cb,
1211 .chan_breakdown = channel_replaced_cb,
1214 static int has_masquerade_store(
struct ast_channel *chan)
1220 static int add_masquerade_store(
struct ast_channel *chan)
1229 datastore = ast_datastore_alloc(&masquerade_store_info, NULL);
1239 static void remove_masquerade_store(
struct ast_channel *chan)
1263 ao2_unlock(control);
1267 if (command_count == 0 || ast_channel_fdno(chan) == -1) {
1268 control_mark_done(control);
1269 ao2_unlock(control);
1272 ao2_unlock(control);
1287 .
type =
"stasis_end_published",
1294 datastore = ast_datastore_alloc(&set_end_published_info, NULL);
1296 ast_channel_lock(chan);
1298 ast_channel_unlock(chan);
1306 ast_channel_lock(chan);
1308 ast_channel_unlock(chan);
1310 return datastore ? 1 : 0;
1313 static void remove_stasis_end_published(
struct ast_channel *chan)
1317 ast_channel_lock(chan);
1323 ast_channel_unlock(chan);
1336 ast_assert(chan != NULL);
1341 remove_stasis_end_published(chan);
1343 if (!apps_registry) {
1350 "Stasis app '%s' not registered\n", app_name);
1355 "Stasis app '%s' not active\n", app_name);
1361 ast_log(LOG_ERROR,
"Control allocation failed or Stasis app '%s' not registered\n", app_name);
1366 ast_log(LOG_ERROR,
"Stasis app '%s' not registered\n", app_name);
1371 ast_log(LOG_ERROR,
"Stasis app '%s' not active\n", app_name);
1376 if (add_masquerade_store(chan)) {
1377 ast_log(LOG_ERROR,
"Failed to attach masquerade detector\n");
1381 res = send_start_msg(
control_app(control), chan, argc, argv);
1384 "Error sending start message to '%s'\n", app_name);
1385 remove_masquerade_store(chan);
1399 if (ast_check_hangup_locked(chan)) {
1400 control_mark_done(control);
1421 control_mark_done(control);
1426 remove_stasis_end_published(chan);
1440 if (add_masquerade_store(chan)) {
1441 ast_log(LOG_ERROR,
"Failed to attach masquerade detector\n");
1443 control_mark_done(control);
1454 res = send_start_msg(
control_app(control), chan, next_argc, next_argv);
1458 for (idx = 0; idx < next_argc; idx++) {
1459 ast_free(next_argv[idx]);
1461 ast_free(next_argv);
1467 remove_masquerade_store(chan);
1468 control_mark_done(control);
1481 ast_log(LOG_ERROR,
"Could not move to Stasis app '%s' - not registered\n",
1484 ast_log(LOG_ERROR,
"Could not move to Stasis app '%s' - not active\n",
1490 ast_log(LOG_ERROR,
"Could not get channel shapshot for '%s'\n",
1491 ast_channel_name(chan));
1498 "type",
"ApplicationMoveFailed",
1504 ast_log(LOG_ERROR,
"Failed to pack JSON for ApplicationMoveFailed message\n");
1508 ast_log(LOG_ERROR,
"Could not get args json array");
1512 for (idx = 0; idx < next_argc; ++idx) {
1516 ast_log(LOG_ERROR,
"Error appending to ApplicationMoveFailed message\n");
1529 ao2_cleanup(next_app);
1532 last_bridge = bridge;
1535 if (bridge != last_bridge) {
1559 ast_channel_uniqueid(chan));
1560 control_mark_done(control);
1566 if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1579 ast_debug(3,
"%s: Hangup (no more frames)\n",
1580 ast_channel_uniqueid(chan));
1581 control_mark_done(control);
1589 ast_channel_uniqueid(chan));
1590 control_mark_done(control);
1596 ast_channel_lock(chan);
1597 needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1598 ast_channel_unlock(chan);
1606 ao2_cleanup(bridge);
1619 remove_stasis_end_published(chan);
1638 if (!res && !ast_channel_pbx(chan)) {
1645 ast_channel_lock(chan);
1648 ast_channel_unlock(chan);
1653 memset(&pbx_args, 0,
sizeof(pbx_args));
1667 if (!apps_registry) {
1676 ast_log(LOG_WARNING,
1677 "Stasis app '%s' not registered\n", app_name);
1690 if (!apps_registry) {
1694 if (!ast_strlen_zero(app_name)) {
1703 return find_app_by_name(name);
1706 static int append_name(
void *obj,
void *arg,
int flags)
1719 if (!apps_registry) {
1737 if (!apps_registry) {
1741 ao2_lock(apps_registry);
1748 ao2_unlock(apps_registry);
1756 ao2_unlock(apps_registry);
1775 ao2_unlock(apps_registry);
1786 return __stasis_app_register(app_name, handler, data, 0);
1791 return __stasis_app_register(app_name, handler, data, 1);
1802 if (!apps_registry) {
1809 "Stasis app '%s' not registered\n", app_name);
1835 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&
event_sources, source, next) {
1836 if (source == obj) {
1837 AST_RWLIST_REMOVE_CURRENT(next);
1841 AST_RWLIST_TRAVERSE_SAFE_END;
1857 static struct ast_json *app_event_sources_to_json(
1880 app, app_event_sources_to_json(app,
app_to_json(app)));
1885 struct stasis_app *app = find_app_by_name(app_name);
1947 const char *app_name,
const char **event_source_uris,
1948 int event_sources_count,
struct ast_json **json,
1949 app_subscription_handler handler)
1951 struct stasis_app *app = find_app_by_name(app_name);
1954 ast_assert(handler != NULL);
1957 return STASIS_ASR_APP_NOT_FOUND;
1960 for (i = 0; i < event_sources_count; ++i) {
1961 const char *uri = event_source_uris[i];
1965 event_source = app_event_source_find(uri);
1966 if (!event_source) {
1967 ast_log(LOG_WARNING,
"Invalid scheme: %s\n", uri);
1970 return STASIS_ASR_EVENT_SOURCE_BAD_SCHEME;
1973 res = handler(app, uri, event_source);
1974 if (res != STASIS_ASR_OK) {
1982 ast_debug(3,
"%s: Successful; setting results\n", app_name);
1988 return STASIS_ASR_OK;
1994 struct stasis_app *app = find_app_by_name(app_name);
1998 return STASIS_ASR_APP_NOT_FOUND;
2001 ast_debug(3,
"%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan));
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;
2012 return STASIS_ASR_OK;
2031 RAII_VAR(
void *, obj, NULL, ao2_cleanup);
2033 ast_debug(3,
"%s: Checking %s\n", app_name, uri);
2035 if (!ast_strlen_zero(uri + strlen(event_source->
scheme)) &&
2036 (!event_source->
find || (!(obj = event_source->
find(app, uri + strlen(event_source->
scheme)))))) {
2037 ast_log(LOG_WARNING,
"Event source not found: %s\n", uri);
2038 return STASIS_ASR_EVENT_SOURCE_NOT_FOUND;
2041 ast_debug(3,
"%s: Subscribing to %s\n", app_name, uri);
2044 ast_log(LOG_WARNING,
"Error subscribing app '%s' to '%s'\n",
2046 return STASIS_ASR_INTERNAL_ERROR;
2049 return STASIS_ASR_OK;
2053 const char **event_source_uris,
int event_sources_count,
2056 return app_handle_subscriptions(
2057 app_name, event_source_uris, event_sources_count,
2058 json, app_subscribe);
2076 const char *
id = uri + strlen(event_source->
scheme);
2080 return STASIS_ASR_EVENT_SOURCE_NOT_FOUND;
2083 ast_debug(3,
"%s: Unsubscribing from %s\n", app_name, uri);
2086 ast_log(LOG_WARNING,
"Error unsubscribing app '%s' to '%s'\n",
2094 const char **event_source_uris,
int event_sources_count,
2097 return app_handle_subscriptions(
2098 app_name, event_source_uris, event_sources_count,
2099 json, app_unsubscribe);
2103 const char *event_name,
2104 const char **source_uris,
int sources_count,
2112 int have_channel = 0;
2116 ast_log(LOG_WARNING,
"App %s not found\n", app_name);
2117 return STASIS_APP_USER_APP_NOT_FOUND;
2124 if (json_variables) {
2135 ast_log(LOG_ERROR,
"Failed to initialize blob\n");
2143 ast_log(LOG_ERROR,
"Failed to initialize multi\n");
2148 for (i = 0; i < sources_count; ++i) {
2149 const char *uri = source_uris[i];
2150 void *snapshot=NULL;
2164 ast_log(LOG_WARNING,
"Invalid scheme: %s\n", uri);
2167 return STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME;
2170 ast_log(LOG_ERROR,
"Unable to get snapshot for %s\n", uri);
2173 return STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND;
2182 ast_log(LOG_ERROR,
"Unable to create stasis user event message\n");
2199 return STASIS_APP_USER_OK;
2202 static int unload_module(
void)
2212 ao2_cleanup(apps_registry);
2213 apps_registry = NULL;
2215 ao2_cleanup(app_controls);
2216 app_controls = NULL;
2218 ao2_cleanup(app_bridges);
2221 ao2_cleanup(app_bridges_moh);
2222 app_bridges_moh = NULL;
2224 ao2_cleanup(app_bridges_playback);
2225 app_bridges_playback = NULL;
2259 ao2_cleanup(snapshot);
2277 .
type =
"stasis-internal-channel",
2280 static int set_internal_datastore(
struct ast_channel *chan)
2286 datastore = ast_datastore_alloc(&stasis_internal_channel_info, NULL);
2297 struct ast_channel *outchan = NULL, *outowner = NULL;
2304 res |= set_internal_datastore(outowner);
2305 ast_channel_unlock(outowner);
2309 res |= set_internal_datastore(outchan);
2310 ast_channel_unlock(outchan);
2313 ao2_unlock(unreal_pvt);
2322 ast_channel_lock(chan);
2323 res = set_internal_datastore(chan);
2324 ast_channel_unlock(chan);
2334 ast_channel_lock(chan);
2339 ast_channel_unlock(chan);
2344 static int load_module(
void)
2364 if (!apps_registry || !app_controls || !app_bridges || !app_bridges_moh || !app_bridges_playback) {
2374 bridge_stasis_init();
2381 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"Stasis application support",
2383 .support_level = AST_MODULE_SUPPORT_CORE,
2384 .load = load_module,
2385 .unload = unload_module,
static int bridges_channel_hash_fn(const void *obj, const int flags)
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
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.
Options for ast_pbx_run()
char * control_next_app(struct stasis_app_control *control)
Returns the name of the application we are moving to.
Main Channel structure associated with a channel.
int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
Register a new Stasis application.
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.
struct ast_json * stasis_app_object_to_json(struct stasis_app *app)
Return the JSON representation of a Stasis application.
struct ast_channel_snapshot * replace_channel
char ** control_next_app_args(struct stasis_app_control *control)
Returns the list of arguments to pass to the application we are moving to.
static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
Sanitization callback for channel snapshots.
struct ast_channel_snapshot_base * base
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Asterisk main include file. File version handling, generic pbx functions.
int stasis_app_send(const char *app_name, struct ast_json *message)
Send a message to the given Stasis application.
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.
const ast_string_field uniqueid
struct ast_bridge * stasis_app_bridge_create(const char *type, const char *name, const char *id)
Create a bridge of the specified type.
struct ast_multi_object_blob * ast_multi_object_blob_create(struct ast_json *blob)
Create a stasis multi object blob.
void stasis_app_register_event_sources(void)
Register core event sources.
ast_bridge_video_mode_type
Video source modes.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
static int bridges_channel_compare(void *obj, void *arg, int flags)
static int app_compare(void *obj, void *arg, int flags)
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.
String manipulation functions.
void *(* find)(const struct stasis_app *app, const char *id)
Find an event source data object by the given id/name.
An application must manually subscribe to each resource that it cares about. This is the default appr...
int stasis_app_control_is_done(struct stasis_app_control *control)
Check if a control is marked as done.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
#define ast_channel_unref(c)
Decrease channel reference count.
Registered applications container.
The arg parameter is a search key, but is not an object.
int(* channel_snapshot)(const struct ast_channel_snapshot *snapshot)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
static int bridges_compare(void *obj, void *arg, int flags)
int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, char *argv[])
Stasis dialplan application callback.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *uniqueid)
Returns the current snapshot for the bridge.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
struct ast_channel_snapshot * snapshot
const char * scheme
The scheme to match against on [un]subscribes.
int(* channel_id)(const char *channel_id)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
static int control_compare(void *obj, void *arg, int flags)
#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.
static int channel_id_sanitizer(const char *id)
Sanitization callback for channel unique IDs.
int messaging_cleanup(void)
Tidy up the messaging layer.
struct ast_channel * stasis_app_bridge_playback_channel_find(struct ast_bridge *bridge)
Finds an existing ARI playback channel in a bridge.
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.
struct ast_endpoint_snapshot * ast_endpoint_latest_snapshot(const char *tech, const char *resource)
Retrieve the most recent snapshot for the endpoint with the given name.
enum stasis_app_user_event_res stasis_app_user_event(const char *app_name, const char *event_name, const char **source_uris, int sources_count, struct ast_json *json_variables)
Generate a Userevent for stasis app (echo to AMI)
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
void control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
const ast_string_field name
enum stasis_app_subscribe_res stasis_app_subscribe_channel(const char *app_name, struct ast_channel *chan)
Directly subscribe an application to a channel.
#define APPS_NUM_BUCKETS
Number of buckets for the Stasis application hash table. Remember to keep it a prime number! ...
void app_deactivate(struct stasis_app *app)
Deactivates an application.
Structure representing a snapshot of channel state.
struct ast_json * stasis_app_to_json(const char *app_name)
Return the JSON representation of a Stasis application.
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
int stasis_app_channel_is_internal(struct ast_channel *chan)
Is this channel internal to Stasis?
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Assume that the ao2_container is already locked.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Structure for a data store type.
int app_unsubscribe_channel(struct stasis_app *app, struct ast_channel *chan)
Cancel the subscription an app has for a channel.
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
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.
const ast_string_field uniqueid
void app_shutdown(struct stasis_app *app)
Tears down an application.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
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.
#define ast_strdup(str)
A wrapper for strdup()
Structure for a data store object.
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.
#define BRIDGES_NUM_BUCKETS
Number of buckets for the Stasis bridges hash table. Remember to keep it a prime number! ...
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
int control_command_count(struct stasis_app_control *control)
Returns the count of items in a control's command queue.
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
struct stasis_app * control_app(struct stasis_app_control *control)
Returns the pointer (non-reffed) to the app associated with this control.
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.
int app_is_active(struct stasis_app *app)
Checks whether an app is active.
Structure containing callbacks for Stasis message sanitization.
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate...
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
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.
struct stasis_app * stasis_app_get_by_name(const char *name)
Retrieve a handle to a Stasis application by its name.
int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all commands enqueued to this control.
int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
Add a bridge subscription to an existing channel subscription.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Blob of data associated with a channel.
static int control_hash(const void *obj, const int flags)
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.
void ast_frame_dtor(struct ast_frame *frame)
NULL-safe wrapper for ast_frfree, good for RAII_VAR.
int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
Send StasisEnd message to the listening app.
ast_bridge_after_cb_reason
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
void control_set_thread(struct stasis_app_control *control, pthread_t threadid)
set the control's thread id
void(* to_json)(const struct stasis_app *app, struct ast_json *json)
Convert event source data to json.
static void cleanup(void)
Clean up any old apps that we don't need any more.
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan)
Has this channel had a StasisEnd published on it?
void control_move_cleanup(struct stasis_app_control *control)
Free any memory that was allocated for switching applications via /channels/{channelId}/move.
int(* unsubscribe)(struct stasis_app *app, const char *id)
Cancel the subscription an app has to an event source.
An application is automatically subscribed to all resources in Asterisk, even if it does not control ...
A multi object blob data structure to carry user event stasis messages.
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
struct stasis_app * app_create(const char *name, stasis_app_cb handler, void *data, enum stasis_app_subscription_model subscription_model)
Create a res_stasis application.
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Event source information and callbacks.
struct ao2_container * stasis_app_get_all(void)
Gets the names of all registered Stasis applications.
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
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. ...
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
void stasis_app_control_shutdown(void)
Let Stasis app internals shut down.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
#define AST_STRING_FIELD(name)
Declare a string field.
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application's name.
int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
Push the semi2 unreal channel into a bridge from either member of the unreal pair.
stasis_user_multi_object_snapshot_type
Object type code for multi user object snapshots.
int(* channel)(const struct ast_channel *chan)
Callback which determines whether a channel should be sanitized from a message based on the channel...
int app_unsubscribe_channel_id(struct stasis_app *app, const char *channel_id)
Cancel the subscription an app has for a channel.
#define ast_debug(level,...)
Log a DEBUG message.
void stasis_app_register_event_source(struct stasis_app_event_source *obj)
Register an application event source.
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.
Internal API for the Stasis application controller.
int app_is_finished(struct stasis_app *app)
Checks whether a deactivated app has no channels.
Structure to describe a channel "technology", ie a channel driver See for examples: ...
int messaging_init(void)
Initialize the messaging layer.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
#define CONTROLS_NUM_BUCKETS
Number of buckets for the Stasis application hash table. Remember to keep it a prime number! ...
Structure that contains information about a bridge.
struct stasis_message_sanitizer app_sanitizer
Sanitization callbacks for communication to Stasis applications.
Backend API for implementing components of res_stasis.
void app_send(struct stasis_app *app, struct ast_json *message)
Send a message to an application.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
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.
const char * stasis_app_control_get_channel_id(const struct stasis_app_control *control)
Returns the uniqueid of the channel associated with this control.
void stasis_app_channel_set_stasis_end_published(struct ast_channel *chan)
Indicate that this channel has had a StasisEnd published for it.
#define ao2_unlink(container, obj)
Remove an object from a container.
Internal API for the Stasis bridge subclass.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
struct stasis_app_control * stasis_app_control_find_by_channel_id(const char *channel_id)
Returns the handler for the channel with the given id.
struct ast_bridge * stasis_app_bridge_find_by_id(const char *bridge_id)
Returns the bridge with the given id.
void stasis_app_unregister(const char *app_name)
Unregister a Stasis application.
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
The base pvt structure for local channel derivatives.
struct stasis_app_control * control_create(struct ast_channel *channel, struct stasis_app *app)
Create a control object.
const char * app_name(struct ast_app *app)
struct stasis_message * ast_channel_blob_create(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Creates a ast_channel_blob message.
struct ast_bridge * bridge
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
#define STASIS_BRIDGE_MIXING_CAPABILITIES
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.
#define ast_calloc(num, len)
A wrapper for calloc()
void stasis_app_control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
int stasis_app_channel_set_internal(struct ast_channel *chan)
Mark this channel as being internal to Stasis.
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...
Module has failed to load, may be in an inconsistent state.
stasis_app_subscribe_res
Return code for stasis_app_[un]subscribe.
void control_set_app(struct stasis_app_control *control, struct stasis_app *app)
Set the application the control object belongs to.
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
void(* stasis_app_cb)(void *data, const char *app_name, struct ast_json *message)
Callback for Stasis application handler.
void stasis_app_bridge_destroy(const char *bridge_id)
Destroy the bridge.
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.
void control_silence_stop_now(struct stasis_app_control *control)
Stop playing silence to a channel right now.
struct stasis_message_type * ast_multi_user_event_type(void)
Message type for custom user defined events with multi object blobs.
int control_is_done(struct stasis_app_control *control)
Returns true if control_continue() has been called on this control.
struct ast_channel_snapshot * channel
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.
STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_sync_message_type)
A message type used to synchronize with the CDR topic.
The arg parameter is an object of the same type.
struct stasis_app_control * stasis_app_control_find_by_channel(const struct ast_channel *chan)
Returns the handler for the given channel.
struct ast_json * app_to_json(const struct stasis_app *app)
Create a JSON representation of a stasis_app.
After Bridge Execution API.
int stasis_app_bridge_playback_channel_add(struct ast_bridge *bridge, struct ast_channel *chan, struct stasis_app_control *control)
Adds a channel to the list of ARI playback channels for bridges.
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
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.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
int app_unsubscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
Cancel the bridge subscription for an application.
Internal API for the Stasis application controller.
struct ao2_container * apps_registry
Stasis application container.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
void app_update(struct stasis_app *app, stasis_app_cb handler, void *data)
Update the handler and data for a res_stasis application.
static int app_hash(const void *obj, const int flags)
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.
Stasis out-of-call text message support.
Data structure associated with a single frame of data.
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Internal Asterisk hangup causes.
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Abstract JSON element (object, array, string, int, ...).
int app_subscribe_channel(struct stasis_app *app, struct ast_channel *chan)
Subscribes an application to a channel.
static int bridges_hash(const void *obj, const int flags)
Reject objects with duplicate keys in container.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
static void remove_bridge_playback(char *bridge_id)
static struct ast_channel * prepare_bridge_moh_channel(void)
Search option field mask.
void stasis_app_unregister_event_sources(void)
Unregister core event sources.
struct ast_json * ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_channel_snapshot.
int(* is_subscribed)(struct stasis_app *app, const char *id)
Find an event source by the given id/name.
#define ASTERISK_GPL_KEY
The text the key() function should return.
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Asterisk module definitions.
unsigned int no_hangup_chan
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
void stasis_app_unregister_event_source(struct stasis_app_event_source *obj)
Unregister an application event source.
char * app_get_replace_channel_app(struct ast_channel *chan)
Get the app that the replacement channel will be controlled by.
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
int(* subscribe)(struct stasis_app *app, void *obj)
Subscribe an application to an event source.
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
int control_prestart_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all queued prestart commands.
static void * moh_channel_thread(void *data)
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.
static int channel_sanitizer(const struct ast_channel *chan)
Sanitization callback for channels.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
void control_wait(struct stasis_app_control *control)
Blocks until control's command queue has a command available.
#define ao2_link(container, obj)
Add an object to a container.
Unreal channel derivative framework.
struct ast_bridge * stasis_app_bridge_create_invisible(const char *type, const char *name, const char *id)
Create an invisible bridge of the specified type.