diff --git a/apps/app_fax.c b/apps/app_fax.c
index bd6bdf9f63de5eea6c3acfcfd05706a291d938dc..e2b7a90ee2f7f38549e238e75be41f47b018c142 100644
--- a/apps/app_fax.c
+++ b/apps/app_fax.c
@@ -710,6 +710,7 @@ static int sndfax_exec(struct ast_channel *chan, const char *data)
 	int res = 0;
 	char *parse;
 	fax_session session;
+	char restore_digit_detect = 0;
 
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(file_name);
@@ -744,8 +745,32 @@ static int sndfax_exec(struct ast_channel *chan, const char *data)
 	session.chan = chan;
 	session.finished = 0;
 
+	/* get current digit detection mode, then disable digit detection if enabled */
+	{
+		int dummy = sizeof(restore_digit_detect);
+
+		ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
+	}
+
+	if (restore_digit_detect) {
+		char new_digit_detect = 0;
+
+		ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
+	}
+
+	/* disable FAX tone detection if enabled */
+	{
+		char new_fax_detect = 0;
+
+		ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
+	}
+
 	res = transmit(&session);
 
+	if (restore_digit_detect) {
+		ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
+	}
+
 	return res;
 }
 
@@ -754,6 +779,7 @@ static int rcvfax_exec(struct ast_channel *chan, const char *data)
 	int res = 0;
 	char *parse;
 	fax_session session;
+	char restore_digit_detect = 0;
 
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(file_name);
@@ -788,8 +814,32 @@ static int rcvfax_exec(struct ast_channel *chan, const char *data)
 	session.chan = chan;
 	session.finished = 0;
 
+	/* get current digit detection mode, then disable digit detection if enabled */
+	{
+		int dummy = sizeof(restore_digit_detect);
+
+		ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
+	}
+
+	if (restore_digit_detect) {
+		char new_digit_detect = 0;
+
+		ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
+	}
+
+	/* disable FAX tone detection if enabled */
+	{
+		char new_fax_detect = 0;
+
+		ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
+	}
+
 	res = transmit(&session);
 
+	if (restore_digit_detect) {
+		ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
+	}
+
 	return res;
 }
 
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 3567aa9e9e07f1410c29efd4d4038a476895893c..bd11e51ea55f344e4117645a9f6359f8bbbb317e 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -1507,6 +1507,7 @@ static struct ast_frame *dahdi_exception(struct ast_channel *ast);
 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
+static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
 static int handle_init_event(struct dahdi_pvt *i, int event);
 static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value);
@@ -1529,6 +1530,7 @@ static const struct ast_channel_tech dahdi_tech = {
 	.indicate = dahdi_indicate,
 	.fixup = dahdi_fixup,
 	.setoption = dahdi_setoption,
+	.queryoption = dahdi_queryoption,
 	.func_channel_read = dahdi_func_read,
 	.func_channel_write = dahdi_func_write,
 };
@@ -5890,6 +5892,66 @@ static int dahdi_answer(struct ast_channel *ast)
 	return res;
 }
 
+static void disable_dtmf_detect(struct dahdi_pvt *p)
+{
+	int val = 0;
+
+	p->ignoredtmf = 1;
+
+	ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
+
+	if (!p->hardwaredtmf && p->dsp) {
+		p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
+		ast_dsp_set_features(p->dsp, p->dsp_features);
+	}
+}
+
+static void enable_dtmf_detect(struct dahdi_pvt *p)
+{
+	int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
+
+	if (p->channel == CHAN_PSEUDO)
+		return;
+
+	p->ignoredtmf = 0;
+
+	ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
+
+	if (!p->hardwaredtmf && p->dsp) {
+		p->dsp_features |= DSP_FEATURE_DIGIT_DETECT;
+		ast_dsp_set_features(p->dsp, p->dsp_features);
+	}
+}
+
+static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
+{
+	char *cp;
+	struct dahdi_pvt *p = chan->tech_pvt;
+
+	/* all supported options require data */
+	if (!data || (*datalen < 1)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	switch (option) {
+	case AST_OPTION_DIGIT_DETECT:
+		cp = (char *) data;
+		*cp = p->ignoredtmf ? 0 : 1;
+		ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp ? "en" : "dis", chan->name);
+		break;
+	case AST_OPTION_FAX_DETECT:
+		cp = (char *) data;
+		*cp = (p->callprogress & CALLPROGRESS_FAX) ? 0 : 1;
+		ast_debug(1, "Reporting fax tone detection %sabled on %s\n", *cp ? "en" : "dis", chan->name);
+		break;
+	}
+
+	errno = 0;
+
+	return 0;
+}
+
 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
 {
 	char *cp;
@@ -6072,6 +6134,29 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
 			dahdi_disable_ec(p);
 		}
 		break;
+	case AST_OPTION_DIGIT_DETECT:
+		cp = (char *) data;
+		ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", chan->name);
+		if (*cp) {
+			enable_dtmf_detect(p);
+		} else {
+			disable_dtmf_detect(p);
+		}
+		break;
+	case AST_OPTION_FAX_DETECT:
+		cp = (char *) data;
+		if (p->dsp) {
+			ast_debug(1, "%sabling fax tone detection on %s\n", *cp ? "En" : "Dis", chan->name);
+			if (*cp) {
+				p->callprogress |= CALLPROGRESS_FAX;
+				p->dsp_features |= DSP_FEATURE_FAX_DETECT;
+			} else {
+				p->callprogress &= ~CALLPROGRESS_FAX;
+				p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
+			}
+			ast_dsp_set_features(p->dsp, p->dsp_features);
+		}
+		break;
 	default:
 		return -1;
 	}
@@ -6279,39 +6364,6 @@ static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
 	ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
 }
 
-static void disable_dtmf_detect(struct dahdi_pvt *p)
-{
-	int val;
-
-	p->ignoredtmf = 1;
-
-	val = 0;
-	ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
-
-	if (!p->hardwaredtmf && p->dsp) {
-		p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
-		ast_dsp_set_features(p->dsp, p->dsp_features);
-	}
-}
-
-static void enable_dtmf_detect(struct dahdi_pvt *p)
-{
-	int val;
-
-	if (p->channel == CHAN_PSEUDO)
-		return;
-
-	p->ignoredtmf = 0;
-
-	val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
-	ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
-
-	if (!p->hardwaredtmf && p->dsp) {
-		p->dsp_features |= DSP_FEATURE_DIGIT_DETECT;
-		ast_dsp_set_features(p->dsp, p->dsp_features);
-	}
-}
-
 static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
 {
 	struct ast_channel *who;
@@ -6814,6 +6866,10 @@ static void dahdi_handle_dtmfup(struct ast_channel *ast, int idx, struct ast_fra
 				}
 			}
 			p->faxhandled = 1;
+			p->callprogress &= ~CALLPROGRESS_FAX;
+			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);
 
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 4158ba5d485ff68c1abb77a92e7d3e510363d6ea..4fd774b94494d1a3d76557ffecd6e23192deea60 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1833,7 +1833,7 @@ struct sip_pvt {
 	int laststate;				/*!< SUBSCRIBE: Last known extension state */
 	int dialogver;				/*!< SUBSCRIBE: Version for subscription dialog-info */
 
-	struct ast_dsp *vad;			/*!< Inband DTMF Detection dsp */
+	struct ast_dsp *dsp;			/*!< Inband DTMF Detection dsp */
 
 	struct sip_peer *relatedpeer;		/*!< If this dialog is related to a peer, which one 
 							Used in peerpoke, mwi subscriptions */
@@ -4076,21 +4076,62 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp
 	return res;
 }
 
+static void enable_digit_detect(struct sip_pvt *p)
+{
+	if (p->dsp) {
+		return;
+	}
+
+	if (!(p->dsp = ast_dsp_new())) {
+		return;
+	}
+
+	ast_dsp_set_features(p->dsp, DSP_FEATURE_DIGIT_DETECT);
+	if (global_relaxdtmf) {
+		ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
+	}
+}
+
+static void disable_digit_detect(struct sip_pvt *p)
+{
+	if (p->dsp) {
+		ast_dsp_free(p->dsp);
+		p->dsp = NULL;
+	}
+}
+
 /*! \brief Set an option on a SIP dialog */
 static int sip_setoption(struct ast_channel *chan, int option, void *data, int datalen)
 {
 	int res = -1;
 	struct sip_pvt *p = chan->tech_pvt;
 
-	if (option == AST_OPTION_FORMAT_READ) {
-		int format = *(int *)data;
-		res = ast_rtp_instance_set_read_format(p->rtp, format);
-	} else if (option == AST_OPTION_FORMAT_WRITE) {
-		int format = *(int *)data;
-		res = ast_rtp_instance_set_write_format(p->rtp, format);
-	} else if (option == AST_OPTION_MAKE_COMPATIBLE) {
-		struct ast_channel *peer = data;
-		res = ast_rtp_instance_make_compatible(chan, p->rtp, peer);
+	switch (option) {
+	case AST_OPTION_FORMAT_READ:
+		res = ast_rtp_instance_set_read_format(p->rtp, *(int *) data);
+		break;
+	case AST_OPTION_FORMAT_WRITE:
+		res = ast_rtp_instance_set_write_format(p->rtp, *(int *) data);
+		break;
+	case AST_OPTION_MAKE_COMPATIBLE:
+		res = ast_rtp_instance_make_compatible(chan, p->rtp, (struct ast_channel *) data);
+		break;
+	case AST_OPTION_DIGIT_DETECT:
+		if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) ||
+		    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
+			char *cp = (char *) data;
+
+			ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", chan->name);
+			if (*cp) {
+				enable_digit_detect(p);
+			} else {
+				disable_digit_detect(p);
+			}
+			res = 0;
+		}
+		break;
+	default:
+		break;
 	}
 
 	return res;
@@ -4102,6 +4143,7 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
 	int res = -1;
 	enum ast_t38_state state = T38_STATE_UNAVAILABLE;
 	struct sip_pvt *p = (struct sip_pvt *) chan->tech_pvt;
+	char *cp;
 
 	switch (option) {
 	case AST_OPTION_T38_STATE:
@@ -4134,6 +4176,11 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
 		*((enum ast_t38_state *) data) = state;
 		res = 0;
 
+		break;
+	case AST_OPTION_DIGIT_DETECT:
+		cp = (char *) data;
+		*cp = p->dsp ? 1 : 0;
+		ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp ? "en" : "dis", chan->name);
 		break;
 	default:
 		break;
@@ -5823,7 +5870,6 @@ static const char *hangup_cause2sip(int cause)
 	return 0;
 }
 
-
 /*! \brief  sip_hangup: Hangup SIP call
  * Part of PBX interface, called from ast_hangup */
 static int sip_hangup(struct ast_channel *ast)
@@ -5902,8 +5948,7 @@ static int sip_hangup(struct ast_channel *ast)
 	append_history(p, needcancel ? "Cancel" : "Hangup", "Cause %s", p->owner ? ast_cause2str(p->hangupcause) : "Unknown");
 
 	/* Disconnect */
-	if (p->vad)
-		ast_dsp_free(p->vad);
+	disable_digit_detect(p);
 
 	p->owner = NULL;
 	ast->tech_pvt = dialog_unref(ast->tech_pvt, "unref ast->tech_pvt");
@@ -6453,7 +6498,6 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
 	return res;
 }
 
-
 /*! \brief Initiate a call in the SIP channel
 	called from sip_request_call (calls from the pbx ) for outbound channels
 	and from handle_request_invite for inbound channels
@@ -6552,12 +6596,10 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 	else
 		ast_debug(3, "This channel will not be able to handle video.\n");
 
-	if ((ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) || (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
+	if ((ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) ||
+	    (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
 		if (!i->rtp || ast_rtp_instance_dtmf_mode_set(i->rtp, AST_RTP_DTMF_MODE_INBAND)) {
-			i->vad = ast_dsp_new();
-			ast_dsp_set_features(i->vad, DSP_FEATURE_DIGIT_DETECT);
-			if (global_relaxdtmf)
-				ast_dsp_set_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
+			enable_digit_detect(i);
 		}
 	} else if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) {
 		if (i->rtp) {
@@ -6853,8 +6895,8 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
 		ast_set_write_format(p->owner, p->owner->writeformat);
 	}
 
-	if (f && (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
-		f = ast_dsp_process(p->owner, p->vad, f);
+	if (f && p->dsp) {
+		f = ast_dsp_process(p->owner, p->dsp, f);
 		if (f && f->frametype == AST_FRAME_DTMF) {
 			if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
 				ast_debug(1, "Fax CNG detected on %s\n", ast->name);
@@ -25354,16 +25396,11 @@ static int sip_dtmfmode(struct ast_channel *chan, const char *data)
 		ast_log(LOG_WARNING, "I don't know about this dtmf mode: %s\n", mode);
 	if (p->rtp)
 		ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
-	if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) {
-		if (!p->vad) {
-			p->vad = ast_dsp_new();
-			ast_dsp_set_features(p->vad, DSP_FEATURE_DIGIT_DETECT);
-		}
+	if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) ||
+	    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
+		enable_digit_detect(p);
 	} else {
-		if (p->vad) {
-			ast_dsp_free(p->vad);
-			p->vad = NULL;
-		}
+		disable_digit_detect(p);
 	}
 	sip_pvt_unlock(p);
 	ast_channel_unlock(chan);
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 46500d2e982ba3d2cb474594f44df19d65b485e8..8b79a5e9987fabd45095f803f79d238dbc658590 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -400,6 +400,12 @@ enum ast_control_transfer {
 /*! Request that the channel driver make two channels of the same tech type compatible if possible */
 #define AST_OPTION_MAKE_COMPATIBLE      13
 
+/*! Get or set the digit detection state of the channel */
+#define AST_OPTION_DIGIT_DETECT		14
+
+/*! Get or set the fax tone detection state of the channel */
+#define AST_OPTION_FAX_DETECT		15
+
 struct oprmode {
 	struct ast_channel *peer;
 	int mode;