--- main/dsp.c.orig	2022-04-19 11:23:04.078148690 +0000
+++ main/dsp.c	2022-01-25 22:57:43.196071618 +0000
@@ -68,6 +68,7 @@
 #include "asterisk/options.h"
 #include "asterisk/config.h"
 #include "asterisk/test.h"
+#include "asterisk/translate.h"
 
 /*! Number of goertzels for progress detect */
 enum gsamp_size {
@@ -165,8 +166,6 @@
 
 #define	MAX_DTMF_DIGITS		128
 
-#define DTMF_MATRIX_SIZE	4
-
 /* Basic DTMF (AT&T) specs:
  *
  * Minimum tone on = 40ms
@@ -280,6 +279,8 @@
 
 } tone_detect_state_t;
 
+#define DTMF_MATRIX_SIZE 5
+
 typedef struct
 {
 	goertzel_state_t row_out[DTMF_MATRIX_SIZE];
@@ -317,15 +318,15 @@
 } digit_detect_state_t;
 
 static const float dtmf_row[] = {
-	697.0,  770.0,  852.0,  941.0
+	697.0,  770.0,  852.0,  941.0, 1700
 };
 static const float dtmf_col[] = {
-	1209.0, 1336.0, 1477.0, 1633.0
+	1209.0, 1336.0, 1477.0, 1633.0, 2200
 };
 static const float mf_tones[] = {
 	700.0, 900.0, 1100.0, 1300.0, 1500.0, 1700.0
 };
-static const char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
+static const char dtmf_positions[] = "123A-" "456B-" "789C-" "*0#D-" "----$";
 static const char bell_mf_positions[] = "1247C-358A--69*---0B----#";
 static int thresholds[THRESHOLD_MAX];
 static float dtmf_normal_twist;		/* AT&T = 8dB */
@@ -437,6 +438,7 @@
 	digit_detect_state_t digit_state;
 	tone_detect_state_t cng_tone_state;
 	tone_detect_state_t ced_tone_state;
+	struct ast_trans_pvt *trans_pvt; /*! Used to convert non-PCM codecs to SLIN if needed */
 };
 
 static void mute_fragment(struct ast_dsp *dsp, fragment_t *fragment)
@@ -734,7 +736,8 @@
 			goertzel_sample(s->td.dtmf.col_out + 2, samp);
 			goertzel_sample(s->td.dtmf.row_out + 3, samp);
 			goertzel_sample(s->td.dtmf.col_out + 3, samp);
-			/* go up to DTMF_MATRIX_SIZE - 1 */
+			goertzel_sample(s->td.dtmf.row_out + 4, samp);
+			goertzel_sample(s->td.dtmf.col_out + 4, samp);
 		}
 		s->td.dtmf.current_sample += (limit - sample);
 		if (s->td.dtmf.current_sample < DTMF_GSIZE) {
@@ -775,11 +778,23 @@
 				}
 			}
 			/* ... and fraction of total energy test */
+			if (hit == '$')
+				ast_verb(2, "Some recognition of %c, i: %d\n", hit, i); ////
 			if (i >= DTMF_MATRIX_SIZE &&
-			    (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY * s->td.dtmf.energy) {
+			    (row_energy[best_row] + col_energy[best_col]) > (DTMF_TO_TOTAL_ENERGY / (relax ? 2 : 1)) * s->td.dtmf.energy) {
 				/* Got a hit */
-				hit = dtmf_positions[(best_row << 2) + best_col];
+				hit = dtmf_positions[(best_row * DTMF_MATRIX_SIZE) + best_col];
 				ast_debug(10, "DTMF hit '%c'\n", hit);
+			} else if (i >= DTMF_MATRIX_SIZE &&
+			    (row_energy[best_row] + col_energy[best_col]) > (DTMF_TO_TOTAL_ENERGY / (relax ? 4 : 1)) * s->td.dtmf.energy) {
+				/* Got a hit */
+				hit = dtmf_positions[(best_row * DTMF_MATRIX_SIZE) + best_col];
+				ast_verb(2, "Would've been a hit x4\n");
+			} else if (i >= DTMF_MATRIX_SIZE &&
+			    (row_energy[best_row] + col_energy[best_col]) > (DTMF_TO_TOTAL_ENERGY / (relax ? 8 : 1)) * s->td.dtmf.energy) {
+				/* Got a hit */
+				hit = dtmf_positions[(best_row * DTMF_MATRIX_SIZE) + best_col];
+				ast_verb(2, "Would've been a hit x8\n");
 			}
 		}
 
@@ -843,6 +858,7 @@
 				s->td.dtmf.misses++;
 				if (s->td.dtmf.misses == dtmf_misses_to_end) {
 					/* There were enough misses to consider digit ended */
+					ast_debug(1, "Enough misses that %c ended\n", s->td.dtmf.current_hit);
 					s->td.dtmf.current_hit = 0;
 				}
 			} else {
@@ -857,6 +873,7 @@
 		   and we may find begin of new digit before we consider last one ended. */
 
 		if (hit != s->td.dtmf.lasthit) {
+			ast_debug(1, "Reset hit from %c to %c\n", s->td.dtmf.lasthit, hit); ////
 			s->td.dtmf.lasthit = hit;
 			s->td.dtmf.hits = 0;
 		}
@@ -867,6 +884,7 @@
 				s->digitlen[s->current_digits - 1] = dtmf_hits_to_begin * DTMF_GSIZE;
 				s->td.dtmf.current_hit = hit;
 				s->td.dtmf.misses = 0;
+				ast_debug(1, "Hit: %c\n", hit); ////
 			}
 		}
 
@@ -1529,12 +1547,46 @@
 			shortdata[x] = AST_ALAW(odata[x]);
 		}
 	} else {
-		/*Display warning only once. Otherwise you would get hundreds of warnings every second */
+		int translated = 0;
+
 		if (dsp->display_inband_dtmf_warning) {
-			ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_format_get_name(af->subclass.format));
+			if (!dsp->trans_pvt) {
+				/* try to build a path from whatever codec is being used to slin */
+				if (!(dsp->trans_pvt = ast_translator_build_path(ast_format_slin, af->subclass.format))) {
+					ast_log(LOG_WARNING, "Cannot build a path from %s (%u) to signed linear\n",
+						ast_format_get_name(af->subclass.format),
+						ast_format_get_codec_id(af->subclass.format));
+				} else {
+					ast_debug(1, "Successfully created translation path from %s (%u) to signed linear for DSP processing\n",
+						ast_format_get_name(af->subclass.format),
+						ast_format_get_codec_id(af->subclass.format));
+				}
+			}
+			if (dsp->trans_pvt) {
+				/* Convert to slin, and allow the original frame to be freed */
+				af = ast_translate(dsp->trans_pvt, af, 1);
+				/* update frame variables */
+				odata = af->data.ptr;
+				len = af->datalen;
+				if (ast_format_cache_is_slinear(af->subclass.format)) {
+					shortdata = af->data.ptr;
+					len = af->datalen / 2;
+					translated = 1;
+					ast_debug(1, "translated a frame to slin\n");
+				} else {
+					ast_log(LOG_WARNING, "Codec translated, but not one of the cached slin formats\n");
+				}
+			} else
+				ast_log(LOG_WARNING, "Failed to translate\n");
+		}
+		if (!translated) {
+			/* Display warning only once. Otherwise you would get hundreds of warnings every second */
+			if (dsp->display_inband_dtmf_warning) {
+				ast_log(LOG_WARNING, "Inband signaling is not supported on codec %s. Use RFC2833 or switch to G.711 codec\n", ast_format_get_name(af->subclass.format));
+				dsp->display_inband_dtmf_warning = 0;
+			}
+			return af;
 		}
-		dsp->display_inband_dtmf_warning = 0;
-		return af;
 	}
 
 	/* Initially we do not want to mute anything */
@@ -1741,6 +1793,8 @@
 		ast_dsp_prog_reset(dsp);
 		/* Initialize fax detector */
 		ast_fax_detect_init(dsp);
+		/* Don't immediately build a translation path */
+		dsp->trans_pvt = NULL;
 	}
 	return dsp;
 }
@@ -1772,6 +1826,9 @@
 
 void ast_dsp_free(struct ast_dsp *dsp)
 {
+	if (dsp && dsp->trans_pvt) {
+		ast_translator_free_path(dsp->trans_pvt);
+	}
 	ast_free(dsp);
 }
 
