[asterisk-commits] rmudgett: trunk r266926 - in /trunk: ./ channels/ configs/ include/asterisk/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jun 2 11:14:16 CDT 2010


Author: rmudgett
Date: Wed Jun  2 11:14:12 2010
New Revision: 266926

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=266926
Log:
Add ETSI Explicit Call Transfer (ECT) support.

Added ability to send and receive ETSI Explicit Call Transfer (ECT)
messages to eliminate tromboned calls.

Note: Asterisk already supported initiating the transfer of calls to
eliminate tromboned calls to libpri so there was nothing to do for the
asterisk portion.

Review:	https://reviewboard.asterisk.org/r/520/

Modified:
    trunk/CHANGES
    trunk/channels/chan_dahdi.c
    trunk/channels/sig_pri.c
    trunk/channels/sig_pri.h
    trunk/configs/chan_dahdi.conf.sample
    trunk/configure
    trunk/configure.ac
    trunk/include/asterisk/autoconfig.h.in

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=266926&r1=266925&r2=266926
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Wed Jun  2 11:14:12 2010
@@ -332,6 +332,10 @@
    dialing option.  Dial(DAHDI/g1/[extension]/K(<keypad_digits>))
    Access any received keypad digits in SETUP message by: ${CHANNEL(keypad_digits)}
    (requires latest LibPRI)
+ * Added ability to send and receive ETSI Explicit Call Transfer (ECT) messages
+   to eliminate tromboned calls.  A tromboned call goes out an interface and comes
+   back into the same interface.  Tromboned calls happen because of call routing,
+   call deflection, call forwarding, and call transfer.
 
 Asterisk Manager Interface
 --------------------------

Modified: trunk/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_dahdi.c?view=diff&rev=266926&r1=266925&r2=266926
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Wed Jun  2 11:14:12 2010
@@ -6904,7 +6904,7 @@
 #ifdef PRI_2BCT
 		if (!triedtopribridge) {
 			triedtopribridge = 1;
-			if (p0->pri && p0->pri == p1->pri && p0->transfer && p1->transfer) {
+			if (p0->pri && p0->pri == p1->pri && p0->pri->transfer) {
 				ast_mutex_lock(&p0->pri->lock);
 				switch (p0->sig) {
 				case SIG_PRI_LIB_HANDLE_CASES:
@@ -11777,6 +11777,7 @@
 						pris[span].pri.cc_qsig_signaling_link_rsp =
 							conf->pri.pri.cc_qsig_signaling_link_rsp;
 #endif	/* defined(HAVE_PRI_CCSS) */
+						pris[span].pri.transfer = conf->chan.transfer;
 						pris[span].pri.facilityenable = conf->pri.pri.facilityenable;
 						ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list));
 						ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));

Modified: trunk/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_pri.c?view=diff&rev=266926&r1=266925&r2=266926
==============================================================================
--- trunk/channels/sig_pri.c (original)
+++ trunk/channels/sig_pri.c Wed Jun  2 11:14:12 2010
@@ -1569,6 +1569,106 @@
 	return 0;
 }
 
+#if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
+/*!
+ * \internal
+ * \brief Attempt to transfer the two calls to each other.
+ * \since 1.8
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param call_1 First call involved in the transfer.
+ * \param call_1_held TRUE if call_1 is on hold.
+ * \param call_2 Second call involved in the transfer.
+ * \param call_2_held TRUE if call_2 is on hold.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int sig_pri_attempt_transfer(struct sig_pri_pri *pri, q931_call *call_1, int call_1_held, q931_call *call_2, int call_2_held)
+{
+	int retval;
+	int call_1_chanpos;
+	int call_2_chanpos;
+	struct ast_channel *call_1_ast;
+	struct ast_channel *call_2_ast;
+	struct ast_channel *bridged;
+
+	call_1_chanpos = pri_find_pri_call(pri, call_1);
+	call_2_chanpos = pri_find_pri_call(pri, call_2);
+	if (call_1_chanpos < 0 || call_2_chanpos < 0) {
+		return -1;
+	}
+
+	/* Deadlock avoidance is attempted. */
+	sig_pri_lock_private(pri->pvts[call_1_chanpos]);
+	sig_pri_lock_owner(pri, call_1_chanpos);
+	sig_pri_lock_private(pri->pvts[call_2_chanpos]);
+	sig_pri_lock_owner(pri, call_2_chanpos);
+
+	call_1_ast = pri->pvts[call_1_chanpos]->owner;
+	call_2_ast = pri->pvts[call_2_chanpos]->owner;
+	if (!call_1_ast || !call_2_ast) {
+		if (call_1_ast) {
+			ast_channel_unlock(call_1_ast);
+		}
+		if (call_2_ast) {
+			ast_channel_unlock(call_2_ast);
+		}
+		sig_pri_unlock_private(pri->pvts[call_1_chanpos]);
+		sig_pri_unlock_private(pri->pvts[call_2_chanpos]);
+		return -1;
+	}
+
+	bridged = ast_bridged_channel(call_2_ast);
+	if (bridged) {
+		if (call_1_held) {
+			ast_queue_control(call_1_ast, AST_CONTROL_UNHOLD);
+		}
+		if (call_2_held) {
+			ast_queue_control(call_2_ast, AST_CONTROL_UNHOLD);
+		}
+
+		ast_verb(3, "TRANSFERRING %s to %s\n", call_2_ast->name, call_1_ast->name);
+		retval = ast_channel_masquerade(call_1_ast, bridged);
+	} else {
+		/* Try masquerading the other way. */
+		bridged = ast_bridged_channel(call_1_ast);
+		if (bridged) {
+			if (call_1_held) {
+				ast_queue_control(call_1_ast, AST_CONTROL_UNHOLD);
+			}
+			if (call_2_held) {
+				ast_queue_control(call_2_ast, AST_CONTROL_UNHOLD);
+			}
+
+			ast_verb(3, "TRANSFERRING %s to %s\n", call_1_ast->name, call_2_ast->name);
+			retval = ast_channel_masquerade(call_2_ast, bridged);
+		} else {
+			/* Could not transfer. */
+			retval = -1;
+		}
+	}
+	if (bridged && retval) {
+		/* Restore HOLD on held calls because masquerade failed. */
+		if (call_1_held) {
+			ast_queue_control(call_1_ast, AST_CONTROL_HOLD);
+		}
+		if (call_2_held) {
+			ast_queue_control(call_2_ast, AST_CONTROL_HOLD);
+		}
+	}
+
+	ast_channel_unlock(call_1_ast);
+	ast_channel_unlock(call_2_ast);
+	sig_pri_unlock_private(pri->pvts[call_1_chanpos]);
+	sig_pri_unlock_private(pri->pvts[call_2_chanpos]);
+
+	return retval;
+}
+#endif	/* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
+
 #if defined(HAVE_PRI_CCSS)
 /*!
  * \internal
@@ -2406,6 +2506,24 @@
 				subcmd->u.cc_cancel.is_agent);
 			break;
 #endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_TRANSFER)
+		case PRI_SUBCMD_TRANSFER_CALL:
+			if (!call_rsp) {
+				/* Should never happen. */
+				ast_log(LOG_ERROR,
+					"Call transfer subcommand without call to send response!\n");
+				break;
+			}
+
+			sig_pri_unlock_private(pri->pvts[chanpos]);
+			pri_transfer_rsp(pri->pri, call_rsp, subcmd->u.transfer.invoke_id,
+				sig_pri_attempt_transfer(pri,
+					subcmd->u.transfer.call_1, subcmd->u.transfer.is_call_1_held,
+					subcmd->u.transfer.call_2, subcmd->u.transfer.is_call_2_held)
+				? 0 : 1);
+			sig_pri_lock_private(pri->pvts[chanpos]);
+			break;
+#endif	/* defined(HAVE_PRI_TRANSFER) */
 		default:
 			ast_debug(2,
 				"Unknown call subcommand(%d) in %s event on channel %d/%d on span %d.\n",
@@ -2415,78 +2533,6 @@
 		}
 	}
 }
-
-#if defined(HAVE_PRI_CALL_HOLD)
-/*!
- * \internal
- * \brief Attempt to transfer the active call to the held call.
- * \since 1.8
- *
- * \param pri sig_pri PRI control structure.
- * \param active_call Active call to transfer.
- * \param held_call Held call to transfer.
- *
- * \note Assumes the pri->lock is already obtained.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int sig_pri_attempt_transfer(struct sig_pri_pri *pri, q931_call *active_call, q931_call *held_call)
-{
-	int retval;
-	int active_chanpos;
-	int held_chanpos;
-	struct ast_channel *active_ast;
-	struct ast_channel *held_ast;
-	struct ast_channel *bridged;
-
-	active_chanpos = pri_find_pri_call(pri, active_call);
-	held_chanpos = pri_find_pri_call(pri, held_call);
-	if (active_chanpos < 0 || held_chanpos < 0) {
-		return -1;
-	}
-
-	sig_pri_lock_private(pri->pvts[active_chanpos]);
-	sig_pri_lock_private(pri->pvts[held_chanpos]);
-	sig_pri_lock_owner(pri, active_chanpos);
-	sig_pri_lock_owner(pri, held_chanpos);
-
-	active_ast = pri->pvts[active_chanpos]->owner;
-	held_ast = pri->pvts[held_chanpos]->owner;
-	if (!active_ast || !held_ast) {
-		if (active_ast) {
-			ast_channel_unlock(active_ast);
-		}
-		if (held_ast) {
-			ast_channel_unlock(held_ast);
-		}
-		sig_pri_unlock_private(pri->pvts[active_chanpos]);
-		sig_pri_unlock_private(pri->pvts[held_chanpos]);
-		return -1;
-	}
-
-	bridged = ast_bridged_channel(held_ast);
-	if (bridged) {
-		ast_queue_control(held_ast, AST_CONTROL_UNHOLD);
-
-		ast_verb(3, "TRANSFERRING %s to %s\n", held_ast->name, active_ast->name);
-		retval = ast_channel_masquerade(active_ast, bridged);
-	} else {
-		/*
-		 * Could not transfer.  Held channel is not bridged anymore.
-		 * Held party probably got tired of waiting and hung up.
-		 */
-		retval = -1;
-	}
-
-	ast_channel_unlock(active_ast);
-	ast_channel_unlock(held_ast);
-	sig_pri_unlock_private(pri->pvts[active_chanpos]);
-	sig_pri_unlock_private(pri->pvts[held_chanpos]);
-
-	return retval;
-}
-#endif	/* defined(HAVE_PRI_CALL_HOLD) */
 
 #if defined(HAVE_PRI_CALL_HOLD)
 /*!
@@ -3766,8 +3812,8 @@
 							&& pri->hold_disconnect_transfer) {
 							/* We are to transfer the call instead of simply hanging up. */
 							sig_pri_unlock_private(pri->pvts[chanpos]);
-							if (!sig_pri_attempt_transfer(pri, e->hangup.call_active,
-								e->hangup.call_held)) {
+							if (!sig_pri_attempt_transfer(pri, e->hangup.call_active, 0,
+								e->hangup.call_held, 1)) {
 								break;
 							}
 							sig_pri_lock_private(pri->pvts[chanpos]);
@@ -4884,6 +4930,9 @@
 	pri_cc_retain_signaling_req(pri->pri, pri->cc_qsig_signaling_link_req);
 	pri_cc_retain_signaling_rsp(pri->pri, pri->cc_qsig_signaling_link_rsp);
 #endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_TRANSFER)
+	pri_transfer_enable(pri->pri, 1);
+#endif	/* defined(HAVE_PRI_TRANSFER) */
 
 	pri->resetpos = -1;
 	if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) {

Modified: trunk/channels/sig_pri.h
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_pri.h?view=diff&rev=266926&r1=266925&r2=266926
==============================================================================
--- trunk/channels/sig_pri.h (original)
+++ trunk/channels/sig_pri.h Wed Jun  2 11:14:12 2010
@@ -253,6 +253,11 @@
 	/*! \brief TRUE if held calls are transferred on disconnect. */
 	unsigned int hold_disconnect_transfer:1;
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
+	/*!
+	 * \brief TRUE if call transfer is enabled for the span.
+	 * \note Support switch-side transfer (called 2BCT, RLT or other names)
+	 */
+	unsigned int transfer:1;
 	int dialplan;							/*!< Dialing plan */
 	int localdialplan;						/*!< Local dialing plan */
 	char internationalprefix[10];			/*!< country access code ('00' for european dialplans) */

Modified: trunk/configs/chan_dahdi.conf.sample
URL: http://svnview.digium.com/svn/asterisk/trunk/configs/chan_dahdi.conf.sample?view=diff&rev=266926&r1=266925&r2=266926
==============================================================================
--- trunk/configs/chan_dahdi.conf.sample (original)
+++ trunk/configs/chan_dahdi.conf.sample Wed Jun  2 11:14:12 2010
@@ -536,6 +536,8 @@
 ;   'facilityenable' setting must also be enabled to allow sending
 ;   the transfer to the ISDN switch, since it sent in a FACILITY
 ;   message.
+;   NOTE:  This should be disabled for NT PTMP mode.  Phones cannot
+;   have tromboned calls pushed down to them.
 ;
 transfer=yes
 ;

Modified: trunk/configure.ac
URL: http://svnview.digium.com/svn/asterisk/trunk/configure.ac?view=diff&rev=266926&r1=266925&r2=266926
==============================================================================
--- trunk/configure.ac (original)
+++ trunk/configure.ac Wed Jun  2 11:14:12 2010
@@ -341,6 +341,7 @@
 AST_EXT_LIB_SETUP([POPT], [popt], [popt])
 AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio])
 AST_EXT_LIB_SETUP([PRI], [ISDN PRI], [pri])
+AST_EXT_LIB_SETUP_DEPENDENT([PRI_TRANSFER], [ISDN PRI call transfer supplementary service], [PRI], [pri])
 AST_EXT_LIB_SETUP_DEPENDENT([PRI_CCSS], [ISDN PRI call completion supplementary service], [PRI], [pri])
 AST_EXT_LIB_SETUP_DEPENDENT([PRI_HANGUP_FIX], [ISDN PRI hangup fix], [PRI], [pri])
 AST_EXT_LIB_SETUP_DEPENDENT([PRI_SUBADDR], [ISDN PRI subaddressing], [PRI], [pri])
@@ -1590,6 +1591,7 @@
 AST_EXT_LIB_CHECK([PORTAUDIO], [portaudio], [Pa_GetDeviceCount], [portaudio.h])
 
 AST_EXT_LIB_CHECK([PRI], [pri], [pri_connected_line_update], [libpri.h])
+AST_EXT_LIB_CHECK([PRI_TRANSFER], [pri], [pri_transfer_enable], [libpri.h])
 AST_EXT_LIB_CHECK([PRI_CCSS], [pri], [pri_cc_enable], [libpri.h])
 AST_EXT_LIB_CHECK([PRI_HANGUP_FIX], [pri], [pri_hangup_fix_enable], [libpri.h])
 AST_EXT_LIB_CHECK([PRI_SUBADDR], [pri], [pri_sr_set_called_subaddress], [libpri.h])

Modified: trunk/include/asterisk/autoconfig.h.in
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/autoconfig.h.in?view=diff&rev=266926&r1=266925&r2=266926
==============================================================================
--- trunk/include/asterisk/autoconfig.h.in (original)
+++ trunk/include/asterisk/autoconfig.h.in Wed Jun  2 11:14:12 2010
@@ -564,6 +564,10 @@
 /* Define to 1 if you have the ISDN PRI subaddressing library. */
 #undef HAVE_PRI_SUBADDR
 
+/* Define to 1 if you have the ISDN PRI call transfer supplementary service
+   library. */
+#undef HAVE_PRI_TRANSFER
+
 /* Define if you have POSIX threads libraries and header files. */
 #undef HAVE_PTHREAD
 
@@ -1044,9 +1048,6 @@
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
-/* Define to 1 if the C compiler supports function prototypes. */
-#undef PROTOTYPES
-
 /* Define to necessary symbol if this constant uses a non-standard name on
    your system. */
 #undef PTHREAD_CREATE_JOINABLE
@@ -1065,11 +1066,6 @@
 
 /* Define to the type of arg 5 for `select'. */
 #undef SELECT_TYPE_ARG5
-
-/* Define to 1 if the `setvbuf' function takes the buffering type as its
-   second argument and the buffer pointer as the third, as on System V before
-   release 3. */
-#undef SETVBUF_REVERSED
 
 /* The size of `char *', as computed by sizeof. */
 #undef SIZEOF_CHAR_P
@@ -1100,20 +1096,30 @@
 /* Define to 1 if your <sys/time.h> declares `struct tm'. */
 #undef TM_IN_SYS_TIME
 
-/* Define to 1 if on AIX 3.
-   System headers sometimes define this.
-   We just want to avoid a redefinition error message.  */
+/* Enable extensions on AIX 3, Interix.  */
 #ifndef _ALL_SOURCE
 # undef _ALL_SOURCE
 #endif
-
-/* Number of bits in a file offset, on hosts where this is settable. */
-#undef _FILE_OFFSET_BITS
-
 /* Enable GNU extensions on systems that have them.  */
 #ifndef _GNU_SOURCE
 # undef _GNU_SOURCE
 #endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
 
 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
 #undef _LARGEFILE_SOURCE
@@ -1130,20 +1136,6 @@
 
 /* Define to 1 if you need to in order for `stat' and other things to work. */
 #undef _POSIX_SOURCE
-
-/* Enable extensions on Solaris.  */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-
-/* Define like PROTOTYPES; this can be used by system headers. */
-#undef __PROTOTYPES
 
 /* Define to empty if `const' does not conform to ANSI C. */
 #undef const




More information about the asterisk-commits mailing list