int cw_sched_runq(struct sched_context *con) { /* * Launch all events which need to be run at this time. */ struct sched *runq, **endq, *current; struct timeval tv; int x=0; int res; #ifdef DEBUG_SCHED DEBUG_LOG(cw_log(LOG_DEBUG, "cw_sched_runq()\n")); #endif cw_mutex_lock(&con->lock); /* schedule all events which are going to expire within 1ms. * We only care about millisecond accuracy anyway, so this will * help us get more than one event at one time if they are very * close together. */ tv = cw_tvadd(cw_tvnow(), cw_tv(0, 1000)); runq = con->schedq; endq = &runq; while (con->schedq && SOONER(con->schedq->when, tv)) { endq = &con->schedq->next; con->schedq = con->schedq->next; con->schedcnt--; } *endq = NULL; cw_mutex_unlock(&con->lock); while ((current = runq)) { runq = runq->next; x++; res = current->callback(current->data); if (res) { /* * If they return non-zero, we should schedule them to be * run again. */ current->when = cw_tvadd(current->when, cw_samp2tv((current->variable ? res : current->resched), 1000)); schedule(con, current); } else { /* No longer needed, so release it */ sched_release(con, current); } } return x; }
int cw_sched_add_variable(struct sched_context *con, int when, cw_sched_cb callback, void *data, int variable) { /* * Schedule callback(data) to happen when ms into the future */ struct sched *tmp; int res = -1; #ifdef DEBUG_SCHED DEBUG_LOG(cw_log(LOG_DEBUG, "cw_sched_add_variable()\n")); #endif cw_mutex_lock(&con->lock); if ((tmp = sched_alloc(con))) { if ((tmp->id = con->eventcnt++) < 0) tmp->id = con->eventcnt = 0; tmp->callback = callback; tmp->data = data; tmp->resched = when; tmp->variable = variable; tmp->when = cw_tvadd(cw_tvnow(), cw_samp2tv(when, 1000)); schedule(con, tmp); res = tmp->id; } #ifdef DUMP_SCHEDULER /* Dump contents of the context while we have the lock so nothing gets screwed up by accident. */ cw_sched_dump(con); #endif cw_mutex_unlock(&con->lock); return res; }
static int pipe_exec(struct cw_channel *chan, int argc, char **argv) { int res=0; struct localuser *u; int fds[2]; int ms = -1; int pid = -1; int owriteformat; int oreadformat; int timeout = 2000; struct timeval last; struct cw_frame *f; struct myframe { struct cw_frame f; char offset[CW_FRIENDLY_OFFSET]; short frdata[160]; } myf; last.tv_usec = 0; last.tv_sec = 0; if (argc < 2 || argc > 3) { cw_log(LOG_ERROR, "Syntax: %s\n", pipe_syntax); return -1; } LOCAL_USER_ADD(u); if (pipe(fds)) { cw_log(LOG_WARNING, "Unable to create pipe\n"); LOCAL_USER_REMOVE(u); return -1; } // MOC: Setting non blocking doesn't seem to change anything // flags = fcntl(fds[1], F_GETFL); // fcntl(fds[1], F_SETFL, flags | O_NONBLOCK); // flags = fcntl(fds[0], F_GETFL); // fcntl(fds[0], F_SETFL, flags | O_NONBLOCK); cw_stopstream(chan); if (chan->_state != CW_STATE_UP) res = cw_answer(chan); if (res) { close(fds[0]); close(fds[1]); cw_log(LOG_WARNING, "Answer failed!\n"); LOCAL_USER_REMOVE(u); return -1; } oreadformat = chan->readformat; res = cw_set_read_format(chan, CW_FORMAT_SLINEAR); owriteformat = chan->writeformat; res += cw_set_write_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { close(fds[0]); close(fds[1]); cw_log(LOG_WARNING, "Unable to set write format to signed linear\n"); LOCAL_USER_REMOVE(u); return -1; } res = pipeencode(argv[1], argv[2], fds[0], fds[1]); if (res >= 0) { last = cw_tvnow(); last.tv_sec += 1; pid = res; for (;;) { /* Wait for audio, and stream */ if (argv[0][0] == '0') { /* START WRITE TO FD */ ms = cw_waitfor(chan, 10); if (ms < 0) { cw_log(LOG_DEBUG, "Hangup detected\n"); res = -1; break; } else if (ms > 0) { f = cw_read(chan); if (!f) { cw_log(LOG_DEBUG, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == CW_FRAME_DTMF) { cw_log(LOG_DEBUG, "User pressed a key\n"); cw_fr_free(f); res = 0; break; } if (f->frametype == CW_FRAME_VOICE) { res = write(fds[1], f->data, f->datalen); if (res < 0) { if (errno != EAGAIN) { cw_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno)); cw_fr_free(f); res = -1; break; } } } cw_fr_free(f); } /* END WRITE TO FD */ } else { /* START WRITE CHANNEL */ ms = cw_tvdiff_ms(last, cw_tvnow()); if (ms <= 0) { res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); if (res > 0) { cw_fr_init_ex(&myf.f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, __PRETTY_FUNCTION__); myf.f.datalen = res; myf.f.samples = res/sizeof(int16_t); myf.f.offset = CW_FRIENDLY_OFFSET; myf.f.data = myf.frdata; if (cw_write(chan, &myf.f) < 0) { res = -1; break; } } else { cw_log(LOG_DEBUG, "No more stream\n"); res = 0; break; } last = cw_tvadd(last, cw_samp2tv(myf.f.samples, 8000)); } else { ms = cw_waitfor(chan, ms); if (ms < 0) { cw_log(LOG_DEBUG, "Hangup detected\n"); res = -1; break; } if (ms) { f = cw_read(chan); if (!f) { cw_log(LOG_DEBUG, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == CW_FRAME_DTMF) { cw_log(LOG_DEBUG, "User pressed a key\n"); cw_fr_free(f); res = 0; break; } cw_fr_free(f); } } /* END WRITE CHANNEL */ } } } close(fds[0]); close(fds[1]); LOCAL_USER_REMOVE(u); if (pid > -1) kill(pid, SIGKILL); if (!res && oreadformat) cw_set_read_format(chan, oreadformat); if (!res && owriteformat) cw_set_write_format(chan, owriteformat); return res; }