aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfile <file@f38db490-d61c-443f-a65b-d21fe96a405b>2006-09-05 20:02:48 +0000
committerfile <file@f38db490-d61c-443f-a65b-d21fe96a405b>2006-09-05 20:02:48 +0000
commit4095dc1815f82e9e0b61948958a268f86278206d (patch)
tree0a0758df6f24d736dce0c5d8b0f438e361c114b8
parent29b9b4cb0b97b71217c3a5df1b62195c7c4ae77f (diff)
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: http://svn.digium.com/svn/asterisk/branches/1.2@42054 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--apps/app_chanspy.c25
-rw-r--r--apps/app_mixmonitor.c24
-rw-r--r--channel.c111
-rw-r--r--include/asterisk/chanspy.h9
4 files changed, 90 insertions, 79 deletions
diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index 450b0a8b1..fe71bbef1 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -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;
}
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index fa4716df0..caff40181 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -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);
@@ -199,8 +181,6 @@ static void *mixmonitor_thread(void *obj)
ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process);
ast_safe_system(mixmonitor->post_process);
}
-
- ast_mutex_destroy(&mixmonitor->spy.lock);
ast_closestream(mixmonitor->fs);
diff --git a/channel.c b/channel.c
index 5a751fca3..327334390 100644
--- a/channel.c
+++ b/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_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);
-
- ast_log(LOG_DEBUG, "Spy %s removed from channel %s\n",
- spy->type, chan->name);
+ /* Destroy our mutex since it is no longer in use */
+ ast_mutex_destroy(&spy->lock);
- 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 */
diff --git a/include/asterisk/chanspy.h b/include/asterisk/chanspy.h
index dcdceccf7..c6a64f592 100644
--- a/include/asterisk/chanspy.h
+++ b/include/asterisk/chanspy.h
@@ -95,6 +95,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
\param type A character string identifying the type of spies to be stopped