void abuf_log(struct abuf *buf) { log_putu(buf->start); log_puts("+"); log_putu(buf->used); log_puts("/"); log_putu(buf->len); }
static int afile_aiff_readcomm(struct afile *f, unsigned int csize, int comp, unsigned int *nfr) { struct aiff_comm comm; unsigned int csize_min; unsigned int e, m; csize_min = comp ? sizeof(struct aiff_comm) : sizeof(struct aiff_commbase); if (csize < csize_min) { log_puts(f->path); log_puts(": "); log_putu(csize); log_puts(": bogus comm chunk size\n"); return 0; } if (read(f->fd, &comm, csize_min) != csize_min) { log_puts(f->path); log_puts(": failed to read comm chunk\n"); return 0; } f->nch = be16_get(&comm.base.nch); e = be16_get(&comm.base.rate_ex); m = be32_get(&comm.base.rate_hi); if (e < 0x3fff || e > 0x3fff + 31) { log_puts(f->path); log_puts(": malformed sample rate\n"); return 0; } f->rate = m >> (0x3fff + 31 - e); if (comp) { if (memcmp(comm.comp_id, aiff_id_none, 4) == 0) { f->fmt = AFILE_FMT_PCM; f->par.bits = be16_get(&comm.base.bits); } else if (memcmp(comm.comp_id, aiff_id_fl32, 4) == 0) { f->fmt = AFILE_FMT_FLOAT; f->par.bits = 32; } else if (memcmp(comm.comp_id, aiff_id_ulaw, 4) == 0) { f->fmt = AFILE_FMT_ULAW; f->par.bits = 8; } else if (memcmp(comm.comp_id, aiff_id_alaw, 4) == 0) { f->fmt = AFILE_FMT_ALAW; f->par.bits = 8; } else { log_puts(f->path); log_puts(": unsupported encoding\n"); return 0; } } else { f->fmt = AFILE_FMT_PCM; f->par.bits = be16_get(&comm.base.bits); } f->par.le = 0; f->par.sig = 1; f->par.msb = 1; f->par.bps = (f->par.bits + 7) / 8; *nfr = be32_get(&comm.base.nfr); return afile_checkpar(f); }
/* * advance the writer pointer by "count" bytes */ void abuf_wcommit(struct abuf *buf, int count) { #ifdef DEBUG if (count < 0 || count > (buf->len - buf->used)) { log_puts("abuf_wcommit: bad count = "); log_putu(count); log_puts("\n"); panic(); } #endif buf->used += count; }
static int afile_checkpar(struct afile *f) { if (f->nch == 0 || f->nch > NCHAN_MAX) { log_puts(f->path); log_puts(": "); log_putu(f->nch); log_puts(": unsupported number of channels\n"); return 0; } if (f->rate < RATE_MIN || f->rate > RATE_MAX) { log_puts(f->path); log_puts(": "); log_putu(f->rate); log_puts(": unsupported rate\n"); return 0; } if (f->par.bits < BITS_MIN || f->par.bits > BITS_MAX) { log_puts(f->path); log_puts(": "); log_putu(f->par.bits); log_puts(": unsupported bits per sample\n"); return 0; } if (f->par.bits > f->par.bps * 8) { log_puts(f->path); log_puts(": bits larger than bytes-per-sample\n"); return 0; } if (f->fmt == AFILE_FMT_FLOAT && f->par.bits != 32) { log_puts(f->path); log_puts(": only 32-bit floating points are supported\n"); return 0; } return 1; }
void abuf_done(struct abuf *buf) { #ifdef DEBUG if (buf->used > 0) { if (log_level >= 3) { log_puts("deleting non-empty buffer, used = "); log_putu(buf->used); log_puts("\n"); } } #endif xfree(buf->data); buf->data = (void *)0xdeadbeef; }
/* * discard "count" bytes at the start postion. */ void abuf_rdiscard(struct abuf *buf, int count) { #ifdef DEBUG if (count < 0 || count > buf->used) { log_puts("abuf_rdiscard: bad count = "); log_putu(count); log_puts("\n"); panic(); } #endif buf->used -= count; buf->start += count; if (buf->start >= buf->len) buf->start -= buf->len; }
static int afile_aiff_readdata(struct afile *f, unsigned int csize, unsigned int *roffs) { struct aiff_data data; if (csize < sizeof(struct aiff_data)) { log_puts(f->path); log_puts(": "); log_putu(csize); log_puts(": bogus data chunk size\n"); return 0; } csize = sizeof(struct aiff_data); if (read(f->fd, &data, csize) != csize) { log_puts(f->path); log_puts(": failed to read data chunk\n"); return 0; } *roffs = csize + be32_get(&data.offs); return 1; }
void midi_log(struct midi *ep) { log_puts("midi"); log_putu(ep - midi_ep); }
static int afile_au_readhdr(struct afile *f) { struct au_hdr hdr; unsigned int fmt; if (!afile_readhdr(f, &hdr, sizeof(struct au_hdr))) return 0; if (memcmp(&hdr.id, &au_id, 4) != 0) { log_puts(f->path); log_puts(": not a .au file\n"); return 0; } f->startpos = be32_get(&hdr.offs); f->endpos = f->startpos + be32_get(&hdr.size); fmt = be32_get(&hdr.fmt); switch (fmt) { case AU_FMT_PCM8: f->fmt = AFILE_FMT_PCM; f->par.bits = 8; break; case AU_FMT_PCM16: f->fmt = AFILE_FMT_PCM; f->par.bits = 16; break; case AU_FMT_PCM24: f->fmt = AFILE_FMT_PCM; f->par.bits = 24; break; case AU_FMT_PCM32: f->fmt = AFILE_FMT_PCM; f->par.bits = 32; break; case AU_FMT_ULAW: f->fmt = AFILE_FMT_ULAW; f->par.bits = 8; break; case AU_FMT_ALAW: f->fmt = AFILE_FMT_ALAW; f->par.bits = 8; break; case AU_FMT_FLOAT: f->fmt = AFILE_FMT_FLOAT; f->par.bits = 32; break; default: log_puts(f->path); log_puts(": "); log_putu(fmt); log_puts(": unsupported encoding\n"); return 0; } f->par.le = 0; f->par.sig = 1; f->par.bps = f->par.bits / 8; f->par.msb = 0; f->rate = be32_get(&hdr.rate); f->nch = be32_get(&hdr.nch); if (lseek(f->fd, f->startpos, SEEK_SET) < 0) { log_puts(f->path); log_puts(": "); log_puts("failed to seek to data chunk\n"); return 0; } return afile_checkpar(f); }
static int afile_wav_readfmt(struct afile *f, unsigned int csize) { struct wav_fmt fmt; unsigned int wenc; if (csize < WAV_FMT_SIZE) { log_puts(f->path); log_puts(": "); log_putu(csize); log_puts(": bogus format chunk size\n"); return 0; } if (csize > WAV_FMT_EXT_SIZE) csize = WAV_FMT_EXT_SIZE; if (read(f->fd, &fmt, csize) != csize) { log_puts(f->path); log_puts(": failed to read format chunk\n"); return 0; } wenc = le16_get(&fmt.fmt); f->par.bits = le16_get(&fmt.bits); if (wenc == WAV_FMT_EXT) { if (csize != WAV_FMT_EXT_SIZE) { log_puts(f->path); log_puts(": missing extended format chunk\n"); return 0; } if (memcmp(fmt.guid, wav_guid, sizeof(wav_guid)) != 0) { log_puts(f->path); log_puts(": unknown format (GUID)\n"); return 0; } f->par.bps = (f->par.bits + 7) / 8; f->par.bits = le16_get(&fmt.valbits); wenc = le16_get(&fmt.extfmt); } else f->par.bps = (f->par.bits + 7) / 8; f->nch = le16_get(&fmt.nch); f->rate = le32_get(&fmt.rate); f->par.le = 1; f->par.msb = 1; switch (wenc) { case WAV_FMT_PCM: f->fmt = AFILE_FMT_PCM; f->par.sig = (f->par.bits <= 8) ? 0 : 1; break; case WAV_FMT_ALAW: f->fmt = AFILE_FMT_ALAW; f->par.bits = 8; f->par.bps = 1; break; case WAV_FMT_ULAW: f->fmt = AFILE_FMT_ULAW; f->par.bits = 8; f->par.bps = 1; break; case WAV_FMT_FLOAT: f->fmt = AFILE_FMT_FLOAT; break; default: log_putu(wenc); log_puts(": unsupported encoding\n"); return 0; } return afile_checkpar(f); }
/* * open the device. */ int dev_sio_open(struct dev *d) { struct sio_par par; unsigned int mode = d->mode & (MODE_PLAY | MODE_REC); d->sio.hdl = sio_open(d->path, mode, 1); if (d->sio.hdl == NULL) { if (mode != (SIO_PLAY | SIO_REC)) return 0; d->sio.hdl = sio_open(d->path, SIO_PLAY, 1); if (d->sio.hdl != NULL) mode = SIO_PLAY; else { d->sio.hdl = sio_open(d->path, SIO_REC, 1); if (d->sio.hdl != NULL) mode = SIO_REC; else return 0; } if (log_level >= 1) { log_puts("warning, device opened in "); log_puts(mode == SIO_PLAY ? "play-only" : "rec-only"); log_puts(" mode\n"); } } sio_initpar(&par); par.bits = d->par.bits; par.bps = d->par.bps; par.sig = d->par.sig; par.le = d->par.le; par.msb = d->par.msb; if (mode & SIO_PLAY) par.pchan = d->pchan; if (mode & SIO_REC) par.rchan = d->rchan; if (d->bufsz) par.appbufsz = d->bufsz; if (d->round) par.round = d->round; if (d->rate) par.rate = d->rate; if (!sio_setpar(d->sio.hdl, &par)) goto bad_close; if (!sio_getpar(d->sio.hdl, &par)) goto bad_close; #ifdef DEBUG /* * We support any parameter combination exposed by the kernel, * and we have no other choice than trusting the kernel for * returning correct parameters. But let's check parameters * early and nicely report kernel bugs rather than crashing * later in memset(), malloc() or alike. */ if (par.bits > BITS_MAX) { log_puts(d->path); log_puts(": "); log_putu(par.bits); log_puts(": unsupported number of bits\n"); goto bad_close; } if (par.bps > SIO_BPS(BITS_MAX)) { log_puts(d->path); log_puts(": "); log_putu(par.bps); log_puts(": unsupported sample size\n"); goto bad_close; } if ((mode & SIO_PLAY) && par.pchan > NCHAN_MAX) { log_puts(d->path); log_puts(": "); log_putu(par.pchan); log_puts(": unsupported number of play channels\n"); goto bad_close; } if ((mode & SIO_REC) && par.rchan > NCHAN_MAX) { log_puts(d->path); log_puts(": "); log_putu(par.rchan); log_puts(": unsupported number of rec channels\n"); goto bad_close; } if (par.bufsz == 0 || par.bufsz > RATE_MAX) { log_puts(d->path); log_puts(": "); log_putu(par.bufsz); log_puts(": unsupported buffer size\n"); goto bad_close; } if (par.round == 0 || par.round > par.bufsz || par.bufsz % par.round != 0) { log_puts(d->path); log_puts(": "); log_putu(par.round); log_puts(": unsupported block size\n"); goto bad_close; } if (par.rate == 0 || par.rate > RATE_MAX) { log_puts(d->path); log_puts(": "); log_putu(par.rate); log_puts(": unsupported rate\n"); goto bad_close; } #endif d->par.bits = par.bits; d->par.bps = par.bps; d->par.sig = par.sig; d->par.le = par.le; d->par.msb = par.msb; if (mode & SIO_PLAY) d->pchan = par.pchan; if (mode & SIO_REC) d->rchan = par.rchan; d->bufsz = par.bufsz; d->round = par.round; d->rate = par.rate; if (!(mode & MODE_PLAY)) d->mode &= ~(MODE_PLAY | MODE_MON); if (!(mode & MODE_REC)) d->mode &= ~MODE_REC; sio_onmove(d->sio.hdl, dev_sio_onmove, d); d->sio.file = file_new(&dev_sio_ops, d, d->path, sio_nfds(d->sio.hdl)); timo_set(&d->sio.watchdog, dev_sio_timeout, d); return 1; bad_close: sio_close(d->sio.hdl); return 0; }
void dev_sio_run(void *arg) { struct dev *d = arg; unsigned char *data, *base; unsigned int n; /* * sio_read() and sio_write() would block at the end of the * cycle so we *must* return and restart poll()'ing. Otherwise * we may trigger dev_cycle() which would make all clients * underrun (ex, on a play-only device) */ for (;;) { if (d->pstate != DEV_RUN) return; switch (d->sio.cstate) { case DEV_SIO_READ: #ifdef DEBUG if (!(d->sio.events & POLLIN)) { dev_log(d); log_puts(": recording, but POLLIN not set\n"); panic(); } if (d->sio.todo == 0) { dev_log(d); log_puts(": can't read data\n"); panic(); } if (d->prime > 0) { dev_log(d); log_puts(": unexpected data\n"); panic(); } #endif base = d->decbuf ? d->decbuf : (unsigned char *)d->rbuf; data = base + d->rchan * d->round * d->par.bps - d->sio.todo; n = sio_read(d->sio.hdl, data, d->sio.todo); d->sio.todo -= n; #ifdef DEBUG if (log_level >= 4) { dev_log(d); log_puts(": read "); log_putu(n); log_puts(": bytes, todo "); log_putu(d->sio.todo); log_puts("/"); log_putu(d->round * d->rchan * d->par.bps); log_puts("\n"); } #endif if (d->sio.todo > 0) return; #ifdef DEBUG d->sio.rused -= d->round; if (log_level >= 2) { if (d->sio.rused >= d->round) { dev_log(d); log_puts(": rec hw xrun, rused = "); log_puti(d->sio.rused); log_puts("/"); log_puti(d->bufsz); log_puts("\n"); } if (d->sio.rused < 0 || d->sio.rused >= d->bufsz) { dev_log(d); log_puts(": out of bounds rused = "); log_puti(d->sio.rused); log_puts("/"); log_puti(d->bufsz); log_puts("\n"); } } #endif d->sio.cstate = DEV_SIO_CYCLE; break; case DEV_SIO_CYCLE: timo_del(&d->sio.watchdog); timo_add(&d->sio.watchdog, WATCHDOG_USEC); #ifdef DEBUG /* * check that we're called at cycle boundary: * either after a recorded block, or when POLLOUT is * raised */ if (!((d->mode & MODE_REC) && d->prime == 0) && !(d->sio.events & POLLOUT)) { dev_log(d); log_puts(": cycle not at block boundary\n"); panic(); } #endif dev_cycle(d); if (d->mode & MODE_PLAY) { d->sio.cstate = DEV_SIO_WRITE; d->sio.todo = d->round * d->pchan * d->par.bps; break; } else { d->sio.cstate = DEV_SIO_READ; d->sio.todo = d->round * d->rchan * d->par.bps; return; } case DEV_SIO_WRITE: #ifdef DEBUG if (d->sio.todo == 0) { dev_log(d); log_puts(": can't write data\n"); panic(); } #endif base = d->encbuf ? d->encbuf : (unsigned char *)DEV_PBUF(d); data = base + d->pchan * d->round * d->par.bps - d->sio.todo; n = sio_write(d->sio.hdl, data, d->sio.todo); d->sio.todo -= n; #ifdef DEBUG if (log_level >= 4) { dev_log(d); log_puts(": wrote "); log_putu(n); log_puts(" bytes, todo "); log_putu(d->sio.todo); log_puts("/"); log_putu(d->round * d->pchan * d->par.bps); log_puts("\n"); } #endif if (d->sio.todo > 0) return; #ifdef DEBUG d->sio.pused += d->round; if (log_level >= 2) { if (d->prime == 0 && d->sio.pused <= d->bufsz - d->round) { dev_log(d); log_puts(": play hw xrun, pused = "); log_puti(d->sio.pused); log_puts("/"); log_puti(d->bufsz); log_puts("\n"); } if (d->sio.pused < 0 || d->sio.pused > d->bufsz) { /* device driver or libsndio bug */ dev_log(d); log_puts(": out of bounds pused = "); log_puti(d->sio.pused); log_puts("/"); log_puti(d->bufsz); log_puts("\n"); } } #endif d->poffs += d->round; if (d->poffs == d->psize) d->poffs = 0; if ((d->mode & MODE_REC) && d->prime == 0) { d->sio.cstate = DEV_SIO_READ; d->sio.todo = d->round * d->rchan * d->par.bps; } else d->sio.cstate = DEV_SIO_CYCLE; return; } } }