[asterisk-commits] kpfleming: branch dhubbard/res_fax_spandsp r208742 - /team/dhubbard/res_fax_s...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jul 24 16:52:42 CDT 2009
Author: kpfleming
Date: Fri Jul 24 16:52:39 2009
New Revision: 208742
URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=208742
Log:
Bring in the latest res_fax changes... this still doesn't work with the current T.38 negotiation control frames, but that will be rectified soon
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=208742&r1=208741&r2=208742
==============================================================================
--- team/dhubbard/res_fax_spandsp/res/res_fax.c (original)
+++ team/dhubbard/res_fax_spandsp/res/res_fax.c Fri Jul 24 16:52:39 2009
@@ -370,7 +370,6 @@
!tech->destroy_session ||
!tech->read ||
!tech->write ||
- !tech->session_frametype ||
!tech->start_session ||
!tech->cancel_session ||
!tech->cli_show_capabilities ||
@@ -427,21 +426,6 @@
}
AST_RWLIST_TRAVERSE_SAFE_END;
AST_RWLIST_UNLOCK(&faxmodules);
-}
-
-/*! \brief unreference a fax session */
-void *ast_fax_session_unreference(struct ast_fax_session *fax)
-{
- if (!fax) {
- ast_log(LOG_ERROR, "no fax session to unreference!\n");
- return NULL;
- }
- ao2_lock(faxregistry.container);
- if (ao2_ref(fax, -1) == 2) {
- ao2_unlink(faxregistry.container, fax);
- }
- ao2_unlock(faxregistry.container);
- return NULL;
}
/*! \brief convert a ast_fax_state to a string */
@@ -456,6 +440,8 @@
return "Open";
case AST_FAX_STATE_ACTIVE:
return "Active";
+ case AST_FAX_STATE_CLOSING:
+ return "Closing";
case AST_FAX_STATE_COMPLETE:
return "Complete";
case AST_FAX_STATE_ZOMBIE:
@@ -502,35 +488,30 @@
static void destroy_session(void *session)
{
struct ast_fax_session *s = session;
- int n = s->id;
-
- s->tech->destroy_session(s);
+
+ if (s->tech) {
+ if (s->tech_pvt) {
+ s->tech->destroy_session(s);
+ }
+ ast_module_unref(s->tech->module);
+ }
if (s->details) {
ao2_ref(s->details, -1);
}
- if (s->tech_pvt) {
- ast_debug(4, "freeing technology implementation structure.\n");
- ast_free(s->tech_pvt);
- }
-
if (s->debug_info) {
ast_debug(4, "freeing debug_info.\n");
ast_free(s->debug_info);
}
- if (s->tech) {
- ast_module_unref(s->tech->module);
- }
-
if (s->smoother) {
ast_smoother_free(s->smoother);
}
ast_atomic_fetchadd_int(&faxregistry.active_sessions, -1);
- ast_debug(4, "channel '%s' fax session '%d' destroyed\n", s->channame, n);
+ ast_debug(4, "channel '%s' fax session '%d' destroyed\n", s->channame, s->id);
ast_free(s->channame);
}
@@ -577,6 +558,8 @@
return NULL;
}
+ ast_atomic_fetchadd_int(&faxregistry.active_sessions, 1);
+
if (details->option.debug && (details->caps & AST_FAX_TECH_AUDIO)) {
if (!(s->debug_info = ast_calloc(1, sizeof(*(s->debug_info))))) {
ao2_ref(s, -1);
@@ -594,7 +577,6 @@
ao2_ref(s->details, 1);
s->state = AST_FAX_STATE_UNINITIALIZED;
- ast_atomic_fetchadd_int(&faxregistry.active_sessions, 1);
details->id = s->id = ast_atomic_fetchadd_int(&faxregistry.nextsessionname, 1);
/* locate a fax technology module that can handle said requirements */
@@ -680,6 +662,7 @@
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); \
+ if (ast_strlen_zero(fax->details->result)) ast_string_field_set(fax->details, result, "FAILED"); \
res = ms = -1; \
} while (0)
@@ -688,8 +671,9 @@
{
int ms = 1000;
int timeout = RES_FAX_TIMEOUT;
- int res = 0, chancount, ofd;
- int exception, expected_frametype;
+ int res = 0, chancount;
+ int expected_frametype = -1;
+ int expected_framesubclass = -1;
char tbuf[10];
int t38negotiated = 0;
const char *tempvar;
@@ -697,6 +681,7 @@
struct ast_fax_session *fax = NULL;
struct ast_frame *frame = NULL;
struct ast_channel *c = chan;
+ enum ast_t38_state t38_state;
if (!chan || !details) {
ast_log(LOG_ERROR, "missing '%s' structure.\n", chan ? "session requirements" : "channel");
@@ -705,10 +690,11 @@
chancount = 1;
/* get the session capability requirements, and switch to T.38 if needed */
- if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
+ if ((t38_state = 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) &&
+ } else if ((t38_state != T38_STATE_UNAVAILABLE) &&
+ (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;
@@ -740,16 +726,23 @@
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) {
+ switch (t38control) {
+ case AST_T38_NEGOTIATED:
+ ast_log(LOG_NOTICE, "Negotiated T.38 for %s on %s\n", (details->caps & AST_FAX_TECH_SEND) ? "send" : "receive", chan->name);
details->caps |= AST_FAX_TECH_UDP;
t38negotiated = 1;
- } else {
- /* T.38 negotiation failed */
+ break;
+ case AST_T38_REFUSED:
+ ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", chan->name);
+ res = -1;
+ break;
+ default:
ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", chan->name);
- ast_frfree(frame);
+ res = -1;
break;
}
+ ast_frfree(frame);
+ break;
}
ast_frfree(frame);
}
@@ -781,18 +774,24 @@
report_fax_status(chan, details, "No Available Resource");
return -1;
}
- expected_frametype = fax->tech->session_frametype(fax);
-
if (details->caps & AST_FAX_TECH_AUDIO) {
+ expected_frametype = AST_FRAME_VOICE;;
+ expected_framesubclass = AST_FORMAT_SLINEAR;
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);
+ ao2_lock(faxregistry.container);
+ ao2_unlink(faxregistry.container, fax);
+ ao2_unlock(faxregistry.container);
+ ao2_ref(fax, -1);
ast_channel_unlock(chan);
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);
+ ao2_lock(faxregistry.container);
+ ao2_unlink(faxregistry.container, fax);
+ ao2_unlock(faxregistry.container);
+ ao2_ref(fax, -1);
ast_channel_unlock(chan);
return -1;
}
@@ -803,6 +802,9 @@
if (!(fax->smoother = ast_smoother_new(320))) {
ast_log(LOG_WARNING, "Channel '%s' fax session '%d' failed to obtain a smoother.\n", chan->name, fax->id);
}
+ } else if (details->caps & AST_FAX_TECH_UDP) {
+ expected_frametype = AST_FRAME_MODEM;
+ expected_framesubclass = AST_MODEM_T38;
}
fax->base_tv = ast_tvnow();
@@ -816,46 +818,13 @@
/* handle frames for the session */
while ((ms > -1) && (timeout > 0)) {
+ struct ast_channel *ready_chan;
+ int ofd, exception;
+
ms = 1000;
- ast_waitfor_nandfds(&c, chancount, &fax->fds, fax->fdcount, &exception, &ofd, &ms);
- if (ms < 0) {
- /* bad stuff happened */
- ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", chan->name);
- res = ms;
- break;
- }
- if (!ms) {
- /* nothing happened */
- if (timeout > 0) {
- timeout -= 1000;
- continue;
- } else {
- ast_log(LOG_WARNING, "channel '%s' timed-out during the fax transmission.\n", chan->name);
- GENERIC_FAX_EXEC_ERROR(fax, chan, "fax session timed-out");
- break;
- }
- }
- if (fax->fdcount && (ofd == fax->fds)) {
- /* read a frame from the fax stack and send it out the channel.
- * the fax stack will return a NULL if the fax session has already completed */
- if (!(frame = fax->tech->read(fax))) {
- break;
- }
-
- if (fax->debug_info && fax->debug_info->debug_frame_hook) {
- ao2_lock(fax);
- fax->debug_info->frame_s2c = frame;
- fax->debug_info->debug_frame_hook(fax);
- fax->debug_info->frame_s2c = NULL;
- ao2_unlock(fax);
- }
-
- ast_write(chan, frame);
- fax->frames_sent++;
- ast_frfree(frame);
- timeout = RES_FAX_TIMEOUT;
- continue;
- } else {
+ errno = 0;
+ ready_chan = ast_waitfor_nandfds(&c, chancount, &fax->fds, fax->fdcount, &exception, &ofd, &ms);
+ if (ready_chan) {
if (!(frame = ast_read(chan))) {
/* the channel is probably gone, so lets stop polling on it and let the
* fax session complete before we exit the application. BUT, we need to
@@ -864,6 +833,7 @@
c = NULL;
chancount = 0;
timeout -= (1000 - ms);
+ fax->tech->cancel_session(fax);
if (fax->tech->generate_silence) {
fax->tech->generate_silence(fax);
}
@@ -877,100 +847,154 @@
fax->debug_info->frame_c2s = NULL;
ao2_unlock(fax);
}
- }
-
- 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);
-
- 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;
- 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);
+
+ 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);
- 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);
+ 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;
+ break;
+ default:
break;
}
-
- expected_frametype = fax->tech->session_frametype(fax);
- report_fax_status(chan, details, "T.38 Negotiated");
+ 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);
+ ao2_lock(faxregistry.container);
+ ao2_unlink(faxregistry.container, fax);
+ ao2_unlock(faxregistry.container);
+ ao2_ref(fax, -1);
+
+ details->caps &= ~AST_FAX_TECH_AUDIO;
+ details->caps |= AST_FAX_TECH_UDP;
+ expected_frametype = AST_FRAME_MODEM;
+ expected_framesubclass = AST_MODEM_T38;
+
+ if (!(fax = fax_session_new(details, chan))) {
+ ast_log(LOG_ERROR, "Can't create a T.38 fax session, fax attempt failed.\n");
+ pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", "Failed to create T.38 fax session");
+ report_fax_status(chan, details, "Failed to switch to T.38");
+ ast_string_field_set(details, result, "FAILED");
+ res = ms = -1;
+ ast_frfree(frame);
+ break;
+ }
+
+ 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) {
+ GENERIC_FAX_EXEC_ERROR(fax, chan, "Failed to start T.38 fax session");
+ ast_frfree(frame);
+ break;
+ } else {
+ report_fax_status(chan, details, "Fax Transmission In Progress");
+ }
+ }
+ } else if ((frame->frametype == expected_frametype) &&
+ (frame->subclass == expected_framesubclass)) {
+ struct ast_frame *f;
- 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) {
- GENERIC_FAX_EXEC_ERROR(fax, chan, "Failed to start T.38 fax session");
- ast_frfree(frame);
- break;
+ if (fax->smoother) {
+ /* push the frame into a smoother */
+ if (ast_smoother_feed(fax->smoother, frame) < 0) {
+ 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 */
+ fax->tech->write(fax, f);
+ fax->frames_received++;
+ timeout = RES_FAX_TIMEOUT;
+ }
} else {
- report_fax_status(chan, fax->details, "Fax Transmission In Progress");
- }
- }
- } else if (frame->frametype == expected_frametype) {
- struct ast_frame *f;
-
- if (fax->smoother) {
- /* push the frame into a smoother */
- if (ast_smoother_feed(fax->smoother, frame) < 0) {
- 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 */
- fax->tech->write(fax, f);
+ fax->tech->write(fax, frame);
fax->frames_received++;
timeout = RES_FAX_TIMEOUT;
}
+ }
+ ast_frfree(frame);
+ } else if (ofd == fax->fds) {
+ /* read a frame from the fax stack and send it out the channel.
+ * the fax stack will return a NULL if the fax session has already completed */
+ if (!(frame = fax->tech->read(fax))) {
+ break;
+ }
+
+ if (fax->debug_info && fax->debug_info->debug_frame_hook) {
+ ao2_lock(fax);
+ fax->debug_info->frame_s2c = frame;
+ fax->debug_info->debug_frame_hook(fax);
+ fax->debug_info->frame_s2c = NULL;
+ ao2_unlock(fax);
+ }
+
+ ast_write(chan, frame);
+ fax->frames_sent++;
+ ast_frfree(frame);
+ timeout = RES_FAX_TIMEOUT;
+ } else {
+ if (ms && (ofd < 0)) {
+ if ((errno == 0) || (errno == EINTR)) {
+ timeout -= (1000 - ms);
+ continue;
+ } else {
+ ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", chan->name);
+ res = ms;
+ break;
+ }
} else {
- /* write the frame to the fax stack */
- fax->tech->write(fax, frame);
- fax->frames_received++;
- timeout = RES_FAX_TIMEOUT;
+ /* nothing happened */
+ if (timeout > 0) {
+ timeout -= 1000;
+ continue;
+ } else {
+ ast_log(LOG_WARNING, "channel '%s' timed-out during the fax transmission.\n", chan->name);
+ GENERIC_FAX_EXEC_ERROR(fax, chan, "fax session timed-out");
+ break;
+ }
}
}
- ast_frfree(frame);
}
ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, ms: %d, res: %d }\n", chan->name, timeout, ms, res);
- pbx_builtin_setvar_helper(chan, "FAXSTATUS", fax->details->result);
- pbx_builtin_setvar_helper(chan, "FAXERROR", fax->details->error);
- pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", fax->details->resultstr);
- pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", fax->details->remotestationid);
- pbx_builtin_setvar_helper(chan, "FAXBITRATE", fax->details->transfer_rate);
- pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", fax->details->resolution);
+ pbx_builtin_setvar_helper(chan, "FAXSTATUS", details->result);
+ pbx_builtin_setvar_helper(chan, "FAXERROR", details->error);
+ pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", details->resultstr);
+ pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", details->remotestationid);
+ pbx_builtin_setvar_helper(chan, "FAXBITRATE", details->transfer_rate);
+ pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", details->resolution);
snprintf(tbuf, sizeof(tbuf), "%d", details->pages_transferred);
pbx_builtin_setvar_helper(chan, "FAXPAGES", tbuf);
ast_atomic_fetchadd_int(&faxregistry.fax_complete, 1);
- if (!strcasecmp(fax->details->result, "FAILED")) {
+ if (!strcasecmp(details->result, "FAILED")) {
ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
}
- ast_fax_session_unreference(fax);
+ if (fax) {
+ ao2_lock(faxregistry.container);
+ ao2_unlink(faxregistry.container, fax);
+ ao2_unlock(faxregistry.container);
+ ao2_ref(fax, -1);
+ }
/* return the chancount so the calling function can determine if the channel hungup during this fax session or not */
return chancount;
@@ -1561,6 +1585,7 @@
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 = find_details(chan);
+ int res = 0;
if (!details) {
ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
@@ -1598,18 +1623,17 @@
ast_fax_modem_to_str(details->modems, buf, len);
} else {
ast_log(LOG_WARNING, "channel '%s' can't read FAXOPT(%s) because it is unhandled!\n", chan->name, data);
- ao2_ref(details, -1);
- return -1;
+ res = -1;
}
ao2_ref(details, -1);
- return 0;
+ return res;
}
/*! \brief FAXOPT write function modifies the contents of a fax option */
static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
- int res;
+ int res = 0;
struct ast_fax_session_details *details;
if (!(details = find_or_create_details(chan))) {
@@ -1633,24 +1657,29 @@
} else if (!strcasecmp(data, "t38_ecc_data")) {
if ((res = sscanf(value, "%d", &details->eccdata)) != 1) {
ast_log(LOG_ERROR, "Huh? channel '%s' scanf(%s) returned '%d'\n", chan->name, value, res);
+ } else {
+ res = 0;
}
} else if (!strcasecmp(data, "t38_ecc_signal")) {
if ((res = sscanf(value, "%d", &details->eccsignal)) != 1) {
ast_log(LOG_ERROR, "Huh? channel '%s' scanf(%s) returned '%d'\n", chan->name, value, res);
+ } else {
+ res = 0;
}
} else if (!strcasecmp(data, "t38_maxdelay")) {
if ((res = sscanf(value, "%d", &details->maxdelay)) != 1) {
ast_log(LOG_ERROR, "Huh? channel '%s' scanf(%s) returned '%d'\n", chan->name, value, res);
+ } else {
+ res = 0;
}
} else {
ast_log(LOG_WARNING, "channel '%s' set FAXOPT(%s) to '%s' is unhandled!\n", chan->name, data, value);
- ao2_ref(details, -1);
- return -1;
+ res = -1;
}
ao2_ref(details, -1);
- return 0;
+ return res;
}
/*! \brief FAXOPT dialplan function */
More information about the asterisk-commits
mailing list