[svn-commits] rmudgett: branch dvossel/generic_aoc r259107 - in /team/dvossel/generic_aoc: ...

SVN commits to the Digium repositories svn-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, &parameters, 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 svn-commits mailing list