Author: dlee
Date: Wed Jul 31 15:35:34 2013
New Revision: 395901

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395901
Log:
Cleanup

Removed:
    team/dlee/ari-async-bridge/res/res_stasis_bridge.c
    team/dlee/ari-async-bridge/res/res_stasis_bridge_add.exports.in
Modified:
    team/dlee/ari-async-bridge/include/asterisk/stasis_app_impl.h
    team/dlee/ari-async-bridge/res/ari/resource_bridges.c
    team/dlee/ari-async-bridge/res/res_stasis.c
    team/dlee/ari-async-bridge/res/res_stasis_playback.c
    team/dlee/ari-async-bridge/res/stasis/control.c
    team/dlee/ari-async-bridge/res/stasis/control.h

Modified: team/dlee/ari-async-bridge/include/asterisk/stasis_app_impl.h
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/include/asterisk/stasis_app_impl.h?view=diff&rev=395901&r1=395900&r2=395901
==============================================================================
--- team/dlee/ari-async-bridge/include/asterisk/stasis_app_impl.h (original)
+++ team/dlee/ari-async-bridge/include/asterisk/stasis_app_impl.h Wed Jul 31 
15:35:34 2013
@@ -95,23 +95,4 @@
  */
 struct ast_bridge *stasis_app_get_bridge(struct stasis_app_control *control);
 
-
-/*!
- * \since 12
- * \brief Imparts the associated channel into the bridge.
- *
- * \param control Control object for the channel to query.
- * \param bridge New bridge to set on the control object.
- */
-void stasis_app_add_to_bridge(struct stasis_app_control *control,
-       struct ast_bridge *bridge);
-
-/*!
- * \since 12
- * \brief Departs the associated channel from its bridge.
- *
- * \param control Control object for the channel to query.
- */
-void stasis_app_remove_from_bridge(struct stasis_app_control *control);
-
 #endif /* _ASTERISK_RES_STASIS_H */

Modified: team/dlee/ari-async-bridge/res/ari/resource_bridges.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/res/ari/resource_bridges.c?view=diff&rev=395901&r1=395900&r2=395901
==============================================================================
--- team/dlee/ari-async-bridge/res/ari/resource_bridges.c (original)
+++ team/dlee/ari-async-bridge/res/ari/resource_bridges.c Wed Jul 31 15:35:34 
2013
@@ -137,6 +137,10 @@
                return;
        }
 
+       /* BUGBUG this should make sure the bridge requested for removal is 
actually
+        * the bridge the channel is in. This will be possible once the bridge 
uniqueid
+        * is added to the channel snapshot. A 409 response should be issued if 
the bridge
+        * uniqueids don't match */
        stasis_app_control_remove_channel_from_bridge(control, bridge);
 
        ast_ari_response_no_content(response);

Modified: team/dlee/ari-async-bridge/res/res_stasis.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/res/res_stasis.c?view=diff&rev=395901&r1=395900&r2=395901
==============================================================================
--- team/dlee/ari-async-bridge/res/res_stasis.c (original)
+++ team/dlee/ari-async-bridge/res/res_stasis.c Wed Jul 31 15:35:34 2013
@@ -620,7 +620,6 @@
                        /* Timeout */
                        continue;
                }
-
 
                f = ast_read(chan);
                if (!f) {

Modified: team/dlee/ari-async-bridge/res/res_stasis_playback.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/res/res_stasis_playback.c?view=diff&rev=395901&r1=395900&r2=395901
==============================================================================
--- team/dlee/ari-async-bridge/res/res_stasis_playback.c (original)
+++ team/dlee/ari-async-bridge/res/res_stasis_playback.c Wed Jul 31 15:35:34 
2013
@@ -85,6 +85,40 @@
        enum stasis_app_playback_state state;
 };
 
+static void playback_dtor(void *obj)
+{
+       struct stasis_app_playback *playback = obj;
+
+       ast_string_field_free_memory(playback);
+       ast_cond_destroy(&playback->done_cond);
+}
+
+static struct stasis_app_playback *playback_create(
+       struct stasis_app_control *control)
+{
+       RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
+       char id[AST_UUID_STR_LEN];
+       int res;
+
+       playback = ao2_alloc(sizeof(*playback), playback_dtor);
+       if (!playback || ast_string_field_init(playback, 128)) {
+               return NULL;
+       }
+
+       res = ast_cond_init(&playback->done_cond, NULL);
+       if (res != 0) {
+               ast_log(LOG_ERROR, "Error creating done condition: %s\n",
+                       strerror(errno));
+               return NULL;
+       }
+
+       ast_uuid_generate_str(id, sizeof(id));
+       ast_string_field_set(playback, id, id);
+
+       ao2_ref(playback, +1);
+       return playback;
+}
+
 static int playback_hash(const void *obj, int flags)
 {
        const struct stasis_app_playback *playback = obj;
@@ -150,12 +184,6 @@
        stasis_app_control_publish(playback->control, message);
 }
 
-static void playback_cleanup(struct stasis_app_playback *playback)
-{
-       ao2_unlink_flags(playbacks, playback,
-               OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
-}
-
 static int playback_first_update(struct stasis_app_playback *playback,
        const char *uniqueid)
 {
@@ -197,6 +225,9 @@
        playback_publish(playback);
 }
 
+/*!
+ * \brief RAII_VAR function to mark a playback as done when leaving scope.
+ */
 static void mark_as_done(struct stasis_app_playback *playback)
 {
        SCOPED_AO2LOCK(lock, playback);
@@ -269,6 +300,12 @@
        return;
 }
 
+/*!
+ * \brief Special case code to play while a channel is in a bridge.
+ *
+ * \param bridge_channel The channel's bridge_channel.
+ * \param playback_id Id of the playback to start.
+ */
 static void play_on_channel_in_bridge(struct ast_bridge_channel 
*bridge_channel,
        const char *playback_id)
 {
@@ -284,11 +321,21 @@
        play_on_channel(playback, bridge_channel->chan);
 }
 
+/*!
+ * \brief \ref RAII_VAR function to remove a playback from the global list when
+ * leaving scope.
+ */
+static void remove_from_playbacks(struct stasis_app_playback *playback)
+{
+       ao2_unlink_flags(playbacks, playback,
+               OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
+}
+
 static void *play_uri(struct stasis_app_control *control,
        struct ast_channel *chan, void *data)
 {
        RAII_VAR(struct stasis_app_playback *, playback, NULL,
-               playback_cleanup);
+               remove_from_playbacks);
        struct ast_bridge *bridge;
        int res;
 
@@ -301,6 +348,8 @@
        bridge = stasis_app_get_bridge(control);
        if (bridge) {
                struct ast_bridge_channel *bridge_chan;
+
+               /* Queue up playback on the bridge */
                ast_bridge_lock(bridge);
                bridge_chan = bridge_find_channel(bridge, chan);
                if (bridge_chan) {
@@ -312,6 +361,7 @@
                }
                ast_bridge_unlock(bridge);
 
+               /* Wait for playback to complete */
                ao2_lock(playback);
                while (!playback->done) {
                        res = ast_cond_wait(&playback->done_cond,
@@ -330,13 +380,6 @@
        return NULL;
 }
 
-static void playback_dtor(void *obj)
-{
-       struct stasis_app_playback *playback = obj;
-
-       ast_string_field_free_memory(playback);
-}
-
 static void set_target_uri(
        struct stasis_app_playback *playback,
        enum stasis_app_playback_target_type target_type,
@@ -364,8 +407,6 @@
        int skipms, long offsetms)
 {
        RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
-       char id[AST_UUID_STR_LEN];
-       int res;
 
        if (skipms < 0 || offsetms < 0) {
                return NULL;
@@ -374,28 +415,15 @@
        ast_debug(3, "%s: Sending play(%s) command\n",
                stasis_app_control_get_channel_id(control), uri);
 
-       playback = ao2_alloc(sizeof(*playback), playback_dtor);
-       if (!playback || ast_string_field_init(playback, 128)) {
-               return NULL;
-       }
-
-       res = ast_cond_init(&playback->done_cond, NULL);
-       if (res != 0) {
-               ast_log(LOG_ERROR, "Error creating done condition: %s\n",
-                       strerror(errno));
-               return NULL;
-       }
+       playback = playback_create(control);
 
        if (skipms == 0) {
                skipms = PLAYBACK_DEFAULT_SKIPMS;
        }
 
-       ast_uuid_generate_str(id, sizeof(id));
-       ast_string_field_set(playback, id, id);
        ast_string_field_set(playback, media, uri);
        ast_string_field_set(playback, language, language);
        set_target_uri(playback, target_type, target_id);
-       playback->control = control;
        playback->skipms = skipms;
        playback->offsetms = offsetms;
        ao2_link(playbacks, playback);

Modified: team/dlee/ari-async-bridge/res/stasis/control.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/res/stasis/control.c?view=diff&rev=395901&r1=395900&r2=395901
==============================================================================
--- team/dlee/ari-async-bridge/res/stasis/control.c (original)
+++ team/dlee/ari-async-bridge/res/stasis/control.c Wed Jul 31 15:35:34 2013
@@ -123,7 +123,6 @@
                return NULL;
        }
 
-       /* command_queue is a thread safe list; no lock needed */
        ao2_lock(control->command_queue);
        ao2_link_flags(control->command_queue, command, OBJ_NOLOCK);
        ast_cond_signal(&control->wait_cond);
@@ -226,7 +225,9 @@
 
        ast_assert(control->channel != NULL);
 
-       if (control->bridge) {
+       /* If we're in a Stasis bridge, depart it before going back to the
+        * dialplan */
+       if (stasis_app_get_bridge(control)) {
                ast_bridge_depart(control->channel);
        }
 
@@ -465,24 +466,32 @@
 {
        if (!control) {
                return NULL;
-       }
-       return control->bridge;
+       } else {
+               SCOPED_AO2LOCK(lock, control);
+               return control->bridge;
+       }
 }
 
 
 static void bridge_after_cb(struct ast_channel *chan, void *data)
 {
        struct stasis_app_control *control = data;
+       SCOPED_AO2LOCK(lock, control);
 
        ast_debug(3, "%s, %s: Channel leaving bridge\n",
                ast_channel_uniqueid(chan), control->bridge->uniqueid);
 
        ast_assert(chan == control->channel);
 
+       /* Restore the channel's PBX */
        ast_channel_pbx_set(control->channel, control->pbx);
        control->pbx = NULL;
 
+       /* No longer in the bridge */
        control->bridge = NULL;
+
+       /* Wakeup the command_queue loop */
+       exec_command(control, NULL, NULL);
 }
 
 static void bridge_after_cb_failed(enum ast_bridge_after_cb_reason reason,
@@ -494,67 +503,118 @@
 
        ast_debug(3, "  reason: %s\n",
                ast_bridge_after_cb_reason_string(reason));
-
-       /* Wakeup the command_queue loop */
-       exec_command(control, NULL, NULL);
-}
-
-void stasis_app_add_to_bridge(struct stasis_app_control *control,
-       struct ast_bridge *bridge)
-{
+}
+
+static void *app_control_add_channel_to_bridge(
+       struct stasis_app_control *control,
+       struct ast_channel *chan, void *data)
+{
+       struct ast_bridge *bridge = data;
        int res;
 
        if (!control || !bridge) {
-               return;
-       }
-
-       ast_assert(control->channel != NULL);
-
-       /* Depart whatever Stasis bridge we're currently in */
-       if (control->bridge) {
-               ast_bridge_depart(control->channel);
-       }
-
-       res = ast_bridge_set_after_callback(control->channel, bridge_after_cb,
+               return NULL;
+       }
+
+       ast_debug(3, "%s: Adding to bridge %s\n",
+               stasis_app_control_get_channel_id(control),
+               bridge->uniqueid);
+
+       ast_assert(chan != NULL);
+
+       /* Depart whatever Stasis bridge we're currently in. */
+       if (stasis_app_get_bridge(control)) {
+               /* Note that it looks like there's a race condition here, since
+                * we don't have control locked. But this happens from the
+                * control callback thread, so there won't be any other
+                * concurrent attempts to bridge.
+                */
+               ast_bridge_depart(chan);
+       }
+
+
+       res = ast_bridge_set_after_callback(chan, bridge_after_cb,
                bridge_after_cb_failed, control);
        if (res != 0) {
                ast_log(LOG_ERROR, "Error setting after-bridge callback\n");
-               return;
-       }
-
-       /* Save off the channel's PBX */
-       ast_assert(!control->pbx || !ast_channel_pbx(control->channel));
-       if (!control->pbx) {
-               control->pbx = ast_channel_pbx(control->channel);
-               ast_channel_pbx_set(control->channel, NULL);
-       }
-
-       res = ast_bridge_impart(bridge,
-               control->channel,
-               NULL, /* swap channel */
-               NULL, /* features */
-               0); /* independent - false allows us to ast_bridge_depart() */
-
-       if (res != 0) {
-               ast_log(LOG_ERROR, "Error adding channel to bridge\n");
-               ast_channel_pbx_set(control->channel, control->pbx);
-               control->pbx = NULL;
-               return;
-       }
-
-       control->bridge = bridge;
-}
-
-void stasis_app_remove_from_bridge(struct stasis_app_control *control)
-{
+               return NULL;
+       }
+
+       {
+               /* pbx and bridge are modified by the bridging impart thread.
+                * It shouldn't happen concurrently, but we still need to lock
+                * for the memory fence.
+                */
+               SCOPED_AO2LOCK(lock, control);
+
+               /* Save off the channel's PBX */
+               ast_assert(control->pbx == NULL);
+               if (!control->pbx) {
+                       control->pbx = ast_channel_pbx(chan);
+                       ast_channel_pbx_set(chan, NULL);
+               }
+
+               res = ast_bridge_impart(bridge,
+                       chan,
+                       NULL, /* swap channel */
+                       NULL, /* features */
+                       0); /* independent - false allows us to 
ast_bridge_depart() */
+
+               if (res != 0) {
+                       ast_log(LOG_ERROR, "Error adding channel to bridge\n");
+                       ast_channel_pbx_set(chan, control->pbx);
+                       control->pbx = NULL;
+                       return NULL;
+               }
+
+               ast_assert(stasis_app_get_bridge(control) == NULL);
+               control->bridge = bridge;
+       }
+       return NULL;
+}
+
+void stasis_app_control_add_channel_to_bridge(
+       struct stasis_app_control *control, struct ast_bridge *bridge)
+{
+       ast_debug(3, "%s: Sending channel add_to_bridge command\n",
+                       stasis_app_control_get_channel_id(control));
+       stasis_app_send_command_async(control,
+               app_control_add_channel_to_bridge, bridge);
+}
+
+static void *app_control_remove_channel_from_bridge(
+       struct stasis_app_control *control,
+       struct ast_channel *chan, void *data)
+{
+       struct ast_bridge *bridge = data;
+
+       if (!control) {
+               return NULL;
+       }
+
        /* We should only depart from our own bridge */
-       if (!control || !control->bridge) {
-               return;
-       }
-
-       ast_assert(control->channel != NULL);
-
-       ast_bridge_depart(control->channel);
+       ast_debug(3, "%s: Departing bridge %s\n",
+               stasis_app_control_get_channel_id(control),
+               bridge->uniqueid);
+
+       if (bridge != stasis_app_get_bridge(control)) {
+               ast_log(LOG_WARNING, "%s: Not in bridge %s; not removing\n",
+                       stasis_app_control_get_channel_id(control),
+                       bridge->uniqueid);
+               return NULL;
+       }
+
+       ast_bridge_depart(chan);
+       return NULL;
+}
+
+void stasis_app_control_remove_channel_from_bridge(
+       struct stasis_app_control *control, struct ast_bridge *bridge)
+{
+       ast_debug(3, "%s: Sending channel remove_from_bridge command\n",
+                       stasis_app_control_get_channel_id(control));
+       stasis_app_send_command_async(control,
+               app_control_remove_channel_from_bridge, bridge);
 }
 
 const char *stasis_app_control_get_channel_id(
@@ -601,18 +661,17 @@
 
 void control_wait(struct stasis_app_control *control)
 {
-       ast_mutex_t *queue_lock;
        if (!control) {
                return;
        }
 
        ast_assert(control->command_queue != NULL);
 
-       queue_lock = ao2_object_get_lockaddr(control->command_queue);
        ao2_lock(control->command_queue);
        while (ao2_container_count(control->command_queue) == 0) {
-               int r = ast_cond_wait(&control->wait_cond, queue_lock);
-               if (r < 0) {
+               int res = ast_cond_wait(&control->wait_cond,
+                       ao2_object_get_lockaddr(control->command_queue));
+               if (res < 0) {
                        ast_log(LOG_ERROR, "Error waiting on command queue\n");
                        break;
                }

Modified: team/dlee/ari-async-bridge/res/stasis/control.h
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/res/stasis/control.h?view=diff&rev=395901&r1=395900&r2=395901
==============================================================================
--- team/dlee/ari-async-bridge/res/stasis/control.h (original)
+++ team/dlee/ari-async-bridge/res/stasis/control.h Wed Jul 31 15:35:34 2013
@@ -48,10 +48,29 @@
 int control_dispatch_all(struct stasis_app_control *control,
        struct ast_channel *chan);
 
+/*!
+ * \brief Blocks until \a control's command queue has a command available.
+ *
+ * \param control Control to block on.
+ */
 void control_wait(struct stasis_app_control *control);
 
+/*!
+ * \brief Signals that a control object should finish and exit back to the
+ * dialplan.
+ *
+ * \param control Control object to continue.
+ */
+void control_continue(struct stasis_app_control *control);
+
+/*!
+ * \brief Returns true if control_continue() has been called on this \a 
control.
+ *
+ * \param control Control to query.
+ * \return True (non-zero) if control_continue() has been called.
+ * \return False (zero) otherwise.
+ */
 int control_is_done(struct stasis_app_control *control);
 
-void control_continue(struct stasis_app_control *control);
 
 #endif /* _ASTERISK_RES_STASIS_CONTROL_H */


--
_____________________________________________________________________
-- Bandwidth and Colocation Provided by http://www.api-digital.com --

svn-commits mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/svn-commits

Reply via email to