diff --git a/src/channels/chan_voicemngr.c b/src/channels/chan_voicemngr.c index c8f5a59a059e81b3058a95bb65a6902e4bd39f46..351ed77d80e2de4f772f8a10e1ed31e027e0ccf1 100644 --- a/src/channels/chan_voicemngr.c +++ b/src/channels/chan_voicemngr.c @@ -148,6 +148,9 @@ static struct ast_format *map_rtpname_to_format(char* name); static int is_sip_account_registered(const char *sip_account); typedef void *(*check_output_cb)(const char *, const char *data); static void *call_cli_command(const char *cmd, check_output_cb check_output, const char *data); +static void chan_voicemngr_start_calling(struct chan_voicemngr_subchannel *sub, char* context); +static int register_504_cb(const void *data); +static int is_sip_account_504_ongoing(const char *sip_account); /* Global jitter buffer configuration - by default, jb is disabled */ static struct ast_jb_conf default_jbconf = @@ -1161,6 +1164,9 @@ static int chan_voicemngr_indicate(struct ast_channel *ast, int condition, const case AST_CAUSE_NETWORK_OUT_OF_ORDER: chan_voicemngr_stop_dialtone(sub->parent); // stop any dialtone exist if disconnection happened due to network/server break; + case AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE: + //504 + break; default: ast_debug(1, "Don't know how to handle cause code %d\n", ast_cause); break; @@ -1519,7 +1525,12 @@ static int chan_voicemngr_hangup(struct ast_channel *ast) ast_log(LOG_WARNING, "Asked to hangup channel not connected\n"); return 0; } - + if (ast_channel_hangupcause(ast) == AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE && is_sip_account_504_ongoing(sub->parent->invoke_context)==1 && sub->register_504_timer_count == 0){ + //chan_voicemngr_mute_connection(sub); + sub->register_504_timer_count++; + sub->register_504_timer_id = ast_sched_add(sched, 1000, register_504_cb, sub); + ast_log(LOG_NOTICE,"INIVTE got 504 with register request, waiting for response from new register request\n"); + } p = sub->parent; pvt_lock(p, "TELCHAN hangup"); sub_peer = chan_voicemngr_subchannel_get_peer(sub); @@ -1647,8 +1658,10 @@ static int chan_voicemngr_hangup(struct ast_channel *ast) sub_peer->channel_state = INCALL; } } - - memset(p->ext, 0, sizeof(p->ext)); + if(!sub->register_504_timer_count){ + // keep ext for re INVITE after re-register after 504 response with xml + memset(p->ext, 0, sizeof(p->ext)); + } sub->owner = NULL; sub->conference_initiator = 0; ast_free(sub->conference_id); @@ -1661,7 +1674,7 @@ static int chan_voicemngr_hangup(struct ast_channel *ast) /* Check for channel state before dial tone timeout */ if (sub->channel_state == CALLENDED && sub_peer->channel_state != INCALL && p->dialtone != DIALTONE_BUSY - && sub->channel_state != TRANSFERING) { + && sub->channel_state != TRANSFERING && !sub->register_504_timer_count) { /* If we hangup but not playing howler or busy, start playing timeout tones */ p->dialtone = DIALTONE_ON; handle_dialtone_timeout(p); @@ -1695,8 +1708,11 @@ static int chan_voicemngr_hangup(struct ast_channel *ast) call_cli_command(cmd, NULL, NULL); } /* reset invoke contexts */ - ast_copy_string(p->invoke_context, p->context, sizeof(p->invoke_context)); - ast_copy_string(p->invoke_context_direct, p->context_direct, sizeof(p->invoke_context_direct)); + if(!sub->register_504_timer_count){ + // keep while doing 504 re-register + ast_copy_string(p->invoke_context, p->context, sizeof(p->invoke_context)); + ast_copy_string(p->invoke_context_direct, p->context_direct, sizeof(p->invoke_context_direct)); + } pvt_unlock(p); return 0; @@ -2323,6 +2339,50 @@ static int switch_back_call_cb( const void *data) return 0; } +/* register due to 504 with xml(init-register) handler. */ +static int register_504_cb(const void *data) +{ + struct chan_voicemngr_subchannel *sub; + sub = (struct chan_voicemngr_subchannel *) data; + int res = 0; + res = is_sip_account_504_ongoing(sub->parent->invoke_context); + switch(res) { + case 0: + // registered, start calling again + ast_log(LOG_NOTICE,"register due to 504 success, start calling\n"); + sub->register_504_timer_count = 0; + sub->register_504_timer_id = -1; + ast_copy_string(sub->parent->dtmfbuf, sub->parent->ext, sizeof(sub->parent->ext)); + chan_voicemngr_start_calling(sub, sub->parent->invoke_context); + break; + case 1: + // ongoing, try again in 1s + ast_log(LOG_NOTICE,"register due to 504 ongoing\n"); + if(sub->register_504_timer_count<=33){ + // continue waiting while not reaching transaction timeout(32s)+1s delay. + sub->channel_state = CALLING; + sub->register_504_timer_id = ast_sched_add(sched, 1000, register_504_cb, sub); + sub->register_504_timer_count++; + break; + } + case 2: + // failed, play congestion tone and waiting for on-hook + sub->register_504_timer_count = 0; + sub->register_504_timer_id = -1; + ast_log(LOG_NOTICE,"register due to 504 failed\n"); + sub->parent->dialtone = DIALTONE_CONGESTION; + sub->channel_state = AWAITONHOOK; + sub->parent->dialtone_timeout_timer_id = ast_sched_add(sched, channel_config[sub->parent->line_id].offhook_nu_timeoutmsec, handle_dialtone_timeout, sub->parent); + chan_voicemngr_signal_dialtone(sub->parent); + memset(sub->parent->ext, 0, sizeof(sub->parent->ext)); + ast_copy_string(sub->parent->invoke_context, sub->parent->context, sizeof(sub->parent->invoke_context)); + ast_copy_string(sub->parent->invoke_context_direct, sub->parent->context_direct, sizeof(sub->parent->invoke_context_direct)); + break; + } + return 0; + +} + /* Hangup incoming call after call waiting times out */ static int cwtimeout_cb(const void *data) { @@ -3781,6 +3841,26 @@ static int is_sip_account_registered(const char *sip_account) return !!call_cli_command(cmd_registrations, (check_output_cb)&check_is_sip_account_registered, sip_account); } +static int check_is_sip_account_504_ongoing(const char *line, const char *sip_account) +{ + return ((strstr(line, sip_account) != NULL) && (strstr(line, "504_ongoing") != NULL)); +} +static int check_is_sip_account_504_failed(const char *line, const char *sip_account) +{ + return ((strstr(line, sip_account) != NULL) && (strstr(line, "504_failed") != NULL)); +} + +static int is_sip_account_504_ongoing(const char *sip_account) +{ + if( !!call_cli_command(cmd_registrations, (check_output_cb)&check_is_sip_account_504_ongoing, sip_account) ){ + return 1; + } + if( !!call_cli_command(cmd_registrations, (check_output_cb)&check_is_sip_account_504_failed, sip_account) ){ + return 2; + } + return 0; +} + static int check_endpoint_status(const char *line, const char *sip_account) { int ret = 1; @@ -3990,6 +4070,18 @@ static void chan_voicemngr_process_event(struct endpt_event *ev) p->busy_internal_call_timer_id = -1; } + if(sub->register_504_timer_id != -1) { + // user hangup before 504 register got any final result, cancel the timer and reset the extension/context memory. + if (ast_sched_del(sched, sub->register_504_timer_id)) { + ast_log(LOG_WARNING, "Failed to remove scheduled 504 register timer\n"); + } + sub->register_504_timer_id = -1; + sub->register_504_timer_count = 0; + memset(sub->parent->ext, 0, sizeof(sub->parent->ext)); + ast_copy_string(sub->parent->invoke_context, sub->parent->context, sizeof(sub->parent->invoke_context)); + ast_copy_string(sub->parent->invoke_context_direct, sub->parent->context_direct, sizeof(sub->parent->invoke_context_direct)); + } + if (sub->owner && sub->audio_announcement == AUDIO_ANNOUNCEMENT_STARTED) { ast_stopstream(sub->owner); sub->audio_announcement = AUDIO_ANNOUNCEMENT_STOPPING; @@ -4243,6 +4335,8 @@ static struct chan_voicemngr_pvt *chan_voicemngr_allocate_pvt(void) sub->congestion_timer_id = -1; sub->audio_announcement_count = 0; sub->audio_announcement = AUDIO_ANNOUNCEMENT_STOPPED; + sub->register_504_timer_count = 0; + sub->register_504_timer_id = -1; sub->sip_client_id = -1; sub->is_internal = false; sub->period = default_ptime; // 20 ms diff --git a/src/channels/chan_voicemngr.h b/src/channels/chan_voicemngr.h index 898b9abcc7b2b1cc895d223aaa5e2ba62cfb23dc..93fb2ea287f237443f27d2825fdcabfe0725a136 100644 --- a/src/channels/chan_voicemngr.h +++ b/src/channels/chan_voicemngr.h @@ -197,6 +197,8 @@ struct chan_voicemngr_subchannel { int congestion_timer_id; int audio_announcement_count; audio_announcement_state audio_announcement; + int register_504_timer_count; + int register_504_timer_id; }; struct chan_voicemngr_channel_tech {