diff --git a/main/channel.c b/main/channel.c index 9d87d3e82f..e2f981f87d 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2864,201 +2864,203 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay) default: break; } return res; } int ast_answer(struct ast_channel *chan) { return __ast_answer(chan, 0); } inline int ast_auto_answer(struct ast_channel *chan) { if (ast_channel_state(chan) == AST_STATE_UP) { /* Already answered */ return 0; } return ast_answer(chan); } int64_t ast_channel_get_duration_ms(struct ast_channel *chan) { ast_assert(NULL != chan); if (ast_tvzero(ast_channel_creationtime(chan))) { return 0; } return ast_tvdiff_ms(ast_tvnow(), ast_channel_creationtime(chan)); } int ast_channel_get_duration(struct ast_channel *chan) { return (ast_channel_get_duration_ms(chan) / 1000); } int64_t ast_channel_get_up_time_ms(struct ast_channel *chan) { ast_assert(NULL != chan); if (ast_tvzero(ast_channel_answertime(chan))) { return 0; } return ast_tvdiff_ms(ast_tvnow(), ast_channel_answertime(chan)); } int ast_channel_get_up_time(struct ast_channel *chan) { return (ast_channel_get_up_time_ms(chan) / 1000); } /*! * \brief Determine whether or not we have to trigger dtmf emulating using 50 fps timer events * especially when no voice frames are received during dtmf processing (direct media or muted * sender case using SIP INFO) */ static inline int should_trigger_dtmf_emulating(struct ast_channel *chan) { if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF)) { /* We're in the middle of emulating a digit, or DTMF has been * explicitly deferred. Trigger dtmf with periodic 50 pfs timer events, then. */ return 1; } if (!ast_tvzero(*ast_channel_dtmf_tv(chan)) && ast_tvdiff_ms(ast_tvnow(), *ast_channel_dtmf_tv(chan)) < 2*AST_MIN_DTMF_GAP) { /* * We're not in the middle of a digit, but it hasn't been long enough * since the last digit, so we'll have to trigger DTMF furtheron. * Using 2 times AST_MIN_DTMF_GAP to trigger readq reading for possible * buffered next dtmf event */ return 1; } return 0; } static void deactivate_generator_nolock(struct ast_channel *chan) { if (ast_channel_generatordata(chan)) { struct ast_generator *generator = ast_channel_generator(chan); if (generator && generator->release) { generator->release(chan, ast_channel_generatordata(chan)); } ast_channel_generatordata_set(chan, NULL); ast_channel_generator_set(chan, NULL); ast_channel_set_fd(chan, AST_GENERATOR_FD, -1); ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT); ast_settimeout(chan, 0, NULL, NULL); } } void ast_deactivate_generator(struct ast_channel *chan) { ast_channel_lock(chan); deactivate_generator_nolock(chan); if (should_trigger_dtmf_emulating(chan)) { /* if in the middle of dtmf emulation keep 50 tick per sec timer on rolling */ - ast_timer_set_rate(ast_channel_timer(chan), 50); + if (ast_channel_timer(chan)) { + ast_timer_set_rate(ast_channel_timer(chan), 50); + } } ast_channel_unlock(chan); } static void generator_write_format_change(struct ast_channel *chan) { struct ast_generator *generator; ast_channel_lock(chan); generator = ast_channel_generator(chan); if (generator && generator->write_format_change) { generator->write_format_change(chan, ast_channel_generatordata(chan)); } ast_channel_unlock(chan); } static int generator_force(const void *data) { /* Called if generator doesn't have data */ void *tmp; int res; int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples) = NULL; struct ast_channel *chan = (struct ast_channel *)data; ast_channel_lock(chan); tmp = ast_channel_generatordata(chan); ast_channel_generatordata_set(chan, NULL); if (ast_channel_generator(chan)) generate = ast_channel_generator(chan)->generate; ast_channel_unlock(chan); if (!tmp || !generate) { return 0; } res = generate(chan, tmp, 0, ast_format_get_sample_rate(ast_channel_writeformat(chan)) / 50); ast_channel_lock(chan); if (ast_channel_generator(chan) && generate == ast_channel_generator(chan)->generate) { ast_channel_generatordata_set(chan, tmp); } ast_channel_unlock(chan); if (res) { ast_debug(1, "Auto-deactivating generator\n"); ast_deactivate_generator(chan); } return 0; } int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params) { int res = 0; void *generatordata = NULL; ast_channel_lock(chan); if (ast_channel_generatordata(chan)) { struct ast_generator *generator_old = ast_channel_generator(chan); if (generator_old && generator_old->release) { generator_old->release(chan, ast_channel_generatordata(chan)); } } if (gen->alloc && !(generatordata = gen->alloc(chan, params))) { res = -1; } ast_channel_generatordata_set(chan, generatordata); if (!res) { ast_settimeout(chan, 50, generator_force, chan); ast_channel_generator_set(chan, gen); } ast_channel_unlock(chan); ast_prod(chan); return res; } /*! \brief Wait for x amount of time on a file descriptor to have input. */ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception) { int winner = -1; ast_waitfor_nandfds(NULL, 0, fds, n, exception, &winner, ms); return winner; } /*! \brief Wait for x amount of time on a file descriptor to have input. */ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms) { struct timeval start = { 0 , 0 }; struct pollfd *pfds = NULL; int res; long rms; int x, y, max; int sz = nfds; struct timeval now = { 0, 0 }; struct timeval whentohangup = { 0, 0 }, diff; struct ast_channel *winner = NULL; @@ -3155,200 +3157,204 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, } for (x = 0; x < n; x++) { ast_channel_lock(c[x]); ast_clear_flag(ast_channel_flags(c[x]), AST_FLAG_BLOCKING); ast_channel_unlock(c[x]); } if (res < 0) { /* Simulate a timeout if we were interrupted */ if (errno != EINTR) { *ms = -1; } return NULL; } if (!ast_tvzero(whentohangup)) { /* if we have a timeout, check who expired */ now = ast_tvnow(); for (x = 0; x < n; x++) { if (!ast_tvzero(*ast_channel_whentohangup(c[x])) && ast_tvcmp(*ast_channel_whentohangup(c[x]), now) <= 0) { ast_test_suite_event_notify("HANGUP_TIME", "Channel: %s", ast_channel_name(c[x])); ast_channel_softhangup_internal_flag_add(c[x], AST_SOFTHANGUP_TIMEOUT); if (winner == NULL) { winner = c[x]; } } } } if (res == 0) { /* no fd ready, reset timeout and done */ *ms = 0; /* XXX use 0 since we may not have an exact timeout. */ return winner; } /* * Then check if any channel or fd has a pending event. * Remember to check channels first and fds last, as they * must have priority on setting 'winner' */ for (x = 0; x < max; x++) { res = pfds[x].revents; if (res == 0) { continue; } if (fdmap[x].chan >= 0) { /* this is a channel */ winner = c[fdmap[x].chan]; /* override previous winners */ ast_channel_lock(winner); if (res & POLLPRI) { ast_set_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION); } else { ast_clear_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION); } ast_channel_fdno_set(winner, fdmap[x].fdno); ast_channel_unlock(winner); } else { /* this is an fd */ if (outfd) { *outfd = pfds[x].fd; } if (exception) { *exception = (res & POLLPRI) ? -1 : 0; } winner = NULL; } } if (*ms > 0) { *ms -= ast_tvdiff_ms(ast_tvnow(), start); if (*ms < 0) { *ms = 0; } } return winner; } struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms) { return ast_waitfor_nandfds(c, n, NULL, 0, NULL, NULL, ms); } int ast_waitfor(struct ast_channel *c, int ms) { if (ms < 0) { do { ms = 100000; ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms); } while (!ms); } else { ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms); } return ms; } int ast_waitfordigit(struct ast_channel *c, int ms) { return ast_waitfordigit_full(c, ms, NULL, -1, -1); } int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data) { return ast_settimeout_full(c, rate, func, data, 0); } int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data, unsigned int is_ao2_obj) { int res; unsigned int real_rate = rate, max_rate; + if (!ast_channel_timer(c)) { + return -1; + } + ast_channel_lock(c); if (ast_channel_timingfd(c) == -1) { ast_channel_unlock(c); return -1; } if (!func) { rate = 0; data = NULL; } if (rate && rate > (max_rate = ast_timer_get_max_rate(ast_channel_timer(c)))) { real_rate = max_rate; } ast_debug(1, "Scheduling timer at (%u requested / %u actual) timer ticks per second\n", rate, real_rate); res = ast_timer_set_rate(ast_channel_timer(c), real_rate); if (ast_channel_timingdata(c) && ast_test_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ)) { ao2_ref(ast_channel_timingdata(c), -1); } ast_channel_timingfunc_set(c, func); ast_channel_timingdata_set(c, data); if (data && is_ao2_obj) { ao2_ref(data, 1); ast_set_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ); } else { ast_clear_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ); } if (func == NULL && rate == 0 && ast_channel_fdno(c) == AST_TIMING_FD) { /* Clearing the timing func and setting the rate to 0 * means that we don't want to be reading from the timingfd * any more. Setting c->fdno to -1 means we won't have any * errant reads from the timingfd, meaning we won't potentially * miss any important frames. */ ast_channel_fdno_set(c, -1); } ast_channel_unlock(c); return res; } int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, const char *breakon, int audiofd, int cmdfd) { struct timeval start = ast_tvnow(); int ms; /* Stop if we're a zombie or need a soft hangup */ if (ast_test_flag(ast_channel_flags(c), AST_FLAG_ZOMBIE) || ast_check_hangup(c)) return -1; /* Only look for the end of DTMF, don't bother with the beginning and don't emulate things */ ast_channel_set_flag(c, AST_FLAG_END_DTMF_ONLY); /* Wait for a digit, no more than timeout_ms milliseconds total. * Or, wait indefinitely if timeout_ms is <0. */ while ((ms = ast_remaining_ms(start, timeout_ms))) { struct ast_channel *rchan; int outfd = -1; errno = 0; /* While ast_waitfor_nandfds tries to help by reducing the timeout by how much was waited, * it is unhelpful if it waited less than a millisecond. */ rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms); if (!rchan && outfd < 0 && ms) { if (errno == 0 || errno == EINTR) continue; ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno)); ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return -1; } else if (outfd > -1) { /* The FD we were watching has something waiting */ ast_log(LOG_WARNING, "The FD we were waiting for has something waiting. Waitfordigit returning numeric 1\n"); ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return 1; } else if (rchan) { int res; struct ast_frame *f = ast_read(c); if (!f) { ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return -1; } switch (f->frametype) { case AST_FRAME_DTMF_BEGIN: break; case AST_FRAME_DTMF_END: res = f->subclass.integer; @@ -3579,201 +3585,203 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int { struct ast_frame *f = NULL; /* the return value */ int prestate; int cause = 0; struct ast_stream *stream = NULL, *default_stream = NULL; /* this function is very long so make sure there is only one return * point at the end (there are only two exceptions to this). */ ast_channel_lock(chan); /* Stop if we're a zombie or need a soft hangup */ if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) { if (ast_channel_generator(chan)) ast_deactivate_generator(chan); /* * It is possible for chan->_softhangup to be set and there * still be control frames that need to be read. Instead of * just going to 'done' in the case of ast_check_hangup(), we * need to queue the end-of-Q frame so that it can mark the end * of the read queue. If there are frames to be read, * ast_queue_control() will be called repeatedly, but will only * queue the first end-of-Q frame. */ if (ast_channel_softhangup_internal_flag(chan)) { ast_queue_control(chan, AST_CONTROL_END_OF_Q); } else { goto done; } } else { #ifdef AST_DEVMODE /* * The ast_waitfor() code records which of the channel's file * descriptors reported that data is available. In theory, * ast_read() should only be called after ast_waitfor() reports * that a channel has data available for reading. However, * there still may be some edge cases throughout the code where * ast_read() is called improperly. This can potentially cause * problems, so if this is a developer build, make a lot of * noise if this happens so that it can be addressed. * * One of the potential problems is blocking on a dead channel. */ if (ast_channel_fdno(chan) == -1) { ast_log(LOG_ERROR, "ast_read() on chan '%s' called with no recorded file descriptor.\n", ast_channel_name(chan)); } #endif } prestate = ast_channel_state(chan); if (ast_channel_timingfd(chan) > -1 && ast_channel_fdno(chan) == AST_TIMING_FD) { enum ast_timer_event res; int trigger_dtmf_emulating = should_trigger_dtmf_emulating(chan); ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION); res = ast_timer_get_event(ast_channel_timer(chan)); switch (res) { case AST_TIMING_EVENT_EXPIRED: if (ast_timer_ack(ast_channel_timer(chan), 1) < 0) { ast_log(LOG_ERROR, "Failed to acknoweldge timer in ast_read\n"); goto done; } if (ast_channel_timingfunc(chan)) { /* save a copy of func/data before unlocking the channel */ ast_timing_func_t func = ast_channel_timingfunc(chan); void *data = ast_channel_timingdata(chan); int got_ref = 0; if (data && ast_test_flag(ast_channel_flags(chan), AST_FLAG_TIMINGDATA_IS_AO2_OBJ)) { ao2_ref(data, 1); got_ref = 1; } ast_channel_fdno_set(chan, -1); ast_channel_unlock(chan); func(data); if (got_ref) { ao2_ref(data, -1); } if (trigger_dtmf_emulating) { /* * Since we're breaking out of this switch block and not * returning, we need to re-lock the channel. */ ast_channel_lock(chan); /* generate null frame to trigger dtmf emulating */ f = &ast_null_frame; break; } } else if (trigger_dtmf_emulating) { /* generate null frame to trigger dtmf emualating */ f = &ast_null_frame; break; } else { - ast_timer_set_rate(ast_channel_timer(chan), 0); + if (ast_channel_timer(chan)) { + ast_timer_set_rate(ast_channel_timer(chan), 0); + } /* generate very last null frame to trigger dtmf emulating */ f = &ast_null_frame; break; } /* cannot 'goto done' because the channel is already unlocked */ return &ast_null_frame; case AST_TIMING_EVENT_CONTINUOUS: if (AST_LIST_EMPTY(ast_channel_readq(chan)) || !AST_LIST_NEXT(AST_LIST_FIRST(ast_channel_readq(chan)), frame_list)) { ast_timer_disable_continuous(ast_channel_timer(chan)); } break; } } else if (ast_channel_fd_isset(chan, AST_GENERATOR_FD) && ast_channel_fdno(chan) == AST_GENERATOR_FD) { /* if the AST_GENERATOR_FD is set, call the generator with args * set to -1 so it can do whatever it needs to. */ void *tmp = ast_channel_generatordata(chan); ast_channel_generatordata_set(chan, NULL); /* reset to let ast_write get through */ ast_channel_generator(chan)->generate(chan, tmp, -1, -1); ast_channel_generatordata_set(chan, tmp); f = &ast_null_frame; ast_channel_fdno_set(chan, -1); goto done; } else if (ast_channel_fd_isset(chan, AST_JITTERBUFFER_FD) && ast_channel_fdno(chan) == AST_JITTERBUFFER_FD) { ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION); } /* Read and ignore anything on the alertpipe, but read only one sizeof(blah) per frame that we send from it */ if (ast_channel_internal_alert_read(chan) == AST_ALERT_READ_FATAL) { f = &ast_null_frame; goto done; } /* Check for pending read queue */ if (!AST_LIST_EMPTY(ast_channel_readq(chan))) { int skipped_dtmf_frame = 0; int skip_dtmf = should_skip_dtmf(chan); AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { /* We have to be picky about which frame we pull off of the readq because * there are cases where we want to leave DTMF frames on the queue until * some later time. */ if ( (f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END) && skip_dtmf) { skipped_dtmf_frame = 1; continue; } AST_LIST_REMOVE_CURRENT(frame_list); break; } AST_LIST_TRAVERSE_SAFE_END; if (!f) { /* There were no acceptable frames on the readq. */ f = &ast_null_frame; if (!skipped_dtmf_frame) { /* * Do not trigger alert pipe if only buffered dtmf begin or end frames * are left in the readq. */ ast_channel_alert_write(chan); } else { /* * Safely disable continous timer events if only buffered dtmf begin or end * frames are left in the readq. */ ast_timer_disable_continuous(ast_channel_timer(chan)); } } /* Interpret hangup and end-of-Q frames to return NULL */ /* XXX why not the same for frames from the channel ? */ if (f->frametype == AST_FRAME_CONTROL) { switch (f->subclass.integer) { case AST_CONTROL_HANGUP: ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_DEV); cause = f->data.uint32; /* Fall through */ case AST_CONTROL_END_OF_Q: ast_frfree(f); f = NULL; break; default: break; } } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { if (ast_channel_tech(chan) && ast_channel_tech(chan)->read_stream) { stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), f->stream_num); default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); } else { /* Since this channel driver does not support multistream determine the default stream this frame * originated from and update the frame to include it. */ stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); @@ -3871,328 +3879,328 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int if (f->subclass.integer == AST_CONTROL_ANSWER) { if (prestate == AST_STATE_UP && ast_channel_is_bridged(chan)) { ast_debug(1, "Dropping duplicate answer!\n"); ast_frfree(f); f = &ast_null_frame; } else { /* * Mark when outgoing channel answered so we can know how * long the channel has been up. */ set_channel_answer_time(chan); ast_setstate(chan, AST_STATE_UP); } } else if (f->subclass.integer == AST_CONTROL_READ_ACTION) { read_action_payload = f->data.ptr; switch (read_action_payload->action) { case AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO: ast_party_connected_line_init(&connected); ast_party_connected_line_copy(&connected, ast_channel_connected(chan)); if (ast_connected_line_parse_data(read_action_payload->payload, read_action_payload->payload_size, &connected)) { ast_party_connected_line_free(&connected); break; } ast_channel_unlock(chan); if (ast_channel_connected_line_sub(NULL, chan, &connected, 0) && ast_channel_connected_line_macro(NULL, chan, &connected, 1, 0)) { ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, read_action_payload->payload, read_action_payload->payload_size); } ast_party_connected_line_free(&connected); ast_channel_lock(chan); break; case AST_FRAME_READ_ACTION_SEND_TEXT: ast_channel_unlock(chan); ast_sendtext(chan, (const char *)read_action_payload->payload); ast_channel_lock(chan); break; case AST_FRAME_READ_ACTION_SEND_TEXT_DATA: ast_channel_unlock(chan); ast_sendtext_data(chan, (struct ast_msg_data *)read_action_payload->payload); ast_channel_lock(chan); break; } ast_frfree(f); f = &ast_null_frame; } else if (f->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE && dropnondefault) { /* The caller of this function is incapable of handling streams so we don't accept the change request * and stick to the streams currently on the channel. */ ast_channel_stream_topology_changed(chan, ast_channel_get_stream_topology(chan)); ast_frfree(f); f = &ast_null_frame; } else if (f->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_CHANGED && dropnondefault) { /* The caller of this function is incapable of handling streams so we absorb the notification that the * stream topology has changed. */ ast_frfree(f); f = &ast_null_frame; } break; case AST_FRAME_DTMF_END: send_dtmf_end_event(chan, DTMF_RECEIVED, f->subclass.integer, f->len); ast_log(LOG_DTMF, "DTMF end '%c' received on %s, duration %ld ms\n", f->subclass.integer, ast_channel_name(chan), f->len); /* Queue it up if DTMF is deferred, or if DTMF emulation is forced. */ if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF) || ast_test_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF)) { queue_dtmf_readq(chan, f); ast_frfree(f); f = &ast_null_frame; } else if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_DTMF | AST_FLAG_END_DTMF_ONLY)) { if (!ast_tvzero(*ast_channel_dtmf_tv(chan)) && ast_tvdiff_ms(ast_tvnow(), *ast_channel_dtmf_tv(chan)) < AST_MIN_DTMF_GAP) { /* If it hasn't been long enough, defer this digit */ queue_dtmf_readq(chan, f); ast_frfree(f); f = &ast_null_frame; } else { /* There was no begin, turn this into a begin and send the end later */ struct timeval tv = ast_tvnow(); f->frametype = AST_FRAME_DTMF_BEGIN; ast_set_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF); ast_channel_dtmf_digit_to_emulate_set(chan, f->subclass.integer); ast_channel_dtmf_tv_set(chan, &tv); if (f->len) { if (f->len > option_dtmfminduration) ast_channel_emulate_dtmf_duration_set(chan, f->len); else ast_channel_emulate_dtmf_duration_set(chan, option_dtmfminduration); } else ast_channel_emulate_dtmf_duration_set(chan, AST_DEFAULT_EMULATE_DTMF_DURATION); ast_log(LOG_DTMF, "DTMF begin emulation of '%c' with duration %u queued on %s\n", f->subclass.integer, ast_channel_emulate_dtmf_duration(chan), ast_channel_name(chan)); /* * Start generating 50 fps timer events (null frames) for dtmf emulating * independently from any existing incoming voice frames. * If channel generator is already activated in regular mode use these * timer events to generate null frames. */ - if (!ast_channel_generator(chan)) { + if (!ast_channel_generator(chan) && ast_channel_timer(chan)) { ast_timer_set_rate(ast_channel_timer(chan), 50); } } if (ast_channel_audiohooks(chan)) { struct ast_frame *old_frame = f; /*! * \todo XXX It is possible to write a digit to the audiohook twice * if the digit was originally read while the channel was in autoservice. */ f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f); if (old_frame != f) ast_frfree(old_frame); } } else { struct timeval now = ast_tvnow(); if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_DTMF)) { ast_log(LOG_DTMF, "DTMF end accepted with begin '%c' on %s\n", f->subclass.integer, ast_channel_name(chan)); ast_clear_flag(ast_channel_flags(chan), AST_FLAG_IN_DTMF); if (!f->len) f->len = ast_tvdiff_ms(now, *ast_channel_dtmf_tv(chan)); /* detect tones that were received on * the wire with durations shorter than * option_dtmfminduration and set f->len * to the actual duration of the DTMF * frames on the wire. This will cause * dtmf emulation to be triggered later * on. */ if (ast_tvdiff_ms(now, *ast_channel_dtmf_tv(chan)) < option_dtmfminduration) { f->len = ast_tvdiff_ms(now, *ast_channel_dtmf_tv(chan)); ast_log(LOG_DTMF, "DTMF end '%c' detected to have actual duration %ld on the wire, emulation will be triggered on %s\n", f->subclass.integer, f->len, ast_channel_name(chan)); } } else if (!f->len) { ast_log(LOG_DTMF, "DTMF end accepted without begin '%c' on %s\n", f->subclass.integer, ast_channel_name(chan)); f->len = option_dtmfminduration; } if (f->len < option_dtmfminduration && !ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY)) { ast_log(LOG_DTMF, "DTMF end '%c' has duration %ld but want minimum %u, emulating on %s\n", f->subclass.integer, f->len, option_dtmfminduration, ast_channel_name(chan)); ast_set_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF); ast_channel_dtmf_digit_to_emulate_set(chan, f->subclass.integer); ast_channel_emulate_dtmf_duration_set(chan, option_dtmfminduration - f->len); ast_frfree(f); f = &ast_null_frame; /* Start generating 50 fps timer events (null frames) for dtmf emulating * independently from any existing incoming voice frames. * If channel generator is already activated in regular mode use these * timer events to generate null frames. */ - if (!ast_channel_generator(chan)) { + if (!ast_channel_generator(chan) && ast_channel_timer(chan)) { ast_timer_set_rate(ast_channel_timer(chan), 50); } } else { ast_log(LOG_DTMF, "DTMF end passthrough '%c' on %s\n", f->subclass.integer, ast_channel_name(chan)); if (f->len < option_dtmfminduration) { f->len = option_dtmfminduration; } ast_channel_dtmf_tv_set(chan, &now); /* Start generating 50 fps timer events (null frames) for dtmf emulating * independently from any existing incoming voice frames. * If channel generator is already activated in regular mode use these * timer events to generate null frames. */ - if (!ast_channel_generator(chan)) { + if (!ast_channel_generator(chan) && ast_channel_timer(chan)) { ast_timer_set_rate(ast_channel_timer(chan), 50); } } if (ast_channel_audiohooks(chan)) { struct ast_frame *old_frame = f; f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f); if (old_frame != f) ast_frfree(old_frame); } } break; case AST_FRAME_DTMF_BEGIN: send_dtmf_begin_event(chan, DTMF_RECEIVED, f->subclass.integer); ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass.integer, ast_channel_name(chan)); if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF | AST_FLAG_END_DTMF_ONLY | AST_FLAG_EMULATE_DTMF) || (!ast_tvzero(*ast_channel_dtmf_tv(chan)) && ast_tvdiff_ms(ast_tvnow(), *ast_channel_dtmf_tv(chan)) < AST_MIN_DTMF_GAP) ) { ast_log(LOG_DTMF, "DTMF begin ignored '%c' on %s\n", f->subclass.integer, ast_channel_name(chan)); ast_frfree(f); f = &ast_null_frame; } else { struct timeval now = ast_tvnow(); ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_DTMF); ast_channel_dtmf_tv_set(chan, &now); ast_log(LOG_DTMF, "DTMF begin passthrough '%c' on %s\n", f->subclass.integer, ast_channel_name(chan)); } break; case AST_FRAME_NULL: /* The EMULATE_DTMF flag must be cleared here as opposed to when the duration * is reached , because we want to make sure we pass at least one * voice frame through before starting the next digit, to ensure a gap * between DTMF digits. */ if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF)) { struct timeval now = ast_tvnow(); if (!ast_channel_emulate_dtmf_duration(chan)) { ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF); ast_channel_dtmf_digit_to_emulate_set(chan, 0); } else if (ast_tvdiff_ms(now, *ast_channel_dtmf_tv(chan)) >= ast_channel_emulate_dtmf_duration(chan)) { ast_channel_emulate_dtmf_duration_set(chan, 0); ast_frfree(f); f = ast_channel_dtmff(chan); f->frametype = AST_FRAME_DTMF_END; f->subclass.integer = ast_channel_dtmf_digit_to_emulate(chan); f->len = ast_tvdiff_ms(now, *ast_channel_dtmf_tv(chan)); ast_channel_dtmf_tv_set(chan, &now); ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF); ast_channel_dtmf_digit_to_emulate_set(chan, 0); ast_log(LOG_DTMF, "DTMF end emulation of '%c' queued on %s\n", f->subclass.integer, ast_channel_name(chan)); if (ast_channel_audiohooks(chan)) { struct ast_frame *old_frame = f; f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f); if (old_frame != f) { ast_frfree(old_frame); } } /* Start generating 50 fps timer events (null frames) for dtmf emulating * independently from any existing incoming voice frames. * If channel generator is already activated in regular mode use these * timer events to generate null frames. */ - if (!ast_channel_generator(chan)) { + if (!ast_channel_generator(chan) && ast_channel_timer(chan)) { ast_timer_set_rate(ast_channel_timer(chan), 50); } } } break; case AST_FRAME_VOICE: /* If media was received from a non-default stream don't perform any actions, let it just go through */ if (stream != default_stream) { break; } /* The EMULATE_DTMF flag must be cleared here as opposed to when the duration * is reached , because we want to make sure we pass at least one * voice frame through before starting the next digit, to ensure a gap * between DTMF digits. */ if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF) && !ast_channel_emulate_dtmf_duration(chan)) { ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF); ast_channel_dtmf_digit_to_emulate_set(chan, 0); } if (dropaudio || ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_DTMF)) { if (dropaudio) ast_read_generator_actions(chan, f); ast_frfree(f); f = &ast_null_frame; } if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF) && !ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_DTMF)) { struct timeval now = ast_tvnow(); if (ast_tvdiff_ms(now, *ast_channel_dtmf_tv(chan)) >= ast_channel_emulate_dtmf_duration(chan)) { ast_channel_emulate_dtmf_duration_set(chan, 0); ast_frfree(f); f = ast_channel_dtmff(chan); f->frametype = AST_FRAME_DTMF_END; f->subclass.integer = ast_channel_dtmf_digit_to_emulate(chan); f->len = ast_tvdiff_ms(now, *ast_channel_dtmf_tv(chan)); ast_channel_dtmf_tv_set(chan, &now); if (ast_channel_audiohooks(chan)) { struct ast_frame *old_frame = f; f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f); if (old_frame != f) ast_frfree(old_frame); } ast_log(LOG_DTMF, "DTMF end emulation of '%c' queued on %s\n", f->subclass.integer, ast_channel_name(chan)); } else { /* Drop voice frames while we're still in the middle of the digit */ ast_frfree(f); f = &ast_null_frame; } break; } if (f->frametype != AST_FRAME_VOICE) { break; } if (ast_format_cmp(f->subclass.format, ast_channel_rawreadformat(chan)) != AST_FORMAT_CMP_EQUAL && ast_format_cmp(f->subclass.format, ast_channel_readformat(chan)) != AST_FORMAT_CMP_EQUAL) { struct ast_format *core_format; /* * Note: This frame may not be one of the current native * formats. We may have gotten it out of the read queue from * a previous multi-frame translation, from a framehook * injected frame, or the device we're talking to isn't * respecting negotiated formats. Regardless we will accept * all frames. * * Update the read translation path to handle the new format * that just came in. If the core wants slinear we need to * setup a new translation path because the core is usually * doing something with the audio itself and may not handle * any other format. e.g., Softmix bridge, holding bridge * announcer channel, recording, AMD... Otherwise, we'll * setup to pass the frame as is to the core. In this case * the core doesn't care. The channel is likely in * autoservice, safesleep, or the channel is in a bridge. * Let the bridge technology deal with format compatibility * between the channels in the bridge. * * Beware of the transcode_via_slin and genericplc options as * they force any transcoding to go through slin on a bridge. * Unfortunately transcode_via_slin is enabled by default and * genericplc is enabled in the codecs.conf.sample file. * * XXX Only updating translation to slinear frames has some * corner cases if slinear is one of the native formats and * there are different sample rates involved. We might wind * up with conflicting translation paths between channels * where the read translation path on this channel reduces * the sample rate followed by a write translation path on * the peer channel that increases the sample rate. */ core_format = ast_channel_readformat(chan); if (!ast_format_cache_is_slinear(core_format)) { core_format = f->subclass.format; } if (ast_set_read_format_path(chan, f->subclass.format, core_format)) { /* Drop frame. We couldn't make it compatible with the core. */ ast_frfree(f); f = &ast_null_frame; break;