[asterisk-commits] irroot: branch irroot/distrotech-customers-trunk r329101 - /team/irroot/distr...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Jul 21 06:08:30 CDT 2011


Author: irroot
Date: Thu Jul 21 06:08:26 2011
New Revision: 329101

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=329101
Log:
Add WaitFAX

Modified:
    team/irroot/distrotech-customers-trunk/res/res_fax.c

Modified: team/irroot/distrotech-customers-trunk/res/res_fax.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/distrotech-customers-trunk/res/res_fax.c?view=diff&rev=329101&r1=329100&r2=329101
==============================================================================
--- team/irroot/distrotech-customers-trunk/res/res_fax.c (original)
+++ team/irroot/distrotech-customers-trunk/res/res_fax.c Thu Jul 21 06:08:26 2011
@@ -225,10 +225,30 @@
 			<ref type="application">SendFax</ref>
 		</see-also>
 	</function>
+	<application name="WaitFAX" language="en_US">
+		<synopsis>
+			Generic Fax Detect CNG/T.38 (Wait For Fax)
+		</synopsis>
+		<syntax>
+			<parameter name="timeout" required="true">
+				<para>Specifies the number of seconds we attempt to detect a fax tone on the channel</para>
+			</parameter>
+			<parameter name="tone" required="false">
+				<para>Either the tone name defined in the "indications.conf" configuration file,
+				or a directly specified list of frequencies and durations.</para>
+				<para>If not specified silence is generated.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>This application sets FAXOPT(status) To SUCCESS | FAILURE | ERROR</para>
+			<para>FAXOPT(statusstr) will be set to CNG | T38 on SUCCESS or reason on FAILURE | ERROR</para>
+		</description>
+	</application>
 ***/
 
 static const char app_receivefax[] = "ReceiveFAX";
 static const char app_sendfax[] = "SendFAX";
+static const char app_waitfax[] = "WaitFAX";
 
 struct debug_info_history {
 	unsigned int consec_frames;
@@ -3031,6 +3051,184 @@
 	return gateway->framehook;
 }
 
+/*! \brief Faxdetect loop used by WaitFAX
+ * \details Run DSP faxdetect on the channel for timeout seconds or until fax is detected
+ * \param chan channel to run fax detect on
+ * \param timeout maximum time to wait for fax detection
+ * \return 0 if nothing was detected 1 on CNG detected 2 if T38 negotiation is started -1 on error*/
+static int do_waitfax_exec(struct ast_channel *chan, int timeout)
+{
+	int timeleft = timeout;
+	int res = 0;
+	struct ast_dsp *dsp = NULL;
+	struct ast_frame *f;
+	enum ast_t38_state t38state = T38_STATE_UNKNOWN;
+	struct ast_format orig_read_format;
+	AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
+
+	/* Setup DSP CNG processing */
+	ast_format_copy(&orig_read_format, &chan->readformat);
+	switch (chan->readformat.id) {
+		case AST_FORMAT_SLINEAR:
+		case AST_FORMAT_ALAW:
+		case AST_FORMAT_ULAW:
+			break;
+		default:
+			if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) {
+				return -1;
+			}
+	}
+
+	if ((dsp = ast_dsp_new())) {
+		ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
+		ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG);
+	} else {
+		return -1;
+	}
+
+	AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
+
+	while ((timeleft = ast_waitfor(chan, timeleft))) {
+		if (!(f = ast_read(chan))) {
+			break;
+		}
+
+		if (dsp && (f->frametype == AST_FRAME_VOICE) && ((f->subclass.format.id == AST_FORMAT_SLINEAR) ||
+		    (f->subclass.format.id == AST_FORMAT_ULAW) || (f->subclass.format.id == AST_FORMAT_ALAW))) {
+			f = ast_dsp_process(chan, dsp, f);
+			if ((f->frametype ==  AST_FRAME_DTMF) && (f->subclass.integer == 'f')) {
+				res = 1;
+				ast_dsp_free(dsp);
+				dsp = NULL;
+			}
+		}
+
+		if (ast_is_deferrable_frame(f)) {
+			AST_LIST_INSERT_HEAD(&deferred_frames, f, frame_list);
+		} else {
+			ast_frfree(f);
+		}
+
+		t38state = ast_channel_get_t38_state(chan);
+		if ((t38state == T38_STATE_NEGOTIATING) || (t38state == T38_STATE_NEGOTIATED)) {
+			res = 2;
+			break;
+		} else if (res) {
+			break;
+		}
+	}
+
+	if (orig_read_format.id != chan->readformat.id) {
+		ast_set_read_format(chan, &orig_read_format);
+	}
+
+	ast_channel_lock(chan);
+	while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
+		ast_queue_frame_head(chan, ast_frisolate(f));
+	}
+	ast_channel_unlock(chan);
+
+	if (dsp) {
+		ast_dsp_free(dsp);
+	}
+
+	return res;
+}
+
+/*! \brief Alternate wait app that listens for CNG
+ * \details This app answers the channel and waits for CNG tone or T38 negotiation
+ * if the channel driver supports faxdetect it will proceed to the fax
+ * extension.
+ * it will set FAXOPT(status) and FAXOPT(statusstr) allowing dial plan processing where
+ * the channel does not have fax detect or the Dialplan needs to handle faxdetection
+ *
+ * \param chan channel this application is called on
+ * \param data the paramaters passed to the application
+ * \return this application will always return 0
+ */
+static int waitfax_exec(struct ast_channel *chan, const char *data)
+{
+	int res = 0;
+	int timeout = 0;
+	int ptres = -1;
+	char *parse;
+	struct ast_fax_session_details *details;
+	struct ast_silence_generator *silgen = NULL;
+	struct ast_tone_zone_sound *ts;
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(timeout);
+		AST_APP_ARG(tone);
+	);
+
+	if (!(details = find_or_create_details(chan))) {
+		ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
+		return 0;
+	}
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	if (args.timeout) {
+		timeout = atoi(args.timeout) * 1000;
+	}
+
+	if (timeout <= 0) {
+		ast_string_field_set(details, result, "ERROR");
+		ast_string_field_set(details, resultstr, "Invalid timeout in WaitFAX");
+		ast_log(LOG_ERROR, "Application WaitFAX requires a valid timeout\n");
+		ao2_ref(details, -1);
+		return 0;
+	}
+
+	if (chan->_state != AST_STATE_UP) {
+		ast_answer(chan);
+	}
+
+	/* If no other generator is present, start tone or silencegen while waiting */
+	if (!chan->generatordata && !ast_strlen_zero(args.tone)) {
+		if ((ts = ast_get_indication_tone(chan->zone, args.tone))) {
+			ptres = ast_playtones_start(chan, 0, ts->data, 0);
+			ts = ast_tone_zone_sound_unref(ts);
+		} else {
+			ptres = ast_playtones_start(chan, 0, args.tone, 0);
+		}
+		if (!ptres && ast_opt_transmit_silence) {
+			silgen = ast_channel_start_silence_generator(chan);
+		}
+	} else if (ast_opt_transmit_silence && !chan->generatordata) {
+		silgen = ast_channel_start_silence_generator(chan);
+	}
+
+	res = do_waitfax_exec(chan, timeout);
+
+	/* stop silgen or tones if present */
+	if (silgen) {
+		ast_channel_stop_silence_generator(chan, silgen);
+	} else if (!ptres) {
+		ast_playtones_stop(chan);
+	}
+
+	if (res > 0) {
+		ast_string_field_set(details, result, "SUCCESS");
+		if (res == 1) {
+			ast_string_field_set(details, resultstr, "CNG");
+		} else {
+			ast_string_field_set(details, resultstr, "T38");
+		}
+	} else if (res < 0) {
+		ast_string_field_set(details, result, "ERROR");
+		ast_string_field_set(details, resultstr, "DSP Error WaitFAX Failed");
+	} else {
+		ast_string_field_set(details, result, "FAILED");
+		ast_string_field_set(details, resultstr, "No CNG Tone Or T38 Detected");
+	}
+
+	ao2_ref(details, -1);
+	return 0;
+}
+
+
 /*! \brief hash callback for ao2 */
 static int session_hash_cb(const void *obj, const int flags)
 {
@@ -3571,6 +3769,10 @@
 		ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_receivefax);
 	}
 
+	if (ast_unregister_application(app_waitfax) < 0) {
+		ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_waitfax);
+	}
+
 	if (fax_logger_level != -1) {
 		ast_logger_unregister_level("FAX");
 	}
@@ -3611,8 +3813,12 @@
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
+	if (ast_register_application_xml(app_waitfax, waitfax_exec) < 0) {
+		ast_log(LOG_WARNING, "failed to register '%s'.\n", app_waitfax);
+	}
+
 	ast_cli_register_multiple(fax_cli, ARRAY_LEN(fax_cli));
-	res = ast_custom_function_register(&acf_faxopt);	
+	res = ast_custom_function_register(&acf_faxopt);
 	fax_logger_level = ast_logger_register_level("FAX");
 
 	return res;




More information about the asterisk-commits mailing list