diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/channel.c | 76 | ||||
-rw-r--r-- | main/pbx.c | 10 | ||||
-rw-r--r-- | main/rtp_engine.c | 16 | ||||
-rw-r--r-- | main/utils.c | 17 |
4 files changed, 77 insertions, 42 deletions
diff --git a/main/channel.c b/main/channel.c index 126e44cf6..9998225f0 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1669,11 +1669,13 @@ int ast_is_deferrable_frame(const struct ast_frame *frame) } /*! \brief Wait, look for hangups and condition arg */ -int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(void*), void *data) +int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*cond)(void*), void *data) { struct ast_frame *f; struct ast_silence_generator *silgen = NULL; int res = 0; + struct timeval start; + int ms; AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); @@ -1683,8 +1685,10 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(voi silgen = ast_channel_start_silence_generator(chan); } - while (ms > 0) { + start = ast_tvnow(); + while ((ms = ast_remaining_ms(start, timeout_ms))) { struct ast_frame *dup_f = NULL; + if (cond && ((*cond)(data) == 0)) { break; } @@ -3005,12 +3009,15 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay, int cdr_answer) do { AST_LIST_HEAD_NOLOCK(, ast_frame) frames; struct ast_frame *cur, *new; - int ms = MAX(delay, 500); + int timeout_ms = MAX(delay, 500); unsigned int done = 0; + struct timeval start; AST_LIST_HEAD_INIT_NOLOCK(&frames); + start = ast_tvnow(); for (;;) { + int ms = ast_remaining_ms(start, timeout_ms); ms = ast_waitfor(chan, ms); if (ms < 0) { ast_log(LOG_WARNING, "Error condition occurred when polling channel %s for a voice frame: %s\n", ast_channel_name(chan), strerror(errno)); @@ -3568,11 +3575,13 @@ struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms) int ast_waitfor(struct ast_channel *c, int ms) { - int oldms = ms; /* -1 if no timeout */ - - ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms); - if ((ms < 0) && (oldms < 0)) { - ms = 0; + 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; } @@ -3628,6 +3637,7 @@ int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const v int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, 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)) @@ -3639,19 +3649,9 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in /* Wait for a digit, no more than timeout_ms milliseconds total. * Or, wait indefinitely if timeout_ms is <0. */ - while (ast_tvdiff_ms(ast_tvnow(), start) < timeout_ms || timeout_ms < 0) { + while ((ms = ast_remaining_ms(start, timeout_ms))) { struct ast_channel *rchan; - int outfd=-1; - int ms; - - if (timeout_ms < 0) { - ms = timeout_ms; - } else { - ms = timeout_ms - ast_tvdiff_ms(ast_tvnow(), start); - if (ms < 0) { - ms = 0; - } - } + int outfd = -1; errno = 0; /* While ast_waitfor_nandfds tries to help by reducing the timeout by how much was waited, @@ -4690,25 +4690,32 @@ int ast_recvchar(struct ast_channel *chan, int timeout) char *ast_recvtext(struct ast_channel *chan, int timeout) { - int res, done = 0; + int res; char *buf = NULL; + struct timeval start = ast_tvnow(); + int ms; - while (!done) { + while ((ms = ast_remaining_ms(start, timeout))) { struct ast_frame *f; - if (ast_check_hangup(chan)) + + if (ast_check_hangup(chan)) { break; - res = ast_waitfor(chan, timeout); - if (res <= 0) /* timeout or error */ + } + res = ast_waitfor(chan, ms); + if (res <= 0) {/* timeout or error */ break; - timeout = res; /* update timeout */ + } f = ast_read(chan); - if (f == NULL) + if (f == NULL) { break; /* no frame */ - if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP) - done = 1; /* force a break */ - else if (f->frametype == AST_FRAME_TEXT) { /* what we want */ + } + if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP) { + ast_frfree(f); + break; + } else if (f->frametype == AST_FRAME_TEXT) { /* what we want */ buf = ast_strndup((char *) f->data.ptr, f->datalen); /* dup and break */ - done = 1; + ast_frfree(f); + break; } ast_frfree(f); } @@ -5724,18 +5731,19 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c if (ast_call(chan, addr, 0)) { /* ast_call failed... */ ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, addr); } else { + struct timeval start = ast_tvnow(); res = 1; /* mark success in case chan->_state is already AST_STATE_UP */ while (timeout && ast_channel_state(chan) != AST_STATE_UP) { struct ast_frame *f; - res = ast_waitfor(chan, timeout); + int ms = ast_remaining_ms(start, timeout); + + res = ast_waitfor(chan, ms); if (res == 0) { /* timeout, treat it like ringing */ *outstate = AST_CONTROL_RINGING; break; } if (res < 0) /* error or done */ break; - if (timeout > -1) - timeout = res; if (!ast_strlen_zero(ast_channel_call_forward(chan))) { if (!(chan = ast_call_forward(NULL, chan, NULL, cap, oh, outstate))) { return NULL; diff --git a/main/pbx.c b/main/pbx.c index 375c232ea..ba66fcac5 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -9767,6 +9767,8 @@ static void *async_wait(void *data) struct ast_frame *f; struct ast_app *app; int have_early_media = 0; + struct timeval start = ast_tvnow(); + int ms; if (chan) { struct ast_callid *callid = ast_channel_callid(chan); @@ -9776,12 +9778,12 @@ static void *async_wait(void *data) } } - while (timeout && (ast_channel_state(chan) != AST_STATE_UP)) { - res = ast_waitfor(chan, timeout); + while ((ms = ast_remaining_ms(start, timeout)) && + ast_channel_state(chan) != AST_STATE_UP) { + res = ast_waitfor(chan, ms); if (res < 1) break; - if (timeout > -1) - timeout = res; + f = ast_read(chan); if (!f) break; diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 55ca0f2b7..29c9286a1 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -949,6 +949,7 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a enum ast_bridge_result res = AST_BRIDGE_FAILED; struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, }; struct ast_frame *fr = NULL; + struct timeval start; /* Start locally bridging both instances */ if (instance0->engine->local_bridge && instance0->engine->local_bridge(instance0, instance1)) { @@ -979,7 +980,9 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a cs[0] = c0; cs[1] = c1; cs[2] = NULL; + start = ast_tvnow(); for (;;) { + int ms; /* If the underlying formats have changed force this bridge to break */ if ((ast_format_cmp(ast_channel_rawreadformat(c0), ast_channel_rawwriteformat(c1)) == AST_FORMAT_CMP_NOT_EQUAL) || (ast_format_cmp(ast_channel_rawreadformat(c1), ast_channel_rawwriteformat(c0)) == AST_FORMAT_CMP_NOT_EQUAL)) { @@ -1005,8 +1008,9 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a break; } /* Wait on a channel to feed us a frame */ - if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) { - if (!timeoutms) { + ms = ast_remaining_ms(start, timeoutms); + if (!(who = ast_waitfor_n(cs, 2, &ms))) { + if (!ms) { res = AST_BRIDGE_RETRY; break; } @@ -1145,6 +1149,7 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct ast_sockaddr ac1 = {{0,}}, vac1 = {{0,}}, tac1 = {{0,}}, ac0 = {{0,}}, vac0 = {{0,}}, tac0 = {{0,}}; struct ast_sockaddr t1 = {{0,}}, vt1 = {{0,}}, tt1 = {{0,}}, t0 = {{0,}}, vt0 = {{0,}}, tt0 = {{0,}}; struct ast_frame *fr = NULL; + struct timeval start; if (!oldcap0 || !oldcap1) { ast_channel_unlock(c0); @@ -1189,7 +1194,9 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, cs[0] = c0; cs[1] = c1; cs[2] = NULL; + start = ast_tvnow(); for (;;) { + int ms; /* Check if anything changed */ if ((ast_channel_tech_pvt(c0) != pvt0) || (ast_channel_tech_pvt(c1) != pvt1) || @@ -1284,9 +1291,10 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, ast_format_cap_copy(oldcap0, cap0); } + ms = ast_remaining_ms(start, timeoutms); /* Wait for frame to come in on the channels */ - if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) { - if (!timeoutms) { + if (!(who = ast_waitfor_n(cs, 2, &ms))) { + if (!ms) { res = AST_BRIDGE_RETRY; break; } diff --git a/main/utils.c b/main/utils.c index 0ff33cba2..3476729ce 100644 --- a/main/utils.c +++ b/main/utils.c @@ -1470,6 +1470,23 @@ struct timeval ast_tvsub(struct timeval a, struct timeval b) } return a; } + +int ast_remaining_ms(struct timeval start, int max_ms) +{ + int ms; + + if (max_ms < 0) { + ms = max_ms; + } else { + ms = max_ms - ast_tvdiff_ms(ast_tvnow(), start); + if (ms < 0) { + ms = 0; + } + } + + return ms; +} + #undef ONE_MILLION /*! \brief glibc puts a lock inside random(3), so that the results are thread-safe. |