]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Stasis: Allow internal channels directly into bridges
authorKinsey Moore <kmoore@digium.com>
Mon, 11 Aug 2014 18:35:27 +0000 (18:35 +0000)
committerKinsey Moore <kmoore@digium.com>
Mon, 11 Aug 2014 18:35:27 +0000 (18:35 +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/

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/12@420795 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 e06e68ed266db1734e2d8db6c92765ec74947bb0..5a7593d67781af506a0e77773f6b704639486028 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 eeb4237d0b31b54a897824ea2ac68ea10e40be87..7691ec83465799c9fb1627c33386e7fed62b20bb 100644 (file)
@@ -305,6 +305,7 @@ static struct ast_channel *prepare_bridge_media_channel(const char *type)
 {
        RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
        struct ast_format format;
+       struct ast_channel *chan;
 
        cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
        if (!cap) {
@@ -317,7 +318,16 @@ static struct ast_channel *prepare_bridge_media_channel(const char *type)
                return NULL;
        }
 
-       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 fd56a97c350753bb4361f79e3e9f271e8dd9d997..80c29e0090fba1a31c90c130a0b8d901482fe253 100644 (file)
@@ -1897,6 +1897,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 be7836d35c284b00beea5c287a0be49770b7789d..93542812f321993d5dfa8fc8328963b329588588 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,