[svn-commits] trunk r8850 - in /trunk: channel.c channels/chan_zap.c include/asterisk/frame.h

svn-commits at lists.digium.com svn-commits at lists.digium.com
Tue Jan 31 14:20:17 MST 2006


Author: kpfleming
Date: Sat Jan 28 23:07:04 2006
New Revision: 8850

URL: http://svn.digium.com/view/asterisk?rev=8850&view=rev
Log:
make ast_read() able to handle channel read()/exception() methods that return a chain of frames
cleanup code in ast_read()
add AST_FRAME_DTMF_BEGIN and AST_FRAME_DTMF_END so that variable-length DTMF events can be supported
teach chan_zap to send DTMF_BEGIN and DTMF_END when appropriate

Modified:
    trunk/channel.c
    trunk/channels/chan_zap.c
    trunk/include/asterisk/frame.h

Modified: trunk/channel.c
URL: http://svn.digium.com/view/asterisk/trunk/channel.c?rev=8850&r1=8849&r2=8850&view=diff
==============================================================================
--- trunk/channel.c (original)
+++ trunk/channel.c Sat Jan 28 23:07:04 2006
@@ -1904,6 +1904,7 @@
 	if (chan->readq) {
 		f = chan->readq;
 		chan->readq = f->next;
+		f->next = NULL;
 		/* Interpret hangup and return NULL */
 		if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
 			ast_frfree(f);
@@ -1928,103 +1929,126 @@
 		}
 	}
 
-
-	if (f && (f->frametype == AST_FRAME_VOICE)) {
-		if (dropaudio) {
-			ast_frfree(f);
-			f = &null_frame;
-		} else if (!(f->subclass & chan->nativeformats)) {
-			/* This frame can't be from the current native formats -- drop it on the
-			   floor */
-			ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n", chan->name, ast_getformatname(f->subclass), ast_getformatname(chan->nativeformats));
-			ast_frfree(f);
-			f = &null_frame;
-		} else {
-			if (chan->spies)
-				queue_frame_to_spies(chan, f, SPY_READ);
-
-			if (chan->monitor && chan->monitor->read_stream ) {
+	if (f) {
+		/* if the channel driver returned more than one frame, stuff the excess
+		   into the readq for the next ast_read call
+		*/
+		if (f->next) {
+			chan->readq = f->next;
+			f->next = NULL;
+		}
+
+		switch (f->frametype) {
+		case AST_FRAME_CONTROL:
+			if (f->subclass == AST_CONTROL_ANSWER) {
+				if (prestate == AST_STATE_UP) {
+					ast_log(LOG_DEBUG, "Dropping duplicate answer!\n");
+					f = &null_frame;
+				}
+				/* Answer the CDR */
+				ast_setstate(chan, AST_STATE_UP);
+				ast_cdr_answer(chan->cdr);
+			}
+			break;
+		case AST_FRAME_DTMF:
+			ast_log(LOG_DTMF, "DTMF '%c' received on %s\n", f->subclass, chan->name);
+			if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF)) {
+				if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2)
+					chan->dtmfq[strlen(chan->dtmfq)] = f->subclass;
+				else
+					ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name);
+				f = &null_frame;
+			}
+			break;
+		case AST_FRAME_DTMF_BEGIN:
+			ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass, chan->name);
+			break;
+		case AST_FRAME_DTMF_END:
+			ast_log(LOG_DTMF, "DTMF end '%c' received on %s\n", f->subclass, chan->name);
+			break;
+		case AST_FRAME_VOICE:
+			if (dropaudio) {
+				ast_frfree(f);
+				f = &null_frame;
+			} else if (!(f->subclass & chan->nativeformats)) {
+				/* This frame can't be from the current native formats -- drop it on the
+				   floor */
+				ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n",
+					chan->name, ast_getformatname(f->subclass), ast_getformatname(chan->nativeformats));
+				ast_frfree(f);
+				f = &null_frame;
+			} else {
+				if (chan->spies)
+					queue_frame_to_spies(chan, f, SPY_READ);
+				
+				if (chan->monitor && chan->monitor->read_stream ) {
 #ifndef MONITOR_CONSTANT_DELAY
-				int jump = chan->outsmpl - chan->insmpl - 4 * f->samples;
-				if (jump >= 0) {
-					if (ast_seekstream(chan->monitor->read_stream, jump + f->samples, SEEK_FORCECUR) == -1)
-						ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
-					chan->insmpl += jump + 4 * f->samples;
-				} else
-					chan->insmpl+= f->samples;
+					int jump = chan->outsmpl - chan->insmpl - 4 * f->samples;
+					if (jump >= 0) {
+						if (ast_seekstream(chan->monitor->read_stream, jump + f->samples, SEEK_FORCECUR) == -1)
+							ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
+						chan->insmpl += jump + 4 * f->samples;
+					} else
+						chan->insmpl+= f->samples;
 #else
-				int jump = chan->outsmpl - chan->insmpl;
-				if (jump - MONITOR_DELAY >= 0) {
-					if (ast_seekstream(chan->monitor->read_stream, jump - f->samples, SEEK_FORCECUR) == -1)
-						ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
-					chan->insmpl += jump;
-				} else
-					chan->insmpl += f->samples;
+					int jump = chan->outsmpl - chan->insmpl;
+					if (jump - MONITOR_DELAY >= 0) {
+						if (ast_seekstream(chan->monitor->read_stream, jump - f->samples, SEEK_FORCECUR) == -1)
+							ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
+						chan->insmpl += jump;
+					} else
+						chan->insmpl += f->samples;
 #endif
-				if (chan->monitor->state == AST_MONITOR_RUNNING) {
-					if (ast_writestream(chan->monitor->read_stream, f) < 0)
-						ast_log(LOG_WARNING, "Failed to write data to channel monitor read stream\n");
+					if (chan->monitor->state == AST_MONITOR_RUNNING) {
+						if (ast_writestream(chan->monitor->read_stream, f) < 0)
+							ast_log(LOG_WARNING, "Failed to write data to channel monitor read stream\n");
+					}
+				}
+
+				if (chan->readtrans) {
+					if (!(f = ast_translate(chan->readtrans, f, 1)))
+						f = &null_frame;
+				}
+
+				/* Run any generator sitting on the channel */
+				if (chan->generatordata) {
+					/* Mask generator data temporarily and apply.  If there is a timing function, it
+					   will be calling the generator instead */
+					void *tmp;
+					int res;
+					int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples);
+					
+					if (chan->timingfunc) {
+						ast_log(LOG_DEBUG, "Generator got voice, switching to phase locked mode\n");
+						ast_settimeout(chan, 0, NULL, NULL);
+					}
+					tmp = chan->generatordata;
+					chan->generatordata = NULL;
+					generate = chan->generator->generate;
+					res = generate(chan, tmp, f->datalen, f->samples);
+					chan->generatordata = tmp;
+					if (res) {
+						ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
+						ast_deactivate_generator(chan);
+					}
+				} else if (f->frametype == AST_FRAME_CNG) {
+					if (chan->generator && !chan->timingfunc && (chan->timingfd > -1)) {
+						ast_log(LOG_DEBUG, "Generator got CNG, switching to timed mode\n");
+						ast_settimeout(chan, 160, generator_force, chan);
+					}
 				}
 			}
-			if (chan->readtrans) {
-				f = ast_translate(chan->readtrans, f, 1);
-				if (!f)
-					f = &null_frame;
-			}
-		}
-	}
-
-	/* Make sure we always return NULL in the future */
-	if (!f) {
+		}
+	} else {
+		/* Make sure we always return NULL in the future */
 		chan->_softhangup |= AST_SOFTHANGUP_DEV;
 		if (chan->generator)
 			ast_deactivate_generator(chan);
 		/* End the CDR if appropriate */
 		if (chan->cdr)
 			ast_cdr_end(chan->cdr);
-	} else if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF) && f->frametype == AST_FRAME_DTMF) {
-		if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2)
-			chan->dtmfq[strlen(chan->dtmfq)] = f->subclass;
-		else
-			ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name);
-		f = &null_frame;
-	} else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
-		if (prestate == AST_STATE_UP) {
-			ast_log(LOG_DEBUG, "Dropping duplicate answer!\n");
-			f = &null_frame;
-		}
-		/* Answer the CDR */
-		ast_setstate(chan, AST_STATE_UP);
-		ast_cdr_answer(chan->cdr);
-	} 
-
-	/* Run any generator sitting on the line */
-	if (f && (f->frametype == AST_FRAME_VOICE) && chan->generatordata) {
-		/* Mask generator data temporarily and apply.  If there is a timing function, it
-		   will be calling the generator instead */
-		void *tmp;
-		int res;
-		int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples);
-
-		if (chan->timingfunc) {
-			ast_log(LOG_DEBUG, "Generator got voice, switching to phase locked mode\n");
-			ast_settimeout(chan, 0, NULL, NULL);
-		}
-		tmp = chan->generatordata;
-		chan->generatordata = NULL;
-		generate = chan->generator->generate;
-		res = generate(chan, tmp, f->datalen, f->samples);
-		chan->generatordata = tmp;
-		if (res) {
-			ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
-			ast_deactivate_generator(chan);
-		}
-	} else if (f && (f->frametype == AST_FRAME_CNG)) {
-		if (chan->generator && !chan->timingfunc && (chan->timingfd > -1)) {
-			ast_log(LOG_DEBUG, "Generator got CNG, switching to zap timed mode\n");
-			ast_settimeout(chan, 160, generator_force, chan);
-		}
-	}
+	}
+
 	/* High bit prints debugging */
 	if (chan->fin & 0x80000000)
 		ast_frame_dump(chan->name, f, "<<");
@@ -2033,6 +2057,7 @@
 	else
 		chan->fin++;
 	ast_mutex_unlock(&chan->lock);
+
 	return f;
 }
 
@@ -2269,6 +2294,11 @@
 		/* XXX Interpret control frames XXX */
 		ast_log(LOG_WARNING, "Don't know how to handle control frames yet\n");
 		break;
+	case AST_FRAME_DTMF_BEGIN:
+	case AST_FRAME_DTMF_END:
+		/* nothing to do with these yet */
+		res = 0;
+		break;
 	case AST_FRAME_DTMF:
 		ast_clear_flag(chan, AST_FLAG_BLOCKING);
 		ast_mutex_unlock(&chan->lock);
@@ -2295,7 +2325,7 @@
 		else
 			res = 0;
 		break;
-	default:
+	case AST_FRAME_VOICE:
 		if (chan->tech->write) {
 			/* Bypass translator if we're writing format in the raw write format.  This
 			   allows mixing of native / non-native formats */
@@ -2304,11 +2334,10 @@
 			else
 				f = (chan->writetrans) ? ast_translate(chan->writetrans, fr, 0) : fr;
 			if (f) {
-				if (f->frametype == AST_FRAME_VOICE && chan->spies)
+				if (chan->spies)
 					queue_frame_to_spies(chan, f, SPY_WRITE);
 
-				if( chan->monitor && chan->monitor->write_stream &&
-						f && ( f->frametype == AST_FRAME_VOICE ) ) {
+				if (chan->monitor && chan->monitor->write_stream) {
 #ifndef MONITOR_CONSTANT_DELAY
 					int jump = chan->insmpl - chan->outsmpl - 4 * f->samples;
 					if (jump >= 0) {
@@ -2336,13 +2365,6 @@
 			} else
 				res = 0;
 		}
-	}
-
-	/* It's possible this is a translated frame */
-	if (f && f->frametype == AST_FRAME_DTMF) {
-		ast_log(LOG_DTMF, "%s : %c\n", chan->name, f->subclass);
-	} else if (fr->frametype == AST_FRAME_DTMF) {
-		ast_log(LOG_DTMF, "%s : %c\n", chan->name, fr->subclass);
 	}
 
 	if (f && (f != fr))

Modified: trunk/channels/chan_zap.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_zap.c?rev=8850&r1=8849&r2=8850&view=diff
==============================================================================
--- trunk/channels/chan_zap.c (original)
+++ trunk/channels/chan_zap.c Sat Jan 28 23:07:04 2006
@@ -3560,12 +3560,14 @@
 	pthread_t threadid;
 	pthread_attr_t attr;
 	struct ast_channel *chan;
+	struct ast_frame dtmf_frame = { .frametype = AST_FRAME_DTMF };
 
 	pthread_attr_init(&attr);
 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
 	index = zt_get_index(ast, p, 0);
 	p->subs[index].f.frametype = AST_FRAME_NULL;
+	p->subs[index].f.subclass = 0;
 	p->subs[index].f.datalen = 0;
 	p->subs[index].f.samples = 0;
 	p->subs[index].f.mallocd = 0;
@@ -3590,12 +3592,17 @@
 		ast_log(LOG_DEBUG, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
 #ifdef ZAPATA_PRI
 		if (!p->proceeding && p->sig == SIG_PRI && p->pri && p->pri->overlapdial) {
-			p->subs[index].f.frametype = AST_FRAME_NULL;
-			p->subs[index].f.subclass = 0;
+			/* absorb event */
 		} else {
 #endif
-			p->subs[index].f.frametype = AST_FRAME_DTMF;
+			/* Send a DTMF event for 'legacy' channels and all applications,
+			   and a DTMF_BEGIN event for channels that handle variable duration
+			   DTMF events
+			*/
+			p->subs[index].f.frametype = AST_FRAME_DTMF_BEGIN;
 			p->subs[index].f.subclass = res & 0xff;
+			dtmf_frame.subclass = res & 0xff;
+			p->subs[index].f.next = ast_frdup(&dtmf_frame);
 #ifdef ZAPATA_PRI
 		}
 #endif
@@ -3606,10 +3613,13 @@
 
 	if (res & ZT_EVENT_DTMFDOWN) {
 		ast_log(LOG_DEBUG, "DTMF Down '%c'\n", res & 0xff);
-		p->subs[index].f.frametype = AST_FRAME_NULL;
-		p->subs[index].f.subclass = 0;
+		/* Mute conference */
 		zt_confmute(p, 1);
-		/* Mute conference, return null frame */
+		/* Send a DTMF_BEGIN event for devices that want variable
+		   duration DTMF events
+		*/
+		p->subs[index].f.frametype = AST_FRAME_DTMF_BEGIN;
+		p->subs[index].f.subclass = res & 0xff;
 		return &p->subs[index].f;
 	}
 
@@ -3705,8 +3715,7 @@
 								alarm2str(res), p->channel);
 			/* fall through intentionally */
 		case ZT_EVENT_ONHOOK:
-			if (p->radio)
-			{
+			if (p->radio) {
 				p->subs[index].f.frametype = AST_FRAME_CONTROL;
 				p->subs[index].f.subclass = AST_CONTROL_RADIO_UNKEY;
 				break;
@@ -3820,8 +3829,7 @@
 			break;
 		case ZT_EVENT_RINGOFFHOOK:
 			if (p->inalarm) break;
-			if (p->radio)
-			{
+			if (p->radio) {
 				p->subs[index].f.frametype = AST_FRAME_CONTROL;
 				p->subs[index].f.subclass = AST_CONTROL_RADIO_KEY;
 				break;

Modified: trunk/include/asterisk/frame.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/frame.h?rev=8850&r1=8849&r2=8850&view=diff
==============================================================================
--- trunk/include/asterisk/frame.h (original)
+++ trunk/include/asterisk/frame.h Sat Jan 28 23:07:04 2006
@@ -148,13 +148,19 @@
 #if defined(T38_SUPPORT)
 /*! Modem-over-IP data streams */
 #define AST_FRAME_MODEM		11
-
+#endif /* T38_SUPPORT */
+/*! DTMF begin event, subclass is the digit */
+#define AST_FRAME_DTMF_BEGIN	12
+/*! DTMF end event, subclass is the digit */
+#define AST_FRAME_DTMF_END	13
+
+#if defined(T38_SUPPORT)
 /* MODEM subclasses */
 /*! T.38 Fax-over-IP */
 #define AST_MODEM_T38		1
 /*! V.150 Modem-over-IP */
 #define AST_MODEM_V150		2
-#endif
+#endif /* T38_SUPPORT */
 
 /* HTML subclasses */
 /*! Sending a URL */



More information about the svn-commits mailing list