diff options
-rw-r--r-- | include/asterisk/stasis_app.h | 30 | ||||
-rw-r--r-- | res/ari/resource_bridges.c | 12 | ||||
-rw-r--r-- | res/res_stasis.c | 68 | ||||
-rw-r--r-- | res/stasis/stasis_bridge.c | 2 |
4 files changed, 110 insertions, 2 deletions
diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h index e06e68ed2..5a7593d67 100644 --- a/include/asterisk/stasis_app.h +++ b/include/asterisk/stasis_app.h @@ -821,6 +821,36 @@ void stasis_app_channel_set_stasis_end_published(struct ast_channel *chan); */ int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan); +/*! + * \brief Is this channel internal to Stasis? + * + * \param chan The channel to check. + * + * \retval 0 No + * \retval 1 Yes + */ +int stasis_app_channel_is_internal(struct ast_channel *chan); + +/*! + * \brief Mark this unreal channel and it's other half as being internal to Stasis. + * + * \param chan The channel to mark. + * + * \retval zero Success + * \retval non-zero Failure + */ +int stasis_app_channel_unreal_set_internal(struct ast_channel *chan); + +/*! + * \brief Mark this channel as being internal to Stasis. + * + * \param chan The channel to mark. + * + * \retval zero Success + * \retval non-zero Failure + */ +int stasis_app_channel_set_internal(struct ast_channel *chan); + /*! @} */ #endif /* _ASTERISK_STASIS_APP_H */ diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index 93ecd14b7..45fa09d13 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -305,6 +305,7 @@ static void *bridge_channel_control_thread(void *data) static struct ast_channel *prepare_bridge_media_channel(const char *type) { RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup); + struct ast_channel *chan; cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!cap) { @@ -313,7 +314,16 @@ static struct ast_channel *prepare_bridge_media_channel(const char *type) ast_format_cap_append(cap, ast_format_slin, 0); - return ast_request(type, cap, NULL, NULL, "ARI", NULL); + chan = ast_request(type, cap, NULL, NULL, "ARI", NULL); + if (!chan) { + return NULL; + } + + if (stasis_app_channel_unreal_set_internal(chan)) { + ast_channel_cleanup(chan); + return NULL; + } + return chan; } /*! diff --git a/res/res_stasis.c b/res/res_stasis.c index 3480c9e23..0ef3d6e40 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -1901,6 +1901,74 @@ static void check_for_stasis_end(void *data, struct stasis_subscription *sub, remove_masquerade_store_by_name(snapshot->name); } +static const struct ast_datastore_info stasis_internal_channel_info = { + .type = "stasis-internal-channel", +}; + +static int set_internal_datastore(struct ast_channel *chan) +{ + struct ast_datastore *datastore; + + datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL); + if (!datastore) { + datastore = ast_datastore_alloc(&stasis_internal_channel_info, NULL); + if (!datastore) { + return -1; + } + ast_channel_datastore_add(chan, datastore); + } + return 0; +} + +int stasis_app_channel_unreal_set_internal(struct ast_channel *chan) +{ + struct ast_channel *outchan = NULL, *outowner = NULL; + int res = 0; + struct ast_unreal_pvt *unreal_pvt = ast_channel_tech_pvt(chan); + + ao2_ref(unreal_pvt, +1); + ast_unreal_lock_all(unreal_pvt, &outowner, &outchan); + if (outowner) { + res |= set_internal_datastore(outowner); + ast_channel_unlock(outowner); + ast_channel_unref(outowner); + } + if (outchan) { + res |= set_internal_datastore(outchan); + ast_channel_unlock(outchan); + ast_channel_unref(outchan); + } + ao2_unlock(unreal_pvt); + ao2_ref(unreal_pvt, -1); + return 0; +} + +int stasis_app_channel_set_internal(struct ast_channel *chan) +{ + int res; + + ast_channel_lock(chan); + res = set_internal_datastore(chan); + ast_channel_unlock(chan); + + return res; +} + +int stasis_app_channel_is_internal(struct ast_channel *chan) +{ + struct ast_datastore *datastore; + int res = 0; + + ast_channel_lock(chan); + datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL); + if (datastore) { + res = 1; + } + ast_channel_unlock(chan); + + return res; +} + static int load_module(void) { if (STASIS_MESSAGE_TYPE_INIT(ast_stasis_end_message_type) != 0) { diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c index be7836d35..93542812f 100644 --- a/res/stasis/stasis_bridge.c +++ b/res/stasis/stasis_bridge.c @@ -117,7 +117,7 @@ static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel { struct stasis_app_control *control = stasis_app_control_find_by_channel(bridge_channel->chan); - if (!control) { + if (!control && !stasis_app_channel_is_internal(bridge_channel->chan)) { /* channel not in Stasis(), get it there */ /* Attach after-bridge callback and pass ownership of swap_app to it */ if (ast_bridge_set_after_callback(bridge_channel->chan, |