[svn-commits] kpfleming: branch dhubbard/res_fax_spandsp r205048 - /team/dhubbard/res_fax_s...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 7 14:17:09 CDT 2009


Author: kpfleming
Date: Tue Jul  7 14:17:05 2009
New Revision: 205048

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=205048
Log:
bring up to date with latest res_fax changes

Modified:
    team/dhubbard/res_fax_spandsp/res/res_fax.c

Modified: team/dhubbard/res_fax_spandsp/res/res_fax.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/dhubbard/res_fax_spandsp/res/res_fax.c?view=diff&rev=205048&r1=205047&r2=205048
==============================================================================
--- team/dhubbard/res_fax_spandsp/res/res_fax.c (original)
+++ team/dhubbard/res_fax_spandsp/res/res_fax.c Tue Jul  7 14:17:05 2009
@@ -160,10 +160,8 @@
 
 static void destroy_callback(void *data) 
 {
-	struct ast_fax_session_details *details = data;
-	
-	if (details) {
-		ao2_ref(details, -1);
+	if (data) {
+		ao2_ref(data, -1);
 	}
 }
 
@@ -175,12 +173,11 @@
 /*! \brief returns a reference counted pointer to a fax datastore, if it exists */
 static struct ast_fax_session_details *find_details(struct ast_channel *chan)
 {
-	struct ast_fax_session_details *details = NULL;
-	struct ast_datastore *datastore = NULL;
+	struct ast_fax_session_details *details;
+	struct ast_datastore *datastore;
 
 	ast_channel_lock(chan);	
-	datastore = ast_channel_datastore_find(chan, &fax_datastore, NULL);
-	if (datastore == NULL) {
+	if (!(datastore = ast_channel_datastore_find(chan, &fax_datastore, NULL))) {
 		ast_channel_unlock(chan);	
 		return NULL;
 	}
@@ -197,15 +194,14 @@
 
 /*! \brief returns a reference counted details structure from the channel's fax datastore.  If the datastore
  * does not exist it will be created */	
-static struct ast_fax_session_details *get_details(struct ast_channel *chan)
-{
-	struct ast_fax_session_details *details = NULL;
-	struct ast_datastore *datastore = NULL;
+static struct ast_fax_session_details *find_or_create_details(struct ast_channel *chan)
+{
+	struct ast_fax_session_details *details;
+	struct ast_datastore *datastore;
 
 	if ((details = find_details(chan))) {
 		return details;
 	}
-
 	/* channel does not have one so we must create one */
 	if (!(details = session_details_new())) {
 		ast_log(LOG_WARNING, "channel '%s' can't get a fax details structure for the datastore!\n", chan->name);
@@ -216,14 +212,12 @@
 		ast_log(LOG_WARNING, "channel '%s' can't get a datastore!\n", chan->name);
 		return NULL;
 	}
+	/* add the datastore to the channel and increment the refcount */
 	datastore->data = details;
-
-	/* add the datastore to the channel and increment the refcount */
+	ao2_ref(details, 1);
 	ast_channel_lock(chan);
 	ast_channel_datastore_add(chan, datastore);
 	ast_channel_unlock(chan);
-	ao2_ref(details, 1);
-
 	return details;
 }
 
@@ -247,13 +241,6 @@
 #define DGMFAX_MAXBUCKETS 10
 
 #define RES_FAX_TIMEOUT 10000
-
-#define APP_FAX_ERROR(fax, chan, reason)	\
-	do {	\
-		ast_log(LOG_ERROR, "channel '%s' fax session '%d' failure, reason: '%s'\n", chan->name, fax->id, reason); \
-		pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", reason); \
-		res = ms = -1; \
-	} while (0)
 
 /*! \brief The faxregistry is used to manage information and statistics for all fax sessions. */
 static struct {
@@ -274,12 +261,11 @@
 } faxregistry;
 
 /*! \brief registered fax technology modules are put into this list */
-struct fax_module_list {
+struct fax_module {
 	const struct ast_fax_tech *tech;
-	AST_RWLIST_ENTRY(fax_module_list) list;
+	AST_RWLIST_ENTRY(fax_module) list;
 };
-static int fax_module_list_size;
-static AST_RWLIST_HEAD_STATIC(faxmodules, fax_module_list);
+static AST_RWLIST_HEAD_STATIC(faxmodules, fax_module);
 
 /*! \brief The astobj2 hash callback for sessions */
 static int session_hash_cb(const void *obj, const int flags);
@@ -373,7 +359,7 @@
 /*! \brief register a fax technology module */
 int ast_fax_tech_register(struct ast_fax_tech *tech)
 {
-	struct fax_module_list *fax;
+	struct fax_module *fax;
 
 	if (!tech || !tech->module) {
 		ast_log(LOG_ERROR, "Cannot register a fax technology missing '%s' structure!\n", tech ? "technology module" : "ast_fax_tech");
@@ -409,7 +395,6 @@
 	}
 	fax->tech = tech;
 	AST_RWLIST_INSERT_HEAD(&faxmodules, fax, list);
-	fax_module_list_size++;
 	AST_RWLIST_UNLOCK(&faxmodules);
 	ast_module_ref(ast_module_info->self);
 
@@ -423,7 +408,7 @@
 /*! \brief unregister a fax technology module */
 void ast_fax_tech_unregister(struct ast_fax_tech *tech)
 {
-	struct fax_module_list *fax;
+	struct fax_module *fax;
 
 	if (option_verbose > 3) {
 		ast_verbose(VERBOSE_PREFIX_3 "Unregistering fax module type '%s'\n", tech->type);
@@ -437,7 +422,6 @@
 		AST_RWLIST_REMOVE_CURRENT(list);
 		ast_module_unref(ast_module_info->self);
 		ast_free(fax);
-		fax_module_list_size--;
 		ast_verb(4, "Unregistered fax module type '%s'\n", tech->type);
 		break;	
 	}
@@ -520,6 +504,8 @@
 	struct ast_fax_session *s = session;
 	int n = s->id;
 
+	s->tech->destroy_session(s);
+
 	if (s->details) {
 		ao2_ref(s->details, -1);
 	}
@@ -567,8 +553,8 @@
 	d->option.ecm = AST_FAX_OPTFLAG_DEFAULT;
 	d->option.statusevents = general_options.statusevents;
 	d->modems = general_options.modem;
-	d->minrate = -1;
-	d->maxrate = -1;
+	d->minrate = general_options.minrate;
+	d->maxrate = general_options.maxrate;
 	d->maxdelay = -1;
 	d->eccdata = -1;
 	d->eccsignal = -1;
@@ -580,7 +566,7 @@
 static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *details, struct ast_channel *chan)
 {
 	struct ast_fax_session *s;
-	struct fax_module_list *faxmod;
+	struct fax_module *faxmod;
 
 	if (!details || !chan) {
 		ast_log(LOG_ERROR, "Missing '%s' structure.\n", details ? "session details" : "channel");
@@ -644,31 +630,6 @@
 	ast_debug(4, "channel '%s' using fax session '%d'\n", s->channame, s->id);
 
 	return s;
-}
-
-/*! \brief cancel an audio fax session and create a T.38 fax session */
-static struct ast_fax_session *switch_session_to_t38(struct ast_fax_session *fax, struct ast_channel *chan)
-{
-	struct ast_fax_session *t38fax;
-	struct ast_fax_session_details *t38details;
-
-	if (!(t38details = find_details(chan))) {
-		ast_log(LOG_WARNING, "channel '%s' cannot find session details.\n", chan->name);
-		return fax;
-	}
-	fax->details->option.switch_to_t38 = 1;
-	fax->tech->cancel_session(fax);
-	/* set the capabilities for a T.38 session */	
-	t38details->caps = (t38details->caps & (AST_FAX_TECH_SEND | AST_FAX_TECH_RECEIVE));
-	t38details->caps |= AST_FAX_TECH_UDP;
-
-	if (!(t38fax = fax_session_new(t38details, chan))) {
-		ast_log(LOG_ERROR, "Can't create a T.38 fax session, fax attempt failed.\n");
-		ao2_ref(t38details, -1);
-		return fax;
-	}
-	ao2_ref(t38details, -1);
-	return t38fax;
 }
 
 struct manager_event_info {
@@ -715,6 +676,13 @@
 	return 0;
 }
 
+#define GENERIC_FAX_EXEC_ERROR(fax, chan, reason)	\
+	do {	\
+		ast_log(LOG_ERROR, "channel '%s' fax session '%d' failure, reason: '%s'\n", chan->name, fax->id, reason); \
+		pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", reason); \
+		res = ms = -1; \
+	} while (0)
+
 /*! \brief this is the generic fax session handling function */
 static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_details *details)
 {
@@ -736,10 +704,60 @@
 	}
 	chancount = 1;
 
-	/* get the session capability requirements */
+	/* get the session capability requirements, and switch to T.38 if needed */
 	if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
 		details->caps |= AST_FAX_TECH_UDP;
 		t38negotiated = 1;
+	} else if ((details->option.request_t38 == AST_FAX_OPTFLAG_TRUE) &&
+		   (t38control = AST_T38_REQUEST_NEGOTIATE, (ast_indicate_data(chan, AST_CONTROL_T38, &t38control, sizeof(t38control)) == 0))) {
+		/* wait up to five seconds for negotiation to complete */
+		unsigned int timeout = 5000;
+		
+		ast_log(LOG_NOTICE, "Negotiating T.38 for %s on %s\n", (details->caps & AST_FAX_TECH_SEND) ? "send" : "receive", chan->name);
+		while (timeout > 0) {
+			ms = ast_waitfor(chan, 1000);
+			if (ms < 0) {
+				ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", chan->name);
+				res = -1;
+				break;
+			}
+			if (!ms) {
+				/* nothing happened */
+				if (timeout > 0) {
+					timeout -= 1000;
+					continue;
+				} else {
+					ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", chan->name);
+					res = -1;
+					break;
+				}
+			}
+			if (!(frame = ast_read(chan))) {
+				chancount = 0;
+				res = -1;
+				break;
+			}
+			if (frame->frametype == AST_FRAME_CONTROL && frame->subclass == AST_CONTROL_T38 && frame->datalen == sizeof(enum ast_control_t38)) {
+				t38control = *((enum ast_control_t38 *) frame->data.ptr);
+
+				ast_log(LOG_NOTICE, "got CONTROL_T38 with value %d\n", t38control);
+				if (t38control == AST_T38_NEGOTIATED) {
+					details->caps |= AST_FAX_TECH_UDP;
+					t38negotiated = 1;
+				} else {
+					/* T.38 negotiation failed */
+					ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", chan->name);
+					ast_frfree(frame);
+					break;
+				}
+			}
+			ast_frfree(frame);
+		}
+
+		if (res) {
+			details->caps |= AST_FAX_TECH_AUDIO;
+			res = 0;
+		}
 	} else {
 		details->caps |= AST_FAX_TECH_AUDIO;
 	}
@@ -766,17 +784,17 @@
 	expected_frametype = fax->tech->session_frametype(fax);
 
 	if (details->caps & AST_FAX_TECH_AUDIO) {
-		if ((res = ast_set_write_format(chan, AST_FORMAT_SLINEAR)) < 0) {
+		if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
 			ast_log(LOG_ERROR, "channel '%s' failed to set write format to signed linear'.\n", chan->name);
 			ast_fax_session_unreference(fax);
 			ast_channel_unlock(chan);
-			return res;
-		}
-		if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)) < 0) {
+			return -1;
+		}
+		if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
 			ast_log(LOG_ERROR, "channel '%s' failed to set read format to signed linear.\n", chan->name);
 			ast_fax_session_unreference(fax);
 			ast_channel_unlock(chan);
-			return res;
+			return -1;
 		}
 		if (fax->smoother) {
 			ast_smoother_free(fax->smoother);
@@ -787,19 +805,9 @@
 		}
 	}
 
-	if (t38negotiated) {
-		report_fax_status(chan, details, "T.38 Negotiated");
-	} else if (details->option.request_t38 == AST_FAX_OPTFLAG_TRUE) {
-		/* let's try to negotiate T.38 to see if we can switch */
-		t38control = AST_T38_REQUEST_NEGOTIATE;
-		ast_indicate_data(chan, AST_CONTROL_T38, &t38control, sizeof(t38control));
-		report_fax_status(chan, details, "Negotiating T.38");
-		/* wait for result of negotiation before proceeding */
-	}
-
 	fax->base_tv = ast_tvnow();
 	if (fax->tech->start_session(fax) < 0) {
-		APP_FAX_ERROR(fax, chan, "failed to start fax session");
+		GENERIC_FAX_EXEC_ERROR(fax, chan, "failed to start fax session");
 	}
 
 	pbx_builtin_setvar_helper(chan, "FAXSTATUS", NULL);
@@ -823,7 +831,7 @@
 				continue;
 			} else {
 				ast_log(LOG_WARNING, "channel '%s' timed-out during the fax transmission.\n", chan->name);
-				APP_FAX_ERROR(fax, chan, "fax session timed-out");
+				GENERIC_FAX_EXEC_ERROR(fax, chan, "fax session timed-out");
 				break;
 			}
 		}
@@ -872,32 +880,52 @@
 		}
 
 		if (frame->frametype == AST_FRAME_CONTROL && frame->subclass == AST_CONTROL_T38 && frame->datalen == sizeof(enum ast_control_t38)) {
+			unsigned int was_t38 = t38negotiated;
 			t38control = *((enum ast_control_t38 *) frame->data.ptr);
 
-			if ((t38control == AST_T38_NEGOTIATED) && !t38negotiated) {
-				/* T.38 was negotiated!  It is time to start the fax session if the technology module
- 				 * already supports T.38; otherwise, we need to switch to T.38 first */
+			switch (t38control) {
+			case AST_T38_REQUEST_NEGOTIATE:
+				/* the other end has requested a switch to T.38, so reply that we are willing, if we can
+				 * do T.38 as well
+				 */
+				t38control = AST_T38_NEGOTIATED;
+				ast_indicate_data(chan, AST_CONTROL_T38, &t38control, sizeof(t38control));
+				/* fall through to the NEGOTIATED case, since it has been */
+			case AST_T38_NEGOTIATED:
 				t38negotiated = 1;
-				if (!(fax->tech->caps & AST_FAX_TECH_UDP)) {
-					struct ast_fax_session *t38fax;
-
-					t38fax = switch_session_to_t38(fax, chan);
-					if (t38fax == fax) {
-						ast_log(LOG_ERROR, "channel '%s' failed to switch to a T.38 fax session\n", chan->name);
-						APP_FAX_ERROR(fax, chan, "Failed to switch to T.38");
-						break;
-					}
-					fax = t38fax;
-					expected_frametype = fax->tech->session_frametype(fax);
-					report_fax_status(chan, details, "T.38 Negotiated");
-
-					if (option_verbose > 3) {
-						ast_verbose(VERBOSE_PREFIX_3 "Channel '%s' switched to T.38 fax session '%d'.\n", chan->name, fax->id);
-					}
+				break;
+			default:
+				break;
+			}
+			if (t38negotiated && !was_t38) {
+				/* time to cancel the existing audio fax session and create a new T.38 session
+				 * if possible. if not, we have to abort, since the channel has already
+				 * switched to T.38.
+				 */
+				details->option.switch_to_t38 = 1;
+				fax->tech->cancel_session(fax);
+				
+				details->caps &= ~AST_FAX_TECH_AUDIO;
+				details->caps |= AST_FAX_TECH_UDP;
+
+				if (!(fax = fax_session_new(details, chan))) {
+					ast_log(LOG_ERROR, "Can't create a T.38 fax session, fax attempt failed.\n");
+					GENERIC_FAX_EXEC_ERROR(fax, chan, "Failed to create T.38 fax session");
+					ast_frfree(frame);
+					break;
+				}
+
+				expected_frametype = fax->tech->session_frametype(fax);
+				report_fax_status(chan, details, "T.38 Negotiated");
+				
+				if (option_verbose > 3) {
+					ast_verbose(VERBOSE_PREFIX_3 "Channel '%s' switched to T.38 fax session '%d'.\n", chan->name, fax->id);
 				}
 				fax->base_tv = ast_tvnow();
 				if (fax->tech->start_session(fax) < 0) {
-					APP_FAX_ERROR(fax, chan, "Failed to start T.38 fax session");
+					GENERIC_FAX_EXEC_ERROR(fax, chan, "Failed to start T.38 fax session");
+					ast_frfree(frame);
+					break;
 				} else {
 					report_fax_status(chan, fax->details, "Fax Transmission In Progress");
 				}
@@ -908,7 +936,7 @@
 			if (fax->smoother) {
 				/* push the frame into a smoother */
 				if (ast_smoother_feed(fax->smoother, frame) < 0) {
-					APP_FAX_ERROR(fax, chan, "Failed to feed the smoother");
+					GENERIC_FAX_EXEC_ERROR(fax, chan, "Failed to feed the smoother");
 				}
 				while ((f = ast_smoother_read(fax->smoother)) && (f->data.ptr)) {
 					/* write the frame to the fax stack */
@@ -937,8 +965,6 @@
 	snprintf(tbuf, sizeof(tbuf), "%d", details->pages_transferred);
 	pbx_builtin_setvar_helper(chan, "FAXPAGES", tbuf);
 
-	fax->tech->destroy_session(fax);
-
 	ast_atomic_fetchadd_int(&faxregistry.fax_complete, 1);
 	if (!strcasecmp(fax->details->result, "FAILED")) {
 		ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
@@ -1009,7 +1035,7 @@
 
 	/* Get a fax session details structure from the channel's fax datastore and create one if
  	 * it does not already exist. */
-	if (!(details = get_details(chan))) {
+	if (!(details = find_or_create_details(chan))) {
 		ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
 		return -1;
 	}
@@ -1135,7 +1161,7 @@
 
 	/* Get a requirement structure and set it.  This structure is used
 	 * to tell the fax technology module about the higher level fax session */
-	if (!(details = get_details(chan))) {
+	if (!(details = find_or_create_details(chan))) {
 		ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
 		return -1;
 	}
@@ -1244,7 +1270,7 @@
 
 static char *cli_fax_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct fax_module_list *fax;
+	struct fax_module *fax;
 
 	switch(cmd) {
 	case CLI_INIT:
@@ -1310,7 +1336,8 @@
 /*! \brief display registered fax capabilities */
 static char *cli_fax_show_capabilities(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct fax_module_list *fax;
+	struct fax_module *fax;
+	unsigned int num_modules = 0;
 	
 	switch (cmd) {
 	case CLI_INIT:
@@ -1328,9 +1355,10 @@
 	AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
 		ast_cli(a->fd, "%-15s : %s\n%-15s : %s\n%-15s : ", "Type", fax->tech->type, "Description", fax->tech->description, "Capabilities");
 		fax->tech->cli_show_capabilities(a->fd);
-	}
-	ast_cli(a->fd, "%d registered modules\n\n", fax_module_list_size);
+		num_modules++;
+	}
 	AST_RWLIST_UNLOCK(&faxmodules);
+	ast_cli(a->fd, "%d registered modules\n\n", num_modules);
 
 	return CLI_SUCCESS;
 }
@@ -1374,7 +1402,7 @@
 /*! \brief display fax stats */
 static char *cli_fax_show_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct fax_module_list *fax;
+	struct fax_module *fax;
 	
 	switch (cmd) {
 	case CLI_INIT:
@@ -1532,7 +1560,7 @@
 /*! \brief FAXOPT read function returns the contents of a fax option */
 static int acf_faxopt_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
-	struct ast_fax_session_details *details = get_details(chan);
+	struct ast_fax_session_details *details = find_details(chan);
 
 	if (!details) {
 		ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
@@ -1584,7 +1612,7 @@
 	int res;
 	struct ast_fax_session_details *details;
 
-	if (!(details = get_details(chan))) {
+	if (!(details = find_or_create_details(chan))) {
 		ast_log(LOG_WARNING, "channel '%s' can't set FAXOPT(%s) to '%s' because it failed to create a datastore.\n", chan->name, data, value);
 		return -1;
 	}




More information about the svn-commits mailing list