[svn-commits] mnicholson: branch mnicholson/new-v21-detect r348153 - in /team/mnicholson/ne...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed Dec 14 10:27:30 CST 2011


Author: mnicholson
Date: Wed Dec 14 10:27:23 2011
New Revision: 348153

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=348153
Log:
New spandsp based v21 detection code for the fax gateway.

This patch removes the hacked together v21 detection from dsp.c and adds a new API for detection to res_fax to be implemented by the fax technology backend modules. This also implements v21 detection in res_fax_spandsp using spandsp's modem connect tones API.

Added:
    team/mnicholson/new-v21-detect/
      - copied from r348152, branches/10/
Modified:
    team/mnicholson/new-v21-detect/include/asterisk/dsp.h
    team/mnicholson/new-v21-detect/include/asterisk/res_fax.h
    team/mnicholson/new-v21-detect/main/dsp.c
    team/mnicholson/new-v21-detect/res/res_fax.c
    team/mnicholson/new-v21-detect/res/res_fax_spandsp.c

Modified: team/mnicholson/new-v21-detect/include/asterisk/dsp.h
URL: http://svnview.digium.com/svn/asterisk/team/mnicholson/new-v21-detect/include/asterisk/dsp.h?view=diff&rev=348153&r1=348152&r2=348153
==============================================================================
--- team/mnicholson/new-v21-detect/include/asterisk/dsp.h (original)
+++ team/mnicholson/new-v21-detect/include/asterisk/dsp.h Wed Dec 14 10:27:23 2011
@@ -45,9 +45,8 @@
 
 #define DSP_FAXMODE_DETECT_CNG		(1 << 0)
 #define DSP_FAXMODE_DETECT_CED		(1 << 1)
-#define DSP_FAXMODE_DETECT_V21		(1 << 2)
-#define DSP_FAXMODE_DETECT_SQUELCH	(1 << 3)
-#define DSP_FAXMODE_DETECT_ALL	(DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED | DSP_FAXMODE_DETECT_V21)
+#define DSP_FAXMODE_DETECT_SQUELCH	(1 << 2)
+#define DSP_FAXMODE_DETECT_ALL	(DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED)
 
 #define DSP_TONE_STATE_SILENCE  0
 #define DSP_TONE_STATE_RINGING  1

Modified: team/mnicholson/new-v21-detect/include/asterisk/res_fax.h
URL: http://svnview.digium.com/svn/asterisk/team/mnicholson/new-v21-detect/include/asterisk/res_fax.h?view=diff&rev=348153&r1=348152&r2=348153
==============================================================================
--- team/mnicholson/new-v21-detect/include/asterisk/res_fax.h (original)
+++ team/mnicholson/new-v21-detect/include/asterisk/res_fax.h Wed Dec 14 10:27:23 2011
@@ -44,6 +44,8 @@
 	AST_FAX_TECH_MULTI_DOC = (1 << 4),
 	/*! T.38 - T.30 Gateway */
 	AST_FAX_TECH_GATEWAY = (1 << 5),
+	/*! V21 detection is supported */
+	AST_FAX_TECH_V21_DETECT = (1 << 6),
 };
 
 /*! \brief fax modem capabilities */

Modified: team/mnicholson/new-v21-detect/main/dsp.c
URL: http://svnview.digium.com/svn/asterisk/team/mnicholson/new-v21-detect/main/dsp.c?view=diff&rev=348153&r1=348152&r2=348153
==============================================================================
--- team/mnicholson/new-v21-detect/main/dsp.c (original)
+++ team/mnicholson/new-v21-detect/main/dsp.c Wed Dec 14 10:27:23 2011
@@ -243,20 +243,6 @@
 	int last_hit;		/* Indicates if the last processed block was a hit */
 
 } tone_detect_state_t;
-
-typedef struct
-{
-	int block_size;
-	goertzel_state_t tone;
-	float energy;		/* Accumulated energy of the current block */
-	int samples_pending;	/* Samples remain to complete the current block */
-
-	float threshold;	/* Energy of the tone relative to energy from all other signals to consider a hit */
-
-	int hit_count;
-	int miss_count;
-
-} v21_detect_state_t;
 
 typedef struct
 {
@@ -405,7 +391,6 @@
 	digit_detect_state_t digit_state;
 	tone_detect_state_t cng_tone_state;
 	tone_detect_state_t ced_tone_state;
-	v21_detect_state_t v21_state;
 };
 
 static void mute_fragment(struct ast_dsp *dsp, fragment_t *fragment)
@@ -478,55 +463,10 @@
 	ast_debug(1, "Setup tone %d Hz, %d ms, block_size=%d, hits_required=%d\n", freq, duration, s->block_size, s->hits_required);
 }
 
-static void ast_v21_detect_init(v21_detect_state_t *s, unsigned int sample_rate)
-{
-	float x;
-	int periods_in_block;
-
-	/* If we want to remove tone, it is important to have block size not
-	   to exceed frame size. Otherwise by the moment tone is detected it is too late
-	   to squelch it from previous frames. Block size is 20ms at the given sample rate.*/
-	s->block_size = (20 * sample_rate) / 1000;
-
-	periods_in_block = s->block_size * 1850 / sample_rate;
-
-	/* Make sure we will have at least 5 periods at target frequency for analisys.
-	   This may make block larger than expected packet and will make squelching impossible
-	   but at least we will be detecting the tone */
-	if (periods_in_block < 5)
-		periods_in_block = 5;
-
-	/* Now calculate final block size. It will contain integer number of periods */
-	s->block_size = periods_in_block * sample_rate / 1850;
-
-	goertzel_init(&s->tone, 1850.0, s->block_size, sample_rate);
-
-	s->samples_pending = s->block_size;
-	s->hit_count = 0;
-	s->miss_count = 0;
-	s->energy = 0.0;
-
-	/* We want tone energy to be amp decibels above the rest of the signal (the noise).
-	   According to Parseval's theorem the energy computed in time domain equals to energy
-	   computed in frequency domain. So subtracting energy in the frequency domain (Goertzel result)
-	   from the energy in the time domain we will get energy of the remaining signal (without the tone
-	   we are detecting). We will be checking that
-		10*log(Ew / (Et - Ew)) > amp
-	   Calculate threshold so that we will be actually checking
-		Ew > Et * threshold
-	*/
-
-	x = pow(10.0, 16 / 10.0);
-	s->threshold = x / (x + 1);
-
-	ast_debug(1, "Setup v21 detector, block_size=%d\n", s->block_size);
-}
-
 static void ast_fax_detect_init(struct ast_dsp *s)
 {
 	ast_tone_detect_init(&s->cng_tone_state, FAX_TONE_CNG_FREQ, FAX_TONE_CNG_DURATION, FAX_TONE_CNG_DB, s->sample_rate);
 	ast_tone_detect_init(&s->ced_tone_state, FAX_TONE_CED_FREQ, FAX_TONE_CED_DURATION, FAX_TONE_CED_DB, s->sample_rate);
-	ast_v21_detect_init(&s->v21_state, s->sample_rate);
 	if (s->faxmode & DSP_FAXMODE_DETECT_SQUELCH) {
 		s->cng_tone_state.squelch = 1;
 		s->ced_tone_state.squelch = 1;
@@ -576,89 +516,6 @@
 	} else {
 		ast_dtmf_detect_init(&s->td.dtmf, sample_rate);
 	}
-}
-
-/*! \brief Detect a v21 preamble.
- * This code is derived from the tone_detect code and detects a pattern of 1850
- * Hz tone found in a v21 preamble.
- */
-static int v21_detect(struct ast_dsp *dsp, v21_detect_state_t *s, int16_t *amp, int samples)
-{
-	float tone_energy;
-	int i;
-	int hit = 0;
-	int limit;
-	int res = 0;
-	int16_t *ptr;
-	int start, end;
-
-	for (start = 0;  start < samples;  start = end) {
-		/* Process in blocks. */
-		limit = samples - start;
-		if (limit > s->samples_pending) {
-			limit = s->samples_pending;
-		}
-		end = start + limit;
-
-		for (i = limit, ptr = amp ; i > 0; i--, ptr++) {
-			/* signed 32 bit int should be enough to suqare any possible signed 16 bit value */
-			s->energy += (int32_t) *ptr * (int32_t) *ptr;
-
-			goertzel_sample(&s->tone, *ptr);
-		}
-
-		s->samples_pending -= limit;
-
-		if (s->samples_pending) {
-			/* Finished incomplete (last) block */
-			break;
-		}
-
-		tone_energy = goertzel_result(&s->tone);
-
-		/* Scale to make comparable */
-		tone_energy *= 2.0;
-		s->energy *= s->block_size;
-
-		ast_debug(10, "v21 1850 Ew=%.2E, Et=%.2E, s/n=%10.2f\n", tone_energy, s->energy, tone_energy / (s->energy - tone_energy));
-
-		hit = 0;
-		if (tone_energy > s->energy * s->threshold) {
-			ast_debug(10, "Hit! count=%d; miss_count=%d\n", s->hit_count, s->miss_count);
-			hit = 1;
-		}
-
-		if (hit) {
-			if (s->miss_count == 3 || (s->hit_count == 1 && s->miss_count == 2)) {
-				s->hit_count++;
-			} else {
-				s->hit_count = 1;
-			}
-
-			s->miss_count = 0;
-		} else {
-			s->miss_count++;
-			if (s->miss_count > 3) {
-				s->hit_count = 0;
-			}
-		}
-
-		if (s->hit_count == 4) {
-			ast_debug(1, "v21 preamble detected\n");
-			res = 1;
-		}
-
-		/* Reinitialise the detector for the next block */
-		goertzel_reset(&s->tone);
-
-		/* Advance to the next block */
-		s->energy = 0.0;
-		s->samples_pending = s->block_size;
-
-		amp += limit;
-	}
-
-	return res;
 }
 
 static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp, int samples)
@@ -1596,10 +1453,6 @@
 		if ((dsp->faxmode & DSP_FAXMODE_DETECT_CED) && tone_detect(dsp, &dsp->ced_tone_state, shortdata, len)) {
 			fax_digit = 'e';
 		}
-
-		if ((dsp->faxmode & DSP_FAXMODE_DETECT_V21) && v21_detect(dsp, &dsp->v21_state, shortdata, len)) {
-			fax_digit = 'g';
-		}
 	}
 
 	if (dsp->features & (DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_BUSY_DETECT)) {

Modified: team/mnicholson/new-v21-detect/res/res_fax.c
URL: http://svnview.digium.com/svn/asterisk/team/mnicholson/new-v21-detect/res/res_fax.c?view=diff&rev=348153&r1=348152&r2=348153
==============================================================================
--- team/mnicholson/new-v21-detect/res/res_fax.c (original)
+++ team/mnicholson/new-v21-detect/res/res_fax.c Wed Dec 14 10:27:23 2011
@@ -243,13 +243,12 @@
 struct fax_gateway {
 	/*! \brief FAX Session */
 	struct ast_fax_session *s;
+	struct ast_fax_session *peer_v21_session;
+	struct ast_fax_session *chan_v21_session;
 	/*! \brief reserved fax session token */
 	struct ast_fax_tech_token *token;
 	/*! \brief the start of our timeout counter */
 	struct timeval timeout_start;
-	/*! \brief DSP Processor */
-	struct ast_dsp *chan_dsp;
-	struct ast_dsp *peer_dsp;
 	/*! \brief framehook used in gateway mode */
 	int framehook;
 	/*! \brief bridged */
@@ -608,7 +607,13 @@
 		ast_build_string(&buf, &size, "GATEWAY");
 		first = 0;
 	}
-
+	if (caps & AST_FAX_TECH_V21_DETECT) {
+		if (!first) {
+			ast_build_string(&buf, &size, ",");
+		}
+		ast_build_string(&buf, &size, "V21");
+		first = 0;
+	}
 
 	return out;
 }
@@ -2413,20 +2418,34 @@
 	return (!channel_alive) ? -1 : 0;
 }
 
+/*! \brief destroy the v21 detection parts of a fax gateway session */
+static void destroy_v21_sessions(struct fax_gateway *gateway)
+{
+	if (gateway->chan_v21_session) {
+		ao2_lock(faxregistry.container);
+		ao2_unlink(faxregistry.container, gateway->chan_v21_session);
+		ao2_unlock(faxregistry.container);
+
+		ao2_ref(gateway->chan_v21_session, -1);
+		gateway->chan_v21_session = NULL;
+	}
+
+	if (gateway->peer_v21_session) {
+		ao2_lock(faxregistry.container);
+		ao2_unlink(faxregistry.container, gateway->peer_v21_session);
+		ao2_unlock(faxregistry.container);
+
+		ao2_ref(gateway->peer_v21_session, -1);
+		gateway->peer_v21_session = NULL;
+	}
+}
+
 /*! \brief destroy a FAX gateway session structure */
 static void destroy_gateway(void *data)
 {
 	struct fax_gateway *gateway = data;
 
-	if (gateway->chan_dsp) {
-		ast_dsp_free(gateway->chan_dsp);
-		gateway->chan_dsp = NULL;
-	}
-
-	if (gateway->peer_dsp) {
-		ast_dsp_free(gateway->peer_dsp);
-		gateway->peer_dsp = NULL;
-	}
+	destroy_v21_sessions(gateway);
 
 	if (gateway->s) {
 		fax_session_release(gateway->s, gateway->token);
@@ -2445,32 +2464,34 @@
  * \param details the fax session details
  * \return NULL or a fax gateway object
  */
-static struct fax_gateway *fax_gateway_new(struct ast_fax_session_details *details)
+static struct fax_gateway *fax_gateway_new(struct ast_channel *chan, struct ast_fax_session_details *details)
 {
 	struct fax_gateway *gateway = ao2_alloc(sizeof(*gateway), destroy_gateway);
+	struct ast_fax_session_details *v21_details;
 	if (!gateway) {
 		return NULL;
 	}
 
-	gateway->chan_dsp = ast_dsp_new();
-	if (!gateway->chan_dsp) {
+	if (!(v21_details = session_details_new())) {
 		ao2_ref(gateway, -1);
 		return NULL;
 	}
 
-	gateway->peer_dsp = ast_dsp_new();
-	if (!gateway->peer_dsp) {
+	v21_details->caps = AST_FAX_TECH_V21_DETECT;
+	if (!(gateway->chan_v21_session = fax_session_new(v21_details, chan, NULL, NULL))) {
+		ao2_ref(v21_details, -1);
 		ao2_ref(gateway, -1);
 		return NULL;
 	}
 
+	if (!(gateway->peer_v21_session = fax_session_new(v21_details, chan, NULL, NULL))) {
+		ao2_ref(v21_details, -1);
+		ao2_ref(gateway, -1);
+		return NULL;
+	}
+	ao2_ref(v21_details, -1);
+
 	gateway->framehook = -1;
-
-	ast_dsp_set_features(gateway->chan_dsp, DSP_FEATURE_FAX_DETECT);
-	ast_dsp_set_faxmode(gateway->chan_dsp, DSP_FAXMODE_DETECT_V21);
-
-	ast_dsp_set_features(gateway->peer_dsp, DSP_FEATURE_FAX_DETECT);
-	ast_dsp_set_faxmode(gateway->peer_dsp, DSP_FAXMODE_DETECT_V21);
 
 	details->caps = AST_FAX_TECH_GATEWAY;
 	if (details->gateway_timeout && !(gateway->s = fax_session_reserve(details, &gateway->token))) {
@@ -2565,24 +2586,19 @@
 
 static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *active, struct ast_frame *f)
 {
-	struct ast_frame *dfr = ast_frdup(f);
-	struct ast_dsp *active_dsp = (active == chan) ? gateway->chan_dsp : gateway->peer_dsp;
 	struct ast_channel *other = (active == chan) ? peer : chan;
+	struct ast_fax_session *active_v21_session = (active == chan) ? gateway->chan_v21_session : gateway->peer_v21_session;
+
+	if (!active_v21_session || gateway->detected_v21) {
+		return f;
+	}
+
+	if (active_v21_session->tech->write(active_v21_session, f) == 1) {
+		gateway->detected_v21 = 1;
+	}
 
 	if (gateway->detected_v21) {
-		return f;
-	}
-
-	if (!dfr) {
-		return f;
-	}
-
-	if (!(dfr = ast_dsp_process(active, active_dsp, dfr))) {
-		return f;
-	}
-
-	if (dfr->frametype == AST_FRAME_DTMF && dfr->subclass.integer == 'g') {
-		gateway->detected_v21 = 1;
+		destroy_v21_sessions(gateway);
 		if (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN) {
 			ast_debug(1, "detected v21 preamble from %s\n", active->name);
 			return fax_gateway_request_t38(gateway, chan, f);
@@ -2591,7 +2607,6 @@
 		}
 	}
 
-	ast_frfree(dfr);
 	return f;
 }
 
@@ -3094,7 +3109,7 @@
 	set_channel_variables(chan, details);
 
 	/* set up the frame hook*/
-	gateway = fax_gateway_new(details);
+	gateway = fax_gateway_new(chan, details);
 	if (!gateway) {
 		ast_string_field_set(details, result, "FAILED");
 		ast_string_field_set(details, resultstr, "error initializing gateway session");
@@ -3366,6 +3381,36 @@
 	return CLI_SUCCESS;
 }
 
+static const char *cli_session_type(struct ast_fax_session *s)
+{
+	if (s->details->caps & AST_FAX_TECH_AUDIO) {
+		return "G.711";
+	}
+	if (s->details->caps & AST_FAX_TECH_T38) {
+		return "T.38";
+	}
+
+	return "none";
+}
+
+static const char *cli_session_operation(struct ast_fax_session *s)
+{
+	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
+		return "gateway";
+	}
+	if (s->details->caps & AST_FAX_TECH_SEND) {
+		return "send";
+	}
+	if (s->details->caps & AST_FAX_TECH_RECEIVE) {
+		return "receive";
+	}
+	if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
+		return "V.21";
+	}
+
+	return "none";
+}
+
 /*! \brief display fax sessions */
 static char *cli_fax_show_sessions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -3396,10 +3441,8 @@
 
 		ast_cli(a->fd, "%-20.20s %-10.10s %-10d %-5.5s %-10.10s %-15.15s %-30s\n",
 			s->channame, s->tech->type, s->id,
-			(s->details->caps & AST_FAX_TECH_AUDIO) ? "G.711" : "T.38",
-			(s->details->caps & AST_FAX_TECH_GATEWAY)
-				? "gateway"
-				: (s->details->caps & AST_FAX_TECH_SEND) ? "send" : "receive",
+			cli_session_type(s),
+			cli_session_operation(s),
 			ast_fax_state_to_str(s->state), S_OR(filenames, ""));
 
 		ast_free(filenames);

Modified: team/mnicholson/new-v21-detect/res/res_fax_spandsp.c
URL: http://svnview.digium.com/svn/asterisk/team/mnicholson/new-v21-detect/res/res_fax_spandsp.c?view=diff&rev=348153&r1=348152&r2=348153
==============================================================================
--- team/mnicholson/new-v21-detect/res/res_fax_spandsp.c (original)
+++ team/mnicholson/new-v21-detect/res/res_fax_spandsp.c Wed Dec 14 10:27:23 2011
@@ -80,6 +80,9 @@
 static int spandsp_fax_gateway_start(struct ast_fax_session *s);
 static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f);
 static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s);
+static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f);
+static void spandsp_v21_cleanup(struct ast_fax_session *s);
+static void spandsp_v21_tone(void *data, int code, int level, int delay);
 
 static char *spandsp_fax_cli_show_capabilities(int fd);
 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
@@ -98,7 +101,9 @@
 	 */
 	.version = "pre-20090220",
 #endif
-	.caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND | AST_FAX_TECH_RECEIVE | AST_FAX_TECH_GATEWAY,
+	.caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND
+		| AST_FAX_TECH_RECEIVE | AST_FAX_TECH_GATEWAY
+		| AST_FAX_TECH_V21_DETECT,
 	.new_session = spandsp_fax_new,
 	.destroy_session = spandsp_fax_destroy,
 	.read = spandsp_fax_read,
@@ -150,8 +155,12 @@
 
 	struct ast_timer *timer;
 	AST_LIST_HEAD(frame_queue, ast_frame) read_frames;
+
+	int v21_detected;
+	modem_connect_tones_rx_state_t *tone_state;
 };
 
+static int spandsp_v21_new(struct spandsp_pvt *p);
 static void session_destroy(struct spandsp_pvt *p);
 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count);
 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code);
@@ -450,6 +459,20 @@
 	t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
 }
 
+static int spandsp_v21_new(struct spandsp_pvt *p)
+{
+	/* XXX Here we use MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE even though
+	 * we don't care about CED tones. Using MODEM_CONNECT_TONES_PREAMBLE
+	 * doesn't seem to work right all the time.
+	 */
+	p->tone_state = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, spandsp_v21_tone, p);
+	if (!p->tone_state) {
+		return -1;
+	}
+
+	return 0;
+}
+
 /*! \brief create an instance of the spandsp tech_pvt for a fax session */
 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
 {
@@ -459,6 +482,15 @@
 	if ((!(p = ast_calloc(1, sizeof(*p))))) {
 		ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
 		goto e_return;
+	}
+
+	if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
+		if (spandsp_v21_new(p)) {
+			ast_log(LOG_ERROR, "Cannot initialize the spandsp private v21 technology structure.\n");
+			goto e_return;
+		}
+		s->state = AST_FAX_STATE_ACTIVE;
+		return p;
 	}
 
 	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
@@ -513,6 +545,11 @@
 	return NULL;
 }
 
+static void spandsp_v21_cleanup(struct ast_fax_session *s) {
+	struct spandsp_pvt *p = s->tech_pvt;
+	modem_connect_tones_rx_free(p->tone_state);
+}
+
 /*! \brief Destroy a spandsp fax session.
  */
 static void spandsp_fax_destroy(struct ast_fax_session *s)
@@ -521,6 +558,8 @@
 
 	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
 		spandsp_fax_gateway_cleanup(s);
+	} else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
+		spandsp_v21_cleanup(s);
 	} else {
 		session_destroy(p);
 	}
@@ -571,6 +610,32 @@
 	return &ast_null_frame;
 }
 
+static void spandsp_v21_tone(void *data, int code, int level, int delay)
+{
+	struct spandsp_pvt *p = data;
+
+	if (code == MODEM_CONNECT_TONES_FAX_PREAMBLE) {
+		p->v21_detected = 1;
+	}
+}
+
+static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f) {
+	struct spandsp_pvt *p = s->tech_pvt;
+
+	if (p->v21_detected) {
+		return p->v21_detected;
+	}
+
+	/*invalid frame*/
+	if (!f->data.ptr || !f->datalen) {
+		return -1;
+	}
+
+	modem_connect_tones_rx(p->tone_state, f->data.ptr, f->samples);
+
+	return p->v21_detected;
+}
+
 /*! \brief Write a frame to the spandsp fax stack.
  * \param s a fax session
  * \param f the frame to write
@@ -584,6 +649,10 @@
 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
 {
 	struct spandsp_pvt *p = s->tech_pvt;
+
+	if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
+		return spandsp_v21_detect(s, f);
+	}
 
 	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
 		return spandsp_fax_gateway_process(s, f);
@@ -906,10 +975,10 @@
 /*! \brief */
 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
 {
-	struct spandsp_pvt *p = s->tech_pvt;
-
 	ao2_lock(s);
 	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
+		struct spandsp_pvt *p = s->tech_pvt;
+
 		ast_cli(fd, "%-22s : %d\n", "session", s->id);
 		ast_cli(fd, "%-22s : %s\n", "operation", "Gateway");
 		ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
@@ -920,7 +989,13 @@
 			ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
 			ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
 		}
+	} else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
+		ast_cli(fd, "%-22s : %d\n", "session", s->id);
+		ast_cli(fd, "%-22s : %s\n", "operation", "V.21 Detect");
+		ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
 	} else {
+		struct spandsp_pvt *p = s->tech_pvt;
+
 		ast_cli(fd, "%-22s : %d\n", "session", s->id);
 		ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
 		ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));




More information about the svn-commits mailing list