[svn-commits] dlee: branch dlee/ari-async-bridge r395901 - in /team/dlee/ari-async-bridge: ...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Wed Jul 31 15:35:37 CDT 2013
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 */
More information about the svn-commits
mailing list