[svn-commits] irroot: branch irroot/distrotech-customers-trunk r329101 - /team/irroot/distr...
SVN commits to the Digium repositories
svn-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 svn-commits
mailing list