[asterisk-commits] rmudgett: branch rmudgett/hold_retrieve r298688 - /team/rmudgett/hold_retriev...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Dec 16 23:52:31 UTC 2010
Author: rmudgett
Date: Thu Dec 16 17:52:27 2010
New Revision: 298688
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=298688
Log:
Initial initate HOLD/RETRIEVE FSM implementation.
Modified:
team/rmudgett/hold_retrieve/channels/sig_pri.c
team/rmudgett/hold_retrieve/channels/sig_pri.h
Modified: team/rmudgett/hold_retrieve/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hold_retrieve/channels/sig_pri.c?view=diff&rev=298688&r1=298687&r2=298688
==============================================================================
--- team/rmudgett/hold_retrieve/channels/sig_pri.c (original)
+++ team/rmudgett/hold_retrieve/channels/sig_pri.c Thu Dec 16 17:52:27 2010
@@ -1078,6 +1078,32 @@
pri_queue_frame(pri, chanpos, &f);
}
+/*!
+ * \internal
+ * \brief Find the channel associated with the libpri call.
+ * \since 1.10
+ *
+ * \param pri sig_pri span controller to find interface.
+ * \param call LibPRI opaque call pointer to find.
+ *
+ * \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_principle_by_call(struct sig_pri_span *pri, q931_call *call)
+{
+ int idx;
+
+ for (idx = 0; idx < pri->numchans; ++idx) {
+ if (pri->pvts[idx] && pri->pvts[idx]->call == call) {
+ /* Found the principle */
+ return idx;
+ }
+ }
+ return -1;
+}
+
static int pri_find_principle(struct sig_pri_span *pri, int channel, q931_call *call)
{
int x;
@@ -1096,15 +1122,7 @@
/* Cannot find a call waiting call or held call without a call. */
return -1;
}
- principle = -1;
- for (x = 0; x < pri->numchans; ++x) {
- if (pri->pvts[x]
- && pri->pvts[x]->call == call) {
- principle = x;
- break;
- }
- }
- return principle;
+ return pri_find_principle_by_call(pri, call);
}
span = PRI_SPAN(channel);
@@ -1222,9 +1240,10 @@
#if defined(HAVE_PRI_SETUP_KEYPAD)
strcpy(new_chan->keypad_digits, old_chan->keypad_digits);
#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
-#if defined(HAVE_PRI_CALL_HOLD)
strcpy(new_chan->moh_suggested, old_chan->moh_suggested);
-#endif /* defined(HAVE_PRI_CALL_HOLD) */
+ new_chan->moh_state = old_chan->moh_state;
+ old_chan->moh_state = SIG_PRI_MOH_STATE_IDLE;
+
#if defined(HAVE_PRI_AOC_EVENTS)
new_chan->aoc_s_request_invoke_id = old_chan->aoc_s_request_invoke_id;
new_chan->aoc_e = old_chan->aoc_e;
@@ -1432,34 +1451,6 @@
idx = -1;
}
return idx;
-}
-#endif /* defined(HAVE_PRI_CALL_HOLD) */
-
-#if defined(HAVE_PRI_CALL_HOLD)
-/*!
- * \internal
- * \brief Find the channel associated with the libpri call.
- * \since 1.8
- *
- * \param pri sig_pri span controller to find interface.
- * \param call LibPRI opaque call pointer to find.
- *
- * \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_pri_call(struct sig_pri_span *pri, q931_call *call)
-{
- int idx;
-
- for (idx = 0; idx < pri->numchans; ++idx) {
- if (pri->pvts[idx] && pri->pvts[idx]->call == call) {
- /* Found the channel */
- return idx;
- }
- }
- return -1;
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
@@ -1975,8 +1966,8 @@
c2.held = call_2_held;
call_2 = &c2;
- call_1->chanpos = pri_find_pri_call(pri, call_1->pri);
- call_2->chanpos = pri_find_pri_call(pri, call_2->pri);
+ call_1->chanpos = pri_find_principle_by_call(pri, call_1->pri);
+ call_2->chanpos = pri_find_principle_by_call(pri, call_2->pri);
if (call_1->chanpos < 0 || call_2->chanpos < 0) {
/* Calls not found in span control. */
if (rsp_callback) {
@@ -4037,6 +4028,656 @@
}
}
+/*!
+ * \internal
+ * \brief Convert the MOH state to string.
+ * \since 1.10
+ *
+ * \param state MOH state to process.
+ *
+ * \return String version of MOH state.
+ */
+static const char *sig_pri_moh_state_str(enum sig_pri_moh_state state)
+{
+ const char *str;
+
+ str = "Unknown";
+ switch (state) {
+ case SIG_PRI_MOH_STATE_IDLE:
+ str = "SIG_PRI_MOH_STATE_IDLE";
+ break;
+ case SIG_PRI_MOH_STATE_NOTIFY:
+ str = "SIG_PRI_MOH_STATE_NOTIFY";
+ break;
+ case SIG_PRI_MOH_STATE_MOH:
+ str = "SIG_PRI_MOH_STATE_MOH";
+ break;
+#if defined(HAVE_PRI_CALL_HOLD)
+ case SIG_PRI_MOH_STATE_HOLD_REQ:
+ str = "SIG_PRI_MOH_STATE_HOLD_REQ";
+ break;
+ case SIG_PRI_MOH_STATE_PEND_UNHOLD:
+ str = "SIG_PRI_MOH_STATE_PEND_UNHOLD";
+ break;
+ case SIG_PRI_MOH_STATE_HOLD:
+ str = "SIG_PRI_MOH_STATE_HOLD";
+ break;
+ case SIG_PRI_MOH_STATE_RETRIEVE_REQ:
+ str = "SIG_PRI_MOH_STATE_RETRIEVE_REQ";
+ break;
+ case SIG_PRI_MOH_STATE_PEND_HOLD:
+ str = "SIG_PRI_MOH_STATE_PEND_HOLD";
+ break;
+ case SIG_PRI_MOH_STATE_RETRIEVE_FAIL:
+ str = "SIG_PRI_MOH_STATE_RETRIEVE_FAIL";
+ break;
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+ case SIG_PRI_MOH_STATE_NUM:
+ /* Not a real state. */
+ break;
+ }
+ return str;
+}
+
+/*!
+ * \internal
+ * \brief Convert the MOH event to string.
+ * \since 1.10
+ *
+ * \param event MOH event to process.
+ *
+ * \return String version of MOH event.
+ */
+static const char *sig_pri_moh_event_str(enum sig_pri_moh_event event)
+{
+ const char *str;
+
+ str = "Unknown";
+ switch (event) {
+ case SIG_PRI_MOH_EVENT_RESET:
+ str = "SIG_PRI_MOH_EVENT_RESET";
+ break;
+ case SIG_PRI_MOH_EVENT_HOLD:
+ str = "SIG_PRI_MOH_EVENT_HOLD";
+ break;
+ case SIG_PRI_MOH_EVENT_UNHOLD:
+ str = "SIG_PRI_MOH_EVENT_UNHOLD";
+ break;
+#if defined(HAVE_PRI_CALL_HOLD)
+ case SIG_PRI_MOH_EVENT_HOLD_ACK:
+ str = "SIG_PRI_MOH_EVENT_HOLD_ACK";
+ break;
+ case SIG_PRI_MOH_EVENT_HOLD_REJ:
+ str = "SIG_PRI_MOH_EVENT_HOLD_REJ";
+ break;
+ case SIG_PRI_MOH_EVENT_RETRIEVE_ACK:
+ str = "SIG_PRI_MOH_EVENT_RETRIEVE_ACK";
+ break;
+ case SIG_PRI_MOH_EVENT_RETRIEVE_REJ:
+ str = "SIG_PRI_MOH_EVENT_RETRIEVE_REJ";
+ break;
+ case SIG_PRI_MOH_EVENT_REMOTE_HOLD_ACK:
+ str = "SIG_PRI_MOH_EVENT_REMOTE_HOLD_ACK";
+ break;
+ case SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK:
+ str = "SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK";
+ break;
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+ case SIG_PRI_MOH_EVENT_NUM:
+ /* Not a real event. */
+ break;
+ }
+ return str;
+}
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Retrieve a call that was placed on hold by the HOLD message.
+ * \since 1.10
+ *
+ * \param pvt Channel private control structure.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+static enum sig_pri_moh_state sig_pri_moh_retrieve_call(struct sig_pri_chan *pvt)
+{
+ int chanpos;
+ int channel;
+
+ if (pvt->pri->nodetype == PRI_NETWORK) {
+ /* Find an available channel to propose */
+ chanpos = pri_find_empty_chan(pvt->pri, 1);
+ if (chanpos < 0) {
+ /* No channels available. */
+ return SIG_PRI_MOH_STATE_RETRIEVE_FAIL;
+ }
+ channel = PVT_TO_CHANNEL(pvt->pri->pvts[chanpos]);
+
+ /*
+ * We cannot occupy or reserve this channel at this time because
+ * the retrieve may fail or we could have a RETRIEVE collision.
+ */
+ } else {
+ /* Let the network pick the channel. */
+ channel = 0;
+ }
+
+ if (pri_retrieve(pvt->pri->pri, pvt->call, channel)) {
+ return SIG_PRI_MOH_STATE_RETRIEVE_FAIL;
+ }
+ return SIG_PRI_MOH_STATE_RETRIEVE_REQ;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+/*!
+ * \internal
+ * \brief MOH FSM state idle.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+static enum sig_pri_moh_state sig_pri_moh_fsm_idle(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
+{
+ enum sig_pri_moh_state next_state;
+
+ next_state = pvt->moh_state;
+ switch (event) {
+ case SIG_PRI_MOH_EVENT_HOLD:
+ if (!strcasecmp(pvt->mohinterpret, "passthrough")) {
+ /* The old way did not send MOH just in case the notification was ignored. */
+ pri_notify(pvt->pri->pri, pvt->call, pvt->prioffset, PRI_NOTIFY_REMOTE_HOLD);
+ next_state = SIG_PRI_MOH_STATE_NOTIFY;
+ break;
+ }
+
+ switch (pvt->pri->moh_signaling) {
+ default:
+ case SIG_PRI_MOH_SIGNALING_MOH:
+ ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
+ next_state = SIG_PRI_MOH_STATE_MOH;
+ break;
+ case SIG_PRI_MOH_SIGNALING_NOTIFY:
+ /* Send MOH anyway in case the far end does not interpret the notification. */
+ ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
+
+ pri_notify(pvt->pri->pri, pvt->call, pvt->prioffset, PRI_NOTIFY_REMOTE_HOLD);
+ next_state = SIG_PRI_MOH_STATE_NOTIFY;
+ break;
+#if defined(HAVE_PRI_CALL_HOLD)
+ case SIG_PRI_MOH_SIGNALING_HOLD:
+ if (pri_hold(pvt->pri->pri, pvt->call)) {
+ /* Fall back to MOH instead */
+ ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
+ next_state = SIG_PRI_MOH_STATE_MOH;
+ } else {
+ next_state = SIG_PRI_MOH_STATE_HOLD_REQ;
+ }
+ break;
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+ }
+ break;
+ default:
+ break;
+ }
+ pvt->moh_state = next_state;
+ return next_state;
+}
+
+/*!
+ * \internal
+ * \brief MOH FSM state notify remote party.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+static enum sig_pri_moh_state sig_pri_moh_fsm_notify(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
+{
+ enum sig_pri_moh_state next_state;
+
+ next_state = pvt->moh_state;
+ switch (event) {
+ case SIG_PRI_MOH_EVENT_UNHOLD:
+ pri_notify(pvt->pri->pri, pvt->call, pvt->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
+ /* Fall through */
+ case SIG_PRI_MOH_EVENT_RESET:
+ ast_moh_stop(chan);
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+ default:
+ break;
+ }
+ pvt->moh_state = next_state;
+ return next_state;
+}
+
+/*!
+ * \internal
+ * \brief MOH FSM state generate moh.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+static enum sig_pri_moh_state sig_pri_moh_fsm_moh(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
+{
+ enum sig_pri_moh_state next_state;
+
+ next_state = pvt->moh_state;
+ switch (event) {
+ case SIG_PRI_MOH_EVENT_RESET:
+ case SIG_PRI_MOH_EVENT_UNHOLD:
+ ast_moh_stop(chan);
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+#if defined(HAVE_PRI_CALL_HOLD)
+ case SIG_PRI_MOH_EVENT_REMOTE_HOLD_ACK:
+ if (pvt->pri->moh_signaling == SIG_PRI_MOH_SIGNALING_HOLD) {
+ /*
+ * Switch to HOLD/RETRIEVE method since that is what we really
+ * want anyway.
+ */
+ if (chan) {
+ ast_moh_stop(chan);
+ }
+ next_state = SIG_PRI_MOH_STATE_HOLD;
+ }
+ break;
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+ default:
+ break;
+ }
+ pvt->moh_state = next_state;
+ return next_state;
+}
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief MOH FSM state hold requested.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+static enum sig_pri_moh_state sig_pri_moh_fsm_hold_req(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
+{
+ enum sig_pri_moh_state next_state;
+
+ next_state = pvt->moh_state;
+ switch (event) {
+ case SIG_PRI_MOH_EVENT_RESET:
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+ case SIG_PRI_MOH_EVENT_UNHOLD:
+ next_state = SIG_PRI_MOH_STATE_PEND_UNHOLD;
+ break;
+ case SIG_PRI_MOH_EVENT_HOLD_REJ:
+ /* Fall back to MOH */
+ if (chan) {
+ ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
+ }
+ next_state = SIG_PRI_MOH_STATE_MOH;
+ break;
+ case SIG_PRI_MOH_EVENT_HOLD_ACK:
+ case SIG_PRI_MOH_EVENT_REMOTE_HOLD_ACK:
+ next_state = SIG_PRI_MOH_STATE_HOLD;
+ break;
+ default:
+ break;
+ }
+ pvt->moh_state = next_state;
+ return next_state;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief MOH FSM state hold requested with pending unhold.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+static enum sig_pri_moh_state sig_pri_moh_fsm_pend_unhold(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
+{
+ enum sig_pri_moh_state next_state;
+
+ next_state = pvt->moh_state;
+ switch (event) {
+ case SIG_PRI_MOH_EVENT_RESET:
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+ case SIG_PRI_MOH_EVENT_HOLD:
+ next_state = SIG_PRI_MOH_STATE_HOLD_REQ;
+ break;
+ case SIG_PRI_MOH_EVENT_HOLD_REJ:
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+ case SIG_PRI_MOH_EVENT_HOLD_ACK:
+ next_state = sig_pri_moh_retrieve_call(pvt);
+ break;
+ default:
+ break;
+ }
+ pvt->moh_state = next_state;
+ return next_state;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief MOH FSM state hold.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+static enum sig_pri_moh_state sig_pri_moh_fsm_hold(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
+{
+ enum sig_pri_moh_state next_state;
+
+ next_state = pvt->moh_state;
+ switch (event) {
+ case SIG_PRI_MOH_EVENT_RESET:
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+ case SIG_PRI_MOH_EVENT_UNHOLD:
+ next_state = sig_pri_moh_retrieve_call(pvt);
+ break;
+ case SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK:
+ /* Fall back to MOH */
+ if (chan) {
+ ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
+ }
+ next_state = SIG_PRI_MOH_STATE_MOH;
+ break;
+ default:
+ break;
+ }
+ pvt->moh_state = next_state;
+ return next_state;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief MOH FSM state retrieve requested.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+static enum sig_pri_moh_state sig_pri_moh_fsm_retrieve_req(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
+{
+ enum sig_pri_moh_state next_state;
+
+ next_state = pvt->moh_state;
+ switch (event) {
+ case SIG_PRI_MOH_EVENT_RESET:
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+ case SIG_PRI_MOH_EVENT_HOLD:
+ next_state = SIG_PRI_MOH_STATE_PEND_UNHOLD;
+ break;
+ case SIG_PRI_MOH_EVENT_RETRIEVE_ACK:
+ case SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK:
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+ case SIG_PRI_MOH_EVENT_RETRIEVE_REJ:
+ next_state = SIG_PRI_MOH_STATE_RETRIEVE_FAIL;
+ break;
+ default:
+ break;
+ }
+ pvt->moh_state = next_state;
+ return next_state;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief MOH FSM state retrieve requested with pending hold.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+static enum sig_pri_moh_state sig_pri_moh_fsm_pend_hold(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
+{
+ enum sig_pri_moh_state next_state;
+
+ next_state = pvt->moh_state;
+ switch (event) {
+ case SIG_PRI_MOH_EVENT_RESET:
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+ case SIG_PRI_MOH_EVENT_UNHOLD:
+ next_state = SIG_PRI_MOH_STATE_RETRIEVE_REQ;
+ break;
+ case SIG_PRI_MOH_EVENT_RETRIEVE_ACK:
+ case SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK:
+ /*
+ * Successfully came off of hold. Now we can reinterpret the
+ * MOH signaling option to handle the pending HOLD request.
+ */
+ switch (pvt->pri->moh_signaling) {
+ default:
+ case SIG_PRI_MOH_SIGNALING_MOH:
+ if (chan) {
+ ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
+ }
+ next_state = SIG_PRI_MOH_STATE_MOH;
+ break;
+ case SIG_PRI_MOH_SIGNALING_NOTIFY:
+ /* Send MOH anyway in case the far end does not interpret the notification. */
+ if (chan) {
+ ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
+ }
+
+ pri_notify(pvt->pri->pri, pvt->call, pvt->prioffset, PRI_NOTIFY_REMOTE_HOLD);
+ next_state = SIG_PRI_MOH_STATE_NOTIFY;
+ break;
+ case SIG_PRI_MOH_SIGNALING_HOLD:
+ if (pri_hold(pvt->pri->pri, pvt->call)) {
+ /* Fall back to MOH instead */
+ if (chan) {
+ ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
+ }
+ next_state = SIG_PRI_MOH_STATE_MOH;
+ } else {
+ next_state = SIG_PRI_MOH_STATE_HOLD_REQ;
+ }
+ break;
+ }
+ break;
+ case SIG_PRI_MOH_EVENT_RETRIEVE_REJ:
+ /*
+ * We cannot reinterpret the MOH signaling option because we
+ * failed to come off of hold.
+ */
+ next_state = SIG_PRI_MOH_STATE_HOLD;
+ break;
+ default:
+ break;
+ }
+ pvt->moh_state = next_state;
+ return next_state;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief MOH FSM state retrieve failed.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+static enum sig_pri_moh_state sig_pri_moh_fsm_retrieve_fail(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
+{
+ enum sig_pri_moh_state next_state;
+
+ next_state = pvt->moh_state;
+ switch (event) {
+ case SIG_PRI_MOH_EVENT_RESET:
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+ case SIG_PRI_MOH_EVENT_HOLD:
+ next_state = SIG_PRI_MOH_STATE_HOLD;
+ break;
+ case SIG_PRI_MOH_EVENT_UNHOLD:
+ next_state = sig_pri_moh_retrieve_call(pvt);
+ break;
+ case SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK:
+ next_state = SIG_PRI_MOH_STATE_IDLE;
+ break;
+ default:
+ break;
+ }
+ pvt->moh_state = next_state;
+ return next_state;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+/*!
+ * \internal
+ * \brief MOH FSM state function type.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Next MOH state
+ */
+typedef enum sig_pri_moh_state (*sig_pri_moh_fsm_state)(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event);
+
+/*! MOH FSM state table. */
+static const sig_pri_moh_fsm_state sig_pri_moh_fsm[SIG_PRI_MOH_STATE_NUM] = {
+/* *INDENT-OFF* */
+ [SIG_PRI_MOH_STATE_IDLE] = sig_pri_moh_fsm_idle,
+ [SIG_PRI_MOH_STATE_NOTIFY] = sig_pri_moh_fsm_notify,
+ [SIG_PRI_MOH_STATE_MOH] = sig_pri_moh_fsm_moh,
+#if defined(HAVE_PRI_CALL_HOLD)
+ [SIG_PRI_MOH_STATE_HOLD_REQ] = sig_pri_moh_fsm_hold_req,
+ [SIG_PRI_MOH_STATE_PEND_UNHOLD] = sig_pri_moh_fsm_pend_unhold,
+ [SIG_PRI_MOH_STATE_HOLD] = sig_pri_moh_fsm_hold,
+ [SIG_PRI_MOH_STATE_RETRIEVE_REQ] = sig_pri_moh_fsm_retrieve_req,
+ [SIG_PRI_MOH_STATE_PEND_HOLD] = sig_pri_moh_fsm_pend_hold,
+ [SIG_PRI_MOH_STATE_RETRIEVE_FAIL] = sig_pri_moh_fsm_retrieve_fail,
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+/* *INDENT-ON* */
+};
+
+/*!
+ * \internal
+ * \brief Send an event to the MOH FSM.
+ * \since 1.10
+ *
+ * \param chan Channel to post event to (Usually pvt->owner)
+ * \param pvt Channel private control structure.
+ * \param event MOH event to process.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_moh_fsm_event(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
+{
+ enum sig_pri_moh_state orig_state;
+ enum sig_pri_moh_state next_state;
+ const char *chan_name;
+
+ if (chan) {
+ chan_name = ast_strdupa(chan->name);
+ } else {
+ chan_name = "Unknown";
+ }
+ orig_state = pvt->moh_state;
+ ast_debug(2, "Channel '%s' MOH-Event: %s in state %s\n", chan_name,
+ sig_pri_moh_event_str(event), sig_pri_moh_state_str(orig_state));
+ if (orig_state < SIG_PRI_MOH_STATE_IDLE || SIG_PRI_MOH_STATE_NUM <= orig_state
+ || !sig_pri_moh_fsm[orig_state]) {
+ /* Programming error: State not implemented. */
+ ast_log(LOG_ERROR, "MOH state not implemented: %s(%d)\n",
+ sig_pri_moh_state_str(orig_state), orig_state);
+ return;
+ }
+ /* Execute the state. */
+ next_state = sig_pri_moh_fsm[orig_state](chan, pvt, event);
+ ast_debug(2, "Channel '%s' MOH-Next-State: %s\n", chan_name,
+ (orig_state == next_state) ? "$" : sig_pri_moh_state_str(next_state));
+}
+
#if defined(HAVE_PRI_CALL_HOLD)
/*!
* \internal
@@ -4139,6 +4780,100 @@
#if defined(HAVE_PRI_CALL_HOLD)
/*!
* \internal
+ * \brief Handle the hold acknowledge event from libpri.
+ * \since 1.10
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param ev Hold acknowledge event received.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_handle_hold_ack(struct sig_pri_span *pri, pri_event *ev)
+{
+ int chanpos;
+
+ /*
+ * We were successfully put on hold by the remote party
+ * so we just need to switch to a no_b_channel channel.
+ */
+ chanpos = pri_find_empty_nobch(pri);
+ if (chanpos < 0) {
+ /*
+ * Very bad news. No hold channel available.
+ * XXX Should seriously consider killing the call.
+ */
+ ast_log(LOG_ERROR,
+ "Span %d: No hold channel available for held call that is on %d/%d\n",
+ pri->span, PRI_SPAN(ev->hold_ack.channel), PRI_CHANNEL(ev->hold_ack.channel));
+ return;
+ }
+ chanpos = pri_fixup_principle(pri, chanpos, ev->hold_ack.call);
+ if (chanpos < 0) {
+ /*
+ * Should never happen.
+ * XXX Should seriously consider killing the call.
+ */
+ return;
+ }
+
+ sig_pri_lock_private(pri->pvts[chanpos]);
+ sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->hold_ack.channel,
+ ev->hold_ack.subcmds, ev->hold_ack.call);
+ sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
+ SIG_PRI_MOH_EVENT_HOLD_ACK);
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Handle the hold reject event from libpri.
+ * \since 1.10
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param ev Hold reject event received.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_handle_hold_rej(struct sig_pri_span *pri, pri_event *ev)
+{
+ int chanpos;
+
+ chanpos = pri_find_principle(pri, ev->hold_rej.channel, ev->hold_rej.call);
+ if (chanpos < 0) {
+ ast_log(LOG_WARNING, "Span %d: Could not find principle for HOLD_REJECT\n",
+ pri->span);
+ return;
+ }
+ chanpos = pri_fixup_principle(pri, chanpos, ev->hold_rej.call);
+ if (chanpos < 0) {
+ /*
+ * Should never happen.
+ * XXX Should seriously consider killing the call.
+ */
+ return;
+ }
+
+ ast_debug(1, "Span %d: HOLD_REJECT cause: %d(%s)\n", pri->span,
+ ev->hold_rej.cause, pri_cause2str(ev->hold_rej.cause));
+
+ sig_pri_lock_private(pri->pvts[chanpos]);
+ sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->hold_rej.channel,
+ ev->hold_rej.subcmds, ev->hold_rej.call);
+ sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
+ SIG_PRI_MOH_EVENT_HOLD_REJ);
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
* \brief Handle the retrieve event from libpri.
* \since 1.8
*
@@ -4196,10 +4931,97 @@
sig_pri_ami_hold_event(pri->pvts[chanpos]->owner, 0);
ast_channel_unlock(pri->pvts[chanpos]->owner);
}
+ pri_retrieve_ack(pri->pri, ev->retrieve.call,
+ PVT_TO_CHANNEL(pri->pvts[chanpos]));
+ sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
+ SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK);
sig_pri_unlock_private(pri->pvts[chanpos]);
sig_pri_span_devstate_changed(pri);
- pri_retrieve_ack(pri->pri, ev->retrieve.call,
- PVT_TO_CHANNEL(pri->pvts[chanpos]));
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Handle the retrieve acknowledge event from libpri.
+ * \since 1.10
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param ev Retrieve acknowledge event received.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_handle_retrieve_ack(struct sig_pri_span *pri, pri_event *ev)
+{
+ int chanpos;
+
+ chanpos = pri_find_principle(pri, ev->retrieve_ack.channel, ev->retrieve_ack.call);
+ if (chanpos < 0) {
+ ast_log(LOG_WARNING,
+ "Span %d: Could not find principle for RETRIEVE_ACKNOWLEDGE\n", pri->span);
+ return;
+ }
+ chanpos = pri_fixup_principle(pri, chanpos, ev->retrieve_ack.call);
+ if (chanpos < 0) {
+ /*
+ * Very bad news. The channel is already in use.
+ * XXX Should seriously consider killing the call.
+ */
+ return;
+ }
+
+ sig_pri_lock_private(pri->pvts[chanpos]);
+ sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->retrieve_ack.channel,
+ ev->retrieve_ack.subcmds, ev->retrieve_ack.call);
+ sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
+ SIG_PRI_MOH_EVENT_RETRIEVE_ACK);
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Handle the retrieve reject event from libpri.
+ * \since 1.10
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param ev Retrieve reject event received.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_handle_retrieve_rej(struct sig_pri_span *pri, pri_event *ev)
+{
+ int chanpos;
+
+ chanpos = pri_find_principle(pri, ev->retrieve_rej.channel, ev->retrieve_rej.call);
+ if (chanpos < 0) {
+ ast_log(LOG_WARNING, "Span %d: Could not find principle for RETRIEVE_REJECT\n",
+ pri->span);
+ return;
+ }
+ chanpos = pri_fixup_principle(pri, chanpos, ev->retrieve_rej.call);
+ if (chanpos < 0) {
+ /*
+ * Should never happen.
+ * XXX Should seriously consider killing the call.
+ */
+ return;
+ }
+
+ ast_debug(1, "Span %d: RETRIEVE_REJECT cause: %d(%s)\n", pri->span,
+ ev->retrieve_rej.cause, pri_cause2str(ev->retrieve_rej.cause));
+
+ sig_pri_lock_private(pri->pvts[chanpos]);
+ sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->retrieve_rej.channel,
+ ev->retrieve_rej.subcmds, ev->retrieve_rej.call);
+ sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
+ SIG_PRI_MOH_EVENT_RETRIEVE_REJ);
+ sig_pri_unlock_private(pri->pvts[chanpos]);
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
@@ -4394,8 +5216,8 @@
if (e) {
if (pri->debug) {
- ast_verbose("Span: %d Processing event: %s\n",
- pri->span, pri_event2str(e->e));
+ ast_verbose("Span: %d Processing event: %s(%d)\n",
+ pri->span, pri_event2str(e->e), e->e);
}
if (e->e != PRI_EVENT_DCHAN_DOWN) {
@@ -5772,17 +6594,27 @@
PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
} else {
pri_hold_ack(pri->pri, e->hold.call);
+ chanpos = pri_find_principle_by_call(pri, e->hold.call);
+ if (chanpos < 0) {
+ break;
+ }
+ sig_pri_lock_private(pri->pvts[chanpos]);
+ sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
+ SIG_PRI_MOH_EVENT_REMOTE_HOLD_ACK);
+ sig_pri_unlock_private(pri->pvts[chanpos]);
}
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
case PRI_EVENT_HOLD_ACK:
- ast_debug(1, "Event: HOLD_ACK\n");
+ /* We should not be getting any CIS calls with this message type. */
+ sig_pri_handle_hold_ack(pri, e);
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
case PRI_EVENT_HOLD_REJ:
- ast_debug(1, "Event: HOLD_REJ\n");
+ /* We should not be getting any CIS calls with this message type. */
+ sig_pri_handle_hold_rej(pri, e);
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
@@ -5793,16 +6625,19 @@
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
case PRI_EVENT_RETRIEVE_ACK:
- ast_debug(1, "Event: RETRIEVE_ACK\n");
+ /* We should not be getting any CIS calls with this message type. */
+ sig_pri_handle_retrieve_ack(pri, e);
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
case PRI_EVENT_RETRIEVE_REJ:
- ast_debug(1, "Event: RETRIEVE_REJ\n");
+ /* We should not be getting any CIS calls with this message type. */
+ sig_pri_handle_retrieve_rej(pri, e);
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
default:
- ast_debug(1, "Event: %d\n", e->e);
+ ast_debug(1, "Span: %d Unhandled event: %s(%d)\n",
+ pri->span, pri_event2str(e->e), e->e);
break;
}
}
@@ -5860,6 +6695,7 @@
/* Make sure we have a call (or REALLY have a call in the case of a PRI) */
if (!pri_grab(p, p->pri)) {
+ sig_pri_moh_fsm_event(ast, p, SIG_PRI_MOH_EVENT_RESET);
if (p->call) {
if (p->alreadyhungup) {
ast_log(LOG_DEBUG, "Already hungup... Calling hangup once, and clearing call\n");
@@ -6548,24 +7384,31 @@
}
break;
case AST_CONTROL_HOLD:
- if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
+ ast_copy_string(p->moh_suggested, S_OR(data, ""), sizeof(p->moh_suggested));
+ if (p->pri) {
if (!pri_grab(p, p->pri)) {
- res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_HOLD);
+ sig_pri_moh_fsm_event(chan, p, SIG_PRI_MOH_EVENT_HOLD);
pri_rel(p->pri);
} else {
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
}
- } else
+ } else {
+ /* Something is wrong here. A PRI channel without the pri pointer? */
ast_moh_start(chan, data, p->mohinterpret);
+ }
break;
case AST_CONTROL_UNHOLD:
- if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
+ if (p->pri) {
if (!pri_grab(p, p->pri)) {
- res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
+ sig_pri_moh_fsm_event(chan, p, SIG_PRI_MOH_EVENT_UNHOLD);
pri_rel(p->pri);
+ } else {
+ ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
}
- } else
+ } else {
+ /* Something is wrong here. A PRI channel without the pri pointer? */
ast_moh_stop(chan);
+ }
break;
case AST_CONTROL_SRCUPDATE:
res = 0;
Modified: team/rmudgett/hold_retrieve/channels/sig_pri.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hold_retrieve/channels/sig_pri.h?view=diff&rev=298688&r1=298687&r2=298688
==============================================================================
--- team/rmudgett/hold_retrieve/channels/sig_pri.h (original)
+++ team/rmudgett/hold_retrieve/channels/sig_pri.h Thu Dec 16 17:52:27 2010
@@ -101,6 +101,7 @@
SIG_PRI_MOH_STATE_NOTIFY,
/*! Bridged peer has put us on hold and we were to play MOH or HOLD/RETRIEVE fallback. */
SIG_PRI_MOH_STATE_MOH,
+#if defined(HAVE_PRI_CALL_HOLD)
/*! Requesting to put channel on hold. */
SIG_PRI_MOH_STATE_HOLD_REQ,
/*! Trying to go on hold when bridged peer requested to unhold. */
@@ -113,25 +114,36 @@
SIG_PRI_MOH_STATE_PEND_HOLD,
/*! Failed to take the channel out of hold. No B channels were available? */
SIG_PRI_MOH_STATE_RETRIEVE_FAIL,
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+ /*! Number of MOH states. Must be last in enum. */
+ SIG_PRI_MOH_STATE_NUM
};
enum sig_pri_moh_event {
+ /*! Reset the MOH state machine. (Because of hangup.) */
+ SIG_PRI_MOH_EVENT_RESET,
/*! Bridged peer placed this channel on hold. */
SIG_PRI_MOH_EVENT_HOLD,
+ /*! Bridged peer took this channel off hold. */
+ SIG_PRI_MOH_EVENT_UNHOLD,
+#if defined(HAVE_PRI_CALL_HOLD)
/*! The hold request was successfully acknowledged. */
SIG_PRI_MOH_EVENT_HOLD_ACK,
/*! The hold request was rejected. */
SIG_PRI_MOH_EVENT_HOLD_REJ,
- /*! Bridged peer took this channel off hold. */
- SIG_PRI_MOH_EVENT_UNHOLD,
/*! The unhold request was successfully acknowledged. */
SIG_PRI_MOH_EVENT_RETRIEVE_ACK,
/*! The unhold request was rejected. */
SIG_PRI_MOH_EVENT_RETRIEVE_REJ,
+ /*! The remote party placed this channel on hold. */
+ SIG_PRI_MOH_EVENT_REMOTE_HOLD_ACK,
/*! The remote party took this channel off hold. */
- SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE,
- /*! The remote party placed this channel on hold. */
- SIG_PRI_MOH_EVENT_REMOTE_HOLD,
+ SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK,
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+ /*! Number of MOH events. Must be last in enum. */
+ SIG_PRI_MOH_EVENT_NUM
};
struct sig_pri_span;
@@ -252,10 +264,9 @@
/*! \brief Keypad digits that came in with the SETUP message. */
char keypad_digits[AST_MAX_EXTENSION];
#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
-#if defined(HAVE_PRI_CALL_HOLD)
/*! Music class suggested with AST_CONTROL_HOLD. */
char moh_suggested[MAX_MUSICCLASS];
-#endif /* defined(HAVE_PRI_CALL_HOLD) */
+ enum sig_pri_moh_state moh_state;
#if defined(HAVE_PRI_AOC_EVENTS)
struct pri_subcmd_aoc_e aoc_e;
More information about the asterisk-commits
mailing list