void pr_enc(struct sio_enc *enc) { fprintf(stderr, "%s%d", enc->sig ? "s" : "u", enc->bits); if (enc->bps > 1) fprintf(stderr, "%s", enc->le ? "le" : "be"); if (enc->bps != SIO_BPS(enc->bits)) fprintf(stderr, "%d%s", enc->bps, enc->msb ? "msb" : "lsb"); }
static struct sio_par *sndio_initpar(uint32_t srate, uint8_t ch) { struct sio_par *par = NULL; if ((par = mem_zalloc(sizeof(*par), NULL)) == NULL) return NULL; sio_initpar(par); /* sndio doesn't support a-low and u-low */ par->bits = 16; par->bps = SIO_BPS(par->bits); par->sig = 1; par->le = SIO_LE_NATIVE; par->rchan = ch; par->pchan = ch; par->rate = srate; return par; }
static struct sio_par *sndio_initpar(void *arg) { struct sio_par *par; struct auplay_prm *prm = arg; if ((par = malloc(sizeof(struct sio_par))) == NULL) return NULL; sio_initpar(par); /* sndio doesn't support a-low and u-low */ par->bits = 16; par->bps = SIO_BPS(par->bits); par->sig = 1; par->le = 1; par->rchan = prm->ch; par->pchan = prm->ch; par->rate = prm->srate; return par; }
static int SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); struct sio_par par; int status; this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden)); if (this->hidden == NULL) { return SDL_OutOfMemory(); } SDL_memset(this->hidden, 0, sizeof(*this->hidden)); this->hidden->mixlen = this->spec.size; /* !!! FIXME: SIO_DEVANY can be a specific device... */ if ((this->hidden->dev = SNDIO_sio_open(SIO_DEVANY, SIO_PLAY, 0)) == NULL) { SNDIO_CloseDevice(this); return SDL_SetError("sio_open() failed"); } SNDIO_sio_initpar(&par); par.rate = this->spec.freq; par.pchan = this->spec.channels; par.round = this->spec.samples; par.appbufsz = par.round * 2; /* Try for a closest match on audio format */ status = -1; while (test_format && (status < 0)) { if (!SDL_AUDIO_ISFLOAT(test_format)) { par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0; par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0; par.bits = SDL_AUDIO_BITSIZE(test_format); if (SNDIO_sio_setpar(this->hidden->dev, &par) == 0) { continue; } if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) { SNDIO_CloseDevice(this); return SDL_SetError("sio_getpar() failed"); } if (par.bps != SIO_BPS(par.bits)) { continue; } if ((par.bits == 8 * par.bps) || (par.msb)) { status = 0; break; } } test_format = SDL_NextAudioFormat(); } if (status < 0) { SNDIO_CloseDevice(this); return SDL_SetError("sndio: Couldn't find any hardware audio formats"); } if ((par.bps == 4) && (par.sig) && (par.le)) this->spec.format = AUDIO_S32LSB; else if ((par.bps == 4) && (par.sig) && (!par.le)) this->spec.format = AUDIO_S32MSB; else if ((par.bps == 2) && (par.sig) && (par.le)) this->spec.format = AUDIO_S16LSB; else if ((par.bps == 2) && (par.sig) && (!par.le)) this->spec.format = AUDIO_S16MSB; else if ((par.bps == 2) && (!par.sig) && (par.le)) this->spec.format = AUDIO_U16LSB; else if ((par.bps == 2) && (!par.sig) && (!par.le)) this->spec.format = AUDIO_U16MSB; else if ((par.bps == 1) && (par.sig)) this->spec.format = AUDIO_S8; else if ((par.bps == 1) && (!par.sig)) this->spec.format = AUDIO_U8; else { SNDIO_CloseDevice(this); return SDL_SetError("sndio: Got unsupported hardware audio format."); } this->spec.freq = par.rate; this->spec.channels = par.pchan; this->spec.samples = par.round; /* Calculate the final parameters for this audio specification */ SDL_CalculateAudioSpec(&this->spec); /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { SNDIO_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen); if (!SNDIO_sio_start(this->hidden->dev)) { return SDL_SetError("sio_start() failed"); } /* We're ready to rock and roll. :-) */ return 0; }
/* * 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; }