[asterisk-commits] rmudgett: branch rmudgett/align_analog r295987 - /team/rmudgett/align_analog/...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Nov 23 12:41:59 CST 2010


Author: rmudgett
Date: Tue Nov 23 12:41:54 2010
New Revision: 295987

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=295987
Log:
Oneway audio to SIP phone from FXS port after FXS port gets a CallWaiting pip.

The FXS connected phone has to have CW/CID support to fail, as it will
send back a DTMF 'A' or 'D' when it's ready to receive CallerID.  A normal
phone with no CID never fails.  Also the SIP phone does not hear MOH when
the CW call is answered.

The DTMF end frame is suppressed when the phone acknowledges the CW signal
for CID.  The problem is the DTMF begin frame needs to be suppressed as
well.  The DTMF begin frame is causing SIP to start sending the DTMF RTP
frames.  Since the DTMF end frame is suppressed, SIP will not stop sending
those DTMF RTP packets.

* Suppress the DTMF begin and end frames when the channel driver is
looking for DTMF digits.

* Fixed a couple issues caused by not cleaning up the CID spill if you
answer the call while it is sending the CID spill.

* Fixed not sending CW/CID spill to the phone when the call is natively
bridged.

Modified:
    team/rmudgett/align_analog/channels/chan_dahdi.c
    team/rmudgett/align_analog/channels/sig_analog.c
    team/rmudgett/align_analog/channels/sig_analog.h
    team/rmudgett/align_analog/channels/sig_pri.h

Modified: team/rmudgett/align_analog/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/align_analog/channels/chan_dahdi.c?view=diff&rev=295987&r1=295986&r2=295987
==============================================================================
--- team/rmudgett/align_analog/channels/chan_dahdi.c (original)
+++ team/rmudgett/align_analog/channels/chan_dahdi.c Tue Nov 23 12:41:54 2010
@@ -1053,7 +1053,7 @@
 	struct timeval	dtmfcid_delay;  /*!< Time value used for allow line to settle */
 	int callingpres;				/*!< The value of calling presentation that we're going to use when placing a PRI call */
 	int callwaitingrepeat;				/*!< How many samples to wait before repeating call waiting */
-	int cidcwexpire;				/*!< When to expire our muting for CID/CW */
+	int cidcwexpire;				/*!< When to stop waiting for CID/CW CAS response (In samples) */
 	/*! \brief Analog caller ID waveform sample buffer */
 	unsigned char *cidspill;
 	/*! \brief Position in the cidspill buffer to send out next. */
@@ -1074,7 +1074,12 @@
 	 * characters are processed.
 	 */
 	int stripmsd;
-	/*! \brief BOOLEAN. XXX Meaning what?? */
+	/*!
+	 * \brief TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
+	 * \note
+	 * After CAS is sent, the call waiting caller id will be sent if the phone
+	 * gives a positive reply.
+	 */
 	int callwaitcas;
 	/*! \brief Number of call waiting rings. */
 	int callwaitrings;
@@ -1839,8 +1844,6 @@
 	return 0;
 }
 
-static int send_callerid(struct dahdi_pvt *p);
-
 static int my_stop_callwait(void *pvt)
 {
 	struct dahdi_pvt *p = pvt;
@@ -1850,7 +1853,9 @@
 	return 0;
 }
 
+static int send_callerid(struct dahdi_pvt *p);
 static int save_conference(struct dahdi_pvt *p);
+static int restore_conference(struct dahdi_pvt *p);
 
 static int my_callwait(void *pvt)
 {
@@ -1860,6 +1865,11 @@
 		ast_log(LOG_WARNING, "Spill already exists?!?\n");
 		ast_free(p->cidspill);
 	}
+
+	/*
+	 * SAS: Subscriber Alert Signal, 440Hz for 300ms
+	 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
+	 */
 	if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
 		return -1;
 	save_conference(p);
@@ -1898,6 +1908,8 @@
 				caller->id.number.str,
 				AST_LAW(p));
 		} else {
+			ast_verb(3, "CPE supports Call Waiting Caller*ID.  Sending '%s/%s'\n",
+				caller->id.name.str, caller->id.number.str);
 			p->callwaitcas = 0;
 			p->cidcwexpire = 0;
 			p->cidlen = ast_callerid_callwaiting_generate(p->cidspill,
@@ -1978,68 +1990,72 @@
 
 static inline int dahdi_confmute(struct dahdi_pvt *p, int muted);
 
-static void my_handle_dtmfup(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
+static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
 {
 	struct ast_frame *f = *dest;
 	struct dahdi_pvt *p = pvt;
 	int idx = analogsub_to_dahdisub(analog_index);
 
-	ast_debug(1, "DTMF digit: %c on %s\n", f->subclass.integer, ast->name);
+	ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
+		f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
+		f->subclass.integer, f->subclass.integer, ast->name);
 
 	if (f->subclass.integer == 'f') {
-		/* Fax tone -- Handle and return NULL */
-		if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
-			/* If faxbuffers are configured, use them for the fax transmission */
-			if (p->usefaxbuffers && !p->bufferoverrideinuse) {
-				struct dahdi_bufferinfo bi = {
-					.txbufpolicy = p->faxbuf_policy,
-					.bufsize = p->bufsize,
-					.numbufs = p->faxbuf_no
-				};
-				int res;
-
-				if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
-					ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
+		if (f->frametype == AST_FRAME_DTMF_END) {
+			/* Fax tone -- Handle and return NULL */
+			if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
+				/* If faxbuffers are configured, use them for the fax transmission */
+				if (p->usefaxbuffers && !p->bufferoverrideinuse) {
+					struct dahdi_bufferinfo bi = {
+						.txbufpolicy = p->faxbuf_policy,
+						.bufsize = p->bufsize,
+						.numbufs = p->faxbuf_no
+					};
+					int res;
+
+					if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
+						ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
+					} else {
+						p->bufferoverrideinuse = 1;
+					}
+				}
+				p->faxhandled = 1;
+				if (p->dsp) {
+					p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
+					ast_dsp_set_features(p->dsp, p->dsp_features);
+					ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast->name);
+				}
+				if (strcmp(ast->exten, "fax")) {
+					const char *target_context = S_OR(ast->macrocontext, ast->context);
+
+					/* We need to unlock 'ast' here because ast_exists_extension has the
+					 * potential to start autoservice on the channel. Such action is prone
+					 * to deadlock.
+					 */
+					ast_mutex_unlock(&p->lock);
+					ast_channel_unlock(ast);
+					if (ast_exists_extension(ast, target_context, "fax", 1,
+						S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
+						ast_channel_lock(ast);
+						ast_mutex_lock(&p->lock);
+						ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
+						/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
+						pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
+						if (ast_async_goto(ast, target_context, "fax", 1))
+							ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
+					} else {
+						ast_channel_lock(ast);
+						ast_mutex_lock(&p->lock);
+						ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+					}
 				} else {
-					p->bufferoverrideinuse = 1;
-				}
-			}
-			p->faxhandled = 1;
-			if (p->dsp) {
-				p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
-				ast_dsp_set_features(p->dsp, p->dsp_features);
-				ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast->name);
-			}
-			if (strcmp(ast->exten, "fax")) {
-				const char *target_context = S_OR(ast->macrocontext, ast->context);
-
-				/* We need to unlock 'ast' here because ast_exists_extension has the
-				 * potential to start autoservice on the channel. Such action is prone
-				 * to deadlock.
-				 */
-				ast_mutex_unlock(&p->lock);
-				ast_channel_unlock(ast);
-				if (ast_exists_extension(ast, target_context, "fax", 1,
-					S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
-					ast_channel_lock(ast);
-					ast_mutex_lock(&p->lock);
-					ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
-					/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
-					pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
-					if (ast_async_goto(ast, target_context, "fax", 1))
-						ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
-				} else {
-					ast_channel_lock(ast);
-					ast_mutex_lock(&p->lock);
-					ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+					ast_debug(1, "Already in a fax extension, not redirecting\n");
 				}
 			} else {
-				ast_debug(1, "Already in a fax extension, not redirecting\n");
-			}
-		} else {
-			ast_debug(1, "Fax already handled\n");
-		}
-		dahdi_confmute(p, 0);
+				ast_debug(1, "Fax already handled\n");
+			}
+			dahdi_confmute(p, 0);
+		}
 		p->subs[idx].f.frametype = AST_FRAME_NULL;
 		p->subs[idx].f.subclass.integer = 0;
 		*dest = &p->subs[idx].f;
@@ -2228,10 +2244,10 @@
 static void my_cancel_cidspill(void *pvt)
 {
 	struct dahdi_pvt *p = pvt;
-	if (p->cidspill) {
-		ast_free(p->cidspill);
-		p->cidspill = NULL;
-	}
+
+	ast_free(p->cidspill);
+	p->cidspill = NULL;
+	restore_conference(p);
 }
 
 static int my_confmute(void *pvt, int mute)
@@ -3504,7 +3520,7 @@
 	.lock_private = my_lock_private,
 	.unlock_private = my_unlock_private,
 	.deadlock_avoidance_private = my_deadlock_avoidance_private,
-	.handle_dtmfup = my_handle_dtmfup,
+	.handle_dtmf = my_handle_dtmf,
 	.wink = my_wink,
 	.new_ast_channel = my_new_analog_ast_channel,
 	.dsp_set_digitmode = my_dsp_set_digitmode,
@@ -5049,12 +5065,10 @@
 			ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
 			return -1;
 		}
-	}
-	ast_debug(1, "Restored conferencing\n");
+		ast_debug(1, "Restored conferencing\n");
+	}
 	return 0;
 }
-
-static int send_callerid(struct dahdi_pvt *p);
 
 static int send_cwcidspill(struct dahdi_pvt *p)
 {
@@ -5140,6 +5154,11 @@
 		ast_log(LOG_WARNING, "Spill already exists?!?\n");
 		ast_free(p->cidspill);
 	}
+
+	/*
+	 * SAS: Subscriber Alert Signal, 440Hz for 300ms
+	 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
+	 */
 	if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
 		return -1;
 	save_conference(p);
@@ -5615,9 +5634,7 @@
 			break;
 		}
 	}
-	if (p->cidspill) {
-		ast_free(p->cidspill);
-	}
+	ast_free(p->cidspill);
 	if (p->use_smdi)
 		ast_smdi_interface_unref(p->smdi_iface);
 	if (p->mwi_event_sub)
@@ -6342,8 +6359,7 @@
 	p->oprmode = 0;
 	ast->tech_pvt = NULL;
 hangup_out:
-	if (p->cidspill)
-		ast_free(p->cidspill);
+	ast_free(p->cidspill);
 	p->cidspill = NULL;
 
 	ast_mutex_unlock(&p->lock);
@@ -7037,6 +7053,23 @@
 		return AST_BRIDGE_RETRY;
 	}
 
+	if (p0->callwaitingcallerid || p1->callwaitingcallerid) {
+		/*
+		 * Call Waiting Caller ID requires DTMF detection to know if it
+		 * can send the CID spill.
+		 *
+		 * For now, don't attempt to native bridge if either channel
+		 * needs DTMF detection.  There is code below to handle it
+		 * properly until DTMF is actually seen, but due to currently
+		 * unresolved issues it's ignored...
+		 */
+		ast_mutex_unlock(&p0->lock);
+		ast_mutex_unlock(&p1->lock);
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return AST_BRIDGE_FAILED_NOWARN;
+	}
+
 #if defined(HAVE_PRI)
 	if ((dahdi_sig_pri_lib_handles(p0->sig)
 			&& ((struct sig_pri_chan *) p0->sig_pvt)->no_b_channel)
@@ -7474,87 +7507,98 @@
 	return DAHDI_ALARM_NONE;
 }
 
-static void dahdi_handle_dtmfup(struct ast_channel *ast, int idx, struct ast_frame **dest)
+static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
 {
 	struct dahdi_pvt *p = ast->tech_pvt;
 	struct ast_frame *f = *dest;
 
-	ast_debug(1, "DTMF digit: %c on %s\n", (int) f->subclass.integer, ast->name);
+	ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
+		f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
+		f->subclass.integer, f->subclass.integer, ast->name);
 
 	if (p->confirmanswer) {
-		ast_debug(1, "Confirm answer on %s!\n", ast->name);
-		/* Upon receiving a DTMF digit, consider this an answer confirmation instead
-		   of a DTMF digit */
-		p->subs[idx].f.frametype = AST_FRAME_CONTROL;
-		p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
+		if (f->frametype == AST_FRAME_DTMF_END) {
+			ast_debug(1, "Confirm answer on %s!\n", ast->name);
+			/* Upon receiving a DTMF digit, consider this an answer confirmation instead
+			   of a DTMF digit */
+			p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+			p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
+			/* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
+			p->confirmanswer = 0;
+		} else {
+			p->subs[idx].f.frametype = AST_FRAME_NULL;
+			p->subs[idx].f.subclass.integer = 0;
+		}
 		*dest = &p->subs[idx].f;
-		/* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
-		p->confirmanswer = 0;
 	} else if (p->callwaitcas) {
-		if ((f->subclass.integer == 'A') || (f->subclass.integer == 'D')) {
-			ast_debug(1, "Got some DTMF, but it's for the CAS\n");
-			if (p->cidspill)
+		if (f->frametype == AST_FRAME_DTMF_END) {
+			if ((f->subclass.integer == 'A') || (f->subclass.integer == 'D')) {
+				ast_debug(1, "Got some DTMF, but it's for the CAS\n");
 				ast_free(p->cidspill);
-			send_cwcidspill(p);
-		}
-		p->callwaitcas = 0;
+				p->cidspill = NULL;
+				send_cwcidspill(p);
+			}
+			p->callwaitcas = 0;
+		}
 		p->subs[idx].f.frametype = AST_FRAME_NULL;
 		p->subs[idx].f.subclass.integer = 0;
 		*dest = &p->subs[idx].f;
 	} else if (f->subclass.integer == 'f') {
-		/* Fax tone -- Handle and return NULL */
-		if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
-			/* If faxbuffers are configured, use them for the fax transmission */
-			if (p->usefaxbuffers && !p->bufferoverrideinuse) {
-				struct dahdi_bufferinfo bi = {
-					.txbufpolicy = p->faxbuf_policy,
-					.bufsize = p->bufsize,
-					.numbufs = p->faxbuf_no
-				};
-				int res;
-
-				if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
-					ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
+		if (f->frametype == AST_FRAME_DTMF_END) {
+			/* Fax tone -- Handle and return NULL */
+			if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
+				/* If faxbuffers are configured, use them for the fax transmission */
+				if (p->usefaxbuffers && !p->bufferoverrideinuse) {
+					struct dahdi_bufferinfo bi = {
+						.txbufpolicy = p->faxbuf_policy,
+						.bufsize = p->bufsize,
+						.numbufs = p->faxbuf_no
+					};
+					int res;
+
+					if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
+						ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
+					} else {
+						p->bufferoverrideinuse = 1;
+					}
+				}
+				p->faxhandled = 1;
+				if (p->dsp) {
+					p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
+					ast_dsp_set_features(p->dsp, p->dsp_features);
+					ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast->name);
+				}
+				if (strcmp(ast->exten, "fax")) {
+					const char *target_context = S_OR(ast->macrocontext, ast->context);
+
+					/* We need to unlock 'ast' here because ast_exists_extension has the
+					 * potential to start autoservice on the channel. Such action is prone
+					 * to deadlock.
+					 */
+					ast_mutex_unlock(&p->lock);
+					ast_channel_unlock(ast);
+					if (ast_exists_extension(ast, target_context, "fax", 1,
+						S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
+						ast_channel_lock(ast);
+						ast_mutex_lock(&p->lock);
+						ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
+						/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
+						pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
+						if (ast_async_goto(ast, target_context, "fax", 1))
+							ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
+					} else {
+						ast_channel_lock(ast);
+						ast_mutex_lock(&p->lock);
+						ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+					}
 				} else {
-					p->bufferoverrideinuse = 1;
-				}
-			}
-			p->faxhandled = 1;
-			if (p->dsp) {
-				p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
-				ast_dsp_set_features(p->dsp, p->dsp_features);
-				ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast->name);
-			}
-			if (strcmp(ast->exten, "fax")) {
-				const char *target_context = S_OR(ast->macrocontext, ast->context);
-
-				/* We need to unlock 'ast' here because ast_exists_extension has the
-				 * potential to start autoservice on the channel. Such action is prone
-				 * to deadlock.
-				 */
-				ast_mutex_unlock(&p->lock);
-				ast_channel_unlock(ast);
-				if (ast_exists_extension(ast, target_context, "fax", 1,
-					S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
-					ast_channel_lock(ast);
-					ast_mutex_lock(&p->lock);
-					ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
-					/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
-					pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
-					if (ast_async_goto(ast, target_context, "fax", 1))
-						ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
-				} else {
-					ast_channel_lock(ast);
-					ast_mutex_lock(&p->lock);
-					ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+					ast_debug(1, "Already in a fax extension, not redirecting\n");
 				}
 			} else {
-				ast_debug(1, "Already in a fax extension, not redirecting\n");
-			}
-		} else {
-			ast_debug(1, "Fax already handled\n");
-		}
-		dahdi_confmute(p, 0);
+				ast_debug(1, "Fax already handled\n");
+			}
+			dahdi_confmute(p, 0);
+		}
 		p->subs[idx].f.frametype = AST_FRAME_NULL;
 		p->subs[idx].f.subclass.integer = 0;
 		*dest = &p->subs[idx].f;
@@ -7632,7 +7676,7 @@
 			p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
 			p->subs[idx].f.subclass.integer = res & 0xff;
 		}
-		dahdi_handle_dtmfup(ast, idx, &f);
+		dahdi_handle_dtmf(ast, idx, &f);
 		return f;
 	}
 
@@ -7642,6 +7686,7 @@
 		dahdi_confmute(p, 1);
 		p->subs[idx].f.frametype = AST_FRAME_DTMF_BEGIN;
 		p->subs[idx].f.subclass.integer = res & 0xff;
+		dahdi_handle_dtmf(ast, idx, &f);
 		return &p->subs[idx].f;
 	}
 
@@ -7959,11 +8004,12 @@
 				p->subs[SUB_REAL].needringing = 0;
 				dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
 				ast_debug(1, "channel %d answered\n", p->channel);
-				if (p->cidspill) {
-					/* Cancel any running CallerID spill */
-					ast_free(p->cidspill);
-					p->cidspill = NULL;
-				}
+
+				/* Cancel any running CallerID spill */
+				ast_free(p->cidspill);
+				p->cidspill = NULL;
+				restore_conference(p);
+
 				p->dialing = 0;
 				p->callwaitcas = 0;
 				if (p->confirmanswer) {
@@ -8128,6 +8174,11 @@
 		case SIG_FXOKS:
 			ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
 				idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
+
+			/* Cancel any running CallerID spill */
+			ast_free(p->cidspill);
+			p->cidspill = NULL;
+			restore_conference(p);
 			p->callwaitcas = 0;
 
 			if (idx != SUB_REAL) {
@@ -8781,21 +8832,26 @@
 			return &p->subs[idx].f;
 		}
 	}
-	/* Ensure the CW timer decrements only on a single subchannel */
-	if (p->callwaitingrepeat && dahdi_get_index(ast, p, 1) == SUB_REAL) {
-		p->callwaitingrepeat--;
-	}
-	if (p->cidcwexpire)
-		p->cidcwexpire--;
-	/* Repeat callwaiting */
-	if (p->callwaitingrepeat == 1) {
-		p->callwaitrings++;
-		dahdi_callwait(ast);
-	}
-	/* Expire CID/CW */
-	if (p->cidcwexpire == 1) {
-		ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
-		restore_conference(p);
+	if (idx == SUB_REAL) {
+		/* Ensure the CW timers decrement only on a single subchannel */
+		if (p->cidcwexpire) {
+			--p->cidcwexpire;
+
+			/* Expire CID/CW */
+			if (p->cidcwexpire == 1) {
+				ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
+				restore_conference(p);
+			}
+		}
+		if (p->callwaitingrepeat) {
+			--p->callwaitingrepeat;
+
+			/* Repeat callwaiting tone */
+			if (p->callwaitingrepeat == 1) {
+				++p->callwaitrings;
+				dahdi_callwait(ast);
+			}
+		}
 	}
 	if (p->subs[idx].linear) {
 		p->subs[idx].f.datalen = READ_SIZE * 2;
@@ -8899,11 +8955,19 @@
 	} else
 		f = &p->subs[idx].f;
 
-	if (f && (f->frametype == AST_FRAME_DTMF)) {
-		if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
-			analog_handle_dtmfup(p->sig_pvt, ast, idx, &f);
-		} else
-			dahdi_handle_dtmfup(ast, idx, &f);
+	if (f) {
+		switch (f->frametype) {
+		case AST_FRAME_DTMF_BEGIN:
+		case AST_FRAME_DTMF_END:
+			if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+				analog_handle_dtmf(p->sig_pvt, ast, idx, &f);
+			} else {
+				dahdi_handle_dtmf(ast, idx, &f);
+			}
+			break;
+		default:
+			break;
+		}
 	}
 
 	/* If we have a fake_event, trigger exception to handle it */
@@ -8968,7 +9032,8 @@
 		return 0;
 	}
 	if (p->cidspill) {
-		ast_debug(1, "Dropping frame since I've still got a callerid spill\n");
+		ast_debug(1, "Dropping frame since I've still got a callerid spill on %s...\n",
+			ast->name);
 		return 0;
 	}
 	/* Return if it's not valid data */
@@ -10880,11 +10945,9 @@
 				handled = 1;
 
 				if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
-					ast_log(LOG_WARNING, "Unable to finsh RP-AS: %s mwi send aborted\n", strerror(errno));
-					if(pvt->cidspill) {
-						ast_free(pvt->cidspill);
-						pvt->cidspill = NULL;
-					}
+					ast_log(LOG_WARNING, "Unable to finish RP-AS: %s mwi send aborted\n", strerror(errno));
+					ast_free(pvt->cidspill);
+					pvt->cidspill = NULL;
 					pvt->mwisend_data.mwisend_current = MWI_SEND_DONE;
 					pvt->mwisendactive = 0;
 				} else {
@@ -10961,11 +11024,12 @@
 			res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
 			if (res && (errno == EBUSY))
 				break;
-			if (i->cidspill) {
-				/* Cancel VMWI spill */
-				ast_free(i->cidspill);
-				i->cidspill = NULL;
-			}
+
+			/* Cancel VMWI spill */
+			ast_free(i->cidspill);
+			i->cidspill = NULL;
+			restore_conference(i);
+
 			if (i->immediate) {
 				dahdi_enable_ec(i);
 				/* The channel is immediately up.  Start right away */

Modified: team/rmudgett/align_analog/channels/sig_analog.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/align_analog/channels/sig_analog.c?view=diff&rev=295987&r1=295986&r2=295987
==============================================================================
--- team/rmudgett/align_analog/channels/sig_analog.c (original)
+++ team/rmudgett/align_analog/channels/sig_analog.c Tue Nov 23 12:41:54 2010
@@ -624,10 +624,10 @@
 	return -1;
 }
 
-static void analog_cb_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
-{
-	if (p->calls->handle_dtmfup) {
-		p->calls->handle_dtmfup(p->chan_pvt, ast, analog_index, dest);
+static void analog_cb_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
+{
+	if (p->calls->handle_dtmf) {
+		p->calls->handle_dtmf(p->chan_pvt, ast, analog_index, dest);
 	}
 }
 
@@ -1574,35 +1574,45 @@
 	}
 }
 
-void analog_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub idx, struct ast_frame **dest)
+void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub idx, struct ast_frame **dest)
 {
 	struct ast_frame *f = *dest;
 
-	ast_debug(1, "DTMF digit: %c on %s\n", f->subclass.integer, ast->name);
+	ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
+		f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
+		f->subclass.integer, f->subclass.integer, ast->name);
 
 	if (analog_check_confirmanswer(p)) {
-		ast_debug(1, "Confirm answer on %s!\n", ast->name);
-		/* Upon receiving a DTMF digit, consider this an answer confirmation instead
-		of a DTMF digit */
-		p->subs[idx].f.frametype = AST_FRAME_CONTROL;
-		p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
+		if (f->frametype == AST_FRAME_DTMF_END) {
+			ast_debug(1, "Confirm answer on %s!\n", ast->name);
+			/* Upon receiving a DTMF digit, consider this an answer confirmation instead
+			of a DTMF digit */
+			p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+			p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
+			/* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
+			analog_set_confirmanswer(p, 0);
+		} else {
+			p->subs[idx].f.frametype = AST_FRAME_NULL;
+			p->subs[idx].f.subclass.integer = 0;
+		}
 		*dest = &p->subs[idx].f;
-		/* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
-		analog_set_confirmanswer(p, 0);
 	} else if (p->callwaitcas) {
-		if ((f->subclass.integer == 'A') || (f->subclass.integer == 'D')) {
-			ast_debug(1, "Got some DTMF, but it's for the CAS\n");
-			p->caller.id.name.str = p->callwait_name;
-			p->caller.id.number.str = p->callwait_num;
-			analog_send_callerid(p, 1, &p->caller);
-		}
-		if (analog_handles_digit(f))
-			p->callwaitcas = 0;
+		if (f->frametype == AST_FRAME_DTMF_END) {
+			if ((f->subclass.integer == 'A') || (f->subclass.integer == 'D')) {
+				ast_debug(1, "Got some DTMF, but it's for the CAS\n");
+				p->caller.id.name.str = p->callwait_name;
+				p->caller.id.number.str = p->callwait_num;
+				analog_send_callerid(p, 1, &p->caller);
+			}
+			if (analog_handles_digit(f)) {
+				p->callwaitcas = 0;
+			}
+		}
 		p->subs[idx].f.frametype = AST_FRAME_NULL;
 		p->subs[idx].f.subclass.integer = 0;
 		*dest = &p->subs[idx].f;
 	} else {
-		analog_cb_handle_dtmfup(p, ast, idx, dest);
+		analog_cb_handle_dtmf(p, ast, idx, dest);
 	}
 }
 
@@ -2631,7 +2641,7 @@
 		analog_confmute(p, 0);
 		p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
 		p->subs[idx].f.subclass.integer = res & 0xff;
-		analog_handle_dtmfup(p, ast, idx, &f);
+		analog_handle_dtmf(p, ast, idx, &f);
 		return f;
 	}
 
@@ -2641,6 +2651,7 @@
 		analog_confmute(p, 1);
 		p->subs[idx].f.frametype = AST_FRAME_DTMF_BEGIN;
 		p->subs[idx].f.subclass.integer = res & 0xff;
+		analog_handle_dtmf(p, ast, idx, &f);
 		return f;
 	}
 
@@ -2890,7 +2901,10 @@
 				analog_set_needringing(p, 0);
 				analog_off_hook(p);
 				ast_debug(1, "channel %d answered\n", p->channel);
+
+				/* Cancel any running CallerID spill */
 				analog_cancel_cidspill(p);
+
 				analog_set_dialing(p, 0);
 				p->callwaitcas = 0;
 				if (analog_check_confirmanswer(p)) {
@@ -3050,6 +3064,8 @@
 			ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
 				idx, analog_get_sub_fd(p, ANALOG_SUB_REAL), analog_get_sub_fd(p, ANALOG_SUB_CALLWAIT), analog_get_sub_fd(p, ANALOG_SUB_THREEWAY));
 
+			/* Cancel any running CallerID spill */
+			analog_cancel_cidspill(p);
 			p->callwaitcas = 0;
 
 			if (idx != ANALOG_SUB_REAL) {
@@ -3568,7 +3584,10 @@
 			if (res && (errno == EBUSY)) {
 				break;
 			}
+
+			/* Cancel VMWI spill */
 			analog_cancel_cidspill(i);
+
 			if (i->immediate) {
 				analog_set_echocanceller(i, 1);
 				/* The channel is immediately up.  Start right away */

Modified: team/rmudgett/align_analog/channels/sig_analog.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/align_analog/channels/sig_analog.h?view=diff&rev=295987&r1=295986&r2=295987
==============================================================================
--- team/rmudgett/align_analog/channels/sig_analog.h (original)
+++ team/rmudgett/align_analog/channels/sig_analog.h Tue Nov 23 12:41:54 2010
@@ -134,10 +134,10 @@
 	/* Do deadlock avoidance for the private signaling structure lock.  */
 	void (* const deadlock_avoidance_private)(void *pvt);
 
-	/* Function which is called back to handle any other DTMF up events that are received.  Called by analog_handle_event.  Why is this
+	/* Function which is called back to handle any other DTMF events that are received.  Called by analog_handle_event.  Why is this
 	 * important to use, instead of just directly using events received before they are passed into the library?  Because sometimes,
 	 * (CWCID) the library absorbs DTMF events received. */
-	void (* const handle_dtmfup)(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest);
+	void (* const handle_dtmf)(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest);
 
 	int (* const get_event)(void *pvt);
 	int (* const wait_event)(void *pvt);
@@ -360,7 +360,7 @@
 
 int analog_config_complete(struct analog_pvt *p);
 
-void analog_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub index, struct ast_frame **dest);
+void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub index, struct ast_frame **dest);
 
 enum analog_cid_start analog_str_to_cidstart(const char *value);
 

Modified: team/rmudgett/align_analog/channels/sig_pri.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/align_analog/channels/sig_pri.h?view=diff&rev=295987&r1=295986&r2=295987
==============================================================================
--- team/rmudgett/align_analog/channels/sig_pri.h (original)
+++ team/rmudgett/align_analog/channels/sig_pri.h Tue Nov 23 12:41:54 2010
@@ -90,10 +90,10 @@
 	void (* const unlock_private)(void *pvt);
 	/* Lock the private in the signalling private structure.  ... */
 	void (* const lock_private)(void *pvt);
-	/* Function which is called back to handle any other DTMF up events that are received.  Called by analog_handle_event.  Why is this
+	/* Function which is called back to handle any other DTMF events that are received.  Called by analog_handle_event.  Why is this
 	 * important to use, instead of just directly using events received before they are passed into the library?  Because sometimes,
 	 * (CWCID) the library absorbs DTMF events received. */
-	//void (* const handle_dtmfup)(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest);
+	//void (* const handle_dtmf)(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest);
 
 	//int (* const dial_digits)(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop);
 	int (* const play_tone)(void *pvt, enum sig_pri_tone tone);




More information about the asterisk-commits mailing list