diff --git a/apps/app_dial.c b/apps/app_dial.c index d611083d9a66f0e4c4a6d865528bb397bbc2c55b..c9f58fe23def9f2e8b94a209ffc4078bb1f68d5e 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -1474,6 +1474,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, handle_cause(AST_CAUSE_CONGESTION, &num); break; case AST_CONTROL_RINGING: + case AST_CONTROL_RINGING_CW: /* This is a tricky area to get right when using a native * CC agent. The reason is that we do the best we can to send only a * single ringing notification to the caller. @@ -1508,8 +1509,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_channel_early_bridge(in, c); } if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK) && ast_strlen_zero(opt_args[OPT_ARG_RINGBACK])) { - ast_indicate(in, AST_CONTROL_RINGING); - pa->sentringing++; + + ast_indicate(in, f->subclass.integer); + + pa->sentringing++; } if (!sent_ring) { struct timeval now, then; diff --git a/channels/chan_brcm.c b/channels/chan_brcm.c index 76a2830fc994c9b5930680ca3db4a12a3da58afc..fadbd81769c0c3253c3178c8a5c33a6192fd5189 100644 --- a/channels/chan_brcm.c +++ b/channels/chan_brcm.c @@ -148,6 +148,9 @@ static int r4hanguptimeout = DEFAULT_R4_HANGUP_TIMEOUT; /* Automatic call on hold hangup */ static int onholdhanguptimeout = DEFAULT_ONHOLD_HANGUP_TIMEOUT; +/* Max call count per line */ +static int max_sessions_per_line; + /* Boolean, controls whether the transferor puts the transfer target on-hold before sending * REFER to the transferee */ static int hold_target_before_refer = 1; @@ -801,8 +804,10 @@ static int brcm_call(struct ast_channel *chan, const char *dest, int timeout) brcm_signal_callwaiting(p); int cwtimeout_ms = cwtimeout * 1000; sub->cw_timer_id = ast_sched_add(sched, cwtimeout_ms, cwtimeout_cb, sub); - ast_setstate(chan, AST_STATE_RINGING); - ast_queue_control(chan, AST_CONTROL_RINGING); + ast_setstate(chan, AST_STATE_RINGING_CW); + ast_queue_control(chan, AST_CONTROL_RINGING_CW); + + } else if (!brcm_subchannel_is_idle(sub_peer)) { ast_debug(1, "Line is busy\n"); @@ -900,7 +905,7 @@ static int brcm_hangup(struct ast_channel *ast) ast_debug(6, "Setting channel state to %s\n", state2str(sub->channel_state)); } - if (terminate_conference && 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); @@ -1653,8 +1658,11 @@ void handle_dtmf_calling(struct brcm_subchannel *sub) ast_debug(9, "Direct extension matching %s found\n", p->dtmfbuf); brcm_start_calling(p, sub, p->context_direct); } - else if (ast_exists_extension(NULL, p->context, p->dtmfbuf, 1, p->cid_num) && dtmf_last_char == termination_digit && - dtmf_one_before_last_char != 0x2A && feature_access_code_match(p->dtmfbuf) != 1) { + + + else if (ast_exists_extension(NULL, p->context, p->dtmfbuf, 1, p->cid_num) && dtmfbuf_len > 2 && dtmf_last_char == termination_digit + && dtmf_one_before_last_char != 0x2A && feature_access_code_match(p->dtmfbuf) != 1) { + //We have a match in the "normal" context, and user ended the dialling sequence with a #, //so have asterisk place a call immediately if sequence is not partially matching a feature access code ast_debug(9, "Termination key %c pressed during dialling, extension %s found\n",termination_digit, p->dtmfbuf); @@ -1704,6 +1712,25 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel ast_log(LOG_DTMF, "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) { + bridge = ast_channel_internal_bridge(peer_owner); + } else { + p->hf_detected = 0; + return; + } + + if (sub->channel_state == INCALL && 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)) { @@ -1713,8 +1740,12 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel brcm_reset_dtmf_buffer(p); p->hf_detected = 0; - /* Put current call on hold */ + /* Put current call on hold */ if (owner) { + AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { + ast_indicate(bridge_channel->chan, AST_CONTROL_HOLD); + } + brcm_mute_connection(sub); sub->channel_state = ONHOLD; ast_queue_hold(owner, NULL); @@ -1729,8 +1760,7 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel } else if ((sub->channel_state == DIALING || sub->channel_state == OFFHOOK || sub->channel_state == AWAITONHOOK || - sub->channel_state == CALLING || - sub->channel_state == RINGBACK) + sub->channel_state == CALLING ) && sub_peer->channel_state == ONHOLD) { ast_debug(2, "R while offhook/dialing and peer subchannel on hold\n"); @@ -1751,19 +1781,27 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel /* Pick up old */ if (peer_owner) { + 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"); + } brcm_unmute_connection(sub_peer); 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) + } 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) { + brcm_reset_dtmf_buffer(p); + brcm_stop_dialtone(p); + } /* Hang up current */ if (owner) { @@ -1777,182 +1815,45 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel sub_peer->channel_state = INCALL; } } - - return; - } - - 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); + else 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_NOTICE, " 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"); } - 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; - } - } + 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); } - 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; - - /* 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); + if (peer_owner) { + ast_queue_control(peer_owner, AST_CONTROL_ANSWER); + sub_peer->channel_state = INCALL; } - break; - - /* Remote transfer held call to active call */ - case '4': - ast_debug(2, "R4 Transfer\n"); - 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 if (sub_peer->channel_state == ONHOLD) { + ast_log(LOG_NOTICE, " R2 on hold\n"); + /* Unhold inactive subchannel */ + brcm_create_conference(p); + if (peer_owner) { + brcm_unmute_connection(sub_peer); + ast_queue_unhold(peer_owner); + sub_peer->channel_state = INCALL; } - break; - - default: - ast_log(LOG_NOTICE, "Unhandled DTMF %c\n", p->dtmfbuf[0]); - break; - } + } + sub->channel_state = ONHOLD; + } + p->hf_detected = 0; + return; + } brcm_reset_dtmf_buffer(p); } @@ -2476,10 +2377,7 @@ static void *brcm_process_event(struct endpt_event *ev) { ast_debug(1, "EVENT_FLASH\n"); p->hf_detected = 1; - /* Schedule hook flash timeout. Until hook flash is handled or timeout expires, no - * dtmf will be relayed to asterisk. */ - int timeoutmsec = line_config[p->line_id].timeoutmsec; - p->interdigit_timer_id = ast_sched_add(sched, timeoutmsec, handle_hookflash_timeout, p); + handle_hookflash(sub, sub_peer, owner, peer_owner); break; @@ -3228,7 +3126,8 @@ static int load_common_settings(struct ast_config **cfg) /* Set default values */ hold_target_before_refer = 1; - + max_sessions_per_line = 2; + if ((*cfg = ast_config_load(config, config_flags)) == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config); return AST_MODULE_LOAD_DECLINE; @@ -3296,6 +3195,13 @@ static int load_common_settings(struct ast_config **cfg) tok = strtok(NULL, ","); } } + } else if (!strcasecmp(v->name, "maxsessionsperline")) { + if (ast_strlen_zero(v->value) || atoi(v->value) > 20 || atoi(v->value) < 1) { + ast_log(LOG_WARNING, "Incorrect session limit per line '%s', defaulting to '%d'\n", + v->value, max_sessions_per_line); + } else { + max_sessions_per_line = atoi(v->value); + } } v = v->next; diff --git a/channels/chan_brcm.h b/channels/chan_brcm.h index 37776853b49445f42cb27c98a995fa8808fde3aa..b94d28f64b358f792027eaf08c9d194c537ae218 100644 --- a/channels/chan_brcm.h +++ b/channels/chan_brcm.h @@ -240,7 +240,7 @@ static struct ast_jb_conf default_jbconf = }; -#define DEFAULT_CALL_WAITING_TIMEOUT 24 // In seconds, Telia uses 24s +#define DEFAULT_CALL_WAITING_TIMEOUT 20 // In seconds #define DEFAULT_R4_HANGUP_TIMEOUT 5000 // In milliseconds #define DEFAULT_ONHOLD_HANGUP_TIMEOUT 20 // In seconds diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5d879410695cd5b0f8fcd7193d2143043af779cc..b091bad6281c9e50b193a4378a2c8d0eaea1bf07 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1633,6 +1633,7 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi switch (condition) { case AST_CONTROL_RINGING: + case AST_CONTROL_RINGING_CW: if (ast_channel_state(ast) == AST_STATE_RING) { if (channel->session->endpoint->inband_progress || (channel->session->inv_session && channel->session->inv_session->neg && @@ -1641,7 +1642,11 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi res = -1; } else { response_code = 180; - } + if (condition == AST_CONTROL_RINGING_CW) + channel->session->ring_cw = PJ_TRUE; + else + channel->session->ring_cw = PJ_FALSE; + } } else { res = -1; } @@ -1756,7 +1761,7 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi device_buf = alloca(device_buf_size); ast_channel_get_device_name(ast, device_buf, device_buf_size); ast_devstate_changed_literal(AST_DEVICE_ONHOLD, 1, device_buf); - if (!channel->session->moh_passthrough) { + if (!channel->session->moh_passthrough || channel->session->endpoint->media.t38.enabled) { ast_moh_start(ast, data, NULL); } else { if (ast_sip_push_task(channel->session->serializer, remote_send_hold, ao2_bump(channel->session))) { @@ -1772,7 +1777,7 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi device_buf = alloca(device_buf_size); ast_channel_get_device_name(ast, device_buf, device_buf_size); ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, 1, device_buf); - if (!channel->session->moh_passthrough) { + if (!channel->session->moh_passthrough || channel->session->endpoint->media.t38.enabled ) { ast_moh_stop(ast); } else { if (ast_sip_push_task(channel->session->serializer, remote_send_unhold, ao2_bump(channel->session))) { diff --git a/include/asterisk/channelstate.h b/include/asterisk/channelstate.h index 08f908256d8760fb71089955a7ee6d4464b0026e..2ae07984043c91d4ae0aee87b5e7207248cf5e4c 100644 --- a/include/asterisk/channelstate.h +++ b/include/asterisk/channelstate.h @@ -45,6 +45,7 @@ enum ast_channel_state { AST_STATE_PRERING, /*!< Channel has detected an incoming call and is waiting for ring */ AST_STATE_MUTE = (1 << 16), /*!< Do not transmit voice data */ + AST_STATE_RINGING_CW, }; /*! diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index f719f8966e2d584794cc145c4386a1bdeac2b325..f6e550f6a51d8ef2bc443dd46fba6f2544b644d2 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -312,7 +312,7 @@ enum ast_control_frame_type { AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE = 35, /*!< Channel indication that a stream topology change has been requested */ AST_CONTROL_STREAM_TOPOLOGY_CHANGED = 36, /*!< Channel indication that a stream topology change has occurred */ AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED = 37, /*!< Channel indication that one of the source streams has changed its source */ - + AST_CONTROL_RINGING_CW = 38, /*!< Remote end is ringing with call wait*/ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 54c704fd117bc6fc03d89b57525fc2a596032c98..e2c0ecac4f6853e39db4f5aed53bfcf472c007c5 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -239,6 +239,7 @@ struct ast_sip_session { unsigned int authentication_challenge_count:4; /*! The direction of the call respective to Asterisk */ enum ast_sip_session_call_direction call_direction; + int ring_cw; }; typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 0365e4110a78f41df58a791c1fa18b13391cf25b..da0b18b32fb145c02cdf3b67bf09a34ab28ab790 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -4539,7 +4539,10 @@ static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_d SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Cannot send response due to missing sequence header", ast_sip_session_get_name(session)); } - + if (session->ring_cw == PJ_TRUE ){ + ast_sip_add_header(tdata, "Alert-Info", "<urn:alert:service:call-waiting>"); + session->ring_cw = PJ_FALSE; /*! Reset call wait status */ + } ast_sip_message_apply_transport(session->endpoint->transport, tdata); AST_LIST_TRAVERSE(&session->supplements, supplement, next) {