diff --git a/src/channels/chan_voicemngr.c b/src/channels/chan_voicemngr.c index 93dbc52f3ec0964c75840a63567246500d6659f8..6f45cc1d60624f3b7e50cea6f307205847b86a2e 100644 --- a/src/channels/chan_voicemngr.c +++ b/src/channels/chan_voicemngr.c @@ -274,14 +274,13 @@ typedef struct shared_context { } share_context_t; static struct shared_context ctxs[MAX_CONTEXTS]; -static struct ubus_context *get_shared_context(const char *func) { - +static struct ubus_context *get_shared_context(const char *func) +{ int tid = ast_get_tid(); // loop through all the contexts looking for our thread for(int i=0; i < MAX_CONTEXTS; i++) { if (ctxs[i].tid == tid) { - ast_log(LOG_DEBUG, "tid=%d, existing context %d for %s", tid, i, func); ctxs[i].last_used = time(NULL); return ctxs[i].ctx; } @@ -290,7 +289,6 @@ static struct ubus_context *get_shared_context(const char *func) { // housekeeping - close contexts that haven't been used in over 5 minutes for(int i=0; i < MAX_CONTEXTS; i++) { if (ctxs[i].tid != 0 && ctxs[i].last_used < time(NULL) - 300) { - ast_log(LOG_DEBUG, "tid=%d, expiring context %d", tid, i); ast_ubus_free_context(ctxs[i].ctx); ctxs[i].tid = 0; ctxs[i].last_used = 0; @@ -301,27 +299,21 @@ static struct ubus_context *get_shared_context(const char *func) { // no match, loop through looking for a spare slot and create // a new context, expiring old ones for(int i=0; i < MAX_CONTEXTS; i++) { - // reused old one (after 3 minutes) if (ctxs[i].tid != 0 && ctxs[i].last_used < time(NULL) - 180) { ctxs[i].tid = ast_get_tid(); ctxs[i].last_used = time(NULL); - - ast_log(LOG_VERBOSE, "tid=%d, reuse context %d for %s", ast_get_tid(), i, func); return ctxs[i].ctx; } if (ctxs[i].tid == 0) { - ctxs[i].ctx = ubus_connect(NULL); if (!ctxs[i].ctx) { - ast_log(LOG_WARNING, "failed to create context"); + ast_log(LOG_ERROR, "failed to create context"); return NULL; } ctxs[i].tid = ast_get_tid(); ctxs[i].last_used = time(NULL); - - ast_log(LOG_VERBOSE, "tid=%d, new context %d for %s", ast_get_tid(), i, func); return ctxs[i].ctx; } } @@ -331,11 +323,8 @@ static struct ubus_context *get_shared_context(const char *func) { int oldest_time = 0; for(int i=0; i < MAX_CONTEXTS; i++) { - ast_log(LOG_VERBOSE, "tid=%d, context %d, last_used=%jd", ast_get_tid(), i, (intmax_t)ctxs[i].last_used); - if (ctxs[i].last_used != 0) { int diff = time(NULL) - ctxs[i].last_used; - ast_log(LOG_VERBOSE, "tid=%d, context %d, diff=%d", ast_get_tid(), i, diff); if (diff > oldest_time) { ctx_id = i; @@ -347,12 +336,9 @@ static struct ubus_context *get_shared_context(const char *func) { if (ctx_id != -1) { ctxs[ctx_id].tid = ast_get_tid(); ctxs[ctx_id].last_used = time(NULL); - - ast_log(LOG_VERBOSE, "tid=%d, reusing oldest context %d for %s", ast_get_tid(), ctx_id, func); return ctxs[ctx_id].ctx; } - ast_log(LOG_WARNING, "tid=%d, no contexts available", ast_get_tid()); return NULL; } @@ -646,7 +632,8 @@ static int pvt_unlock_silent(struct chan_voicemngr_pvt *pvt) #endif // Get call_id state based on the call_id value -static callid_state get_callid_state(int call_id) { +static callid_state get_callid_state(int call_id) +{ if (call_id <= CALLID_INVALID) return CALLID_INVALID; else if (call_id == CALLID_OBTAINING) @@ -657,7 +644,8 @@ static callid_state get_callid_state(int call_id) { // Get the voicemngr ubus address. It's dynamically updated // by another thread without locking. -static uint32_t get_ubus_endpt_id(int log) { +static uint32_t get_ubus_endpt_id(int log) +{ if (!endpt_id) { if (ubus_lookup_id(get_shared_context(__FUNCTION__), endpt_ubus_path, (uint32_t*)&endpt_id) != UBUS_STATUS_OK) { if (log) @@ -672,57 +660,59 @@ static uint32_t get_ubus_endpt_id(int log) { // Callback for: a ubus call (invocation) has replied with some data static void ubus_call_answer(struct ubus_request *req, int type, struct blob_attr *msg) { - ast_verbose("%s() from thread %d\n", __func__, ast_get_tid()); + return; } // Callback for: a ubus call (invocation) has finished static void ubus_call_complete(struct ubus_request *req, int ret) { - ast_verbose("%s() from thread %d\n", __func__, ast_get_tid()); - free(req); + ast_free(req); } -static void endpt_signal(int line, char *signal, char *state, char *data) { +static void endpt_signal(int line, char *signal, char *state, char *data) +{ struct blob_buf bb; struct ubus_request *req; int res; - ast_debug(5, "line = %d, signal = %s, state = %s, data = %s\n", line, signal, state, data); - - if (endpt_id) { - memset(&bb, 0, sizeof(bb)); - if(blob_buf_init(&bb, 0)) { - return; - } + if (!endpt_id) { + ast_log(LOG_ERROR, "endpt_id is 0\n"); + return; + } - blobmsg_add_u32(&bb, "line", line); - blobmsg_add_string(&bb, "signal", signal); - blobmsg_add_string(&bb, "state", state); - if (data) - blobmsg_add_string(&bb, "data", data); + memset(&bb, 0, sizeof(bb)); + if(blob_buf_init(&bb, 0)) { + return; + } - req = calloc(1, sizeof(struct ubus_request)); - if (!req) { - blob_buf_free(&bb); - return; - } + blobmsg_add_u32(&bb, "line", line); + blobmsg_add_string(&bb, "signal", signal); + blobmsg_add_string(&bb, "state", state); + if (data) + blobmsg_add_string(&bb, "data", data); - ast_verbose("thread %d: ubus call endpt signal\n", ast_get_tid()); - res = ubus_invoke_async(get_shared_context(__FUNCTION__), endpt_id, "signal", bb.head, req); + req = ast_calloc(1, sizeof(struct ubus_request)); + if (!req) { + blob_buf_free(&bb); + return; + } - if(res != UBUS_STATUS_OK) { - ast_log(LOG_ERROR, "Error invoking method: %s %d\n", "signal", res); - free(req); - blob_buf_free(&bb); - return; - } + ast_debug(3, "thread %d invoking ubus call endpt signal {line:%d,sginal:%s,state:%s,data:%s}\n", + ast_get_tid(), line, signal, state, data ? data : ""); + res = ubus_invoke_async(get_shared_context(__FUNCTION__), endpt_id, "signal", bb.head, req); - req->data_cb = ubus_call_answer; - req->complete_cb = ubus_call_complete; - req->priv = NULL; - ubus_complete_request_async(get_shared_context(__FUNCTION__), req); + if(res != UBUS_STATUS_OK) { + ast_log(LOG_ERROR, "Error invoking method: %s %d\n", "signal", res); + ast_free(req); blob_buf_free(&bb); + return; } + + req->data_cb = ubus_call_answer; + req->complete_cb = ubus_call_complete; + req->priv = NULL; + ubus_complete_request_async(get_shared_context(__FUNCTION__), req); + blob_buf_free(&bb); } static int chan_voicemngr_send_ubus_event(char *ev_name, int line) @@ -743,73 +733,79 @@ static int chan_voicemngr_send_ubus_event(char *ev_name, int line) } blob_buf_free(&blob); - return res; } -static void endpt_connection_data(int line, int id, const char *action, const struct config_update_struct *data){ +static void endpt_connection_data(int line, int id, const char *action, const struct config_update_struct *data) +{ struct blob_buf bb; struct ubus_request *req; int res; - if (endpt_id) { - memset(&bb, 0, sizeof(bb)); - if(blob_buf_init(&bb, 0)) { - return; - } + if (!endpt_id) { + ast_log(LOG_ERROR, "endpt_id is 0\n"); + return; + } - blobmsg_add_u32(&bb, "line", line); - blobmsg_add_u32(&bb, "id", id); - blobmsg_add_string(&bb, "action", action); + memset(&bb, 0, sizeof(bb)); + if(blob_buf_init(&bb, 0)) { + return; + } - if (data){ - ast_log(LOG_NOTICE, "connection parm_update, codec: %d, ptime: %d",data->codec, data->ptime); - if (data->mask & UBUS_DATA_CODEC_BIT){ - blobmsg_add_u32(&bb, "codec", data->codec); - } - if (data->mask & UBUS_DATA_PTIME_BIT){ - blobmsg_add_u32(&bb, "ptime", data->ptime); - } - } + blobmsg_add_u32(&bb, "line", line); + blobmsg_add_u32(&bb, "id", id); + blobmsg_add_string(&bb, "action", action); - req = calloc(1, sizeof(struct ubus_request)); - if (!req) { - blob_buf_free(&bb); - return; + if (data) { + ast_log(LOG_NOTICE, "connection parm_update, codec: %d, ptime: %d",data->codec, data->ptime); + if (data->mask & UBUS_DATA_CODEC_BIT) { + blobmsg_add_u32(&bb, "codec", data->codec); } - ast_verbose("thread %d: ubus call endpt connection\n", ast_get_tid()); - res = ubus_invoke_async(get_shared_context(__FUNCTION__), endpt_id, "connection", bb.head, req); - - if(res != UBUS_STATUS_OK) { - ast_log(LOG_ERROR, "Error invoking method: %s %d\n", "connection", res); - free(req); - blob_buf_free(&bb); - return; + if (data->mask & UBUS_DATA_PTIME_BIT) { + blobmsg_add_u32(&bb, "ptime", data->ptime); } + } - req->data_cb = ubus_call_answer; - req->complete_cb = ubus_call_complete; - req->priv = NULL; - ubus_complete_request_async(get_shared_context(__FUNCTION__), req); + req = ast_calloc(1, sizeof(struct ubus_request)); + if (!req) { blob_buf_free(&bb); + return; } + ast_verbose("thread %d: ubus call endpt connection\n", ast_get_tid()); + res = ubus_invoke_async(get_shared_context(__FUNCTION__), endpt_id, "connection", bb.head, req); + + if(res != UBUS_STATUS_OK) { + ast_log(LOG_ERROR, "Error invoking method: %s %d\n", "connection", res); + ast_free(req); + blob_buf_free(&bb); + return; + } + + req->data_cb = ubus_call_answer; + req->complete_cb = ubus_call_complete; + req->priv = NULL; + ubus_complete_request_async(get_shared_context(__FUNCTION__), req); + blob_buf_free(&bb); } -static void endpt_connection(int line, int id, char *action) { +static void endpt_connection(int line, int id, char *action) +{ endpt_connection_data(line, id, action, NULL); } -static void chan_voicemngr_modify_codec(struct chan_voicemngr_subchannel *sub) { +static void chan_voicemngr_modify_codec(struct chan_voicemngr_subchannel *sub) +{ if (sub->owner && sub->updated_codec != 1 ) { - ast_debug(4, "sub->owner Channel %s, ast_channel_codec_get(): %s\n",ast_channel_name(sub->owner), ast_channel_codec_get(sub->owner)); + ast_debug(4, "sub->owner Channel %s, ast_channel_codec_get(): %s\n", + ast_channel_name(sub->owner), ast_channel_codec_get(sub->owner)); ast_channel_lock(sub->owner); struct ast_bridge *bridge = ast_channel_internal_bridge(sub->owner); ast_channel_unlock(sub->owner); struct ast_bridge_channel *bridge_channel; struct ast_channel *bridged_chan=NULL; - if(bridge){ + if(bridge) { AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { - if ( strcmp(ast_channel_name(bridge_channel->chan), ast_channel_name(sub->owner)) ){ + if ( strcmp(ast_channel_name(bridge_channel->chan), ast_channel_name(sub->owner)) ) { ast_channel_unlock(bridge_channel->chan); bridged_chan = ast_channel_get_by_name(ast_channel_name(bridge_channel->chan)); break; @@ -831,7 +827,6 @@ static void chan_voicemngr_modify_codec(struct chan_voicemngr_subchannel *sub) { //return if has no codec set return; } - ast_debug(5, "set format\n"); // we need to set caps here to avoid asterisk transcoding which break audio in some cases struct ast_format_cap *caps; caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); @@ -855,7 +850,7 @@ static void chan_voicemngr_modify_codec(struct chan_voicemngr_subchannel *sub) { data.mask = data.mask|UBUS_DATA_CODEC_BIT; } /* update ptime */ - if (ast_channel_ptime_get(sub->owner) && ast_channel_ptime_get(sub->owner) != sub->period){ + if (ast_channel_ptime_get(sub->owner) && ast_channel_ptime_get(sub->owner) != sub->period) { sub->period = ast_channel_ptime_get(sub->owner); } data.ptime = sub->period; @@ -1023,7 +1018,7 @@ static int chan_voicemngr_indicate(struct ast_channel *ast, int condition, const struct ast_bridge *bridge = ast_channel_internal_bridge(sub->owner); ast_channel_unlock(sub->owner); struct ast_bridge_channel *bridge_channel; - if(bridge){ + if(bridge) { // Find out which end party of call conference hangs up AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { if (strstr(ast_channel_name(bridge_channel->chan), "PJSIP") != NULL) { @@ -1040,7 +1035,7 @@ static int chan_voicemngr_indicate(struct ast_channel *ast, int condition, const } } sub->conference_initiator = 0; - free(sub->conference_id); + ast_free(sub->conference_id); sub->conference_id = NULL; res = 0; @@ -1119,7 +1114,7 @@ static int chan_voicemngr_indicate(struct ast_channel *ast, int condition, const break; case AST_CAUSE_NORMAL_CLEARING: if (sub->congestion_timer_id != -1) { - if(ast_sched_del(sched, sub->congestion_timer_id)){ + if(ast_sched_del(sched, sub->congestion_timer_id)) { ast_log(LOG_WARNING, "Failed to remove scheduled congestion tone timer\n"); } sub->congestion_timer_id = -1; @@ -1377,7 +1372,6 @@ static int chan_voicemngr_devicestate(const char *device_number) case DIALING: return AST_DEVICE_INUSE; case CALLING: return AST_DEVICE_INUSE; case INCALL: return AST_DEVICE_INUSE; - case ANSWER: return AST_DEVICE_INUSE; case CALLENDED: return AST_DEVICE_NOT_INUSE; case RINGING: return AST_DEVICE_RINGINUSE; case CALLWAITING: return AST_DEVICE_INUSE; @@ -1539,11 +1533,9 @@ static int chan_voicemngr_hangup(struct ast_channel *ast) ast_channel_name(ast), p->line_id, sub->connection_id, dialtone_map[p->dialtone].str, state2str(sub->channel_state), state2str(sub_peer->channel_state), sub->conf_timer_id, sub_peer->conf_timer_id); /* 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)) - { + 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) - { + 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->extensionCallStatus, "Idle", CALL_STATUS_MAX_LEN); @@ -1561,7 +1553,7 @@ static int chan_voicemngr_hangup(struct ast_channel *ast) } } - if (sub->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"); } else { @@ -1664,7 +1656,7 @@ static int chan_voicemngr_hangup(struct ast_channel *ast) memset(p->ext, 0, sizeof(p->ext)); sub->owner = NULL; sub->conference_initiator = 0; - free(sub->conference_id); + ast_free(sub->conference_id); sub->conference_id = NULL; sub->sip_client_id = -1; ast_module_unref(ast_module_info->self); @@ -1777,7 +1769,8 @@ static int chan_voicemngr_answer(struct ast_channel *ast) /* * Map RTP data header value to a codec name */ -static char* chan_voicemngr_get_codec_string(int payload_type) { +static char* chan_voicemngr_get_codec_string(int payload_type) +{ switch (payload_type) { case RTP_PT_CN: return "cn"; case -1: return "none set"; @@ -1790,8 +1783,8 @@ static char* chan_voicemngr_get_codec_string(int payload_type) { return "unknown id"; } -static int chan_voicemngr_classify_rtp_packet(int payload_type) { - +static int chan_voicemngr_classify_rtp_packet(int payload_type) +{ switch (payload_type) { case RTCP_SR: return CHAN_VOICEMNGR_RTCP_SR; case RTCP_RR: return CHAN_VOICEMNGR_RTCP_RR; @@ -1824,7 +1817,8 @@ static struct ast_frame *chan_voicemngr_read(struct ast_channel *ast) /* Handle stream events on audio_bus. Parses raw stream and calls registered packet handlers. */ -static void audio_rx_stream_handler(pe_stream_t *stream __attribute__((unused)), pe_event_t *event __attribute__((unused))) { +static void audio_rx_stream_handler(pe_stream_t *stream __attribute__((unused)), pe_event_t *event __attribute__((unused))) +{ if (pe_bus_receive(audio_rx_bus, event) < 0) { printf("audio_bus rx buffer full"); return; // Drop packets if we can't cope the pace @@ -1858,7 +1852,7 @@ static int chan_voicemngr_write(struct ast_channel *ast, struct ast_frame *frame /*packet_size = sizeof(audio_packet_t) - 1 + RTP_HEADER_SIZE + frame->datalen; CNG paket has only 1 data for the noise lvl, datalen=1*/ packet_size = sizeof(audio_packet_t) + RTP_HEADER_SIZE ; - ap = calloc(1, packet_size); + ap = ast_calloc(1, packet_size); if (!ap) { ast_log(LOG_ERROR, "Out of memory\n"); return -1; @@ -1889,13 +1883,11 @@ static int chan_voicemngr_write(struct ast_channel *ast, struct ast_frame *frame //ast_mutex_unlock(&sub->parent->lock); pvt_unlock(sub->parent); - pe_bus_send(audio_tx_bus, (uint8_t *)ap, packet_size); - free(ap); } if(frame->frametype == AST_FRAME_VOICE) { packet_size = sizeof(audio_packet_t) - 1 + RTP_HEADER_SIZE + frame->datalen; - ap = calloc(1, packet_size); + ap = ast_calloc(1, packet_size); if (!ap) { ast_log(LOG_ERROR, "Out of memory\n"); return -1; @@ -1932,14 +1924,11 @@ static int chan_voicemngr_write(struct ast_channel *ast, struct ast_frame *frame //ast_mutex_unlock(&sub->parent->lock); pvt_unlock(sub->parent); chan_voicemngr_modify_codec(sub); //in case of early media on outgoing - - pe_bus_send(audio_tx_bus, (uint8_t *)ap, packet_size); - free(ap); } if(frame->frametype == AST_FRAME_RTCP) { packet_size = sizeof(audio_packet_t) - 1 + frame->datalen; - ap = calloc(1, packet_size); + ap = ast_calloc(1, packet_size); if (!ap) { ast_log(LOG_ERROR, "Out of memory\n"); return -1; @@ -1953,10 +1942,14 @@ static int chan_voicemngr_write(struct ast_channel *ast, struct ast_frame *frame memcpy(ap->rtp, frame->data.ptr, frame->datalen); chan_voicemngr_process_incoming_rtcp_packet(sub, ap->rtp, ap->rtp_size); + } + if (ap) { pe_bus_send(audio_tx_bus, (uint8_t *)ap, packet_size); - free(ap); + ast_free(ap); } + + return 0; } @@ -1976,7 +1969,6 @@ static char *state2str(enum chan_voicemngr_channel_state state) case DIALING: return "DIALING"; case CALLING: return "CALLING"; case INCALL: return "INCALL"; - case ANSWER: return "ANSWER"; case CALLENDED: return "CALLENDED"; case RINGING: return "RINGING"; case CALLWAITING: return "CALLWAITING"; @@ -2005,8 +1997,8 @@ struct chan_voicemngr_subchannel *chan_voicemngr_subchannel_get_peer(const struc } /* Tell endpoint to play country specific dialtone. */ -static int chan_voicemngr_signal_dialtone(struct chan_voicemngr_pvt *p) { - +static int chan_voicemngr_signal_dialtone(struct chan_voicemngr_pvt *p) +{ ast_verbose("Setting dialtone to %s\n", dialtone_map[p->dialtone].str); switch (p->dialtone) { case DIALTONE_OFF: @@ -2039,7 +2031,8 @@ static int chan_voicemngr_signal_dialtone(struct chan_voicemngr_pvt *p) { return 0; } -static void chan_voicemngr_signal_howler(struct chan_voicemngr_pvt *p) { +static void chan_voicemngr_signal_howler(struct chan_voicemngr_pvt *p) +{ struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); if(!sub) { @@ -2060,7 +2053,8 @@ static void chan_voicemngr_signal_howler(struct chan_voicemngr_pvt *p) { chan_voicemngr_new(sub, AST_STATE_RING, "0", "howler", NULL, NULL, NULL); } -int chan_voicemngr_stop_dialtone(struct chan_voicemngr_pvt *p) { +int chan_voicemngr_stop_dialtone(struct chan_voicemngr_pvt *p) +{ p->dialtone = DIALTONE_OFF; chan_voicemngr_signal_dialtone(p); chan_voicemngr_send_ubus_event("DIALTONE_OFF",p->line_id); @@ -2100,7 +2094,7 @@ static struct ast_channel *chan_voicemngr_new(struct chan_voicemngr_subchannel * ast_channel_set_rawwriteformat(chan, fmt); ast_channel_set_readformat(chan, fmt); ast_channel_set_rawreadformat(chan, fmt); - if (subchan->call_direction != OUTGOING_CALL){ + if (subchan->call_direction != OUTGOING_CALL) { // set default codec for incoming call to avoid transcoding ast_channel_codec_set(chan, ast_format_get_name(fmt)); ast_log(LOG_NOTICE, "set local codec to :%s \n", ast_channel_codec_get(chan)); @@ -2142,7 +2136,8 @@ static struct ast_channel *chan_voicemngr_new(struct chan_voicemngr_subchannel * } -static struct chan_voicemngr_pvt* chan_voicemngr_get_next_pvt(struct chan_voicemngr_pvt *p) { +static struct chan_voicemngr_pvt* chan_voicemngr_get_next_pvt(struct chan_voicemngr_pvt *p) +{ if (p && p->next) return p->next; else @@ -2181,17 +2176,25 @@ struct chan_voicemngr_subchannel* chan_voicemngr_get_active_subchannel(const str case TRANSFERING: case RINGBACK: sub = p->sub[i]; - return sub; + return sub; // Select this sub-channel and return right away without checking the next one + case CALLWAITING: case ONHOLD: break; + case ONHOOK: - case ANSWER: - case CALLENDED: + // This is the least active state and will be selected as the last choice if (!sub) { sub = p->sub[i]; } break; + + case CALLENDED: + /* Select this sub-channel and override the sub-channel with ONHOOK state because + * CALLENDED is more active than ONHOOK */ + sub = p->sub[i]; + break; + default: ast_log(LOG_WARNING, "Unhandled channel state %d\n", p->sub[i]->channel_state); break; @@ -2218,39 +2221,38 @@ static struct chan_voicemngr_subchannel *chan_voicemngr_get_onhold_subchannel(co /*Set up a Conference call on press of flash hook once timer expires */ static int setup_conference_call_cb( const void *data) { - struct chan_voicemngr_subchannel *sub_peer; - struct ast_channel *peer_owner = NULL; - - ast_log(LOG_NOTICE ,"Set up a conference call\n"); - struct chan_voicemngr_pvt *p = (struct chan_voicemngr_pvt *) data; - struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); - sub_peer = chan_voicemngr_subchannel_get_peer(sub); - pvt_lock(sub->parent, "setup_conference_call_cb"); - if (sub_peer->owner) { - ast_channel_ref(sub_peer->owner); - peer_owner = sub_peer->owner; - } + struct chan_voicemngr_subchannel *sub_peer; + struct ast_channel *peer_owner = NULL; - pvt_unlock(sub->parent); - /* Setup conference if no DTMF is pressed after flash ,i.e we are not waiting for DTMF now*/ - if((sub->conf_timer_id != -1) || (sub_peer->conf_timer_id != -1)) - { - sub->conf_timer_id = -1; - sub_peer->conf_timer_id = -1; - ast_log(LOG_NOTICE,"Valid flags to start a Conference Call\n"); - chan_voicemngr_create_conference(p); - if (peer_owner) { - sub_peer->channel_state = INCALL; - } - sub->channel_state = INCALL; - } + ast_log(LOG_NOTICE ,"Set up a conference call\n"); + struct chan_voicemngr_pvt *p = (struct chan_voicemngr_pvt *) data; + struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); + sub_peer = chan_voicemngr_subchannel_get_peer(sub); + pvt_lock(sub->parent, "setup_conference_call_cb"); + if (sub_peer->owner) { + ast_channel_ref(sub_peer->owner); + peer_owner = sub_peer->owner; + } - chan_voicemngr_send_ubus_event("UNHOLD",sub->parent->line_id); - chan_voicemngr_send_ubus_event("CONFERENCE_START",sub->parent->line_id); - if (peer_owner) { - ast_channel_unref(peer_owner); - } - return 0; + pvt_unlock(sub->parent); + /* Setup conference if no DTMF is pressed after flash ,i.e we are not waiting for DTMF now*/ + if((sub->conf_timer_id != -1) || (sub_peer->conf_timer_id != -1)) { + sub->conf_timer_id = -1; + sub_peer->conf_timer_id = -1; + ast_log(LOG_NOTICE,"Valid flags to start a Conference Call\n"); + chan_voicemngr_create_conference(p); + if (peer_owner) { + sub_peer->channel_state = INCALL; + } + sub->channel_state = INCALL; + } + + chan_voicemngr_send_ubus_event("UNHOLD",sub->parent->line_id); + chan_voicemngr_send_ubus_event("CONFERENCE_START",sub->parent->line_id); + if (peer_owner) { + ast_channel_unref(peer_owner); + } + return 0; } /*Switch back to held call once timer expires */ @@ -2495,10 +2497,10 @@ static void chan_voicemngr_start_calling(struct chan_voicemngr_subchannel *sub, /* Changed state from AST_STATE_UP to AST_STATE_RING ito get the chan_voicemngr_answer callback * which is needed for call waiting. */ chan_voicemngr_new(sub, AST_STATE_RING, sub->parent->ext, context, NULL, NULL, NULL); - if(sub->owner){ + if(sub->owner) { sub->updated_codec = 0; /* check and set the emergency call flag */ - if(check_emergency_number(channel_config[sub->parent->line_id].emergency_numbers_list, sub->parent->ext)){ + if(check_emergency_number(channel_config[sub->parent->line_id].emergency_numbers_list, sub->parent->ext)) { ast_channel_emergency_ongoing_set(sub->owner, 1); /* flag in ast_channel to add emergency headers */ ast_log(LOG_WARNING, "%s has emergency call ongoing %d \n", ast_channel_name(sub->owner), ast_channel_emergency_ongoing_get(sub->owner)); sub->parent->emergency = 1; /* flag in chan_voicemngr_pvt for local handling: ignore flash-hook, deny any incoming calls */ @@ -2575,33 +2577,31 @@ static int handle_audio_announcement_timeout(const void *data) */ static int handle_interdigit_timeout(const void *data) { - ast_debug(9, "Interdigit timeout\n"); - struct chan_voicemngr_pvt *p = (struct chan_voicemngr_pvt *) data; - //ast_mutex_lock(&p->lock); + struct chan_voicemngr_pvt *p = (struct chan_voicemngr_pvt *)data; pvt_lock(p, "interdigit callback"); p->interdigit_timer_id = -1; struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); - if (channel_config[p->line_id].minimumnumberdigits && strlen(p->dtmfbuf) >= channel_config[p->line_id].minimumnumberdigits){ - if (ast_exists_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num)) - { - //We have at least one matching extension in "normal" context, - //and interdigit timeout has passed, so have asterisk start calling. - //Asterisk will select the best matching extension if there are more than one possibility. - ast_debug(9, "Interdigit timeout, extension(s) matching %s found\n", p->dtmfbuf); - chan_voicemngr_start_calling(sub, p->invoke_context); + if (channel_config[p->line_id].minimumnumberdigits && + strlen(p->dtmfbuf) >= channel_config[p->line_id].minimumnumberdigits) { + if (ast_exists_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num)) { + //We have at least one matching extension in "normal" context, + //and interdigit timeout has passed, so have asterisk start calling. + //Asterisk will select the best matching extension if there are more than one possibility. + ast_debug(9, "Interdigit timeout, extension(s) matching %s found\n", p->dtmfbuf); + chan_voicemngr_start_calling(sub, p->invoke_context); } - } - //if no limit on minimum digits check extension exits - if(!channel_config[p->line_id].minimumnumberdigits){ - if (ast_exists_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num)) - { - //We have at least one matching extension in "normal" context, - //and interdigit timeout has passed, so have asterisk start calling. - //Asterisk will select the best matching extension if there are more than one possibility. - ast_debug(9, "Interdigit timeout, extension(s) matching %s found\n", p->dtmfbuf); - chan_voicemngr_start_calling(sub, p->invoke_context); - } - } + } + + //if no limit on minimum digits check extension exits + if(!channel_config[p->line_id].minimumnumberdigits) { + if (ast_exists_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num)) { + //We have at least one matching extension in "normal" context, + //and interdigit timeout has passed, so have asterisk start calling. + //Asterisk will select the best matching extension if there are more than one possibility. + ast_debug(9, "Interdigit timeout, extension(s) matching %s found\n", p->dtmfbuf); + chan_voicemngr_start_calling(sub, p->invoke_context); + } + } //ast_mutex_unlock(&p->lock); pvt_unlock(p); return 0; @@ -2628,6 +2628,7 @@ static int handle_congestion_timeout(const void *data) pvt_unlock(sub->parent); return 0; } + /* * Start autodialing if we have an autodial extension. * Called on scheduler thread. @@ -2642,8 +2643,7 @@ static int handle_autodial_timeout(const void *data) struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); channel_settings *s = &channel_config[p->line_id]; - if (ast_exists_extension(NULL, p->invoke_context, s->autodial_ext, 1, p->cid_num)) - { + if (ast_exists_extension(NULL, p->invoke_context, s->autodial_ext, 1, p->cid_num)) { chan_voicemngr_stop_dialtone(p); ast_copy_string(p->dtmfbuf, s->autodial_ext, sizeof(p->dtmfbuf)); ast_debug(9, "Autodialing extension: %s\n", p->dtmfbuf); @@ -2666,7 +2666,6 @@ static int handle_dialtone_timeout(const void *data) strncpy(p->extensionCallStatus, "Disconnected", CALL_STATUS_MAX_LEN); //ast_mutex_lock(&p->lock); p->dialtone_timeout_timer_id = -1; - struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); ast_debug(9, "Dialtone timeout, sub->channel_state: %s\n", state2str(sub->channel_state)); @@ -2716,7 +2715,7 @@ static int handle_emergency_registration(const void *data) p->emergency_registration_timer_count++; struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); - if (is_sip_account_registered(p->invoke_context) || p->emergency_registration_timer_count > 15){ + if (is_sip_account_registered(p->invoke_context) || p->emergency_registration_timer_count > 15) { p->emergency_registration_timer_count = 0; chan_voicemngr_start_calling(sub, p->invoke_context_direct); } else { @@ -2742,8 +2741,8 @@ void handle_dtmf_calling(struct chan_voicemngr_subchannel *sub) char dtmf_last_char = p->dtmfbuf[(dtmfbuf_len - 1)]; char dtmf_first_char = p->dtmfbuf[0]; - if (ast_exists_extension(NULL, p->invoke_context_direct, p->dtmfbuf, 1, p->cid_num) && !ast_matchmore_extension(NULL, p->invoke_context_direct, p->dtmfbuf, 1, p->cid_num)) - { + if (ast_exists_extension(NULL, p->invoke_context_direct, p->dtmfbuf, 1, p->cid_num) && + !ast_matchmore_extension(NULL, p->invoke_context_direct, p->dtmfbuf, 1, p->cid_num)) { //We have a full match in the "direct" context, so have asterisk place a call immediately ast_debug(9, "Direct extension matching %s found\n", p->dtmfbuf); /* Emergency call, sip client exists but not registered */ @@ -2759,19 +2758,16 @@ void handle_dtmf_calling(struct chan_voicemngr_subchannel *sub) } else { chan_voicemngr_start_calling(sub, p->invoke_context_direct); } - } - else if (ast_exists_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num) && !ast_matchmore_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num)) - { + } else if (ast_exists_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num) && + !ast_matchmore_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num)) { //We have a full match in the "normal" context, so have asterisk place a call immediately, //since no more digits can be added to the number //(this is unlikely to happen IF there is probably a "catch-all" extension) ast_debug(9, "Unique extension matching %s found\n", p->dtmfbuf); chan_voicemngr_start_calling(sub, p->invoke_context); - } - else if (termination_digit && dtmf_last_char == termination_digit && isdigit(dtmf_first_char)) { + } else if (termination_digit && dtmf_last_char == termination_digit && isdigit(dtmf_first_char)) { ast_log(LOG_NOTICE, "Termination key %c is pressed during dialing general number\n",termination_digit); - if(channel_config[p->line_id].minimumnumberdigits && strlen(p->dtmfbuf) <= channel_config[p->line_id].minimumnumberdigits) - { + if(channel_config[p->line_id].minimumnumberdigits && strlen(p->dtmfbuf) <= channel_config[p->line_id].minimumnumberdigits) { ast_log(LOG_ERROR, "Not reached the minimum digits to start a call!! \n"); //Not reached the minimum digits //Set dialtone to Congestion, and awaiting on hook @@ -2779,9 +2775,7 @@ void handle_dtmf_calling(struct chan_voicemngr_subchannel *sub) sub->channel_state = AWAITONHOOK; p->dialtone_timeout_timer_id = ast_sched_add(sched, channel_config[p->line_id].offhook_nu_timeoutmsec, handle_dialtone_timeout, p); chan_voicemngr_signal_dialtone(p); - } - else - { + } else { //No minimum limit or reached minimum limit, Start calling if we encounter a terminatingdigit //We have a match in the "normal" context, and user ended the dialling sequence with a # or temination digit set in dialplan, //so have asterisk place a call immediately @@ -2790,8 +2784,7 @@ void handle_dtmf_calling(struct chan_voicemngr_subchannel *sub) chan_voicemngr_start_calling(sub, p->invoke_context); } - } - else if (line_invoke_checker(p->dtmfbuf, channel_config[p->line_id].lineinvoke_code) == 0){ + } else if (line_invoke_checker(p->dtmfbuf, channel_config[p->line_id].lineinvoke_code) == 0) { // line changing // get line id from code int sip_id; @@ -2823,8 +2816,7 @@ void handle_dtmf_calling(struct chan_voicemngr_subchannel *sub) p->dialtone_timeout_timer_id = ast_sched_add(sched, channel_config[p->line_id].offhook_nu_timeoutmsec, handle_dialtone_timeout, p); chan_voicemngr_signal_dialtone(p); } - } - else if (feature_access_code_match(p->dtmfbuf) == 0) { + } else if (feature_access_code_match(p->dtmfbuf) == 0) { ast_log(LOG_NOTICE, "extension %s found, start dialing\n", p->dtmfbuf); if (SPEEDDIAL_IS_ERASE_FEATURE_CODE(p->dtmfbuf)) { @@ -2833,9 +2825,8 @@ void handle_dtmf_calling(struct chan_voicemngr_subchannel *sub) } sub->is_internal = true; chan_voicemngr_start_calling(sub, p->invoke_context); - } - else if (!ast_matchmore_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num) && line_invoke_checker(p->dtmfbuf, channel_config[p->line_id].lineinvoke_code) == -1) - { + } else if (!ast_matchmore_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num) && + line_invoke_checker(p->dtmfbuf, channel_config[p->line_id].lineinvoke_code) == -1) { //Full match has been handled in the upper conditions //Number become invalid if no ast_matchmore_extension, and not matching line inovke code. //Set dialtone to Congestion, and awaiting on hook @@ -2844,10 +2835,10 @@ void handle_dtmf_calling(struct chan_voicemngr_subchannel *sub) sub->channel_state = AWAITONHOOK; p->dialtone_timeout_timer_id = ast_sched_add(sched, channel_config[p->line_id].offhook_nu_timeoutmsec, handle_dialtone_timeout, p); chan_voicemngr_signal_dialtone(p); - } - else { + } else { int timeoutmsec = channel_config[p->line_id].timeoutmsec; - if (channel_config[p->line_id].minimumnumberdigits && strlen(p->dtmfbuf) >= channel_config[p->line_id].minimumnumberdigits && channel_config[p->line_id].interdigitopenmsec){ + if (channel_config[p->line_id].minimumnumberdigits && + strlen(p->dtmfbuf) >= channel_config[p->line_id].minimumnumberdigits && channel_config[p->line_id].interdigitopenmsec) { timeoutmsec = channel_config[p->line_id].interdigitopenmsec; } @@ -2874,8 +2865,6 @@ static void handle_Rnumber_etsi(struct chan_voicemngr_subchannel *sub, struct ch 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"); } @@ -2896,7 +2885,6 @@ static void handle_Rnumber_etsi(struct chan_voicemngr_subchannel *sub, struct ch /* 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); @@ -2938,7 +2926,6 @@ static void handle_Rnumber_etsi(struct chan_voicemngr_subchannel *sub, struct ch /* 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)) { - chan_voicemngr_mute_connection(sub); if (owner) { ast_queue_hold(owner, NULL); @@ -3062,7 +3049,7 @@ static void handle_Rkey_uk(struct chan_voicemngr_subchannel *sub, struct chan_vo if (p->sub[1]->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 (p->sub[1]->call_direction == INCOMING_CALL){ + } else if (p->sub[1]->call_direction == INCOMING_CALL) { chan_voicemngr_unmute_connection(sub_peer); ast_queue_unhold(peer_owner); sub_peer->channel_state = INCALL; @@ -3083,9 +3070,9 @@ static void handle_Rkey_uk(struct chan_voicemngr_subchannel *sub, struct chan_vo /* * Perform actions for hook flash. * Preconditions: One subchannel should be in CALLWAITING or ONHOLD, - * One subchannel should be in INCALL. - * channel locks are held - * chan_voicemngr_pvt->lock is held + * One subchannel should be in INCALL. + * channel locks are held + * chan_voicemngr_pvt->lock is held */ static void handle_hookflash(struct chan_voicemngr_subchannel *sub, struct chan_voicemngr_subchannel *sub_peer, struct ast_channel *owner, struct ast_channel *peer_owner) @@ -3110,20 +3097,20 @@ static void handle_hookflash(struct chan_voicemngr_subchannel *sub, struct chan_ p->hf_detected = 0; return; } - if(p->emergency){ + if(p->emergency) { p->hf_detected = 0; ast_log(LOG_WARNING, "Emergency call ongoing, ignore flash-hook\n"); return; } - if (sub->channel_state == INCALL){ + if (sub->channel_state == INCALL) { if (bridge && bridge->num_active > max_sessions_per_extension) { ast_log(LOG_WARNING, "Max call per extension limit exceeded [%d/%d]\n", bridge->num_active, max_sessions_per_extension); p->hf_detected = 0; return; } - } else if (sub->channel_state == CALLING && sub_peer->channel_state != ONHOLD){ + } else if (sub->channel_state == CALLING && sub_peer->channel_state != ONHOLD) { //ignore the flash hook sending from voicemngr for DECT when got 183 from IVR system and interacting through DTMF p->hf_detected = 0; return; @@ -3141,7 +3128,7 @@ static void handle_hookflash(struct chan_voicemngr_subchannel *sub, struct chan_ /* Put current call on hold */ if (owner) { - if(bridge){ + if(bridge) { AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { if ((strstr(ast_channel_name(bridge_channel->chan), "TELCHAN") != NULL) && (strcmp(ast_channel_name(bridge_channel->chan), ast_channel_name(owner)))) { // only indicate other local channels, as asterisk will handle the pjsip channels with the queued frame. @@ -3186,7 +3173,7 @@ static void handle_hookflash(struct chan_voicemngr_subchannel *sub, struct chan_ /* Pick up old */ if (peer_owner) { - if(bridge){ + if(bridge) { AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { if ((strstr(ast_channel_name(bridge_channel->chan), "TELCHAN") != NULL) && (strcmp(ast_channel_name(bridge_channel->chan), ast_channel_name(peer_owner)))) { // only indicate other local channels, as asterisk will handle the pjsip channels with the queued frame. @@ -3246,15 +3233,15 @@ static void handle_dect_event(struct chan_voicemngr_subchannel *sub, struct chan { struct chan_voicemngr_pvt *p = sub->parent; - ast_log(LOG_NOTICE, "%s sub->channel_state = %d, sub_peer->channel_state = %d\n", __func__, sub->channel_state, sub_peer->channel_state); + ast_log(LOG_NOTICE, "%s sub->channel_state = %d, sub_peer->channel_state = %d\n", + __func__, sub->channel_state, sub_peer->channel_state); if (event == EVENT_JOIN) { ast_log(LOG_NOTICE, "Join detected for phone line %d\n", sub->parent->line_id); // Start 3way call conference if (sub->channel_state == INCALL && sub_peer->channel_state == ONHOLD) sub->conf_timer_id = ast_sched_add(sched, dtmf_wait_timer, setup_conference_call_cb, p); - } - else if (event == EVENT_SWITCH) { + } else if (event == EVENT_SWITCH) { ast_log(LOG_NOTICE, "Switch detected for phone line %d\n", sub->parent->line_id); // Toggle calls if (sub->channel_state == INCALL && sub_peer->channel_state == ONHOLD) { @@ -3266,11 +3253,22 @@ static void handle_dect_event(struct chan_voicemngr_subchannel *sub, struct chan ast_queue_hold(owner, NULL); sub->channel_state = ONHOLD; } - } - else if (event == EVENT_RELEASE) { + } else if (event == EVENT_RELEASE) { ast_log(LOG_NOTICE, "EVENT_RELEASE detected for phone line %d\n", sub->parent->line_id); - if (sub->channel_state == AWAITONHOOK && sub_peer->channel_state == ONHOOK) { + + // Delete timer + if (sub->congestion_timer_id != -1) { + if(ast_sched_del(sched, sub->congestion_timer_id)){ + ast_log(LOG_WARNING, "Failed to remove scheduled congestion tone timer\n"); + } + sub->congestion_timer_id = -1; + } + + // Update state + if (sub->channel_state == AWAITONHOOK && (sub_peer->channel_state == ONHOOK || sub_peer->channel_state == CALLENDED)) { chan_voicemngr_close_connection(sub); + sub->channel_state = ONHOOK; + sub_peer->channel_state = ONHOOK; } else if (sub->channel_state == INCALL && sub_peer->channel_state != CALLWAITING) { ast_log(LOG_ERROR, "Hanging up call\n"); ast_queue_control(owner, AST_CONTROL_HANGUP); @@ -3334,14 +3332,8 @@ static void handle_dtmf(enum LINE_EVENT event, handle_hookflash(sub, sub_peer, owner, peer_owner); } else { /* HF while not in a call doesn't make sense */ - ast_debug(2, "DTMF after HF while not in call. \ - state: %d, \ - callwaiting: %d, \ - onhold: %d, \ - conference: %d\n", - sub->channel_state, - chan_voicemngr_in_callwaiting(p), - chan_voicemngr_in_onhold(p), + ast_debug(2, "DTMF after HF while not in call. state: %d, callwaiting: %d, onhold: %d, conference: %d\n", + sub->channel_state, chan_voicemngr_in_callwaiting(p), chan_voicemngr_in_onhold(p), chan_voicemngr_in_conference(p)); } } else { @@ -3379,7 +3371,8 @@ static void handle_dtmf(enum LINE_EVENT event, } } -static void send_outgoing_dtmf(struct ast_channel *owner, char dtmf_button, int frametype) { +static void send_outgoing_dtmf(struct ast_channel *owner, char dtmf_button, int frametype) +{ struct ast_frame frame; if (!owner) return; @@ -3404,7 +3397,8 @@ static void send_outgoing_dtmf(struct ast_channel *owner, char dtmf_button, int } /* Get asterisk format from RTP payload type */ -static struct ast_format *map_rtptype_to_format(uint8_t payload_type) { +static struct ast_format *map_rtptype_to_format(uint8_t payload_type) +{ for (int i=0; i<VOICEMNGR_CODECS_NUM; i++) if (voicemngr_codecs[i].rtp_payload_type == payload_type) return *voicemngr_codecs[i].ast_format; @@ -3413,7 +3407,8 @@ static struct ast_format *map_rtptype_to_format(uint8_t payload_type) { return ast_format_ulaw; } -static struct ast_format *map_rtpname_to_format(char* name) { +static struct ast_format *map_rtpname_to_format(char* name) +{ for (int i=0; i<VOICEMNGR_CODECS_NUM; i++) if (!strcmp(voicemngr_codecs[i].name,name)) return *voicemngr_codecs[i].ast_format; @@ -3423,7 +3418,8 @@ static struct ast_format *map_rtpname_to_format(char* name) { } /* Handle audio packets from voicemngr. */ -static void audio_packet_handler(pe_packet_t *p) { +static void audio_packet_handler(pe_packet_t *p) +{ struct chan_voicemngr_subchannel *sub; int packet_type = CHAN_VOICEMNGR_UNKNOWN, drop_frame = 0; audio_packet_t *ap = (audio_packet_t *)p->data; @@ -3441,7 +3437,8 @@ static void audio_packet_handler(pe_packet_t *p) { pvt = chan_voicemngr_get_pvt_from_lineid(iflist, ap->line); sub = chan_voicemngr_get_active_subchannel(pvt); if (!pvt || !sub) { - ast_log(LOG_ERROR, "Failed to find subchannel for %s/%d/%d\n", frame.src, ap->line, ap->connection_id); + ast_log(LOG_DEBUG, "Failed to find sub-channel for %s/%d/%d. Maybe the call has been ended\n", + frame.src, ap->line, ap->connection_id); endpt_connection(ap->line, ap->connection_id, "destroy"); // Request line close return; } @@ -3470,7 +3467,8 @@ static void audio_packet_handler(pe_packet_t *p) { frame.subclass.integer = ap->rtp[12]; } else if (sub->channel_state == OFFHOOK || sub->channel_state == DIALING - || (owner && !ast_strlen_zero(ast_channel_codec_get(owner)) && strcmp(chan_voicemngr_get_codec_string(payload_type),ast_channel_codec_get(owner)))){ + || (owner && !ast_strlen_zero(ast_channel_codec_get(owner)) && + strcmp(chan_voicemngr_get_codec_string(payload_type),ast_channel_codec_get(owner)))) { drop_frame=1; } else { struct ast_format *format = map_rtptype_to_format(payload_type); @@ -3549,40 +3547,40 @@ static int chan_voicemngr_should_relay_dtmf(const struct chan_voicemngr_subchann */ static void *call_cli_command(const char *cmd, check_output_cb check_output, const char *data) { - void *res = NULL; - char template[] = "/tmp/ast-chan_voicemngr-XXXXXX"; /* template for temporary file */ - char line[160]; - int fd_temp = -1; - FILE *fp = NULL; - - if ((fd_temp = mkstemp(template)) < 0) { - ast_log(LOG_ERROR, "Failed to create temporary file for command \"%s\": %s\n", - cmd, strerror(errno)); - return res; - } - - if (ast_cli_command(fd_temp, cmd) == 0) { - close(fd_temp); - fd_temp = -1; - - fp = fopen(template, "r"); - if (fp) { - while (fgets(line, sizeof(line), fp) != NULL) { - if ((res = (*check_output)(line, data))) { - break; - } - } - } - } else { - ast_log(LOG_ERROR, "Execution CLI \"%s\" failed\n", cmd); - } - - if (fd_temp >= 0) - close(fd_temp); - if (fp) - fclose(fp); - unlink(template); - return res; + void *res = NULL; + char template[] = "/tmp/ast-chan_voicemngr-XXXXXX"; /* template for temporary file */ + char line[160]; + int fd_temp = -1; + FILE *fp = NULL; + + if ((fd_temp = mkstemp(template)) < 0) { + ast_log(LOG_ERROR, "Failed to create temporary file for command \"%s\": %s\n", + cmd, strerror(errno)); + return res; + } + + if (ast_cli_command(fd_temp, cmd) == 0) { + close(fd_temp); + fd_temp = -1; + + fp = fopen(template, "r"); + if (fp) { + while (fgets(line, sizeof(line), fp) != NULL) { + if ((res = (*check_output)(line, data))) { + break; + } + } + } + } else { + ast_log(LOG_ERROR, "Execution CLI \"%s\" failed\n", cmd); + } + + if (fd_temp >= 0) + close(fd_temp); + if (fp) + fclose(fp); + unlink(template); + return res; } static int mwi_has_messages(const char *line, const char *data) @@ -3624,13 +3622,11 @@ static int mwi_check(const char *sip_account) static int check_endpoint_cw_enabled(const char *line, const char *data) { return (strstr(line, "call_waiting_enabled") != NULL && strstr(line, "true") != NULL); - } static int check_endpoint_state_in_use(const char *line, const char *data) { return (strstr(line, "Endpoint:") != NULL && strstr(line, "In use") != NULL); - } static int is_call_waiting_enabled(const char *sip_account) @@ -3853,7 +3849,7 @@ static void chan_voicemngr_process_event(struct endpt_event *ev) case EVENT_ONHOOK: { strncpy(p->extensionCallStatus, "Idle", CALL_STATUS_MAX_LEN); if (sub->congestion_timer_id != -1) { - if(ast_sched_del(sched, sub->congestion_timer_id)){ + if(ast_sched_del(sched, sub->congestion_timer_id)) { ast_log(LOG_WARNING, "Failed to remove scheduled congestion tone timer\n"); } sub->congestion_timer_id = -1; @@ -3971,7 +3967,6 @@ static void chan_voicemngr_process_event(struct endpt_event *ev) case EVENT_DTMFB: case EVENT_DTMFC: case EVENT_DTMFD: - { if (sub->audio_announcement == AUDIO_ANNOUNCEMENT_STOPPING || sub->audio_announcement == AUDIO_ANNOUNCEMENT_STOPPED) { @@ -3991,8 +3986,6 @@ static void chan_voicemngr_process_event(struct endpt_event *ev) } } break; - } - case EVENT_FLASH: p->hf_detected = 1; handle_hookflash(sub, sub_peer, owner, peer_owner); @@ -4159,7 +4152,8 @@ static struct chan_voicemngr_pvt *chan_voicemngr_allocate_pvt(void) } -static void chan_voicemngr_create_pvts(struct chan_voicemngr_pvt *p, int mode) { +static void chan_voicemngr_create_pvts(struct chan_voicemngr_pvt *p, int mode) +{ int i; struct chan_voicemngr_pvt *tmp = iflist; struct chan_voicemngr_pvt *tmp_next; @@ -4658,7 +4652,6 @@ static char *chan_voicemngr_set_autodial_extension(struct ast_cli_entry *e, int return CLI_SUCCESS; } - /*! \brief Channel CLI commands definition */ static struct ast_cli_entry cli_chan_voicemngr[] = { AST_CLI_DEFINE(chan_voicemngr_show_status, "Show chan_voicemngr status"), @@ -4669,7 +4662,6 @@ static struct ast_cli_entry cli_chan_voicemngr[] = { AST_CLI_DEFINE(chan_voicemngr_reload, "Reload chan_voicemngr configuration"), }; - static int unload_module(void) { struct chan_voicemngr_pvt *p, *pl; @@ -4696,7 +4688,7 @@ static int unload_module(void) ast_mutex_lock(&p->lock); } } - free(registration_change_sub); + ast_free(registration_change_sub); registration_change_sub = NULL; pvt_unlock(p); //ast_mutex_unlock(&p->lock); @@ -4760,7 +4752,7 @@ static int unload_module(void) */ static channel_settings channel_settings_create(void) { - channel_settings line_conf = (channel_settings){ + channel_settings line_conf = (channel_settings) { .enabled = 1, .language = "", .cid_num = "", @@ -4778,8 +4770,8 @@ static channel_settings channel_settings_create(void) .offhook_silence_timeoutmsec = 180000, .do_not_disturb = 0, .calleridenable = 0, //clip - .calleridnameenable = 0, //cnip - .anonymouscallenable = 0, //clir + .calleridnameenable = 0, //cnip + .anonymouscallenable = 0, //clir .flashSpec = 0, .second_dial_tone = DIALTONE_ON, .emergency_numbers_list = "", @@ -4813,12 +4805,12 @@ static void channel_settings_load(channel_settings *channel_config, struct ast_v channel_config->ringsignal = ast_true(v->value)?1:0; } else if (!strcasecmp(v->name, "dialoutmsec")) { channel_config->timeoutmsec = atoi(v->value); - } else if (!strcasecmp(v->name, "interdigitopenmsec")) { - channel_config->interdigitopenmsec = atoi(v->value); - } else if (!strcasecmp(v->name, "minimumnumberdigits")) { - channel_config->minimumnumberdigits = atoi(v->value); - } else if (!strcasecmp(v->name, "terminationdigit")) { - channel_config->terminationdigit =v->value[0]; + } else if (!strcasecmp(v->name, "interdigitopenmsec")) { + channel_config->interdigitopenmsec = atoi(v->value); + } else if (!strcasecmp(v->name, "minimumnumberdigits")) { + channel_config->minimumnumberdigits = atoi(v->value); + } else if (!strcasecmp(v->name, "terminationdigit")) { + channel_config->terminationdigit =v->value[0]; } else if (!strcasecmp(v->name, "autodial_timeoutmsec")) { channel_config->autodial_timeoutmsec = atoi(v->value); } else if (!strcasecmp(v->name, "dialtone_timeoutmsec")) { @@ -4837,19 +4829,18 @@ static void channel_settings_load(channel_settings *channel_config, struct ast_v else if (!strcasecmp(v->name, "calleridenable")) { channel_config->calleridenable = ast_true(v->value)?1:0; } - else if (!strcasecmp(v->name, "calleridnameenable")) { - channel_config->calleridnameenable = ast_true(v->value)?1:0; - } - else if (!strcasecmp(v->name, "anonymouscallenable")) { - channel_config->anonymouscallenable = ast_true(v->value)?1:0; - } + else if (!strcasecmp(v->name, "calleridnameenable")) { + channel_config->calleridnameenable = ast_true(v->value)?1:0; + } + 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; - } - else if (!strcasecmp(v->name, "mwi_enabled")) { + } else if (!strcasecmp(v->name, "mwi_enabled")) { channel_config->mwi_enabled = ast_true(v->value)?1:0; } else if (!strcasecmp(v->name, "second_dial_tone")) { if (!strcasecmp(v->value, "special")) @@ -5145,8 +5136,8 @@ static void ubus_event_new_obj(struct ubus_context *ctx __attribute__((unused)), } } -static void endpt_get_count_cb(struct ubus_request *req, - int type, struct blob_attr *msg) { +static void endpt_get_count_cb(struct ubus_request *req, int type, struct blob_attr *msg) +{ struct blob_attr *tb[__MAX_ENDPOINTS]; blobmsg_parse(endpt_count_policy, __MAX_ENDPOINTS, tb, blob_data(msg), blob_len(msg)); @@ -5160,7 +5151,8 @@ static void endpt_get_count_cb(struct ubus_request *req, num_endpoints = num_fxs_endpoints + num_dect_endpoints; } -static int endpt_get_count(void) { +static int endpt_get_count(void) +{ struct blob_buf bb; int ret = 0; @@ -5185,7 +5177,8 @@ static int endpt_get_count(void) { return ((ret == UBUS_STATUS_OK) ? 0 : -1); } -static void ubus_call_answer_rtp_stats(struct ubus_request *req, int type, struct blob_attr *msg) { +static void ubus_call_answer_rtp_stats(struct ubus_request *req, int type, struct blob_attr *msg) +{ struct blob_attr *tb[__MAX_RTP_STATS]; uint16_t lineId = 0; struct chan_voicemngr_subchannel *sub = (struct chan_voicemngr_subchannel *)req->priv; @@ -5308,7 +5301,8 @@ static void ubus_call_answer_rtp_stats(struct ubus_request *req, int type, struc overruns, underruns); } -static int endpt_get_rtp_stats(struct chan_voicemngr_subchannel *sub) { +static int endpt_get_rtp_stats(struct chan_voicemngr_subchannel *sub) +{ struct blob_buf bb; int ret; @@ -5523,7 +5517,7 @@ static int asterisk_sip_client_status(struct ubus_context *ctx, struct ubus_obje struct ubus_request_data *req, const char *method, struct blob_attr *msg) { - struct blob_attr *tb[__SIP_CLIENT_MAX]; + struct blob_attr *tb[__SIP_CLIENT_MAX]; struct blob_buf blob; const char *sip_alias; char *status; @@ -5572,7 +5566,7 @@ static int asterisk_sip_force_register(struct ubus_context *ctx, struct ubus_obj blobmsg_add_string(&blob, "result", res ? : "Error"); ubus_send_reply(ctx, req, blob.head); blob_buf_free(&blob); - free(res); + ast_free(res); return UBUS_STATUS_OK; } @@ -5688,11 +5682,13 @@ static struct ubus_object asterisk_obj = { }; /* Process ubus events by ubus stack */ -static void ubus_stream_handler(pe_stream_t *stream __attribute__((unused)), pe_event_t *event __attribute__((unused))) { +static void ubus_stream_handler(pe_stream_t *stream __attribute__((unused)), pe_event_t *event __attribute__((unused))) +{ ubus_handle_event(ctx); } -static int ubus_init(void) { +static int ubus_init(void) +{ pe_stream_t *ubus_stream; for(int i=0; i < MAX_CONTEXTS; i++) { @@ -5713,24 +5709,21 @@ static int ubus_init(void) { * { "ubus.object.add": {"id":123, "path":"foo"} } */ memset(&ObjAddListener, 0, sizeof(ObjAddListener)); ObjAddListener.cb = ubus_event_new_obj; - if(ubus_register_event_handler(ctx, &ObjAddListener, - ubusStrObjAdd) != UBUS_STATUS_OK) { + if(ubus_register_event_handler(ctx, &ObjAddListener, ubusStrObjAdd) != UBUS_STATUS_OK) { printf("Error registering ubus event handler %s", ubusStrObjAdd); return -1; } memset(&ObjRmListener, 0, sizeof(ObjRmListener)); ObjRmListener.cb = ubus_event_new_obj; - if(ubus_register_event_handler(ctx, &ObjRmListener, - ubusStrObjRm) != UBUS_STATUS_OK) { + if(ubus_register_event_handler(ctx, &ObjRmListener, ubusStrObjRm) != UBUS_STATUS_OK) { printf("Error registering ubus event handler %s", ubusStrObjRm); return -1; } /* Lookup path to voicemngr AFTER registration of ubus object * event handler above. It's no error if lookup fails. */ - if(ubus_lookup_id(ctx, endpt_ubus_path, - (uint32_t*) &endpt_id) != UBUS_STATUS_OK) { + if(ubus_lookup_id(ctx, endpt_ubus_path, (uint32_t*) &endpt_id) != UBUS_STATUS_OK) { endpt_id = 0; } @@ -5748,7 +5741,8 @@ static int ubus_init(void) { } // pthread wrapper for lib picoevent dispatcher -static void *pe_base_run(void *unused) { +static void *pe_base_run(void *unused) +{ int delay; ast_verbose("thread %d started\n", ast_get_tid()); @@ -5823,7 +5817,7 @@ static int load_module(void) goto err; } - registration_change_sub = calloc(num_endpoints, sizeof(struct stasis_subscription *)); + registration_change_sub = ast_calloc(num_endpoints, sizeof(struct stasis_subscription *)); /* Setup scheduler thread */ if (!(sched = ast_sched_context_create())) { @@ -5878,7 +5872,7 @@ static int load_module(void) ast_debug(3, "The module is loaded successfully\n"); return AST_MODULE_LOAD_SUCCESS; - err: +err: ao2_ref(default_cap, -1); return AST_MODULE_LOAD_FAILURE; } @@ -5952,11 +5946,9 @@ static int parse_time_buff(const char *local_time_buff, struct ast_tm *tm_local) static const char mon_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; char mon[4] = {0}; int ret = sscanf(local_time_buff, "%*3s %3s %2d %2d:%2d:%2d %4d", mon, &tm_local->tm_mday, &tm_local->tm_hour, &tm_local->tm_min, &tm_local->tm_sec, &tm_local->tm_year); - if (ret == 6) - { + if (ret == 6) { char *pos = strstr(mon_names, mon); - if (pos) - { + if (pos) { tm_local->tm_mon = (pos - mon_names) / 3; return 0; } @@ -5964,17 +5956,16 @@ static int parse_time_buff(const char *local_time_buff, struct ast_tm *tm_local) return -1; } -static int get_timezone(const char* filepath, char* timezone, size_t size) { +static int get_timezone(const char* filepath, char* timezone, size_t size) +{ FILE *file = fopen(filepath, "r"); if (file == NULL) { return -1; } char buffer[256]; - while (fgets(buffer, sizeof(buffer), file) != NULL) - { - if (strncmp(buffer, "TZ=", 3) == 0) - { + while (fgets(buffer, sizeof(buffer), file) != NULL) { + if (strncmp(buffer, "TZ=", 3) == 0) { strncpy(timezone, buffer + 3, size - 1); timezone[size - 1] = '\0'; timezone[strcspn(timezone, "\n")] = 0; // remove trailing \n @@ -6006,17 +5997,13 @@ static int chan_voicemngr_signal_callerid(struct ast_channel *chan, struct chan_ char timezone[64] = {0}; if (get_timezone("/tmp/syscfg.db", timezone, sizeof(timezone)) == 0) - { time_translate(timezone, &local_time_buff_ptr); - } else - { + else time_translate("Europe/Berlin", &local_time_buff_ptr); - } if (parse_time_buff(local_time_buff, &local_time)) - { ast_log(LOG_WARNING, "Error parsing time_translate response\n"); - } + /* Add datetime to caller id string, format: MMDDHHMM */ sprintf(clid_string.date, "%02d%02d%02d%02d, ", @@ -6083,7 +6070,8 @@ static int chan_voicemngr_signal_callerid(struct ast_channel *chan, struct chan_ return 0; } -static int chan_voicemngr_create_connection(struct chan_voicemngr_subchannel *sub) { +static int chan_voicemngr_create_connection(struct chan_voicemngr_subchannel *sub) +{ if (!sub->connection_init) { ast_debug(1, "Creating virtual Asterisk connection for pvt line_id=%i connection_id=%d\n", sub->parent->line_id, sub->connection_id); sub->connection_init = 1; @@ -6100,11 +6088,14 @@ static int chan_voicemngr_create_connection(struct chan_voicemngr_subchannel *su sub->call_id = CALLID_OBTAINING; } - if(!chan_voicemngr_in_onhold(sub->parent) && !chan_voicemngr_in_call(sub->parent)) { // Is there another connection already? - ast_debug(1, "Creating real endpoint connection for pvt line_id=%i, connection_id: %d, call_id: %d\n", sub->parent->line_id, sub->connection_id, sub->call_id); + if(!chan_voicemngr_in_onhold(sub->parent) && !chan_voicemngr_in_call(sub->parent)) { + // Is there another connection already? + ast_debug(1, "Creating real endpoint connection for pvt line_id=%i, connection_id: %d, call_id: %d\n", + sub->parent->line_id, sub->connection_id, sub->call_id); endpt_connection(sub->parent->line_id, sub->call_id, "create"); } else if (get_callid_state(sub->call_id) == CALLID_ESTABLISHED) { - ast_debug(1, "Updating real endpoint connection for pvt line_id=%i, connection_id: %d, call_id: %d\n", sub->parent->line_id, sub->connection_id, sub->call_id); + ast_debug(1, "Updating real endpoint connection for pvt line_id=%i, connection_id: %d, call_id: %d\n", + sub->parent->line_id, sub->connection_id, sub->call_id); endpt_connection(sub->parent->line_id, sub->call_id, "update"); } } @@ -6180,12 +6171,12 @@ static int chan_voicemngr_create_conference(struct chan_voicemngr_pvt *p) if(onholdBridge && secondBridge) res = ast_bridge_merge(onholdBridge, secondBridge, 0, chanToKick, 1); while(ast_bridge_find_by_id(second->conference_id)) sched_yield(); - // SIP calls need unhold sent to the bridge as well. + // SIP calls need unhold sent to the bridge as well. astFrame.frametype = AST_FRAME_CONTROL; astFrame.subclass.integer = AST_CONTROL_UNHOLD; ast_bridge_queue_everyone_else(onholdBridge, NULL, &astFrame); pvt_unlock(second->parent); - ast_log(LOG_NOTICE,"Conference started \n"); + ast_log(LOG_NOTICE,"Conference started \n"); return res; } @@ -6218,8 +6209,8 @@ static void chan_voicemngr_attended_call_transfer(struct chan_voicemngr_subchann { struct chan_voicemngr_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)))) { + 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)) { @@ -6327,10 +6318,12 @@ static int chan_voicemngr_close_connection(struct chan_voicemngr_subchannel *sub struct chan_voicemngr_pvt *p = sub->parent; if (sub->connection_init) { - if (!chan_voicemngr_in_onhold(p) && !chan_voicemngr_in_call(p) && !chan_voicemngr_in_dialing(p) && !chan_voicemngr_in_ringback(p) && - !chan_voicemngr_in_callwaiting(p) && !chan_voicemngr_in_transferring(p)) { // Does the line have another call? - ast_debug(1, "Closing real endpoint connection line_id: %d, connection_id=%d, call_id: %d\n", p->line_id, sub->connection_id, sub->call_id); - endpt_connection(p->line_id, sub->call_id, "destroy"); + if (!chan_voicemngr_in_onhold(p) && !chan_voicemngr_in_call(p) && !chan_voicemngr_in_dialing(p) && + !chan_voicemngr_in_ringback(p) && !chan_voicemngr_in_callwaiting(p) && !chan_voicemngr_in_transferring(p)) { + // There is no other call on the line + ast_debug(1, "Closing real endpoint connection line_id: %d, connection_id=%d\n", + p->line_id, sub->connection_id); + endpt_connection(p->line_id, -1, "destroy"); } else { ast_debug(1, "Releasing connection for pvt line_id=%i connection_id=%d, call_id: %d\n", sub->parent->line_id, sub->connection_id, sub->call_id); diff --git a/src/channels/chan_voicemngr.h b/src/channels/chan_voicemngr.h index 7a8a57807d12131a0b9a6efc62a7371530f209e7..8bfc7acdd8b802ff28e1aecf8f426fcb18665ae2 100644 --- a/src/channels/chan_voicemngr.h +++ b/src/channels/chan_voicemngr.h @@ -47,7 +47,6 @@ enum chan_voicemngr_channel_state { DIALING, CALLING, INCALL, - ANSWER, CALLENDED, RINGING, CALLWAITING,