summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2018-11-01 06:43:37 +0200
committerJari Vetoniemi <mailroxas@gmail.com>2018-11-01 07:14:55 +0200
commitfdb250e1369d4364731cc7c28998669db957a360 (patch)
tree0e214e6a95991935590493a069937086705fd169
parent2412048fc02d00341f735e2b4e3a6b2ccb17a6b8 (diff)
tidy up code, and start checking up hwcaps
supported formats and their conversions are handled more nicer now too.
-rw-r--r--src/pcm.c548
-rw-r--r--src/util/util.h2
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, &params, (pcm->hw.stream == SND_PCM_STREAM_PLAYBACK ? pcm->hw.par.pchan : pcm->hw.par.rchan));
- enc_init(&enc, &params, (pcm->hw.stream == SND_PCM_STREAM_PLAYBACK ? pcm->hw.par.pchan : pcm->hw.par.rchan));
+ dec_init(&dec, &params[0], (pcm->hw.stream == SND_PCM_STREAM_PLAYBACK ? pcm->hw.par.pchan : pcm->hw.par.rchan));
+ enc_init(&enc, &params[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(&params->par);
- copy_important_params(&params->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, &params->par)) {
- WARNX1("sio_setpar failed");
+ const struct sio_par old = params->par;
+ if (!apply_par(pcm, &old, &params->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);
}
@@ -440,6 +613,13 @@ snd_pcm_hw_params_current(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
}
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)
{
if (_access != SND_PCM_ACCESS_RW_INTERLEAVED)
@@ -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, &params->par, &params->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, &params->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)