diff --git a/channels/chan_brcm.c b/channels/chan_brcm.c index d806b74a4c2327399a5389da4a49fe04bbd041a3..fe5cc6319ab16d63b5118255624c8da434650ff2 100644 --- a/channels/chan_brcm.c +++ b/channels/chan_brcm.c @@ -84,6 +84,10 @@ static int brcm_unmute_connection(struct brcm_subchannel *p); static int brcm_close_connection(struct brcm_subchannel *p); static int brcm_create_conference(struct brcm_pvt *p); static int brcm_stop_conference(struct brcm_subchannel *p); +static void brcm_attended_call_transfer(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer, + struct ast_channel *owner, struct ast_channel *peer_owner); +static void brcm_unattended_call_transfer(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer, + struct ast_channel *owner, struct ast_channel *peer_owner); static int brcm_finish_transfer(struct ast_channel *owner, struct brcm_subchannel *p, int result); static int brcm_call(struct ast_channel *ast, const char *dest, int timeout); static int brcm_devicestate(const char *device_number); @@ -2097,6 +2101,249 @@ void handle_dtmf_calling(struct brcm_subchannel *sub) } } +// Hangup ALL brcm lines currently ringing with busy casue. +static int brcm_busy_all_ringers(void) +{ + struct brcm_pvt *pvt; + int i; + + brcm_lock_pvts(); + pvt = iflist; + + while(pvt) { + for (i=0; i<NUM_SUBCHANNELS; i++) { + if (pvt->sub[i] && pvt->sub[i]->owner && pvt->sub[i]->channel_state == RINGING) { + ast_debug(4, "Hangup BUSY on %s\n", ast_channel_name(pvt->sub[i]->owner)); + ast_queue_control(pvt->sub[i]->owner, AST_CONTROL_BUSY); + ast_queue_hangup_with_cause(pvt->sub[i]->owner, AST_CAUSE_USER_BUSY); + } + } + + pvt = brcm_get_next_pvt(pvt); + } + + brcm_unlock_pvts(); + + return 0; +} + +static void handle_Rnumber_etsi(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer, + struct ast_channel *owner, struct ast_channel *peer_owner) +{ + struct brcm_pvt *p = sub->parent; + + switch (p->dtmf_first) { + /* Force busy on waiting call or hang up call on hold */ + case '0': + if (sub->channel_state == INCALL && sub_peer->channel_state == CALLWAITING) { + ast_debug(2, "Sending busy to waiting call\n"); + + /* Immediately send busy next time someone calls us during this call */ + //sub->cw_rejected = 1; + + if (ast_sched_del(sched, sub_peer->cw_timer_id)) { + ast_log(LOG_WARNING, "Failed to remove scheduled call waiting timer\n"); + } + sub_peer->cw_timer_id = -1; + + ast_queue_control(peer_owner, AST_CONTROL_BUSY); + brcm_busy_all_ringers(); + ast_indicate(owner, AST_CONTROL_UNHOLD); + } else if (sub->channel_state == INCALL && sub_peer->channel_state == ONHOLD) { + ast_debug(2, "Hanging up call on hold\n"); + + sub_peer = brcm_get_onhold_subchannel(p); + + ast_queue_control(peer_owner, AST_CONTROL_HANGUP); + sub_peer->channel_state = CALLENDED; + brcm_close_connection(sub_peer); + } + break; + /* Hangup current call and answer waiting call */ + case '1': + if (sub->channel_state == INCALL && (sub_peer->channel_state == CALLWAITING || sub_peer->channel_state == ONHOLD)) { + + /* Close connection and hangup active subchannel */ + if (owner) { + ast_queue_control(owner, AST_CONTROL_HANGUP); + } + sub->channel_state = CALLENDED; + brcm_close_connection(sub); + + if (sub_peer->channel_state == CALLWAITING) { + ast_log(LOG_WARNING, "R1 call waiting\n"); + /* Stop call waiting tone on current call */ + brcm_stop_callwaiting(p); + + if (ast_sched_del(sched, sub_peer->cw_timer_id)) { + ast_log(LOG_WARNING, "Failed to remove scheduled call waiting timer\n"); + } + sub_peer->cw_timer_id = -1; + + /* Pick up call waiting */ + if (!sub_peer->connection_init) { + ast_debug(9, "create_connection()\n"); + brcm_create_connection(sub_peer); + } + if (peer_owner) { + ast_queue_control(peer_owner, AST_CONTROL_ANSWER); + sub_peer->channel_state = INCALL; + } + } else if (sub_peer->channel_state == ONHOLD) { + ast_log(LOG_WARNING, "R1 Unholding\n"); + + /* Unhold inactive subchannel */ + if (peer_owner) { + brcm_unmute_connection(sub_peer); + ast_queue_unhold(peer_owner); + sub_peer->channel_state = INCALL; + } + } + } + break; + /* Answer waiting call and put other call on hold (switch calls) */ + case '2': + if (sub->channel_state == INCALL && (sub_peer->channel_state == CALLWAITING || sub_peer->channel_state == ONHOLD)) { + + brcm_mute_connection(sub); + if (owner) { + ast_queue_hold(owner, NULL); + } + + if (sub_peer->channel_state == CALLWAITING) { + ast_log(LOG_WARNING, "R2 Call waiting\n"); + + /* Stop call waiting tone on current call */ + brcm_stop_callwaiting(p); + + /* Cancel timer */ + if (ast_sched_del(sched, sub_peer->cw_timer_id)) { + ast_log(LOG_WARNING, "Failed to remove scheduled call waiting timer\n"); + } + sub_peer->cw_timer_id = -1; + + if (ast_sched_del(sched, sub_peer->cwBeep_timer_id)) { + ast_log(LOG_WARNING, "Failed to remove scheduled call waiting beep timer\n"); + } + sub_peer->cwBeep_timer_id = -1; + + /* Pick up call waiting */ + if (!sub_peer->connection_init) { + ast_debug(9, "create_connection()\n"); + brcm_create_connection(sub_peer); + } + if (peer_owner) { + ast_queue_control(peer_owner, AST_CONTROL_ANSWER); + sub_peer->channel_state = INCALL; + } + } else if (sub_peer->channel_state == ONHOLD) { + ast_log(LOG_WARNING, "R2 on hold\n"); + + /* Unhold inactive subchannel */ + if (peer_owner) { + brcm_unmute_connection(sub_peer); + ast_queue_unhold(peer_owner); + sub_peer->channel_state = INCALL; + } + } + + sub->channel_state = ONHOLD; + } + break; + /* Connect waiting call to existing call to create 3-way */ + case '3': + if (sub->channel_state == INCALL && sub_peer->channel_state == ONHOLD) { + ast_debug(2, "DTMF3 after HF\n"); + brcm_create_conference(p); + } + break; + /* Remote transfer held call to active call */ + case '4': + brcm_attended_call_transfer(sub, sub_peer, owner, peer_owner); + break; + case '5': + brcm_unattended_call_transfer(sub, sub_peer, owner, peer_owner); + break; + default: + ast_log(LOG_NOTICE, "Unhandled DTMF %c\n", p->dtmfbuf[0]); + break; + } +} + +static void handle_Rnumber_uk(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer, + struct ast_channel *owner, struct ast_channel *peer_owner) +{ + struct brcm_pvt *p = sub->parent; + + switch (p->dtmf_first) { + case '4': + brcm_attended_call_transfer(sub, sub_peer, owner, peer_owner); + break; + case '5': + brcm_unattended_call_transfer(sub, sub_peer, owner, peer_owner); + break; + default: + ast_log(LOG_ERROR, "Unhandled DTMF %c\n", p->dtmfbuf[0]); + break; + } +} + +static void handle_Rkey_uk(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer, + struct ast_channel *owner, struct ast_channel *peer_owner) +{ + struct brcm_pvt *p = sub->parent; + + if (sub->channel_state == INCALL && (sub_peer->channel_state == CALLWAITING || sub_peer->channel_state == ONHOLD)) { + brcm_mute_connection(sub); + if (sub_peer->channel_state == CALLWAITING) { + if (owner) { + ast_queue_hold(owner, NULL); + } + ast_log(LOG_NOTICE, " R in Call waiting\n"); + /* Cancel timers */ + if (ast_sched_del(sched, sub_peer->cw_timer_id)) { + ast_log(LOG_WARNING, "Failed to remove scheduled call waiting timer\n"); + } + sub_peer->cw_timer_id = -1; + if (ast_sched_del(sched, sub_peer->cwBeep_timer_id)) { + ast_log(LOG_WARNING, "Failed to remove scheduled call waiting beep timer\n"); + } + sub_peer->cwBeep_timer_id = -1; + /* Pick up call waiting */ + if (!sub_peer->connection_init) { + ast_debug(9, "create_connection()\n"); + brcm_create_connection(sub_peer); + } + if (peer_owner) { + ast_queue_control(peer_owner, AST_CONTROL_ANSWER); + sub_peer->channel_state = INCALL; + sub_peer->call_direction = INCOMING_CALL; + sub->channel_state = ONHOLD; + } + } else if (sub_peer->channel_state == ONHOLD) { + ast_log(LOG_NOTICE, "R on hold, line: %d action: %s\n", + p->line_id, sub->call_direction == INCOMING_CALL ? "Toggle" : "3way Conference"); + if (sub->call_direction == OUTGOING_CALL) { + sub->channel_state = INCALL; + sub->conf_timer_id = ast_sched_add(sched, dtmf_wait_timer, setup_conference_call_cb, p); + } else if (sub->call_direction == INCOMING_CALL){ + brcm_unmute_connection(sub_peer); + ast_queue_unhold(peer_owner); + sub_peer->channel_state = INCALL; + + brcm_mute_connection(sub); + ast_queue_hold(owner, NULL); + sub->channel_state = ONHOLD; + } + } + } else if ((sub->channel_state == DIALING || sub->channel_state == OFFHOOK || sub->channel_state == RINGBACK) && + sub_peer->channel_state != ONHOLD) { + ast_log(LOG_NOTICE, "R while offhook/dialing\n"); + brcm_cancel_dialing_timeouts(p); + brcm_reset_dtmf_buffer(p); + p->hf_detected = 0; + } +} /* * Perform actions for hook flash. * Preconditions: One subchannel should be in CALLWAITING or ONHOLD, @@ -2111,7 +2358,8 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel struct ast_bridge *bridge; struct ast_bridge_channel *bridge_channel; - ast_log(LOG_NOTICE, "Hook Flash detected for phone line %d, p->dtmf_first = %d\r\n", sub->parent->line_id, p->dtmf_first); + ast_log(LOG_NOTICE, "Hook Flash detected for phone line %d, p->dtmf_first = %d, flashSpec: %d\r\n", sub->parent->line_id, p->dtmf_first, + channel_config[p->line_id].flashSpec); if (owner) { bridge = ast_channel_internal_bridge(owner); @@ -2132,7 +2380,7 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel } if (p->dtmf_first < 0) { - ast_log(LOG_NOTICE, "sub->channel_state = %d, sub_peer->channel_state = %d\n", sub->channel_state, sub_peer->channel_state); + ast_log(LOG_NOTICE, "sub->channel_state = %s, sub_peer->channel_state = %s\n", state2str(sub->channel_state), state2str(sub_peer->channel_state)); /* 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)) { ast_debug(2, "R while in call and idle peer subchannel\n"); @@ -2219,159 +2467,21 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel brcm_send_ubus_event("CALL_UNHOLD",p->line_id); sub_peer->channel_state = INCALL; } - } else if (sub->channel_state == INCALL && (sub_peer->channel_state == CALLWAITING || sub_peer->channel_state == ONHOLD)) { - brcm_mute_connection(sub); - if (sub_peer->channel_state == CALLWAITING) { - if (owner) { - ast_queue_hold(owner, NULL); - } - ast_log(LOG_NOTICE, " R in Call waiting\n"); - /* Cancel timers */ - if (ast_sched_del(sched, sub_peer->cw_timer_id)) { - ast_log(LOG_WARNING, "Failed to remove scheduled call waiting timer\n"); - } - sub_peer->cw_timer_id = -1; - if (ast_sched_del(sched, sub_peer->cwBeep_timer_id)) { - ast_log(LOG_WARNING, "Failed to remove scheduled call waiting beep timer\n"); - } - sub_peer->cwBeep_timer_id = -1; - /* Pick up call waiting */ - if (!sub_peer->connection_init) { - ast_debug(9, "create_connection()\n"); - brcm_create_connection(sub_peer); - } - if (peer_owner) { - ast_queue_control(peer_owner, AST_CONTROL_ANSWER); - sub_peer->channel_state = INCALL; - sub_peer->call_direction = INCOMING_CALL; - sub->channel_state = ONHOLD; - } - } else if (sub_peer->channel_state == ONHOLD) { - ast_log(LOG_NOTICE, "R on hold, line: %d direction of 2nd call is %s\n", - p->line_id, sub->call_direction == INCOMING_CALL ? "incoming" : "outgoing"); - if (sub->call_direction == OUTGOING_CALL) { - sub->channel_state = INCALL; - sub->conf_timer_id = ast_sched_add(sched, dtmf_wait_timer, setup_conference_call_cb, p); - } else if (sub->call_direction == INCOMING_CALL){ - brcm_unmute_connection(sub_peer); - ast_queue_unhold(peer_owner); - sub_peer->channel_state = INCALL; - - brcm_mute_connection(sub); - ast_queue_hold(owner, NULL); - sub->channel_state = ONHOLD; - } - } - } else if ((sub->channel_state == DIALING || sub->channel_state == OFFHOOK || sub->channel_state == RINGBACK) && - sub_peer->channel_state != ONHOLD) { - ast_log(LOG_NOTICE, "R while offhook/dialing\n"); - brcm_cancel_dialing_timeouts(p); - brcm_reset_dtmf_buffer(p); - p->hf_detected = 0; } 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); } + + if (channel_config[p->line_id].flashSpec == FLASH_SPEC_UK) + handle_Rkey_uk(sub, sub_peer, owner, peer_owner); } 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; - case '5': - ast_debug(4 ,"R5 unattended call transfer\n"); - if((sub_peer->conf_timer_id != -1) || (sub->conf_timer_id != -1)) { - 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_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_debug(4, "sub_peer->conf_timer_id deleted\n"); - } - sub_peer->conf_timer_id = -1; - - channel_settings *s = &channel_config[p->line_id]; - if (!s->calleridenable) { - p->tech->stop_ringing(p); - } else { - p->tech->stop_ringing_callerid_pending(p); - } - - // unattended call transfer: cancel the the call to transfer target - if (sub->owner && sub_peer->owner) { - strncpy(sub_peer->blind_xfer_target, ast_channel_exten(owner), sizeof(sub->blind_xfer_target) - 1); - ast_queue_control(sub->owner, AST_CONTROL_HANGUP); - ast_queue_unhold(sub_peer->owner); - sub_peer->channel_state = TRANSFERING; - } - } - else - ast_log(LOG_ERROR,"Late R5 ,Ignoring since conference should be set up by now \n"); - break; - default: - ast_log(LOG_ERROR, "Unhandled DTMF %c\n", p->dtmfbuf[0]); - break; - - } + if (channel_config[p->line_id].flashSpec == FLASH_SPEC_ETSI) + handle_Rnumber_etsi(sub, sub_peer, owner, peer_owner); + else + handle_Rnumber_uk(sub, sub_peer, owner, peer_owner); } brcm_reset_dtmf_buffer(p); } @@ -3778,7 +3888,7 @@ static channel_settings channel_settings_create(void) .calleridenable = 0, //clip .calleridnameenable = 0, //cnip .anonymouscallenable = 0, //clir - + .flashSpec = 0, }; return line_conf; } @@ -3836,6 +3946,12 @@ static void channel_settings_load(channel_settings *channel_config, struct ast_v else if (!strcasecmp(v->name, "anonymouscallenable")) { channel_config->anonymouscallenable = ast_true(v->value)?1:0; } + else if (!strcasecmp(v->name, "flash_spec")) { + if (!strcasecmp(v->value, "etsi")) + channel_config->flashSpec = FLASH_SPEC_ETSI; + else + channel_config->flashSpec = FLASH_SPEC_UK; + } v = v->next; } } @@ -4776,6 +4892,108 @@ static int brcm_stop_conference(struct brcm_subchannel *p) return 0; } +static void brcm_attended_call_transfer(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer, + struct ast_channel *owner, struct ast_channel *peer_owner) +{ + struct brcm_pvt *p = sub->parent; + + if( channel_config[p->line_id].flashSpec == FLASH_SPEC_ETSI || + channel_config[p->line_id].flashSpec == FLASH_SPEC_UK && ((sub_peer->conf_timer_id != -1) || (sub->conf_timer_id != -1))) { + ast_log(LOG_NOTICE ,"Setting up attended 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"); +} + +static void brcm_unattended_call_transfer(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer, + struct ast_channel *owner, struct ast_channel *peer_owner) +{ + struct brcm_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); + 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_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_debug(4, "sub_peer->conf_timer_id deleted\n"); + } + sub_peer->conf_timer_id = -1; + + channel_settings *s = &channel_config[p->line_id]; + if (!s->calleridenable) { + p->tech->stop_ringing(p); + } else { + p->tech->stop_ringing_callerid_pending(p); + } + + // unattended call transfer: cancel the the call to transfer target + if (sub->owner && sub_peer->owner) { + strncpy(sub_peer->blind_xfer_target, ast_channel_exten(owner), sizeof(sub->blind_xfer_target) - 1); + ast_queue_control(sub->owner, AST_CONTROL_HANGUP); + ast_queue_unhold(sub_peer->owner); + sub_peer->channel_state = TRANSFERING; + } + } + else + ast_log(LOG_ERROR,"Late R5 ,Ignoring since conference should be set up by now \n"); +} + static int brcm_close_connection(struct brcm_subchannel *sub) { struct brcm_pvt *p = sub->parent; diff --git a/channels/chan_brcm.h b/channels/chan_brcm.h index 2e52f85919e7b376c8cca250a203e90ecb87e09b..14520b940f9e745975c95bcd5a1f693537b3ebfb 100644 --- a/channels/chan_brcm.h +++ b/channels/chan_brcm.h @@ -198,7 +198,10 @@ typedef struct DTMF_CHARNAME_MAP } DTMF_CHARNAME_MAP; - +typedef enum flash_spec { + FLASH_SPEC_UK = 0, + FLASH_SPEC_ETSI, +} flash_spec; typedef struct DIALTONE_MAP { @@ -242,6 +245,7 @@ typedef struct { int anonymouscallenable; int calleridenable; int calleridnameenable; + flash_spec flashSpec; } channel_settings;