[asterisk-commits] dvossel: branch dvossel/awesomehooks r287058 - in /team/dvossel/awesomehooks:...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Sep 15 18:09:18 CDT 2010


Author: dvossel
Date: Wed Sep 15 18:09:14 2010
New Revision: 287058

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=287058
Log:
adds awesomehook interception points in ast_read, ast_write, and ast_indicate

Modified:
    team/dvossel/awesomehooks/include/asterisk/awesomehook.h
    team/dvossel/awesomehooks/main/awesomehook.c
    team/dvossel/awesomehooks/main/channel.c

Modified: team/dvossel/awesomehooks/include/asterisk/awesomehook.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/awesomehooks/include/asterisk/awesomehook.h?view=diff&rev=287058&r1=287057&r2=287058
==============================================================================
--- team/dvossel/awesomehooks/include/asterisk/awesomehook.h (original)
+++ team/dvossel/awesomehooks/include/asterisk/awesomehook.h Wed Sep 15 18:09:14 2010
@@ -148,6 +148,8 @@
  * even NULL.  There is nothing to keep up with after this function. If the frame is modified, the
  * awesomehook callback is in charge of any memory management associated with that modification.
  *
+ * \note the list's channel owner _MUST_ be locked while calling this function.
+ *
  * \param awesomehook list to push event to.
  * \param frame being pushed to the awesomehook list.
  *
@@ -162,12 +164,22 @@
  * even NULL.  There is nothing to keep up with after this function. If the frame is modified, the
  * awesomehook callback is in charge of any memory management associated with that modification.
  *
+ * \note the list's channel owner _MUST_ be locked while calling this function.
+ *
  * \param awesomehook list to push event to.
  * \param frame being pushed to the awesomehook list.
  *
  * \return The resulting frame after being viewed and modified by the awesomehook callbacks.
  */
 struct ast_frame *ast_awesomehook_list_write_event(struct ast_awesomehook_list *awesomehooks, struct ast_frame *frame);
+
+/*!
+ * \brief Determine if an awesomehook list is empty or not
+ * \param the awesomehook list
+ * \retval 0, not empty
+ * \retval 1, is empty
+ */
+int ast_awesomehook_list_is_empty(struct ast_awesomehook_list *awesomehooks);
 
 /*!
  * \brief Set the awesomehook's custom data storage pointer.

Modified: team/dvossel/awesomehooks/main/awesomehook.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/awesomehooks/main/awesomehook.c?view=diff&rev=287058&r1=287057&r2=287058
==============================================================================
--- team/dvossel/awesomehooks/main/awesomehook.c (original)
+++ team/dvossel/awesomehooks/main/awesomehook.c Wed Sep 15 18:09:14 2010
@@ -18,7 +18,7 @@
 
 /*! \file
  *
- * \brief Awesomehooks Architecture
+ * \brief AwesomeHooks Architecture
  *
  * \author David Vossel <dvossel at digium.com>
  */
@@ -75,6 +75,38 @@
 	return 0;
 }
 
+static void awesomehook_detach_and_destroy(struct ast_awesomehook *awesomehook)
+{
+	struct ast_frame *frame;
+	awesomehook_update_status(awesomehook, AST_AWESOMEHOOK_STATUS_DETACHED);
+	frame = awesomehook->event_cb(awesomehook, awesomehook->chan, NULL, AST_AWESOMEHOOK_EVENT_DETACHED);
+	/* never assume anything about this function. If you can return a frame during
+	 * the detached event, then assume someone will. */
+	if (frame) {
+		ast_frfree(frame);
+	}
+	awesomehook->chan = NULL;
+	awesomehook_destroy(awesomehook);
+}
+
+static struct ast_frame *awesomehook_list_push_event(struct ast_awesomehook_list *awesomehooks, struct ast_frame *frame, enum ast_awesomehook_event event)
+{
+	struct ast_awesomehook *awesomehook;
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&awesomehooks->list, awesomehook, list) {
+		/* check to see if this hook was signaled for detachment, if so do not push the
+		 * read/write event.  Instead detach from list and destroy */
+		if (awesomehook->status == AST_AWESOMEHOOK_STATUS_DETACHED) {
+			AST_LIST_REMOVE_CURRENT(list);
+			awesomehook_detach_and_destroy(awesomehook);
+			continue;
+		}
+		frame = awesomehook->event_cb(awesomehook, awesomehook->chan, frame, event);
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
+	return frame;
+}
+
 struct ast_awesomehook *ast_awesomehook_alloc(ast_awesomehook_event_callback event_cb, ast_awesomehook_destroy_callback destroy_cb)
 {
 	struct ast_awesomehook *awesomehook;
@@ -111,20 +143,6 @@
 	return 0;
 }
 
-static void awesomehook_detach_and_destroy(struct ast_awesomehook *awesomehook)
-{
-	struct ast_frame *frame;
-	awesomehook_update_status(awesomehook, AST_AWESOMEHOOK_STATUS_DETACHED);
-	frame = awesomehook->event_cb(awesomehook, awesomehook->chan, NULL, AST_AWESOMEHOOK_EVENT_DETACHED);
-	/* never assume anything about this function. If you can return a frame during
-	 * the detached event, then assume someone will. */
-	if (frame) {
-		ast_frfree(frame);
-	}
-	awesomehook->chan = NULL;
-	awesomehook_destroy(awesomehook);
-}
-
 int ast_awesomehook_signal_destroy(struct ast_awesomehook *awesomehook)
 {
 	/* This signals to the channel to detach and destroy the hook on the next read or write */
@@ -145,22 +163,10 @@
 	return 0;
 }
 
-static struct ast_frame *awesomehook_list_push_event(struct ast_awesomehook_list *awesomehooks, struct ast_frame *frame, enum ast_awesomehook_event event)
+
+int ast_awesomehook_list_is_empty(struct ast_awesomehook_list *awesomehooks)
 {
-	struct ast_awesomehook *awesomehook;
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&awesomehooks->list, awesomehook, list) {
-		/* check to see if this hook was signaled for detachment, if so do not push the
-		 * read/write event.  Instead detach from list and destroy */
-		if (awesomehook->status == AST_AWESOMEHOOK_STATUS_DETACHED) {
-			AST_LIST_REMOVE_CURRENT(list);
-			awesomehook_detach_and_destroy(awesomehook);
-			continue;
-		}
-		frame = awesomehook->event_cb(awesomehook, awesomehook->chan, frame, event);
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	return frame;
+	return AST_LIST_EMPTY(&awesomehooks->list) ? 1 : 0;
 }
 
 struct ast_frame *ast_awesomehook_list_write_event(struct ast_awesomehook_list *awesomehooks, struct ast_frame *frame)

Modified: team/dvossel/awesomehooks/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/awesomehooks/main/channel.c?view=diff&rev=287058&r1=287057&r2=287058
==============================================================================
--- team/dvossel/awesomehooks/main/channel.c (original)
+++ team/dvossel/awesomehooks/main/channel.c Wed Sep 15 18:09:14 2010
@@ -2633,6 +2633,8 @@
 		chan->audiohooks = NULL;
 	}
 
+	ast_awesomehook_list_destroy(&chan->awesomehooks);
+
 	ast_autoservice_stop(chan);
 
 	if (chan->masq) {
@@ -3749,6 +3751,10 @@
 	 * easily detect when ast_read() is called without properly using ast_waitfor().
 	 */
 	chan->fdno = -1;
+
+	/* Perform the awesomehook read event here. After the frame enters the awesomehook list
+	 * there is no telling what will happen, <insert mad scientist laugh here>!!! */
+	f = ast_awesomehook_list_read_event(&chan->awesomehooks, f);
 
 	if (f) {
 		struct ast_frame *readq_tail = AST_LIST_LAST(&chan->readq);
@@ -4143,14 +4149,42 @@
 	enum ast_control_frame_type condition = _condition;
 	struct ast_tone_zone_sound *ts = NULL;
 	int res;
+	/* this frame is used by awesomehooks. if it is set, we must free it at the end of this function */
+	struct ast_frame *awesome_frame = NULL;
 
 	ast_channel_lock(chan);
 
 	/* Don't bother if the channel is about to go away, anyway. */
 	if (ast_test_flag(chan, AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) {
 		ast_channel_unlock(chan);
-		return -1;
-	}
+		res = -1;
+		goto indicate_cleanup;
+	}
+
+	if (!ast_awesomehook_list_is_empty(&chan->awesomehooks)) {
+		/* Do awesomehooks now, do it, go, go now */
+		struct ast_frame frame = {
+			.frametype = AST_FRAME_CONTROL,
+			.subclass.integer = condition,
+			.data.ptr = (void *) data, /* this cast from const is only okay because we do the ast_frdup below */
+			.datalen = datalen
+		};
+
+		/* we have now committed to freeing this frame */
+		awesome_frame = ast_frdup(&frame);
+
+		/* who knows what we will get back! the anticipation is killing me. */
+		if (!(awesome_frame = ast_awesomehook_list_read_event(&chan->awesomehooks, &frame))) {
+			ast_channel_unlock(chan);
+			res = 0;
+			goto indicate_cleanup;
+		}
+
+		condition = awesome_frame->subclass.integer;
+		data = awesome_frame->data.ptr;
+		datalen = awesome_frame->datalen;
+	}
+
 	switch (condition) {
 	case AST_CONTROL_CONNECTED_LINE:
 		{
@@ -4196,7 +4230,8 @@
 		if (is_visible_indication(condition)) {
 			chan->visible_indication = condition;
 		}
-		return 0;
+		res = 0;
+		goto indicate_cleanup;
 	}
 
 	/* The channel driver does not support this indication, let's fake
@@ -4208,14 +4243,16 @@
 	if (_condition < 0) {
 		/* Stop any tones that are playing */
 		ast_playtones_stop(chan);
-		return 0;
+		res = 0;
+		goto indicate_cleanup;
 	}
 
 	/* Handle conditions that we have tones for. */
 	switch (condition) {
 	case _XXX_AST_CONTROL_T38:
 		/* deprecated T.38 control frame */
-		return -1;
+		res = -1;
+		goto indicate_cleanup;
 	case AST_CONTROL_T38_PARAMETERS:
 		/* there is no way to provide 'default' behavior for these
 		 * control frames, so we need to return failure, but there
@@ -4224,7 +4261,7 @@
 		 * so just return right now. in addition, we want to return
 		 * whatever value the channel driver returned, in case it
 		 * has some meaning.*/
-		return res;
+		goto indicate_cleanup;
 	case AST_CONTROL_RINGING:
 		ts = ast_get_indication_tone(chan->zone, "ring");
 		/* It is common practice for channel drivers to return -1 if trying
@@ -4286,6 +4323,11 @@
 		ast_log(LOG_WARNING, "Unable to handle indication %d for '%s'\n", condition, chan->name);
 	}
 
+indicate_cleanup:
+	if (awesome_frame) {
+		ast_frfree(awesome_frame);
+	}
+
 	return res;
 }
 
@@ -4572,6 +4614,14 @@
 		res = 0;	/* XXX explain, why 0 ? */
 		goto done;
 	}
+
+	/* Perform the awesomehook write event here. After the frame enters the awesomehook list
+	 * there is no telling what will happen, how awesome is that!!! */
+	if (!(fr = ast_awesomehook_list_write_event(&chan->awesomehooks, fr))) {
+		res = 0;
+		goto done;
+	}
+
 	if (chan->generatordata && (!fr->src || strcasecmp(fr->src, "ast_prod"))) {
 		if (ast_test_flag(chan, AST_FLAG_WRITE_INT)) {
 				ast_deactivate_generator(chan);




More information about the asterisk-commits mailing list