Stasis: Allow internal channels directly into bridges
authorKinsey Moore <kmoore@digium.com>
Mon, 11 Aug 2014 18:38:15 +0000 (18:38 +0000)
committerKinsey Moore <kmoore@digium.com>
Mon, 11 Aug 2014 18:38:15 +0000 (18:38 +0000)
The patch to catch channels being shoehorned into Stasis() via external
mechanisms also happens to catch Announcer and Recorder channels
because they aren't known to be stasis-controlled channels in the usual
sense. This marks those channels as Stasis()-internal channels and
allows them directly into bridges.

Review: https://reviewboard.asterisk.org/r/3903/
........

Merged revisions 420795 from http://svn.asterisk.org/svn/asterisk/branches/12
........

Merged revisions 420796 from http://svn.asterisk.org/svn/asterisk/branches/13

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@420797 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/stasis_app.h
res/ari/resource_bridges.c
res/res_stasis.c
res/stasis/stasis_bridge.c

index e06e68e..5a7593d 100644 (file)
@@ -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 */
index 93ecd14..45fa09d 100644 (file)
@@ -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;
 }
 
 /*!
index 3480c9e..0ef3d6e 100644 (file)
@@ -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) {
index be7836d..9354281 100644 (file)
@@ -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,