[svn-commits] irroot: branch irroot/t38gateway-1.8 r338903 - in /team/irroot/t38gateway-1.8...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Sun Oct 2 06:46:34 CDT 2011


Author: irroot
Date: Sun Oct  2 06:44:33 2011
New Revision: 338903

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=338903
Log:
Revision 338902 - Directory Listing
Modified Sun Oct 2 10:54:30 2011 UTC (46 minutes, 4 seconds ago) by irroot

Add faxdetect framehook

Revision 338898 - Directory Listing
Modified Sun Oct 2 10:47:14 2011 UTC (53 minutes, 20 seconds ago) by irroot

Move func OOH323 to func CHANNEL

-------------------------
Merged from distrotech branch

Modified:
    team/irroot/t38gateway-1.8/addons/chan_ooh323.c
    team/irroot/t38gateway-1.8/funcs/func_channel.c
    team/irroot/t38gateway-1.8/include/asterisk/res_fax.h
    team/irroot/t38gateway-1.8/res/res_fax.c

Modified: team/irroot/t38gateway-1.8/addons/chan_ooh323.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/t38gateway-1.8/addons/chan_ooh323.c?view=diff&rev=338903&r1=338902&r2=338903
==============================================================================
--- team/irroot/t38gateway-1.8/addons/chan_ooh323.c (original)
+++ team/irroot/t38gateway-1.8/addons/chan_ooh323.c Sun Oct  2 06:44:33 2011
@@ -25,42 +25,6 @@
 #include "chan_ooh323.h"
 #include <math.h>
 
-/*** DOCUMENTATION
-	<function name="OOH323" language="en_US">
-		<synopsis>
-			Allow Setting / Reading OOH323 Settings
-		</synopsis>
-		<syntax>
-			<parameter name="name" required="true">
-				<enumlist>
-					<enum name="faxdetect">
-						<para>Fax Detect [R/W]</para>
-						<para>Returns 0 or 1</para>
-						<para>Write yes or no</para>
-					</enum>
-				</enumlist>
-				<enumlist>
-					<enum name="t38support">
-						<para>t38support [R/W]</para>
-						<para>Returns 0 or 1</para>
-						<para>Write yes or no</para>
-					</enum>
-				</enumlist>
-				<enumlist>
-					<enum name="h323id">
-						<para>Returns h323id [R]</para>
-					</enum>
-				</enumlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Read and set channel parameters in the dialplan.
-			<replaceable>name</replaceable> is one of the above only those with a [W] can be writen to.
-			</para>
-		</description>
-	</function>
-***/
-
 #define FORMAT_STRING_SIZE	512
 
 /* Defaults */
@@ -118,6 +82,8 @@
 static int ooh323_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
 static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
 static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+static int function_ooh323_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
+static int function_ooh323_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);
 
 static enum ast_rtp_glue_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp);
 static enum ast_rtp_glue_result ooh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp);
@@ -152,7 +118,8 @@
 	.queryoption = ooh323_queryoption,
 	.bridge = ast_rtp_instance_bridge,		/* XXX chan unlocked ? */
 	.early_bridge = ast_rtp_instance_early_bridge,
-
+	.func_channel_read = function_ooh323_read,
+	.func_channel_write = function_ooh323_write,
 };
 
 static struct ast_rtp_glue ooh323_rtp = {
@@ -3516,13 +3483,6 @@
 	return res;
 }
 
-/*! \brief Structure to declare a dialplan function: OOH323 */
-static struct ast_custom_function ooh323_function = {
-        .name = "OOH323",
-        .read = function_ooh323_read,
-        .write = function_ooh323_write,
-};
-
 static int load_module(void)
 {
 	int res;
@@ -3678,9 +3638,6 @@
 		/* And start the monitor for the first time */
 		restart_monitor();
 	}
-
-	/* Register dialplan functions */
-	ast_custom_function_register(&ooh323_function);
 
 	return 0;
 }
@@ -4070,9 +4027,6 @@
 		ast_verbose("	unload_module- destroying OOH323 endpoint \n");
 	}
 	ooH323EpDestroy();
-
-	/* Unregister dial plan functions */
-	ast_custom_function_unregister(&ooh323_function);
 
 	if (gH323Debug) {
 		ast_verbose("+++ ooh323  unload_module \n");

Modified: team/irroot/t38gateway-1.8/funcs/func_channel.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/t38gateway-1.8/funcs/func_channel.c?view=diff&rev=338903&r1=338902&r2=338903
==============================================================================
--- team/irroot/t38gateway-1.8/funcs/func_channel.c (original)
+++ team/irroot/t38gateway-1.8/funcs/func_channel.c Sun Oct  2 06:44:33 2011
@@ -251,6 +251,22 @@
 						The channel is either on hold or a call waiting call.</para>
 					</enum>
 				</enumlist>
+				<para><emphasis>chan_ooh323</emphasis> provides the following additional options:</para>
+				<enumlist>
+					<enum name="faxdetect">
+						<para>Fax Detect [R/W]</para>
+						<para>Returns 0 or 1</para>
+						<para>Write yes or no</para>
+					</enum>
+					<enum name="t38support">
+						<para>t38support [R/W]</para>
+						<para>Returns 0 or 1</para>
+						<para>Write yes or no</para>
+					</enum>
+					<enum name="h323id">
+						<para>Returns h323id [R]</para>
+					</enum>
+				</enumlist>
 			</parameter>
 		</syntax>
 		<description>

Modified: team/irroot/t38gateway-1.8/include/asterisk/res_fax.h
URL: http://svnview.digium.com/svn/asterisk/team/irroot/t38gateway-1.8/include/asterisk/res_fax.h?view=diff&rev=338903&r1=338902&r2=338903
==============================================================================
--- team/irroot/t38gateway-1.8/include/asterisk/res_fax.h (original)
+++ team/irroot/t38gateway-1.8/include/asterisk/res_fax.h Sun Oct  2 06:44:33 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/t38gateway-1.8/res/res_fax.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/t38gateway-1.8/res/res_fax.c?view=diff&rev=338903&r1=338902&r2=338903
==============================================================================
--- team/irroot/t38gateway-1.8/res/res_fax.c (original)
+++ team/irroot/t38gateway-1.8/res/res_fax.c Sun Oct  2 06:44:33 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 svn-commits mailing list