[asterisk-commits] seanbright: branch group/1.6.1-maintenance r265082 - in /team/group/1.6.1-mai...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri May 21 13:28:32 CDT 2010


Author: seanbright
Date: Fri May 21 13:28:29 2010
New Revision: 265082

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=265082
Log:
Merged revisions 264997 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

................
  r264997 | mmichelson | 2010-05-21 12:44:27 -0400 (Fri, 21 May 2010) | 38 lines
  
  Merged revisions 264996 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r264996 | mmichelson | 2010-05-21 11:28:34 -0500 (Fri, 21 May 2010) | 32 lines
    
    Allow ast_safe_sleep to defer specific frames until after the sleep has concluded.
    
    From reviewboard
    
    Background:
    A Digium customer discovered a somewhat odd bug. The setup is that parties A
    and B are bridged, and party A places party B on hold. While party B is 
    listening to hold music, he mashes a bunch of DTMF. Party A takes party
    B off hold while this is happening, but party B continues to hear hold
    music. I could reproduce this about 1 in 5 times.
    
    The issue:
    When DTMF features are enabled and a user presses keys, the channel that
    the DTMF is streamed to is placed in an ast_safe_sleep for 100 ms, the
    duration of the emulated tone. If an AST_CONTROL_UNHOLD frame is read
    from the channel during the sleep, the frame is dropped. Thus the
    unhold indication is never made to the channel that was originally placed
    on hold.
    
    The fix:
    Originally, I discussed with Kevin possible ways of fixing the specific
    problem reported. However, we determined that the same type of problem
    could happen in other situations where ast_safe_sleep() is used. Using
    autoservice as a model, I modified ast_safe_sleep_conditional() to
    defer specific frame types so they can be re-queued once the sleep has
    finished. I made a common function for determining if a frame should
    be deferred so that there are not two identical switch blocks to
    maintain.
    
    Review: https://reviewboard.asterisk.org/r/674/
  ........
................

Modified:
    team/group/1.6.1-maintenance/   (props changed)
    team/group/1.6.1-maintenance/include/asterisk/channel.h
    team/group/1.6.1-maintenance/main/autoservice.c
    team/group/1.6.1-maintenance/main/channel.c

Propchange: team/group/1.6.1-maintenance/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.

Modified: team/group/1.6.1-maintenance/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/group/1.6.1-maintenance/include/asterisk/channel.h?view=diff&rev=265082&r1=265081&r2=265082
==============================================================================
--- team/group/1.6.1-maintenance/include/asterisk/channel.h (original)
+++ team/group/1.6.1-maintenance/include/asterisk/channel.h Fri May 21 13:28:29 2010
@@ -1134,7 +1134,23 @@
   \return Returns < 0 on  failure, 0 if nothing ever arrived, and the # of ms remaining otherwise */
 int ast_waitfor(struct ast_channel *chan, int ms);
 
-/*! \brief Wait for a specified amount of time, looking for hangups
+/*!
+ * \brief Should we keep this frame for later?
+ *
+ * There are functions such as ast_safe_sleep which will service a channel to
+ * ensure that it does not have a large backlog of queued frames. When this
+ * happens, we want to hold on to specific frame types and just drop
+ * others. This function will tell if the frame we just read should be held
+ * onto.
+ *
+ * \param frame The frame we just read
+ * \retval 1 frame should be kept
+ * \retval 0 frame should be dropped
+ */
+int ast_is_deferrable_frame(const struct ast_frame *frame);
+
+/*!
+ * \brief Wait for a specified amount of time, looking for hangups
  * \param chan channel to wait for
  * \param ms length of time in milliseconds to sleep
  * Waits for a specified amount of time, servicing the channel as required.

Modified: team/group/1.6.1-maintenance/main/autoservice.c
URL: http://svnview.digium.com/svn/asterisk/team/group/1.6.1-maintenance/main/autoservice.c?view=diff&rev=265082&r1=265081&r2=265082
==============================================================================
--- team/group/1.6.1-maintenance/main/autoservice.c (original)
+++ team/group/1.6.1-maintenance/main/autoservice.c Fri May 21 13:28:29 2010
@@ -128,32 +128,8 @@
 			 * thread in charge of this channel will know. */
 
 			defer_frame = &hangup_frame;
-		} else {
-
-			/* Do not add a default entry in this switch statement.  Each new
-			 * frame type should be addressed directly as to whether it should
-			 * be queued up or not. */
-
-			switch (f->frametype) {
-			/* Save these frames */
-			case AST_FRAME_DTMF_END:
-			case AST_FRAME_CONTROL:
-			case AST_FRAME_TEXT:
-			case AST_FRAME_IMAGE:
-			case AST_FRAME_HTML:
-				defer_frame = f;
-				break;
-
-			/* Throw these frames away */
-			case AST_FRAME_DTMF_BEGIN:
-			case AST_FRAME_VOICE:
-			case AST_FRAME_VIDEO:
-			case AST_FRAME_NULL:
-			case AST_FRAME_IAX:
-			case AST_FRAME_CNG:
-			case AST_FRAME_MODEM:
-				break;
-			}
+		} else if (ast_is_deferrable_frame(f)) {
+			defer_frame = f;
 		}
 
 		if (defer_frame) {

Modified: team/group/1.6.1-maintenance/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/group/1.6.1-maintenance/main/channel.c?view=diff&rev=265082&r1=265081&r2=265082
==============================================================================
--- team/group/1.6.1-maintenance/main/channel.c (original)
+++ team/group/1.6.1-maintenance/main/channel.c Fri May 21 13:28:29 2010
@@ -1307,12 +1307,41 @@
 	return channel_find_locked(chan, NULL, 0, context, exten);
 }
 
+int ast_is_deferrable_frame(const struct ast_frame *frame)
+{
+	/* Do not add a default entry in this switch statement.  Each new
+	 * frame type should be addressed directly as to whether it should
+	 * be queued up or not.
+	 */
+	switch (frame->frametype) {
+	case AST_FRAME_DTMF_END:
+	case AST_FRAME_CONTROL:
+	case AST_FRAME_TEXT:
+	case AST_FRAME_IMAGE:
+	case AST_FRAME_HTML:
+		return 1;
+
+	case AST_FRAME_DTMF_BEGIN:
+	case AST_FRAME_VOICE:
+	case AST_FRAME_VIDEO:
+	case AST_FRAME_NULL:
+	case AST_FRAME_IAX:
+	case AST_FRAME_CNG:
+	case AST_FRAME_MODEM:
+		return 0;
+	}
+	return 0;
+}
+
 /*! \brief Wait, look for hangups and condition arg */
 int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(void*), void *data)
 {
 	struct ast_frame *f;
 	struct ast_silence_generator *silgen = NULL;
 	int res = 0;
+	AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
+
+	AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
 
 	/* If no other generator is present, start silencegen while waiting */
 	if (ast_opt_transmit_silence && !chan->generatordata) {
@@ -1320,6 +1349,7 @@
 	}
 
 	while (ms > 0) {
+		struct ast_frame *dup_f = NULL;
 		if (cond && ((*cond)(data) == 0)) {
 			break;
 		}
@@ -1334,7 +1364,18 @@
 				res = -1;
 				break;
 			}
-			ast_frfree(f);
+
+			if (!ast_is_deferrable_frame(f)) {
+				ast_frfree(f);
+				continue;
+			}
+			
+			if ((dup_f = ast_frisolate(f))) {
+				if (dup_f != f) {
+					ast_frfree(f);
+				}
+				AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
+			}
 		}
 	}
 
@@ -1342,6 +1383,19 @@
 	if (silgen) {
 		ast_channel_stop_silence_generator(chan, silgen);
 	}
+
+	/* We need to free all the deferred frames, but we only need to
+	 * queue the deferred frames if there was no error and no
+	 * hangup was received
+	 */
+	ast_channel_lock(chan);
+	while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
+		if (!res) {
+			ast_queue_frame_head(chan, f);
+		}
+		ast_frfree(f);
+	}
+	ast_channel_unlock(chan);
 
 	return res;
 }




More information about the asterisk-commits mailing list