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;
|
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
|
/* Map 'volume' levels from -4 through +4 into
|
||||||
decibel (dB) settings for channel drivers
|
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);
|
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) {
|
if (option_verbose >= 2) {
|
||||||
ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
|
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;
|
running = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_mutex_destroy(&csth.spy.lock);
|
ast_channel_spy_free(&csth.spy);
|
||||||
|
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
@@ -109,23 +109,6 @@ AST_APP_OPTIONS(mixmonitor_opts, {
|
|||||||
AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
|
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)
|
static int startmon(struct ast_channel *chan, struct ast_channel_spy *spy)
|
||||||
{
|
{
|
||||||
struct ast_channel *peer;
|
struct ast_channel *peer;
|
||||||
@@ -164,9 +147,8 @@ static void *mixmonitor_thread(void *obj)
|
|||||||
|
|
||||||
ast_channel_spy_trigger_wait(&mixmonitor->spy);
|
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;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!(f = ast_channel_spy_read_frame(&mixmonitor->spy, SAMPLES_PER_FRAME)))
|
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);
|
ast_mutex_unlock(&mixmonitor->spy.lock);
|
||||||
|
|
||||||
stopmon(&mixmonitor->spy);
|
ast_channel_spy_free(&mixmonitor->spy);
|
||||||
|
|
||||||
if (option_verbose > 1)
|
if (option_verbose > 1)
|
||||||
ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);
|
ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);
|
||||||
@@ -199,8 +181,6 @@ static void *mixmonitor_thread(void *obj)
|
|||||||
ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process);
|
ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process);
|
||||||
ast_safe_system(mixmonitor->post_process);
|
ast_safe_system(mixmonitor->post_process);
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_mutex_destroy(&mixmonitor->spy.lock);
|
|
||||||
|
|
||||||
ast_closestream(mixmonitor->fs);
|
ast_closestream(mixmonitor->fs);
|
||||||
|
|
||||||
|
111
channel.c
111
channel.c
@@ -1017,22 +1017,59 @@ int ast_channel_spy_add(struct ast_channel *chan, struct ast_channel_spy *spy)
|
|||||||
return 0;
|
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)
|
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)
|
if (!chan->spies)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AST_LIST_TRAVERSE(&chan->spies->list, spy, list) {
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) {
|
||||||
ast_mutex_lock(&spy->lock);
|
ast_mutex_lock(&spy->lock);
|
||||||
if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) {
|
if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) {
|
||||||
spy->status = CHANSPY_STOP;
|
ast_mutex_unlock(&spy->lock);
|
||||||
if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
|
AST_LIST_REMOVE_CURRENT(&chan->spies->list, list);
|
||||||
ast_cond_signal(&spy->trigger);
|
spy_detach(spy, chan);
|
||||||
}
|
} else
|
||||||
ast_mutex_unlock(&spy->lock);
|
ast_mutex_unlock(&spy->lock);
|
||||||
}
|
}
|
||||||
|
AST_LIST_TRAVERSE_SAFE_END
|
||||||
|
spy_cleanup(chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_channel_spy_trigger_wait(struct ast_channel_spy *spy)
|
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)
|
void ast_channel_spy_remove(struct ast_channel *chan, struct ast_channel_spy *spy)
|
||||||
{
|
{
|
||||||
struct ast_frame *f;
|
|
||||||
|
|
||||||
if (!chan->spies)
|
if (!chan->spies)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AST_LIST_REMOVE(&chan->spies->list, spy, list);
|
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) {
|
if (spy->status == CHANSPY_DONE)
|
||||||
spy->read_queue.head = f->next;
|
return;
|
||||||
ast_frfree(f);
|
|
||||||
}
|
/* 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) {
|
for (f = spy->write_queue.head; f; f = spy->write_queue.head) {
|
||||||
spy->write_queue.head = f->next;
|
spy->write_queue.head = f->next;
|
||||||
ast_frfree(f);
|
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)
|
if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
|
||||||
ast_cond_destroy(&spy->trigger);
|
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",
|
return;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void detach_spies(struct ast_channel *chan)
|
static void detach_spies(struct ast_channel *chan)
|
||||||
{
|
{
|
||||||
struct ast_channel_spy *spy;
|
struct ast_channel_spy *spy = NULL;
|
||||||
|
|
||||||
if (!chan->spies)
|
if (!chan->spies)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Marking the spies as done is sufficient. Chanspy or spy users will get the picture. */
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) {
|
||||||
AST_LIST_TRAVERSE(&chan->spies->list, spy, list) {
|
AST_LIST_REMOVE_CURRENT(&chan->spies->list, list);
|
||||||
ast_mutex_lock(&spy->lock);
|
spy_detach(spy, chan);
|
||||||
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_END
|
||||||
|
|
||||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list)
|
spy_cleanup(chan);
|
||||||
ast_channel_spy_remove(chan, spy);
|
|
||||||
AST_LIST_TRAVERSE_SAFE_END;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--- ast_softhangup_nolock: Softly hangup a channel, don't lock */
|
/*--- 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);
|
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.
|
\brief Find all spies of a particular type on a channel and stop them.
|
||||||
\param chan The channel to operate on
|
\param chan The channel to operate on
|
||||||
|
Reference in New Issue
Block a user