int is_cc_recall;
int cc_frame_received = 0;
int num_ringing = 0;
+ struct timeval start = ast_tvnow();
ast_party_connected_line_init(&connected_caller);
if (single) {
}
#endif
- while (*to && !peer) {
+ while ((*to = ast_remaining_ms(start, orig)) && !peer) {
struct chanlist *o;
int pos = 0; /* how many channels do we handle */
int numlines = prestart;
skip_frame:;
ast_frfree(f);
}
- if (!*to)
- ast_verb(3, "Nobody picked up in %d ms\n", orig);
- if (!*to || ast_check_hangup(in))
- ast_cdr_noanswer(ast_channel_cdr(in));
+ }
+
+ if (!*to) {
+ ast_verb(3, "Nobody picked up in %d ms\n", orig);
+ }
+ if (!*to || ast_check_hangup(in)) {
+ ast_cdr_noanswer(ast_channel_cdr(in));
}
#ifdef HAVE_EPOLL
while (!jack_data->stop) {
struct ast_frame *f;
- ast_waitfor(chan, -1);
+ if (ast_waitfor(chan, -1) < 0) {
+ break;
+ }
f = ast_read(chan);
if (!f) {
/* when no frames are available, this will wait
for 1 millisecond maximum
*/
- while (ast_waitfor(chan, 1)) {
+ while (ast_waitfor(chan, 1) > 0) {
f = ast_read(chan);
if (f)
ast_frfree(f);
#endif
struct ast_party_connected_line connected_caller;
char *inchan_name;
+ struct timeval start_time_tv = ast_tvnow();
ast_party_connected_line_init(&connected_caller);
}
#endif
- while (*to && !peer) {
+ while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
int numlines, retry, pos = 1;
struct ast_channel *watchers[AST_MAX_WATCHERS];
watchers[0] = in;
rna(endtime * 1000, qe, on, membername, qe->parent->autopausebusy);
if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
if (qe->parent->timeoutrestart) {
- *to = orig;
+ start_time_tv = ast_tvnow();
}
/* Have enough time for a queue member to answer? */
- if (*to > 500) {
+ if (ast_remaining_ms(start_time_tv, orig) > 500) {
ring_one(qe, outgoing, &numbusies);
starttime = (long) time(NULL);
}
do_hang(o);
if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
if (qe->parent->timeoutrestart) {
- *to = orig;
+ start_time_tv = ast_tvnow();
}
- if (*to > 500) {
+ if (ast_remaining_ms(start_time_tv, orig) > 500) {
ring_one(qe, outgoing, &numbusies);
starttime = (long) time(NULL);
}
do_hang(o);
if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
if (qe->parent->timeoutrestart) {
- *to = orig;
+ start_time_tv = ast_tvnow();
}
- if (*to > 500) {
+ if (ast_remaining_ms(start_time_tv, orig) > 500) {
ring_one(qe, outgoing, &numbusies);
starttime = (long) time(NULL);
}
ast_frfree(f);
}
- if (!*to) {
- for (o = start; o; o = o->call_next) {
- rna(orig, qe, o->interface, o->member->membername, 1);
- }
+ }
+
+ if (!*to) {
+ for (o = start; o; o = o->call_next) {
+ rna(orig, qe, o->interface, o->member->membername, 1);
}
if (ast_channel_cdr(in)
int terminator = '#';
struct ast_format rfmt;
int ioflags;
- int waitres;
struct ast_silence_generator *silgen = NULL;
struct ast_flags flags = { 0, };
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(maxduration);
AST_APP_ARG(options);
);
+ int ms;
+ struct timeval start;
ast_format_clear(&rfmt);
+
/* The next few lines of code parse out the filename and header from the input string */
if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
if (maxduration <= 0)
maxduration = -1;
- while ((waitres = ast_waitfor(chan, maxduration)) > -1) {
- if (maxduration > 0) {
- if (waitres == 0) {
- gottimeout = 1;
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "TIMEOUT");
- break;
- }
- maxduration = waitres;
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, maxduration))) {
+ ms = ast_waitfor(chan, ms);
+ if (ms < 0) {
+ break;
+ }
+
+ if (maxduration > 0 && ms == 0) {
+ break;
}
f = ast_read(chan);
}
ast_frfree(f);
}
+
+ if (maxduration > 0 && !ms) {
+ gottimeout = 1;
+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "TIMEOUT");
+ }
+
if (!f) {
ast_debug(1, "Got hangup\n");
res = -1;
struct ast_silence_generator *silgen = NULL;
int res = 0;
double s;
+ int timeout_ms;
int ms;
+ struct timeval start = ast_tvnow();
if (!data || (sscanf(data, "%30lg", &s) != 1)) {
ast_log(LOG_WARNING, "WaitForRing requires an argument (minimum seconds)\n");
return 0;
}
+ if (s < 0.0) {
+ ast_log(LOG_WARNING, "Invalid timeout provided for WaitForRing (%lg)\n", s);
+ return 0;
+ }
+
if (ast_opt_transmit_silence) {
silgen = ast_channel_start_silence_generator(chan);
}
- ms = s * 1000.0;
- while (ms > 0) {
+ timeout_ms = s * 1000.0;
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
ms = ast_waitfor(chan, ms);
if (ms < 0) {
- res = ms;
+ res = -1;
break;
}
if (ms > 0) {
}
/* Now we're really ready for the ring */
if (!res) {
- ms = 99999999;
- while(ms > 0) {
- ms = ast_waitfor(chan, ms);
- if (ms < 0) {
- res = ms;
+ for (;;) {
+ int wait_res = ast_waitfor(chan, -1);
+ if (wait_res < 0) {
+ res = -1;
break;
- }
- if (ms > 0) {
+ } else {
f = ast_read(chan);
if (!f) {
res = -1;
int res=0;
int to = 1000;
struct ast_frame *f;
+ struct timeval start = ast_tvnow();
+ int ms;
/* Wait a second and look for something */
if (!p->chan)
return -1;
- for(;;) {
- to = ast_waitfor(p->chan, to);
- if (to < 0)
+ while ((ms = ast_remaining_ms(start, to))) {
+ ms = ast_waitfor(p->chan, ms);
+ if (ms < 0) {
return -1;
- if (!to)
+ }
+ if (ms == 0) {
return 0;
+ }
f = ast_read(p->chan);
if (!f)
return -1;
ast_mutex_unlock(&p->lock);
res = 0;
}
- return res;
+ return 0;
}
static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
if (res == 0) {
continue;
}
+ res = 0;
f = ast_read(chan);
if (!f) {
ast_debug(1, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
int priority = 0;
struct ast_channel *oc0, *oc1;
enum ast_bridge_result res;
+ struct timeval start = ast_tvnow();
#ifdef PRI_2BCT
int triedtopribridge = 0;
q931_call *q931c0;
for (;;) {
struct ast_channel *c0_priority[2] = {c0, c1};
struct ast_channel *c1_priority[2] = {c1, c0};
+ int ms;
/* Here's our main loop... Start by locking things, looking for private parts,
and then balking if anything is wrong */
ast_channel_unlock(c0);
ast_channel_unlock(c1);
-
- if (!timeoutms ||
+ ms = ast_remaining_ms(start, timeoutms);
+ if (!ms ||
(op0 != p0) ||
(op1 != p1) ||
(ofd0 != ast_channel_fd(c0, 0)) ||
}
#endif
- who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &timeoutms);
+ who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &ms);
if (!who) {
ast_debug(1, "Ooh, empty read...\n");
continue;
/* If set to use DTMF CID signalling, listen for DTMF */
if (p->cid_signalling == CID_SIG_DTMF) {
int k = 0;
+ int off_ms;
+ struct timeval start = ast_tvnow();
+ int ms;
cs = NULL;
ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
dahdi_setlinear(p->subs[idx].dfd, 0);
* can drop some of them.
*/
ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
- res = 4000;/* This is a typical OFF time between rings. */
+ off_ms = 4000;/* This is a typical OFF time between rings. */
for (;;) {
struct ast_frame *f;
- res = ast_waitfor(chan, res);
+
+ ms = ast_remaining_ms(start, off_ms);
+ res = ast_waitfor(chan, ms);
if (res <= 0) {
/*
* We do not need to restore the dahdi_setlinear()
dtmfbuf[k++] = f->subclass.integer;
}
ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
- res = 4000;/* This is a typical OFF time between rings. */
+ start = ast_tvnow();
}
ast_frfree(f);
if (ast_channel_state(chan) == AST_STATE_RING ||
} else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
cs = callerid_new(p->cid_signalling);
if (cs) {
+ int off_ms;
+ struct timeval start;
+ int ms;
samples = 0;
#if 1
bump_gains(p);
}
/* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
- res = 4000;/* This is a typical OFF time between rings. */
+ start = ast_tvnow();
+ off_ms = 4000;/* This is a typical OFF time between rings. */
for (;;) {
struct ast_frame *f;
- res = ast_waitfor(chan, res);
+
+ ms = ast_remaining_ms(start, off_ms);
+ res = ast_waitfor(chan, ms);
if (res <= 0) {
ast_log(LOG_WARNING, "CID timed out waiting for ring. "
"Exiting simple switch\n");
} else if (p->use_callerid && p->cid_start == CID_START_RING) {
if (p->cid_signalling == CID_SIG_DTMF) {
int k = 0;
+ int off_ms;
+ struct timeval start;
+ int ms;
cs = NULL;
dahdi_setlinear(p->subs[idx].dfd, 0);
- res = 2000;
+ off_ms = 2000;
+ start = ast_tvnow();
for (;;) {
struct ast_frame *f;
- res = ast_waitfor(chan, res);
+
+ ms = ast_remaining_ms(start, off_ms);
+ res = ast_waitfor(chan, ms);
if (res <= 0) {
ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
"Exiting simple switch\n");
if (f->frametype == AST_FRAME_DTMF) {
dtmfbuf[k++] = f->subclass.integer;
ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
- res = 2000;
+ start = ast_tvnow();
}
ast_frfree(f);
}
to = 1000;
who = ast_waitfor_n(cs, 2, &to);
+ /* XXX This will need to be updated to calculate
+ * timeout correctly once timeoutms is allowed to be
+ * > 0. Right now, this can go badly if the waitfor
+ * times out in less than a millisecond
+ */
if (timeoutms > -1) {
timeoutms -= (1000 - to);
if (timeoutms < 0)
/* By here we must have a dp */
if (dp->flags & CACHE_FLAG_PENDING) {
+ struct timeval start;
+ int ms;
/* Okay, here it starts to get nasty. We need a pipe now to wait
for a reply to come back so long as it's pending */
for (x = 0; x < ARRAY_LEN(dp->waiters); x++) {
if (chan)
old = ast_channel_defer_dtmf(chan);
doabort = 0;
- while(timeout) {
- c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &timeout);
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout))) {
+ c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &ms);
if (outfd > -1)
break;
if (!c)
}
ast_frfree(f);
}
- if (!timeout) {
+ if (!ms) {
ast_log(LOG_WARNING, "Timeout waiting for %s exten %s\n", data, exten);
}
AST_LIST_LOCK(&dpcache);
if (p->cid_signalling == CID_SIG_DTMF) {
int k = 0;
int oldlinearity;
+ int timeout_ms;
+ int ms;
+ struct timeval start = ast_tvnow();
cs = NULL;
ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
* can drop some of them.
*/
ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
- res = 4000;/* This is a typical OFF time between rings. */
+ timeout_ms = 4000;/* This is a typical OFF time between rings. */
for (;;) {
struct ast_frame *f;
- res = ast_waitfor(chan, res);
+
+ ms = ast_remaining_ms(start, timeout_ms);
+ res = ast_waitfor(chan, ms);
if (res <= 0) {
/*
* We do not need to restore the analog_set_linear_mode()
dtmfbuf[k++] = f->subclass.integer;
}
ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
- res = 4000;/* This is a typical OFF time between rings. */
+ start = ast_tvnow();
}
ast_frfree(f);
if (ast_channel_state(chan) == AST_STATE_RING ||
numbuf[0] = 0;
if (!analog_start_cid_detect(p, p->cid_signalling)) {
+ int off_ms;
+ int ms;
+ struct timeval off_start;
while (1) {
res = analog_get_callerid(p, namebuf, numbuf, &ev, timeout - ast_tvdiff_ms(ast_tvnow(), start));
}
/* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
- res = 4000;/* This is a typical OFF time between rings. */
- for (;;) {
+ off_start = ast_tvnow();
+ off_ms = 4000;/* This is a typical OFF time between rings. */
+ while ((ms = ast_remaining_ms(off_start, off_ms))) {
struct ast_frame *f;
- res = ast_waitfor(chan, res);
+
+ res = ast_waitfor(chan, ms);
if (res <= 0) {
ast_log(LOG_WARNING, "CID timed out waiting for ring. "
"Exiting simple switch\n");
struct ast_frame *f;
char ex[80];
/* Wait up to 30 seconds for an answer */
- int newms, ms = 30000;
+ int timeout_ms = 30000;
+ int ms;
+ struct timeval start;
struct ast_callid *callid;
if ((callid = ast_channel_callid(chan))) {
ast_hangup(chan);
return NULL;
}
- while ((newms = ast_waitfor(chan, ms)) > 0) {
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ if (ast_waitfor(chan, ms) <= 0) {
+ break;
+ }
+
f = ast_read(chan);
if (!f) {
/* Got hangup */
};
}
ast_frfree(f);
- ms = newms;
}
/* Hangup the channel since nothing happend */
ast_hangup(chan);
/*!
* \brief Wait for a specified amount of time, looking for hangups
* \param chan channel to wait for
- * \param ms length of time in milliseconds to sleep
+ * \param ms length of time in milliseconds to sleep. This should never be less than zero.
* \details
* Waits for a specified amount of time, servicing the channel as required.
* \return returns -1 on hangup, otherwise 0.
/*!
* \brief Wait for a specified amount of time, looking for hangups and a condition argument
* \param chan channel to wait for
- * \param ms length of time in milliseconds to sleep
+ * \param ms length of time in milliseconds to sleep.
* \param cond a function pointer for testing continue condition
* \param data argument to be passed to the condition test function
* \return returns -1 on hangup, otherwise 0.
struct timeval ast_tvsub(struct timeval a, struct timeval b);
/*!
+ * \brief Calculate remaining milliseconds given a starting timestamp
+ * and upper bound
+ *
+ * If the upper bound is negative, then this indicates that there is no
+ * upper bound on the amount of time to wait. This will result in a
+ * negative return.
+ *
+ * \param start When timing started being calculated
+ * \param max_ms The maximum number of milliseconds to wait from start. May be negative.
+ * \return The number of milliseconds left to wait for. May be negative.
+ */
+int ast_remaining_ms(struct timeval start, int max_ms);
+
+/*!
* \brief Returns a timeval from sec, usec
*/
AST_INLINE_API(
}
/*! \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);
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;
}
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));
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;
}
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))
/* 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,
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);
}
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;
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);
}
}
- 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;
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)) {
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)) {
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;
}
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);
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) ||
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;
}
}
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.
static int disable_t38(struct ast_channel *chan)
{
- int ms;
+ int timeout_ms;
struct ast_frame *frame = NULL;
struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
+ struct timeval start;
+ int ms;
ast_debug(1, "Shutting down T.38 on %s\n", ast_channel_name(chan));
if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0) {
}
/* wait up to five seconds for negotiation to complete */
- ms = 5000;
-
- while (ms > 0) {
+ timeout_ms = 5000;
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
ms = ast_waitfor(chan, ms);
+
+ if (ms == 0) {
+ break;
+ }
if (ms < 0) {
ast_debug(1, "error while disabling T.38 on channel '%s'\n", ast_channel_name(chan));
return -1;
}
- if (ms == 0) { /* all done, nothing happened */
- ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", ast_channel_name(chan));
- break;
- }
-
if (!(frame = ast_read(chan))) {
return -1;
}
ast_frfree(frame);
}
+ if (ms == 0) { /* all done, nothing happened */
+ ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", ast_channel_name(chan));
+ }
+
return 0;
}
{
int ms;
int timeout = RES_FAX_TIMEOUT;
- int res = 0, chancount;
+ int res, chancount;
unsigned int expected_frametype = -1;
union ast_frame_subclass expected_framesubclass = { .integer = -1 };
unsigned int t38negotiated = (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED);
struct ast_channel *c = chan;
struct ast_format orig_write_format;
struct ast_format orig_read_format;
+ int remaining_time;
+ struct timeval start;
ast_format_clear(&orig_write_format);
ast_format_clear(&orig_read_format);
ast_debug(5, "channel %s will wait on FAX fd %d\n", ast_channel_name(chan), fax->fd);
/* handle frames for the session */
- ms = 1000;
- while ((res > -1) && (ms > -1) && (timeout > 0)) {
+ remaining_time = timeout;
+ start = ast_tvnow();
+ while (remaining_time > 0) {
struct ast_channel *ready_chan;
int ofd, exception;
GENERIC_FAX_EXEC_SET_VARS(fax, chan, "HANGUP", "remote channel hungup");
c = NULL;
chancount = 0;
- timeout -= (1000 - ms);
+ remaining_time = ast_remaining_ms(start, timeout);
fax->tech->cancel_session(fax);
if (fax->tech->generate_silence) {
fax->tech->generate_silence(fax);
fax->tech->write(fax, frame);
fax->frames_received++;
}
- timeout = RES_FAX_TIMEOUT;
+ start = ast_tvnow();
}
ast_frfree(frame);
} else if (ofd == fax->fd) {
ast_write(chan, frame);
fax->frames_sent++;
ast_frfree(frame);
- timeout = RES_FAX_TIMEOUT;
+ start = ast_tvnow();
} else {
if (ms && (ofd < 0)) {
if ((errno == 0) || (errno == EINTR)) {
- timeout -= (1000 - ms);
- if (timeout <= 0)
+ remaining_time = ast_remaining_ms(start, timeout);
+ if (remaining_time <= 0)
GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
continue;
} else {
ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(chan));
GENERIC_FAX_EXEC_ERROR(fax, chan, "UNKNOWN", "error polling data");
- res = ms;
break;
}
} else {
/* nothing happened */
- if (timeout > 0) {
- timeout -= 1000;
- if (timeout <= 0)
- GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
- continue;
- } else {
- ast_log(LOG_WARNING, "channel '%s' timed-out during the FAX transmission.\n", ast_channel_name(chan));
+ remaining_time = ast_remaining_ms(start, timeout);
+ if (remaining_time <= 0) {
GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
break;
}
}
}
}
- ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, ms: %d, res: %d }\n", ast_channel_name(chan), timeout, ms, res);
+ ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, remaining_time: %d }\n", ast_channel_name(chan), timeout, remaining_time);
set_channel_variables(chan, details);
static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_details *details)
{
- int ms;
+ int timeout_ms;
struct ast_frame *frame = NULL;
struct ast_control_t38_parameters t38_parameters;
+ struct timeval start;
+ int ms;
/* don't send any audio if we've already received a T.38 reinvite */
if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
return -1;
}
- ms = 3000;
- while (ms > 0) {
+ timeout_ms = 3000;
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
ms = ast_waitfor(chan, ms);
+
if (ms < 0) {
ast_log(LOG_ERROR, "error while generating CED tone on %s\n", ast_channel_name(chan));
ast_playtones_stop(chan);
ast_debug(1, "Negotiating T.38 for receive on %s\n", ast_channel_name(chan));
/* wait up to five seconds for negotiation to complete */
- ms = 5000;
+ timeout_ms = 5000;
/* set parameters based on the session's parameters */
t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
return -1;
}
- while (ms > 0) {
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ int break_loop = 0;
+
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", ast_channel_name(chan));
return -1;
}
-
if (ms == 0) { /* all done, nothing happened */
ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
- ms = 0;
+ break_loop = 1;
break;
case AST_T38_REFUSED:
ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
- ms = 0;
+ break_loop = 1;
break;
default:
ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
- ms = 0;
+ break_loop = 1;
break;
}
}
ast_frfree(frame);
+ if (break_loop) {
+ break;
+ }
}
/* if T.38 was negotiated, we are done initializing */
static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_details *details)
{
- int ms;
+ int timeout_ms;
struct ast_frame *frame = NULL;
struct ast_control_t38_parameters t38_parameters;
+ struct timeval start;
+ int ms;
/* send CNG tone while listening for the receiver to initiate a switch
* to T.38 mode; if they do, stop sending the CNG tone and proceed with
*
* 10500 is enough time for 3 CNG tones
*/
- ms = 10500;
+ timeout_ms = 10500;
/* don't send any audio if we've already received a T.38 reinvite */
if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
}
}
- while (ms > 0) {
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ int break_loop = 0;
ms = ast_waitfor(chan, ms);
+
if (ms < 0) {
ast_log(LOG_ERROR, "error while generating CNG tone on %s\n", ast_channel_name(chan));
ast_playtones_stop(chan);
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
- ms = 0;
+ break_loop = 1;
break;
default:
break;
}
}
ast_frfree(frame);
+ if (break_loop) {
+ break;
+ }
}
ast_playtones_stop(chan);
ast_debug(1, "Negotiating T.38 for send on %s\n", ast_channel_name(chan));
/* wait up to five seconds for negotiation to complete */
- ms = 5000;
+ timeout_ms = 5000;
/* set parameters based on the session's parameters */
t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
return -1;
}
- while (ms > 0) {
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ int break_loop = 0;
+
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", ast_channel_name(chan));
return -1;
}
-
if (ms == 0) { /* all done, nothing happened */
ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
- ms = 0;
+ break_loop = 1;
break;
case AST_T38_REFUSED:
ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
- ms = 0;
+ break_loop = 1;
break;
default:
ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
- ms = 0;
+ break_loop = 1;
break;
}
}
ast_frfree(frame);
+ if (break_loop) {
+ break;
+ }
}
/* if T.38 was negotiated, we are done initializing */
return -1;
}
- ms = 3500;
- while (ms > 0) {
+ timeout_ms = 3500;
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ int break_loop = 0;
+
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_ERROR, "error while generating second CNG tone on %s\n", ast_channel_name(chan));
ast_playtones_stop(chan);
return -1;
}
-
if (ms == 0) { /* all done, nothing happened */
break;
}
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
- ms = 0;
+ break_loop = 1;
break;
default:
break;
}
}
ast_frfree(frame);
+ if (break_loop) {
+ break;
+ }
}
ast_playtones_stop(chan);