mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-18 18:58:22 +00:00
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:
@@ -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;
|
||||
}
|
||||
|
@@ -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
109
channel.c
@@ -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 */
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user