From fdb250e1369d4364731cc7c28998669db957a360 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 1 Nov 2018 06:43:37 +0200 Subject: tidy up code, and start checking up hwcaps supported formats and their conversions are handled more nicer now too. --- src/pcm.c | 548 +++++++++++++++++++++++++++----------------------------- src/util/util.h | 2 + 2 files changed, 264 insertions(+), 286 deletions(-) diff --git a/src/pcm.c b/src/pcm.c index 1a4ee08..a238e8e 100644 --- a/src/pcm.c +++ b/src/pcm.c @@ -6,10 +6,90 @@ #include "util/dsp.h" #include "util/util.h" +static struct format_info { + const char *name; + snd_pcm_format_t fmt; + struct sio_enc enc; +} SUPPORTED_FORMATS[] = { +#define FMT(F, BITS, BPS, SIG, LE, MSB) { .name = #F, .fmt = F, .enc = { .bits = BITS, .bps = BPS, .sig = SIG, .le = LE, .msb = MSB } } + FMT(SND_PCM_FORMAT_S8, 8, 1, 1, 1, 1), + FMT(SND_PCM_FORMAT_U8, 8, 1, 0, 1, 1), + FMT(SND_PCM_FORMAT_S16_LE, 16, 2, 1, 1, 1), + FMT(SND_PCM_FORMAT_S16_BE, 16, 2, 1, 0, 1), + FMT(SND_PCM_FORMAT_U16_LE, 16, 2, 0, 1, 1), + FMT(SND_PCM_FORMAT_U16_BE, 16, 2, 0, 0, 1), + FMT(SND_PCM_FORMAT_S24_3LE, 24, 3, 1, 1, 1), + FMT(SND_PCM_FORMAT_S24_3BE, 24, 3, 1, 0, 1), + FMT(SND_PCM_FORMAT_U24_3LE, 24, 3, 0, 1, 1), + FMT(SND_PCM_FORMAT_U24_3BE, 24, 3, 0, 0, 1), + FMT(SND_PCM_FORMAT_S32_LE, 24, 4, 1, 1, 1), + FMT(SND_PCM_FORMAT_S32_BE, 24, 4, 1, 0, 1), + FMT(SND_PCM_FORMAT_U32_LE, 24, 4, 0, 1, 1), + FMT(SND_PCM_FORMAT_U32_BE, 24, 4, 0, 0, 1), + FMT(SND_PCM_FORMAT_FLOAT_LE, 32, 4, 1, 1, 0), // always transcoded + FMT(SND_PCM_FORMAT_FLOAT_BE, 32, 4, 1, 0, 0) // always transcoded +#undef FMT +}; + +const struct format_info* +format_info_for_sio_enc(const struct sio_enc *enc) +{ + for (size_t i = 0; i < ARRAY_SIZE(SUPPORTED_FORMATS); ++i) { + if (!memcmp(enc, &SUPPORTED_FORMATS[i].enc, sizeof(*enc))) + return &SUPPORTED_FORMATS[i]; + } + return NULL; +} + +const struct format_info* +format_info_for_format(const snd_pcm_format_t format) +{ + for (size_t i = 0; i < ARRAY_SIZE(SUPPORTED_FORMATS); ++i) { + if (SUPPORTED_FORMATS[i].fmt == format) + return &SUPPORTED_FORMATS[i]; + } + return NULL; +} + +snd_pcm_format_t +snd_pcm_format_value(const char* name) +{ + for (size_t i = 0; i < ARRAY_SIZE(SUPPORTED_FORMATS); ++i) { + if (!strcmp(SUPPORTED_FORMATS[i].name, name)) + return SUPPORTED_FORMATS[i].fmt; + } + return SND_PCM_FORMAT_UNKNOWN; +} + +const char* +snd_pcm_format_name(const snd_pcm_format_t format) +{ + const struct format_info *info = format_info_for_format(format); + return (info ? info->name : NULL); +} + +int +snd_pcm_format_width(snd_pcm_format_t format) +{ + const struct format_info *info = format_info_for_format(format); + return (info ? (int)info->enc.bits : -1); +} + +int +snd_pcm_format_physical_width(snd_pcm_format_t format) +{ + const struct format_info *info = format_info_for_format(format); + return (info ? (int)info->enc.bps * 8 : -1); +} + struct _snd_pcm_hw_params { struct sio_cap cap; struct sio_par par; - snd_pcm_format_t alsa_format; + struct hw_limits { + snd_pcm_format_t supported[ARRAY_SIZE(SUPPORTED_FORMATS)]; + unsigned int pchan[2], rchan[2], rate[2]; + } limits; + snd_pcm_format_t format; snd_pcm_access_t access; snd_pcm_stream_t stream; bool needs_conversion; // for unsupported formats @@ -18,7 +98,7 @@ struct _snd_pcm_hw_params { struct _snd_pcm_sw_params { char noop; }; struct _snd_pcm { - struct _snd_pcm_hw_params hw, hw_requested; + struct _snd_pcm_hw_params hw; struct _snd_pcm_sw_params sw; struct sio_hdl *hdl; const char *name; @@ -68,12 +148,71 @@ device_open(snd_pcm_t *pcm, const char *name, snd_pcm_stream_t stream, int mode) return NULL; } - sio_onmove(hdl, onmove, pcm); pcm->mode = mode; pcm->hw.stream = stream; + sio_onmove(hdl, onmove, pcm); return hdl; } +static void +dump_enc(const struct sio_enc *enc, struct hw_limits *limits) +{ + WARNX("- - - bits: %u bps: %u sig: %u le: %u msb: %u", enc->bits, enc->bps, enc->sig, enc->le, enc->msb); + const struct format_info *info = format_info_for_sio_enc(enc); + assert(info); + WARNX("- - - aka %s", info->name); + + size_t i; + for (i = 0; i < ARRAY_SIZE(limits->supported) && limits->supported[i] != SND_PCM_FORMAT_UNKNOWN; ++i); + assert(i < ARRAY_SIZE(limits->supported)); + limits->supported[i] = info->fmt; +} + +static void +dump_cap(const char *name, const struct sio_cap *cap, struct hw_limits *limits) +{ + *limits = (struct hw_limits){0}; + limits->rate[0] = limits->rchan[0] = limits->pchan[0] = ~(unsigned int)0; + memset(limits->supported, SND_PCM_FORMAT_UNKNOWN, sizeof(limits->supported)); + + WARNX("* %s", name); + for (unsigned int c = 0; c < cap->nconf; ++c) { + WARNX("- - configuration %u", c); + + for (unsigned int i = 0; i < SIO_NENC; ++i) { + if (cap->confs[c].enc & (1 << i)) + dump_enc(&cap->enc[i], limits); + } + + for (unsigned int i = 0; i < SIO_NCHAN; ++i) { + if (!(cap->confs[c].rchan & (1 << i))) + continue; + + WARNX("- - - rchan: %u", cap->rchan[i]); + limits->rchan[0] = MIN(limits->rchan[0], cap->rchan[i]); + limits->rchan[1] = MAX(limits->rchan[1], cap->rchan[i]); + } + + for (unsigned int i = 0; i < SIO_NCHAN; ++i) { + if (!(cap->confs[c].pchan & (1 << i))) + continue; + + WARNX("- - - pchan: %u", cap->pchan[i]); + limits->pchan[0] = MIN(limits->pchan[0], cap->pchan[i]); + limits->pchan[1] = MAX(limits->pchan[1], cap->pchan[i]); + } + + for (unsigned int i = 0; i < SIO_NRATE; ++i) { + if (!(cap->confs[c].rate & (1 << i))) + continue; + + WARNX("- - - rate: %u", cap->rate[i]); + limits->rate[0] = MIN(limits->rate[0], cap->rate[i]); + limits->rate[1] = MAX(limits->rate[1], cap->rate[i]); + } + } +} + int snd_pcm_open(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode) { @@ -85,9 +224,15 @@ snd_pcm_open(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mod if (!((*pcm)->hdl = device_open(*pcm, name, stream, mode))) goto fail; - sio_initpar(&(*pcm)->hw_requested.par); + sio_initpar(&(*pcm)->hw.par); (*pcm)->name = (name ? name : "default"); - return (sio_getcap((*pcm)->hdl, &(*pcm)->hw.cap) && sio_getpar((*pcm)->hdl, &(*pcm)->hw.par) ? 0 : -1); + + if (!sio_getcap((*pcm)->hdl, &(*pcm)->hw.cap) || !sio_getpar((*pcm)->hdl, &(*pcm)->hw.par)) + goto fail; + + dump_cap(name, &(*pcm)->hw.cap, &(*pcm)->hw.limits); + (*pcm)->hw.format = SND_PCM_FORMAT_UNKNOWN; + return 0; fail: free(*pcm); @@ -121,7 +266,7 @@ snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock) if (!(pcm->hdl = device_open(pcm, pcm->name, pcm->hw.stream, (nonblock ? SND_PCM_NONBLOCK : false)))) return -1; - return snd_pcm_hw_params(pcm, &pcm->hw_requested); + return snd_pcm_hw_params(pcm, &pcm->hw); } int @@ -184,17 +329,28 @@ static size_t io_do(snd_pcm_t *pcm, const void *buffer, const size_t frames, size_t (*io)(struct sio_hdl*, const void*, size_t, void*), void *arg) { if (pcm->hw.needs_conversion) { - struct aparams params = { - .bps = pcm->hw.par.bps, - .bits = pcm->hw.par.bits, - .le = pcm->hw.par.le, - .sig = pcm->hw.par.sig, - .msb = pcm->hw.par.msb + const struct format_info *info = format_info_for_format(pcm->hw.format); + assert(info); + + struct aparams params[2] = { + { + .bps = info->enc.bps, + .bits = info->enc.bits, + .le = info->enc.le, + .sig = info->enc.sig, + .msb = info->enc.msb + }, { + .bps = pcm->hw.par.bps, + .bits = pcm->hw.par.bits, + .le = pcm->hw.par.le, + .sig = pcm->hw.par.sig, + .msb = pcm->hw.par.msb + } }; struct conv dec, enc; - dec_init(&dec, ¶ms, (pcm->hw.stream == SND_PCM_STREAM_PLAYBACK ? pcm->hw.par.pchan : pcm->hw.par.rchan)); - enc_init(&enc, ¶ms, (pcm->hw.stream == SND_PCM_STREAM_PLAYBACK ? pcm->hw.par.pchan : pcm->hw.par.rchan)); + dec_init(&dec, ¶ms[0], (pcm->hw.stream == SND_PCM_STREAM_PLAYBACK ? pcm->hw.par.pchan : pcm->hw.par.rchan)); + enc_init(&enc, ¶ms[1], (pcm->hw.stream == SND_PCM_STREAM_PLAYBACK ? pcm->hw.par.pchan : pcm->hw.par.rchan)); size_t total_frames = frames, io_bytes = 0; unsigned char decoded[4096], encoded[sizeof(decoded)]; @@ -204,7 +360,7 @@ io_do(snd_pcm_t *pcm, const void *buffer, const size_t frames, size_t (*io)(stru total_frames -= todo_frames; // sadly can't function pointer here as some formats may need different parameters for decoder - if (pcm->hw.alsa_format == SND_PCM_FORMAT_FLOAT_LE || pcm->hw.alsa_format == SND_PCM_FORMAT_FLOAT_BE) { + if (pcm->hw.format == SND_PCM_FORMAT_FLOAT_LE || pcm->hw.format == SND_PCM_FORMAT_FLOAT_BE) { dec_do_float(&dec, (void*)p, decoded, todo_frames); } else { dec_do(&dec, (void*)p, decoded, todo_frames); @@ -387,48 +543,65 @@ snd_pcm_hw_params_copy(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src) *dst = *src; } -static void -copy_important_params(struct sio_par *dst, const struct sio_par *src) +static bool +apply_par(snd_pcm_t *pcm, const struct sio_par *old, struct sio_par *new_par) { - assert(dst && src); - dst->rate = src->rate; - dst->pchan = src->pchan; - dst->rchan = src->rchan; - dst->appbufsz = src->appbufsz; - dst->round = src->round; -} + const bool was_started = pcm->started; -int -snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) -{ - params->cap = pcm->hw.cap; - params->stream = pcm->hw.stream; - sio_initpar(¶ms->par); - copy_important_params(¶ms->par, &pcm->hw.par); - WARNX("rate: %u, round: %u, appbufsz: %u chan: %u", params->par.rate, params->par.round, params->par.appbufsz, (params->stream == SND_PCM_STREAM_PLAYBACK ? params->par.pchan : params->par.rchan)); - return 0; + if (was_started) + snd_pcm_drain(pcm); + + if (!new_par->__magic) { + // sndio sets magic to 0 after getpar, so it becomes "uninitialized". + // using "uninitialized" par in setpar fails. however, due to how asound + // design is, we really want to use our getparred pars in setpar, so + // lets force the initialized state here. + struct sio_par tmp; + sio_initpar(&tmp); + new_par->__magic = tmp.__magic; + new_par->bufsz = ~0U; // read-only + } + + if (!sio_setpar(pcm->hdl, new_par)) { + WARNX1("sio_setpar failed"); + goto fail; + } + + struct sio_par hpar; + if (!sio_getpar(pcm->hdl, &hpar)) { + WARNX1("sio_getpar failed"); + goto fail; + } + + *new_par = hpar; + bool ret = true; + goto out; + +fail: + *new_par = *old; + ret = false; + +out: + if (was_started) + snd_pcm_prepare(pcm); + + return ret; } int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { if (memcmp(params, &pcm->hw, sizeof(*params))) { - snd_pcm_drain(pcm); + WARNX("requested: rate: %u, round: %u, appbufsz: %u chan: %u", params->par.rate, params->par.round, params->par.appbufsz, (params->stream == SND_PCM_STREAM_PLAYBACK ? params->par.pchan : params->par.rchan)); - pcm->hw_requested = *params; - if (!sio_setpar(pcm->hdl, ¶ms->par)) { - WARNX1("sio_setpar failed"); + const struct sio_par old = params->par; + if (!apply_par(pcm, &old, ¶ms->par)) return -1; - } + WARNX("set: rate: %u, round: %u, appbufsz: %u chan: %u", params->par.rate, params->par.round, params->par.appbufsz, (params->stream == SND_PCM_STREAM_PLAYBACK ? params->par.pchan : params->par.rchan)); pcm->hw = *params; - if (!sio_getpar(pcm->hdl, &pcm->hw.par)) { - WARNX1("sio_getpar failed"); - return -1; - } } - WARNX("rate: %u, round: %u, appbufsz: %u, bufsz: %u, chan: %u", pcm->hw.par.rate, pcm->hw.par.round, pcm->hw.par.appbufsz, pcm->hw.par.bufsz, (pcm->hw.stream == SND_PCM_STREAM_PLAYBACK ? pcm->hw.par.pchan : pcm->hw.par.rchan)); return snd_pcm_prepare(pcm); } @@ -439,6 +612,13 @@ snd_pcm_hw_params_current(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) return 0; } +int +snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + *params = pcm->hw; + return 0; +} + int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access) { @@ -460,172 +640,6 @@ snd_pcm_hw_params_get_access(const snd_pcm_hw_params_t *params, snd_pcm_access_t return 0; } -static snd_pcm_format_t SUPPORTED_FORMATS[] = { - SND_PCM_FORMAT_U8, - SND_PCM_FORMAT_S8, - SND_PCM_FORMAT_S16_LE, - SND_PCM_FORMAT_S16_BE, - SND_PCM_FORMAT_U16_LE, - SND_PCM_FORMAT_U16_BE, - SND_PCM_FORMAT_S24_LE, - SND_PCM_FORMAT_S24_BE, - SND_PCM_FORMAT_U24_LE, - SND_PCM_FORMAT_U24_BE, - SND_PCM_FORMAT_S32_LE, - SND_PCM_FORMAT_S32_BE, - SND_PCM_FORMAT_U32_LE, - SND_PCM_FORMAT_U32_BE, - SND_PCM_FORMAT_FLOAT_LE, - SND_PCM_FORMAT_FLOAT_BE -}; - -const char* -snd_pcm_format_name(const snd_pcm_format_t format) -{ -#define NAME(x) case x: return #x - switch (format) { - NAME(SND_PCM_FORMAT_U8); - NAME(SND_PCM_FORMAT_S8); - NAME(SND_PCM_FORMAT_S16_LE); - NAME(SND_PCM_FORMAT_S16_BE); - NAME(SND_PCM_FORMAT_U16_LE); - NAME(SND_PCM_FORMAT_U16_BE); - NAME(SND_PCM_FORMAT_S24_LE); - NAME(SND_PCM_FORMAT_S24_BE); - NAME(SND_PCM_FORMAT_U24_LE); - NAME(SND_PCM_FORMAT_U24_BE); - NAME(SND_PCM_FORMAT_S32_LE); - NAME(SND_PCM_FORMAT_S32_BE); - NAME(SND_PCM_FORMAT_U32_LE); - NAME(SND_PCM_FORMAT_U32_BE); - NAME(SND_PCM_FORMAT_FLOAT_LE); - NAME(SND_PCM_FORMAT_FLOAT_BE); - default: - WARNX("unsupported format: 0x%x", format); - return NULL; - } -#undef NAME -} - -snd_pcm_format_t -snd_pcm_format_value(const char* name) -{ - for (uint8_t i = 0; i < ARRAY_SIZE(SUPPORTED_FORMATS); ++i) { - const char *needle = snd_pcm_format_name(SUPPORTED_FORMATS[i]); - if (name && !strcmp(needle, name)) - return SUPPORTED_FORMATS[i]; - } - return SND_PCM_FORMAT_UNKNOWN; -} - -static bool -pcm_format(const snd_pcm_format_t format, struct sio_par *par, bool *out_needs_conversion) -{ - switch (format) { - case SND_PCM_FORMAT_U8: - par->bits = 8; - par->sig = 0; - break; - case SND_PCM_FORMAT_S8: - par->bits = 8; - par->sig = 1; - break; - case SND_PCM_FORMAT_S16_LE: - par->bits = 16; - par->sig = 1; - par->le = 1; - break; - case SND_PCM_FORMAT_S16_BE: - par->bits = 16; - par->sig = 1; - par->le = 0; - break; - case SND_PCM_FORMAT_U16_LE: - par->bits = 16; - par->sig = 0; - par->le = 1; - break; - case SND_PCM_FORMAT_U16_BE: - par->bits = 16; - par->sig = 0; - par->le = 0; - break; - case SND_PCM_FORMAT_S24_LE: - par->bits = 24; - par->sig = 1; - par->le = 1; - break; - case SND_PCM_FORMAT_S24_BE: - par->bits = 24; - par->sig = 1; - par->le = 0; - break; - case SND_PCM_FORMAT_U24_LE: - par->bits = 24; - par->sig = 0; - par->le = 1; - break; - case SND_PCM_FORMAT_U24_BE: - par->bits = 24; - par->sig = 0; - par->le = 0; - break; - case SND_PCM_FORMAT_FLOAT_LE: - *out_needs_conversion = true; - /* fallthrough */ - case SND_PCM_FORMAT_S32_LE: - par->bits = 32; - par->sig = 1; - par->le = 1; - break; - case SND_PCM_FORMAT_FLOAT_BE: - *out_needs_conversion = true; - /* fallthrough */ - case SND_PCM_FORMAT_S32_BE: - par->bits = 32; - par->sig = 1; - par->le = 0; - break; - case SND_PCM_FORMAT_U32_LE: - par->bits = 32; - par->sig = 0; - par->le = 1; - break; - case SND_PCM_FORMAT_U32_BE: - par->bits = 32; - par->sig = 0; - par->le = 0; - break; - default: - WARNX("unsupported format: 0x%x", format); - return false; - } - return true; -} - -int snd_pcm_format_width(snd_pcm_format_t format) -{ - struct sio_par par = {0}; - pcm_format(format, &par, (bool[]){false}); - return par.bits; -} - -int snd_pcm_format_physical_width(snd_pcm_format_t format) -{ - return snd_pcm_format_width(format); -} - -struct _snd_pcm_format_mask { - snd_pcm_format_t *fmts; - uint8_t nmemb; -}; - -size_t -snd_pcm_format_mask_sizeof(void) -{ - return sizeof(snd_pcm_format_mask_t); -} - int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr) { @@ -639,23 +653,32 @@ snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj) free(obj); } -void -snd_pcm_hw_params_get_format_mask(snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask) +struct _snd_pcm_format_mask { + snd_pcm_format_t supported[ARRAY_SIZE(SUPPORTED_FORMATS)]; +}; + +size_t +snd_pcm_format_mask_sizeof(void) { - static snd_pcm_format_mask_t def_mask = { .fmts = SUPPORTED_FORMATS, .nmemb = ARRAY_SIZE(SUPPORTED_FORMATS) }; - if (mask) *mask = def_mask; + return sizeof(snd_pcm_format_mask_t); } int snd_pcm_format_mask_test(const snd_pcm_format_mask_t *mask, snd_pcm_format_t val) { - for (uint8_t i = 0; i < mask->nmemb; ++i) { - if (mask->fmts[i] == val) + for (size_t i = 0; i < ARRAY_SIZE(mask->supported) && mask->supported[i] != SND_PCM_FORMAT_UNKNOWN; ++i) { + if (mask->supported[i] == val) return true; } return false; } +void +snd_pcm_hw_params_get_format_mask(snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask) +{ + if (mask) memcpy(mask->supported, params->limits.supported, sizeof(mask->supported)); +} + int snd_pcm_hw_params_test_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val) { @@ -667,48 +690,32 @@ snd_pcm_hw_params_test_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_p int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val) { - // FIXME: prob should check hw caps - if (!pcm_format(val, ¶ms->par, ¶ms->needs_conversion)) + const struct format_info *info; + if (!(info = format_info_for_format(val))) return -1; - WARNX1(snd_pcm_format_name(val)); - params->alsa_format = val; - params->par.bps = SIO_BPS(params->par.bits); - return 0; + params->format = val; + WARNX("%s", info->name); + params->needs_conversion = (snd_pcm_hw_params_test_format(pcm, params, val) != 0); + + const struct sio_par old = params->par; + params->par.bits = info->enc.bits; + params->par.bps = info->enc.bps; + params->par.sig = info->enc.sig; + params->par.le = (params->needs_conversion ? SIO_LE_NATIVE : info->enc.le); + params->par.msb = info->enc.msb; + return (apply_par(pcm, &old, ¶ms->par) ? 0 : -1); } static int update(snd_pcm_t *pcm, struct sio_par *par, void *curv, void *newv, const size_t size) { - if (!newv) - return 0; - - struct sio_par old = *par; + if (!newv) return 0; + const struct sio_par old = *par; memcpy(curv, newv, size); - const bool was_started = pcm->started; - - if (was_started) - snd_pcm_drain(pcm); - - if (!sio_setpar(pcm->hdl, par)) { - WARNX1("sio_setpar failed"); - *par = old; - return 0; - } - - struct sio_par hpar; - if (sio_getpar(pcm->hdl, &hpar)) { - copy_important_params(par, &hpar); - } else { - WARNX1("sio_getpar failed"); - } - + const bool ret = apply_par(pcm, &old, par); memcpy(newv, curv, size); - - if (was_started) - snd_pcm_prepare(pcm); - - return 0; + return (ret ? 0 : -1); } int @@ -743,16 +750,7 @@ int snd_pcm_hw_params_get_channels_min(const snd_pcm_hw_params_t *params, unsigned int *val) { const bool pb = (params->stream == SND_PCM_STREAM_PLAYBACK); - unsigned int min = (unsigned int)~0; - for (unsigned int c = 0; c < params->cap.nconf; ++c) { - const unsigned int cconf = (pb ? params->cap.confs[c].pchan : params->cap.confs[c].rchan); - for (unsigned int i = 0; i < SIO_NCHAN; ++i) { - if (!(cconf & (1 << i))) - continue; - min = ((pb ? params->cap.pchan[i] : params->cap.rchan[i]) < min ? (pb ? params->cap.pchan[i] : params->cap.rchan[i]) : min); - } - } - if (val) *val = min; + if (val) *val = (pb ? params->limits.pchan[0] : params->limits.rchan[0]); return 0; } @@ -760,16 +758,7 @@ int snd_pcm_hw_params_get_channels_max(const snd_pcm_hw_params_t *params, unsigned int *val) { const bool pb = (params->stream == SND_PCM_STREAM_PLAYBACK); - unsigned int max = 2; - for (unsigned int c = 0; c < params->cap.nconf; ++c) { - const unsigned int cconf = (pb ? params->cap.confs[c].pchan : params->cap.confs[c].rchan); - for (unsigned int i = 0; i < SIO_NCHAN; ++i) { - if (!(cconf & (1 << i))) - continue; - max = ((pb ? params->cap.pchan[i] : params->cap.rchan[i]) > max ? (pb ? params->cap.pchan[i] : params->cap.rchan[i]) : max); - } - } - if (val) *val = max; + if (val) *val = (pb ? params->limits.pchan[1] : params->limits.rchan[1]); return 0; } @@ -798,32 +787,16 @@ snd_pcm_hw_params_set_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int snd_pcm_hw_params_get_rate_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) { - unsigned int min = (unsigned int)~0; - for (unsigned int c = 0; c < params->cap.nconf; ++c) { - for (int i = 0; i < SIO_NRATE; ++i) { - if (!(params->cap.confs[c].rate & (1 << i))) - continue; - min = (params->cap.rate[i] < min ? params->cap.rate[i] : min); - } - } if (dir) *dir = 0; - if (val) *val = min; + if (val) *val = params->limits.rate[0]; return 0; } int snd_pcm_hw_params_get_rate_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) { - unsigned int max = 0; - for (unsigned int c = 0; c < params->cap.nconf; ++c) { - for (int i = 0; i < SIO_NRATE; ++i) { - if (!(params->cap.confs[c].rate & (1 << i))) - continue; - max = (params->cap.rate[i] > max ? params->cap.rate[i] : max); - } - } if (dir) *dir = 0; - if (val) *val = max; + if (val) *val = params->limits.rate[1]; return 0; } @@ -967,6 +940,9 @@ snd_pcm_get_chmap(snd_pcm_t *pcm) { const unsigned int nc = (pcm->hw.stream == SND_PCM_STREAM_PLAYBACK ? pcm->hw.par.pchan : pcm->hw.par.rchan); + if (!nc || nc > 2) + return NULL; + snd_pcm_chmap_t *map; if (!(map = calloc(1, sizeof(*map) + nc))) { WARN1("calloc"); diff --git a/src/util/util.h b/src/util/util.h index 67c47e0..fe3f50c 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -25,6 +25,8 @@ do_debug(void) #define ERR(x, y, ...) do { err(x, "asound: %s " y, __func__, ##__VA_ARGS__); } while (0) #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) static inline char* c_strdup(const char *str) -- cgit v1.2.3