[asterisk-commits] rmudgett: branch rmudgett/dahdi_facility r218797 - /team/rmudgett/dahdi_facil...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Sep 15 19:23:56 CDT 2009


Author: rmudgett
Date: Tue Sep 15 19:23:52 2009
New Revision: 218797

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=218797
Log:
Handle HOLD/RETRIEVE events from libpri.

Work in progress.

Next need to handle transferring held calls.

Modified:
    team/rmudgett/dahdi_facility/channels/sig_pri.c

Modified: team/rmudgett/dahdi_facility/channels/sig_pri.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/rmudgett/dahdi_facility/channels/sig_pri.c?view=diff&rev=218797&r1=218796&r2=218797
==============================================================================
--- team/rmudgett/dahdi_facility/channels/sig_pri.c (original)
+++ team/rmudgett/dahdi_facility/channels/sig_pri.c Tue Sep 15 19:23:52 2009
@@ -67,11 +67,12 @@
 #define DCHAN_NOTINALARM  (1 << 0)
 #define DCHAN_UP          (1 << 1)
 
-#define PRI_CHANNEL(p)		((p) & 0xff)
-#define PRI_SPAN(p)			(((p) >> 8) & 0xff)
-#define PRI_EXPLICIT(p)		(((p) >> 16) & 0x01)
-#define PRI_CIS_CALL(p)		(((p) >> 17) & 0x01)	/* Call is using the D channel only. */
-#define PRI_HELD_CALL(p)	(((p) >> 18) & 0x01)
+/* Defines to help decode the encoded event channel id. */
+#define PRI_CHANNEL(p)	((p) & 0xff)
+#define PRI_SPAN(p)		(((p) >> 8) & 0xff)
+#define PRI_EXPLICIT	(1 << 16)
+#define PRI_CIS_CALL	(1 << 17)	/* Call is using the D channel only. */
+#define PRI_HELD_CALL	(1 << 18)
 
 
 #define DCHAN_AVAILABLE	(DCHAN_NOTINALARM | DCHAN_UP)
@@ -92,7 +93,7 @@
 
 static unsigned int PVT_TO_CHANNEL(struct sig_pri_chan *p)
 {
-	int res = (((p)->prioffset) | ((p)->logicalspan << 8) | (p->mastertrunkgroup ? 0x10000 : 0));
+	int res = (((p)->prioffset) | ((p)->logicalspan << 8) | (p->mastertrunkgroup ? PRI_EXPLICIT : 0));
 	ast_debug(5, "prioffset: %d mastertrunkgroup: %d logicalspan: %d result: %d\n",
 		p->prioffset, p->mastertrunkgroup, p->logicalspan, res);
 
@@ -672,7 +673,7 @@
 		return -1;
 	}
 
-	if (PRI_HELD_CALL(channel)) {
+	if (channel & PRI_HELD_CALL) {
 		if (!call) {
 			/* Cannot find a held call without a call. */
 			return -1;
@@ -689,7 +690,7 @@
 	}
 
 	span = PRI_SPAN(channel);
-	if (!PRI_EXPLICIT(channel)) {
+	if (!(channel & PRI_EXPLICIT)) {
 		int index;
 
 		index = pri_active_dchan_index(pri);
@@ -903,6 +904,41 @@
 			x++;
 	}
 	return -1;
+}
+
+/*!
+ * \internal
+ * \brief Find or create an empty no-B-channel interface to use.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri span controller to find interface.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval array-index into private pointer array on success.
+ * \retval -1 on error.
+ */
+static int pri_find_empty_nobch(struct sig_pri_pri *pri)
+{
+	int idx;
+
+	for (idx = 0; idx < pri->numchans; ++idx) {
+		if (pri->pvts[idx]
+			&& pri->pvts[idx]->no_b_channel
+			&& !pri->pvts[idx]->inalarm
+			&& !pri->pvts[idx]->owner) {
+			ast_debug(1, "Found empty available no B channel interface\n");
+			return idx;
+		}
+	}
+
+	/* Need to create a new interface. */
+	if (pri->calls->new_nobch_intf) {
+		idx = pri->calls->new_nobch_intf(pri);
+	} else {
+		idx = -1;
+	}
+	return idx;
 }
 
 static void *do_idle_thread(void *vchan)
@@ -2429,36 +2465,114 @@
 				break;
 #if defined(HAVE_PRI)	/* BUGBUG */
 			case PRI_EVENT_HOLD:
-/* BUGBUG */
+				chanpos = pri_find_principle(pri, e->hold.channel, e->hold.call);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING,
+						"Received HOLD on unconfigured channel %d/%d span %d\n",
+						PRI_SPAN(e->hold.channel), PRI_CHANNEL(e->hold.channel),
+						pri->span);
+					pri_hold_rej(pri->pri, e->hold.call,
+						PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->hold.channel,
+					e->hold.subcmds);
+				sig_pri_unlock_private(pri->pvts[chanpos]);
+				if (pri->pvts[chanpos]->no_b_channel) {
+					/* Call is already on hold or is call waiting call. */
+					pri_hold_rej(pri->pri, e->hold.call,
+						PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
+					break;
+				}
+				chanpos = pri_find_empty_nobch(pri);
+				if (chanpos < 0) {
+					pri_hold_rej(pri->pri, e->hold.call,
+						PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
+					break;
+				}
+				chanpos = pri_fixup_principle(pri, chanpos, e->hold.call);
+				if (chanpos < 0) {
+					pri_hold_rej(pri->pri, e->hold.call,
+						PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
+					break;
+				}
+				{
+					struct ast_frame f = { AST_FRAME_CONTROL, };
+	
+					f.subclass = AST_CONTROL_HOLD;
+					pri_queue_frame(pri->pvts[chanpos], &f, pri);
+				}
+				pri_hold_ack(pri->pri, e->hold.call);
 				break;
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
 #if defined(HAVE_PRI)	/* BUGBUG */
 			case PRI_EVENT_HOLD_ACK:
-/* BUGBUG */
+				ast_debug(1, "Event: HOLD_ACK\n");
 				break;
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
 #if defined(HAVE_PRI)	/* BUGBUG */
 			case PRI_EVENT_HOLD_REJ:
-/* BUGBUG */
+				ast_debug(1, "Event: HOLD_REJ\n");
 				break;
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
 #if defined(HAVE_PRI)	/* BUGBUG */
 			case PRI_EVENT_RETRIEVE:
-/* BUGBUG */
+				if (!(e->retrieve.channel & PRI_HELD_CALL)
+					|| pri_find_principle(pri, e->retrieve.channel, e->retrieve.call) < 0) {
+					/* The call is not currently held. */
+					pri_retrieve_rej(pri->pri, e->retrieve.call,
+						PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
+					break;
+				}
+				if (PRI_CHANNEL(e->retrieve.channel) == 0xFF) {
+					chanpos = pri_find_empty_chan(pri, 1);
+				} else {
+					chanpos = pri_find_principle(pri,
+						e->retrieve.channel & ~PRI_HELD_CALL, e->retrieve.call);
+					if (e->retrieve.flexible
+						&& (chanpos < 0 || pri->pvts[chanpos]->owner)) {
+						/*
+						 * Channel selection is flexible and the requested channel
+						 * is bad or already in use.  Pick another channel.
+						 */
+						chanpos = pri_find_empty_chan(pri, 1);
+					}
+				}
+				if (chanpos < 0) {
+					pri_retrieve_rej(pri->pri, e->retrieve.call,
+						e->retrieve.flexible ? PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION
+						: PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+					break;
+				}
+				chanpos = pri_fixup_principle(pri, chanpos, e->retrieve.call);
+				if (chanpos < 0) {
+					/* Channel is already in use. */
+					pri_retrieve_rej(pri->pri, e->retrieve.call,
+						PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->retrieve.channel,
+					e->retrieve.subcmds);
+				sig_pri_unlock_private(pri->pvts[chanpos]);
+				pri_retrieve_ack(pri->pri, e->retrieve.call,
+					PVT_TO_CHANNEL(pri->pvts[chanpos]));
 				break;
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
 #if defined(HAVE_PRI)	/* BUGBUG */
 			case PRI_EVENT_RETRIEVE_ACK:
-/* BUGBUG */
+				ast_debug(1, "Event: RETRIEVE_ACK\n");
 				break;
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
 #if defined(HAVE_PRI)	/* BUGBUG */
 			case PRI_EVENT_RETRIEVE_REJ:
-/* BUGBUG */
+				ast_debug(1, "Event: RETRIEVE_REJ\n");
 				break;
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
 			default:
 				ast_debug(1, "Event: %d\n", e->e);
+				break;
 			}
 		}
 		ast_mutex_unlock(&pri->lock);




More information about the asterisk-commits mailing list