[asterisk-commits] mmichelson: branch russell/ast_channel_ao2 r176808 - in /team/russell/ast_cha...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Feb 17 18:22:32 CST 2009
Author: mmichelson
Date: Tue Feb 17 18:22:32 2009
New Revision: 176808
URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=176808
Log:
Add autochan interface to ast_channel_ao2 and convert chanspy and mixmonitor to use it
chanspy and mixmonitor are examples of applications which attempt to keep a pointer to
a channel in a thread external to the channel's main (i.e. PBX) thread. In both cases,
the channel that they reference may change due to a masquerade. The autochan interface
is a method by which a pointer to a channel may be automatically updated if a channel
is masqueraded.
This also finishes the conversion of app_chanspy and app_mixmonitor to use refcounted
channels.
Added:
team/russell/ast_channel_ao2/include/asterisk/autochan.h (with props)
team/russell/ast_channel_ao2/main/autochan.c (with props)
Modified:
team/russell/ast_channel_ao2/apps/app_chanspy.c
team/russell/ast_channel_ao2/apps/app_mixmonitor.c
team/russell/ast_channel_ao2/main/Makefile
team/russell/ast_channel_ao2/main/channel.c
Modified: team/russell/ast_channel_ao2/apps/app_chanspy.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/apps/app_chanspy.c?view=diff&rev=176808&r1=176807&r2=176808
==============================================================================
--- team/russell/ast_channel_ao2/apps/app_chanspy.c (original)
+++ team/russell/ast_channel_ao2/apps/app_chanspy.c Tue Feb 17 18:22:32 2009
@@ -50,6 +50,7 @@
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
+#include "asterisk/autochan.h"
#define AST_NAME_STRLEN 256
#define NUM_SPYGROUPS 128
@@ -336,8 +337,6 @@
AST_APP_OPTION('d', OPTION_DTMF_SWITCH_MODES),
});
-static int next_unique_id_to_use = 0;
-
struct chanspy_translation_helper {
/* spy data */
struct ast_audiohook spy_audiohook;
@@ -399,26 +398,20 @@
.generate = spy_generate,
};
-static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook)
+static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
{
int res = 0;
struct ast_channel *peer = NULL;
- ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
-
- res = ast_audiohook_attach(chan, audiohook);
-
- if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
+ ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, autochan->chan->name);
+
+ res = ast_audiohook_attach(autochan->chan, audiohook);
+
+ if (!res && ast_test_flag(autochan->chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) {
ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
}
return res;
}
-
-struct chanspy_ds {
- struct ast_channel *chan;
- char unique_id[20];
- ast_mutex_t lock;
-};
static void change_spy_mode(const char digit, struct ast_flags *flags)
{
@@ -434,7 +427,7 @@
}
}
-static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds,
+static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
int *volfactor, int fd, struct ast_flags *flags, char *exitcontext)
{
struct chanspy_translation_helper csth;
@@ -443,32 +436,22 @@
char *name;
struct ast_frame *f;
struct ast_silence_generator *silgen = NULL;
- struct ast_channel *spyee = NULL, *spyee_bridge = NULL;
+ struct ast_autochan *spyee_bridge_autochan = NULL;
const char *spyer_name;
ast_channel_lock(chan);
spyer_name = ast_strdupa(chan->name);
ast_channel_unlock(chan);
- ast_mutex_lock(&spyee_chanspy_ds->lock);
- if (spyee_chanspy_ds->chan) {
- spyee = spyee_chanspy_ds->chan;
- ast_channel_lock(spyee);
- }
- ast_mutex_unlock(&spyee_chanspy_ds->lock);
-
- if (!spyee) {
+ /* We now hold the channel lock on spyee */
+
+ if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
return 0;
}
- /* We now hold the channel lock on spyee */
-
- if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
- ast_channel_unlock(spyee);
- return 0;
- }
-
- name = ast_strdupa(spyee->name);
+ ast_channel_lock(spyee_autochan->chan);
+ name = ast_strdupa(spyee_autochan->chan->name);
+ ast_channel_unlock(spyee_autochan->chan);
ast_verb(2, "Spying on channel %s\n", name);
manager_event(EVENT_FLAG_CALL, "ChanSpyStart",
@@ -480,26 +463,23 @@
ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
- if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
+ if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
ast_audiohook_destroy(&csth.spy_audiohook);
- ast_channel_unlock(spyee);
return 0;
}
ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
- if (start_spying(spyee, spyer_name, &csth.whisper_audiohook)) {
- ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", spyee->name);
- }
- if ((spyee_bridge = ast_bridged_channel(spyee))) {
- ast_channel_lock(spyee_bridge);
- if (start_spying(spyee_bridge, spyer_name, &csth.bridge_whisper_audiohook)) {
- ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", spyee->name);
- }
- ast_channel_unlock(spyee_bridge);
- }
- ast_channel_unlock(spyee);
- spyee = NULL;
+ if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
+ ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
+ }
+ if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
+ ast_channel_lock(spyee_bridge_autochan->chan);
+ if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
+ ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
+ }
+ ast_channel_unlock(spyee_bridge_autochan->chan);
+ }
ast_channel_lock(chan);
ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
@@ -632,6 +612,10 @@
ast_audiohook_detach(&csth.spy_audiohook);
ast_audiohook_unlock(&csth.spy_audiohook);
ast_audiohook_destroy(&csth.spy_audiohook);
+
+ if (spyee_bridge_autochan) {
+ ast_autochan_destroy(spyee_bridge_autochan);
+ }
ast_verb(2, "Done Spying on channel %s\n", name);
manager_event(EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
@@ -639,115 +623,29 @@
return running;
}
-/*!
- * \note This relies on the embedded lock to be recursive, as it may be called
- * due to a call to chanspy_ds_free with the lock held there.
- */
-static void chanspy_ds_destroy(void *data)
-{
- struct chanspy_ds *chanspy_ds = data;
-
- /* Setting chan to be NULL is an atomic operation, but we don't want this
- * value to change while this lock is held. The lock is held elsewhere
- * while it performs non-atomic operations with this channel pointer */
-
- ast_mutex_lock(&chanspy_ds->lock);
- chanspy_ds->chan = NULL;
- ast_mutex_unlock(&chanspy_ds->lock);
-}
-
-static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
- struct chanspy_ds *chanspy_ds = data;
-
- ast_mutex_lock(&chanspy_ds->lock);
- chanspy_ds->chan = new_chan;
- ast_mutex_unlock(&chanspy_ds->lock);
-}
-
-static const struct ast_datastore_info chanspy_ds_info = {
- .type = "chanspy",
- .destroy = chanspy_ds_destroy,
- .chan_fixup = chanspy_ds_chan_fixup,
-};
-
-static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
-{
- if (!chanspy_ds)
- return NULL;
-
- ast_mutex_lock(&chanspy_ds->lock);
- if (chanspy_ds->chan) {
- struct ast_datastore *datastore;
- struct ast_channel *chan;
-
- chan = chanspy_ds->chan;
-
- ast_channel_lock(chan);
- if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
- ast_channel_datastore_remove(chan, datastore);
- /* chanspy_ds->chan is NULL after this call */
- chanspy_ds_destroy(datastore->data);
- datastore->data = NULL;
- ast_datastore_free(datastore);
- }
- ast_channel_unlock(chan);
- }
- ast_mutex_unlock(&chanspy_ds->lock);
-
- return NULL;
-}
-
-/*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
-static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
-{
- struct ast_datastore *datastore = NULL;
-
- ast_mutex_lock(&chanspy_ds->lock);
-
- if (!(datastore = ast_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
- ast_mutex_unlock(&chanspy_ds->lock);
- chanspy_ds = chanspy_ds_free(chanspy_ds);
- ast_channel_unlock(chan);
- return NULL;
- }
-
- chanspy_ds->chan = chan;
- datastore->data = chanspy_ds;
- ast_channel_datastore_add(chan, datastore);
-
- return chanspy_ds;
-}
-
-static struct chanspy_ds *next_channel(struct ast_channel *chan,
- const struct ast_channel *last, const char *spec,
- const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
+static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
+ struct ast_autochan *autochan, struct ast_channel *chan)
{
struct ast_channel *next;
const size_t pseudo_len = strlen("DAHDI/pseudo");
+ if (!iter) {
+ return NULL;
+ }
+
redo:
- if (!ast_strlen_zero(spec))
- next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
- else if (!ast_strlen_zero(exten))
- next = ast_walk_channel_by_exten_locked(last, exten, context);
- else
- next = ast_channel_walk_locked(last);
-
- if (!next)
+
+ if (!(next = ast_channel_iterator_next(iter))) {
return NULL;
+ }
if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
- last = next;
- ast_channel_unlock(next);
goto redo;
} else if (next == chan) {
- last = next;
- ast_channel_unlock(next);
goto redo;
}
- return setup_chanspy_ds(next, chanspy_ds);
+ return ast_autochan_setup(next);
}
static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
@@ -764,7 +662,7 @@
char *ptr;
int num;
int num_spyed_upon = 1;
- struct chanspy_ds chanspy_ds = { 0, };
+ struct ast_channel_iterator *iter = NULL;
if (ast_test_flag(flags, OPTION_EXIT)) {
const char *c;
@@ -779,10 +677,6 @@
ast_channel_unlock(chan);
}
- ast_mutex_init(&chanspy_ds.lock);
-
- snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
-
if (chan->_state != AST_STATE_UP)
ast_answer(chan);
@@ -791,8 +685,8 @@
waitms = 100;
for (;;) {
- struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
- struct ast_channel *prev = NULL, *peer = NULL;
+ struct ast_autochan *autochan = NULL, *next_autochan = NULL;
+ struct ast_channel *prev = NULL;
if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
res = ast_streamfile(chan, "beep", chan->language);
@@ -812,6 +706,19 @@
ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
}
}
+
+ /* Set up the iterator we'll be using during this call */
+ if (!ast_strlen_zero(spec)) {
+ iter = ast_channel_iterator_by_name_new(0, spec, strlen(spec));
+ } else if (!ast_strlen_zero(exten)) {
+ iter = ast_channel_iterator_by_exten_new(0, exten, context);
+ } else {
+ iter = ast_channel_iterator_all_new(0);
+ }
+
+ if (!iter) {
+ return -1;
+ }
res = ast_waitfordigit(chan, waitms);
if (res < 0) {
@@ -832,38 +739,30 @@
waitms = 100;
num_spyed_upon = 0;
- for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
- peer_chanspy_ds;
- chanspy_ds_free(peer_chanspy_ds), prev = peer,
- peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
- next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
+ for (autochan = next_channel(iter, autochan, chan);
+ autochan;
+ prev = autochan->chan, ast_autochan_destroy(autochan),
+ autochan = next_autochan ? next_autochan :
+ next_channel(iter, autochan, chan), next_autochan = NULL) {
int igrp = !mygroup;
int ienf = !myenforced;
char *s;
- peer = peer_chanspy_ds->chan;
-
- ast_mutex_unlock(&peer_chanspy_ds->lock);
-
- if (peer == prev) {
- ast_channel_unlock(peer);
- chanspy_ds_free(peer_chanspy_ds);
+ if (autochan->chan == prev) {
+ ast_autochan_destroy(autochan);
break;
}
if (ast_check_hangup(chan)) {
- ast_channel_unlock(peer);
- chanspy_ds_free(peer_chanspy_ds);
+ ast_autochan_destroy(autochan);
break;
}
- if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
- ast_channel_unlock(peer);
+ if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
continue;
}
- if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
- ast_channel_unlock(peer);
+ if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
continue;
}
@@ -881,7 +780,7 @@
num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
ARRAY_LEN(mygroups));
- if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
+ if ((group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP"))) {
ast_copy_string(dup_group, group, sizeof(dup_group));
num_groups = ast_app_separate_args(dup_group, ':', groups,
ARRAY_LEN(groups));
@@ -898,7 +797,6 @@
}
if (!igrp) {
- ast_channel_unlock(peer);
continue;
}
@@ -909,7 +807,7 @@
snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
- ast_copy_string(ext + 1, peer->name, sizeof(ext) - 1);
+ ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
if ((end = strchr(ext, '-'))) {
*end++ = ':';
*end = '\0';
@@ -927,18 +825,13 @@
}
strcpy(peer_name, "spy-");
- strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
+ strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
ptr = strchr(peer_name, '/');
*ptr++ = '\0';
ptr = strsep(&ptr, "-");
for (s = peer_name; s < ptr; s++)
*s = tolower(*s);
- /* We have to unlock the peer channel here to avoid a deadlock.
- * So, when we need to dereference it again, we have to lock the
- * datastore and get the pointer from there to see if the channel
- * is still valid. */
- ast_channel_unlock(peer);
if (!ast_test_flag(flags, OPTION_QUIET)) {
if (ast_test_flag(flags, OPTION_NAME)) {
@@ -954,7 +847,7 @@
res = ast_waitstream(chan, "");
}
if (res) {
- chanspy_ds_free(peer_chanspy_ds);
+ ast_autochan_destroy(autochan);
break;
}
} else {
@@ -966,42 +859,38 @@
}
}
- res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
+ res = channel_spy(chan, autochan, &volfactor, fd, flags, exitcontext);
num_spyed_upon++;
if (res == -1) {
- chanspy_ds_free(peer_chanspy_ds);
+ ast_autochan_destroy(autochan);
goto exit;
} else if (res == -2) {
res = 0;
- chanspy_ds_free(peer_chanspy_ds);
+ ast_autochan_destroy(autochan);
goto exit;
} else if (res > 1 && spec) {
struct ast_channel *next;
snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
- if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
- peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
- next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
+ if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
+ next_autochan = ast_autochan_setup(next);
+ next = ast_channel_unref(next);
} else {
/* stay on this channel, if it is still valid */
-
- ast_mutex_lock(&peer_chanspy_ds->lock);
- if (peer_chanspy_ds->chan) {
- ast_channel_lock(peer_chanspy_ds->chan);
- next_chanspy_ds = peer_chanspy_ds;
- peer_chanspy_ds = NULL;
+ if (!ast_check_hangup(autochan->chan)) {
+ next_autochan = ast_autochan_setup(autochan->chan);
} else {
/* the channel is gone */
- ast_mutex_unlock(&peer_chanspy_ds->lock);
- next_chanspy_ds = NULL;
+ next_autochan = NULL;
}
}
-
- peer = NULL;
- }
- }
+ }
+ }
+
+ iter = ast_channel_iterator_destroy(iter);
+
if (res == -1 || ast_check_hangup(chan))
break;
}
@@ -1010,10 +899,6 @@
ast_clear_flag(chan, AST_FLAG_SPYING);
ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
-
- ast_mutex_lock(&chanspy_ds.lock);
- ast_mutex_unlock(&chanspy_ds.lock);
- ast_mutex_destroy(&chanspy_ds.lock);
return res;
}
Modified: team/russell/ast_channel_ao2/apps/app_mixmonitor.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/apps/app_mixmonitor.c?view=diff&rev=176808&r1=176807&r2=176808
==============================================================================
--- team/russell/ast_channel_ao2/apps/app_mixmonitor.c (original)
+++ team/russell/ast_channel_ao2/apps/app_mixmonitor.c Tue Feb 17 18:22:32 2009
@@ -45,6 +45,7 @@
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/channel.h"
+#include "asterisk/autochan.h"
/*** DOCUMENTATION
<application name="MixMonitor" language="en_US">
@@ -138,7 +139,7 @@
char *post_process;
char *name;
unsigned int flags;
- struct mixmonitor_ds *mixmonitor_ds;
+ struct ast_autochan *autochan;
};
enum {
@@ -164,50 +165,6 @@
AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
});
-/* This structure is used as a means of making sure that our pointer to
- * the channel we are monitoring remains valid. This is very similar to
- * what is used in app_chanspy.c.
- */
-struct mixmonitor_ds {
- struct ast_channel *chan;
- /* These condition variables are used to be sure that the channel
- * hangup code completes before the mixmonitor thread attempts to
- * free this structure. The combination of a bookean flag and a
- * ast_cond_t ensure that no matter what order the threads run in,
- * we are guaranteed to never have the waiting thread block forever
- * in the case that the signaling thread runs first.
- */
- unsigned int destruction_ok;
- ast_cond_t destruction_condition;
- ast_mutex_t lock;
-};
-
-static void mixmonitor_ds_destroy(void *data)
-{
- struct mixmonitor_ds *mixmonitor_ds = data;
-
- ast_mutex_lock(&mixmonitor_ds->lock);
- mixmonitor_ds->chan = NULL;
- mixmonitor_ds->destruction_ok = 1;
- ast_cond_signal(&mixmonitor_ds->destruction_condition);
- ast_mutex_unlock(&mixmonitor_ds->lock);
-}
-
-static void mixmonitor_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
- struct mixmonitor_ds *mixmonitor_ds = data;
-
- ast_mutex_lock(&mixmonitor_ds->lock);
- mixmonitor_ds->chan = new_chan;
- ast_mutex_unlock(&mixmonitor_ds->lock);
-}
-
-static struct ast_datastore_info mixmonitor_ds_info = {
- .type = "mixmonitor",
- .destroy = mixmonitor_ds_destroy,
- .chan_fixup = mixmonitor_ds_chan_fixup,
-};
-
static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
{
struct ast_channel *peer = NULL;
@@ -249,9 +206,7 @@
if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
continue;
- ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
- if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
- ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
+ if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
/* Initialize the file if not already done so */
if (!fs && !errflag) {
oflags = O_CREAT | O_WRONLY;
@@ -271,10 +226,7 @@
/* Write out frame */
if (fs)
ast_writestream(fs, fr);
- } else {
- ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
-
/* All done! free it. */
ast_frame_free(fr, 0);
@@ -294,46 +246,10 @@
ast_safe_system(mixmonitor->post_process);
}
- ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
- if (!mixmonitor->mixmonitor_ds->destruction_ok) {
- ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
- }
- ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
- ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
- ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
- ast_free(mixmonitor->mixmonitor_ds);
+ ast_autochan_destroy(mixmonitor->autochan);
ast_free(mixmonitor);
return NULL;
-}
-
-static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan)
-{
- struct ast_datastore *datastore = NULL;
- struct mixmonitor_ds *mixmonitor_ds;
-
- if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
- return -1;
- }
-
- ast_mutex_init(&mixmonitor_ds->lock);
- ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
-
- if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) {
- ast_free(mixmonitor_ds);
- return -1;
- }
-
- /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */
- mixmonitor_ds->chan = chan;
- datastore->data = mixmonitor_ds;
-
- ast_channel_lock(chan);
- ast_channel_datastore_add(chan, datastore);
- ast_channel_unlock(chan);
-
- mixmonitor->mixmonitor_ds = mixmonitor_ds;
- return 0;
}
static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags,
@@ -369,7 +285,7 @@
/* Copy over flags and channel name */
mixmonitor->flags = flags;
- if (setup_mixmonitor_ds(mixmonitor, chan)) {
+ if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
return;
}
mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
Added: team/russell/ast_channel_ao2/include/asterisk/autochan.h
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/include/asterisk/autochan.h?view=auto&rev=176808
==============================================================================
--- team/russell/ast_channel_ao2/include/asterisk/autochan.h (added)
+++ team/russell/ast_channel_ao2/include/asterisk/autochan.h Tue Feb 17 18:22:32 2009
@@ -1,0 +1,102 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) <Year>, <Your Name Here>
+ *
+ * Mark Michelson <mmichelson at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief "smart" channels that update automatically if a channel is masqueraded
+ *
+ * \author Mark Michelson <mmichelson at digium.com>
+ *
+ */
+
+#include "asterisk.h"
+#include "asterisk/linkedlists.h"
+
+#ifndef _ASTERISK_AUTOCHAN_H
+#define _ASTERISK_AUTOCHAN_H
+
+struct ast_autochan {
+ struct ast_channel *chan;
+ AST_LIST_ENTRY(ast_autochan) list;
+};
+
+/*! \par Just what the $!@# is an autochan?
+ *
+ * An ast_autochan is a structure which contains an ast_channel. The pointer
+ * inside an autochan has the ability to update itself if the channel it points
+ * to is masqueraded into a different channel.
+ *
+ * This has a great benefit for any application or service which creates a thread
+ * outside of the channel's main operating thread which keeps a pointer to said
+ * channel. when a masquerade occurs on the channel, the autochan's chan pointer
+ * will automatically update to point to the new channel.
+ *
+ * Some rules for autochans
+ *
+ * 1. If you are going to use an autochan, then be sure to always refer to the
+ * channel using the chan pointer inside the autochan if possible, since this is
+ * the pointer that will be updated during a masquerade.
+ *
+ * 2. If you are going to save off a pointer to the autochan's chan, then be sure
+ * to save off the pointer using ast_channel_ref and to unref the channel when you
+ * are finished with the pointer. If you do not do this and a masquerade occurs on
+ * the channel, then it is possible that your saved pointer will become invalid.
+ */
+
+/* \brief set up a new ast_autochan structure
+ *
+ * Allocates and initializes an ast_autochan, sets the
+ * autochan's chan pointer to point to the chan parameter, and
+ * adds the autochan to the global list of autochans. The newly-
+ * created autochan is returned to the caller. This function will
+ * cause the refcount of chan to increase by 1.
+ *
+ * \note autochans must be freed using ast_autochan_destroy
+ * \param chan The channel our new autochan will point to
+ * \retval NULL Failure
+ * \retval non-NULL success
+ */
+struct ast_autochan *ast_autochan_setup(struct ast_channel *chan);
+
+/* \brief destroy an ast_autochan structure
+ *
+ * Removes the passed-in autochan from the list of autochans and
+ * unrefs the channel that is pointed to. Also frees the autochan
+ * struct itself. This function will unref the channel reference
+ * which was made in ast_autochan_setup
+ *
+ * \param autochan The autochan that you wish to destroy
+ * \retval void
+ */
+void ast_autochan_destroy(struct ast_autochan *autochan);
+
+/* \brief Switch what channel autochans point to
+ *
+ * Traverses the list of autochans. All autochans which point to
+ * old_chan will be updated to point to new_chan instead. Currently
+ * this is only called from ast_do_masquerade in channel.c. If some
+ * other context for calling this function should be determined, please
+ * call this function with both channels locked.
+ *
+ * \param old_chan The channel that autochans may currently point to
+ * \param new_chan The channel that we want to point those autochans to now
+ * \retval void
+ */
+void ast_autochan_new_channel(struct ast_channel *old_chan, struct ast_channel *new_chan);
+
+#endif /* _ASTERISK_AUTOCHAN_H */
Propchange: team/russell/ast_channel_ao2/include/asterisk/autochan.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/russell/ast_channel_ao2/include/asterisk/autochan.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/russell/ast_channel_ao2/include/asterisk/autochan.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: team/russell/ast_channel_ao2/main/Makefile
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/main/Makefile?view=diff&rev=176808&r1=176807&r2=176808
==============================================================================
--- team/russell/ast_channel_ao2/main/Makefile (original)
+++ team/russell/ast_channel_ao2/main/Makefile Tue Feb 17 18:22:32 2009
@@ -29,7 +29,7 @@
strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
astobj2.o hashtab.o global_datastores.o version.o \
features.o taskprocessor.o timing.o datastore.o xml.o xmldoc.o \
- strings.o
+ strings.o autochan.o
# we need to link in the objects statically, not as a library, because
# otherwise modules will not have them available if none of the static
Added: team/russell/ast_channel_ao2/main/autochan.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/main/autochan.c?view=auto&rev=176808
==============================================================================
--- team/russell/ast_channel_ao2/main/autochan.c (added)
+++ team/russell/ast_channel_ao2/main/autochan.c Tue Feb 17 18:22:32 2009
@@ -1,0 +1,89 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) <Year>, <Your Name Here>
+ *
+ * Mark Michelson <mmichelson at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief "smart" channels
+ *
+ * \author Mark Michelson <mmichelson at digium.com>
+ *
+ */
+
+#include "asterisk.h"
+#include "asterisk/autochan.h"
+#include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/options.h"
+#include "asterisk/channel.h"
+
+AST_LIST_HEAD_STATIC(autochans, ast_autochan);
+
+struct ast_autochan *ast_autochan_setup(struct ast_channel *chan)
+{
+ struct ast_autochan *autochan;
+
+ if (!(autochan = ast_calloc(1, sizeof(*autochan)))) {
+ return NULL;
+ }
+
+ autochan->chan = ast_channel_ref(chan);
+
+ AST_LIST_LOCK(&autochans);
+ AST_LIST_INSERT_TAIL(&autochans, autochan, list);
+ AST_LIST_UNLOCK(&autochans);
+
+ ast_debug(1, "Created autochan %p to hold channel %s (%p)\n", autochan, chan->name, chan);
+
+ return autochan;
+}
+
+void ast_autochan_destroy(struct ast_autochan *autochan)
+{
+ struct ast_autochan *autochan_iter;
+
+ AST_LIST_LOCK(&autochans);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&autochans, autochan_iter, list) {
+ if (autochan_iter == autochan) {
+ AST_LIST_REMOVE_CURRENT(list);
+ ast_debug(1, "Removed autochan %p from the list, about to free it\n", autochan);
+ break;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ AST_LIST_UNLOCK(&autochans);
+ autochan->chan = ast_channel_unref(autochan->chan);
+ ast_free(autochan);
+}
+
+void ast_autochan_new_channel(struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+ struct ast_autochan *autochan;
+
+ AST_LIST_LOCK(&autochans);
+ AST_LIST_TRAVERSE(&autochans, autochan, list) {
+ if (autochan->chan == old_chan) {
+ autochan->chan = ast_channel_unref(old_chan);
+ autochan->chan = ast_channel_ref(new_chan);
+ if (option_debug > 1) {
+ ast_log(LOG_DEBUG, "Autochan %p used to hold channel %s (%p) but now holds channel %s (%p)\n",
+ autochan, old_chan->name, old_chan, new_chan->name, new_chan);
+ }
+ }
+ }
+ AST_LIST_UNLOCK(&autochans);
+}
Propchange: team/russell/ast_channel_ao2/main/autochan.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/russell/ast_channel_ao2/main/autochan.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/russell/ast_channel_ao2/main/autochan.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: team/russell/ast_channel_ao2/main/channel.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/main/channel.c?view=diff&rev=176808&r1=176807&r2=176808
==============================================================================
--- team/russell/ast_channel_ao2/main/channel.c (original)
+++ team/russell/ast_channel_ao2/main/channel.c Tue Feb 17 18:22:32 2009
@@ -61,6 +61,7 @@
#include "asterisk/slinfactory.h"
#include "asterisk/audiohook.h"
#include "asterisk/timing.h"
+#include "asterisk/autochan.h"
#ifdef HAVE_EPOLL
#include <sys/epoll.h>
@@ -4140,6 +4141,8 @@
AST_LIST_APPEND_LIST(&original->datastores, &clonechan->datastores, entry);
}
+ ast_autochan_new_channel(clonechan, original);
+
clone_variables(original, clonechan);
/* Presense of ADSI capable CPE follows clone */
original->adsicpe = clonechan->adsicpe;
More information about the asterisk-commits
mailing list