[asterisk-commits] file: trunk r41959 - in /trunk: apps/ include/asterisk/ main/

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Sun Sep 3 16:30:37 MST 2006


Author: file
Date: Sun Sep  3 18:30:37 2006
New Revision: 41959

URL: http://svn.digium.com/view/asterisk?rev=41959&view=rev
Log:
Make the difference clear about what the responsibilities of the core and a spy are when it comes to spying on a channel. The core is responsible for adding a spy to a channel, feeding frames into the spy, removing the spy from the channel, and notifying the spy that is has been detached. The spy is responsible for reading frames in, and cleaning itself up. Each side will not try to do the other's job.

Modified:
    trunk/apps/app_chanspy.c
    trunk/apps/app_mixmonitor.c
    trunk/include/asterisk/chanspy.h
    trunk/main/channel.c

Modified: trunk/apps/app_chanspy.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_chanspy.c?rev=41959&r1=41958&r2=41959&view=diff
==============================================================================
--- trunk/apps/app_chanspy.c (original)
+++ trunk/apps/app_chanspy.c Sun Sep  3 18:30:37 2006
@@ -211,21 +211,6 @@
 	return res;
 }
 
-static void stop_spying(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 (!spy->chan)
-		return;
-
-	ast_channel_lock(spy->chan);
-	ast_channel_spy_remove(spy->chan, spy);
-	ast_channel_unlock(spy->chan);
-};
-
 /* Map 'volume' levels from -4 through +4 into
    decibel (dB) settings for channel drivers
 */
@@ -327,10 +312,11 @@
 	*/
 	while ((res = ast_waitfor(chan, -1) > -1) &&
 	       csth.spy.status == CHANSPY_RUNNING &&
-	       !ast_check_hangup(chan) &&
 	       csth.spy.chan) {
-		if (!(f = ast_read(chan)))
+		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
+			running = -1;
 			break;
+		}
 
 		if (ast_test_flag(flags, OPTION_WHISPER) &&
 		    (f->frametype == AST_FRAME_VOICE)) {
@@ -381,13 +367,16 @@
 	else
 		ast_deactivate_generator(chan);
 
-	stop_spying(&csth.spy);
+	/* If a channel still exists on our spy structure then we need to remove ourselves */
+        if (csth.spy.chan) {
+                csth.spy.status = CHANSPY_DONE;
+                ast_channel_spy_remove(csth.spy.chan, &csth.spy);
+        }
+	ast_channel_spy_free(&csth.spy);
 	
 	if (option_verbose >= 2)
 		ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
 	
-	ast_mutex_destroy(&csth.spy.lock);
-
 	return running;
 }
 
@@ -532,6 +521,8 @@
 				peer = NULL;
 			}
 		}
+		if (res == -1)
+			break;
 	}
 	
 	ast_clear_flag(chan, AST_FLAG_SPYING);

Modified: trunk/apps/app_mixmonitor.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_mixmonitor.c?rev=41959&r1=41958&r2=41959&view=diff
==============================================================================
--- trunk/apps/app_mixmonitor.c (original)
+++ trunk/apps/app_mixmonitor.c Sun Sep  3 18:30:37 2006
@@ -122,23 +122,6 @@
 	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_channel_lock(chan);
-	ast_channel_spy_remove(chan, spy);
-	ast_channel_unlock(chan);
-}
-
 static int startmon(struct ast_channel *chan, struct ast_channel_spy *spy) 
 {
 	struct ast_channel *peer;
@@ -176,9 +159,8 @@
 
 		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)))
@@ -194,15 +176,15 @@
 				next = AST_LIST_NEXT(f, frame_list);
 				if (write)
 					ast_writestream(mixmonitor->fs, f);
-				ast_frfree(f);
+				ast_frame_free(f, 0);
 			}
 		}
 	}
 
 	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);
 
@@ -211,8 +193,6 @@
 			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);
 

Modified: trunk/include/asterisk/chanspy.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/chanspy.h?rev=41959&r1=41958&r2=41959&view=diff
==============================================================================
--- trunk/include/asterisk/chanspy.h (original)
+++ trunk/include/asterisk/chanspy.h Sun Sep  3 18:30:37 2006
@@ -95,6 +95,15 @@
 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

Modified: trunk/main/channel.c
URL: http://svn.digium.com/view/asterisk/trunk/main/channel.c?rev=41959&r1=41958&r2=41959&view=diff
==============================================================================
--- trunk/main/channel.c (original)
+++ trunk/main/channel.c Sun Sep  3 18:30:37 2006
@@ -1203,22 +1203,61 @@
 	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) {
+		/* Indicate to the spy to stop */
+		spy->status = CHANSPY_STOP;
+		spy->chan = NULL;
+		/* Poke the spy if needed */
+		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)
@@ -1235,62 +1274,54 @@
 
 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->chan = NULL;
-
+	spy_detach(spy, chan);
+	spy_cleanup(chan);
+}
+
+void ast_channel_spy_free(struct ast_channel_spy *spy)
+{
+	struct ast_frame *f = NULL;
+
+	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 */
+	while ((f = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list)))
+		ast_frfree(f);
 	while ((f = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list)))
 		ast_frfree(f);
-	
-	while ((f = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list)))
-		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);
-
-	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;
-	}
+	/* Destroy our mutex since it is no longer in use */
+	ast_mutex_destroy(&spy->lock);
+
+	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_channel_spy_remove(chan, spy);
-	AST_LIST_TRAVERSE_SAFE_END;
+	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
+
+	spy_cleanup(chan);
 }
 
 /*! \brief Softly hangup a channel, don't lock */



More information about the asterisk-commits mailing list