[asterisk-commits] pcadach: trunk r43845 - in /trunk: ./ channels/ channels/h323/ configs/

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Thu Sep 28 03:41:39 MST 2006


Author: pcadach
Date: Thu Sep 28 05:41:38 2006
New Revision: 43845

URL: http://svn.digium.com/view/asterisk?rev=43845&view=rev
Log:
Handle HOLD/RETRIEVE notifications

Modified:
    trunk/CHANGES
    trunk/channels/chan_h323.c
    trunk/channels/h323/ast_h323.cxx
    trunk/channels/h323/ast_h323.h
    trunk/channels/h323/chan_h323.h
    trunk/configs/h323.conf.sample

Modified: trunk/CHANGES
URL: http://svn.digium.com/view/asterisk/trunk/CHANGES?rev=43845&r1=43844&r2=43845&view=diff
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Thu Sep 28 05:41:38 2006
@@ -15,3 +15,5 @@
   * Ability to use libcap to set high ToS bits when non-root
      on Linux. If configure is unable to find libcap then you
      can use --with-cap to specify the path.
+  * H323 remote hold notification support added (by NOTIFY message
+     and/or H.450 supplementary service)

Modified: trunk/channels/chan_h323.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_h323.c?rev=43845&r1=43844&r2=43845&view=diff
==============================================================================
--- trunk/channels/chan_h323.c (original)
+++ trunk/channels/chan_h323.c Thu Sep 28 05:41:38 2006
@@ -117,6 +117,7 @@
 hangup_cb on_hangup;
 setcapabilities_cb on_setcapabilities;
 setpeercapabilities_cb on_setpeercapabilities;
+onhold_cb on_hold;
 
 /* global debug flag */
 int h323debug;
@@ -866,7 +867,7 @@
 	ast_mutex_unlock(&pvt->lock);
 
 	if (h323debug)
-		ast_log(LOG_DEBUG, "OH323: Indicating %d on %s\n", condition, token);
+		ast_log(LOG_DEBUG, "OH323: Indicating %d on %s (%s)\n", condition, token, c->name);
 
 	switch(condition) {
 	case AST_CONTROL_RINGING:
@@ -910,11 +911,14 @@
 			free(token);
 		return -1;
 	case AST_CONTROL_HOLD:
+		h323_hold_call(token, 1);
+		/* We should start MOH only if remote party isn't provide audio for us */
 		ast_moh_start(c, data, NULL);
 		if (token)
 			free(token);
 		return 0;
 	case AST_CONTROL_UNHOLD:
+		h323_hold_call(token, 0);
 		ast_moh_stop(c);
 		if (token)
 			free(token);
@@ -1338,6 +1342,17 @@
 			options->tunnelOptions |= H323_TUNNEL_QSIG;
 		else
 			ast_log(LOG_WARNING, "Invalid value %s for %s at line %d\n", v->value, v->name, v->lineno);
+	} else if (!strcasecmp(v->name, "hold")) {
+		if (!strcasecmp(v->value, "none"))
+			options->holdHandling = ~0;
+		else if (!strcasecmp(v->value, "notify"))
+			options->holdHandling |= H323_HOLD_NOTIFY;
+		else if (!strcasecmp(v->value, "q931only"))
+			options->holdHandling |= H323_HOLD_NOTIFY | H323_HOLD_Q931ONLY;
+		else if (!strcasecmp(v->value, "h450"))
+			options->holdHandling |= H323_HOLD_H450;
+		else
+			ast_log(LOG_WARNING, "Invalid value %s for %s at line %d\n", v->value, v->name, v->lineno);
 	} else
 		return 1;
 
@@ -1364,6 +1379,7 @@
 	user->ha = (struct ast_ha *)NULL;
 	memcpy(&user->options, &global_options, sizeof(user->options));
 	user->options.dtmfmode = 0;
+	user->options.holdHandling = 0;
 	/* Set default context */
 	strncpy(user->context, default_context, sizeof(user->context) - 1);
 	if (user && !found)
@@ -1410,6 +1426,10 @@
 	}
 	if (!user->options.dtmfmode)
 		user->options.dtmfmode = global_options.dtmfmode;
+	if (user->options.holdHandling == ~0)
+		user->options.holdHandling = 0;
+	else if (!user->options.holdHandling)
+		user->options.holdHandling = global_options.holdHandling;
 	ASTOBJ_UNMARK(user);
 	ast_free_ha(oldha);
 	return user;
@@ -1472,6 +1492,7 @@
 	peer->ha = NULL;
 	memcpy(&peer->options, &global_options, sizeof(peer->options));
 	peer->options.dtmfmode = 0;
+	peer->options.holdHandling = 0;
 	peer->addr.sin_port = htons(h323_signalling_port);
 	peer->addr.sin_family = AF_INET;
 	if (!found && name)
@@ -1511,6 +1532,10 @@
 	}
 	if (!peer->options.dtmfmode)
 		peer->options.dtmfmode = global_options.dtmfmode;
+	if (peer->options.holdHandling == ~0)
+		peer->options.holdHandling = 0;
+	else if (!peer->options.holdHandling)
+		peer->options.holdHandling = global_options.holdHandling;
 	ASTOBJ_UNMARK(peer);
 	ast_free_ha(oldha);
 	return peer;
@@ -2450,6 +2475,32 @@
 		ast_log(LOG_DEBUG, "Capabilities for connection %s is set\n", token);
 }
 
+static void remote_hold(unsigned call_reference, const char *token, int is_hold)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Setting %shold status for connection %s\n", (is_hold ? "" : "un"), token);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt)
+		return;
+	if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+		if (is_hold)
+			ast_queue_control(pvt->owner, AST_CONTROL_HOLD);
+		else
+			ast_queue_control(pvt->owner, AST_CONTROL_UNHOLD);
+		ast_channel_unlock(pvt->owner);
+	}
+	else {
+		if (is_hold)
+			pvt->newcontrol = AST_CONTROL_HOLD;
+		else
+			pvt->newcontrol = AST_CONTROL_UNHOLD;
+	}
+	ast_mutex_unlock(&pvt->lock);
+}
+
 static void *do_monitor(void *data)
 {
 	int res;
@@ -2767,6 +2818,7 @@
 	global_options.dtmfcodec[0] = H323_DTMF_RFC2833_PT;
 	global_options.dtmfcodec[1] = H323_DTMF_CISCO_PT;
 	global_options.dtmfmode = 0;
+	global_options.holdHandling = 0;
 	global_options.capability = GLOBAL_CAPABILITY;
 	global_options.bridge = 1;		/* Do native bridging by default */
 	strncpy(default_context, "default", sizeof(default_context) - 1);
@@ -2861,6 +2913,10 @@
 	}
 	if (!global_options.dtmfmode)
 		global_options.dtmfmode = H323_DTMF_RFC2833;
+	if (global_options.holdHandling == ~0)
+		global_options.holdHandling = 0;
+	else if (!global_options.holdHandling)
+		global_options.holdHandling = H323_HOLD_H450;
 
 	for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
 		if (strcasecmp(cat, "general")) {
@@ -3175,7 +3231,8 @@
 						set_dtmf_payload,
 						hangup_connection,
 						set_local_capabilities,
-						set_peer_capabilities);
+						set_peer_capabilities,
+						remote_hold);
 		/* start the h.323 listener */
 		if (h323_start_listener(h323_signalling_port, bindaddr)) {
 			ast_log(LOG_ERROR, "Unable to create H323 listener.\n");

Modified: trunk/channels/h323/ast_h323.cxx
URL: http://svn.digium.com/view/asterisk/trunk/channels/h323/ast_h323.cxx?rev=43845&r1=43844&r2=43845&view=diff
==============================================================================
--- trunk/channels/h323/ast_h323.cxx (original)
+++ trunk/channels/h323/ast_h323.cxx Thu Sep 28 05:41:38 2006
@@ -40,6 +40,12 @@
 #include <h323neg.h>
 #include <mediafmt.h>
 #include <lid.h>
+#ifdef H323_H450
+#include "h4501.h"
+#include "h4504.h"
+#include "h45011.h"
+#include "h450pdu.h"
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -528,10 +534,20 @@
 							unsigned options)
 	: H323Connection(ep, callReference, options)
 {
+#ifdef H323_H450
+	/* Dispatcher will free out all registered handlers */
+	if (h450dispatcher)
+		delete h450dispatcher;
+	h450dispatcher = new H450xDispatcher(*this);
+	h4502handler = new H4502Handler(*this, *h450dispatcher);
+	h4504handler = new MyH4504Handler(*this, *h450dispatcher);
+	h4506handler = new H4506Handler(*this, *h450dispatcher);
+	h45011handler = new H45011Handler(*this, *h450dispatcher);
+#endif
 	cause = -1;
 	sessionId = 0;
 	bridging = FALSE;
-	progressSetup = progressAlert = 0;
+	holdHandling = progressSetup = progressAlert = 0;
 	dtmfMode = 0;
 	dtmfCodec[0] = dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)0;
 	redirect_reason = -1;
@@ -664,6 +680,7 @@
 
 	progressSetup = opts->progress_setup;
 	progressAlert = opts->progress_alert;
+	holdHandling = opts->holdHandling;
 	dtmfCodec[0] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[0];
 	dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[1];
 	dtmfMode = opts->dtmfmode;
@@ -1641,6 +1658,48 @@
 	return TRUE;
 }
 
+#ifdef H323_H450
+void MyH323Connection::OnReceivedLocalCallHold(int linkedId)
+{
+	if (on_hold)
+		on_hold(GetCallReference(), (const char *)GetCallToken(), 1);
+}
+
+void MyH323Connection::OnReceivedLocalCallRetrieve(int linkedId)
+{
+	if (on_hold)
+		on_hold(GetCallReference(), (const char *)GetCallToken(), 0);
+}
+#endif
+
+void MyH323Connection::MyHoldCall(BOOL isHold)
+{
+	if (((holdHandling & H323_HOLD_NOTIFY) != 0) || ((holdHandling & H323_HOLD_Q931ONLY) != 0)) {
+		PBYTEArray x ((const BYTE *)(isHold ? "\xF9" : "\xFA"), 1);
+		H323SignalPDU signal;
+		signal.BuildNotify(*this);
+		signal.GetQ931().SetIE((Q931::InformationElementCodes)39 /* Q931::NotifyIE */, x);
+		if (h323debug)
+			cout << "Sending " << (isHold ? "HOLD" : "RETRIEVE") << " notification: " << signal << endl;
+		if ((holdHandling & H323_HOLD_Q931ONLY) != 0) {
+			PBYTEArray rawData;
+			signal.GetQ931().RemoveIE(Q931::UserUserIE);
+			signal.GetQ931().Encode(rawData);
+			signallingChannel->WritePDU(rawData);
+		} else
+			WriteSignalPDU(signal);
+	}
+#ifdef H323_H450
+	if ((holdHandling & H323_HOLD_H450) != 0) {
+		if (isHold)
+			h4504handler->HoldCall(TRUE);
+		else if (IsLocalHold())
+			h4504handler->RetrieveCall();
+	}
+#endif
+}
+
+
 /* MyH323_ExternalRTPChannel */
 MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
 							const H323Capability & capability,
@@ -1721,6 +1780,32 @@
 	}
 	return FALSE;
 }
+
+#ifdef H323_H450
+MyH4504Handler::MyH4504Handler(MyH323Connection &_conn, H450xDispatcher &_disp)
+	:H4504Handler(_conn, _disp)
+{
+	conn = &_conn;
+}
+
+void MyH4504Handler::OnReceivedLocalCallHold(int linkedId)
+{
+	if (conn) {
+		conn->Lock();
+		conn->OnReceivedLocalCallHold(linkedId);
+		conn->Unlock();
+	}
+}
+
+void MyH4504Handler::OnReceivedLocalCallRetrieve(int linkedId)
+{
+	if (conn) {
+		conn->Lock();
+		conn->OnReceivedLocalCallRetrieve(linkedId);
+		conn->Unlock();
+	}
+}
+#endif
 
 
 /** IMPLEMENTATION OF C FUNCTIONS */
@@ -1780,7 +1865,8 @@
 							rfc2833_cb				dtmffunc,
 							hangup_cb				hangupfunc,
 							setcapabilities_cb		capabilityfunc,
-							setpeercapabilities_cb	peercapabilityfunc)
+							setpeercapabilities_cb	peercapabilityfunc,
+							onhold_cb				holdfunc)
 {
 	on_incoming_call = ifunc;
 	on_outgoing_call = sfunc;
@@ -1796,6 +1882,7 @@
 	on_hangup = hangupfunc;
 	on_setcapabilities = capabilityfunc;
 	on_setpeercapabilities = peercapabilityfunc;
+	on_hold = holdfunc;
 }
 
 /**
@@ -2097,6 +2184,18 @@
 
 }
 
+int h323_hold_call(const char *token, int is_hold)
+{
+	MyH323Connection *conn = (MyH323Connection *)endPoint->FindConnectionWithLock(token);
+	if (!conn) {
+		cout << "ERROR: No connection found, this is bad" << endl;
+		return -1;
+	}
+	conn->MyHoldCall((BOOL)is_hold);
+	conn->Unlock();
+	return 0;
+}
+
 #undef cout
 #undef endl
 void h323_end_process(void)

Modified: trunk/channels/h323/ast_h323.h
URL: http://svn.digium.com/view/asterisk/trunk/channels/h323/ast_h323.h?rev=43845&r1=43844&r2=43845&view=diff
==============================================================================
--- trunk/channels/h323/ast_h323.h (original)
+++ trunk/channels/h323/ast_h323.h Thu Sep 28 05:41:38 2006
@@ -93,6 +93,11 @@
 	virtual BOOL HandleSignalPDU(H323SignalPDU &pdu);
 	BOOL EmbedTunneledInfo(H323SignalPDU &pdu);
 #endif
+#ifdef H323_H450
+	virtual void OnReceivedLocalCallHold(int linkedId);
+	virtual void OnReceivedLocalCallRetrieve(int linkedId);
+#endif
+	void MyHoldCall(BOOL localHold);
 
 	PString sourceAliases;
 	PString destAliases;
@@ -108,6 +113,7 @@
 	int tunnelOptions;
 #endif
 
+	unsigned holdHandling;
 	unsigned progressSetup;
 	unsigned progressAlert;
 	int cause;
@@ -156,6 +162,23 @@
 	void Main();
 };
 
+#ifdef H323_H450
+#include <h450pdu.h>
+
+class MyH4504Handler : public H4504Handler
+{
+	PCLASSINFO(MyH4504Handler, H4504Handler);
+
+public:
+	MyH4504Handler(MyH323Connection &_conn, H450xDispatcher &_disp);
+	virtual void OnReceivedLocalCallHold(int linkedId);
+	virtual void OnReceivedLocalCallRetrieve(int linkedId);
+
+private:
+	MyH323Connection *conn;
+};
+#endif
+
 #include "compat_h323.h"
 
 #endif /* !defined AST_H323_H */

Modified: trunk/channels/h323/chan_h323.h
URL: http://svn.digium.com/view/asterisk/trunk/channels/h323/chan_h323.h?rev=43845&r1=43844&r2=43845&view=diff
==============================================================================
--- trunk/channels/h323/chan_h323.h (original)
+++ trunk/channels/h323/chan_h323.h Thu Sep 28 05:41:38 2006
@@ -38,6 +38,10 @@
 
 #define H323_TUNNEL_CISCO	(1 << 0)
 #define H323_TUNNEL_QSIG	(1 << 1)
+
+#define H323_HOLD_NOTIFY	(1 << 0)
+#define H323_HOLD_Q931ONLY	(1 << 1)
+#define H323_HOLD_H450		(1 << 2)
 
 /** call_option struct holds various bits
  *         of information for each call */
@@ -58,6 +62,7 @@
 	int				bridge;
 	int				nat;
 	int				tunnelOptions;
+	int				holdHandling;
 	struct ast_codec_pref	prefs;
 } call_options_t;
 
@@ -184,6 +189,9 @@
 typedef void (*setpeercapabilities_cb)(unsigned, const char *, int, struct ast_codec_pref *);
 extern setpeercapabilities_cb on_setpeercapabilities;
 
+typedef void (*onhold_cb)(unsigned, const char *, int);
+extern onhold_cb on_hold;
+
 /* debug flag */
 extern int h323debug;
 
@@ -224,7 +232,8 @@
 					rfc2833_cb,
 					hangup_cb,
 					setcapabilities_cb,
-					setpeercapabilities_cb);
+					setpeercapabilities_cb,
+					onhold_cb);
 	int h323_set_capabilities(const char *, int, int, struct ast_codec_pref *, int);
 	int h323_set_alias(struct oh323_alias *);
 	int h323_set_gk(int, char *, char *);
@@ -249,6 +258,7 @@
 	int h323_answering_call(const char *token, int);
 	int h323_soft_hangup(const char *data);
 	int h323_show_codec(int fd, int argc, char *argv[]);
+	int h323_hold_call(const char *token, int);
 
 #ifdef __cplusplus
 }

Modified: trunk/configs/h323.conf.sample
URL: http://svn.digium.com/view/asterisk/trunk/configs/h323.conf.sample?rev=43845&r1=43844&r2=43845&view=diff
==============================================================================
--- trunk/configs/h323.conf.sample (original)
+++ trunk/configs/h323.conf.sample Thu Sep 28 05:41:38 2006
@@ -104,9 +104,18 @@
 ; example, for Cisco CallManager when Q.SIG tunneling is enabled for a
 ; gateway where Asterisk lives.
 ; The option can be used multiple times, one option per line.
-;tunneling=none              ; Totally disable tunneling (default)
-;tunneling=cisco             ; Enable Cisco-specific tunneling
-;tunneling=qsig              ; Enable tunneling via Q.SIG messages
+;tunneling=none               ; Totally disable tunneling (default)
+;tunneling=cisco              ; Enable Cisco-specific tunneling
+;tunneling=qsig               ; Enable tunneling via Q.SIG messages
+;
+; Specify how to pass hold notification to remote party. Default is to
+; use H.450.4 supplementary service message.
+;hold=none                    ; Do not pass hold/retrieve notifications
+;hold=notify                  ; Use H.225 NOTIFY message
+;hold=q931only                ; Use stripped H.225 NOTIFY message (Q.931 part
+;                             ; only, usable for Cisco CallManager)
+;hold=h450                    ; Pass notification as H.450.4 supplementary
+;                             ; service
 ;
 ;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
 ; jbenable = yes              ; Enables the use of a jitterbuffer on the receiving side of a



More information about the asterisk-commits mailing list