[asterisk-commits] irroot: branch irroot/distrotech-customers-1.8 r338900 - in /team/irroot/dist...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sun Oct 2 05:53:41 CDT 2011
Author: irroot
Date: Sun Oct 2 05:53:38 2011
New Revision: 338900
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=338900
Log:
Add faxdetect framehook
Modified:
team/irroot/distrotech-customers-1.8/include/asterisk/res_fax.h
team/irroot/distrotech-customers-1.8/res/res_fax.c
Modified: team/irroot/distrotech-customers-1.8/include/asterisk/res_fax.h
URL: http://svnview.digium.com/svn/asterisk/team/irroot/distrotech-customers-1.8/include/asterisk/res_fax.h?view=diff&rev=338900&r1=338899&r2=338900
==============================================================================
--- team/irroot/distrotech-customers-1.8/include/asterisk/res_fax.h (original)
+++ team/irroot/distrotech-customers-1.8/include/asterisk/res_fax.h Sun Oct 2 05:53:38 2011
@@ -174,6 +174,8 @@
int gateway_id;
/*! the timeout for this gateway in seconds */
int gateway_timeout;
+ /*! the id of the faxdetect framehook for this channel */
+ int faxdetect_id;
};
struct ast_fax_tech;
Modified: team/irroot/distrotech-customers-1.8/res/res_fax.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/distrotech-customers-1.8/res/res_fax.c?view=diff&rev=338900&r1=338899&r2=338900
==============================================================================
--- team/irroot/distrotech-customers-1.8/res/res_fax.c (original)
+++ team/irroot/distrotech-customers-1.8/res/res_fax.c Sun Oct 2 05:53:38 2011
@@ -184,7 +184,10 @@
<para>R/W Modem type (v17/v27/v29).</para>
</enum>
<enum name="gateway">
- <para>R/W T38 Gateway Enabled With optional fax activity timeout in seconds (yes[,gwtimeout]/no)</para>
+ <para>R/W T38 fax gateway, with optional fax activity timeout in seconds (yes[,timeout]/no)</para>
+ </enum>
+ <enum name="faxdetect">
+ <para>R/W Enable FAX detect with optional timeout in seconds seconds (yes[,timeout]/no)</para>
</enum>
<enum name="pages">
<para>R/O Number of pages transferred.</para>
@@ -285,6 +288,24 @@
unsigned int peer_write_format;
};
+/*! \brief used for fax detect framehook */
+struct fax_detect {
+ /*! \brief the start of our timeout counter */
+ struct timeval timeout_start;
+ /*! \brief faxdetect timeout */
+ int timeout;
+ /*! \brief DSP Processor */
+ struct ast_dsp *dsp;
+ /*! \brief original audio formats */
+ unsigned int orig_format;
+ /*! \brief Noise limit to end faxdetect */
+ int noiselim;
+ /*! \brief result of the framehook e[CED]/f[CNG]/n[Noise]/t[T38] */
+ int result;
+ /*! \brief fax session details */
+ struct ast_fax_session_details *details;
+};
+
static int fax_logger_level = -1;
/*! \brief maximum buckets for res_fax ao2 containers */
@@ -467,6 +488,8 @@
d->minrate = general_options.minrate;
d->maxrate = general_options.maxrate;
d->gateway_id = -1;
+ d->faxdetect_id = -1;
+ d->gateway_timeout = 0;
return d;
}
@@ -3155,6 +3178,247 @@
return gateway->framehook;
}
+/*! \brief destroy a FAX detect structure */
+static void destroy_faxdetect(void *data)
+{
+ struct fax_detect *faxdetect = data;
+
+ if (faxdetect->dsp) {
+ ast_dsp_free(faxdetect->dsp);
+ faxdetect->dsp = NULL;
+ }
+ ao2_ref(faxdetect->details, -1);
+}
+
+/*! \brief Create a new fax detect object.
+ * \param chan the channel attaching to
+ * \param timeout remove framehook in this time if set
+ * \param noiselim end faxdetect when noiselim ms of noise is detected
+ * \param dsp_detect_flag dsp faxmode detect flags
+ * \return NULL or a fax gateway object
+ */
+static struct fax_detect *fax_detect_new(struct ast_channel *chan, int timeout, int noiselim, int dsp_detect_flag)
+{
+ struct fax_detect *faxdetect = ao2_alloc(sizeof(*faxdetect), destroy_faxdetect);
+ if (!faxdetect) {
+ return NULL;
+ }
+
+ faxdetect->noiselim = noiselim;
+ faxdetect->result = 0;
+
+ if (timeout) {
+ faxdetect->timeout_start = ast_tvnow();
+ } else {
+ faxdetect->timeout_start.tv_sec = 0;
+ faxdetect->timeout_start.tv_usec = 0;
+ }
+
+ faxdetect->dsp = ast_dsp_new();
+ if (!faxdetect->dsp) {
+ ao2_ref(faxdetect, -1);
+ return NULL;
+ }
+
+ ast_dsp_set_features(faxdetect->dsp, DSP_FEATURE_FAX_DETECT);
+ if (noiselim) {
+ ast_dsp_set_faxmode(faxdetect->dsp, dsp_detect_flag || DSP_FAXMODE_DETECT_SQUELCH);
+ ast_dsp_set_threshold(faxdetect->dsp, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
+ } else {
+ ast_dsp_set_faxmode(faxdetect->dsp, dsp_detect_flag);
+ }
+ return faxdetect;
+}
+
+/*! \brief Deref the faxdetect data structure when the faxdetect framehook is detached
+ * \param data framehook data (faxdetect data)*/
+static void fax_detect_framehook_destroy(void *data) {
+ struct fax_detect *faxdetect = data;
+
+ ao2_ref(faxdetect, -1);
+}
+
+/*! \brief Fax Detect Framehook
+ *
+ * Listen for fax tones in audio path and enable jumping to a extension when detected.
+ *
+ * \param chan channel
+ * \param f frame to handle may be NULL
+ * \param event framehook event
+ * \param data framehook data (struct fax_detect *)
+ *
+ * \return processed frame or NULL when f is NULL or a null frame
+ */
+static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data) {
+ struct fax_detect *faxdetect = data;
+ struct ast_fax_session_details *details;
+ struct ast_control_t38_parameters *control_params;
+ struct ast_channel *peer;
+ int dspnoise;
+
+ details = faxdetect->details;
+
+ switch (event) {
+ case AST_FRAMEHOOK_EVENT_ATTACHED:
+ /* Setup format for DSP on ATTACH*/
+ ao2_lock(faxdetect);
+ faxdetect->orig_format = chan->readformat;
+ switch (chan->readformat) {
+ case AST_FORMAT_SLINEAR:
+ break;
+ default:
+ if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
+ ast_framehook_detach(chan, details->faxdetect_id);
+ details->faxdetect_id = -1;
+ }
+ }
+ ao2_unlock(faxdetect);
+ return NULL;
+ case AST_FRAMEHOOK_EVENT_DETACHED:
+ /* restore audio formats when we are detached */
+ ao2_lock(faxdetect);
+ ast_set_read_format(chan, faxdetect->orig_format);
+ if ((peer = ast_bridged_channel(chan))) {
+ ast_channel_make_compatible(chan, peer);
+ }
+ ao2_unlock(faxdetect);
+ return NULL;
+ case AST_FRAMEHOOK_EVENT_READ:
+ if (f) {
+ break;
+ }
+ default:
+ return f;
+ };
+
+ if ((!ast_tvzero(faxdetect->timeout_start) &&
+ (ast_tvdiff_ms(ast_tvnow(), faxdetect->timeout_start) > faxdetect->timeout))) {
+ ast_framehook_detach(chan, details->faxdetect_id);
+ details->faxdetect_id = -1;
+ }
+
+ /* only handle VOICE and CONTROL frames*/
+ switch (f->frametype) {
+ case AST_FRAME_VOICE:
+ /* We can only process some formats*/
+ switch (f->subclass.codec) {
+ case AST_FORMAT_SLINEAR:
+ break;
+ default:
+ return f;
+ }
+ break;
+ case AST_FRAME_CONTROL:
+ if (f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
+ break;
+ }
+ return f;
+ default:
+ return f;
+ }
+
+ ao2_lock(faxdetect);
+ if (f->frametype == AST_FRAME_VOICE) {
+ f = ast_dsp_process(chan, faxdetect->dsp, f);
+ if (f->frametype == AST_FRAME_DTMF) {
+ faxdetect->result = f->subclass.integer;
+ } else if ((f->frametype == AST_FRAME_VOICE) && (faxdetect->noiselim > 0)) {
+ ast_dsp_noise(faxdetect->dsp, f, &dspnoise);
+ if (dspnoise > faxdetect->noiselim) {
+ faxdetect->result = 'n';
+ }
+ }
+ } else if ((f->frametype == AST_FRAME_CONTROL) && (f->datalen != sizeof(struct ast_control_t38_parameters))) {
+ control_params = f->data.ptr;
+ switch (control_params->request_response) {
+ case AST_T38_NEGOTIATED:
+ case AST_T38_REQUEST_NEGOTIATE:
+ faxdetect->result = 't';
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (faxdetect->result) {
+ const char *target_context = S_OR(chan->macrocontext, chan->context);
+ switch (faxdetect->result) {
+ case 'f':
+ case 't':
+ ast_channel_unlock(chan);
+ if (ast_exists_extension(chan, target_context, "fax", 1,
+ S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
+ ast_channel_lock(chan);
+ ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension due to %s detection\n",
+ chan->name, (faxdetect->result == 'f') ? "CNG" : "T38");
+ pbx_builtin_setvar_helper(chan, "FAXEXTEN", chan->exten);
+ if (ast_async_goto(chan, target_context, "fax", 1)) {
+ ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", chan->name, target_context);
+ }
+ ast_frfree(f);
+ f = &ast_null_frame;
+ } else {
+ ast_channel_lock(chan);
+ ast_log(LOG_NOTICE, "FAX %s detected but no fax extension\n",
+ (faxdetect->result == 'f') ? "CNG" : "T38");
+ }
+ }
+ ast_framehook_detach(chan, details->faxdetect_id);
+ details->faxdetect_id = -1;
+ }
+
+ ao2_unlock(faxdetect);
+
+ return f;
+}
+
+/*! \brief Attach a faxdetect framehook object to a channel.
+ * \param chan the channel to attach to
+ * \param timeout remove framehook in this time if set
+ * \param noiselim end faxdetect when noiselim ms of noise is detected
+ * \param dsp_detect_flag dsp faxmode detect flags
+ * \return the faxdetect structure or NULL on error
+ * \retval -1 error
+ */
+static struct fax_detect* fax_detect_attach(struct ast_channel *chan, int timeout, int noiselim, int dsp_detect_flags)
+{
+ struct fax_detect *faxdetect;
+ struct ast_fax_session_details *details;
+ struct ast_framehook_interface fr_hook = {
+ .version = AST_FRAMEHOOK_INTERFACE_VERSION,
+ .event_cb = fax_detect_framehook,
+ .destroy_cb = fax_detect_framehook_destroy,
+ };
+
+ if (!(details = find_or_create_details(chan))) {
+ ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
+ return NULL;
+ }
+
+ /* set up the frame hook*/
+ faxdetect = fax_detect_new(chan, timeout, noiselim, dsp_detect_flags);
+ if (!faxdetect) {
+ ao2_ref(details, -1);
+ return NULL;
+ }
+
+ fr_hook.data = faxdetect;
+ faxdetect->details = details;
+ ast_channel_lock(chan);
+ details->faxdetect_id = ast_framehook_attach(chan, &fr_hook);
+ ast_channel_unlock(chan);
+
+ if (details->faxdetect_id < 0) {
+ ao2_ref(details, -1);
+ ao2_ref(faxdetect, -1);
+ return NULL;
+ }
+
+ /* return it with ref held in framhook and return*/
+ ao2_ref(faxdetect, 1);
+ return faxdetect;
+}
+
/*! \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
@@ -3164,31 +3428,13 @@
{
int timeleft = timeout;
int res = 0;
- int dspnoise = 0;
- struct ast_dsp *dsp = NULL;
struct ast_frame *f, *dup_f;
- enum ast_t38_state t38state = T38_STATE_UNKNOWN;
- unsigned int orig_read_format;
AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
-
- /* Setup DSP CNG processing */
- orig_read_format = chan->readformat;
- switch (chan->readformat) {
- case AST_FORMAT_SLINEAR:
- break;
- default:
- if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
- return -1;
- }
- }
-
- if (!(dsp = ast_dsp_new())) {
+ struct fax_detect *faxdetect = NULL;
+
+ if (!(faxdetect = fax_detect_attach(chan, 0, noiselim, DSP_FAXMODE_DETECT_CNG))) {
return -1;
}
-
- ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
- ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_SQUELCH);
- ast_dsp_set_threshold(dsp, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
@@ -3197,18 +3443,18 @@
break;
}
- if (dsp && (f->frametype == AST_FRAME_VOICE) && ((f->subclass.codec == AST_FORMAT_SLINEAR) ||
- (f->subclass.codec == AST_FORMAT_ULAW) || (f->subclass.codec == AST_FORMAT_ALAW))) {
- f = ast_dsp_process(chan, dsp, f);
- if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == 'f')) {
+ ao2_lock(faxdetect);
+ switch (faxdetect->result) {
+ case 'f':
res = 1;
- } else if ((f->frametype == AST_FRAME_VOICE) && (noiselim > 0)) {
- ast_dsp_noise(dsp, f, &dspnoise);
- if (dspnoise > noiselim) {
- break;
- }
- }
- }
+ break;
+ case 't':
+ res = 2;
+ break;
+ case 'n':
+ break;
+ }
+ ao2_unlock(faxdetect);
if (ast_is_deferrable_frame(f)) {
AST_LIST_INSERT_HEAD(&deferred_frames, f, frame_list);
@@ -3216,18 +3462,11 @@
ast_frfree(f);
}
- t38state = ast_channel_get_t38_state(chan);
- if ((t38state == T38_STATE_NEGOTIATING) || (t38state == T38_STATE_NEGOTIATED)) {
- res = 2;
+ if (res) {
break;
- } else if (res) {
- break;
- }
- }
-
- if (orig_read_format != chan->readformat) {
- ast_set_read_format(chan, orig_read_format);
- }
+ }
+ }
+ ao2_ref(faxdetect, -1);
ast_channel_lock(chan);
while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
@@ -3238,10 +3477,6 @@
}
}
ast_channel_unlock(chan);
-
- if (dsp) {
- ast_dsp_free(dsp);
- }
return res;
}
@@ -3860,6 +4095,40 @@
} else {
ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data);
}
+ } else if (!strcasecmp(data, "faxdetect")) {
+ const char *val = ast_skip_blanks(value);
+ char *timeout = strchr(val, ',');
+ unsigned int fdtimeout = 0;
+ struct fax_detect *faxdetect;
+
+ if (timeout) {
+ *timeout++ = '\0';
+ }
+
+ if (ast_true(val)) {
+ if (details->faxdetect_id < 0) {
+ if (timeout && (sscanf(timeout, "%u", &fdtimeout) == 1)) {
+ fdtimeout = fdtimeout * 1000;
+ }
+
+ faxdetect = fax_detect_attach(chan, fdtimeout, 0, DSP_FAXMODE_DETECT_CNG);
+
+ if (faxdetect && (details->faxdetect_id >= 0)) {
+ ast_debug(1, "Attached FAX detect to channel %s.\n", chan->name);
+ } else {
+ ast_log(LOG_ERROR, "Error attaching FAX detect to channel %s.\n", chan->name);
+ res = -1;
+ }
+ ao2_ref(faxdetect, -1);
+ } else {
+ ast_log(LOG_WARNING, "Attempt to attach a FAX detect on channel (%s) with FAX detect already running.\n", chan->name);
+ }
+ } else if (ast_false(val)) {
+ ast_framehook_detach(chan, details->faxdetect_id);
+ details->faxdetect_id = -1;
+ } else {
+ ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data);
+ }
} else if (!strcasecmp(data, "headerinfo")) {
ast_string_field_set(details, headerinfo, value);
} else if (!strcasecmp(data, "localstationid")) {
More information about the asterisk-commits
mailing list