From 89eb691abc5a47f77672e059e32b3661f4dfc044 Mon Sep 17 00:00:00 2001 From: Yalu Zhang <yalu.zhang@iopsys.eu> Date: Tue, 28 Sep 2021 14:05:40 +0200 Subject: [PATCH] Fix no audio issue when the held call released before the second outgoing call gets answered Don't destroy the connection when the peer sub-channel is in dialing or ringback state. --- channels/chan_brcm.c | 132 ++++++++++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 52 deletions(-) diff --git a/channels/chan_brcm.c b/channels/chan_brcm.c index 62512be18c..9d25422c29 100644 --- a/channels/chan_brcm.c +++ b/channels/chan_brcm.c @@ -899,50 +899,52 @@ static int brcm_call(struct ast_channel *chan, const char *dest, int timeout) static int brcm_hangup(struct ast_channel *ast) { struct brcm_pvt *p; - struct brcm_subchannel *sub, *sub_peer; + struct brcm_subchannel *sub = ast_channel_tech_pvt(ast), *sub_peer; struct ast_channel *peer_owner; - sub = ast_channel_tech_pvt(ast); int conf_timer_removed = 0; - if (!ast_channel_tech_pvt(ast)) { + if (!sub) { ast_log(LOG_WARNING, "Asked to hangup channel not connected\n"); return 0; } - pvt_lock(sub->parent, "TELCHAN hangup"); - p = sub->parent; - sub_peer = brcm_subchannel_get_peer(sub); - /*If call is not connected (INCALL state )/ Call is dialing but Subchannel is busy move to Disconnected state */ - if((sub->channel_state!= ONHOOK && sub_peer->channel_state != OFFHOOK)) - { - //Ignore state change if we are INCALL - if(sub->channel_state != INCALL && sub_peer->channel_state != INCALL) - { - /*Cases where other party doesnt picksup call ,after timeout move it to idle status */ - if(sub->channel_state == RINGING && sub_peer->channel_state == ONHOOK) - strncpy(p->callStatus, "Idle", CALL_STATUS_MAX_LEN); - else - strncpy(p->callStatus, "Disconnected", CALL_STATUS_MAX_LEN); - } - } + p = sub->parent; + pvt_lock(p, "TELCHAN hangup"); + sub_peer = brcm_subchannel_get_peer(sub); - ast_debug(1, "brcm_hangup(%s) line_id=%d connection_id=%d dialtone=%s channel_state=%s\n", + ast_debug(1, "%s(%s): line_id=%d connection_id=%d dialtone=%s channel_state=%s, peer_state=%s\n", __func__, ast_channel_name(ast), p->line_id, sub->connection_id, dialtone_map[p->dialtone].str, - state2str(sub->channel_state)); - if(sub_peer->conf_timer_id != -1){ - conf_timer_removed = 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){ - conf_timer_removed = 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; - } + state2str(sub->channel_state), state2str(sub_peer->channel_state)); + + /* If call is not connected (INCALL) or is dialing but Subchannel is busy, move to Disconnected state */ + if ((sub->channel_state!= ONHOOK && sub_peer->channel_state != OFFHOOK)) + { + //Ignore state change if we are INCALL + if(sub->channel_state != INCALL && sub_peer->channel_state != INCALL) + { + /*Cases where other party doesnt picksup call ,after timeout move it to idle status */ + if(sub->channel_state == RINGING && sub_peer->channel_state == ONHOOK) + strncpy(p->callStatus, "Idle", CALL_STATUS_MAX_LEN); + else + strncpy(p->callStatus, "Disconnected", CALL_STATUS_MAX_LEN); + } + } + + if (sub_peer->conf_timer_id != -1) { + conf_timer_removed = 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){ + conf_timer_removed = 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 == CALLWAITING) { brcm_stop_callwaiting(p); @@ -958,7 +960,8 @@ static int brcm_hangup(struct ast_channel *ast) p->tech->stop_ringing_callerid_pending(p); } } else if (brcm_subchannel_is_idle(sub_peer) && p->tech->release) { - //No active subchannel left, release + // No active subchannel left, release + ast_debug(1, "Release the call since the peer sub-channel is also idle\n"); p->tech->release(p); } @@ -994,23 +997,23 @@ static int brcm_hangup(struct ast_channel *ast) * Additional check for ONHOOK channel state so that handle_dialtone_timeout() * 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)); + if (p->dialtone != DIALTONE_HOWLER && sub->channel_state != ONHOOK) { /*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)); } - if ( sub->conference_initiator && brcm_in_conference(p)) { + 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) { + 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) @@ -1033,7 +1036,7 @@ static int brcm_hangup(struct ast_channel *ast) ast_channel_tech_pvt_set(ast, NULL); brcm_close_connection(sub); - /*Check for channelstate before dialtone timeout */ + /* Check for channel state before dial tone timeout */ if(sub->channel_state == CALLENDED && sub_peer->channel_state != INCALL) { /* If we hangup but not playing howler, start playing timeout tones */ p->dialtone = DIALTONE_ON; @@ -2708,13 +2711,36 @@ static void brcm_assign_line_id(struct brcm_pvt *p) } } +static int brcm_in_dialing(const struct brcm_pvt *p) +{ + int i; + for (i=0; i<NUM_SUBCHANNELS; i++) { + if (p->sub[i]->channel_state == DIALING) { + return 1; + } + } + + return 0; +} + +static int brcm_in_ringback(const struct brcm_pvt *p) +{ + int i; + for (i=0; i<NUM_SUBCHANNELS; i++) { + if (p->sub[i]->channel_state == RINGBACK) { + return 1; + } + } + + return 0; +} static int brcm_in_call(const struct brcm_pvt *p) { int i; for (i=0; i<NUM_SUBCHANNELS; i++) { if (p->sub[i]->channel_state == INCALL) { - return 1; + return 1; } } @@ -2759,7 +2785,6 @@ static int brcm_in_onhold(const struct brcm_pvt *p) static int brcm_in_conference(const struct brcm_pvt *p) { - return (p->sub[0]->channel_state == INCALL && p->sub[1]->channel_state == INCALL) || p->sub[0]->conference_initiator || @@ -3987,7 +4012,7 @@ static int brcm_signal_callwaiting(const struct brcm_pvt *p) static int brcm_stop_callwaiting(const struct brcm_pvt *p) { endpt_signal(p->line_id, "callwt", "off", NULL); - brcm_send_ubus_event("CALLWAITING_STOPPED",p->line_id); + brcm_send_ubus_event("CALLWAITING_STOPPED", p->line_id); return 0; } @@ -4204,8 +4229,9 @@ static int brcm_create_conference(struct brcm_pvt *p) static int brcm_stop_conference(struct brcm_subchannel *p) { struct ast_bridge *confBridge; - struct brcm_pvt *pvt; - pvt = p->parent; + struct brcm_pvt *pvt; + + pvt = p->parent; if (p->connection_init && p->owner) { ast_debug(1, "Ending conference for pvt line_id=%i connection_id=%d\n", p->parent->line_id, p->connection_id); @@ -4224,16 +4250,18 @@ static int brcm_stop_conference(struct brcm_subchannel *p) return 0; } -static int brcm_close_connection(struct brcm_subchannel *sub) { +static int brcm_close_connection(struct brcm_subchannel *sub) +{ + struct brcm_pvt *p = sub->parent; if (sub->connection_init) { - if(!brcm_in_onhold(sub->parent) && !brcm_in_call(sub->parent) && - !brcm_in_callwaiting(sub->parent) && !brcm_in_transferring(sub->parent) ) { // Does line have another call? - ast_debug(1, "Closing real endpoint connection %d\n", sub->parent->line_id); - endpt_connection(sub->parent->line_id, sub->connection_id, "destroy"); + if (!brcm_in_onhold(p) && !brcm_in_call(p) && !brcm_in_dialing(p) && !brcm_in_ringback(p) && + !brcm_in_callwaiting(p) && !brcm_in_transferring(p)) { // Does the line have another call? + ast_debug(1, "Closing real endpoint connection %d\n", p->line_id); + endpt_connection(p->line_id, sub->connection_id, "destroy"); } sub->connection_init = 0; - ast_debug(1, "Virtual Asterisk connection %d/%d destroyed\n", sub->parent->line_id, sub->connection_id); + ast_debug(1, "Virtual Asterisk connection %d/%d destroyed\n", p->line_id, sub->connection_id); } return 0; -- GitLab