diff --git a/src/channels/chan_voicemngr.c b/src/channels/chan_voicemngr.c index ac9212600eeaaccb15a37149627f68a89b926a60..f161446e8a1f0470666bc2f2c347d57cdfa533b6 100644 --- a/src/channels/chan_voicemngr.c +++ b/src/channels/chan_voicemngr.c @@ -2121,6 +2121,62 @@ static int setup_conference_call_cb( const void *data) return 0; } +/*Switch back to held call once timer expires */ +static int switch_back_call_cb( const void *data) +{ + struct chan_voicemngr_subchannel *sub_peer, *sub; + struct ast_channel *peer_owner, *owner; + + ast_log(LOG_NOTICE ,"Switch back to held call\n"); + sub = (struct chan_voicemngr_subchannel *) data; + + pvt_lock(sub->parent, "switch_back_call_cb"); + sub_peer = chan_voicemngr_subchannel_get_peer(sub); + if (!sub || !sub_peer) { + ast_debug(3, "sub-channels are not found\n"); + pvt_unlock(sub->parent); + return 0; + } + if (sub->owner) { + ast_channel_ref(sub->owner); + owner = sub->owner; + } + if (sub_peer->owner) { + ast_channel_ref(sub_peer->owner); + peer_owner = sub_peer->owner; + } + sub->parent->hf_detected = 0; + chan_voicemngr_reset_dtmf_buffer(sub->parent); + chan_voicemngr_stop_dialtone(sub->parent); + + pvt_unlock(sub->parent); + + /* Reset timer*/ + sub->conf_timer_id = -1; + + /* Hang up current */ + sub->channel_state = ONHOOK; + if (owner) { + ast_channel_lock(owner); + ast_queue_control(owner, AST_CONTROL_HANGUP); + ast_channel_unlock(owner); + ast_channel_unref(owner); + } + + /* Pick up old */ + if (peer_owner) { + ast_channel_lock(peer_owner); + chan_voicemngr_unmute_connection(sub_peer); + ast_queue_unhold(peer_owner); + sub_peer->channel_state = INCALL; + ast_channel_unlock(peer_owner); + ast_channel_unref(peer_owner); + chan_voicemngr_send_ubus_event("CALL_UNHOLD",sub->parent->line_id); + } + + return 0; +} + /* Hangup incoming call after call waiting times out */ static int cwtimeout_cb(const void *data) { @@ -2887,8 +2943,7 @@ static void handle_hookflash(struct chan_voicemngr_subchannel *sub, struct chan_ } } else if (sub->channel_state == RINGBACK && sub_peer->channel_state == ONHOLD) { ast_debug(4, "R during ringback\n"); - sub->channel_state = INCALL; - sub->conf_timer_id = ast_sched_add(sched, dtmf_wait_timer, setup_conference_call_cb, p); + sub->conf_timer_id = ast_sched_add(sched, dtmf_wait_timer, switch_back_call_cb, sub); } if (channel_config[p->line_id].flashSpec == FLASH_SPEC_UK) @@ -2990,7 +3045,7 @@ static void handle_dtmf(enum LINE_EVENT event, if (p->hf_detected) { ast_debug(2, "DTMF after HF\n"); p->hf_detected = 0; - if (sub->channel_state == INCALL && + if ((sub->channel_state == INCALL || sub->channel_state == RINGBACK)&& (chan_voicemngr_in_callwaiting(p) || chan_voicemngr_in_onhold(p) || chan_voicemngr_in_conference(p))) { handle_hookflash(sub, sub_peer, owner, peer_owner); } else { @@ -5501,18 +5556,18 @@ static void chan_voicemngr_unattended_call_transfer(struct chan_voicemngr_subcha { struct chan_voicemngr_pvt *p = sub->parent; - ast_log(LOG_ERROR ,"flashSpec sub_peer->conf_timer_id: %d, sub->conf_timer_id: %d\n", sub_peer->conf_timer_id, sub->conf_timer_id); + ast_log(LOG_NOTICE ,"flashSpec sub_peer->conf_timer_id: %d, sub->conf_timer_id: %d\n", sub_peer->conf_timer_id, sub->conf_timer_id); if((sub_peer->conf_timer_id != -1) || (sub->conf_timer_id != -1)) { ast_log(LOG_NOTICE ,"Setting up unattended call transfer \n"); if(sub->conf_timer_id != -1) { if (ast_sched_del(sched, sub->conf_timer_id)) - ast_log(LOG_ERROR, "Failed to remove scheduled conference setup timer\n"); + ast_log(LOG_ERROR, "Failed to remove scheduled switch_back_call_cb timer\n"); ast_debug(4, "sub->conf_timer_id deleted\n"); } sub->conf_timer_id = -1; if(sub_peer->conf_timer_id != -1) { if (ast_sched_del(sched, sub_peer->conf_timer_id)) - ast_log(LOG_ERROR, "Failed to remove scheduled conference setup timer\n"); + ast_log(LOG_ERROR, "Failed to remove scheduled switch_back_call_cb timer\n"); ast_debug(4, "sub_peer->conf_timer_id deleted\n"); } sub_peer->conf_timer_id = -1;