diff --git a/channels/chan_brcm.c b/channels/chan_brcm.c index e41a905df5eacbe2164465b68f51845ab65eae2a..abeb330f9c3c70158de1fb9e630898e63e556ccb 100644 --- a/channels/chan_brcm.c +++ b/channels/chan_brcm.c @@ -469,7 +469,6 @@ static int brcm_send_ubus_event(char *ev_name, int line) } blobmsg_add_string(&blob, "event", ev_name); - blobmsg_add_u32(&blob, "data", 0); blobmsg_add_u32(&blob, "line", line); if (ubus_send_event(ubusctx, broadcast_path, blob.head) != UBUS_STATUS_OK) { @@ -888,9 +887,9 @@ static int brcm_hangup(struct ast_channel *ast) { struct brcm_pvt *p; struct brcm_subchannel *sub, *sub_peer; - struct ast_channel *peer_owner; + struct ast_channel *peer_owner; sub = ast_channel_tech_pvt(ast); - int conf_timer_removed = 0; + int conf_timer_removed = 0; if (!ast_channel_tech_pvt(ast)) { ast_log(LOG_WARNING, "Asked to hangup channel not connected\n"); @@ -968,34 +967,32 @@ static int brcm_hangup(struct ast_channel *ast) * isn't called again when going on-hook */ if(p->dialtone != DIALTONE_HOWLER && sub->channel_state != ONHOOK) { - ast_debug(6, "Setting channel state to %s\n", state2str(sub->channel_state)); - /*In case the call ends before connecting ,move the party to ONHOOK state Since its already on ONHOOK , - we never get on ONHOOK event again*/ - if (sub->channel_state == RINGING) - sub->channel_state = ONHOOK; - else - sub->channel_state = CALLENDED; + ast_debug(6, "Setting channel state to %s\n", state2str(sub->channel_state)); + /*In case the call ends before connecting ,move the party to ONHOOK state Since its already on ONHOOK , + we never get on ONHOOK event again*/ + if (sub->channel_state == RINGING) + sub->channel_state = ONHOOK; + else + sub->channel_state = CALLENDED; } - brcm_send_ubus_event("HANGUP",p->line_id); - if ( sub->conference_initiator && brcm_in_conference(p)) { /* Switch still active call leg out of conference mode */ brcm_stop_conference(sub); brcm_stop_conference(sub_peer); } - if(sub_peer->channel_state == INCALL && conf_timer_removed== 1) { - ast_log(LOG_NOTICE,"In case some party hangs up ,Unhold the other parties \n"); - pvt_lock(sub_peer->parent, "Brcm Hangup"); - if(sub_peer->owner) - ast_channel_ref(sub_peer->owner); - peer_owner = sub_peer->owner; - pvt_unlock(sub_peer->parent); - brcm_unmute_connection(sub_peer); - ast_queue_unhold(peer_owner); - sub_peer->channel_state = INCALL; - } + if(sub_peer->channel_state == INCALL && conf_timer_removed== 1) { + ast_log(LOG_NOTICE,"In case some party hangs up ,Unhold the other parties \n"); + pvt_lock(sub_peer->parent, "Brcm Hangup"); + if(sub_peer->owner) + ast_channel_ref(sub_peer->owner); + peer_owner = sub_peer->owner; + pvt_unlock(sub_peer->parent); + brcm_unmute_connection(sub_peer); + ast_queue_unhold(peer_owner); + sub_peer->channel_state = INCALL; + } memset(p->ext, 0, sizeof(p->ext)); sub->owner = NULL; @@ -1807,15 +1804,15 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel struct ast_channel *owner, struct ast_channel *peer_owner) { struct brcm_pvt *p = sub->parent; + struct ast_bridge *bridge; + struct ast_bridge_channel *bridge_channel; ast_log(LOG_NOTICE, "Hook Flash detected for phone line %d\r\n", sub->parent->line_id); - struct ast_bridge *bridge; - struct ast_bridge_channel *bridge_channel; if (owner) { bridge = ast_channel_internal_bridge(owner); } - else if (peer_owner) { + else if (peer_owner) { bridge = ast_channel_internal_bridge(peer_owner); } else { p->hf_detected = 0; @@ -1823,12 +1820,13 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel } if (sub->channel_state == INCALL){ - if (bridge && bridge->num_active > max_sessions_per_line) { - ast_log(LOG_WARNING, "Max call limit exceeded\n"); - p->hf_detected = 0; - return; - } + if (bridge && bridge->num_active > max_sessions_per_line) { + ast_log(LOG_WARNING, "Max call limit exceeded\n"); + p->hf_detected = 0; + return; + } } + if (p->dtmf_first < 0) { /* If current subchannel is in call and peer subchannel is idle, provide dialtone */ if (sub->channel_state == INCALL && (sub_peer->channel_state == ONHOOK || sub_peer->channel_state == CALLENDED)) { @@ -1847,7 +1845,6 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel } brcm_send_ubus_event("CALL_HOLD",p->line_id); - brcm_mute_connection(sub); sub->channel_state = ONHOLD; ast_queue_hold(owner, NULL); @@ -1857,7 +1854,6 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel p->dialtone = DIALTONE_ON; brcm_signal_dialtone(p); sub_peer->channel_state = OFFHOOK; - /* If offhook/dialing/calling and peer subchannel is on hold, switch call */ } else if ((sub->channel_state == DIALING || sub->channel_state == OFFHOOK || @@ -1886,7 +1882,7 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel if(bridge){ AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { ast_indicate(bridge_channel->chan, AST_CONTROL_UNHOLD); - ast_log(LOG_NOTICE,"blogs : pick up old unhold \n"); + ast_log(LOG_NOTICE,"Pick up old unhold\n"); } } brcm_send_ubus_event("CALL_UNHOLD",p->line_id); @@ -1894,16 +1890,14 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel ast_queue_unhold(peer_owner); sub_peer->channel_state = INCALL; } - /* Switch back to old call (remote hung up) */ } else if ((sub->channel_state == ONHOOK || sub->channel_state == CALLENDED ||sub->channel_state == RINGBACK) && sub_peer->channel_state == ONHOLD) { - ast_debug(2, "R when idle and peer subchannel on hold\n"); brcm_cancel_dialing_timeouts(p); p->hf_detected = 0; - if(sub->channel_state == RINGBACK) { + if(sub->channel_state == RINGBACK) { brcm_reset_dtmf_buffer(p); brcm_stop_dialtone(p); } @@ -1942,82 +1936,82 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel if (peer_owner) { ast_queue_control(peer_owner, AST_CONTROL_ANSWER); sub_peer->channel_state = INCALL; - sub->channel_state = ONHOLD; + sub->channel_state = ONHOLD; } - } else if (sub_peer->channel_state == ONHOLD) { - ast_log(LOG_NOTICE, "R on hold \n"); - sub->channel_state = INCALL; - sub->conf_timer_id = ast_sched_add(sched, dtmf_wait_timer, setup_conference_call_cb, p); - } - } - } - - if (p->dtmf_first > 0) { - switch (p->dtmf_first) { - case '4': - if((sub_peer->conf_timer_id != -1) || (sub->conf_timer_id != -1)){ - ast_log(LOG_NOTICE ,"Setting up a R4 call transfer \n"); - if(sub_peer->conf_timer_id != -1) - if (ast_sched_del(sched, sub_peer->conf_timer_id)) { - ast_log(LOG_WARNING, "Failed to remove scheduled conference setup timer\n"); - } - sub_peer->conf_timer_id = -1; - if(sub->conf_timer_id != -1) - if (ast_sched_del(sched, sub->conf_timer_id)) { - ast_log(LOG_WARNING, "Failed to remove scheduled conference setup timer\n"); - } - sub->conf_timer_id = -1; - - if (sub->channel_state == INCALL && sub_peer->channel_state == ONHOLD && - owner && peer_owner) { - struct ast_channel *bridged_chan_inactive = ast_channel_bridge_peer(peer_owner); - struct ast_channel *bridged_chan_active = ast_channel_bridge_peer(owner); - char dest[AST_CHANNEL_NAME * 2] = { '\0', }; - - if (bridged_chan_inactive && bridged_chan_active) { - // Hold the transfer target by default unless being configured no - if (hold_target_before_refer) - ast_queue_hold(owner, NULL); - - // Start the transfer by sending REFER to the transferee - snprintf(dest, sizeof(dest) - 1, "%s?Replaces=%s", - ast_channel_exten(owner), ast_channel_name(bridged_chan_active)); - ast_debug(1, "Start transfer to [%s] on channel %s\n", dest, ast_channel_name(bridged_chan_active)); - int res = -1; - ast_channel_lock(bridged_chan_inactive); - if (!ast_test_flag(ast_channel_flags(bridged_chan_inactive), AST_FLAG_ZOMBIE) && - !ast_check_hangup(bridged_chan_inactive)) { - if (ast_channel_tech(bridged_chan_inactive)->transfer) { - res = ast_channel_tech(bridged_chan_inactive)->transfer(bridged_chan_inactive, dest); - if (res == 0) - res = 1; - } else - res = 0; - } - ast_channel_unlock(bridged_chan_inactive); - if (res < 0) { - ast_log(LOG_ERROR, "ast_transfer() failed\n"); - } else if (res == 0) { - ast_log(LOG_ERROR, "ast_transfer() is not supported on the peer channel\n"); - } else { - sub->channel_state = TRANSFERING; - } - } else { - ast_log(LOG_ERROR, "can't get the peer channel\n"); - } - } - } - else - ast_log(LOG_ERROR,"Late R4 ,Ignoring since conference should be set up by now \n"); - break; + } else if (sub_peer->channel_state == ONHOLD) { + ast_log(LOG_NOTICE, "R on hold \n"); + sub->channel_state = INCALL; + sub->conf_timer_id = ast_sched_add(sched, dtmf_wait_timer, setup_conference_call_cb, p); + } + } + } + + if (p->dtmf_first > 0) { + switch (p->dtmf_first) { + case '4': + if((sub_peer->conf_timer_id != -1) || (sub->conf_timer_id != -1)){ + ast_log(LOG_NOTICE ,"Setting up a R4 call transfer \n"); + if(sub_peer->conf_timer_id != -1) + if (ast_sched_del(sched, sub_peer->conf_timer_id)) { + ast_log(LOG_WARNING, "Failed to remove scheduled conference setup timer\n"); + } + sub_peer->conf_timer_id = -1; + if(sub->conf_timer_id != -1) + if (ast_sched_del(sched, sub->conf_timer_id)) { + ast_log(LOG_WARNING, "Failed to remove scheduled conference setup timer\n"); + } + sub->conf_timer_id = -1; + + if (sub->channel_state == INCALL && sub_peer->channel_state == ONHOLD && + owner && peer_owner) { + struct ast_channel *bridged_chan_inactive = ast_channel_bridge_peer(peer_owner); + struct ast_channel *bridged_chan_active = ast_channel_bridge_peer(owner); + char dest[AST_CHANNEL_NAME * 2] = { '\0', }; + + if (bridged_chan_inactive && bridged_chan_active) { + // Hold the transfer target by default unless being configured no + if (hold_target_before_refer) + ast_queue_hold(owner, NULL); + + // Start the transfer by sending REFER to the transferee + snprintf(dest, sizeof(dest) - 1, "%s?Replaces=%s", + ast_channel_exten(owner), ast_channel_name(bridged_chan_active)); + ast_debug(1, "Start transfer to [%s] on channel %s\n", dest, ast_channel_name(bridged_chan_active)); + int res = -1; + ast_channel_lock(bridged_chan_inactive); + if (!ast_test_flag(ast_channel_flags(bridged_chan_inactive), AST_FLAG_ZOMBIE) && + !ast_check_hangup(bridged_chan_inactive)) { + if (ast_channel_tech(bridged_chan_inactive)->transfer) { + res = ast_channel_tech(bridged_chan_inactive)->transfer(bridged_chan_inactive, dest); + if (res == 0) + res = 1; + } else + res = 0; + } + ast_channel_unlock(bridged_chan_inactive); + if (res < 0) { + ast_log(LOG_ERROR, "ast_transfer() failed\n"); + } else if (res == 0) { + ast_log(LOG_ERROR, "ast_transfer() is not supported on the peer channel\n"); + } else { + sub->channel_state = TRANSFERING; + } + } else { + ast_log(LOG_ERROR, "can't get the peer channel\n"); + } + } + } + else + ast_log(LOG_ERROR,"Late R4 ,Ignoring since conference should be set up by now \n"); + break; - default: - ast_log(LOG_ERROR, "Unhandled DTMF %c\n", p->dtmfbuf[0]); - break; + default: + ast_log(LOG_ERROR, "Unhandled DTMF %c\n", p->dtmfbuf[0]); + break; - } - } - brcm_reset_dtmf_buffer(p); + } + } + brcm_reset_dtmf_buffer(p); } static void handle_dtmf(enum LINE_EVENT event, @@ -2336,7 +2330,8 @@ static int is_sip_account_registered(const char *sip_account) return call_cli_command(cmd, &check_is_sip_account_registered, sip_account); } -static void *brcm_process_event(struct endpt_event *ev) { +static void *brcm_process_event(struct endpt_event *ev) +{ struct brcm_pvt *p = NULL; struct brcm_subchannel *sub = NULL; @@ -2390,7 +2385,6 @@ static void *brcm_process_event(struct endpt_event *ev) { ast_debug(3, "me: got mutex\n"); if (sub) { - switch (ev->event) { case EVENT_OFFHOOK: { ast_debug(9, "EVENT_OFFHOOK detected\n"); @@ -2419,32 +2413,26 @@ static void *brcm_process_event(struct endpt_event *ev) { sub->channel_state = INCALL; ast_queue_control(owner, AST_CONTROL_ANSWER); brcm_send_ubus_event("ANSWERED_CALL",p->line_id); - - //TODO Ronny: ast_channel_queue_connected_line_update() ? - } - else if (sub_peer->channel_state == ONHOLD) { - + } else if (sub_peer->channel_state == ONHOLD) { /* Picking up during reminder ringing for call on hold */ - if (ast_sched_del(sched, sub_peer->onhold_hangup_timer_id) < 0) + if (ast_sched_del(sched, sub_peer->onhold_hangup_timer_id) < 0) { ast_debug(3, "Error deleting timer\n"); + } sub_peer->onhold_hangup_timer_id = -1; - sub->channel_state = CALLENDED; sub_peer->channel_state = INCALL; ast_queue_control(peer_owner, AST_CONTROL_ANSWER); - brcm_unmute_connection(sub_peer); - endpt_connection(sub_peer->parent->line_id, sub_peer->connection_id, "create"); ast_queue_unhold(peer_owner); - } - else if (sub->channel_state == OFFHOOK) { + brcm_send_ubus_event("CALL_UNHOLD", p->line_id); + } else if (sub->channel_state == OFFHOOK) { /* EVENT_OFFHOOK changed endpoint state to OFFHOOK, apply dialtone */ if ( p->context[0] != '\0' && is_sip_account_registered(p->context)) { ast_debug(9, "Resetting dial tones.\n"); p->dialtone = voicemail_messages_waiting(p->context) ? mwi_dialtone_state : DIALTONE_ON; brcm_signal_dialtone(p); - brcm_send_ubus_event("DIALTONE_ON",p->line_id); + brcm_send_ubus_event("DIALTONE_ON", p->line_id); line_settings *s = &line_config[p->line_id]; if (strlen(s->autodial_ext)) { /* Schedule autodial timeout if autodial extension is set */ @@ -2484,20 +2472,21 @@ static void *brcm_process_event(struct endpt_event *ev) { ast_queue_control(owner, AST_CONTROL_HANGUP); } - //TODO: possible bug below - we don't change the channel_state when hanging up if (sub_peer->channel_state == CALLWAITING) { /* Remind user of waiting call */ sub_peer->channel_state = RINGING; - p->tech->signal_ringing(p); //TODO: This should use CCSS "ringing signal" + p->tech->signal_ringing(p); + brcm_send_ubus_event("RINGING",p->line_id); } else if (sub_peer->channel_state == ONHOLD) { /* Remind user of call on hold */ sub_peer->onhold_hangup_timer_id = ast_sched_add(sched, onholdhanguptimeout * 1000, onholdhanguptimeout_cb, sub_peer); ast_debug(2, "Forgotten call on hold for %s!\n", ast_channel_name(peer_owner)); endpt_connection(sub_peer->parent->line_id, sub_peer->connection_id, "destroy"); p->tech->signal_ringing_callerid_pending(p); - p->tech->signal_callerid(sub_peer->owner, sub_peer); //TODO: This should use CCSS "ringing signal" + p->tech->signal_callerid(sub_peer->owner, sub_peer); sub->channel_state = RINGING; ast_queue_control(peer_owner, AST_CONTROL_RINGING); + brcm_send_ubus_event("RINGING",p->line_id); } else if (peer_owner && sub_peer->channel_state != TRANSFERING) { /* Hangup peer subchannels in call or on hold */ ast_debug(2, "Hanging up call (not transfering)\n");