From 39ec20119841c84500e589fee15c10e9fe6c0c97 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Tue, 31 Aug 2021 14:30:07 -0700 Subject: [PATCH] alsa: Port to tinyalsa --- libsndio/debug.c | 2 +- libsndio/sio_alsa.c | 747 +++++++++++++++----------------------------- 2 files changed, 247 insertions(+), 502 deletions(-) diff --git a/libsndio/debug.c b/libsndio/debug.c index 304975a..40fdc92 100644 --- a/libsndio/debug.c +++ b/libsndio/debug.c @@ -35,7 +35,7 @@ _sndio_debug_init(void) if (_sndio_debug < 0) { dbg = issetugid() ? NULL : getenv("SNDIO_DEBUG"); - if (!dbg || sscanf(dbg, "%u", &_sndio_debug) != 1) + if (!dbg || sscanf(dbg, "%d", &_sndio_debug) != 1) _sndio_debug = 0; } } diff --git a/libsndio/sio_alsa.c b/libsndio/sio_alsa.c index 6107617..e460bf6 100644 --- a/libsndio/sio_alsa.c +++ b/libsndio/sio_alsa.c @@ -29,31 +29,28 @@ #include #include #include -#include +#include #include "debug.h" #include "sio_priv.h" #include "bsd-compat.h" -#define DEVNAME_PREFIX "hw:" - #ifdef DEBUG -static snd_output_t *output = NULL; -#define DALSA(str, err) fprintf(stderr, "%s: %s\n", str, snd_strerror(err)) +#define DALSA(str, pcm) fprintf(stderr, "%s: %s\n", str, pcm_get_error(pcm)) #else -#define DALSA(str, err) do {} while (0) +#define DALSA(str, pcm) do {} while (0) #endif struct sio_alsa_hdl { struct sio_hdl sio; struct sio_par par; - char *devname; - snd_pcm_t *opcm; - snd_pcm_t *ipcm; + struct pcm_params *opar; + struct pcm_params *ipar; + struct pcm *opcm; + struct pcm *ipcm; unsigned ibpf, obpf; /* bytes per frame */ int iused, oused; /* frames used in hardware fifos */ int idelta, odelta; /* position reported to client */ - int nfds, infds, onfds; int running; int events; int ipartial, opartial; @@ -102,90 +99,56 @@ static unsigned int cap_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 }; -static snd_pcm_format_t cap_fmts[] = { +static enum pcm_format cap_fmts[] = { /* XXX add s24le3 and s24be3 */ - SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_BE, - SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_BE, - SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE, - SND_PCM_FORMAT_U8 + PCM_FORMAT_S32_LE, PCM_FORMAT_S32_BE, + PCM_FORMAT_S24_LE, PCM_FORMAT_S24_BE, + PCM_FORMAT_S16_LE, PCM_FORMAT_S16_BE, + PCM_FORMAT_S8 }; /* * convert ALSA format to sio_par encoding */ static int -sio_alsa_fmttopar(struct sio_alsa_hdl *hdl, snd_pcm_format_t fmt, +sio_alsa_fmttopar(struct sio_alsa_hdl *hdl, enum pcm_format fmt, unsigned int *bits, unsigned int *sig, unsigned int *le) { switch (fmt) { - case SND_PCM_FORMAT_U8: - *bits = 8; - *sig = 0; - break; - case SND_PCM_FORMAT_S8: + case PCM_FORMAT_S8: *bits = 8; *sig = 1; break; - case SND_PCM_FORMAT_S16_LE: + case PCM_FORMAT_S16_LE: *bits = 16; *sig = 1; *le = 1; break; - case SND_PCM_FORMAT_S16_BE: + case PCM_FORMAT_S16_BE: *bits = 16; *sig = 1; *le = 0; break; - case SND_PCM_FORMAT_U16_LE: - *bits = 16; - *sig = 0; - *le = 1; - break; - case SND_PCM_FORMAT_U16_BE: - *bits = 16; - *sig = 0; - *le = 0; - break; - case SND_PCM_FORMAT_S24_LE: + case PCM_FORMAT_S24_LE: *bits = 24; *sig = 1; *le = 1; break; - case SND_PCM_FORMAT_S24_BE: + case PCM_FORMAT_S24_BE: *bits = 24; *sig = 1; *le = 0; break; - case SND_PCM_FORMAT_U24_LE: - *bits = 24; - *sig = 0; - *le = 1; - break; - case SND_PCM_FORMAT_U24_BE: - *bits = 24; - *sig = 0; - *le = 0; - break; - case SND_PCM_FORMAT_S32_LE: + case PCM_FORMAT_S32_LE: *bits = 32; *sig = 1; *le = 1; break; - case SND_PCM_FORMAT_S32_BE: + case PCM_FORMAT_S32_BE: *bits = 32; *sig = 1; *le = 0; break; - case SND_PCM_FORMAT_U32_LE: - *bits = 32; - *sig = 0; - *le = 1; - break; - case SND_PCM_FORMAT_U32_BE: - *bits = 32; - *sig = 0; - *le = 0; - break; default: DPRINTF("sio_alsa_fmttopar: 0x%x: unsupported format\n", fmt); hdl->sio.eof = 1; @@ -199,78 +162,19 @@ sio_alsa_fmttopar(struct sio_alsa_hdl *hdl, snd_pcm_format_t fmt, * convert sio_par encoding to ALSA format */ static void -sio_alsa_enctofmt(struct sio_alsa_hdl *hdl, snd_pcm_format_t *rfmt, +sio_alsa_enctofmt(struct sio_alsa_hdl *hdl, enum pcm_format *rfmt, unsigned int bits, unsigned int sig, unsigned int le) { - if (bits == 8) { - if (sig == ~0U || !sig) - *rfmt = SND_PCM_FORMAT_U8; - else - *rfmt = SND_PCM_FORMAT_S8; - } else if (bits == 16) { - if (sig == ~0U || sig) { - if (le == ~0U) { - *rfmt = SIO_LE_NATIVE ? - SND_PCM_FORMAT_S16_LE : - SND_PCM_FORMAT_S16_BE; - } else if (le) - *rfmt = SND_PCM_FORMAT_S16_LE; - else - *rfmt = SND_PCM_FORMAT_S16_BE; - } else { - if (le == ~0U) { - *rfmt = SIO_LE_NATIVE ? - SND_PCM_FORMAT_U16_LE : - SND_PCM_FORMAT_U16_BE; - } else if (le) - *rfmt = SND_PCM_FORMAT_U16_LE; - else - *rfmt = SND_PCM_FORMAT_U16_BE; - } - } else if (bits == 24) { - if (sig == ~0U || sig) { - if (le == ~0U) { - *rfmt = SIO_LE_NATIVE ? - SND_PCM_FORMAT_S24_LE : - SND_PCM_FORMAT_S24_BE; - } else if (le) - *rfmt = SND_PCM_FORMAT_S24_LE; - else - *rfmt = SND_PCM_FORMAT_S24_BE; - } else { - if (le == ~0U) { - *rfmt = SIO_LE_NATIVE ? - SND_PCM_FORMAT_U24_LE : - SND_PCM_FORMAT_U24_BE; - } else if (le) - *rfmt = SND_PCM_FORMAT_U24_LE; - else - *rfmt = SND_PCM_FORMAT_U24_BE; - } - } else if (bits == 32) { - if (sig == ~0U || sig) { - if (le == ~0U) { - *rfmt = SIO_LE_NATIVE ? - SND_PCM_FORMAT_S32_LE : - SND_PCM_FORMAT_S32_BE; - } else if (le) - *rfmt = SND_PCM_FORMAT_S32_LE; - else - *rfmt = SND_PCM_FORMAT_S32_BE; - } else { - if (le == ~0U) { - *rfmt = SIO_LE_NATIVE ? - SND_PCM_FORMAT_U32_LE : - SND_PCM_FORMAT_U32_BE; - } else if (le) - *rfmt = SND_PCM_FORMAT_U32_LE; - else - *rfmt = SND_PCM_FORMAT_U32_BE; - } - } else { - *rfmt = SIO_LE_NATIVE ? - SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_S16_BE; - } + if (le == ~0U) + le = SIO_LE_NATIVE; + if (bits == 8) + *rfmt = PCM_FORMAT_S8; + else if (bits == 24) + *rfmt = le ? PCM_FORMAT_S24_LE : PCM_FORMAT_S24_BE; + else if (bits == 32) + *rfmt = le ? PCM_FORMAT_S32_LE : PCM_FORMAT_S32_BE; + else + *rfmt = le ? PCM_FORMAT_S16_LE : PCM_FORMAT_S16_BE; } struct sio_hdl * @@ -279,8 +183,7 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio) const char *p; struct sio_alsa_hdl *hdl; struct sio_par par; - size_t len; - int err; + unsigned card, dev; p = _sndio_parsetype(str, "rsnd"); if (p == NULL) { @@ -300,42 +203,45 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio) return NULL; _sio_create(&hdl->sio, &sio_alsa_ops, mode, nbio); -#ifdef DEBUG - err = snd_output_stdio_attach(&output, stderr, 0); - if (err < 0) - DALSA("couldn't attach to stderr", err); -#endif - if (strcmp(p, "default") == 0) - p = "0"; - len = strlen(p); - hdl->devname = malloc(len + sizeof(DEVNAME_PREFIX)); - if (hdl->devname == NULL) - goto bad_free_hdl; - memcpy(hdl->devname, DEVNAME_PREFIX, sizeof(DEVNAME_PREFIX) - 1); - memcpy(hdl->devname + sizeof(DEVNAME_PREFIX) - 1, p, len + 1); + if (strcmp(p, "default") == 0) { + card = 0; + dev = 0; + } else { + switch (sscanf(p, "%u,%u", &card, &dev)) { + case 1: + dev = 0; + break; + case 2: + break; + default: + DPRINTF("invalid device name\n"); + } + } if (mode & SIO_PLAY) { - err = snd_pcm_open(&hdl->opcm, hdl->devname, - SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); - if (err < 0) { - DALSA("couldn't open play stream", err); - goto bad_free; + hdl->opar = pcm_params_get(card, dev, PCM_OUT); + if (hdl->opar == NULL) { + DPRINTF("couldn't get play params\n"); + goto bad_free_hdl; + } + hdl->opcm = pcm_open(card, dev, PCM_OUT | PCM_NONBLOCK, NULL); + if (!pcm_is_ready(hdl->opcm)) { + DALSA("couldn't open play stream", hdl->opcm); + goto bad_free_opar; } } if (mode & SIO_REC) { - err = snd_pcm_open(&hdl->ipcm, hdl->devname, - SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); - if (err < 0) { - DALSA("couldn't open rec stream", err); + hdl->ipar = pcm_params_get(card, dev, PCM_IN); + if (hdl->ipar == NULL) { + DPRINTF("couldn't get rec params\n"); goto bad_free_opcm; } + hdl->ipcm = pcm_open(card, dev, PCM_IN | PCM_NONBLOCK, NULL); + if (!pcm_is_ready(hdl->ipcm)) { + DALSA("couldn't open rec stream", hdl->ipcm); + goto bad_free_ipar; + } } - /* - * snd_pcm_poll_descriptors_count returns a small value - * that grows later, after the stream is started - */ - hdl->nfds = SIO_MAXNFDS; - /* * Default parameters may not be compatible with libsndio (eg. mulaw * encodings, different playback and recording parameters, etc...), so @@ -356,12 +262,16 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio) return (struct sio_hdl *)hdl; bad_free_ipcm: if (mode & SIO_REC) - snd_pcm_close(hdl->ipcm); + pcm_close(hdl->ipcm); +bad_free_ipar: + if (mode & SIO_REC) + free(hdl->ipar); bad_free_opcm: if (mode & SIO_PLAY) - snd_pcm_close(hdl->opcm); -bad_free: - free(hdl->devname); + pcm_close(hdl->opcm); +bad_free_opar: + if (mode & SIO_PLAY) + free(hdl->opar); bad_free_hdl: free(hdl); return NULL; @@ -372,11 +282,14 @@ sio_alsa_close(struct sio_hdl *sh) { struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; - if (hdl->sio.mode & SIO_PLAY) - snd_pcm_close(hdl->opcm); - if (hdl->sio.mode & SIO_REC) - snd_pcm_close(hdl->ipcm); - free(hdl->devname); + if (hdl->sio.mode & SIO_PLAY) { + free(hdl->opar); + pcm_close(hdl->opcm); + } + if (hdl->sio.mode & SIO_REC) { + free(hdl->ipar); + pcm_close(hdl->ipcm); + } free(hdl); } @@ -394,14 +307,12 @@ sio_alsa_start(struct sio_hdl *sh) hdl->oused = 0; hdl->idelta = 0; hdl->odelta = 0; - hdl->infds = 0; - hdl->onfds = 0; hdl->running = 0; if (hdl->sio.mode & SIO_PLAY) { - err = snd_pcm_prepare(hdl->opcm); + err = pcm_prepare(hdl->opcm); if (err < 0) { - DALSA("couldn't prepare play stream", err); + DALSA("couldn't prepare play stream", hdl->opcm); hdl->sio.eof = 1; return 0; } @@ -413,9 +324,9 @@ sio_alsa_start(struct sio_hdl *sh) hdl->opartial = 0; } if (hdl->sio.mode & SIO_REC) { - err = snd_pcm_prepare(hdl->ipcm); + err = pcm_prepare(hdl->ipcm); if (err < 0) { - DALSA("couldn't prepare rec stream", err); + DALSA("couldn't prepare rec stream", hdl->ipcm); hdl->sio.eof = 1; return 0; } @@ -427,17 +338,17 @@ sio_alsa_start(struct sio_hdl *sh) hdl->ipartial = 0; } if ((hdl->sio.mode & SIO_PLAY) && (hdl->sio.mode & SIO_REC)) { - err = snd_pcm_link(hdl->ipcm, hdl->opcm); + err = pcm_link(hdl->ipcm, hdl->opcm); if (err < 0) { - DALSA("couldn't link streams", err); + DALSA("couldn't link streams", hdl->ipcm); hdl->sio.eof = 1; return 0; } } if (!(hdl->sio.mode & SIO_PLAY)) { - err = snd_pcm_start(hdl->ipcm); + err = pcm_start(hdl->ipcm); if (err < 0) { - DALSA("couldn't start rec stream", err); + DALSA("couldn't start rec stream", hdl->ipcm); hdl->sio.eof = 1; return 0; } @@ -449,30 +360,26 @@ static int sio_alsa_flush(struct sio_hdl *sh) { struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; - int err; if (hdl->sio.mode & SIO_PLAY) { - err = snd_pcm_drop(hdl->opcm); - if (err < 0) { - DALSA("couldn't stop play stream", err); + if (pcm_stop(hdl->opcm) != 0) { + DALSA("couldn't stop play stream", hdl->opcm); hdl->sio.eof = 1; return 0; } free(hdl->otmpbuf); } if (hdl->sio.mode & SIO_REC) { - err = snd_pcm_drop(hdl->ipcm); - if (err < 0) { - DALSA("couldn't stop rec stream", err); + if (pcm_stop(hdl->ipcm) != 0) { + DALSA("couldn't stop rec stream", hdl->ipcm); hdl->sio.eof = 1; return 0; } free(hdl->itmpbuf); } if ((hdl->sio.mode & SIO_PLAY) && (hdl->sio.mode & SIO_REC)) { - err = snd_pcm_unlink(hdl->ipcm); - if (err < 0) { - DALSA("couldn't unlink streams", err); + if (pcm_unlink(hdl->ipcm) != 0) { + DALSA("couldn't unlink streams", hdl->ipcm); hdl->sio.eof = 1; return 0; } @@ -537,143 +444,110 @@ sio_alsa_xrun(struct sio_alsa_hdl *hdl) } static int -sio_alsa_setpar_hw(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwp, - snd_pcm_format_t *reqfmt, unsigned int *rate, unsigned int *chans, - snd_pcm_uframes_t *round, unsigned int *periods) +sio_alsa_setpar_hw(struct pcm *pcm, struct pcm_params *par, + struct pcm_config *cfg) { - static snd_pcm_format_t fmts[] = { - SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_BE, - SND_PCM_FORMAT_U32_LE, SND_PCM_FORMAT_U32_BE, - SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_BE, - SND_PCM_FORMAT_U24_LE, SND_PCM_FORMAT_U24_BE, - SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE, - SND_PCM_FORMAT_U16_LE, SND_PCM_FORMAT_U16_BE, - SND_PCM_FORMAT_U8, SND_PCM_FORMAT_S8 + static enum pcm_format fmts[] = { + PCM_FORMAT_S32_LE, PCM_FORMAT_S32_BE, + PCM_FORMAT_S24_LE, PCM_FORMAT_S24_BE, + PCM_FORMAT_S16_LE, PCM_FORMAT_S16_BE, + PCM_FORMAT_S8 }; - int i, err, dir = 0; - unsigned req_rate, min_periods = 2; + int i, err; + unsigned req_rate; + unsigned min, max; - req_rate = *rate; + /* XXX: HW_FREE */ - err = snd_pcm_hw_free(pcm); - if (err < 0) { - DALSA("couldn't reset hw configuration", err); - return 0; - } - err = snd_pcm_hw_params_any(pcm, hwp); - if (err < 0) { - DALSA("couldn't init pars", err); - return 0; - } - err = snd_pcm_hw_params_set_access(pcm, hwp, - SND_PCM_ACCESS_RW_INTERLEAVED); - if (err < 0) { - DALSA("couldn't set interleaved access", err); - return 0; - } - err = snd_pcm_hw_params_test_format(pcm, hwp, *reqfmt); - if (err < 0) { + if (pcm_params_format_test(par, cfg->format) == 0) { for (i = 0; ; i++) { - if (i == sizeof(fmts) / sizeof(snd_pcm_format_t)) { + if (i == sizeof(fmts) / sizeof(fmts[0])) { DPRINTF("no known format found\n"); return 0; } - err = snd_pcm_hw_params_test_format(pcm, hwp, fmts[i]); - if (err) + if (pcm_params_format_test(par, fmts[i]) == 0) continue; - *reqfmt = fmts[i]; + cfg->format = fmts[i]; break; } } - err = snd_pcm_hw_params_set_format(pcm, hwp, *reqfmt); - if (err < 0) { - DALSA("couldn't set fmt", err); - return 0; - } - err = snd_pcm_hw_params_set_rate_resample(pcm, hwp, 0); - if (err < 0) { - DALSA("couldn't turn resampling off", err); - return 0; - } - err = snd_pcm_hw_params_set_rate_near(pcm, hwp, rate, 0); - if (err < 0) { - DALSA("couldn't set rate", err); - return 0; - } - err = snd_pcm_hw_params_set_channels_near(pcm, hwp, chans); - if (err < 0) { - DALSA("couldn't set channel count", err); - return 0; - } - err = snd_pcm_hw_params_set_periods_integer(pcm, hwp); - if (err < 0) { - DALSA("couldn't set periods to integer", err); - return 0; - } - err = snd_pcm_hw_params_set_periods_min(pcm, hwp, &min_periods, NULL); - if (err < 0) { - DALSA("couldn't set minimum periods", err); - return 0; - } - err = snd_pcm_hw_params_set_period_size_integer(pcm, hwp); - if (err < 0) { - DALSA("couldn't set period to integer", err); - return 0; - } - - *round = *round * *rate / req_rate; - *round = (*round + 31) & ~31; - err = snd_pcm_hw_params_set_period_size_near(pcm, hwp, round, &dir); - if (err < 0) { - DALSA("couldn't set period size failed", err); - return 0; - } - err = snd_pcm_hw_params_set_periods_near(pcm, hwp, periods, &dir); - if (err < 0) { - DALSA("couldn't set period count", err); - return 0; - } - err = snd_pcm_hw_params(pcm, hwp); + req_rate = cfg->rate; + min = pcm_params_get_min(par, PCM_PARAM_RATE); + if (cfg->rate < min) + cfg->rate = min; + max = pcm_params_get_max(par, PCM_PARAM_RATE); + if (cfg->rate > max) + cfg->rate = max; + + min = pcm_params_get_min(par, PCM_PARAM_CHANNELS); + if (cfg->channels < min) + cfg->channels = min; + max = pcm_params_get_max(par, PCM_PARAM_CHANNELS); + if (cfg->channels > max) + cfg->channels = max; + + cfg->period_size = cfg->period_size * cfg->rate / req_rate; + cfg->period_size = (cfg->period_size + 31) & ~31; + + min = pcm_params_get_min(par, PCM_PARAM_PERIOD_SIZE); + if (min < 2) + min = 2; + if (cfg->period_size < min) + cfg->period_size = min; + max = pcm_params_get_max(par, PCM_PARAM_PERIOD_SIZE); + if (cfg->period_size > max) + cfg->period_size = max; + + min = pcm_params_get_min(par, PCM_PARAM_PERIODS); + if (cfg->period_count < min) + cfg->period_count = min; + max = pcm_params_get_max(par, PCM_PARAM_PERIODS); + if (cfg->period_count > max) + cfg->period_count = max; + + cfg->start_threshold = 0; + cfg->stop_threshold = cfg->period_count * cfg->period_size; + cfg->avail_min = 1; + cfg->silence_size = 0; + cfg->silence_threshold = 0; + + /* XXX: period_event=1, silence?, silence_threshold? */ + + err = pcm_set_config(pcm, cfg); if (err < 0) { - DALSA("couldn't commit params", err); + DALSA("couldn't set config", pcm); return 0; } return 1; } static int -sio_alsa_getcap_hw(snd_pcm_t *pcm, int *rates, int *fmts, int *chans) +sio_alsa_getcap_hw(struct pcm_params *par, int *rates, int *fmts, int *chans) { int i, err; - snd_pcm_hw_params_t *hwp; - - snd_pcm_hw_params_alloca(&hwp); - - err = snd_pcm_hw_params_any(pcm, hwp); - if (err < 0) { - DALSA("sio_alsa_trypar: couldn't init pars", err); - return 0; - } + unsigned min, max; *fmts = 0; for (i = 0; i < CAP_NFMTS; i++) { - err = snd_pcm_hw_params_test_format(pcm, hwp, cap_fmts[i]); + err = pcm_params_format_test(par, cap_fmts[i]); if (err == 0) { *fmts |= 1 << i; } } *rates = 0; + min = pcm_params_get_min(par, PCM_PARAM_RATE); + max = pcm_params_get_max(par, PCM_PARAM_RATE); for (i = 0; i < CAP_NRATES; i++) { - err = snd_pcm_hw_params_test_rate(pcm, hwp, cap_rates[i], 0); - if (err == 0) { + if (min <= cap_rates[i] && cap_rates[i] <= max) { *rates |= 1 << i; } } *chans = 0; + min = pcm_params_get_min(par, PCM_PARAM_CHANNELS); + max = pcm_params_get_max(par, PCM_PARAM_CHANNELS); for (i = 0; i < CAP_NCHANS; i++) { - err = snd_pcm_hw_params_test_channels(pcm, hwp, cap_chans[i]); - if (err == 0) { + if (min <= cap_chans[i] && cap_chans[i] <= max) { *chans |= 1 << i; } } @@ -693,13 +567,13 @@ sio_alsa_getcap(struct sio_hdl *sh, struct sio_cap *cap) irates = orates = ifmts = ofmts = ichans = ochans = 0; if (hdl->sio.mode & SIO_PLAY) { - if (!sio_alsa_getcap_hw(hdl->opcm, + if (!sio_alsa_getcap_hw(hdl->opar, &orates, &ofmts, &ochans)) { return 0; } } if (hdl->sio.mode & SIO_REC) { - if (!sio_alsa_getcap_hw(hdl->ipcm, + if (!sio_alsa_getcap_hw(hdl->ipar, &irates, &ifmts, &ichans)) { return 0; } @@ -711,7 +585,7 @@ sio_alsa_getcap(struct sio_hdl *sh, struct sio_cap *cap) &cap->enc[i].sig, &cap->enc[i].le); cap->enc[i].bps = SIO_BPS(cap->enc[0].bits); - cap->enc[i].msb = 1; + cap->enc[i].msb = 0; } for (i = 0; i < CAP_NRATES; i++) { cap->rate[i] = cap_rates[i]; @@ -744,186 +618,72 @@ static int sio_alsa_setpar(struct sio_hdl *sh, struct sio_par *par) { struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; - snd_pcm_hw_params_t *ohwp, *ihwp; - snd_pcm_sw_params_t *oswp, *iswp; - snd_pcm_uframes_t iround, oround; - snd_pcm_format_t ifmt, ofmt; - unsigned int iperiods, operiods; - unsigned irate, orate; - int err; - - snd_pcm_hw_params_alloca(&ohwp); - snd_pcm_sw_params_alloca(&oswp); - snd_pcm_hw_params_alloca(&ihwp); - snd_pcm_sw_params_alloca(&iswp); + struct pcm_config icfg, ocfg; - sio_alsa_enctofmt(hdl, &ifmt, par->bits, par->sig, par->le); - irate = (par->rate == ~0U) ? 48000 : par->rate; + sio_alsa_enctofmt(hdl, &icfg.format, par->bits, par->sig, par->le); + icfg.rate = (par->rate == ~0U) ? 48000 : par->rate; if (par->appbufsz != ~0U) { - iround = (par->round != ~0U) ? + icfg.period_size = (par->round != ~0U) ? par->round : (par->appbufsz + 1) / 2; - iperiods = par->appbufsz / iround; - if (iperiods < 2) - iperiods = 2; + icfg.period_count = par->appbufsz / icfg.period_size; + if (icfg.period_count < 2) + icfg.period_count = 2; } else if (par->round != ~0U) { - iround = par->round; - iperiods = 2; + icfg.period_size = par->round; + icfg.period_count = 2; } else { - iperiods = 2; - iround = irate / 100; + icfg.period_count = 2; + icfg.period_size = icfg.rate / 100; } if (hdl->sio.mode & SIO_REC) { hdl->par.rchan = par->rchan; - if (!sio_alsa_setpar_hw(hdl->ipcm, ihwp, - &ifmt, &irate, &hdl->par.rchan, - &iround, &iperiods)) { + if (!sio_alsa_setpar_hw(hdl->ipcm, hdl->ipar, &icfg)) { hdl->sio.eof = 1; return 0; } } - ofmt = ifmt; - orate = irate; - oround = iround; - operiods = iperiods; + ocfg = icfg; if (hdl->sio.mode & SIO_PLAY) { hdl->par.pchan = par->pchan; - if (!sio_alsa_setpar_hw(hdl->opcm, ohwp, - &ofmt, &orate, &hdl->par.pchan, - &oround, &operiods)) { + if (!sio_alsa_setpar_hw(hdl->opcm, hdl->opar, &ocfg)) { hdl->sio.eof = 1; return 0; } - if (!(hdl->sio.mode & SIO_REC)) { - ifmt = ofmt; - irate = orate; - iround = oround; - iperiods = operiods; - } + if (!(hdl->sio.mode & SIO_REC)) + icfg = ocfg; } DPRINTFN(2, "ofmt = %u, orate = %u, oround = %u, operiods = %u\n", - ofmt, orate, (unsigned int)oround, operiods); + ocfg.format, ocfg.rate, ocfg.period_size, ocfg.period_count); DPRINTFN(2, "ifmt = %u, irate = %u, iround = %u, iperiods = %u\n", - ifmt, irate, (unsigned int)iround, iperiods); + icfg.format, icfg.rate, icfg.period_size, icfg.period_count); - if (ifmt != ofmt) { + if (icfg.format != ocfg.format) { DPRINTF("play and rec formats differ\n"); hdl->sio.eof = 1; return 0; } - if (irate != orate) { + if (icfg.rate != ocfg.rate) { DPRINTF("play and rec rates differ\n"); hdl->sio.eof = 1; return 0; } - if (iround != oround) { + if (icfg.period_size != ocfg.period_size) { DPRINTF("play and rec block sizes differ\n"); hdl->sio.eof = 1; return 0; } - if (!sio_alsa_fmttopar(hdl, ifmt, + if (!sio_alsa_fmttopar(hdl, icfg.format, &hdl->par.bits, &hdl->par.sig, &hdl->par.le)) return 0; - hdl->par.msb = 1; + hdl->par.msb = 0; hdl->par.bps = SIO_BPS(hdl->par.bits); - hdl->par.rate = orate; - hdl->par.round = oround; - hdl->par.bufsz = oround * operiods; + hdl->par.rate = ocfg.rate; + hdl->par.round = ocfg.period_size; + hdl->par.bufsz = ocfg.period_size * ocfg.period_count; hdl->par.appbufsz = hdl->par.bufsz; - /* software params */ - - if (hdl->sio.mode & SIO_REC) { - err = snd_pcm_sw_params_current(hdl->ipcm, iswp); - if (err < 0) { - DALSA("couldn't get current rec params", err); - hdl->sio.eof = 1; - return 0; - } - err = snd_pcm_sw_params_set_start_threshold(hdl->ipcm, - iswp, 0); - if (err < 0) { - DALSA("couldn't set rec start threshold", err); - hdl->sio.eof = 1; - return 0; - } - err = snd_pcm_sw_params_set_stop_threshold(hdl->ipcm, - iswp, hdl->par.bufsz); - if (err < 0) { - DALSA("couldn't set rec stop threshold", err); - hdl->sio.eof = 1; - return 0; - } - err = snd_pcm_sw_params_set_avail_min(hdl->ipcm, - iswp, 1); - if (err < 0) { - DALSA("couldn't set rec avail min", err); - hdl->sio.eof = 1; - return 0; - } - err = snd_pcm_sw_params_set_period_event(hdl->ipcm, iswp, 1); - if (err < 0) { - DALSA("couldn't set rec period event", err); - hdl->sio.eof = 1; - return 0; - } - err = snd_pcm_sw_params(hdl->ipcm, iswp); - if (err < 0) { - DALSA("couldn't commit rec sw params", err); - hdl->sio.eof = 1; - return 0; - } - } - if (hdl->sio.mode & SIO_PLAY) { - err = snd_pcm_sw_params_current(hdl->opcm, oswp); - if (err < 0) { - DALSA("couldn't get current play params", err); - hdl->sio.eof = 1; - return 0; - } - err = snd_pcm_sw_params_set_start_threshold(hdl->opcm, - oswp, hdl->par.bufsz - hdl->par.round); - if (err < 0) { - DALSA("couldn't set play start threshold", err); - hdl->sio.eof = 1; - return 0; - } - err = snd_pcm_sw_params_set_stop_threshold(hdl->opcm, - oswp, hdl->par.bufsz); - if (err < 0) { - DALSA("couldn't set play stop threshold", err); - hdl->sio.eof = 1; - return 0; - } - err = snd_pcm_sw_params_set_avail_min(hdl->opcm, - oswp, 1); - if (err < 0) { - DALSA("couldn't set play avail min", err); - hdl->sio.eof = 1; - return 0; - } - err = snd_pcm_sw_params_set_period_event(hdl->opcm, oswp, 1); - if (err < 0) { - DALSA("couldn't set play period event", err); - hdl->sio.eof = 1; - return 0; - } - err = snd_pcm_sw_params(hdl->opcm, oswp); - if (err < 0) { - DALSA("couldn't commit play sw params", err); - hdl->sio.eof = 1; - return 0; - } - } -#ifdef DEBUG - if (_sndio_debug >= 2) { - if (hdl->sio.mode & SIO_REC) - snd_pcm_dump(hdl->ipcm, output); - if (hdl->sio.mode & SIO_PLAY) - snd_pcm_dump(hdl->opcm, output); - } -#endif return 1; } @@ -940,7 +700,7 @@ static size_t sio_alsa_read(struct sio_hdl *sh, void *buf, size_t len) { struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; - snd_pcm_sframes_t n; + int n; size_t todo; if (hdl->ipartial > 0) { @@ -959,7 +719,7 @@ sio_alsa_read(struct sio_hdl *sh, void *buf, size_t len) todo = len / hdl->ibpf; if (todo == 0) return 0; - while ((n = snd_pcm_readi(hdl->ipcm, buf, todo)) < 0) { + while ((n = pcm_readi(hdl->ipcm, buf, todo)) < 0) { if (n == -EINTR) continue; if (n == -EPIPE || n == -ESTRPIPE) { @@ -967,7 +727,7 @@ sio_alsa_read(struct sio_hdl *sh, void *buf, size_t len) return 0; } if (n != -EAGAIN) { - DALSA("couldn't read data", n); + DALSA("couldn't read data", hdl->ipcm); hdl->sio.eof = 1; } return 0; @@ -989,7 +749,7 @@ static size_t sio_alsa_write(struct sio_hdl *sh, const void *buf, size_t len) { struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; - snd_pcm_sframes_t n; + int n; size_t todo; if (len < hdl->obpf || hdl->opartial > 0) { @@ -1007,7 +767,7 @@ sio_alsa_write(struct sio_hdl *sh, const void *buf, size_t len) todo = len / hdl->obpf; if (todo == 0) return 0; - while ((n = snd_pcm_writei(hdl->opcm, buf, todo)) < 0) { + while ((n = pcm_writei(hdl->opcm, buf, todo)) < 0) { if (n == -EINTR) continue; if (n == -ESTRPIPE || n == -EPIPE) { @@ -1015,7 +775,7 @@ sio_alsa_write(struct sio_hdl *sh, const void *buf, size_t len) return 0; } if (n != -EAGAIN) { - DALSA("couldn't write data", n); + DALSA("couldn't write data", hdl->opcm); hdl->sio.eof = 1; } return 0; @@ -1062,16 +822,14 @@ sio_alsa_onmove(struct sio_alsa_hdl *hdl) static int sio_alsa_nfds(struct sio_hdl *sh) { - struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; - - return hdl->nfds; + return 2; } static int sio_alsa_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) { struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; - int i; + int i, nfds; if (hdl->sio.eof) return 0; @@ -1083,100 +841,86 @@ sio_alsa_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) hdl->events &= ~POLLIN; if (!hdl->sio.started) hdl->events = 0; - memset(pfd, 0, sizeof(struct pollfd) * hdl->nfds); - hdl->onfds = hdl->infds = 0; + memset(pfd, 0, sizeof(struct pollfd) * 2); + nfds = 0; if (hdl->events & POLLOUT) { if (!hdl->running && - snd_pcm_state(hdl->opcm) == SND_PCM_STATE_RUNNING) + pcm_state(hdl->opcm) == PCM_STATE_RUNNING) sio_alsa_onmove(hdl); - hdl->onfds = snd_pcm_poll_descriptors(hdl->opcm, - pfd, hdl->nfds); - if (hdl->onfds < 0) { - DALSA("couldn't poll play descriptors", - hdl->onfds); - hdl->sio.eof = 1; - return 0; - } + + pfd[0].fd = pcm_get_poll_fd(hdl->opcm); + pfd[0].events = POLLOUT; + nfds++; } if (hdl->events & POLLIN) { if (!hdl->running && - snd_pcm_state(hdl->ipcm) == SND_PCM_STATE_RUNNING) + pcm_state(hdl->ipcm) == PCM_STATE_RUNNING) sio_alsa_onmove(hdl); - hdl->infds = snd_pcm_poll_descriptors(hdl->ipcm, - pfd + hdl->onfds, hdl->nfds - hdl->onfds); - if (hdl->infds < 0) { - DALSA("couldn't poll rec descriptors", - hdl->infds); - hdl->sio.eof = 1; - return 0; - } + + pfd[nfds].fd = pcm_get_poll_fd(hdl->ipcm); + pfd[nfds].events = POLLIN; + nfds++; } - DPRINTFN(4, "sio_alsa_pollfd: events = %x, nfds = %d + %d\n", - events, hdl->onfds, hdl->infds); + DPRINTFN(4, "sio_alsa_pollfd: events = %x, nfds = %d\n", + events, nfds); - for (i = 0; i < hdl->onfds + hdl->infds; i++) { + for (i = 0; i < nfds; i++) { DPRINTFN(4, "sio_alsa_pollfd: pfds[%d].events = %x\n", i, pfd[i].events); } - return hdl->onfds + hdl->infds; + return nfds; } int sio_alsa_revents(struct sio_hdl *sh, struct pollfd *pfd) { struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; - snd_pcm_sframes_t iused, oavail, oused; - snd_pcm_state_t istate, ostate; - unsigned short revents, r; - int nfds, err, i; + struct timespec ts; + unsigned iused, oavail, oused; + int istate, ostate; + unsigned short revents; + int nfds, i; if (hdl->sio.eof) return POLLHUP; - for (i = 0; i < hdl->onfds + hdl->infds; i++) { + nfds = 0; + if (hdl->events & POLLOUT) + nfds++; + if (hdl->events & POLLIN) + nfds++; + + for (i = 0; i < nfds; i++) { DPRINTFN(4, "sio_alsa_revents: pfds[%d].revents = %x\n", i, pfd[i].revents); } revents = nfds = 0; if (hdl->events & POLLOUT) { - err = snd_pcm_poll_descriptors_revents(hdl->opcm, - pfd, hdl->onfds, &r); - if (err < 0) { - DALSA("couldn't get play events", err); - hdl->sio.eof = 1; - return POLLHUP; - } - revents |= r; - nfds += hdl->onfds; + revents |= pfd[0].revents; + ++nfds; } if (hdl->events & POLLIN) { - err = snd_pcm_poll_descriptors_revents(hdl->ipcm, - pfd + nfds, hdl->infds, &r); - if (err < 0) { - DALSA("couldn't get rec events", err); - hdl->sio.eof = 1; - return POLLHUP; - } - revents |= r; - nfds += hdl->infds; + revents |= pfd[nfds].revents; + ++nfds; } if (hdl->sio.mode & SIO_PLAY) { - ostate = snd_pcm_state(hdl->opcm); - if (ostate == SND_PCM_STATE_XRUN) { + ostate = pcm_state(hdl->opcm); + if (ostate == PCM_STATE_XRUN) { if (!sio_alsa_xrun(hdl)) return POLLHUP; return 0; } - if (ostate == SND_PCM_STATE_RUNNING || - ostate == SND_PCM_STATE_PREPARED) { - oavail = snd_pcm_avail_update(hdl->opcm); - if (oavail < 0) { + if (ostate == PCM_STATE_RUNNING || + ostate == PCM_STATE_PREPARED) { + if (pcm_get_htimestamp(hdl->opcm, &oavail, &ts) != 0) { + /* if (oavail == -EPIPE || oavail == -ESTRPIPE) { if (!sio_alsa_xrun(hdl)) return POLLHUP; return 0; } - DALSA("couldn't get play buffer ptr", oavail); + */ + DPRINTF("couldn't get play buffer ptr\n"); hdl->sio.eof = 1; return POLLHUP; } @@ -1186,22 +930,23 @@ sio_alsa_revents(struct sio_hdl *sh, struct pollfd *pfd) } } if (hdl->sio.mode & SIO_REC) { - istate = snd_pcm_state(hdl->ipcm); - if (istate == SND_PCM_STATE_XRUN) { + istate = pcm_state(hdl->ipcm); + if (istate == PCM_STATE_XRUN) { if (!sio_alsa_xrun(hdl)) return POLLHUP; return 0; } - if (istate == SND_PCM_STATE_RUNNING || - istate == SND_PCM_STATE_PREPARED) { - iused = snd_pcm_avail_update(hdl->ipcm); - if (iused < 0) { + if (istate == PCM_STATE_RUNNING || + istate == PCM_STATE_PREPARED) { + if (pcm_get_htimestamp(hdl->ipcm, &iused, &ts) != 0) { + /* if (iused == -EPIPE || iused == -ESTRPIPE) { if (!sio_alsa_xrun(hdl)) return POLLHUP; return 0; } - DALSA("couldn't get rec buffer ptr", iused); + */ + DPRINTF("couldn't get rec buffer ptr\n"); hdl->sio.eof = 1; return POLLHUP; } -- 2.37.3