[asterisk-commits] rmudgett: branch dvossel/generic_aoc r259107 - in /team/dvossel/generic_aoc: ...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Apr 26 16:47:29 CDT 2010
Author: rmudgett
Date: Mon Apr 26 16:47:25 2010
New Revision: 259107
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=259107
Log:
Merged revisions 258833,258878,258919,258958,258999,259081 via svnmerge from
https://origsvn.digium.com/svn/asterisk/team/rmudgett/aoc_event
................
r258833 | root | 2010-04-25 13:33:10 -0500 (Sun, 25 Apr 2010) | 27 lines
Merged revisions 258782 via svnmerge from
file:///srv/subversion/repos/asterisk/team/group/CCSS
................
r258782 | root | 2010-04-25 13:18:32 -0500 (Sun, 25 Apr 2010) | 20 lines
Merged revisions 258776 via svnmerge from
file:///srv/subversion/repos/asterisk/trunk
................
r258776 | tilghman | 2010-04-25 13:12:14 -0500 (Sun, 25 Apr 2010) | 13 lines
Merged revisions 258775 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r258775 | tilghman | 2010-04-25 13:09:05 -0500 (Sun, 25 Apr 2010) | 6 lines
When StopMonitor is called, ensure that it will not be restarted by a channel event.
(closes issue #16590)
Reported by: kkm
Patches:
resmonitor-16590-trunk.239289.diff uploaded by kkm (license 888)
........
................
................
................
r258878 | root | 2010-04-25 14:23:16 -0500 (Sun, 25 Apr 2010) | 29 lines
Merged revisions 258857 via svnmerge from
file:///srv/subversion/repos/asterisk/team/group/CCSS
................
r258857 | root | 2010-04-25 14:17:46 -0500 (Sun, 25 Apr 2010) | 22 lines
Merged revisions 258838,258855 via svnmerge from
file:///srv/subversion/repos/asterisk/trunk
........
r258838 | may | 2010-04-25 13:34:29 -0500 (Sun, 25 Apr 2010) | 12 lines
Don't pass zero length callerid to ooh323 stack
Don't pass zero callerid string to ooh323 stack because it can't encode this properly and
can't generate setup message.
(closes issue #17186)
Reported by: vmikhelson
Patches:
zero_callerid_num.patch uploaded by may213 (license 454)
Tested by: may213
........
r258855 | may | 2010-04-25 13:51:37 -0500 (Sun, 25 Apr 2010) | 2 lines
additional checking related to issue 17186
........
................
................
r258919 | root | 2010-04-26 10:23:07 -0500 (Mon, 26 Apr 2010) | 28 lines
Merged revisions 258898 via svnmerge from
file:///srv/subversion/repos/asterisk/team/group/CCSS
................
r258898 | root | 2010-04-26 10:17:45 -0500 (Mon, 26 Apr 2010) | 21 lines
Merged revisions 258896 via svnmerge from
file:///srv/subversion/repos/asterisk/trunk
........
r258896 | mnicholson | 2010-04-26 09:18:15 -0500 (Mon, 26 Apr 2010) | 14 lines
Update res_fax and res_fax_spandsp to be compatible with Fax For Asterisk 1.2.
The fax session initilization code for T.38 faxes has been rewritten. T.38 session initialization was removed from generic_fax_exec, and split into two different code paths for receive and send. Also the 'z' option (to send a T.38 reinvite if we do not receive one) was added to sendfax.
In the output of 'fax show sessions', the 'Type' column has been renamed to 'Tech' and replaced with a new 'Tech' column that will report 'G.711' or 'T.38'.
Control of ECM defaults has been added to res_fax
A 'fax show settings' CLI command has been added.
Support of the new AST_T38_REQUEST_PARMS control method request to handle channels that have already received a T.38 reinvite before the FAX application is start has been added.
Support for the 'fax show settings' command has been added to res_fax_spandsp and handling of the ECM flag has been slightly altered.
........
................
................
r258958 | root | 2010-04-26 11:23:20 -0500 (Mon, 26 Apr 2010) | 22 lines
Merged revisions 258937 via svnmerge from
file:///srv/subversion/repos/asterisk/team/group/CCSS
................
r258937 | root | 2010-04-26 11:17:45 -0500 (Mon, 26 Apr 2010) | 15 lines
Merged revisions 258934 via svnmerge from
file:///srv/subversion/repos/asterisk/trunk
........
r258934 | lmadsen | 2010-04-26 10:59:34 -0500 (Mon, 26 Apr 2010) | 7 lines
Small error in the T.140 RTP port verbose log.
(closes issue #16988)
Reported by: frawd
Patches:
chan_sip_sdp_verbose_fix.diff uploaded by frawd (license 610)
Tested by: russell
........
................
................
r258999 | root | 2010-04-26 14:23:04 -0500 (Mon, 26 Apr 2010) | 18 lines
Merged revisions 258978 via svnmerge from
file:///srv/subversion/repos/asterisk/team/group/CCSS
................
r258978 | root | 2010-04-26 14:17:43 -0500 (Mon, 26 Apr 2010) | 11 lines
Merged revisions 258974 via svnmerge from
file:///srv/subversion/repos/asterisk/trunk
........
r258974 | diruggles | 2010-04-26 14:05:47 -0500 (Mon, 26 Apr 2010) | 4 lines
Line 24 missed in compatibility fix in revision 233577
added a "fun:" prefix line 24
........
................
................
r259081 | root | 2010-04-26 16:28:57 -0500 (Mon, 26 Apr 2010) | 33 lines
Merged revisions 259027 via svnmerge from
file:///srv/subversion/repos/asterisk/team/group/CCSS
................
r259027 | root | 2010-04-26 16:18:08 -0500 (Mon, 26 Apr 2010) | 26 lines
Merged revisions 259023 via svnmerge from
file:///srv/subversion/repos/asterisk/trunk
................
r259023 | mmichelson | 2010-04-26 16:13:35 -0500 (Mon, 26 Apr 2010) | 19 lines
Merged revisions 259018 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r259018 | mmichelson | 2010-04-26 16:03:08 -0500 (Mon, 26 Apr 2010) | 13 lines
Prevent Newchannel manager events for dummy channels.
No Newchannel manager event will be fired for channels that are
allocated to not match a registered technology type. Thus bogus
channels allocated solely for variable substitution or CDR
operations do not result in a Newchannel event.
(closes issue #16957)
Reported by: atis
Review: https://reviewboard.asterisk.org/r/601
........
................
................
................
Modified:
team/dvossel/generic_aoc/ (props changed)
team/dvossel/generic_aoc/addons/chan_ooh323.c
team/dvossel/generic_aoc/channels/chan_sip.c
team/dvossel/generic_aoc/contrib/valgrind.supp
team/dvossel/generic_aoc/include/asterisk/res_fax.h
team/dvossel/generic_aoc/main/channel.c
team/dvossel/generic_aoc/res/res_fax.c
team/dvossel/generic_aoc/res/res_fax_spandsp.c
team/dvossel/generic_aoc/res/res_monitor.c
Propchange: team/dvossel/generic_aoc/
------------------------------------------------------------------------------
--- aoc_event-integrated (original)
+++ aoc_event-integrated Mon Apr 26 16:47:25 2010
@@ -1,1 +1,1 @@
-/team/group/CCSS:1-258759
+/team/group/CCSS:1-259080
Propchange: team/dvossel/generic_aoc/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.
Propchange: team/dvossel/generic_aoc/
------------------------------------------------------------------------------
--- generic_aoc-integrated (original)
+++ generic_aoc-integrated Mon Apr 26 16:47:25 2010
@@ -1,1 +1,1 @@
-/team/rmudgett/aoc_event:1-258763
+/team/rmudgett/aoc_event:1-259089
Propchange: team/dvossel/generic_aoc/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Apr 26 16:47:25 2010
@@ -1,1 +1,1 @@
-/trunk:1-257854
+/trunk:1-259026
Modified: team/dvossel/generic_aoc/addons/chan_ooh323.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/addons/chan_ooh323.c?view=diff&rev=259107&r1=259106&r2=259107
==============================================================================
--- team/dvossel/generic_aoc/addons/chan_ooh323.c (original)
+++ team/dvossel/generic_aoc/addons/chan_ooh323.c Mon Apr 26 16:47:25 2010
@@ -1882,10 +1882,10 @@
}
ast_mutex_lock(&p->lock);
- if (p->callerid_name) {
+ if (!ast_strlen_zero(p->callerid_name)) {
ooCallSetCallerId(call, p->callerid_name);
}
- if (p->callerid_num) {
+ if (!ast_strlen_zero(p->callerid_num)) {
i = 0;
while (*(p->callerid_num + i) != '\0') {
if(!isdigit(*(p->callerid_num+i))) { break; }
@@ -1894,7 +1894,7 @@
if(*(p->callerid_num+i) == '\0')
ooCallSetCallingPartyNumber(call, p->callerid_num);
else {
- if(!p->callerid_name)
+ if(ast_strlen_zero(p->callerid_name))
ooCallSetCallerId(call, p->callerid_num);
}
}
@@ -1907,7 +1907,7 @@
ast_verbose("Setting dialed digits %s\n", p->caller_dialedDigits);
}
ooCallAddAliasDialedDigits(call, p->caller_dialedDigits);
- } else if (p->callerid_num) {
+ } else if (!ast_strlen_zero(p->callerid_num)) {
if (ooIsDailedDigit(p->callerid_num)) {
if (gH323Debug) {
ast_verbose("setting callid number %s\n", p->callerid_num);
Modified: team/dvossel/generic_aoc/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/channels/chan_sip.c?view=diff&rev=259107&r1=259106&r2=259107
==============================================================================
--- team/dvossel/generic_aoc/channels/chan_sip.c (original)
+++ team/dvossel/generic_aoc/channels/chan_sip.c Mon Apr 26 16:47:25 2010
@@ -8031,7 +8031,7 @@
memcpy(&tsin.sin_addr, thp->h_addr, sizeof(tsin.sin_addr));
ast_rtp_instance_set_remote_address(p->trtp, &tsin);
if (debug)
- ast_verbose("Peer T.140 RTP is at port %s:%d\n", ast_inet_ntoa(vsin.sin_addr), ntohs(vsin.sin_port));
+ ast_verbose("Peer T.140 RTP is at port %s:%d\n", ast_inet_ntoa(tsin.sin_addr), ntohs(tsin.sin_port));
if ((p->jointcapability & AST_FORMAT_T140RED)) {
p->red = 1;
ast_rtp_red_init(p->trtp, 300, red_data_pt, 2);
@@ -8060,7 +8060,7 @@
}
}
} else {
- memcpy(&isin.sin_addr, ihp->h_addr, sizeof(sin.sin_addr));
+ memcpy(&isin.sin_addr, ihp->h_addr, sizeof(isin.sin_addr));
}
ast_udptl_set_peer(p->udptl, &isin);
if (debug)
Modified: team/dvossel/generic_aoc/contrib/valgrind.supp
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/contrib/valgrind.supp?view=diff&rev=259107&r1=259106&r2=259107
==============================================================================
--- team/dvossel/generic_aoc/contrib/valgrind.supp (original)
+++ team/dvossel/generic_aoc/contrib/valgrind.supp Mon Apr 26 16:47:25 2010
@@ -21,7 +21,7 @@
{
dlclose-4
Memcheck:Addr4
- ...
+ fun:...
fun:dlclose
fun:load_dynamic_module
fun:...
Modified: team/dvossel/generic_aoc/include/asterisk/res_fax.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/include/asterisk/res_fax.h?view=diff&rev=259107&r1=259106&r2=259107
==============================================================================
--- team/dvossel/generic_aoc/include/asterisk/res_fax.h (original)
+++ team/dvossel/generic_aoc/include/asterisk/res_fax.h Mon Apr 26 16:47:25 2010
@@ -139,13 +139,19 @@
/*! flag to send debug manager events */
uint32_t debug:2;
/*! flag indicating the use of Error Correction Mode (ECM) */
- uint32_t ecm:2;
+ uint32_t ecm:1;
/*! flag indicating the sending of status manager events */
uint32_t statusevents:2;
/*! allow audio mode FAX on T.38-capable channels */
uint32_t allow_audio:2;
/*! indicating the session switched to T38 */
uint32_t switch_to_t38:1;
+ /*! flag indicating whether CED should be sent (for receive mode) */
+ uint32_t send_ced:1;
+ /*! flag indicating whether CNG should be sent (for send mode) */
+ uint32_t send_cng:1;
+ /*! send a T.38 reinvite */
+ uint32_t request_t38:1;
};
} option;
/*! override the minimum transmission rate with a channel variable */
@@ -181,6 +187,8 @@
enum ast_fax_state state;
/*! name of the Asterisk channel using the fax session */
char *channame;
+ /*! unique ID of the Asterisk channel using the fax session */
+ char *chan_uniqueid;
/*! Asterisk channel using the fax session */
struct ast_channel *chan;
/*! fax debugging structure */
@@ -229,6 +237,8 @@
char * (* const cli_show_session)(struct ast_fax_session *, int);
/*! displays statistics from the fax technology module */
char * (* const cli_show_stats)(int);
+ /*! displays settings from the fax technology module */
+ char * (* const cli_show_settings)(int);
};
/*! \brief register a fax technology */
Modified: team/dvossel/generic_aoc/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/main/channel.c?view=diff&rev=259107&r1=259106&r2=259107
==============================================================================
--- team/dvossel/generic_aoc/main/channel.c (original)
+++ team/dvossel/generic_aoc/main/channel.c Mon Apr 26 16:47:25 2010
@@ -855,6 +855,7 @@
int x;
int flags;
struct varshead *headp;
+ char *tech;
/* If shutting down, don't allocate any new channels */
if (shutting_down) {
@@ -977,6 +978,7 @@
}
if (!ast_strlen_zero(name_fmt)) {
+ char *slash;
/* Almost every channel is calling this function, and setting the name via the ast_string_field_build() call.
* And they all use slightly different formats for their name string.
* This means, to set the name here, we have to accept variable args, and call the string_field_build from here.
@@ -985,6 +987,10 @@
* This new function was written so this can be accomplished.
*/
ast_string_field_build_va(tmp, name, name_fmt, ap1, ap2);
+ tech = ast_strdupa(tmp->name);
+ if ((slash = strchr(tech, '/'))) {
+ *slash = '\0';
+ }
}
/* Reminder for the future: under what conditions do we NOT want to track cdrs on channels? */
@@ -1037,7 +1043,7 @@
* proper and correct place to make this call, but you sure do have to pass
* a lot of data into this func to do it here!
*/
- if (!ast_strlen_zero(name_fmt)) {
+ if (ast_get_channel_tech(tech)) {
ast_manager_event(tmp, EVENT_FLAG_CALL, "Newchannel",
"Channel: %s\r\n"
"ChannelState: %d\r\n"
Modified: team/dvossel/generic_aoc/res/res_fax.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/res/res_fax.c?view=diff&rev=259107&r1=259106&r2=259107
==============================================================================
--- team/dvossel/generic_aoc/res/res_fax.c (original)
+++ team/dvossel/generic_aoc/res/res_fax.c Mon Apr 26 16:47:25 2010
@@ -50,12 +50,15 @@
#include "asterisk/utils.h"
#include "asterisk/config.h"
#include "asterisk/astobj2.h"
+#include "asterisk/res_fax.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/manager.h"
#include "asterisk/dsp.h"
-#include "asterisk/res_fax.h"
+#include "asterisk/indications.h"
+
+#include "asterisk/version.h"
static const char app_receivefax[] = "ReceiveFAX";
static const char synopsis_receivefax[] = "Receive a FAX and save as a TIFF/F file.";
@@ -78,6 +81,7 @@
" The application arguments are:\n"
" 'd' - enables FAX debugging\n"
" 'f' - allow audio fallback FAX transfer on T.38 capable channels\n"
+ " 'z' - initiate a T.38 reinvite on the channel if the remote end does not\n"
" 's' - send progress Manager events (overrides statusevents setting in res_fax.conf)\n"
"\n"
" Use the FAXOPT function to specify session arguments prior to calling SendFAX()\n"
@@ -135,6 +139,7 @@
static struct {
enum ast_fax_modems modems;
uint32_t statusevents:1;
+ uint32_t ecm:1;
unsigned int minrate;
unsigned int maxrate;
} general_options;
@@ -144,11 +149,12 @@
static int global_fax_debug = 0;
enum {
- OPT_CALLEDMODE = (1 << 0),
- OPT_CALLERMODE = (1 << 1),
- OPT_DEBUG = (1 << 2),
- OPT_STATUS = (1 << 3),
- OPT_ALLOWAUDIO = (1 << 5),
+ OPT_CALLEDMODE = (1 << 0),
+ OPT_CALLERMODE = (1 << 1),
+ OPT_DEBUG = (1 << 2),
+ OPT_STATUS = (1 << 3),
+ OPT_ALLOWAUDIO = (1 << 5),
+ OPT_REQUEST_T38 = (1 << 6),
};
AST_APP_OPTIONS(fax_exec_options, BEGIN_OPTIONS
@@ -157,6 +163,7 @@
AST_APP_OPTION('d', OPT_DEBUG),
AST_APP_OPTION('f', OPT_ALLOWAUDIO),
AST_APP_OPTION('s', OPT_STATUS),
+ AST_APP_OPTION('z', OPT_REQUEST_T38),
END_OPTIONS);
struct manager_event_info {
@@ -262,7 +269,10 @@
/* These options need to be set to the configured default and may be overridden by
* SendFAX, ReceiveFAX, or FAXOPT */
- d->option.ecm = AST_FAX_OPTFLAG_DEFAULT;
+ d->option.request_t38 = AST_FAX_OPTFLAG_FALSE;
+ d->option.send_cng = AST_FAX_OPTFLAG_FALSE;
+ d->option.send_ced = AST_FAX_OPTFLAG_FALSE;
+ d->option.ecm = general_options.ecm;
d->option.statusevents = general_options.statusevents;
d->modems = general_options.modems;
d->minrate = general_options.minrate;
@@ -491,6 +501,7 @@
ast_atomic_fetchadd_int(&faxregistry.active_sessions, -1);
ast_free(s->channame);
+ ast_free(s->chan_uniqueid);
}
/*! \brief create a FAX session */
@@ -523,6 +534,12 @@
ao2_ref(s, -1);
return NULL;
}
+
+ if (!(s->chan_uniqueid = ast_strdup(chan->uniqueid))) {
+ ao2_ref(s, -1);
+ return NULL;
+ }
+
s->chan = chan;
s->details = details;
ao2_ref(s->details, 1);
@@ -634,55 +651,10 @@
dst->transcoding_jbig = src->transcoding_jbig;
}
-/*! \brief this is the generic FAX session handling function */
-static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_details *details)
-{
- int ms;
- int timeout = RES_FAX_TIMEOUT;
- int res = 0, chancount;
- unsigned int expected_frametype = -1;
- union ast_frame_subclass expected_framesubclass = { .integer = -1 };
- char tbuf[10];
- unsigned int t38negotiated = 0;
- enum ast_t38_state t38_state;
- struct ast_control_t38_parameters t38_parameters;
- int send_cng = -1;
- unsigned int disable_t38 = 0;
- const char *tempvar;
- struct ast_fax_session *fax = NULL;
- struct ast_frame *frame = NULL;
- struct ast_channel *c = chan;
- unsigned int orig_write_format = 0, orig_read_format = 0;
- unsigned int request_t38 = 0;
- unsigned int send_audio = 1;
-
- details->our_t38_parameters.version = 0;
- details->our_t38_parameters.max_ifp = 400;
- details->our_t38_parameters.rate = AST_T38_RATE_14400;
- details->our_t38_parameters.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
-
- chancount = 1;
-
- switch ((t38_state = ast_channel_get_t38_state(chan))) {
+static int set_fax_t38_caps(struct ast_channel *chan, struct ast_fax_session_details *details)
+{
+ switch (ast_channel_get_t38_state(chan)) {
case T38_STATE_UNKNOWN:
- if (details->caps & AST_FAX_TECH_SEND) {
- if (details->option.allow_audio) {
- details->caps |= AST_FAX_TECH_AUDIO;
- } else {
- /* we are going to send CNG to attempt to stimulate the receiver
- * into switching to T.38, since audio mode is not allowed
- */
- send_cng = 0;
- }
- } else {
- /* we *always* request a switch to T.38 if allowed; if audio is also
- * allowed, then we will allow the switch to happen later if needed
- */
- if (details->option.allow_audio) {
- details->caps |= AST_FAX_TECH_AUDIO;
- }
- request_t38 = 1;
- }
details->caps |= AST_FAX_TECH_T38;
break;
case T38_STATE_UNAVAILABLE:
@@ -697,14 +669,11 @@
* that gets called after this one completes
*/
struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_PARMS, };
- ast_log(LOG_NOTICE, "Channel is already in T.38 negotiation state; retrieving remote parameters.\n");
if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)) != AST_T38_REQUEST_PARMS) {
ast_log(LOG_ERROR, "channel '%s' is in an unsupported T.38 negotiation state, cannot continue.\n", chan->name);
return -1;
}
details->caps |= AST_FAX_TECH_T38;
- details->option.allow_audio = 0;
- send_audio = 0;
break;
}
default:
@@ -712,199 +681,97 @@
return -1;
}
- /* generate 3 seconds of CED if we are in receive mode and not already negotiating T.38 */
- if (send_audio && (details->caps & AST_FAX_TECH_RECEIVE)) {
- ms = 3000;
- if (ast_tonepair_start(chan, 2100, 0, ms, 0)) {
- ast_log(LOG_ERROR, "error generating CED tone on %s\n", chan->name);
+ return 0;
+}
+
+static int disable_t38(struct ast_channel *chan)
+{
+ int ms;
+ struct ast_frame *frame = NULL;
+ struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
+
+ ast_debug(1, "Shutting down T.38 on %s\n", chan->name);
+ if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0) {
+ ast_log(LOG_WARNING, "error while disabling T.38 on channel '%s'\n", chan->name);
+ return -1;
+ }
+
+ /* wait up to five seconds for negotiation to complete */
+ ms = 5000;
+
+ while (ms > 0) {
+ ms = ast_waitfor(chan, ms);
+ if (ms < 0) {
+ ast_log(LOG_WARNING, "error while disabling T.38 on channel '%s'\n", chan->name);
return -1;
}
- do {
- ms = ast_waitfor(chan, ms);
- if (ms < 0) {
- ast_log(LOG_ERROR, "error while generating CED tone on %s\n", chan->name);
- ast_tonepair_stop(chan);
+ if (ms == 0) { /* all done, nothing happened */
+ ast_log(LOG_WARNING, "channel '%s' timed-out during T.38 shutdown\n", chan->name);
+ break;
+ }
+
+ if (!(frame = ast_read(chan))) {
+ return -1;
+ }
+ if ((frame->frametype == AST_FRAME_CONTROL) &&
+ (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
+ (frame->datalen == sizeof(t38_parameters))) {
+ struct ast_control_t38_parameters *parameters = frame->data.ptr;
+
+ switch (parameters->request_response) {
+ case AST_T38_TERMINATED:
+ ast_debug(1, "Shut down T.38 on %s\n", chan->name);
+ break;
+ case AST_T38_REFUSED:
+ ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", chan->name);
+ ast_frfree(frame);
+ return -1;
+ default:
+ ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", chan->name);
+ ast_frfree(frame);
return -1;
}
-
- if (ms == 0) { /* all done, nothing happened */
- break;
- }
-
- if (!(frame = ast_read(chan))) {
- ast_log(LOG_ERROR, "error reading frame while generating CED tone on %s\n", chan->name);
- ast_tonepair_stop(chan);
- return -1;
- }
-
- if ((frame->frametype == AST_FRAME_CONTROL) &&
- (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
- (frame->datalen == sizeof(t38_parameters))) {
- struct ast_control_t38_parameters *parameters = frame->data.ptr;
-
- switch (parameters->request_response) {
- 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
- */
- t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
- t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
- ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
- break;
- case AST_T38_NEGOTIATED:
- ast_log(LOG_NOTICE, "Negotiated T.38 for receive on %s\n", chan->name);
- t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
- details->caps &= ~AST_FAX_TECH_AUDIO;
- report_fax_status(chan, details, "T.38 Negotiated");
- t38negotiated = 1;
- ms = 0;
- break;
- default:
- break;
- }
- }
ast_frfree(frame);
- } while (ms > 0);
- ast_tonepair_stop(chan);
- }
-
- if (request_t38) {
- /* wait up to five seconds for negotiation to complete */
- timeout = 5000;
-
- /* set parameters based on the session's parameters */
- t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
- t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
- if ((ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0)) {
- res = -1;
- goto t38done;
- }
-
- ast_log(LOG_NOTICE, "Negotiating T.38 for %s on %s\n", (details->caps & AST_FAX_TECH_SEND) ? "send" : "receive", chan->name);
- } else if (!details->option.allow_audio) {
- /* wait up to sixty seconds for negotiation to complete */
- timeout = 60000;
-
- ast_log(LOG_NOTICE, "Waiting for T.38 negotiation for %s on %s\n", (details->caps & AST_FAX_TECH_SEND) ? "send" : "receive", chan->name);
- }
-
- if (request_t38 || !details->option.allow_audio) {
- struct ast_silence_generator *silence_gen = NULL;
-
- if (send_audio && (send_cng != -1)) {
- silence_gen = ast_channel_start_silence_generator(chan);
- }
-
- while (timeout > 0) {
- if (send_cng > 3000) {
- if (send_audio) {
- ast_channel_stop_silence_generator(chan, silence_gen);
- silence_gen = NULL;
- ast_tonepair_start(chan, 1100, 0, 500, 0);
- }
- send_cng = 0;
- } else if (!chan->generator && (send_cng != -1)) {
- if (send_audio) {
- /* The CNG tone is done so restart silence generation. */
- silence_gen = ast_channel_start_silence_generator(chan);
- }
- }
- /* this timeout *MUST* be 500ms, in order to keep the spacing
- * of CNG tones correct when this loop is sending them
- */
- ms = ast_waitfor(chan, 500);
- if (ms < 0) {
- ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", chan->name);
- res = -1;
- break;
- }
- if (send_cng != -1) {
- send_cng += 500 - ms;
- }
- if (!ms) {
- /* nothing happened */
- if (timeout > 0) {
- timeout -= 500;
- 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))) {
- if (silence_gen) {
- ast_channel_stop_silence_generator(chan, silence_gen);
- silence_gen = NULL;
- }
- return -1;
- }
- if ((frame->frametype == AST_FRAME_CONTROL) &&
- (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
- (frame->datalen == sizeof(t38_parameters))) {
- struct ast_control_t38_parameters *parameters = frame->data.ptr;
- int stop = 1;
-
- switch (parameters->request_response) {
- case AST_T38_REQUEST_NEGOTIATE:
- t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
- t38_parameters.request_response = AST_T38_NEGOTIATED;
- ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
- stop = 0;
- send_audio = 0;
- break;
- 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);
- t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
- details->caps &= ~AST_FAX_TECH_AUDIO;
- t38negotiated = 1;
- disable_t38 = 1;
- 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);
- res = -1;
- break;
- }
- if (stop) {
- ast_frfree(frame);
- break;
- }
- }
- ast_frfree(frame);
- }
-
- if (silence_gen) {
- ast_channel_stop_silence_generator(chan, silence_gen);
- silence_gen = NULL;
- }
- }
-
-t38done:
- /* if any failures occurred during T.38 negotiation, handle them here */
- if (res) {
- /* if audio is allowed, then drop the T.38 session requirement
- * and proceed, otherwise the request has failed
- */
- if (details->option.allow_audio) {
- details->caps &= ~AST_FAX_TECH_T38;
- res = 0;
- } else {
- ast_log(LOG_WARNING, "Audio FAX not allowed on channel '%s' and T.38 negotiation failed; aborting.\n", chan->name);
- return -1;
- }
- }
+ break;
+ }
+ ast_frfree(frame);
+ }
+
+ return 0;
+}
+
+static struct ast_control_t38_parameters our_t38_parameters = {
+ .version = 0,
+ .max_ifp = 400,
+ .rate = AST_T38_RATE_14400,
+ .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
+};
+
+/*! \brief this is the generic FAX session handling function */
+static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_details *details)
+{
+ int ms;
+ int timeout = RES_FAX_TIMEOUT;
+ int res = 0, chancount;
+ unsigned int expected_frametype = -1;
+ union ast_frame_subclass expected_framesubclass = { .integer = -1 };
+ char tbuf[10];
+ unsigned int t38negotiated = (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED);
+ struct ast_control_t38_parameters t38_parameters;
+ const char *tempvar;
+ struct ast_fax_session *fax = NULL;
+ struct ast_frame *frame = NULL;
+ struct ast_channel *c = chan;
+ unsigned int orig_write_format = 0, orig_read_format = 0;
+
+ chancount = 1;
/* create the FAX session */
if (!(fax = fax_session_new(details, chan))) {
ast_log(LOG_ERROR, "Can't create a FAX session, FAX attempt failed.\n");
report_fax_status(chan, details, "No Available Resource");
- chancount = -1;
- goto disable_t38;
+ return -1;
}
ast_channel_lock(chan);
@@ -1132,62 +999,160 @@
}
}
-disable_t38:
- if (disable_t38 &&
- (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED)) {
- struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
-
- if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) {
- /* wait up to five seconds for negotiation to complete */
- unsigned int timeout = 5000;
- int ms;
-
- ast_debug(1, "Shutting down T.38 on %s\n", 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);
- return -1;
- }
- if (!ms) {
- /* nothing happened */
- if (timeout > 0) {
- timeout -= 1000;
- continue;
- } else {
- ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", chan->name);
- break;
- }
- }
- if (!(frame = ast_read(chan))) {
- return -1;
- }
- if ((frame->frametype == AST_FRAME_CONTROL) &&
- (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
- (frame->datalen == sizeof(t38_parameters))) {
- struct ast_control_t38_parameters *parameters = frame->data.ptr;
-
- switch (parameters->request_response) {
- case AST_T38_TERMINATED:
- ast_debug(1, "Shut down T.38 on %s\n", chan->name);
- break;
- case AST_T38_REFUSED:
- ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", chan->name);
- break;
- default:
- ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", chan->name);
- break;
- }
- ast_frfree(frame);
+ /* return the chancount so the calling function can determine if the channel hungup during this FAX session or not */
+ return chancount;
+}
+
+static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_details *details)
+{
+ int ms;
+ struct ast_frame *frame = NULL;
+ struct ast_control_t38_parameters t38_parameters;
+
+ t38_parameters_ast_to_fax(&details->our_t38_parameters, &our_t38_parameters);
+
+ /* don't send any audio if we've already received a T.38 reinvite */
+ if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
+ /* generate 3 seconds of CED */
+ if (ast_playtones_start(chan, 1024, "!2100/3000", 1)) {
+ ast_log(LOG_ERROR, "error generating CED tone on %s\n", chan->name);
+ return -1;
+ }
+
+ ms = 3000;
+ while (ms > 0) {
+ ms = ast_waitfor(chan, ms);
+ if (ms < 0) {
+ ast_log(LOG_ERROR, "error while generating CED tone on %s\n", chan->name);
+ ast_playtones_stop(chan);
+ return -1;
+ }
+
+ if (ms == 0) { /* all done, nothing happened */
+ break;
+ }
+
+ if (!(frame = ast_read(chan))) {
+ ast_log(LOG_ERROR, "error reading frame while generating CED tone on %s\n", chan->name);
+ ast_playtones_stop(chan);
+ return -1;
+ }
+
+ if ((frame->frametype == AST_FRAME_CONTROL) &&
+ (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
+ (frame->datalen == sizeof(t38_parameters))) {
+ struct ast_control_t38_parameters *parameters = frame->data.ptr;
+
+ switch (parameters->request_response) {
+ 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
+ */
+ t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
+ t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
+ ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
+ ast_playtones_stop(chan);
+ break;
+ case AST_T38_NEGOTIATED:
+ ast_log(LOG_NOTICE, "Negotiated T.38 for receive on %s\n", chan->name);
+ t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
+ details->caps &= ~AST_FAX_TECH_AUDIO;
+ report_fax_status(chan, details, "T.38 Negotiated");
+ break;
+ default:
break;
}
- ast_frfree(frame);
}
- }
- }
-
- /* return the chancount so the calling function can determine if the channel hungup during this FAX session or not */
- return chancount;
+ ast_frfree(frame);
+ }
+
+ ast_playtones_stop(chan);
+ }
+
+ /* if T.38 was negotiated, we are done initializing */
+ if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
+ return 0;
+ }
+
+ /* request T.38 */
+ ast_log(LOG_NOTICE, "Negotiating T.38 for receive on %s\n", chan->name);
+
+ /* wait up to five seconds for negotiation to complete */
+ ms = 5000;
+
+ /* set parameters based on the session's parameters */
+ t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
+ t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
+ if ((ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0)) {
+ return -1;
+ }
+
+ while (ms > 0) {
+ ms = ast_waitfor(chan, ms);
+ if (ms < 0) {
+ ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
+ return -1;
+ }
+
+ if (ms == 0) { /* all done, nothing happened */
+ ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", chan->name);
+ details->caps &= ~AST_FAX_TECH_T38;
+ break;
+ }
+
+ if (!(frame = ast_read(chan))) {
+ ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
+ return -1;
+ }
+
+ if ((frame->frametype == AST_FRAME_CONTROL) &&
+ (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
+ (frame->datalen == sizeof(t38_parameters))) {
+ struct ast_control_t38_parameters *parameters = frame->data.ptr;
+
+ switch (parameters->request_response) {
+ case AST_T38_REQUEST_NEGOTIATE:
+ t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
+ t38_parameters.request_response = AST_T38_NEGOTIATED;
+ ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
+ break;
+ case AST_T38_NEGOTIATED:
+ ast_log(LOG_NOTICE, "Negotiated T.38 for receive on %s\n", chan->name);
+ t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
+ details->caps &= ~AST_FAX_TECH_AUDIO;
+ report_fax_status(chan, details, "T.38 Negotiated");
+ ms = 0;
+ break;
+ case AST_T38_REFUSED:
+ ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", chan->name);
+ details->caps &= ~AST_FAX_TECH_T38;
+ ms = 0;
+ break;
+ default:
+ ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", chan->name);
+ details->caps &= ~AST_FAX_TECH_T38;
+ ms = 0;
+ break;
+ }
+ }
+ ast_frfree(frame);
+ }
+
+ /* if T.38 was negotiated, we are done initializing */
+ if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
+ return 0;
+ }
+
+ /* if we made it here, then T.38 failed, check the 'f' flag */
+ if (details->option.allow_audio != AST_FAX_OPTFLAG_TRUE) {
+ ast_log(LOG_WARNING, "Audio FAX not allowed on channel '%s' and T.38 negotiation failed; aborting.\n", chan->name);
+ return -1;
+ }
+
+ /* ok, audio fallback is allowed */
+ details->caps |= AST_FAX_TECH_AUDIO;
+
+ return 0;
}
/*! \brief initiate a receive FAX session */
@@ -1283,10 +1248,31 @@
details->option.allow_audio = AST_FAX_OPTFLAG_TRUE;
}
+ if (set_fax_t38_caps(chan, details)) {
+ ao2_ref(details, -1);
+ return -1;
+ }
+
+ if (details->caps & AST_FAX_TECH_T38) {
+ if (receivefax_t38_init(chan, details)) {
+ ao2_ref(details, -1);
+ ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", chan->name);
+ return -1;
+ }
+ } else {
+ details->option.send_ced = 1;
+ }
+
if ((channel_alive = generic_fax_exec(chan, details)) < 0) {
ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
}
-
+
+ if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
+ if (disable_t38(chan)) {
+ ast_log(LOG_WARNING, "error disabling T.38 mode on %s\n", chan->name);
+ }
+ }
+
/* send out the AMI completion event */
ast_channel_lock(chan);
@@ -1321,6 +1307,231 @@
return (!channel_alive) ? -1 : 0;
}
+static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_details *details)
+{
+ int ms;
+ struct ast_frame *frame = NULL;
+ struct ast_control_t38_parameters t38_parameters;
+
+ t38_parameters_ast_to_fax(&details->our_t38_parameters, &our_t38_parameters);
+
+ /* send CNG tone while listening for the receiver to initiate a switch
+ * to T.38 mode; if they do, stop sending the CNG tone and proceed with
+ * the switch.
+ *
+ * 10500 is enough time for 3 CNG tones
+ */
+ ms = 10500;
+
+ /* don't send any audio if we've already received a T.38 reinvite */
+ if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
+ if (ast_playtones_start(chan, 1024, "!1100/500,!0/3000,!1100/500,!0/3000,!1100/500,!0/3000", 1)) {
+ ast_log(LOG_ERROR, "error generating CNG tone on %s\n", chan->name);
+ return -1;
+ }
+ }
+
+ while (ms > 0) {
+ ms = ast_waitfor(chan, ms);
+ if (ms < 0) {
+ ast_log(LOG_ERROR, "error while generating CNG tone on %s\n", chan->name);
+ ast_playtones_stop(chan);
+ return -1;
+ }
+
+ if (ms == 0) { /* all done, nothing happened */
+ break;
+ }
+
+ if (!(frame = ast_read(chan))) {
+ ast_log(LOG_ERROR, "error reading frame while generating CNG tone on %s\n", chan->name);
+ ast_playtones_stop(chan);
+ return -1;
+ }
+
+ if ((frame->frametype == AST_FRAME_CONTROL) &&
+ (frame->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
+ (frame->datalen == sizeof(t38_parameters))) {
+ struct ast_control_t38_parameters *parameters = frame->data.ptr;
+
+ switch (parameters->request_response) {
+ 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
+ */
+ t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
+ t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED;
+ ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
+ ast_playtones_stop(chan);
+ break;
+ case AST_T38_NEGOTIATED:
+ ast_log(LOG_NOTICE, "Negotiated T.38 for send on %s\n", chan->name);
+ t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
[... 424 lines stripped ...]
More information about the asterisk-commits
mailing list