Merge in last round of spy fixes. This should hopefully eliminate all the issues people have been seeing by distinctly separating what each component (core/spy) is responsible for. Core is responsible for adding a spy to a channel, feeding frames to the spy, removing the spy from a channel, and telling the spy to stop. Spy is responsible for reading frames in, and cleaning up after itself.

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.2@42054 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Joshua Colp
2006-09-05 20:02:48 +00:00
parent cc82df15ff
commit 68de3c0b29
4 changed files with 90 additions and 79 deletions

View File

@@ -207,21 +207,6 @@ static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, s
return res;
}
static void stop_spying(struct ast_channel *chan, struct ast_channel_spy *spy)
{
/* If our status has changed to DONE, then the channel we're spying on is gone....
DON'T TOUCH IT!!! RUN AWAY!!! */
if (spy->status == CHANSPY_DONE)
return;
if (!chan)
return;
ast_mutex_lock(&chan->lock);
ast_channel_spy_remove(chan, spy);
ast_mutex_unlock(&chan->lock);
};
/* Map 'volume' levels from -4 through +4 into
decibel (dB) settings for channel drivers
*/
@@ -338,7 +323,13 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int
}
}
ast_deactivate_generator(chan);
stop_spying(spyee, &csth.spy);
if (csth.spy.chan) {
csth.spy.status = CHANSPY_DONE;
ast_mutex_lock(&csth.spy.chan->lock);
ast_channel_spy_remove(csth.spy.chan, &csth.spy);
ast_mutex_unlock(&csth.spy.chan->lock);
}
if (option_verbose >= 2) {
ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
@@ -347,7 +338,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int
running = 0;
}
ast_mutex_destroy(&csth.spy.lock);
ast_channel_spy_free(&csth.spy);
return running;
}

View File

@@ -109,23 +109,6 @@ AST_APP_OPTIONS(mixmonitor_opts, {
AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
});
static void stopmon(struct ast_channel_spy *spy)
{
struct ast_channel *chan = spy->chan;
/* If our status has changed to DONE, then the channel we're spying on is gone....
DON'T TOUCH IT!!! RUN AWAY!!! */
if (spy->status == CHANSPY_DONE)
return;
if (!chan)
return;
ast_mutex_lock(&chan->lock);
ast_channel_spy_remove(chan, spy);
ast_mutex_unlock(&chan->lock);
}
static int startmon(struct ast_channel *chan, struct ast_channel_spy *spy)
{
struct ast_channel *peer;
@@ -164,9 +147,8 @@ static void *mixmonitor_thread(void *obj)
ast_channel_spy_trigger_wait(&mixmonitor->spy);
if (!mixmonitor->spy.chan || mixmonitor->spy.status != CHANSPY_RUNNING) {
if (!mixmonitor->spy.chan || mixmonitor->spy.status != CHANSPY_RUNNING)
break;
}
while (1) {
if (!(f = ast_channel_spy_read_frame(&mixmonitor->spy, SAMPLES_PER_FRAME)))
@@ -189,7 +171,7 @@ static void *mixmonitor_thread(void *obj)
ast_mutex_unlock(&mixmonitor->spy.lock);
stopmon(&mixmonitor->spy);
ast_channel_spy_free(&mixmonitor->spy);
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);
@@ -200,8 +182,6 @@ static void *mixmonitor_thread(void *obj)
ast_safe_system(mixmonitor->post_process);
}
ast_mutex_destroy(&mixmonitor->spy.lock);
ast_closestream(mixmonitor->fs);
free(mixmonitor);

109
channel.c
View File

@@ -1017,22 +1017,59 @@ int ast_channel_spy_add(struct ast_channel *chan, struct ast_channel_spy *spy)
return 0;
}
/* Clean up a channel's spy information */
static void spy_cleanup(struct ast_channel *chan)
{
if (AST_LIST_EMPTY(&chan->spies->list))
return;
if (chan->spies->read_translator.path)
ast_translator_free_path(chan->spies->read_translator.path);
if (chan->spies->write_translator.path)
ast_translator_free_path(chan->spies->write_translator.path);
free(chan->spies);
chan->spies = NULL;
return;
}
/* Detach a spy from it's channel */
static void spy_detach(struct ast_channel_spy *spy, struct ast_channel *chan)
{
ast_mutex_lock(&spy->lock);
/* We only need to poke them if they aren't already done */
if (spy->status != CHANSPY_DONE) {
spy->status = CHANSPY_STOP;
spy->chan = NULL;
if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
ast_cond_signal(&spy->trigger);
}
/* Print it out while we still have a lock so the structure can't go away (if signalled above) */
ast_log(LOG_DEBUG, "Spy %s removed from channel %s\n", spy->type, chan->name);
ast_mutex_unlock(&spy->lock);
return;
}
void ast_channel_spy_stop_by_type(struct ast_channel *chan, const char *type)
{
struct ast_channel_spy *spy;
struct ast_channel_spy *spy = NULL;
if (!chan->spies)
return;
AST_LIST_TRAVERSE(&chan->spies->list, spy, list) {
AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) {
ast_mutex_lock(&spy->lock);
if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) {
spy->status = CHANSPY_STOP;
if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
ast_cond_signal(&spy->trigger);
}
ast_mutex_unlock(&spy->lock);
AST_LIST_REMOVE_CURRENT(&chan->spies->list, list);
spy_detach(spy, chan);
} else
ast_mutex_unlock(&spy->lock);
}
AST_LIST_TRAVERSE_SAFE_END
spy_cleanup(chan);
}
void ast_channel_spy_trigger_wait(struct ast_channel_spy *spy)
@@ -1049,65 +1086,59 @@ void ast_channel_spy_trigger_wait(struct ast_channel_spy *spy)
void ast_channel_spy_remove(struct ast_channel *chan, struct ast_channel_spy *spy)
{
struct ast_frame *f;
if (!chan->spies)
return;
AST_LIST_REMOVE(&chan->spies->list, spy, list);
ast_mutex_lock(&spy->lock);
spy_detach(spy, chan);
spy_cleanup(chan);
}
spy->chan = NULL;
void ast_channel_spy_free(struct ast_channel_spy *spy)
{
struct ast_frame *f = NULL;
for (f = spy->read_queue.head; f; f = spy->read_queue.head) {
spy->read_queue.head = f->next;
ast_frfree(f);
}
if (spy->status == CHANSPY_DONE)
return;
/* Switch status to done in case we get called twice */
spy->status = CHANSPY_DONE;
/* Drop any frames in the queue */
for (f = spy->write_queue.head; f; f = spy->write_queue.head) {
spy->write_queue.head = f->next;
ast_frfree(f);
}
for (f = spy->read_queue.head; f; f= spy->read_queue.head) {
spy->read_queue.head = f->next;
ast_frfree(f);
}
/* Destroy the condition if in use */
if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
ast_cond_destroy(&spy->trigger);
ast_mutex_unlock(&spy->lock);
/* Destroy our mutex since it is no longer in use */
ast_mutex_destroy(&spy->lock);
ast_log(LOG_DEBUG, "Spy %s removed from channel %s\n",
spy->type, chan->name);
if (AST_LIST_EMPTY(&chan->spies->list)) {
if (chan->spies->read_translator.path)
ast_translator_free_path(chan->spies->read_translator.path);
if (chan->spies->write_translator.path)
ast_translator_free_path(chan->spies->write_translator.path);
free(chan->spies);
chan->spies = NULL;
}
return;
}
static void detach_spies(struct ast_channel *chan)
{
struct ast_channel_spy *spy;
struct ast_channel_spy *spy = NULL;
if (!chan->spies)
return;
/* Marking the spies as done is sufficient. Chanspy or spy users will get the picture. */
AST_LIST_TRAVERSE(&chan->spies->list, spy, list) {
ast_mutex_lock(&spy->lock);
spy->chan = NULL;
if (spy->status == CHANSPY_RUNNING)
spy->status = CHANSPY_DONE;
if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
ast_cond_signal(&spy->trigger);
ast_mutex_unlock(&spy->lock);
AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) {
AST_LIST_REMOVE_CURRENT(&chan->spies->list, list);
spy_detach(spy, chan);
}
AST_LIST_TRAVERSE_SAFE_END
AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list)
ast_channel_spy_remove(chan, spy);
AST_LIST_TRAVERSE_SAFE_END;
spy_cleanup(chan);
}
/*--- ast_softhangup_nolock: Softly hangup a channel, don't lock */

View File

@@ -94,6 +94,15 @@ int ast_channel_spy_add(struct ast_channel *chan, struct ast_channel_spy *spy);
*/
void ast_channel_spy_remove(struct ast_channel *chan, struct ast_channel_spy *spy);
/*!
\brief Free a spy.
\param spy The spy to free
\return nothing
Note: This function MUST NOT be called with the spy locked.
*/
void ast_channel_spy_free(struct ast_channel_spy *spy);
/*!
\brief Find all spies of a particular type on a channel and stop them.
\param chan The channel to operate on