/* Core streaming function for this module * This is what actually produces the data which gets streamed. * * returns: >0 Number of bytes read * 0 Non-fatal error. * <0 Fatal error. */ static int sndio_read(void *self, ref_buffer *rb) { int result; im_sndio_state *s = self; rb->buf = malloc(BUFSIZE * s->par.bps * s->par.rchan); if(!rb->buf) return -1; result = sio_read(s->hdl, rb->buf, BUFSIZE * s->par.bps * s->par.rchan); rb->len = result; rb->aux_data = s->par.rate * s->par.rchan * s->par.bps; if(s->newtrack) { rb->critical = 1; s->newtrack = 0; } if(result == 0) { if(sio_eof(s->hdl)) { LOG_ERROR0("Error reading from audio device"); free(rb->buf); return -1; } } return rb->len; }
/* Retrieves the just recorded buffer, if there is one. */ static int sndio_rec_read(void *buf) { struct pollfd pfd; nfds_t nfds; int ret, nbytes, offset = 0; /* make sure counters have been updated */ nfds = sio_pollfd(hdl, &pfd, POLLIN); poll(&pfd, nfds, 0); sio_revents(hdl, &pfd); if (!(sio_revents(hdl, &pfd) & POLLIN)) return 0; nbytes = sndio_rec_bufsize; while (nbytes) { ret = sio_read(hdl, buf + offset, nbytes); if (sio_eof(hdl)) return 0; offset += ret; nbytes -= ret; } return 1; }
/* write as many blocks as is currently possible */ static void sndio_update(int threaded) { struct pollfd pfd; nfds_t nfds; int i, nblocks, nbytes; /* make sure counters have been updated */ nfds = sio_pollfd(hdl, &pfd, POLLOUT); poll(&pfd, nfds, 0); if (!(sio_revents(hdl, &pfd) & POLLOUT)) return; nblocks = (sndio_play_appbufsz - (sndio_playpos - sndio_realpos)) / sndio_play_round; /* we got POLLOUT, so we can write something. if we don't * write anything, we could underrun. */ if (nblocks < 1) nblocks = 1; for (i = 0; i < nblocks; i++) { sio_write(hdl, sndio_play_bufdata, sndio_play_bufsize); sndio_playpos += sndio_play_round; if (sio_eof(hdl)) { /* print error message? */ return; } _mix_some_samples((uintptr_t) sndio_play_bufdata, 0, sndio_signed); } }
static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) { SndioData *s = s1->priv_data; int64_t bdelay, cur_time; int ret; if ((ret = av_new_packet(pkt, s->buffer_size)) < 0) return ret; ret = sio_read(s->hdl, pkt->data, pkt->size); if (ret == 0 || sio_eof(s->hdl)) { av_free_packet(pkt); return AVERROR_EOF; } pkt->size = ret; s->softpos += ret; /* compute pts of the start of the packet */ cur_time = av_gettime(); bdelay = ret + s->hwpos - s->softpos; /* convert to pts */ pkt->pts = cur_time - ((bdelay * 1000000) / (s->bps * s->channels * s->sample_rate)); return 0; }
unsigned int siofile_read(struct file *file, unsigned char *data, unsigned int count) { struct siofile *f = (struct siofile *)file; unsigned int n; #ifdef DEBUG if (f->rtickets == 0) { file_dbg(&f->file); dbg_puts(": called with no read tickets\n"); } #endif if (count > f->rtickets) count = f->rtickets; n = f->started ? sio_read(f->hdl, data, count) : 0; if (n == 0) { f->file.state &= ~FILE_ROK; if (sio_eof(f->hdl)) { #ifdef DEBUG dbg_puts(f->file.name); dbg_puts(": failed to read from device\n"); #endif file_eof(&f->file); } else { #ifdef DEBUG if (debug_level >= 4) { file_dbg(&f->file); dbg_puts(": reading blocked\n"); } #endif } return 0; } else { f->rtickets -= n; if (f->rtickets == 0) { f->file.state &= ~FILE_ROK; #ifdef DEBUG if (debug_level >= 4) { file_dbg(&f->file); dbg_puts(": read tickets exhausted\n"); } #endif } } return n; }
void siofile_stop(struct file *file) { struct siofile *f = (struct siofile *)file; f->started = 0; f->onmove = NULL; if (!sio_eof(f->hdl) && !sio_stop(f->hdl)) { #ifdef DEBUG dbg_puts(f->file.name); dbg_puts(": failed to stop device\n"); #endif file_close(file); return; } #ifdef DEBUG if (debug_level >= 3) { file_dbg(&f->file); dbg_puts(": stopped\n"); } #endif }
void dev_sio_stop(struct dev *d) { if (!sio_eof(d->sio.hdl) && !sio_stop(d->sio.hdl)) { if (log_level >= 1) { dev_log(d); log_puts(": failed to stop device\n"); } return; } #ifdef DEBUG if (log_level >= 3) { dev_log(d); log_puts(": stopped, load avg = "); log_puti(d->sio.sum_utime / 1000); log_puts(" / "); log_puti(d->sio.sum_wtime / 1000); log_puts("\n"); } #endif timo_del(&d->sio.watchdog); }
static void * sndio_mainloop(void *arg) { #define MAXFDS 8 struct pollfd pfds[MAXFDS]; cubeb_stream *s = arg; int n, eof = 0, prime, nfds, events, revents, state = CUBEB_STATE_STARTED; size_t pstart = 0, pend = 0, rstart = 0, rend = 0; long nfr; DPR("sndio_mainloop()\n"); s->state_cb(s, s->arg, CUBEB_STATE_STARTED); pthread_mutex_lock(&s->mtx); if (!sio_start(s->hdl)) { pthread_mutex_unlock(&s->mtx); return NULL; } DPR("sndio_mainloop(), started\n"); if (s->mode & SIO_PLAY) { pstart = pend = s->nfr * s->pbpf; prime = s->nblks; if (s->mode & SIO_REC) { memset(s->rbuf, 0, s->nfr * s->rbpf); rstart = rend = s->nfr * s->rbpf; } } else { prime = 0; rstart = 0; rend = s->nfr * s->rbpf; } for (;;) { if (!s->active) { DPR("sndio_mainloop() stopped\n"); state = CUBEB_STATE_STOPPED; break; } /* do we have a complete block? */ if ((!(s->mode & SIO_PLAY) || pstart == pend) && (!(s->mode & SIO_REC) || rstart == rend)) { if (eof) { DPR("sndio_mainloop() drained\n"); state = CUBEB_STATE_DRAINED; break; } if ((s->mode & SIO_REC) && s->conv) s16_to_float(s->rbuf, s->nfr * s->rchan); /* invoke call-back, it returns less that s->nfr if done */ pthread_mutex_unlock(&s->mtx); nfr = s->data_cb(s, s->arg, s->rbuf, s->pbuf, s->nfr); pthread_mutex_lock(&s->mtx); if (nfr < 0) { DPR("sndio_mainloop() cb err\n"); state = CUBEB_STATE_ERROR; break; } s->swpos += nfr; /* was this last call-back invocation (aka end-of-stream) ? */ if (nfr < s->nfr) { if (!(s->mode & SIO_PLAY) || nfr == 0) { state = CUBEB_STATE_DRAINED; break; } /* need to write (aka drain) the partial play block we got */ pend = nfr * s->pbpf; eof = 1; } if (prime > 0) prime--; if ((s->mode & SIO_PLAY) && s->conv) float_to_s16(s->pbuf, nfr * s->pchan); if (s->mode & SIO_REC) rstart = 0; if (s->mode & SIO_PLAY) pstart = 0; } events = 0; if ((s->mode & SIO_REC) && rstart < rend && prime == 0) events |= POLLIN; if ((s->mode & SIO_PLAY) && pstart < pend) events |= POLLOUT; nfds = sio_pollfd(s->hdl, pfds, events); if (nfds > 0) { pthread_mutex_unlock(&s->mtx); n = poll(pfds, nfds, -1); pthread_mutex_lock(&s->mtx); if (n < 0) continue; } revents = sio_revents(s->hdl, pfds); if (revents & POLLHUP) { state = CUBEB_STATE_ERROR; break; } if (revents & POLLOUT) { n = sio_write(s->hdl, s->pbuf + pstart, pend - pstart); if (n == 0 && sio_eof(s->hdl)) { DPR("sndio_mainloop() werr\n"); state = CUBEB_STATE_ERROR; break; } pstart += n; } if (revents & POLLIN) { n = sio_read(s->hdl, s->rbuf + rstart, rend - rstart); if (n == 0 && sio_eof(s->hdl)) { DPR("sndio_mainloop() rerr\n"); state = CUBEB_STATE_ERROR; break; } rstart += n; } /* skip rec block, if not recording (yet) */ if (prime > 0 && (s->mode & SIO_REC)) rstart = rend; } sio_stop(s->hdl); s->hwpos = s->swpos; pthread_mutex_unlock(&s->mtx); s->state_cb(s, s->arg, state); return NULL; }