Split Hold event into Hold/Unhold, and move it into core.
authorJason Parker <jparker@digium.com>
Fri, 24 May 2013 21:21:25 +0000 (21:21 +0000)
committerJason Parker <jparker@digium.com>
Fri, 24 May 2013 21:21:25 +0000 (21:21 +0000)
(closes issue ASTERISK-21487)
Review: https://reviewboard.asterisk.org/r/2565/

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@389746 65c4cc65-6c06-0410-ace0-fbb531ad65f3

18 files changed:
CHANGES
channels/chan_dahdi.c
channels/chan_h323.c
channels/chan_iax2.c
channels/chan_mgcp.c
channels/chan_misdn.c
channels/chan_motif.c
channels/chan_sip.c
channels/chan_skinny.c
channels/chan_unistim.c
channels/sig_analog.c
channels/sig_pri.c
include/asterisk/channel.h
include/asterisk/stasis_channels.h
main/channel.c
main/manager_channels.c
main/stasis_channels.c
res/res_sip_sdp_rtp.c

diff --git a/CHANGES b/CHANGES
index 273a470..ec01719 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -96,6 +96,10 @@ AMI (Asterisk Manager Interface)
    BridgedChannel and BridgedUniqueid headers with the BridgeID header to
    indicate what bridge the channel is currently in.
 
+ * The AMI 'Hold' event has been moved out of individual channel drivers, into
+   core, and is now two events: Hold and Unhold.  The status field has been
+   removed.
+
 Channel Drivers
 ------------------
  * When a channel driver is configured to enable jiterbuffers, they are now
index 03279a0..9f2dda2 100644 (file)
@@ -6560,7 +6560,7 @@ static int dahdi_hangup(struct ast_channel *ast)
                                p->owner = p->subs[SUB_REAL].owner;
                                if (ast_channel_state(p->owner) != AST_STATE_UP)
                                        p->subs[SUB_REAL].needanswer = 1;
-                               ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(p->subs[SUB_REAL].owner);
                        } else if (p->subs[SUB_THREEWAY].dfd > -1) {
                                swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                unalloc_sub(p, SUB_THREEWAY);
@@ -6582,9 +6582,7 @@ static int dahdi_hangup(struct ast_channel *ast)
                                /* This is actually part of a three way, placed on hold.  Place the third part
                                   on music on hold now */
                                if (p->subs[SUB_THREEWAY].owner) {
-                                       ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
-                                               S_OR(p->mohsuggest, NULL),
-                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                       ast_queue_hold(p->subs[SUB_THREEWAY].owner, p->mohsuggest);
                                }
                                p->subs[SUB_THREEWAY].inthreeway = 0;
                                /* Make it the call wait now */
@@ -6597,9 +6595,7 @@ static int dahdi_hangup(struct ast_channel *ast)
                                /* The other party of the three way call is currently in a call-wait state.
                                   Start music on hold for them, and take the main guy out of the third call */
                                if (p->subs[SUB_CALLWAIT].owner) {
-                                       ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
-                                               S_OR(p->mohsuggest, NULL),
-                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                       ast_queue_hold(p->subs[SUB_CALLWAIT].owner, p->mohsuggest);
                                }
                                p->subs[SUB_CALLWAIT].inthreeway = 0;
                        }
@@ -7851,7 +7847,7 @@ static int attempt_transfer(struct dahdi_pvt *p)
        if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
                /* The three-way person we're about to transfer to could still be in MOH, so
                   stop it now */
-               ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
+               ast_queue_unhold(p->subs[SUB_THREEWAY].owner);
                if (ast_channel_state(p->subs[SUB_REAL].owner) == AST_STATE_RINGING) {
                        ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_RINGING);
                }
@@ -7867,7 +7863,7 @@ static int attempt_transfer(struct dahdi_pvt *p)
                ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
                unalloc_sub(p, SUB_THREEWAY);
        } else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
-               ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
+               ast_queue_unhold(p->subs[SUB_REAL].owner);
                if (ast_channel_state(p->subs[SUB_THREEWAY].owner) == AST_STATE_RINGING) {
                        ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_RINGING);
                }
@@ -8535,7 +8531,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                /* Make sure it stops ringing */
                                dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
                                /* Okay -- probably call waiting*/
-                               ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(p->owner);
                                p->subs[idx].needunhold = 1;
                                break;
                        case AST_STATE_RESERVED:
@@ -8690,14 +8686,10 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                p->cid_suppress_expire = 0;
                                /* Start music on hold if appropriate */
                                if (!p->subs[SUB_CALLWAIT].inthreeway) {
-                                       ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
-                                               S_OR(p->mohsuggest, NULL),
-                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                       ast_queue_hold(p->subs[SUB_CALLWAIT].owner, p->mohsuggest);
                                }
                                p->subs[SUB_CALLWAIT].needhold = 1;
-                               ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
-                                       S_OR(p->mohsuggest, NULL),
-                                       !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                               ast_queue_hold(p->subs[SUB_REAL].owner, p->mohsuggest);
                                p->subs[SUB_REAL].needunhold = 1;
                        } else if (!p->subs[SUB_THREEWAY].owner) {
                                if (!p->threewaycalling) {
@@ -8775,9 +8767,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                                ast_verb(3, "Started three way call on channel %d\n", p->channel);
 
                                                /* Start music on hold */
-                                               ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
-                                                       S_OR(p->mohsuggest, NULL),
-                                                       !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                               ast_queue_hold(p->subs[SUB_THREEWAY].owner, p->mohsuggest);
                                                p->subs[SUB_THREEWAY].needhold = 1;
                                        }
                                        ast_callid_threadstorage_auto_clean(callid, callid_created);
@@ -8814,8 +8804,9 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                                        swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                                        otherindex = SUB_REAL;
                                                }
-                                               if (p->subs[otherindex].owner)
-                                                       ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
+                                               if (p->subs[otherindex].owner) {
+                                                       ast_queue_unhold(p->subs[otherindex].owner);
+                                               }
                                                p->subs[otherindex].needunhold = 1;
                                                p->owner = p->subs[SUB_REAL].owner;
                                        } else {
@@ -8823,8 +8814,9 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                                swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                                ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
                                                p->owner = p->subs[SUB_REAL].owner;
-                                               if (p->subs[SUB_REAL].owner)
-                                                       ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
+                                               if (p->subs[SUB_REAL].owner) {
+                                                       ast_queue_unhold(p->subs[SUB_REAL].owner);
+                                               }
                                                p->subs[SUB_REAL].needunhold = 1;
                                                dahdi_enable_ec(p);
                                        }
@@ -9017,8 +9009,9 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
                        (res != DAHDI_EVENT_HOOKCOMPLETE)) {
                        ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
                        p->owner = p->subs[SUB_REAL].owner;
-                       if (p->owner)
-                               ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                       if (p->owner) {
+                               ast_queue_unhold(p->owner);
+                       }
                        p->subs[SUB_REAL].needunhold = 1;
                }
                switch (res) {
@@ -9062,7 +9055,7 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
                                p->callwaitingrepeat = 0;
                                p->cidcwexpire = 0;
                                p->cid_suppress_expire = 0;
-                               ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(p->owner);
                                p->subs[SUB_REAL].needunhold = 1;
                        } else
                                ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
@@ -10699,7 +10692,7 @@ static void *analog_ss_thread(void *data)
                                        swap_subs(p, SUB_REAL, SUB_THREEWAY);
                                        unalloc_sub(p, SUB_THREEWAY);
                                        p->owner = p->subs[SUB_REAL].owner;
-                                       ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
+                                       ast_queue_unhold(p->subs[SUB_REAL].owner);
                                        ast_hangup(chan);
                                        goto quit;
                                } else {
index 2476f50..61817db 100644 (file)
@@ -2096,18 +2096,17 @@ static void setup_rtp_connection(unsigned call_reference, const char *remoteIp,
                                ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS);
                        switch (rtp_change) {
                        case NEED_HOLD:
-                               ast_queue_control(pvt->owner, AST_CONTROL_HOLD);
+                               ast_queue_hold(pvt->owner, NULL);
                                break;
                        case NEED_UNHOLD:
-                               ast_queue_control(pvt->owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(pvt->owner);
                                break;
                        default:
                                break;
                        }
                        ast_channel_unlock(pvt->owner);
                        pvt_native = ast_format_cap_destroy(pvt_native);
-               }
-               else {
+               } else {
                        if (pvt->options.progress_audio)
                                pvt->newcontrol = AST_CONTROL_PROGRESS;
                        else if (rtp_change == NEED_HOLD)
@@ -2599,10 +2598,11 @@ static void remote_hold(unsigned call_reference, const char *token, int is_hold)
        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);
+               if (is_hold) {
+                       ast_queue_hold(pvt->owner, NULL);
+               } else {
+                       ast_queue_unhold(pvt->owner);
+               }
                ast_channel_unlock(pvt->owner);
        }
        else {
index 7f98159..6f1aec0 100644 (file)
@@ -3095,9 +3095,9 @@ static int iax2_queue_frame(int callno, struct ast_frame *f)
 }
 
 /*!
- * \brief Queue a hangup frame on the ast_channel owner
+ * \brief Queue a hold frame on the ast_channel owner
  *
- * This function queues a hangup frame on the owner of the IAX2 pvt struct that
+ * This function queues a hold frame on the owner of the IAX2 pvt struct that
  * is active for the given call number.
  *
  * \pre Assumes lock for callno is already held.
@@ -3107,20 +3107,20 @@ static int iax2_queue_frame(int callno, struct ast_frame *f)
  * This function may unlock and lock the mutex associated with this callno,
  * meaning that another thread may grab it and destroy the call.
  */
-static int iax2_queue_hangup(int callno)
+static int iax2_queue_hold(int callno, const char *musicclass)
 {
        iax2_lock_owner(callno);
        if (iaxs[callno] && iaxs[callno]->owner) {
-               ast_queue_hangup(iaxs[callno]->owner);
+               ast_queue_hold(iaxs[callno]->owner, musicclass);
                ast_channel_unlock(iaxs[callno]->owner);
        }
        return 0;
 }
 
 /*!
- * \brief Queue a control frame on the ast_channel owner
+ * \brief Queue an unhold frame on the ast_channel owner
  *
- * This function queues a control frame on the owner of the IAX2 pvt struct that
+ * This function queues an unhold frame on the owner of the IAX2 pvt struct that
  * is active for the given call number.
  *
  * \pre Assumes lock for callno is already held.
@@ -3130,12 +3130,34 @@ static int iax2_queue_hangup(int callno)
  * This function may unlock and lock the mutex associated with this callno,
  * meaning that another thread may grab it and destroy the call.
  */
-static int iax2_queue_control_data(int callno, 
-       enum ast_control_frame_type control, const void *data, size_t datalen)
+static int iax2_queue_unhold(int callno)
 {
        iax2_lock_owner(callno);
        if (iaxs[callno] && iaxs[callno]->owner) {
-               ast_queue_control_data(iaxs[callno]->owner, control, data, datalen);
+               ast_queue_unhold(iaxs[callno]->owner);
+               ast_channel_unlock(iaxs[callno]->owner);
+       }
+       return 0;
+}
+
+/*!
+ * \brief Queue a hangup frame on the ast_channel owner
+ *
+ * This function queues a hangup frame on the owner of the IAX2 pvt struct that
+ * is active for the given call number.
+ *
+ * \pre Assumes lock for callno is already held.
+ *
+ * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno]
+ * was valid before calling it, it may no longer be valid after calling it.
+ * This function may unlock and lock the mutex associated with this callno,
+ * meaning that another thread may grab it and destroy the call.
+ */
+static int iax2_queue_hangup(int callno)
+{
+       iax2_lock_owner(callno);
+       if (iaxs[callno] && iaxs[callno]->owner) {
+               ast_queue_hangup(iaxs[callno]->owner);
                ast_channel_unlock(iaxs[callno]->owner);
        }
        return 0;
@@ -10302,16 +10324,6 @@ static int socket_process_helper(struct iax2_thread *thread)
                                break;
                        case IAX_COMMAND_QUELCH:
                                if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
-                                       /* Generate Manager Hold event, if necessary*/
-                                       if (iaxs[fr->callno]->owner) {
-                                               ast_manager_event(iaxs[fr->callno]->owner, EVENT_FLAG_CALL, "Hold",
-                                                       "Status: On\r\n"
-                                                       "Channel: %s\r\n"
-                                                       "Uniqueid: %s\r\n",
-                                                       ast_channel_name(iaxs[fr->callno]->owner),
-                                                       ast_channel_uniqueid(iaxs[fr->callno]->owner));
-                                       }
-
                                        ast_set_flag64(iaxs[fr->callno], IAX_QUELCH);
                                        if (ies.musiconhold) {
                                                const char *moh_suggest;
@@ -10326,9 +10338,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                 * need to check iaxs[fr->callno] after it returns.
                                                 */
                                                moh_suggest = iaxs[fr->callno]->mohsuggest;
-                                               iax2_queue_control_data(fr->callno, AST_CONTROL_HOLD,
-                                                       S_OR(moh_suggest, NULL),
-                                                       !ast_strlen_zero(moh_suggest) ? strlen(moh_suggest) + 1 : 0);
+                                               iax2_queue_hold(fr->callno, moh_suggest);
                                                ast_channel_unlock(iaxs[fr->callno]->owner);
                                        }
                                }
@@ -10339,15 +10349,6 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        if (!iaxs[fr->callno]) {
                                                break;
                                        }
-                                       /* Generate Manager Unhold event, if necessary */
-                                       if (iaxs[fr->callno]->owner && ast_test_flag64(iaxs[fr->callno], IAX_QUELCH)) {
-                                               ast_manager_event(iaxs[fr->callno]->owner, EVENT_FLAG_CALL, "Hold",
-                                                       "Status: Off\r\n"
-                                                       "Channel: %s\r\n"
-                                                       "Uniqueid: %s\r\n",
-                                                       ast_channel_name(iaxs[fr->callno]->owner),
-                                                       ast_channel_uniqueid(iaxs[fr->callno]->owner));
-                                       }
 
                                        ast_clear_flag64(iaxs[fr->callno], IAX_QUELCH);
                                        if (!iaxs[fr->callno]->owner) {
@@ -10358,7 +10359,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                         * We already hold the owner lock so we do not
                                         * need to check iaxs[fr->callno] after it returns.
                                         */
-                                       iax2_queue_control_data(fr->callno, AST_CONTROL_UNHOLD, NULL, 0);
+                                       iax2_queue_unhold(fr->callno);
                                        ast_channel_unlock(iaxs[fr->callno]->owner);
                                }
                                break;
index c6b4410..a6c161d 100644 (file)
@@ -3229,7 +3229,7 @@ static int attempt_transfer(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
        enum ast_transfer_result res;
 
        /* Ensure that the other channel goes off hold and that it is indicating properly */
-       ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
+       ast_queue_unhold(sub->next->owner);
        if (ast_channel_state(sub->owner) == AST_STATE_RINGING) {
                ast_queue_control(sub->next->owner, AST_CONTROL_RINGING);
        }
@@ -3275,7 +3275,7 @@ static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
        if (sub->outgoing) {
                /* Answered */
                if (sub->owner) {
-                       ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
+                       ast_queue_unhold(sub->owner);
                        sub->cxmode = MGCP_CX_SENDRECV;
                        if (!sub->rtp) {
                                start_rtp(sub);
@@ -3331,7 +3331,7 @@ static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
                                ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
                                ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
                        }
-                       ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
+                       ast_queue_unhold(sub->owner);
                        sub->cxmode = MGCP_CX_SENDRECV;
                        if (!sub->rtp) {
                                start_rtp(sub);
@@ -3448,8 +3448,9 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                        sub->cxmode = MGCP_CX_MUTE;
                                        ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
                                        transmit_modify_request(sub);
-                                       if (sub->owner)
-                                               ast_queue_control(sub->owner, AST_CONTROL_HOLD);
+                                       if (sub->owner) {
+                                               ast_queue_hold(sub->owner, NULL);
+                                       }
                                        sub->next->cxmode = MGCP_CX_RECVONLY;
                                        handle_hd_hf(sub->next, ev);
                                } else if (sub->owner && sub->next->owner) {
@@ -3460,7 +3461,7 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                                                sub->id, sub->next->id, p->name, p->parent->name);
                                                sub->cxmode = MGCP_CX_CONF;
                                                sub->next->cxmode = MGCP_CX_CONF;
-                                               ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
+                                               ast_queue_unhold(sub->next->owner);
                                                transmit_modify_request(sub);
                                                transmit_modify_request(sub->next);
                                        } else {
@@ -3473,8 +3474,8 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                                ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
                                                transmit_modify_request(sub);
 
-                                               ast_queue_control(sub->owner, AST_CONTROL_HOLD);
-                                               ast_queue_control(sub->next->owner, AST_CONTROL_HOLD);
+                                               ast_queue_hold(sub->owner, NULL);
+                                               ast_queue_hold(sub->next->owner, NULL);
 
                                                handle_hd_hf(sub->next, ev);
                                        }
@@ -3489,7 +3490,7 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                                /* XXX - What do we do now? */
                                                return -1;
                                        }
-                                       ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD);
+                                       ast_queue_unhold(p->sub->owner);
                                        p->sub->cxmode = MGCP_CX_SENDRECV;
                                        transmit_modify_request(p->sub);
                                }
index aaa7170..c68538e 100644 (file)
@@ -10943,7 +10943,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                ch->hold.port = 0;
                ch->hold.channel = 0;
 
-               ast_queue_control(ch->ast, AST_CONTROL_UNHOLD);
+               ast_queue_unhold(ch->ast);
 
                if (misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0) {
                        chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
@@ -10973,7 +10973,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        ch->hold.port = bc->port;
                        ch->hold.channel = bc->channel;
 
-                       ast_queue_control(ch->ast, AST_CONTROL_HOLD);
+                       ast_queue_hold(ch->ast, NULL);
 
                        misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
                } else {
index 56b06b1..a3b8512 100644 (file)
@@ -2481,9 +2481,9 @@ static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct
                        ast_setstate(chan, AST_STATE_RINGING);
                }
        } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
-               ast_queue_control(chan, AST_CONTROL_HOLD);
+               ast_queue_hold(chan, NULL);
        } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
-               ast_queue_control(chan, AST_CONTROL_UNHOLD);
+               ast_queue_unhold(chan);
        }
 
        ast_channel_unlock(chan);
index 77cd9c2..987a973 100644 (file)
@@ -9879,16 +9879,9 @@ static int find_sdp(struct sip_request *req)
 /*! \brief Change hold state for a call */
 static void change_hold_state(struct sip_pvt *dialog, struct sip_request *req, int holdstate, int sendonly)
 {
-       if (sip_cfg.notifyhold && (!holdstate || !ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD)))
+       if (sip_cfg.notifyhold && (!holdstate || !ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD))) {
                sip_peer_hold(dialog, holdstate);
-       if (sip_cfg.callevents)
-               manager_event(EVENT_FLAG_CALL, "Hold",
-                             "Status: %s\r\n"
-                             "Channel: %s\r\n"
-                             "Uniqueid: %s\r\n",
-                             holdstate ? "On" : "Off",
-                             ast_channel_name(dialog->owner),
-                             ast_channel_uniqueid(dialog->owner));
+       }
        append_history(dialog, holdstate ? "Hold" : "Unhold", "%s", ast_str_buffer(req->data));
        if (!holdstate) {       /* Put off remote hold */
                ast_clear_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD);       /* Clear both flags */
@@ -10795,16 +10788,14 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 
        if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && (!ast_sockaddr_isnull(sa) || !ast_sockaddr_isnull(vsa) || !ast_sockaddr_isnull(tsa) || !ast_sockaddr_isnull(isa)) && (!sendonly || sendonly == -1)) {
                if (!ast_test_flag(&p->flags[2], SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL)) {
-                       ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                       ast_queue_unhold(p->owner);
                }
                /* Activate a re-invite */
                ast_queue_frame(p->owner, &ast_null_frame);
                change_hold_state(p, req, FALSE, sendonly);
        } else if ((sockaddr_is_null_or_any(sa) && sockaddr_is_null_or_any(vsa) && sockaddr_is_null_or_any(tsa) && sockaddr_is_null_or_any(isa)) || (sendonly && sendonly != -1)) {
                if (!ast_test_flag(&p->flags[2], SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL)) {
-                       ast_queue_control_data(p->owner, AST_CONTROL_HOLD,
-                                      S_OR(p->mohsuggest, NULL),
-                                      !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                       ast_queue_hold(p->owner, p->mohsuggest);
                }
                if (sendonly)
                        ast_rtp_instance_stop(p->rtp);
@@ -25440,7 +25431,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
                                   *without* an SDP, which is supposed to mean "Go back to your state"
                                   and since they put os on remote hold, we go back to off hold */
                                if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) {
-                                       ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                                       ast_queue_unhold(p->owner);
                                        /* Activate a re-invite */
                                        ast_queue_frame(p->owner, &ast_null_frame);
                                        change_hold_state(p, req, FALSE, 0);
@@ -26703,7 +26694,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
                                bridged_to = ast_bridged_channel(c);
                                if (bridged_to) {
                                        /* Don't actually hangup here... */
-                                       ast_queue_control(c, AST_CONTROL_UNHOLD);
+                                       ast_queue_unhold(c);
                                        ast_channel_unlock(c);  /* async_goto can do a masquerade, no locks can be held during a masq */
                                        ast_async_goto(bridged_to, p->context, p->refer->refer_to, 1);
                                        ast_channel_lock(c);
index f139804..89339fc 100644 (file)
@@ -5263,7 +5263,7 @@ static int skinny_transfer(struct skinny_subchannel *sub)
                        ast_channel_name(xferor->owner), ast_bridged_channel(xferor->owner) ? ast_channel_name(ast_bridged_channel(xferor->owner)) : "");
 
                if (ast_bridged_channel(xferor->owner)) {
-                       ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
+                       ast_queue_unhold(xferee->owner);
                        if (ast_channel_state(xferor->owner) == AST_STATE_RING) {
                                /* play ringing inband */
                                if ((ts = ast_get_indication_tone(ast_channel_zone(xferor->owner), "ring"))) {
@@ -5279,7 +5279,7 @@ static int skinny_transfer(struct skinny_subchannel *sub)
                                return -1;
                        }
                } else if (ast_bridged_channel(xferee->owner)) {
-                       ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
+                       ast_queue_unhold(xferee->owner);
                        if (ast_channel_state(xferor->owner) == AST_STATE_RING) {
                                /* play ringing inband */
                                if ((ts = ast_get_indication_tone(ast_channel_zone(xferor->owner), "ring"))) {
@@ -5690,9 +5690,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 
                        sub->substate = SUBSTATE_HOLD;
 
-                       ast_queue_control_data(sub->owner, AST_CONTROL_HOLD,
-                               S_OR(l->mohsuggest, NULL),
-                               !ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
+                       ast_queue_hold(sub->owner, l->mohsuggest);
 
                        return;
                default:
@@ -5874,7 +5872,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
                        transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
                }
                if (sub->substate == SUBSTATE_HOLD) {
-                       ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
+                       ast_queue_unhold(sub->owner);
                        transmit_connect(d, sub);
                }
                transmit_ringer_mode(d, SKINNY_RING_OFF);
@@ -5952,9 +5950,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
                        ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_HOLD from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
                        return;
                }
-               ast_queue_control_data(sub->owner, AST_CONTROL_HOLD,
-                       S_OR(l->mohsuggest, NULL),
-                       !ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
+               ast_queue_hold(sub->owner, l->mohsuggest);
 
                transmit_activatecallplane(d, l);
                transmit_closereceivechannel(d, sub);
index 42a71ba..426e6ab 100644 (file)
@@ -2453,7 +2453,7 @@ static void sub_hold(struct unistimsession *pte, struct unistim_subchannel *sub)
        send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
        send_stop_timer(pte);
        if (sub->owner) {
-               ast_queue_control_data(sub->owner, AST_CONTROL_HOLD, NULL, 0);
+               ast_queue_hold(sub->owner, NULL);
                send_end_call(pte);
        }
        return;
@@ -2474,7 +2474,7 @@ static void sub_unhold(struct unistimsession *pte, struct unistim_subchannel *su
        send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
        send_start_timer(pte);
        if (sub->owner) {
-               ast_queue_control_data(sub->owner, AST_CONTROL_UNHOLD, NULL, 0);
+               ast_queue_unhold(sub->owner);
                if (sub->rtp) {
                        send_start_rtp(sub);
                }
@@ -2961,8 +2961,7 @@ static void transfer_call_step1(struct unistimsession *pte)
        if (sub->moh) {
                ast_log(LOG_WARNING, "Transfer with peer already listening music on hold\n");
        } else {
-               ast_queue_control_data(sub->owner, AST_CONTROL_HOLD,
-                       sub->parent->musicclass, strlen(sub->parent->musicclass) + 1);
+               ast_queue_hold(sub->owner, sub->parent->musicclass);
                sub->moh = 1;
                sub->subtype = SUB_THREEWAY;
        }
@@ -2988,7 +2987,7 @@ static void transfer_cancel_step2(struct unistimsession *pte)
                }
                if (sub->owner) {
                        swap_subs(sub, sub_trans);
-                       ast_queue_control(sub_trans->owner, AST_CONTROL_UNHOLD);
+                       ast_queue_unhold(sub_trans->owner);
                        sub_trans->moh = 0;
                        sub_trans->subtype = SUB_REAL;
                        sub->subtype = SUB_THREEWAY;
@@ -3498,7 +3497,7 @@ static void key_dial_page(struct unistimsession *pte, char keycode)
                if (sub && sub->owner) {
                        sub_stop_silence(pte, sub);
                        send_tone(pte, 0, 0);
-                       ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
+                       ast_queue_unhold(sub->owner);
                        sub->moh = 0;
                        sub->subtype = SUB_REAL;
                        pte->state = STATE_CALL;
@@ -4789,7 +4788,7 @@ static int unistim_hangup(struct ast_channel *ast)
                if (unistimdebug) {
                        ast_verb(0, "Threeway call disconnected, switching to real call\n");
                }
-               ast_queue_control(sub_trans->owner, AST_CONTROL_UNHOLD);
+               ast_queue_unhold(sub_trans->owner);
                sub_trans->moh = 0;
                sub_trans->subtype = SUB_REAL;
                swap_subs(sub_trans, sub);
index 7d34390..e3bd1d0 100644 (file)
@@ -1354,7 +1354,7 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
                                if (ast_channel_state(p->owner) != AST_STATE_UP) {
                                        ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_ANSWER);
                                }
-                               ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(p->subs[ANALOG_SUB_REAL].owner);
                                /* Unlock the call-waiting call that we swapped to real-call. */
                                ast_channel_unlock(p->subs[ANALOG_SUB_REAL].owner);
                        } else if (p->subs[ANALOG_SUB_THREEWAY].allocd) {
@@ -1382,9 +1382,7 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
                                /* This is actually part of a three way, placed on hold.  Place the third part
                                   on music on hold now */
                                if (p->subs[ANALOG_SUB_THREEWAY].owner) {
-                                       ast_queue_control_data(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_HOLD,
-                                               S_OR(p->mohsuggest, NULL),
-                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                       ast_queue_hold(p->subs[ANALOG_SUB_THREEWAY].owner, p->mohsuggest);
                                }
                                analog_set_inthreeway(p, ANALOG_SUB_THREEWAY, 0);
                                /* Make it the call wait now */
@@ -1406,9 +1404,7 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
                                   Start music on hold for them, and take the main guy out of the third call */
                                analog_set_inthreeway(p, ANALOG_SUB_CALLWAIT, 0);
                                if (p->subs[ANALOG_SUB_CALLWAIT].owner) {
-                                       ast_queue_control_data(p->subs[ANALOG_SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
-                                               S_OR(p->mohsuggest, NULL),
-                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                       ast_queue_hold(p->subs[ANALOG_SUB_CALLWAIT].owner, p->mohsuggest);
                                }
                        }
                        if (p->subs[ANALOG_SUB_CALLWAIT].owner) {
@@ -2323,7 +2319,7 @@ static void *__analog_ss_thread(void *data)
                                        analog_swap_subs(p, ANALOG_SUB_REAL, ANALOG_SUB_THREEWAY);
                                        analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
                                        analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
-                                       ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
+                                       ast_queue_unhold(p->subs[ANALOG_SUB_REAL].owner);
                                        ast_hangup(chan);
                                        goto quit;
                                } else {
@@ -3024,7 +3020,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                                /* Make sure it stops ringing */
                                analog_off_hook(p);
                                /* Okay -- probably call waiting */
-                               ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(p->owner);
                                break;
                        case AST_STATE_RESERVED:
                                /* Start up dialtone */
@@ -3183,14 +3179,10 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 
                                /* Start music on hold if appropriate */
                                if (!p->subs[ANALOG_SUB_CALLWAIT].inthreeway) {
-                                       ast_queue_control_data(p->subs[ANALOG_SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
-                                               S_OR(p->mohsuggest, NULL),
-                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                       ast_queue_hold(p->subs[ANALOG_SUB_CALLWAIT].owner, p->mohsuggest);
                                }
-                               ast_queue_control_data(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_HOLD,
-                                       S_OR(p->mohsuggest, NULL),
-                                       !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
-                               ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
+                               ast_queue_hold(p->subs[ANALOG_SUB_REAL].owner, p->mohsuggest);
+                               ast_queue_unhold(p->subs[ANALOG_SUB_REAL].owner);
 
                                /* Unlock the call-waiting call that we swapped to real-call. */
                                ast_channel_unlock(p->subs[ANALOG_SUB_REAL].owner);
@@ -3282,9 +3274,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                                                ast_verb(3, "Started three way call on channel %d\n", p->channel);
 
                                                /* Start music on hold */
-                                               ast_queue_control_data(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_HOLD,
-                                                       S_OR(p->mohsuggest, NULL),
-                                                       !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                               ast_queue_hold(p->subs[ANALOG_SUB_THREEWAY].owner, p->mohsuggest);
                                        }
                                        ast_callid_threadstorage_auto_clean(callid, callid_created);
                                }
@@ -3334,7 +3324,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                                                        analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
                                                        orig_3way_sub = ANALOG_SUB_REAL;
                                                }
-                                               ast_queue_control(p->subs[orig_3way_sub].owner, AST_CONTROL_UNHOLD);
+                                               ast_queue_unhold(p->subs[orig_3way_sub].owner);
                                                analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
                                        } else {
                                                ast_verb(3, "Dumping incomplete call on %s\n", ast_channel_name(p->subs[ANALOG_SUB_THREEWAY].owner));
@@ -3342,7 +3332,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                                                orig_3way_sub = ANALOG_SUB_REAL;
                                                ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
                                                analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
-                                               ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
+                                               ast_queue_unhold(p->subs[ANALOG_SUB_REAL].owner);
                                                analog_set_echocanceller(p, 1);
                                        }
                                }
@@ -3585,7 +3575,7 @@ struct ast_frame *analog_exception(struct analog_pvt *p, struct ast_channel *ast
                                        analog_event2str(res), ast_channel_name(ast), ast_channel_name(p->owner));
                        }
                        if (p->owner) {
-                               ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(p->owner);
                        }
                }
                switch (res) {
@@ -3624,7 +3614,7 @@ struct ast_frame *analog_exception(struct analog_pvt *p, struct ast_channel *ast
                                        ast_setstate(p->owner, AST_STATE_UP);
                                }
                                analog_stop_callwait(p);
-                               ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(p->owner);
                        } else {
                                ast_log(LOG_WARNING, "Absorbed %s, but nobody is left!?!?\n",
                                        analog_event2str(res));
index db0c920..461ea51 100644 (file)
@@ -1247,6 +1247,50 @@ static void pri_queue_frame(struct sig_pri_span *pri, int chanpos, struct ast_fr
 
 /*!
  * \internal
+ * \brief Queue a hold frame onto the owner channel.
+ * \since 12
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_queue_hold(struct sig_pri_span *pri, int chanpos)
+{
+       sig_pri_lock_owner(pri, chanpos);
+       if (pri->pvts[chanpos]->owner) {
+               ast_queue_hold(pri->pvts[chanpos]->owner, NULL);
+               ast_channel_unlock(pri->pvts[chanpos]->owner);
+       }
+}
+
+/*!
+ * \internal
+ * \brief Queue an unhold frame onto the owner channel.
+ * \since 12
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_queue_unhold(struct sig_pri_span *pri, int chanpos)
+{
+       sig_pri_lock_owner(pri, chanpos);
+       if (pri->pvts[chanpos]->owner) {
+               ast_queue_unhold(pri->pvts[chanpos]->owner);
+               ast_channel_unlock(pri->pvts[chanpos]->owner);
+       }
+}
+
+/*!
+ * \internal
  * \brief Queue a control frame of the specified subclass onto the owner channel.
  * \since 1.8
  *
@@ -5177,42 +5221,6 @@ static void sig_pri_moh_fsm_event(struct ast_channel *chan, struct sig_pri_chan
                (orig_state == next_state) ? "$" : sig_pri_moh_state_str(next_state));
 }
 
-#if defined(HAVE_PRI_CALL_HOLD)
-/*!
- * \internal
- * \brief Post an AMI hold event.
- * \since 10.0
- *
- * \param chan Channel to post event to
- * \param is_held TRUE if the call was placed on hold.
- *
- * \return Nothing
- */
-static void sig_pri_ami_hold_event(struct ast_channel *chan, int is_held)
-{
-       /*** DOCUMENTATION
-               <managerEventInstance>
-                       <synopsis>Raised when a PRI channel is put on Hold.</synopsis>
-                       <syntax>
-                               <parameter name="Status">
-                                       <enumlist>
-                                               <enum name="On"/>
-                                               <enum name="Off"/>
-                                       </enumlist>
-                               </parameter>
-                       </syntax>
-               </managerEventInstance>
-       ***/
-       ast_manager_event(chan, EVENT_FLAG_CALL, "Hold",
-               "Status: %s\r\n"
-               "Channel: %s\r\n"
-               "Uniqueid: %s\r\n",
-               is_held ? "On" : "Off",
-               ast_channel_name(chan),
-               ast_channel_uniqueid(chan));
-}
-#endif /* defined(HAVE_PRI_CALL_HOLD) */
-
 /*!
  * \internal
  * \brief Set callid threadstorage for the pri_dchannel thread when a new call is created
@@ -5327,13 +5335,11 @@ static int sig_pri_handle_hold(struct sig_pri_span *pri, pri_event *ev)
                goto done_with_owner;
        }
        sig_pri_handle_subcmds(pri, chanpos_old, ev->e, ev->hold.subcmds, ev->hold.call);
-       pri_queue_control(pri, chanpos_old, AST_CONTROL_HOLD);
+       sig_pri_queue_hold(pri, chanpos_old);
        chanpos_new = pri_fixup_principle(pri, chanpos_new, ev->hold.call);
        if (chanpos_new < 0) {
                /* Should never happen. */
-               pri_queue_control(pri, chanpos_old, AST_CONTROL_UNHOLD);
-       } else {
-               sig_pri_ami_hold_event(owner, 1);
+               sig_pri_queue_unhold(pri, chanpos_old);
        }
 
 done_with_owner:;
@@ -5521,12 +5527,7 @@ static void sig_pri_handle_retrieve(struct sig_pri_span *pri, pri_event *ev)
        sig_pri_lock_private(pri->pvts[chanpos]);
        callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
        sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->retrieve.subcmds, ev->retrieve.call);
-       sig_pri_lock_owner(pri, chanpos);
-       pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
-       if (pri->pvts[chanpos]->owner) {
-               sig_pri_ami_hold_event(pri->pvts[chanpos]->owner, 0);
-               ast_channel_unlock(pri->pvts[chanpos]->owner);
-       }
+       sig_pri_queue_unhold(pri, chanpos);
        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],
@@ -7428,12 +7429,12 @@ static void *pri_dchannel(void *vpri)
                                switch (e->notify.info) {
                                case PRI_NOTIFY_REMOTE_HOLD:
                                        if (!pri->discardremoteholdretrieval) {
-                                               pri_queue_control(pri, chanpos, AST_CONTROL_HOLD);
+                                               sig_pri_queue_hold(pri, chanpos);
                                        }
                                        break;
                                case PRI_NOTIFY_REMOTE_RETRIEVAL:
                                        if (!pri->discardremoteholdretrieval) {
-                                               pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
+                                               sig_pri_queue_unhold(pri, chanpos);
                                        }
                                        break;
                                }
index b27183e..efd1ac8 100644 (file)
@@ -1203,6 +1203,31 @@ int ast_queue_hangup(struct ast_channel *chan);
 int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause);
 
 /*!
+ * \brief Queue a hold frame
+ *
+ * \param chan channel to queue frame onto
+ * \param musicclass The suggested musicclass for the other end to use
+ *
+ * \note The channel does not need to be locked before calling this function.
+ *
+ * \retval zero on success
+ * \retval non-zero on failure
+ */
+int ast_queue_hold(struct ast_channel *chan, const char *musicclass);
+
+/*!
+ * \brief Queue an unhold frame
+ *
+ * \param chan channel to queue frame onto
+ *
+ * \note The channel does not need to be locked before calling this function.
+ *
+ * \retval zero on success
+ * \retval non-zero on failure
+ */
+int ast_queue_unhold(struct ast_channel *chan);
+
+/*!
  * \brief Queue a control frame without payload
  *
  * \param chan channel to queue frame onto
index 7c214d5..42e50eb 100644 (file)
@@ -341,6 +341,22 @@ struct stasis_message_type *ast_channel_dtmf_end_type(void);
 
 /*!
  * \since 12
+ * \brief Message type for when a channel is placed on hold.
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_channel_hold_type(void);
+
+/*!
+ * \since 12
+ * \brief Message type for when a channel is removed from hold.
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_channel_unhold_type(void);
+
+/*!
+ * \since 12
  * \brief Message type for when a channel starts spying on another channel
  *
  * \retval A stasis message type
index aec43ed..f7aa0bf 100644 (file)
@@ -1353,9 +1353,11 @@ static void publish_channel_blob(struct ast_channel *chan,
        struct stasis_message_type *type, struct ast_json *blob)
 {
        RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-       if (blob) {
-               message = ast_channel_blob_create(chan, type, blob);
+       if (!blob) {
+               blob = ast_json_null();
        }
+
+       message = ast_channel_blob_create(chan, type, blob);
        if (message) {
                stasis_publish(ast_channel_topic(chan), message);
        }
@@ -1405,6 +1407,39 @@ int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause)
        return res;
 }
 
+int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
+{
+       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+       RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+       struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HOLD };
+       int res;
+
+       if (!ast_strlen_zero(musicclass)) {
+               f.data.ptr = (void *) musicclass;
+               f.datalen = strlen(musicclass) + 1;
+
+               blob = ast_json_pack("{s: s}",
+                                    "musicclass", musicclass);
+       }
+
+       publish_channel_blob(chan, ast_channel_hold_type(), blob);
+
+       res = ast_queue_frame(chan, &f);
+       return res;
+}
+
+int ast_queue_unhold(struct ast_channel *chan)
+{
+       RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+       struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_UNHOLD };
+       int res;
+
+       publish_channel_blob(chan, ast_channel_unhold_type(), NULL);
+
+       res = ast_queue_frame(chan, &f);
+       return res;
+}
+
 /*! \brief Queue a control frame */
 int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
 {
@@ -6694,7 +6729,7 @@ static void masquerade_colp_transfer(struct ast_channel *transferee, struct xfer
 
        /* Release any hold on the target. */
        if (colp->target_held) {
-               ast_queue_control(transferee, AST_CONTROL_UNHOLD);
+               ast_queue_unhold(transferee);
        }
 
        /*
index f3c72ec..a66080c 100644 (file)
@@ -228,6 +228,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        </see-also>
                </managerEventInstance>
        </managerEvent>
+       <managerEvent language="en_US" name="Hold">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised when a channel goes on hold.</synopsis>
+                       <syntax>
+                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <parameter name="MusicClass">
+                                       <para>The suggested MusicClass, if provided.</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="Unhold">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised when a channel goes off hold.</synopsis>
+                       <syntax>
+                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
        <managerEvent language="en_US" name="ChanSpyStart">
                <managerEventInstance class="EVENT_FLAG_CALL">
                        <synopsis>Raised when one channel begins spying on another channel.</synopsis>
@@ -1180,6 +1199,48 @@ static void channel_dial_cb(void *data, struct stasis_subscription *sub,
 
 }
 
+static void channel_hold_cb(void *data, struct stasis_subscription *sub,
+       struct stasis_topic *topic, struct stasis_message *message)
+{
+       struct ast_channel_blob *obj = stasis_message_data(message);
+       const char *musicclass;
+       RAII_VAR(struct ast_str *, musicclass_string, NULL, ast_free);
+       RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+
+       if (!(musicclass_string = ast_str_create(32))) {
+               return;
+       }
+
+       channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
+
+       if (obj->blob) {
+               musicclass = ast_json_string_get(ast_json_object_get(obj->blob, "musicclass"));
+
+               if (!ast_strlen_zero(musicclass)) {
+                       ast_str_set(&musicclass_string, 0, "MusicClass: %s\r\n", musicclass);
+               }
+       }
+
+       manager_event(EVENT_FLAG_CALL, "Hold",
+               "%s"
+               "%s",
+               ast_str_buffer(channel_event_string),
+               ast_str_buffer(musicclass_string));
+}
+
+static void channel_unhold_cb(void *data, struct stasis_subscription *sub,
+       struct stasis_topic *topic, struct stasis_message *message)
+{
+       struct ast_channel_blob *obj = stasis_message_data(message);
+       RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+
+       channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
+
+       manager_event(EVENT_FLAG_CALL, "Unhold",
+               "%s",
+               ast_str_buffer(channel_event_string));
+}
+
 static void manager_channels_shutdown(void)
 {
        stasis_unsubscribe(topic_forwarder);
@@ -1249,6 +1310,16 @@ int manager_channels_init(void)
                                         NULL);
 
        ret |= stasis_message_router_add(message_router,
+                                        ast_channel_hold_type(),
+                                        channel_hold_cb,
+                                        NULL);
+
+       ret |= stasis_message_router_add(message_router,
+                                        ast_channel_unhold_type(),
+                                        channel_unhold_cb,
+                                        NULL);
+
+       ret |= stasis_message_router_add(message_router,
                                         ast_channel_fax_type(),
                                         channel_fax_cb,
                                         NULL);
index d3c543a..249576b 100644 (file)
@@ -48,6 +48,8 @@ STASIS_MESSAGE_TYPE_DEFN(ast_channel_user_event_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_begin_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type);
@@ -585,6 +587,8 @@ void ast_stasis_channels_shutdown(void)
        STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_request_type);
        STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_begin_type);
        STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_end_type);
+       STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hold_type);
+       STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_unhold_type);
        STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_start_type);
        STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_stop_type);
        STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_fax_type);
@@ -604,6 +608,8 @@ void ast_stasis_channels_init(void)
        STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_request_type);
        STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_begin_type);
        STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_end_type);
+       STASIS_MESSAGE_TYPE_INIT(ast_channel_hold_type);
+       STASIS_MESSAGE_TYPE_INIT(ast_channel_unhold_type);
        STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_start_type);
        STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_stop_type);
        STASIS_MESSAGE_TYPE_INIT(ast_channel_fax_type);
@@ -612,6 +618,7 @@ void ast_stasis_channels_init(void)
        STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_stop_type);
        STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_start_type);
        STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_stop_type);
+
        channel_topic_all = stasis_topic_create("ast_channel_topic_all");
        channel_topic_all_cached = stasis_caching_topic_create(channel_topic_all, channel_snapshot_get_id);
 }
index bd5be08..b0c8ae3 100644 (file)
@@ -698,15 +698,14 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a
            (!ast_sockaddr_isnull(addrs) ||
             !pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL))) {
                /* The remote side has taken us off hold */
-               ast_queue_control(session->channel, AST_CONTROL_UNHOLD);
+               ast_queue_unhold(session->channel);
                ast_queue_frame(session->channel, &ast_null_frame);
                session_media->held = 0;
        } else if (ast_sockaddr_isnull(addrs) ||
                   ast_sockaddr_is_any(addrs) ||
                   pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
                /* The remote side has put us on hold */
-               ast_queue_control_data(session->channel, AST_CONTROL_HOLD, S_OR(session->endpoint->mohsuggest, NULL),
-                                      !ast_strlen_zero(session->endpoint->mohsuggest) ? strlen(session->endpoint->mohsuggest) + 1 : 0);
+               ast_queue_hold(session->channel, session->endpoint->mohsuggest);
                ast_rtp_instance_stop(session_media->rtp);
                ast_queue_frame(session->channel, &ast_null_frame);
                session_media->held = 1;