[asterisk-commits] kpfleming: branch dhubbard/res_fax_spandsp r205048 - /team/dhubbard/res_fax_s...
SVN commits to the Asterisk project
asterisk-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 asterisk-commits
mailing list