static int sio_psleep(struct sio_hdl *hdl, int event) { struct pollfd pfd[SIO_MAXNFDS]; int revents; int nfds; nfds = sio_nfds(hdl); if (nfds > SIO_MAXNFDS) { DPRINTF("sio_psleep: %d: too many descriptors\n", nfds); hdl->eof = 1; return 0; } for (;;) { nfds = sio_pollfd(hdl, pfd, event); while (poll(pfd, nfds, -1) < 0) { if (errno == EINTR) continue; DPERROR("sio_psleep: poll"); hdl->eof = 1; return 0; } revents = sio_revents(hdl, pfd); if (revents & POLLHUP) { DPRINTF("sio_psleep: hang-up\n"); return 0; } if (revents & event) break; } return 1; }
int siofile_nfds(struct file *file) { return sio_nfds(((struct siofile *)file)->hdl); }
/* * Open the device. */ struct siofile * siofile_new(struct fileops *ops, char *path, unsigned int *rmode, struct aparams *ipar, struct aparams *opar, unsigned int *bufsz, unsigned int *round) { struct sio_par par; struct sio_hdl *hdl; struct siofile *f; unsigned int mode = *rmode; hdl = sio_open(path, mode, 1); if (hdl == NULL) { if (mode != (SIO_PLAY | SIO_REC)) return NULL; hdl = sio_open(path, SIO_PLAY, 1); if (hdl != NULL) mode = SIO_PLAY; else { hdl = sio_open(path, SIO_REC, 1); if (hdl != NULL) mode = SIO_REC; else return NULL; } #ifdef DEBUG if (debug_level >= 1) { dbg_puts("warning, device opened in "); dbg_puts(mode == SIO_PLAY ? "play-only" : "rec-only"); dbg_puts(" mode\n"); } #endif } sio_initpar(&par); if (mode & SIO_REC) { par.bits = ipar->bits; par.bps = ipar->bps; par.sig = ipar->sig; par.le = ipar->le; par.msb = ipar->msb; par.rate = ipar->rate; par.rchan = ipar->cmax + 1; } else { par.bits = opar->bits; par.bps = opar->bps; par.sig = opar->sig; par.le = opar->le; par.msb = opar->msb; par.rate = opar->rate; } if (mode & SIO_PLAY) par.pchan = opar->cmax + 1; if (*bufsz) par.appbufsz = *bufsz; if (*round) par.round = *round; if (!sio_setpar(hdl, &par)) goto bad_close; if (!sio_getpar(hdl, &par)) goto bad_close; if (mode & SIO_REC) { ipar->bits = par.bits; ipar->bps = par.bps; ipar->sig = par.sig; ipar->le = par.le; ipar->msb = par.msb; ipar->rate = par.rate; ipar->cmin = 0; ipar->cmax = par.rchan - 1; } if (mode & SIO_PLAY) { opar->bits = par.bits; opar->bps = par.bps; opar->sig = par.sig; opar->le = par.le; opar->msb = par.msb; opar->rate = par.rate; opar->cmin = 0; opar->cmax = par.pchan - 1; } *rmode = mode; *bufsz = par.bufsz; *round = par.round; f = (struct siofile *)file_new(ops, path, sio_nfds(hdl)); if (f == NULL) goto bad_close; f->hdl = hdl; f->started = 0; f->wtickets = 0; f->rtickets = 0; f->wbpf = par.pchan * par.bps; f->rbpf = par.rchan * par.bps; f->bufsz = par.bufsz; sio_onmove(f->hdl, siofile_cb, f); return f; bad_close: sio_close(hdl); return NULL; }
/* * open device and setup parameters * return: 0=success -1=fail */ static int init(struct ao *ao) { struct priv *p = ao->priv; struct af_to_par { int format, bits, sig, le; } static const af_to_par[] = { {AF_FORMAT_U8, 8, 0, 0}, {AF_FORMAT_S8, 8, 1, 0}, {AF_FORMAT_U16_LE, 16, 0, 1}, {AF_FORMAT_U16_BE, 16, 0, 0}, {AF_FORMAT_S16_LE, 16, 1, 1}, {AF_FORMAT_S16_BE, 16, 1, 0}, {AF_FORMAT_U24_LE, 16, 0, 1}, {AF_FORMAT_U24_BE, 24, 0, 0}, {AF_FORMAT_S24_LE, 24, 1, 1}, {AF_FORMAT_S24_BE, 24, 1, 0}, {AF_FORMAT_U32_LE, 32, 0, 1}, {AF_FORMAT_U32_BE, 32, 0, 0}, {AF_FORMAT_S32_LE, 32, 1, 1}, {AF_FORMAT_S32_BE, 32, 1, 0} }, *ap; int i; p->hdl = sio_open(p->dev, SIO_PLAY, 0); if (p->hdl == NULL) { MP_ERR(ao, "can't open sndio %s\n", p->dev); goto error; } ao->format = af_fmt_from_planar(ao->format); sio_initpar(&p->par); for (i = 0, ap = af_to_par;; i++, ap++) { if (i == sizeof(af_to_par) / sizeof(struct af_to_par)) { MP_VERBOSE(ao, "unsupported format\n"); p->par.bits = 16; p->par.sig = 1; p->par.le = SIO_LE_NATIVE; break; } if (ap->format == ao->format) { p->par.bits = ap->bits; p->par.sig = ap->sig; if (ap->bits > 8) p->par.le = ap->le; if (ap->bits != SIO_BPS(ap->bits)) p->par.bps = ap->bits / 8; break; } } p->par.rate = ao->samplerate; struct mp_chmap_sel sel = {0}; for (int n = 0; n < MP_NUM_CHANNELS+1; n++) mp_chmap_sel_add_map(&sel, &sndio_layouts[n]); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto error; p->par.pchan = ao->channels.num; p->par.appbufsz = p->par.rate * 250 / 1000; /* 250ms buffer */ p->par.round = p->par.rate * 10 / 1000; /* 10ms block size */ if (!sio_setpar(p->hdl, &p->par)) { MP_ERR(ao, "couldn't set params\n"); goto error; } if (!sio_getpar(p->hdl, &p->par)) { MP_ERR(ao, "couldn't get params\n"); goto error; } if (p->par.bits == 8 && p->par.bps == 1) { ao->format = p->par.sig ? AF_FORMAT_S8 : AF_FORMAT_U8; } else if (p->par.bits == 16 && p->par.bps == 2) { ao->format = p->par.sig ? (p->par.le ? AF_FORMAT_S16_LE : AF_FORMAT_S16_BE) : (p->par.le ? AF_FORMAT_U16_LE : AF_FORMAT_U16_BE); } else if ((p->par.bits == 24 || p->par.msb) && p->par.bps == 3) { ao->format = p->par.sig ? (p->par.le ? AF_FORMAT_S24_LE : AF_FORMAT_S24_BE) : (p->par.le ? AF_FORMAT_U24_LE : AF_FORMAT_U24_BE); } else if ((p->par.bits == 32 || p->par.msb) && p->par.bps == 4) { ao->format = p->par.sig ? (p->par.le ? AF_FORMAT_S32_LE : AF_FORMAT_S32_BE) : (p->par.le ? AF_FORMAT_U32_LE : AF_FORMAT_U32_BE); } else { MP_ERR(ao, "couldn't set format\n"); goto error; } ao->bps = p->par.bps * p->par.pchan * p->par.rate; p->havevol = sio_onvol(p->hdl, volcb, p); sio_onmove(p->hdl, movecb, p); p->delay = 0; if (!sio_start(p->hdl)) MP_ERR(ao, "init: couldn't start\n"); p->pfd = calloc (sio_nfds(p->hdl), sizeof (struct pollfd)); if (!p->pfd) goto error; return 0; error: if (p->hdl) sio_close(p->hdl); return -1; }
/* * 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; }
static PaError OpenStream(struct PaUtilHostApiRepresentation *hostApi, PaStream **stream, const PaStreamParameters *inputPar, const PaStreamParameters *outputPar, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData) { PaSndioHostApiRepresentation *sndioHostApi = (PaSndioHostApiRepresentation *)hostApi; PaSndioStream *s; PaError err; struct sio_hdl *hdl; struct sio_par par; unsigned mode; int readChannels, writeChannels; PaSampleFormat readFormat, writeFormat, deviceFormat; PA_DEBUG(("OpenStream:\n")); mode = 0; readChannels = writeChannels = 0; readFormat = writeFormat = 0; sio_initpar(&par); if (outputPar && outputPar->channelCount > 0) { if (outputPar->device != 0) { PA_DEBUG(("OpenStream: %d: bad output device\n", outputPar->device)); return paInvalidDevice; } if (outputPar->hostApiSpecificStreamInfo) { PA_DEBUG(("OpenStream: output specific info\n")); return paIncompatibleHostApiSpecificStreamInfo; } if (!SampleFormatToSndioParameters(&par, outputPar->sampleFormat)) { return paSampleFormatNotSupported; } writeFormat = outputPar->sampleFormat; writeChannels = par.pchan = outputPar->channelCount; mode |= SIO_PLAY; } if (inputPar && inputPar->channelCount > 0) { if (inputPar->device != 0) { PA_DEBUG(("OpenStream: %d: bad input device\n", inputPar->device)); return paInvalidDevice; } if (inputPar->hostApiSpecificStreamInfo) { PA_DEBUG(("OpenStream: input specific info\n")); return paIncompatibleHostApiSpecificStreamInfo; } if (!SampleFormatToSndioParameters(&par, inputPar->sampleFormat)) { return paSampleFormatNotSupported; } readFormat = inputPar->sampleFormat; readChannels = par.rchan = inputPar->channelCount; mode |= SIO_REC; } par.rate = sampleRate; if (framesPerBuffer != paFramesPerBufferUnspecified) par.round = framesPerBuffer; PA_DEBUG(("OpenStream: mode = %x, trying rate = %u\n", mode, par.rate)); hdl = sio_open(SIO_DEVANY, mode, 0); if (hdl == NULL) return paUnanticipatedHostError; if (!sio_setpar(hdl, &par)) { sio_close(hdl); return paUnanticipatedHostError; } if (!sio_getpar(hdl, &par)) { sio_close(hdl); return paUnanticipatedHostError; } if (!SndioParametersToSampleFormat(&par, &deviceFormat)) { sio_close(hdl); return paSampleFormatNotSupported; } if ((mode & SIO_REC) && par.rchan != inputPar->channelCount) { PA_DEBUG(("OpenStream: rchan(%u) != %d\n", par.rchan, inputPar->channelCount)); sio_close(hdl); return paInvalidChannelCount; } if ((mode & SIO_PLAY) && par.pchan != outputPar->channelCount) { PA_DEBUG(("OpenStream: pchan(%u) != %d\n", par.pchan, outputPar->channelCount)); sio_close(hdl); return paInvalidChannelCount; } if ((double)par.rate < sampleRate * 0.995 || (double)par.rate > sampleRate * 1.005) { PA_DEBUG(("OpenStream: rate(%u) != %g\n", par.rate, sampleRate)); sio_close(hdl); return paInvalidSampleRate; } s = (PaSndioStream *)PaUtil_AllocateMemory(sizeof(PaSndioStream)); if (s == NULL) { sio_close(hdl); return paInsufficientMemory; } PaUtil_InitializeStreamRepresentation(&s->base, streamCallback ? &sndioHostApi->callback : &sndioHostApi->blocking, streamCallback, userData); PA_DEBUG(("readChannels = %d, writeChannels = %d, readFormat = %x, writeFormat = %x\n", readChannels, writeChannels, readFormat, writeFormat)); err = PaUtil_InitializeBufferProcessor(&s->bufferProcessor, readChannels, readFormat, deviceFormat, writeChannels, writeFormat, deviceFormat, sampleRate, streamFlags, framesPerBuffer, par.round, paUtilFixedHostBufferSize, streamCallback, userData); if (err) { PA_DEBUG(("OpenStream: PaUtil_InitializeBufferProcessor failed\n")); PaUtil_FreeMemory(s); sio_close(hdl); return err; } if (mode & SIO_REC) { s->readBuffer = malloc(par.round * par.rchan * par.bps); if (s->readBuffer == NULL) { PA_DEBUG(("OpenStream: failed to allocate readBuffer\n")); PaUtil_FreeMemory(s); sio_close(hdl); return paInsufficientMemory; } } if (mode & SIO_PLAY) { s->writeBuffer = malloc(par.round * par.pchan * par.bps); if (s->writeBuffer == NULL) { PA_DEBUG(("OpenStream: failed to allocate writeBuffer\n")); free(s->readBuffer); PaUtil_FreeMemory(s); sio_close(hdl); return paInsufficientMemory; } } s->nfds = sio_nfds(hdl); s->pfds = malloc(sizeof(struct pollfd) * s->nfds); s->base.streamInfo.inputLatency = 0; s->base.streamInfo.outputLatency = (mode & SIO_PLAY) ? (double)(par.bufsz + PaUtil_GetBufferProcessorOutputLatencyFrames(&s->bufferProcessor)) / (double)par.rate : 0; s->base.streamInfo.sampleRate = par.rate; s->active = 0; s->stopped = 1; s->mode = mode; s->hdl = hdl; s->par = par; *stream = s; PA_DEBUG(("OpenStream: done\n")); return paNoError; }