[svn-commits] twilson: branch group/srtp_reboot r254537 - in /team/group/srtp_reboot: ./ ch...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Mar 25 11:44:29 CDT 2010


Author: twilson
Date: Thu Mar 25 11:44:24 2010
New Revision: 254537

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=254537
Log:
Merged revisions 254446,254450,254453-254454 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

................
  r254446 | lmadsen | 2010-03-25 10:21:26 -0500 (Thu, 25 Mar 2010) | 9 lines
  
  handle_speechset has 4 arguments.
  
  Update code to reflect that handle_speechset has 4 arguments.
  
  (closes issue #17093)
  Reported by: gpatri
  Patches: 
        res_agi.patch uploaded by gpatri (license 1014)
  Tested by: pabelanger, mmichelson
................
  r254450 | kpfleming | 2010-03-25 10:27:31 -0500 (Thu, 25 Mar 2010) | 49 lines
  
  Improve handling of T.38 re-INVITEs that arrive before a T.38-capable
  application is executing on a channel.
  
  This patch addresses an issue found during working with end-users
  using res_fax. If an incoming call is answered in the dialplan, or
  jumps to the 'fax' extension due to reception of a CNG tone (with
  faxdetect enabled), and then the remote endpoint sends a T.38
  re-INVITE, it is possible for the channel's T.38 state to be
  'T38_STATE_NEGOTIATING' when the application starts up. Unfortunately,
  even if the application wants to use T.38, it can't respond to the
  peer's negotiation request, because the AST_CONTROL_T38_PARAMETERS
  control frame that chan_sip sent originally has been lost, and the
  application needs the content of that frame to be able to formulate a
  reply.
  
  This patch adds a new 'request' type to AST_CONTROL_T38_PARAMETERS,
  AST_T38_REQUEST_PARMS. If the application sends this request, chan_sip
  will re-send the original control frame (with
  AST_T38_REQUEST_NEGOTIATE as the request type), and the application
  can respond as normal. If this occurs within the five second timeout
  in chan_sip, the automatic cancellation of the peer reinvite will be
  stopped, and the application will 'own' the negotiation process from
  that point onwards.
  
  This also improves the code path in chan_sip to allow sip_indicate(),
  when called for AST_CONTROL_T38_PARAMETERS, to be able to return a
  non-zero response, which should have been in place before since the
  control frame *can* fail to be processed properly. It also modifies
  ast_indicate() to return whatever result the channel driver returned
  for this control frame, rather than converting all non-zero results
  into '-1'. Finally, the new request type intentionally returns a
  positive value, so that an application that sends
  AST_T38_REQUEST_PARMS can know for certain whether the channel driver
  accepted it and will be replying with a control frame of its own, or
  whether it was ignored (if the sip_indicate()/ast_indicate() path had
  properly supported failure responses before, this would not be
  necessary).
  
  This patch also modifies res_fax to take advantage of the new request.
  
  In addition, this patch makes sip_t38_abort() actually lock the
  private structure before doing its work... bad programmer, no donut.
  
  This patch also enhances chan_sip's 'faxdetect' support to allow
  triggering on T.38 re-INVITEs received as well as CNG tone detection.
  
  Review: https://reviewboard.asterisk.org/r/556/
................
  r254453 | twilson | 2010-03-25 11:03:51 -0500 (Thu, 25 Mar 2010) | 9 lines
  
  Merged revisions 254451 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r254451 | twilson | 2010-03-25 10:57:29 -0500 (Thu, 25 Mar 2010) | 2 lines
    
    Handle new SRCCHANGE control message here too
  ........
................
  r254454 | mmichelson | 2010-03-25 11:04:48 -0500 (Thu, 25 Mar 2010) | 50 lines
  
  Recorded merge of revisions 254452 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r254452 | mmichelson | 2010-03-25 10:59:56 -0500 (Thu, 25 Mar 2010) | 44 lines
    
    Several fixes regarding RFC2833 DTMF detection.
    
    Here is a copy and paste of the details from my request on
    reviewboard that dealt with these changes:
    
    Fix 1. The first change in place is to fix Mantis issue 15811, which deals with a situation where Asterisk will incorrectly interpret out of order RFC2833 frames as duplicate DTMF digits. For instance, we would receive a sequence like:
    
    seqno 1: DTMF 1
    seqno 2: DTMF 1
    seqno 3: DTMF 1
    seqno 4: DTMF 1
    seqno 6: DTMF 1 (end)
    seqno 5: DTMF 1
    seqno 7: DTMF 1 (end)
    seqno 8: DTMF 1 (end)
    
    Prior to this patch when we received the frame with seqno 5, we would interpret this as a new DTMF 1. With this patch, we will check the seqno of the incoming digit and not process the frame if the seqno is lower than the last recorded seqno. Note that we do not record the seqno of the dropped DTMF frame for future processing. While the above situation is what was designed to be fixed, the patch is written in such a way that the following would also be fixed too:
    
    seqno  9: DTMF 1
    seqno 10: DTMF 1 (end)
    seqno 11: DTMF 1 (end)
    seqno 13: DTMF 2
    seqno 12: DTMF 1 (end)
    seqno 14: DTMF 2
    seqno 15: DTMF 2 (end)
    seqno 16: DTMF 2 (end)
    seqno 17: DTMF 2 (end)
    
    In this second situation, the beginning of the DTMF 2 arrives before the final end frame of the DTMF 1. With the patch, seqno 12 is no processed and thus we properly interpret the DTMF.
    
    Fix 2. The second change in place is to fix an issue like the following:
    
    seqno 1: DTMF 1
    seqno 2: DTMF 1
    seqno 3: DTMF 1 (end) *packet lost*
    seqno 4: DTMF 1 (end) *packet lost*
    seqno 5: DTMF 1 (end) *packet lost*
    seqno 6: DTMF 2
    
    When we receive seqno 6, we had code in place that was supposed to properly end the previously unended DTMF 1. The problem was that the code was essentially a no-op. The code would set up an end frame for the DTMF 1 but would immediately overwrite the frame with the begin for DTMF 2. I changed process_dtmf_rfc2833() so that instead of returning a single frame, it is given as an output parameter a list of frames. Each frame that needs to be returned is appended to this list.
    
    Fix 3. The final change is a minor one where an AST_CONTROL_SRCCHANGE frame could get lost. If we process a cisco DTMF or an RFC 3389 frame and no frame was returned, then we would return &ast_null_frame. The problem is that earlier in the function, we may have generated an AST_CONTROL_SRCCHANGE frame and put it in the list of frames we wish to return. This frame would be lost in such a case. The patch fixes this problem
  ........
................

Modified:
    team/group/srtp_reboot/   (props changed)
    team/group/srtp_reboot/channels/chan_sip.c
    team/group/srtp_reboot/channels/sip/include/sip.h
    team/group/srtp_reboot/configs/sip.conf.sample
    team/group/srtp_reboot/include/asterisk/frame.h
    team/group/srtp_reboot/main/channel.c
    team/group/srtp_reboot/main/file.c
    team/group/srtp_reboot/res/res_agi.c
    team/group/srtp_reboot/res/res_fax.c
    team/group/srtp_reboot/res/res_rtp_asterisk.c

Propchange: team/group/srtp_reboot/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/group/srtp_reboot/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Propchange: team/group/srtp_reboot/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Thu Mar 25 11:44:24 2010
@@ -1,1 +1,1 @@
-/trunk:1-254412
+/trunk:1-254505

Modified: team/group/srtp_reboot/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/group/srtp_reboot/channels/chan_sip.c?view=diff&rev=254537&r1=254536&r2=254537
==============================================================================
--- team/group/srtp_reboot/channels/chan_sip.c (original)
+++ team/group/srtp_reboot/channels/chan_sip.c Thu Mar 25 11:44:24 2010
@@ -3059,7 +3059,7 @@
                 }
 	}
 
-	if (ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT)) {
+	if (ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) {
 		features |= DSP_FEATURE_FAX_DETECT;
 	}
 
@@ -4216,6 +4216,11 @@
 
 	res = 0;
 	ast_set_flag(&p->flags[0], SIP_OUTGOING);
+
+	/* T.38 re-INVITE FAX detection should never be done for outgoing calls,
+	 * so ensure it is disabled.
+	 */
+	ast_clear_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_T38);
 
 	if (p->options->transfer) {
 		char buf[SIPBUFSIZE/2];
@@ -5268,22 +5273,24 @@
 }
 
 /*! \brief Helper function which updates T.38 capability information and triggers a reinvite */
-static void interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_t38_parameters *parameters)
-{
+static int interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_t38_parameters *parameters)
+{
+	int res = 0;
+
 	if (!ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) {
-		return;
+		return -1;
 	}
 	switch (parameters->request_response) {
 	case AST_T38_NEGOTIATED:
 	case AST_T38_REQUEST_NEGOTIATE:         /* Request T38 */
 		/* Negotiation can not take place without a valid max_ifp value. */
 		if (!parameters->max_ifp) {
-				change_t38_state(p, T38_DISABLED);
-				if (p->t38.state == T38_PEER_REINVITE) {
-					AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
-					transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
-				}
-				break;
+			change_t38_state(p, T38_DISABLED);
+			if (p->t38.state == T38_PEER_REINVITE) {
+				AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
+				transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
+			}
+			break;
 		} else if (p->t38.state == T38_PEER_REINVITE) {
 			AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
 			p->t38.our_parms = *parameters;
@@ -5325,9 +5332,28 @@
 		} else if (p->t38.state == T38_ENABLED)
 			transmit_reinvite_with_sdp(p, FALSE, FALSE);
 		break;
+	case AST_T38_REQUEST_PARMS: {		/* Application wants remote's parameters re-sent */
+		struct ast_control_t38_parameters parameters = p->t38.their_parms;
+
+		if (p->t38.state == T38_PEER_REINVITE) {
+			AST_SCHED_DEL(sched, p->t38id);
+			parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
+			parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
+			ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
+			/* we need to return a positive value here, so that applications that
+			 * send this request can determine conclusively whether it was accepted or not...
+			 * older versions of chan_sip would just silently accept it and return zero.
+			 */
+			res = AST_T38_REQUEST_PARMS;
+		}
+		break;
+	}
 	default:
+		res = -1;
 		break;
 	}
+
+	return res;
 }
 
 /*! \brief Play indication to user
@@ -5417,9 +5443,10 @@
 	case AST_CONTROL_T38_PARAMETERS:
 		if (datalen != sizeof(struct ast_control_t38_parameters)) {
 			ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38_PARAMETERS. Expected %d, got %d\n", (int) sizeof(struct ast_control_t38_parameters), (int) datalen);
+			res = -1;
 		} else {
 			const struct ast_control_t38_parameters *parameters = data;
-			interpret_t38_parameters(p, parameters);
+			res = interpret_t38_parameters(p, parameters);
 		}
 		break;
 	case AST_CONTROL_SRCUPDATE:
@@ -5907,20 +5934,20 @@
 	p->lastrtprx = time(NULL);
 
 	/* If we detect a CNG tone and fax detection is enabled then send us off to the fax extension */
-	if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT)) {
+	if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) {
 		ast_channel_lock(ast);
 		if (strcmp(ast->exten, "fax")) {
 			const char *target_context = S_OR(ast->macrocontext, ast->context);
 			ast_channel_unlock(ast);
 			if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
-				ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension\n", ast->name);
+				ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension due to CNG detection\n", ast->name);
 				pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
 				if (ast_async_goto(ast, target_context, "fax", 1)) {
 					ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
 				}
 				fr = &ast_null_frame;
 			} else {
-				ast_log(LOG_NOTICE, "Fax detected but no fax extension\n");
+				ast_log(LOG_NOTICE, "FAX CNG detected but no fax extension\n");
                         }
 		} else {
 			ast_channel_unlock(ast);
@@ -7280,6 +7307,25 @@
 			} else if ((t38action == SDP_T38_INITIATE) &&
 				   p->owner && p->lastinvite) {
 				change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */
+				/* If fax detection is enabled then send us off to the fax extension */
+				if (ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_T38)) {
+					ast_channel_lock(p->owner);
+					if (strcmp(p->owner->exten, "fax")) {
+						const char *target_context = S_OR(p->owner->macrocontext, p->owner->context);
+						ast_channel_unlock(p->owner);
+						if (ast_exists_extension(p->owner, target_context, "fax", 1, p->owner->cid.cid_num)) {
+							ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension due to peer T.38 re-INVITE\n", p->owner->name);
+							pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten);
+							if (ast_async_goto(p->owner, target_context, "fax", 1)) {
+								ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name, target_context);
+							}
+						} else {
+							ast_log(LOG_NOTICE, "T.38 re-INVITE detected but no fax extension\n");
+						}
+					} else {
+						ast_channel_unlock(p->owner);
+					}
+				}
 			}
 		} else {
 			ast_udptl_stop(p->udptl);
@@ -18996,15 +19042,24 @@
 	return 0;
 }
 
+/*! \brief Called to deny a T38 reinvite if the core does not respond to our request */
 static int sip_t38_abort(const void *data)
 {
 	struct sip_pvt *p = (struct sip_pvt *) data;
 
-	change_t38_state(p, T38_DISABLED);
-	transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
-	p->t38id = -1;
-	dialog_unref(p, "unref the dialog ptr from sip_t38_abort, because it held a dialog ptr");
-
+	sip_pvt_lock(p);
+	/* an application may have taken ownership of the T.38 negotiation on this
+	 * channel while we were waiting to grab the lock... if it did, the scheduler
+	 * id will have been reset to -1, which is our indication that we do *not*
+	 * want to abort the negotiation process
+	 */
+	if (p->t38id != -1) {
+		change_t38_state(p, T38_DISABLED);
+		transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
+		p->t38id = -1;
+		dialog_unref(p, "unref the dialog ptr from sip_t38_abort, because it held a dialog ptr");
+	}
+	sip_pvt_unlock(p);
 	return 0;
 }
 
@@ -22779,7 +22834,24 @@
 		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_IGNORESDPVERSION);
 	} else if (!strcasecmp(v->name, "faxdetect")) {
 		ast_set_flag(&mask[1], SIP_PAGE2_FAX_DETECT);
-		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_FAX_DETECT);
+		if (ast_true(v->value)) {
+			ast_set_flag(&flags[1], SIP_PAGE2_FAX_DETECT_BOTH);
+		} else if (ast_false(v->value)) {
+			ast_clear_flag(&flags[1], SIP_PAGE2_FAX_DETECT_BOTH);
+		} else {
+			char *buf = ast_strdupa(v->value);
+			char *word, *next = buf;
+
+			while ((word = strsep(&next, ","))) {
+				if (!strcasecmp(word, "cng")) {
+					ast_set_flag(&flags[1], SIP_PAGE2_FAX_DETECT_CNG);
+				} else if (!strcasecmp(word, "t38")) {
+					ast_set_flag(&flags[1], SIP_PAGE2_FAX_DETECT_T38);
+				} else {
+					ast_log(LOG_WARNING, "Unknown faxdetect mode '%s' on line %d.\n", word, v->lineno);
+				}
+			}
+		}
 	} else if (!strcasecmp(v->name, "rfc2833compensate")) {
 		ast_set_flag(&mask[1], SIP_PAGE2_RFC2833_COMPENSATE);
 		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RFC2833_COMPENSATE);

Modified: team/group/srtp_reboot/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/group/srtp_reboot/channels/sip/include/sip.h?view=diff&rev=254537&r1=254536&r2=254537
==============================================================================
--- team/group/srtp_reboot/channels/sip/include/sip.h (original)
+++ team/group/srtp_reboot/channels/sip/include/sip.h Thu Mar 25 11:44:24 2010
@@ -302,44 +302,46 @@
 	a second page of flags (for flags[1] */
 /*@{*/
 /* realtime flags */
-#define SIP_PAGE2_RTCACHEFRIENDS        (1 << 0)    /*!< GP: Should we keep RT objects in memory for extended time? */
-#define SIP_PAGE2_RTAUTOCLEAR           (1 << 2)    /*!< GP: Should we clean memory from peers after expiry? */
-#define SIP_PAGE2_RPID_UPDATE           (1 << 3)
-#define SIP_PAGE2_Q850_REASON           (1 << 4)    /*!< DP: Get/send cause code via Reason header */
-
-/* Space for addition of other realtime flags in the future */
-#define SIP_PAGE2_USE_SRTP              (1 << 7)    /*!< DP: Whether we should offer (only)  SRTP */
-#define SIP_PAGE2_SYMMETRICRTP          (1 << 8)    /*!< GDP: Whether symmetric RTP is enabled or not */
-#define SIP_PAGE2_STATECHANGEQUEUE      (1 << 9)    /*!< D: Unsent state pending change exists */
-
-#define SIP_PAGE2_CONNECTLINEUPDATE_PEND (1 << 10)
-#define SIP_PAGE2_RPID_IMMEDIATE         (1 << 11)
-#define SIP_PAGE2_RPORT_PRESENT         (1 << 12)   /*!< Was rport received in the Via header? */
-#define SIP_PAGE2_PREFERRED_CODEC	(1 << 13)   /*!< GDP: Only respond with single most preferred joint codec */
-#define SIP_PAGE2_VIDEOSUPPORT		(1 << 14)   /*!< DP: Video supported if offered? */
-#define SIP_PAGE2_TEXTSUPPORT		(1 << 15)   /*!< GDP: Global text enable */
-#define SIP_PAGE2_ALLOWSUBSCRIBE	(1 << 16)   /*!< GP: Allow subscriptions from this peer? */
-#define SIP_PAGE2_ALLOWOVERLAP		(1 << 17)   /*!< DP: Allow overlap dialing ? */
-#define SIP_PAGE2_SUBSCRIBEMWIONLY	(1 << 18)   /*!< GP: Only issue MWI notification if subscribed to */
-#define SIP_PAGE2_IGNORESDPVERSION	(1 << 19)   /*!< GDP: Ignore the SDP session version number we receive and treat all sessions as new */
-
-#define SIP_PAGE2_T38SUPPORT                   (3 << 20)    /*!< GDP: T.38 Fax Support */
-#define SIP_PAGE2_T38SUPPORT_UDPTL             (1 << 20)    /*!< GDP: T.38 Fax Support (no error correction) */
-#define SIP_PAGE2_T38SUPPORT_UDPTL_FEC         (2 << 20)    /*!< GDP: T.38 Fax Support (FEC error correction) */
-#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY  (3 << 20)    /*!< GDP: T.38 Fax Support (redundancy error correction) */
-
-#define SIP_PAGE2_CALL_ONHOLD           (3 << 23)  /*!< D: Call hold states: */
-#define SIP_PAGE2_CALL_ONHOLD_ACTIVE    (1 << 23)  /*!< D: Active hold */
-#define SIP_PAGE2_CALL_ONHOLD_ONEDIR    (2 << 23)  /*!< D: One directional hold */
-#define SIP_PAGE2_CALL_ONHOLD_INACTIVE  (3 << 23)  /*!< D: Inactive hold */
-
-#define SIP_PAGE2_RFC2833_COMPENSATE    (1 << 25)  /*!< DP: Compensate for buggy RFC2833 implementations */
-#define SIP_PAGE2_BUGGY_MWI             (1 << 26)  /*!< DP: Buggy CISCO MWI fix */
-#define SIP_PAGE2_DIALOG_ESTABLISHED    (1 << 27)  /*!< 29: Has a dialog been established? */
-#define SIP_PAGE2_FAX_DETECT            (1 << 28)  /*!< DP: Fax Detection support */
-#define SIP_PAGE2_REGISTERTRYING        (1 << 29)  /*!< DP: Send 100 Trying on REGISTER attempts */
-#define SIP_PAGE2_UDPTL_DESTINATION     (1 << 30)  /*!< DP: Use source IP of RTP as destination if NAT is enabled */
-#define SIP_PAGE2_VIDEOSUPPORT_ALWAYS   (1 << 31)  /*!< DP: Always set up video, even if endpoints don't support it */
+#define SIP_PAGE2_RTCACHEFRIENDS		(1 <<  0)    /*!< GP: Should we keep RT objects in memory for extended time? */
+#define SIP_PAGE2_RTAUTOCLEAR			(1 <<  1)    /*!< GP: Should we clean memory from peers after expiry? */
+#define SIP_PAGE2_RPID_UPDATE			(1 <<  2)
+#define SIP_PAGE2_Q850_REASON			(1 <<  3)    /*!< DP: Get/send cause code via Reason header */
+#define SIP_PAGE2_SYMMETRICRTP			(1 <<  4)    /*!< GDP: Whether symmetric RTP is enabled or not */
+#define SIP_PAGE2_STATECHANGEQUEUE		(1 <<  5)    /*!< D: Unsent state pending change exists */
+#define SIP_PAGE2_CONNECTLINEUPDATE_PEND	(1 <<  6)
+#define SIP_PAGE2_RPID_IMMEDIATE		(1 <<  7)
+#define SIP_PAGE2_RPORT_PRESENT			(1 <<  8)   /*!< Was rport received in the Via header? */
+#define SIP_PAGE2_PREFERRED_CODEC		(1 <<  9)   /*!< GDP: Only respond with single most preferred joint codec */
+#define SIP_PAGE2_VIDEOSUPPORT			(1 << 10)   /*!< DP: Video supported if offered? */
+#define SIP_PAGE2_TEXTSUPPORT			(1 << 11)   /*!< GDP: Global text enable */
+#define SIP_PAGE2_ALLOWSUBSCRIBE		(1 << 12)   /*!< GP: Allow subscriptions from this peer? */
+#define SIP_PAGE2_ALLOWOVERLAP			(1 << 13)   /*!< DP: Allow overlap dialing ? */
+#define SIP_PAGE2_SUBSCRIBEMWIONLY		(1 << 14)   /*!< GP: Only issue MWI notification if subscribed to */
+#define SIP_PAGE2_IGNORESDPVERSION		(1 << 15)   /*!< GDP: Ignore the SDP session version number we receive and treat all sessions as new */
+
+#define SIP_PAGE2_T38SUPPORT			(3 << 16)    /*!< GDP: T.38 Fax Support */
+#define SIP_PAGE2_T38SUPPORT_UDPTL		(1 << 16)    /*!< GDP: T.38 Fax Support (no error correction) */
+#define SIP_PAGE2_T38SUPPORT_UDPTL_FEC		(2 << 16)    /*!< GDP: T.38 Fax Support (FEC error correction) */
+#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY	(3 << 16)    /*!< GDP: T.38 Fax Support (redundancy error correction) */
+
+#define SIP_PAGE2_CALL_ONHOLD			(3 << 18)  /*!< D: Call hold states: */
+#define SIP_PAGE2_CALL_ONHOLD_ACTIVE		(1 << 18)  /*!< D: Active hold */
+#define SIP_PAGE2_CALL_ONHOLD_ONEDIR		(2 << 18)  /*!< D: One directional hold */
+#define SIP_PAGE2_CALL_ONHOLD_INACTIVE		(3 << 18)  /*!< D: Inactive hold */
+
+#define SIP_PAGE2_RFC2833_COMPENSATE		(1 << 20)  /*!< DP: Compensate for buggy RFC2833 implementations */
+#define SIP_PAGE2_BUGGY_MWI			(1 << 21)  /*!< DP: Buggy CISCO MWI fix */
+#define SIP_PAGE2_DIALOG_ESTABLISHED		(1 << 22)  /*!< 29: Has a dialog been established? */
+
+#define SIP_PAGE2_FAX_DETECT			(3 << 23)  /*!< DP: Fax Detection support */
+#define SIP_PAGE2_FAX_DETECT_CNG		(1 << 23)  /*!< DP: Fax Detection support - detect CNG in audio */
+#define SIP_PAGE2_FAX_DETECT_T38		(2 << 23)  /*!< DP: Fax Detection support - detect T.38 reinvite from peer */
+#define SIP_PAGE2_FAX_DETECT_BOTH		(3 << 23)  /*!< DP: Fax Detection support - detect both */
+
+#define SIP_PAGE2_REGISTERTRYING		(1 << 24)  /*!< DP: Send 100 Trying on REGISTER attempts */
+#define SIP_PAGE2_UDPTL_DESTINATION		(1 << 25)  /*!< DP: Use source IP of RTP as destination if NAT is enabled */
+#define SIP_PAGE2_VIDEOSUPPORT_ALWAYS		(1 << 26)  /*!< DP: Always set up video, even if endpoints don't support it */
+#define SIP_PAGE2_USE_SRTP              (1 << 27)    /*!< DP: Whether we should offer (only)  SRTP */
 
 #define SIP_PAGE2_FLAGS_TO_COPY \
 	(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_IGNORESDPVERSION | \

Modified: team/group/srtp_reboot/configs/sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/group/srtp_reboot/configs/sip.conf.sample?view=diff&rev=254537&r1=254536&r2=254537
==============================================================================
--- team/group/srtp_reboot/configs/sip.conf.sample (original)
+++ team/group/srtp_reboot/configs/sip.conf.sample Thu Mar 25 11:44:24 2010
@@ -533,9 +533,13 @@
 ;                                       ; send 400 byte T.38 FAX packets to it.
 ;
 ; FAX detection will cause the SIP channel to jump to the 'fax' extension (if it exists)
-; when a CNG tone is detected on an incoming call.
-;
-; faxdetect = yes              ; Default false
+; based one or more events being detected. The events that can be detected are an incoming
+; CNG tone or an incoming T.38 re-INVITE request.
+;
+; faxdetect = yes		; Default 'no', 'yes' enables both CNG and T.38 detection
+; faxdetect = cng		; Enables only CNG detection
+; faxdetect = t38		; Enables only T.38 detection
+; faxdetect = both		; Enables both CNG and T.38 detection (same as 'yes')
 ;
 ;----------------------------------------- OUTBOUND SIP REGISTRATIONS  ------------------------
 ; Asterisk can register as a SIP user agent to a SIP proxy (provider)

Modified: team/group/srtp_reboot/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/team/group/srtp_reboot/include/asterisk/frame.h?view=diff&rev=254537&r1=254536&r2=254537
==============================================================================
--- team/group/srtp_reboot/include/asterisk/frame.h (original)
+++ team/group/srtp_reboot/include/asterisk/frame.h Thu Mar 25 11:44:24 2010
@@ -332,7 +332,8 @@
 	AST_T38_REQUEST_TERMINATE,	/*!< Terminate T38 on a channel (fax to voice) */
 	AST_T38_NEGOTIATED,		/*!< T38 negotiated (fax mode) */
 	AST_T38_TERMINATED,		/*!< T38 terminated (back to voice) */
-	AST_T38_REFUSED			/*!< T38 refused for some reason (usually rejected by remote end) */
+	AST_T38_REFUSED,		/*!< T38 refused for some reason (usually rejected by remote end) */
+	AST_T38_REQUEST_PARMS,		/*!< request far end T.38 parameters for a channel in 'negotiating' state */
 };
 
 enum ast_control_t38_rate {

Modified: team/group/srtp_reboot/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/group/srtp_reboot/main/channel.c?view=diff&rev=254537&r1=254536&r2=254537
==============================================================================
--- team/group/srtp_reboot/main/channel.c (original)
+++ team/group/srtp_reboot/main/channel.c Thu Mar 25 11:44:24 2010
@@ -3716,9 +3716,10 @@
 		 * control frames, so we need to return failure, but there
 		 * is also no value in the log message below being emitted
 		 * since failure to handle these frames is not an 'error'
-		 * so just return right now.
-		 */
-		return -1;
+		 * so just return right now. in addition, we want to return
+		 * whatever value the channel driver returned, in case it
+		 * has some meaning.*/
+		return res;
 	case AST_CONTROL_RINGING:
 		ts = ast_get_indication_tone(chan->zone, "ring");
 		/* It is common practice for channel drivers to return -1 if trying

Modified: team/group/srtp_reboot/main/file.c
URL: http://svnview.digium.com/svn/asterisk/team/group/srtp_reboot/main/file.c?view=diff&rev=254537&r1=254536&r2=254537
==============================================================================
--- team/group/srtp_reboot/main/file.c (original)
+++ team/group/srtp_reboot/main/file.c Thu Mar 25 11:44:24 2010
@@ -1273,6 +1273,7 @@
 				case AST_CONTROL_ANSWER:
 				case AST_CONTROL_VIDUPDATE:
 				case AST_CONTROL_SRCUPDATE:
+				case AST_CONTROL_SRCCHANGE:
 				case AST_CONTROL_HOLD:
 				case AST_CONTROL_UNHOLD:
 				case -1:

Modified: team/group/srtp_reboot/res/res_agi.c
URL: http://svnview.digium.com/svn/asterisk/team/group/srtp_reboot/res/res_agi.c?view=diff&rev=254537&r1=254536&r2=254537
==============================================================================
--- team/group/srtp_reboot/res/res_agi.c (original)
+++ team/group/srtp_reboot/res/res_agi.c Thu Mar 25 11:44:24 2010
@@ -2661,7 +2661,7 @@
 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
 {
 	/* Check for minimum arguments */
-        if (argc != 3)
+	if (argc != 4)
 		return RESULT_SHOWUSAGE;
 
 	/* Check to make sure speech structure exists */

Modified: team/group/srtp_reboot/res/res_fax.c
URL: http://svnview.digium.com/svn/asterisk/team/group/srtp_reboot/res/res_fax.c?view=diff&rev=254537&r1=254536&r2=254537
==============================================================================
--- team/group/srtp_reboot/res/res_fax.c (original)
+++ team/group/srtp_reboot/res/res_fax.c Thu Mar 25 11:44:24 2010
@@ -654,6 +654,7 @@
 	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;
@@ -662,8 +663,57 @@
 
 	chancount = 1;
 
-	/* generate 3 seconds of CED if we are in receive mode */
-	if (details->caps & AST_FAX_TECH_RECEIVE) {
+	switch ((t38_state = 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:
+		details->caps |= AST_FAX_TECH_AUDIO;
+		break;
+	case T38_STATE_NEGOTIATING: {
+		/* the other end already sent us a T.38 reinvite, so we need to prod the channel
+		 * driver into resending their parameters to us if it supports doing so... if
+		 * not, we can't proceed, because we can't create a proper reply without them.
+		 * if it does work, the channel driver will send an AST_CONTROL_T38_PARAMETERS
+		 * with a request of AST_T38_REQUEST_NEGOTIATE, which will be read by the function
+		 * 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:
+		ast_log(LOG_ERROR, "channel '%s' is in an unsupported T.38 negotiation state, cannot continue.\n", chan->name);
+		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);
@@ -719,36 +769,6 @@
 		ast_tonepair_stop(chan);
 	}
 
-	switch ((t38_state = 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:
-		details->caps |= AST_FAX_TECH_AUDIO;
-		break;
-	default:
-		ast_log(LOG_ERROR, "channel '%s' is in an unsupported T.38 negotiation state, cannot continue.\n", chan->name);
-		return -1;
-	}
-
 	if (request_t38) {
 		/* wait up to five seconds for negotiation to complete */
 		timeout = 5000;
@@ -772,19 +792,23 @@
 	if (request_t38 || !details->option.allow_audio) {
 		struct ast_silence_generator *silence_gen = NULL;
 
-		if (send_cng != -1) {
+		if (send_audio && (send_cng != -1)) {
 			silence_gen = ast_channel_start_silence_generator(chan);
 		}
 
 		while (timeout > 0) {
 			if (send_cng > 3000) {
-				ast_channel_stop_silence_generator(chan, silence_gen);
-				silence_gen = NULL;
-				ast_tonepair_start(chan, 1100, 0, 500, 0);
+				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)) {
-				/* The CNG tone is done so restart silence generation. */
-				silence_gen = ast_channel_start_silence_generator(chan);
+				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
@@ -828,6 +852,7 @@
 					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);

Modified: team/group/srtp_reboot/res/res_rtp_asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/group/srtp_reboot/res/res_rtp_asterisk.c?view=diff&rev=254537&r1=254536&r2=254537
==============================================================================
--- team/group/srtp_reboot/res/res_rtp_asterisk.c (original)
+++ team/group/srtp_reboot/res/res_rtp_asterisk.c Thu Mar 25 11:44:24 2010
@@ -250,6 +250,8 @@
 	long int prev_ts;
 };
 
+AST_LIST_HEAD_NOLOCK(frame_list, ast_frame);
+
 /* Forward Declarations */
 static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data);
 static int ast_rtp_destroy(struct ast_rtp_instance *instance);
@@ -1334,7 +1336,7 @@
 	}
 }
 
-static struct ast_frame *send_dtmf(struct ast_rtp_instance *instance, enum ast_frame_type type, int compensate)
+static struct ast_frame *create_dtmf_frame(struct ast_rtp_instance *instance, enum ast_frame_type type, int compensate)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	struct sockaddr_in remote_address = { 0, };
@@ -1359,11 +1361,12 @@
 	rtp->f.samples = 0;
 	rtp->f.mallocd = 0;
 	rtp->f.src = "RTP";
+	AST_LIST_NEXT(&rtp->f, frame_list) = NULL;
 
 	return &rtp->f;
 }
 
-static struct ast_frame *process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark)
+static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark, struct frame_list *frames)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	struct sockaddr_in remote_address = { 0, };
@@ -1405,16 +1408,17 @@
 	} else {
 		/* Not a supported event */
 		ast_log(LOG_DEBUG, "Ignoring RTP 2833 Event: %08x. Not a DTMF Digit.\n", event);
-		return &ast_null_frame;
+		return;
 	}
 
 	if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)) {
 		if ((rtp->lastevent != timestamp) || (rtp->resp && rtp->resp != resp)) {
 			rtp->resp = resp;
 			rtp->dtmf_timeout = 0;
-			f = send_dtmf(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE));
+			f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)));
 			f->len = 0;
 			rtp->lastevent = timestamp;
+			AST_LIST_INSERT_TAIL(frames, f, frame_list);
 		}
 	} else {
 		/*  The duration parameter measures the complete
@@ -1430,24 +1434,34 @@
 		}
 		new_duration = (new_duration & ~0xFFFF) | samples;
 
+		if (rtp->lastevent > seqno) {
+			/* Out of order frame. Processing this can cause us to
+			 * improperly duplicate incoming DTMF, so just drop
+			 * this.
+			 */
+			return;
+		}
+
 		if (event_end & 0x80) {
 			/* End event */
 			if ((rtp->lastevent != seqno) && rtp->resp) {
 				rtp->dtmf_duration = new_duration;
-				f = send_dtmf(instance, AST_FRAME_DTMF_END, 0);
+				f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0));
 				f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.codec)), ast_tv(0, 0));
 				rtp->resp = 0;
 				rtp->dtmf_duration = rtp->dtmf_timeout = 0;
+				AST_LIST_INSERT_TAIL(frames, f, frame_list);
 			}
 		} else {
 			/* Begin/continuation */
 
 			if (rtp->resp && rtp->resp != resp) {
 				/* Another digit already began. End it */
-				f = send_dtmf(instance, AST_FRAME_DTMF_END, 0);
+				f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0));
 				f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.codec)), ast_tv(0, 0));
 				rtp->resp = 0;
 				rtp->dtmf_duration = rtp->dtmf_timeout = 0;
+				AST_LIST_INSERT_TAIL(frames, f, frame_list);
 			}
 
 			if (rtp->resp) {
@@ -1456,8 +1470,9 @@
 			} else {
 				/* New digit began */
 				rtp->resp = resp;
-				f = send_dtmf(instance, AST_FRAME_DTMF_BEGIN, 0);
+				f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_BEGIN, 0));
 				rtp->dtmf_duration = samples;
+				AST_LIST_INSERT_TAIL(frames, f, frame_list);
 			}
 
 			rtp->dtmf_timeout = timestamp + rtp->dtmf_duration + dtmftimeout;
@@ -1468,7 +1483,7 @@
 
 	rtp->dtmfsamples = samples;
 
-	return f;
+	return;
 }
 
 static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark)
@@ -1535,11 +1550,11 @@
 		rtp->resp = resp;
 		/* Why we should care on DTMF compensation at reception? */
 		if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)) {
-			f = send_dtmf(instance, AST_FRAME_DTMF_BEGIN, 0);
+			f = create_dtmf_frame(instance, AST_FRAME_DTMF_BEGIN, 0);
 			rtp->dtmfsamples = 0;
 		}
 	} else if ((rtp->resp == resp) && !power) {
-		f = send_dtmf(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE));
+		f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE));
 		f->samples = rtp->dtmfsamples * (rtp_get_rate(f->subclass.codec) / 1000);
 		rtp->resp = 0;
 	} else if (rtp->resp == resp)
@@ -1920,7 +1935,7 @@
 	unsigned int *rtpheader = (unsigned int*)(rtp->rawdata + AST_FRIENDLY_OFFSET), seqno, ssrc, timestamp;
 	struct ast_rtp_payload_type payload;
 	struct sockaddr_in remote_address = { 0, };
-	AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
+	struct frame_list frames;
 
 	/* If this is actually RTCP let's hop on over and handle it */
 	if (rtcp) {
@@ -2100,7 +2115,11 @@
 	if (!payload.asterisk_format) {
 		struct ast_frame *f = NULL;
 		if (payload.code == AST_RTP_DTMF) {
-			f = process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark);
+			/* process_dtmf_rfc2833 may need to return multiple frames. We do this
+			 * by passing the pointer to the frame list to it so that the method
+			 * can append frames to the list as needed.
+			 */
+			process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark, &frames);
 		} else if (payload.code == AST_RTP_CISCO_DTMF) {
 			f = process_dtmf_cisco(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark);
 		} else if (payload.code == AST_RTP_CN) {
@@ -2111,6 +2130,11 @@
 
 		if (f) {
 			AST_LIST_INSERT_TAIL(&frames, f, frame_list);
+		}

[... 17 lines stripped ...]



More information about the svn-commits mailing list