case SND_PCM_IOCTL_INFO:
ctrl->result = snd_pcm_info(pcm, (snd_pcm_info_t *) &ctrl->u.info);
break;
- case SND_PCM_IOCTL_HW_INFO:
- ctrl->result = snd_pcm_hw_info(pcm, (snd_pcm_hw_info_t *) &ctrl->u.hw_info);
+ case SND_PCM_IOCTL_HW_REFINE:
+ ctrl->result = snd_pcm_hw_refine(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_refine);
break;
case SND_PCM_IOCTL_HW_PARAMS:
ctrl->result = snd_pcm_hw_params(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_params);
pid_t pid;
} async;
snd_pcm_info_t info;
- snd_pcm_hw_info_t hw_info;
+ snd_pcm_hw_params_t hw_refine;
snd_pcm_hw_params_t hw_params;
snd_pcm_sw_params_t sw_params;
snd_pcm_dig_params_t dig_params;
SND_PCM_TYPE_LBSERVER,
} snd_pcm_type_t;
-enum {
- SND_PCM_RULE_PAR_MASK = 0x00ff,
- SND_PCM_RULE_REL_LT = 0x100,
- SND_PCM_RULE_REL_GT = 0x200,
- SND_PCM_RULE_REL_EQ = 0x300,
- SND_PCM_RULE_REL_LE = 0x400,
- SND_PCM_RULE_REL_GE = 0x500,
- SND_PCM_RULE_REL_NEAR = 0x600,
- SND_PCM_RULE_REL_BITS = 0x700,
- SND_PCM_RULE_REL_MASK = 0xff00
-};
-
typedef struct _snd_pcm_channel_area {
void *addr; /* base address of channel samples */
unsigned int first; /* offset to first sample in bits */
int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock);
int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid);
int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info);
-int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info);
-int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
+int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
int snd_pcm_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info);
int snd_pcm_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params);
int snd_pcm_dump_hw_setup(snd_pcm_t *pcm, FILE *fp);
int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, FILE *fp);
int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp);
-int snd_pcm_dump_hw_info(snd_pcm_hw_info_t *info, FILE *fp);
+int snd_pcm_dump_hw_params(snd_pcm_hw_params_t *params, FILE *fp);
int snd_pcm_dump_hw_params_fail(snd_pcm_hw_params_t *params, FILE *fp);
int snd_pcm_dump_sw_params_fail(snd_pcm_sw_params_t *params, FILE *fp);
int snd_pcm_dump(snd_pcm_t *pcm, FILE *fp);
int snd_pcm_wait(snd_pcm_t *pcm, int timeout);
ssize_t snd_pcm_avail_update(snd_pcm_t *pcm);
int snd_pcm_set_avail_min(snd_pcm_t *pcm, size_t size);
-void snd_pcm_hw_info_any(snd_pcm_hw_info_t *info);
-int snd_pcm_hw_params_info(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info);
+
+typedef struct _mask mask_t;
+size_t mask_sizeof();
+void mask_none(mask_t *mask);
+void mask_all(mask_t *mask);
+void mask_load(mask_t *mask, unsigned int msk);
+int mask_empty(const mask_t *mask);
+void mask_set(mask_t *mask, unsigned int val);
+void mask_reset(mask_t *mask, unsigned int val);
+void mask_copy(mask_t *mask, const mask_t *v);
+int mask_test(const mask_t *mask, unsigned int val);
+void mask_intersect(mask_t *mask, const mask_t *v);
+int mask_eq(const mask_t *a, const mask_t *b);
+int mask_single(const mask_t *mask);
+
+int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int par, unsigned int val);
+int snd_pcm_hw_params_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int par, unsigned int val);
+int snd_pcm_hw_params_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int par, unsigned int val);
+int snd_pcm_hw_params_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int par, unsigned int min, unsigned int max);
+int snd_pcm_hw_params_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int par);
+int snd_pcm_hw_params_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int par);
+int snd_pcm_hw_params_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int par, unsigned int val);
+int snd_pcm_hw_params_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int par, const mask_t *mask);
+int snd_pcm_hw_params_info_rate(const snd_pcm_hw_params_t *params,
+ unsigned int *rate_num,
+ unsigned int *rate_den);
+int snd_pcm_hw_params_info_msbits(const snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_info_flags(const snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_info_fifo_size(const snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_info_dig_groups(const snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_value(const snd_pcm_hw_params_t *params,
+ unsigned int var);
+const mask_t *snd_pcm_hw_params_value_mask(const snd_pcm_hw_params_t *params,
+ unsigned int var);
+const interval_t *snd_pcm_hw_params_value_interval(const snd_pcm_hw_params_t *params,
+ unsigned int var);
+unsigned int snd_pcm_hw_params_value_min(const snd_pcm_hw_params_t *params,
+ unsigned int var);
+unsigned int snd_pcm_hw_params_value_max(const snd_pcm_hw_params_t *params,
+ unsigned int var);
+int snd_pcm_hw_params_test(const snd_pcm_hw_params_t *params,
+ unsigned int var, unsigned int val);
+int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
typedef struct _snd_pcm_strategy snd_pcm_strategy_t;
unsigned int badness;
} snd_pcm_strategy_simple_choices_list_t;
-int snd_pcm_hw_info_strategy(snd_pcm_t *pcm, snd_pcm_hw_info_t *info,
+int snd_pcm_hw_info_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *info,
const snd_pcm_strategy_t *strategy);
int snd_pcm_strategy_free(snd_pcm_strategy_t *strategy);
unsigned int param,
unsigned int count,
snd_pcm_strategy_simple_choices_list_t *choices);
-int snd_pcm_hw_info_try_explain_failure(snd_pcm_t *pcm,
- snd_pcm_hw_info_t *fail,
- snd_pcm_hw_info_t *success,
+int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *fail,
+ snd_pcm_hw_params_t *success,
unsigned int depth,
FILE *fp);
ssize_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, size_t size);
ssize_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, size_t size);
+const char *snd_pcm_access_name(unsigned int access);
const char *snd_pcm_format_name(unsigned int format);
+const char *snd_pcm_subformat_name(unsigned int subformat);
+const char *snd_pcm_hw_param_name(unsigned int params);
+const char *snd_pcm_sw_param_name(unsigned int params);
+
const char *snd_pcm_format_description(unsigned int format);
int snd_pcm_format_value(const char* name);
EXTRA_LTLIBRARIES = libpcm.la
-libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \
+libpcm_la_SOURCES = mask.c interval.c \
+ pcm.c pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \
pcm_route.c pcm_mulaw.c pcm_alaw.c pcm_adpcm.c \
pcm_rate.c pcm_plug.c pcm_misc.c pcm_mmap.c pcm_multi.c \
- pcm_shm.c pcm_file.c pcm_share.c pcm_null.c
-noinst_HEADERS = pcm_local.h pcm_plugin.h
+ pcm_shm.c pcm_file.c pcm_share.c pcm_null.c pcm_params.c
+noinst_HEADERS = pcm_local.h pcm_plugin.h mask.h mask_inline.h \
+ interval.h interval_inline.h
all: libpcm.la
--- /dev/null
+/*
+ * Interval functions
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define INTERVAL_C
+
+#include <sys/types.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/asound.h>
+#include "interval.h"
+
+static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
+{
+ *rem = *n % div;
+ *n /= div;
+}
+
+static inline unsigned int div32(unsigned int a, unsigned int b,
+ unsigned int *r)
+{
+ *r = a % b;
+ return a / b;
+}
+
+static inline unsigned int div_down(unsigned int a, unsigned int b)
+{
+ return a / b;
+}
+
+static inline unsigned int div_up(unsigned int a, unsigned int b)
+{
+ unsigned int r;
+ unsigned int q = div32(a, b, &r);
+ if (r)
+ ++q;
+ return q;
+}
+
+static inline unsigned int mul(unsigned int a, unsigned int b)
+{
+ if (div_down(UINT_MAX, a) < b)
+ return UINT_MAX;
+ return a * b;
+}
+
+static inline unsigned int add(unsigned int a, unsigned int b)
+{
+ if (a >= UINT_MAX - b)
+ return UINT_MAX;
+ return a + b;
+}
+
+static inline unsigned int sub(unsigned int a, unsigned int b)
+{
+ if (a > b)
+ return a - b;
+ return 0;
+}
+
+static inline unsigned int muldiv32(unsigned int a, unsigned int b,
+ unsigned int c, unsigned int *r)
+{
+ u_int64_t n = (u_int64_t) a * b;
+ div64_32(&n, c, r);
+ if (n >= UINT_MAX) {
+ *r = 0;
+ return UINT_MAX;
+ }
+ return n;
+}
+
+int interval_refine_min(interval_t *i, unsigned int min)
+{
+ int changed = 0;
+ int openmin = 0;
+ assert(!interval_empty(i));
+ if (i->min < min) {
+ i->min = min;
+ i->openmin = openmin;
+ changed = 1;
+ } else if (i->min == min && !i->openmin && openmin) {
+ i->openmin = 1;
+ changed = 1;
+ }
+ if (!i->real) {
+ if (i->openmin) {
+ i->min++;
+ i->openmin = 0;
+ }
+ }
+ if (i->min > i->max ||
+ (i->min == i->max && (i->openmin || i->openmax))) {
+ i->empty = 1;
+ return -EINVAL;
+ }
+ return changed;
+}
+
+int interval_refine_max(interval_t *i, unsigned int max)
+{
+ int changed = 0;
+ int openmax = 1;
+ max = add(max, 1);
+ assert(!interval_empty(i));
+ if (i->max > max) {
+ i->max = max;
+ i->openmax = openmax;
+ changed = 1;
+ } else if (i->max == max && !i->openmax && openmax) {
+ i->openmax = 1;
+ changed = 1;
+ }
+ if (!i->real) {
+ if (i->openmax) {
+ i->max--;
+ i->openmax = 0;
+ }
+ }
+ if (i->min > i->max ||
+ (i->min == i->max && (i->openmin || i->openmax))) {
+ i->empty = 1;
+ return -EINVAL;
+ }
+ return changed;
+}
+
+/* r <- v */
+int interval_refine(interval_t *i, const interval_t *v)
+{
+ int changed = 0;
+ assert(!interval_empty(i));
+ if (i->min < v->min) {
+ i->min = v->min;
+ i->openmin = v->openmin;
+ changed = 1;
+ } else if (i->min == v->min && !i->openmin && v->openmin) {
+ i->openmin = 1;
+ changed = 1;
+ }
+ if (i->max > v->max) {
+ i->max = v->max;
+ i->openmax = v->openmax;
+ changed = 1;
+ } else if (i->max == v->max && !i->openmax && v->openmax) {
+ i->openmax = 1;
+ changed = 1;
+ }
+ if (!i->real) {
+ if (i->openmin) {
+ i->min++;
+ i->openmin = 0;
+ }
+ if (i->openmax) {
+ i->max--;
+ i->openmax = 0;
+ }
+ }
+ if (i->min > i->max ||
+ (i->min == i->max && (i->openmin || i->openmax))) {
+ i->empty = 1;
+ return -EINVAL;
+ }
+ return changed;
+}
+
+int interval_refine_first(interval_t *i)
+{
+ assert(!interval_empty(i));
+ if (i->min == i->max ||
+ (i->min + 1 == i->max && i->openmin && i->openmax))
+ return 0;
+ i->max = i->min;
+ i->openmax = i->openmin;
+ if (i->openmax)
+ i->max++;
+ return 1;
+}
+
+int interval_refine_last(interval_t *i)
+{
+ assert(!interval_empty(i));
+ if (i->min == i->max ||
+ (i->min + 1 == i->max && i->openmin && i->openmax))
+ return 0;
+ i->min = i->max;
+ i->openmin = i->openmax;
+ if (i->openmin)
+ i->min--;
+ return 1;
+}
+
+int interval_refine_set(interval_t *i, unsigned int val)
+{
+ interval_t t;
+ t.min = val;
+ t.openmin = 0;
+ t.max = add(val, 1);
+ t.openmax = 1;
+ return interval_refine(i, &t);
+}
+
+/* a <- b * c */
+int interval_mul(interval_t *a, const interval_t *b, const interval_t *c)
+{
+ interval_t t;
+ assert(!a->empty && !b->empty && !c->empty);
+ t.min = mul(b->min, c->min);
+ t.openmin = (b->openmin || c->openmin);
+ t.max = mul(b->max, c->max);
+ t.openmax = (b->openmax || c->openmax);
+ return interval_refine(a, &t);
+}
+
+/* a <- b / c */
+int interval_div(interval_t *a, const interval_t *b, const interval_t *c)
+{
+ interval_t t;
+ unsigned int r;
+ assert(!a->empty && !b->empty && !c->empty);
+ t.min = div32(b->min, c->max, &r);
+ t.openmin = (r || b->openmin || c->openmax);
+ t.max = div32(b->max, c->min, &r);
+ if (r) {
+ t.max++;
+ t.openmax = 1;
+ } else
+ t.openmax = (b->openmax || c->openmin);
+ return interval_refine(a, &t);
+}
+
+
+/* a <- b * c / k */
+int interval_muldivk(interval_t *a, unsigned int k,
+ const interval_t *b, const interval_t *c)
+{
+ interval_t t;
+ unsigned int r;
+ assert(!a->empty && !b->empty && !c->empty);
+ t.min = muldiv32(b->min, c->min, k, &r);
+ t.openmin = (r || b->openmin || c->openmin);
+ t.max = muldiv32(b->max, c->max, k, &r);
+ if (r) {
+ t.max++;
+ t.openmax = 1;
+ } else
+ t.openmax = (b->openmax || c->openmax);
+ return interval_refine(a, &t);
+}
+
+/* a <- b * k / c */
+int interval_mulkdiv(interval_t *a, unsigned int k,
+ const interval_t *b, const interval_t *c)
+{
+ interval_t t;
+ unsigned int r;
+ assert(!a->empty && !b->empty && !c->empty);
+ t.min = muldiv32(b->min, k, c->max, &r);
+ t.openmin = (r || b->openmin || c->openmax);
+ t.max = muldiv32(b->max, k, c->min, &r);
+ if (r) {
+ t.max++;
+ t.openmax = 1;
+ } else
+ t.openmax = (b->openmax || c->openmin);
+ return interval_refine(a, &t);
+}
+
+void interval_print(const interval_t *i, FILE *fp)
+{
+ if (interval_single(i)) {
+ fprintf(fp, "%u", interval_value(i));
+ } else {
+ fprintf(fp, "%c%u %u%c",
+ i->openmin ? '(' : '[',
+ i->min, i->max,
+ i->openmax ? ')' : ']');
+ }
+}
--- /dev/null
+/*
+ * Interval header
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+
+#ifdef INTERVAL_C
+#include "interval_inline.h"
+#endif
+
+void interval_all(interval_t *i);
+void interval_setreal(interval_t *i);
+int interval_empty(const interval_t *i);
+int interval_single(const interval_t *i);
+int interval_value(const interval_t *i);
+int interval_min(const interval_t *i);
+int interval_max(const interval_t *i);
+int interval_test(const interval_t *i, unsigned int val);
+int interval_refine_min(interval_t *i, unsigned int min);
+int interval_refine_max(interval_t *i, unsigned int max);
+int interval_refine(interval_t *i, const interval_t *v);
+int interval_refine_first(interval_t *i);
+int interval_refine_last(interval_t *i);
+int interval_refine_set(interval_t *i, unsigned int val);
+int interval_mul(interval_t *a, const interval_t *b, const interval_t *c);
+int interval_div(interval_t *a, const interval_t *b, const interval_t *c);
+int interval_muldivk(interval_t *a, unsigned int k,
+ const interval_t *b, const interval_t *c);
+int interval_mulkdiv(interval_t *a, unsigned int k,
+ const interval_t *b, const interval_t *c);
+void interval_copy(interval_t *dst, const interval_t *src);
+void interval_print(const interval_t *i, FILE *fp);
+int interval_eq(const interval_t *i1, const interval_t *i2);
--- /dev/null
+/*
+ * Interval inlines
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef INTERVAL_C
+#define INLINE inline
+#else
+#define INLINE static inline
+#endif
+
+INLINE void interval_all(interval_t *i)
+{
+ i->min = 1;
+ i->max = UINT_MAX;
+}
+
+INLINE int interval_empty(const interval_t *i)
+{
+ return i->empty;
+}
+
+INLINE int interval_single(const interval_t *i)
+{
+ assert(!interval_empty(i));
+ return (i->min == i->max ||
+ (i->min + 1 == i->max && i->openmax));
+}
+
+INLINE int interval_value(const interval_t *i)
+{
+ assert(interval_single(i));
+ return i->min;
+}
+
+INLINE int interval_min(const interval_t *i)
+{
+ assert(!interval_empty(i));
+ return i->min;
+}
+
+INLINE int interval_max(const interval_t *i)
+{
+ unsigned int v;
+ assert(!interval_empty(i));
+ v = i->max;
+ if (i->openmax)
+ v--;
+ return v;
+}
+
+INLINE int interval_test(const interval_t *i, unsigned int val)
+{
+ return !((i->min > val || (i->min == val && i->openmin) ||
+ i->max < val || (i->max == val && i->openmax)));
+}
+
+INLINE void interval_copy(interval_t *d, const interval_t *s)
+{
+ *d = *s;
+}
+
+INLINE void interval_setreal(interval_t *i)
+{
+ i->real = 1;
+}
+
+INLINE int interval_eq(const interval_t *i1, const interval_t *i2)
+{
+ if (i1->empty)
+ return i2->empty;
+ if (i2->empty)
+ return i1->empty;
+ return i1->min == i2->min && i1->openmin == i2->openmin &&
+ i1->max == i2->max && i1->openmax == i2->openmax;
+}
+
--- /dev/null
+/*
+ * Mask functions
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define MASK_C
+
+#include <sys/types.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include "asoundlib.h"
+#include "mask.h"
+
--- /dev/null
+/*
+ * Mask header
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include "asoundlib.h"
+
+#define MASK_MAX 32
+
+#ifdef MASK_C
+#include "mask_inline.h"
+#endif
+
+void mask_none(mask_t *mask);
+void mask_all(mask_t *mask);
+void mask_load(mask_t *mask, unsigned int msk);
+int mask_empty(const mask_t *mask);
+void mask_set(mask_t *mask, unsigned int val);
+void mask_reset(mask_t *mask, unsigned int val);
+void mask_copy(mask_t *mask, const mask_t *v);
+int mask_test(const mask_t *mask, unsigned int val);
+void mask_intersect(mask_t *mask, const mask_t *v);
+unsigned int mask_count(const mask_t *mask);
+unsigned int mask_min(const mask_t *mask);
+unsigned int mask_max(const mask_t *mask);
+void mask_set_range(mask_t *mask, unsigned int from, unsigned int to);
+void mask_reset_range(mask_t *mask, unsigned int from, unsigned int to);
+void mask_leave(mask_t *mask, unsigned int val);
+int mask_eq(const mask_t *mask, const mask_t *v);
+int mask_single(const mask_t *mask);
+int mask_refine(mask_t *mask, const mask_t *v);
+int mask_refine_first(mask_t *mask);
+int mask_refine_last(mask_t *mask);
+int mask_refine_min(mask_t *mask, unsigned int val);
+int mask_refine_max(mask_t *mask, unsigned int val);
+int mask_refine_set(mask_t *mask, unsigned int val);
+int mask_value(const mask_t *mask);
--- /dev/null
+/*
+ * Mask inlines
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef MASK_C
+#define INLINE inline
+#else
+#define INLINE static inline
+#endif
+
+struct _mask {
+ unsigned int bits;
+};
+
+#define mask_bits(mask) ((mask)->bits)
+
+INLINE unsigned int ld2(u_int32_t v)
+{
+ unsigned r = 0;
+
+ if (v >= 0x10000) {
+ v >>= 16;
+ r += 16;
+ }
+ if (v >= 0x100) {
+ v >>= 8;
+ r += 8;
+ }
+ if (v >= 0x10) {
+ v >>= 4;
+ r += 4;
+ }
+ if (v >= 4) {
+ v >>= 2;
+ r += 2;
+ }
+ if (v >= 2)
+ r++;
+ return r;
+}
+
+INLINE unsigned int hweight32(u_int32_t v)
+{
+ v = (v & 0x55555555) + ((v >> 1) & 0x55555555);
+ v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+ v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F);
+ v = (v & 0x00FF00FF) + ((v >> 8) & 0x00FF00FF);
+ return (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFF);
+}
+
+INLINE size_t mask_sizeof(void)
+{
+ return sizeof(mask_t);
+}
+
+INLINE void mask_none(mask_t *mask)
+{
+ mask_bits(mask) = 0;
+}
+
+INLINE void mask_all(mask_t *mask)
+{
+ mask_bits(mask) = ~0U;
+}
+
+INLINE void mask_load(mask_t *mask, unsigned int msk)
+{
+ mask_bits(mask) = msk;
+}
+
+INLINE int mask_empty(const mask_t *mask)
+{
+ return mask_bits(mask) == 0;
+}
+
+INLINE unsigned int mask_count(const mask_t *mask)
+{
+ return hweight32(mask_bits(mask));
+}
+
+INLINE unsigned int mask_min(const mask_t *mask)
+{
+ assert(!mask_empty(mask));
+ return ffs(mask_bits(mask)) - 1;
+}
+
+INLINE unsigned int mask_max(const mask_t *mask)
+{
+ assert(!mask_empty(mask));
+ return ld2(mask_bits(mask));
+}
+
+INLINE void mask_set(mask_t *mask, unsigned int val)
+{
+ assert(val <= MASK_MAX);
+ mask_bits(mask) |= (1U << val);
+}
+
+INLINE void mask_reset(mask_t *mask, unsigned int val)
+{
+ assert(val <= MASK_MAX);
+ mask_bits(mask) &= ~(1U << val);
+}
+
+INLINE void mask_set_range(mask_t *mask, unsigned int from, unsigned int to)
+{
+ assert(to <= MASK_MAX && from <= to);
+ mask_bits(mask) |= ((1U << (from - to + 1)) - 1) << from;
+}
+
+INLINE void mask_reset_range(mask_t *mask, unsigned int from, unsigned int to)
+{
+ assert(to <= MASK_MAX && from <= to);
+ mask_bits(mask) &= ~(((1U << (from - to + 1)) - 1) << from);
+}
+
+INLINE void mask_leave(mask_t *mask, unsigned int val)
+{
+ assert(val <= MASK_MAX);
+ mask_bits(mask) &= 1U << val;
+}
+
+INLINE void mask_intersect(mask_t *mask, const mask_t *v)
+{
+ mask_bits(mask) &= mask_bits(v);
+}
+
+INLINE int mask_eq(const mask_t *mask, const mask_t *v)
+{
+ return mask_bits(mask) == mask_bits(v);
+}
+
+INLINE void mask_copy(mask_t *mask, const mask_t *v)
+{
+ mask_bits(mask) = mask_bits(v);
+}
+
+INLINE int mask_test(const mask_t *mask, unsigned int val)
+{
+ assert(val <= MASK_MAX);
+ return mask_bits(mask) & (1U << val);
+}
+
+INLINE int mask_single(const mask_t *mask)
+{
+ assert(!mask_empty(mask));
+ return !(mask_bits(mask) & (mask_bits(mask) - 1));
+}
+
+INLINE int mask_refine(mask_t *mask, const mask_t *v)
+{
+ mask_t old;
+ assert(!mask_empty(mask));
+ mask_copy(&old, mask);
+ mask_intersect(mask, v);
+ if (mask_empty(mask))
+ return -EINVAL;
+ return !mask_eq(mask, &old);
+}
+
+INLINE int mask_refine_first(mask_t *mask)
+{
+ assert(!mask_empty(mask));
+ if (mask_single(mask))
+ return 0;
+ mask_leave(mask, mask_min(mask));
+ return 1;
+}
+
+INLINE int mask_refine_last(mask_t *mask)
+{
+ assert(!mask_empty(mask));
+ if (mask_single(mask))
+ return 0;
+ mask_leave(mask, mask_max(mask));
+ return 1;
+}
+
+INLINE int mask_refine_min(mask_t *mask, unsigned int val)
+{
+ assert(!mask_empty(mask));
+ if (mask_min(mask) >= val)
+ return 0;
+ mask_reset_range(mask, 0, val - 1);
+ if (mask_empty(mask))
+ return -EINVAL;
+ return 1;
+}
+
+INLINE int mask_refine_max(mask_t *mask, unsigned int val)
+{
+ assert(!mask_empty(mask));
+ if (mask_max(mask) <= val)
+ return 0;
+ mask_reset_range(mask, val + 1, MASK_MAX);
+ if (mask_empty(mask))
+ return -EINVAL;
+ return 1;
+}
+
+INLINE int mask_refine_set(mask_t *mask, unsigned int val)
+{
+ int changed;
+ assert(!mask_empty(mask));
+ changed = !mask_single(mask);
+ mask_leave(mask, val);
+ if (mask_empty(mask))
+ return -EINVAL;
+ return changed;
+}
+
+INLINE int mask_value(const mask_t *mask)
+{
+ assert(!mask_empty(mask));
+ return mask_min(mask);
+}
return pcm->ops->info(pcm->op_arg, info);
}
-int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
-{
- int err;
- assert(pcm && info);
-#if 0
- fprintf(stderr, "hw_info entered:\n");
- snd_pcm_dump_hw_info(info, stderr);
- fprintf(stderr, "\n");
-#endif
- err = pcm->ops->hw_info(pcm->op_arg, info);
-#if 0
- fprintf(stderr, "hw_info return %d:\n", err);
- snd_pcm_dump_hw_info(info, stderr);
- fprintf(stderr, "\n");
-#endif
- return err;
-}
-
-void snd_pcm_hw_info_any(snd_pcm_hw_info_t *info)
-{
- assert(info);
- info->flags = 0;
- info->access_mask = ~0;
- info->format_mask = ~0;
- info->subformat_mask = ~0;
- info->channels_min = 1;
- info->channels_max = UINT_MAX;
- info->rate_min = 1;
- info->rate_max = UINT_MAX;
- info->fragment_length_min = 0;
- info->fragment_length_max = UINT_MAX;
- info->fragments_min = 1;
- info->fragments_max = UINT_MAX;
- info->buffer_length_min = 1;
- info->buffer_length_max = UINT_MAX;
-}
-
-void snd_pcm_hw_params_to_info(snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info)
-{
- int r;
- assert(info && params);
- info->flags = 0;
- info->access_mask = 1U << params->access;
- info->format_mask = 1U << params->format;
- info->subformat_mask = 1U << params->subformat;
- info->channels_min = info->channels_max = params->channels;
- info->rate_min = info->rate_max = params->rate;
- info->fragment_length_min = muldiv_down(params->fragment_size, 1000000, params->rate);
- info->fragment_length_max = muldiv(params->fragment_size + 1, 1000000, params->rate, &r);
- if (r == 0)
- info->fragment_length_max--;
- info->fragments_min = info->fragments_max = params->fragments;
- info->buffer_length_min = muldiv_down(params->fragment_size * params->fragments, 1000000, params->rate);
- info->buffer_length_max = muldiv((params->fragment_size + 1) * params->fragments, 1000000, params->rate, &r);
- if (r == 0)
- info->buffer_length_max--;
-}
-
int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
{
int err;
#define XRUN(v) [SND_PCM_XRUN_##v] = #v
#define ACCESS(v) [SND_PCM_ACCESS_##v] = #v
#define START(v) [SND_PCM_START_##v] = #v
-#define HW_INFO(v) [SND_PCM_HW_INFO_##v] = #v
#define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v
#define SW_PARAM(v) [SND_PCM_SW_PARAM_##v] = #v
#define FORMAT(v) [SND_PCM_FORMAT_##v] = #v
STATE(PAUSED),
};
-char *snd_pcm_hw_info_names[] = {
- HW_INFO(ACCESS),
- HW_INFO(FORMAT),
- HW_INFO(SUBFORMAT),
- HW_INFO(CHANNELS),
- HW_INFO(RATE),
- HW_INFO(FRAGMENT_LENGTH),
- HW_INFO(FRAGMENTS),
- HW_INFO(BUFFER_LENGTH),
-};
-
char *snd_pcm_hw_param_names[] = {
HW_PARAM(ACCESS),
HW_PARAM(FORMAT),
HW_PARAM(SUBFORMAT),
HW_PARAM(CHANNELS),
HW_PARAM(RATE),
+ HW_PARAM(FRAGMENT_LENGTH),
HW_PARAM(FRAGMENT_SIZE),
HW_PARAM(FRAGMENTS),
+ HW_PARAM(BUFFER_LENGTH),
+ HW_PARAM(BUFFER_SIZE),
+ HW_PARAM(SAMPLE_BITS),
+ HW_PARAM(FRAME_BITS),
+ HW_PARAM(FRAGMENT_BYTES),
+ HW_PARAM(BUFFER_BYTES),
};
char *snd_pcm_sw_param_names[] = {
return 0;
}
-int snd_pcm_dump_hw_params_fail(snd_pcm_hw_params_t *params, FILE *fp)
-{
- int k;
- if (params->fail_mask == 0) {
- fprintf(fp, "unknown hw_params failure reason\n");
- return 0;
- }
- fprintf(fp, "hw_params failed on the following field value(s):\n");
- for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
- if (!(params->fail_mask & (1U << k)))
- continue;
- switch (k) {
- case SND_PCM_HW_PARAM_ACCESS:
- fprintf(fp, "access: %s\n", assoc(params->access, snd_pcm_access_names));
- break;
- case SND_PCM_HW_PARAM_FORMAT:
- fprintf(fp, "format: %s\n", assoc(params->format, snd_pcm_format_names));
- break;
- case SND_PCM_HW_PARAM_SUBFORMAT:
- fprintf(fp, "subformat: %s\n", assoc(params->subformat, snd_pcm_subformat_names));
- break;
- case SND_PCM_HW_PARAM_CHANNELS:
- fprintf(fp, "channels: %u\n", params->channels);
- break;
- case SND_PCM_HW_PARAM_RATE:
- fprintf(fp, "rate: %u\n", params->rate);
- break;
- case SND_PCM_HW_PARAM_FRAGMENT_SIZE:
- fprintf(fp, "fragment_size: %lu\n", (long)params->fragment_size);
- break;
- case SND_PCM_HW_PARAM_FRAGMENTS:
- fprintf(fp, "fragments: %u\n", params->fragments);
- break;
- default:
- assert(0);
- break;
- }
- }
- return 0;
-}
-
int snd_pcm_dump_sw_params_fail(snd_pcm_sw_params_t *params, FILE *fp)
{
int k;
return 0;
}
+const char *snd_pcm_access_name(unsigned int access)
+{
+ assert(access <= SND_PCM_ACCESS_LAST);
+ return snd_pcm_access_names[access];
+}
+
const char *snd_pcm_format_name(unsigned int format)
{
assert(format <= SND_PCM_FORMAT_LAST);
return -1;
}
+const char *snd_pcm_subformat_name(unsigned int subformat)
+{
+ assert(subformat <= SND_PCM_SUBFORMAT_LAST);
+ return snd_pcm_subformat_names[subformat];
+}
+
+const char *snd_pcm_hw_param_name(unsigned int param)
+{
+ assert(param <= SND_PCM_HW_PARAM_LAST);
+ return snd_pcm_hw_param_names[param];
+}
+
ssize_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes)
{
assert(pcm);
return err;
}
-#if 0
-int snd_pcm_alloc_user_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
-{
- i->type = SND_PCM_MMAP_USER;
- i->size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
- i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666);
- if (i->u.user.shmid < 0) {
- SYSERR("shmget failed");
- return -errno;
- }
- i->addr = shmat(i->u.user.shmid, 0, 0);
- if (i->addr == (void*) -1) {
- SYSERR("shmat failed");
- return -errno;
- }
- return 0;
-}
-
-int snd_pcm_alloc_kernel_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i, int fd)
-{
- i->type = SND_PCM_MMAP_KERNEL;
- /* FIXME */
- i->size = PAGE_ALIGN(snd_pcm_frames_to_bytes(pcm, pcm->buffer_size));
- i->addr = mmap(NULL, i->size,
- PROT_WRITE | PROT_READ,
- MAP_FILE|MAP_SHARED,
- fd, SND_PCM_MMAP_OFFSET_DATA);
- if (i->addr == MAP_FAILED ||
- i->addr == NULL) {
- SYSERR("data mmap failed");
- return -errno;
- }
- i->u.kernel.fd = fd;
- return 0;
-}
-
-int snd_pcm_free_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
-{
- if (i->type == SND_PCM_MMAP_USER) {
- if (shmdt(i->addr) < 0) {
- SYSERR("shmdt failed");
- return -errno;
- }
- if (shmctl(i->u.user.shmid, IPC_RMID, 0) < 0) {
- SYSERR("shmctl IPC_RMID failed");
- return -errno;
- }
- } else {
- if (munmap(pcm->mmap_info->addr, pcm->mmap_info->size) < 0) {
- SYSERR("data munmap failed");
- return -errno;
- }
- }
- return 0;
-}
-#endif
-
-int snd_pcm_hw_info_bits_per_sample(snd_pcm_hw_info_t *info,
- unsigned int *min, unsigned int *max)
-{
- int k;
- unsigned int bits_min = UINT_MAX, bits_max = 0;
- int changed = 0;
- for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k) {
- int bits;
- if (!(info->format_mask & (1U << k)))
- continue;
- bits = snd_pcm_format_physical_width(k);
- assert(bits > 0);
- if ((unsigned) bits < *min || (unsigned)bits > *max) {
- info->format_mask &= ~(1U << k);
- changed++;
- continue;
- }
- if ((unsigned)bits < bits_min)
- bits_min = bits;
- if ((unsigned)bits > bits_max)
- bits_max = bits;
- }
- *min = bits_min;
- *max = bits_max;
- if (info->format_mask == 0)
- return -EINVAL;
- return changed;
-}
-
-
-int snd_pcm_hw_info_complete(snd_pcm_hw_info_t *info)
-{
- if (info->msbits == 0) {
- unsigned int bits_min = 0, bits_max = UINT_MAX;
- snd_pcm_hw_info_bits_per_sample(info, &bits_min, &bits_max);
- if (bits_min == bits_max)
- info->msbits = bits_min;
- }
- if (info->rate_den == 0 &&
- info->rate_min == info->rate_max) {
- info->rate_num = info->rate_min;
- info->rate_den = 1;
- }
- return 0;
-}
-
-struct _snd_pcm_strategy {
- unsigned int badness_min, badness_max;
- int (*choose_param)(const snd_pcm_hw_info_t *info,
- snd_pcm_t *pcm,
- const snd_pcm_strategy_t *strategy);
- int (*next_value)(const snd_pcm_hw_info_t *info,
- unsigned int param,
- int value,
- snd_pcm_t *pcm,
- const snd_pcm_strategy_t *strategy);
- int (*min_badness)(const snd_pcm_hw_info_t *info,
- unsigned int max_badness,
- snd_pcm_t *pcm,
- const snd_pcm_strategy_t *strategy);
- void *private;
- void (*free)(snd_pcm_strategy_t *strategy);
-};
-
-/* Independent badness */
-typedef struct _snd_pcm_strategy_simple snd_pcm_strategy_simple_t;
-
-struct _snd_pcm_strategy_simple {
- int valid;
- unsigned int order;
- int (*next_value)(const snd_pcm_hw_info_t *info,
- unsigned int param,
- int value,
- snd_pcm_t *pcm,
- const snd_pcm_strategy_simple_t *par);
- unsigned int (*min_badness)(const snd_pcm_hw_info_t *info,
- unsigned int param,
- snd_pcm_t *pcm,
- const snd_pcm_strategy_simple_t *par);
- void *private;
- void (*free)(snd_pcm_strategy_simple_t *strategy);
-};
-
-typedef struct _snd_pcm_strategy_simple_near {
- int best;
- unsigned int mul;
-} snd_pcm_strategy_simple_near_t;
-
-typedef struct _snd_pcm_strategy_simple_choices {
- unsigned int count;
- /* choices need to be sorted on ascending badness */
- snd_pcm_strategy_simple_choices_list_t *choices;
-} snd_pcm_strategy_simple_choices_t;
-
-static inline unsigned int hweight32(u_int32_t v)
-{
- v = (v & 0x55555555) + ((v >> 1) & 0x55555555);
- v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
- v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F);
- v = (v & 0x00FF00FF) + ((v >> 8) & 0x00FF00FF);
- return (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFF);
-}
-
-static inline unsigned int ld2(u_int32_t v)
-{
- unsigned r = 0;
-
- if (v >= 0x10000) {
- v >>= 16;
- r += 16;
- }
- if (v >= 0x100) {
- v >>= 8;
- r += 8;
- }
- if (v >= 0x10) {
- v >>= 4;
- r += 4;
- }
- if (v >= 4) {
- v >>= 2;
- r += 2;
- }
- if (v >= 2)
- r++;
- return r;
-}
-
-typedef struct {
- enum { MASK, MINMAX } type;
- char **names;
- unsigned int last;
-} par_desc_t;
-
-par_desc_t hw_infos[SND_PCM_HW_INFO_LAST + 1] = {
- [SND_PCM_HW_INFO_ACCESS] = {
- type: MASK,
- names: snd_pcm_access_names,
- last: SND_PCM_ACCESS_LAST,
- },
- [SND_PCM_HW_INFO_FORMAT] = {
- type: MASK,
- names: snd_pcm_format_names,
- last: SND_PCM_FORMAT_LAST,
- },
- [SND_PCM_HW_INFO_SUBFORMAT] = {
- type: MASK,
- names: snd_pcm_subformat_names,
- last: SND_PCM_SUBFORMAT_LAST,
- },
- [SND_PCM_HW_INFO_CHANNELS] = {
- type: MINMAX,
- names: 0,
- last: 0,
- },
- [SND_PCM_HW_INFO_RATE] = {
- type: MINMAX,
- names: 0,
- last: 0,
- },
- [SND_PCM_HW_INFO_FRAGMENT_LENGTH] = {
- type: MINMAX,
- names: 0,
- last: 0,
- },
- [SND_PCM_HW_INFO_FRAGMENTS] = {
- type: MINMAX,
- names: 0,
- last: 0,
- },
- [SND_PCM_HW_INFO_BUFFER_LENGTH] = {
- type: MINMAX,
- names: 0,
- last: 0,
- },
-};
-
-unsigned int snd_pcm_hw_info_par_get_mask(const snd_pcm_hw_info_t *info,
- unsigned int param)
-{
- switch (param) {
- case SND_PCM_HW_INFO_ACCESS:
- return info->access_mask;
- case SND_PCM_HW_INFO_FORMAT:
- return info->format_mask;
- case SND_PCM_HW_INFO_SUBFORMAT:
- return info->subformat_mask;
- default:
- assert(0);
- return 0;
- }
-}
-
-void snd_pcm_hw_info_par_get_minmax(const snd_pcm_hw_info_t *info,
- unsigned int param,
- unsigned int *min, unsigned int *max)
-{
- switch (param) {
- case SND_PCM_HW_INFO_ACCESS:
- case SND_PCM_HW_INFO_FORMAT:
- case SND_PCM_HW_INFO_SUBFORMAT:
- {
- unsigned int mask = snd_pcm_hw_info_par_get_mask(info, param);
- if (!mask) {
- *min = 32;
- *max = 0;
- } else {
- *min = ffs(mask) - 1;
- *max = ld2(mask);
- }
- break;
- }
- case SND_PCM_HW_INFO_CHANNELS:
- *min = info->channels_min;
- *max = info->channels_max;
- break;
- case SND_PCM_HW_INFO_RATE:
- *min = info->rate_min;
- *max = info->rate_max;
- break;
- case SND_PCM_HW_INFO_FRAGMENT_LENGTH:
- *min = info->fragment_length_min;
- *max = info->fragment_length_max;
- break;
- case SND_PCM_HW_INFO_FRAGMENTS:
- *min = info->fragments_min;
- *max = info->fragments_max;
- break;
- case SND_PCM_HW_INFO_BUFFER_LENGTH:
- *min = info->buffer_length_min;
- *max = info->buffer_length_max;
- break;
- default:
- assert(0);
- }
-}
-
-void snd_pcm_hw_info_par_set_mask(snd_pcm_hw_info_t *info, unsigned int param,
- unsigned int v)
-{
- switch (param) {
- case SND_PCM_HW_INFO_ACCESS:
- info->access_mask = v;
- break;
- case SND_PCM_HW_INFO_FORMAT:
- info->format_mask = v;
- break;
- case SND_PCM_HW_INFO_SUBFORMAT:
- info->subformat_mask = v;
- break;
- default:
- assert(0);
- }
-}
-
-void snd_pcm_hw_info_par_set_minmax(snd_pcm_hw_info_t *info,
- unsigned int param,
- unsigned int min, unsigned int max)
-{
- switch (param) {
- case SND_PCM_HW_INFO_ACCESS:
- case SND_PCM_HW_INFO_FORMAT:
- case SND_PCM_HW_INFO_SUBFORMAT:
- {
- unsigned int mask;
- if (min >= 32 || max <= 0 || min > max) {
- snd_pcm_hw_info_par_set_mask(info, param, 0);
- break;
- }
- if (max >= 31) {
- max = 31;
- if (min <= 0)
- break;
- }
- mask = snd_pcm_hw_info_par_get_mask(info, param);
- mask &= ((1U << (max - min + 1)) - 1) << min;
- snd_pcm_hw_info_par_set_mask(info, param, mask);
- break;
- }
- case SND_PCM_HW_INFO_CHANNELS:
- info->channels_min = min;
- info->channels_max = max;
- break;
- case SND_PCM_HW_INFO_RATE:
- info->rate_min = min;
- info->rate_max = max;
- break;
- case SND_PCM_HW_INFO_FRAGMENT_LENGTH:
- info->fragment_length_min = min;
- info->fragment_length_max = max;
- break;
- case SND_PCM_HW_INFO_FRAGMENTS:
- info->fragments_min = min;
- info->fragments_max = max;
- break;
- case SND_PCM_HW_INFO_BUFFER_LENGTH:
- info->buffer_length_min = min;
- info->buffer_length_max = max;
- break;
- default:
- assert(0);
- }
-}
-
-void snd_pcm_hw_info_par_copy(snd_pcm_hw_info_t *info, unsigned int param,
- snd_pcm_hw_info_t *src)
-{
- switch (param) {
- case SND_PCM_HW_INFO_ACCESS:
- info->access_mask = src->access_mask;
- break;
- case SND_PCM_HW_INFO_FORMAT:
- info->format_mask = src->format_mask;
- break;
- case SND_PCM_HW_INFO_SUBFORMAT:
- info->subformat_mask = src->subformat_mask;
- break;
- case SND_PCM_HW_INFO_CHANNELS:
- info->channels_min = src->channels_min;
- info->channels_max = src->channels_max;
- break;
- case SND_PCM_HW_INFO_RATE:
- info->rate_min = src->rate_min;
- info->rate_max = src->rate_max;
- break;
- case SND_PCM_HW_INFO_FRAGMENT_LENGTH:
- info->fragment_length_min = src->fragment_length_min;
- info->fragment_length_max = src->fragment_length_max;
- break;
- case SND_PCM_HW_INFO_FRAGMENTS:
- info->fragments_min = src->fragments_min;
- info->fragments_max = src->fragments_max;
- break;
- case SND_PCM_HW_INFO_BUFFER_LENGTH:
- info->buffer_length_min = src->buffer_length_min;
- info->buffer_length_max = src->buffer_length_max;
- break;
- default:
- assert(0);
- break;
- }
-}
-
-unsigned int snd_pcm_hw_info_par_choices(const snd_pcm_hw_info_t *info,
- unsigned int param)
-{
- par_desc_t *p;
- assert(param <= SND_PCM_HW_INFO_LAST);
- p = &hw_infos[param];
- switch (p->type) {
- case MASK:
- return hweight32(snd_pcm_hw_info_par_get_mask(info, param));
- case MINMAX:
- {
- unsigned int min, max;
- snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
- return max - min + 1;
- }
- default:
- assert(0);
- return 0;
- }
-}
-
-unsigned int snd_pcm_hw_info_par_refine_min(snd_pcm_hw_info_t *info,
- unsigned int param,
- unsigned int value)
-{
- unsigned int min, max;
- snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
- if (min < value) {
- min = value;
- snd_pcm_hw_info_par_set_minmax(info, param, min, max);
- }
- return min;
-}
-
-unsigned int snd_pcm_hw_info_par_refine_max(snd_pcm_hw_info_t *info,
- unsigned int param,
- unsigned int value)
-{
- unsigned int min, max;
- snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
- if (max > value) {
- max = value;
- snd_pcm_hw_info_par_set_minmax(info, param, min, max);
- }
- return max;
-}
-
-int snd_pcm_hw_info_par_check(const snd_pcm_hw_info_t *info,
- unsigned int param,
- unsigned int value)
-{
- par_desc_t *p;
- assert(param <= SND_PCM_HW_INFO_LAST);
- p = &hw_infos[param];
- switch (p->type) {
- case MASK:
- return snd_pcm_hw_info_par_get_mask(info, param) & (1 << value);
- case MINMAX:
- {
- unsigned int min, max;
- snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
- return value >= min && value <= max;
- }
- default:
- assert(0);
- return 0;
- }
-}
-
-int snd_pcm_hw_info_par_nearest_next(const snd_pcm_hw_info_t *info,
- unsigned int param,
- unsigned int best, int value,
- snd_pcm_t *pcm)
-{
- unsigned int min, max;
- unsigned int max1, min2;
- snd_pcm_hw_info_t i1, i2;
- int err1 = -EINVAL;
- int err2 = -EINVAL;
-
- snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
- i1 = *info;
- i2 = *info;
- if (value < 0) {
- max1 = best;
- min2 = best + 1;
- } else {
- int diff = value - best;
- if (diff < 0) {
- if (value > 1)
- max1 = value - 1;
- else
- max1 = 0;
- min2 = best - diff;
- } else {
- if (best > (unsigned int) diff)
- max1 = best - diff - 1;
- else
- max1 = 0;
- min2 = value + 1;
- }
- }
- max1 = snd_pcm_hw_info_par_refine_max(&i1, param, max1);
- min2 = snd_pcm_hw_info_par_refine_min(&i2, param, min2);
- if (min <= max1) {
- err1 = snd_pcm_hw_info(pcm, &i1);
- if (err1 >= 0)
- max1 = snd_pcm_hw_info_par_refine_max(&i1, param, max1);
- }
- if (min2 <= max && (err1 < 0 || best - max1 > min2 - best)) {
- err2 = snd_pcm_hw_info(pcm, &i2);
- if (err2 >= 0)
- min2 = snd_pcm_hw_info_par_refine_min(&i2, param, min2);
- }
- if (err1 < 0) {
- if (err2 < 0)
- return -1;
- return min2;
- } else if (err2 < 0)
- return max1;
- if (best - max1 <= min2 - best)
- return max1;
- return min2;
-}
-
-void snd_pcm_hw_info_par_dump(snd_pcm_hw_info_t *info, unsigned int param, FILE *fp)
-{
- par_desc_t *p;
- assert(param <= SND_PCM_HW_INFO_LAST);
- p = &hw_infos[param];
- switch (p->type) {
- case MASK:
- {
- unsigned int mask = snd_pcm_hw_info_par_get_mask(info, param);
- if (mask == ~0U)
- fputs(" ALL", fp);
- else if (mask) {
- unsigned int k;
- for (k = 0; k <= p->last; ++k)
- if (mask & (1U << k)) {
- putc(' ', fp);
- fputs(p->names[k], fp);
- }
- } else
- fputs(" NONE", fp);
- break;
- }
- case MINMAX:
- {
- unsigned int min, max;
- snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
- if (min == max)
- printf("%u", min);
- else
- printf("%u - %u", min, max);
- break;
- }
- default:
- assert(0);
- break;
- }
-}
-
-int snd_pcm_hw_info_par_empty(snd_pcm_hw_info_t *info, unsigned int param)
-{
- par_desc_t *p;
- assert(param <= SND_PCM_HW_INFO_LAST);
- p = &hw_infos[param];
- switch (p->type) {
- case MASK:
- return !snd_pcm_hw_info_par_get_mask(info, param);
- case MINMAX:
- {
- unsigned int min, max;
- snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
- return min > max;
- }
- default:
- assert(0);
- return 0;;
- }
-}
-
-unsigned int snd_pcm_hw_info_fail_mask(snd_pcm_hw_info_t *info)
-{
- unsigned int k, mask = 0;
- for (k = 0; k <= SND_PCM_HW_INFO_LAST; ++k) {
- if (snd_pcm_hw_info_par_empty(info, k))
- mask |= 1 << k;
- }
- return mask;
-}
-
-int snd_pcm_hw_info_to_params(snd_pcm_t *pcm, snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params)
-{
- int err;
- err = snd_pcm_hw_info(pcm, info);
- if (err < 0) {
- params->fail_mask = snd_pcm_hw_info_fail_mask(info);
- return err;
- }
-
- assert(info->access_mask);
- if (info->access_mask & (info->access_mask - 1)) {
- info->access_mask = 1 << (ffs(info->access_mask) - 1);
- err = snd_pcm_hw_info(pcm, info);
- assert(err >= 0);
- }
- assert(info->format_mask);
- if (info->format_mask & (info->format_mask - 1)) {
- info->format_mask = 1 << (ffs(info->format_mask) - 1);
- err = snd_pcm_hw_info(pcm, info);
- assert(err >= 0);
- }
- assert(info->subformat_mask);
- if (info->subformat_mask & (info->subformat_mask - 1)) {
- info->subformat_mask = 1 << (ffs(info->subformat_mask) - 1);
- err = snd_pcm_hw_info(pcm, info);
- assert(err >= 0);
- }
- assert(info->channels_min <= info->channels_max);
- if (info->channels_min < info->channels_max) {
- info->channels_max = info->channels_min;
- err = snd_pcm_hw_info(pcm, info);
- assert(err >= 0);
- }
- assert(info->rate_min <= info->rate_max);
- if (info->rate_min < info->rate_max) {
- info->rate_max = info->rate_min;
- err = snd_pcm_hw_info(pcm, info);
- assert(err >= 0);
- }
- assert(info->fragment_length_min <= info->fragment_length_max);
- if (info->fragment_length_min < info->fragment_length_max) {
- info->fragment_length_max = info->fragment_length_min;
- err = snd_pcm_hw_info(pcm, info);
- assert(err >= 0);
- }
- assert(info->fragments_min <= info->fragments_max);
- if (info->fragments_min < info->fragments_max) {
- /* Defaults to maximum use of buffer */
- info->fragments_min = info->fragments_max;
- err = snd_pcm_hw_info(pcm, info);
- assert(err >= 0);
- }
- params->access = ffs(info->access_mask) - 1;
- params->format = ffs(info->format_mask) - 1;
- params->subformat = ffs(info->subformat_mask) - 1;
- params->channels = info->channels_min;
- params->rate = info->rate_min;
- params->fragment_size = muldiv_near(info->fragment_length_min, info->rate_min, 1000000);
- params->fragments = info->fragments_min;
- return 0;
-}
-
-int _snd_pcm_hw_params_info(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info)
-{
- int err;
- params->fail_mask = 0;
-
- if (pcm->mmap_channels) {
- err = snd_pcm_munmap(pcm);
- if (err < 0)
- return err;
- }
- err = pcm->ops->hw_params(pcm->op_arg, params);
- if (err < 0)
- goto _mmap;
-
- pcm->setup = 1;
- pcm->access = params->access;
- pcm->format = params->format;
- pcm->subformat = params->subformat;
- pcm->rate = params->rate;
- pcm->channels = params->channels;
- pcm->fragment_size = params->fragment_size;
- pcm->fragments = params->fragments;
- pcm->bits_per_sample = snd_pcm_format_physical_width(params->format);
- pcm->bits_per_frame = pcm->bits_per_sample * params->channels;
- pcm->buffer_size = params->fragment_size * params->fragments;
-
- pcm->info = info->info;
- pcm->msbits = info->msbits;
- pcm->rate_num = info->rate_num;
- pcm->rate_den = info->rate_den;
- pcm->fifo_size = info->fifo_size;
-
- /* Default sw params */
- pcm->start_mode = SND_PCM_START_DATA;
- pcm->ready_mode = SND_PCM_READY_FRAGMENT;
- pcm->xrun_mode = SND_PCM_XRUN_FRAGMENT;
- pcm->avail_min = pcm->fragment_size;
- pcm->xfer_min = pcm->fragment_size;
- pcm->xfer_align = pcm->fragment_size;
- pcm->time = 0;
- pcm->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
-
- _mmap:
- if (pcm->setup &&
- (pcm->mmap_rw ||
- (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
- pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
- pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX))) {
- int err;
- err = snd_pcm_mmap(pcm);
- if (err < 0)
- return err;
- }
- return err;
-}
-
-int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
-{
- snd_pcm_hw_info_t info;
- int err;
- assert(pcm && params);
- snd_pcm_hw_params_to_info(params, &info);
- err = snd_pcm_hw_info(pcm, &info);
- if (err < 0) {
- params->fail_mask = snd_pcm_hw_info_fail_mask(&info);
- return err;
- }
- return _snd_pcm_hw_params_info(pcm, params, &info);
-}
-
-int snd_pcm_hw_params_info(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
- snd_pcm_hw_info_t *info)
-{
- int err = snd_pcm_hw_info_to_params(pcm, info, params);
- if (err < 0)
- return err;
- return _snd_pcm_hw_params_info(pcm, params, info);
-}
-
-
-int snd_pcm_hw_info_strategy1(snd_pcm_t *pcm, snd_pcm_hw_info_t *info,
- const snd_pcm_strategy_t *strategy,
- unsigned int badness_min, unsigned int badness_max)
-{
- snd_pcm_hw_info_t best_info;
- int param;
- int value;
- unsigned int best_badness;
- unsigned int mask = ~0;
- int badness = strategy->min_badness(info, badness_max, pcm, strategy);
- snd_pcm_hw_info_t info1;
-#if 0
- printf("\nBadness: %d\n", badness);
- snd_pcm_dump_hw_info(info, stdout);
-#endif
- if (badness < 0)
- return badness;
- if ((unsigned int)badness > badness_min)
- badness_min = badness_min;
- param = strategy->choose_param(info, pcm, strategy);
- if (param < 0)
- return badness;
- best_badness = UINT_MAX;
- value = -1;
- while (1) {
- int err;
- value = strategy->next_value(info, param, value, pcm, strategy);
- if (value < 0)
- break;
- info1 = *info;
- snd_pcm_hw_info_par_set_minmax(&info1, param, value, value);
- err = snd_pcm_hw_info(pcm, &info1);
- if (err >= 0) {
- badness = snd_pcm_hw_info_strategy1(pcm, &info1, strategy, badness_min, badness_max);
- if (badness >= 0) {
-
- if ((unsigned int) badness <= badness_min) {
- *info = info1;
- return badness;
- }
- best_badness = badness;
- best_info = info1;
- badness_max = badness - 1;
- continue;
- }
- if (badness != -EINVAL)
- continue;
- }
- mask &= snd_pcm_hw_info_fail_mask(&info1);
- }
- if (best_badness == UINT_MAX) {
- for (param = 0; param <= SND_PCM_HW_INFO_LAST; param++) {
- if (!(mask & (1 << param)))
- continue;
- snd_pcm_hw_info_par_copy(info, param, &info1);
- }
- return -EINVAL;
- }
- *info = best_info;
- return best_badness;
-}
-
-int snd_pcm_hw_info_strategy(snd_pcm_t *pcm, snd_pcm_hw_info_t *info,
- const snd_pcm_strategy_t *strategy)
-{
- int err;
- err = snd_pcm_hw_info(pcm, info);
- if (err < 0)
- return err;
- return snd_pcm_hw_info_strategy1(pcm, info, strategy,
- strategy->badness_min,
- strategy->badness_max);
-}
-
-
-void snd_pcm_strategy_simple_free(snd_pcm_strategy_t *strategy)
-{
- snd_pcm_strategy_simple_t *pars = strategy->private;
- int k;
- for (k = 0; k <= SND_PCM_HW_INFO_LAST; ++k) {
- if (pars[k].valid && pars[k].free)
- pars[k].free(&pars[k]);
- }
- free(pars);
-}
-
-int snd_pcm_strategy_simple_choose_param(const snd_pcm_hw_info_t *info,
- snd_pcm_t *pcm ATTRIBUTE_UNUSED,
- const snd_pcm_strategy_t *strategy)
-{
- unsigned int param;
- int best_param = -1;
- const snd_pcm_strategy_simple_t *pars = strategy->private;
- unsigned int min_choices = UINT_MAX;
- unsigned int min_order = UINT_MAX;
- for (param = 0; param <= SND_PCM_HW_INFO_LAST; ++param) {
- const snd_pcm_strategy_simple_t *p = &pars[param];
- unsigned int choices;
- if (!p->valid)
- continue;
- choices = snd_pcm_hw_info_par_choices(info, param);
- if (choices == 1)
- continue;
- assert(choices != 0);
- if (p->order < min_order ||
- (p->order == min_order &&
- choices < min_choices)) {
- min_order = p->order;
- min_choices = choices;
- best_param = param;
- }
- }
- return best_param;
-}
-
-int snd_pcm_strategy_simple_next_value(const snd_pcm_hw_info_t *info,
- unsigned int param,
- int value,
- snd_pcm_t *pcm,
- const snd_pcm_strategy_t *strategy)
-{
- const snd_pcm_strategy_simple_t *pars = strategy->private;
- assert(pars[param].valid);
- return pars[param].next_value(info, param, value, pcm, &pars[param]);
-}
-
-
-int snd_pcm_strategy_simple_min_badness(const snd_pcm_hw_info_t *info,
- unsigned int max_badness,
- snd_pcm_t *pcm,
- const snd_pcm_strategy_t *strategy)
-{
- unsigned int param;
- unsigned int badness = 0;
- const snd_pcm_strategy_simple_t *pars = strategy->private;
- for (param = 0; param <= SND_PCM_HW_INFO_LAST; ++param) {
- unsigned int b;
- if (!pars[param].valid)
- continue;
- b = pars[param].min_badness(info, param, pcm, &pars[param]);
- if (b > max_badness || max_badness - b < badness)
- return -E2BIG;
- badness += b;
- }
- return badness;
-}
-
-
-void snd_pcm_strategy_simple_near_free(snd_pcm_strategy_simple_t *par)
-{
- snd_pcm_strategy_simple_near_t *p = par->private;
- free(p);
-}
-
-unsigned int snd_pcm_strategy_simple_near_min_badness(const snd_pcm_hw_info_t *info,
- unsigned int param,
- snd_pcm_t *pcm,
- const snd_pcm_strategy_simple_t *par)
-{
- const snd_pcm_strategy_simple_near_t *p = par->private;
- int value = snd_pcm_hw_info_par_nearest_next(info, param, p->best, -1, pcm);
- int diff;
- assert(value >= 0);
- diff = p->best - value;
- if (diff < 0)
- diff = -diff;
- return diff * p->mul;
-}
-
-int snd_pcm_strategy_simple_near_next_value(const snd_pcm_hw_info_t *info,
- unsigned int param,
- int value,
- snd_pcm_t *pcm,
- const snd_pcm_strategy_simple_t *par)
-{
- const snd_pcm_strategy_simple_near_t *p = par->private;
- return snd_pcm_hw_info_par_nearest_next(info, param, p->best, value, pcm);
-}
-
-void snd_pcm_strategy_simple_choices_free(snd_pcm_strategy_simple_t *par)
-{
- snd_pcm_strategy_simple_choices_t *p = par->private;
-// free(p->choices);
- free(p);
-}
-
-unsigned int snd_pcm_strategy_simple_choices_min_badness(const snd_pcm_hw_info_t *info,
- unsigned int param,
- snd_pcm_t *pcm ATTRIBUTE_UNUSED,
- const snd_pcm_strategy_simple_t *par)
-{
- const snd_pcm_strategy_simple_choices_t *p = par->private;
- unsigned int k;
- for (k = 0; k < p->count; ++k) {
- if (snd_pcm_hw_info_par_check(info, param, p->choices[k].value))
- return p->choices[k].badness;
- }
- assert(0);
- return UINT_MAX;
-}
-
-int snd_pcm_strategy_simple_choices_next_value(const snd_pcm_hw_info_t *info,
- unsigned int param,
- int value,
- snd_pcm_t *pcm ATTRIBUTE_UNUSED,
- const snd_pcm_strategy_simple_t *par)
-{
- const snd_pcm_strategy_simple_choices_t *p = par->private;
- unsigned int k = 0;
- if (value >= 0) {
- for (; k < p->count; ++k) {
- if (p->choices[k].value == (unsigned int) value) {
- k++;
- break;
- }
- }
- }
- for (; k < p->count; ++k) {
- unsigned int v = p->choices[k].value;
- if (snd_pcm_hw_info_par_check(info, param, v))
- return v;
- }
- return -1;
-}
-
-int snd_pcm_strategy_free(snd_pcm_strategy_t *strategy)
-{
- if (strategy->free)
- strategy->free(strategy);
- free(strategy);
- return 0;
-}
-
-int snd_pcm_strategy_simple(snd_pcm_strategy_t **strategyp,
- unsigned int badness_min,
- unsigned int badness_max)
-{
- snd_pcm_strategy_simple_t *data;
- snd_pcm_strategy_t *s;
- assert(strategyp);
- data = calloc(SND_PCM_HW_INFO_LAST + 1, sizeof(*data));
- if (!data)
- return -ENOMEM;
- s = calloc(1, sizeof(*s));
- if (!s) {
- free(data);
- return -ENOMEM;
- }
- s->choose_param = snd_pcm_strategy_simple_choose_param;
- s->next_value = snd_pcm_strategy_simple_next_value;
- s->min_badness = snd_pcm_strategy_simple_min_badness;
- s->badness_min = badness_min;
- s->badness_max = badness_max;
- s->private = data;
- s->free = snd_pcm_strategy_simple_free;
- *strategyp = s;
- return 0;
-}
-
-int snd_pcm_strategy_simple_near(snd_pcm_strategy_t *strategy,
- int order,
- unsigned int param,
- unsigned int best,
- unsigned int mul)
-{
- snd_pcm_strategy_simple_t *s = strategy->private;
- snd_pcm_strategy_simple_near_t *data;
- assert(strategy);
- assert(param <= SND_PCM_HW_INFO_LAST);
- assert(!s->valid);
- data = calloc(1, sizeof(*data));
- if (!data)
- return -ENOMEM;
- data->best = best;
- data->mul = mul;
- s += param;
- s->order = order;
- s->valid = 1;
- s->next_value = snd_pcm_strategy_simple_near_next_value;
- s->min_badness = snd_pcm_strategy_simple_near_min_badness;
- s->private = data;
- s->free = snd_pcm_strategy_simple_near_free;
- return 0;
-}
-
-int snd_pcm_strategy_simple_choices(snd_pcm_strategy_t *strategy,
- int order,
- unsigned int param,
- unsigned int count,
- snd_pcm_strategy_simple_choices_list_t *choices)
-{
- snd_pcm_strategy_simple_t *s = strategy->private;
- snd_pcm_strategy_simple_choices_t *data;
- assert(strategy);
- assert(param <= SND_PCM_HW_INFO_LAST);
- assert(!s->valid);
- data = calloc(1, sizeof(*data));
- if (!data)
- return -ENOMEM;
- data->count = count;
- data->choices = choices;
- s += param;
- s->valid = 1;
- s->order = order;
- s->next_value = snd_pcm_strategy_simple_choices_next_value;
- s->min_badness = snd_pcm_strategy_simple_choices_min_badness;
- s->private = data;
- s->free = snd_pcm_strategy_simple_choices_free;
- return 0;
-}
-
-int snd_pcm_dump_hw_info(snd_pcm_hw_info_t *info, FILE *fp)
-{
- unsigned int param;
- for (param = 0; param <= SND_PCM_HW_INFO_LAST; param++) {
- fprintf(fp, "%s: ", snd_pcm_hw_info_names[param]);
- snd_pcm_hw_info_par_dump(info, param, fp);
- putc('\n', fp);
- }
- return 0;
-}
-
-int snd_pcm_hw_info_try_explain_failure1(snd_pcm_t *pcm,
- snd_pcm_hw_info_t *fail,
- snd_pcm_hw_info_t *success,
- unsigned int depth,
- FILE *fp)
-{
- unsigned int param;
- snd_pcm_hw_info_t i;
- if (depth < 1)
- return -ENOENT;
- for (param = 0; param <= SND_PCM_HW_INFO_LAST; param++) {
- int err;
- i = *success;
- snd_pcm_hw_info_par_copy(&i, param, fail);
- err = snd_pcm_hw_info(pcm, &i);
- if (err == 0 &&
- snd_pcm_hw_info_try_explain_failure1(pcm, fail, &i, depth - 1, fp) < 0)
- continue;
- fprintf(fp, "%s: ", snd_pcm_hw_info_names[param]);
- snd_pcm_hw_info_par_dump(fail, param, fp);
- putc('\n', fp);
- return 0;
- }
- return -ENOENT;
-}
-
-int snd_pcm_hw_info_try_explain_failure(snd_pcm_t *pcm,
- snd_pcm_hw_info_t *fail,
- snd_pcm_hw_info_t *success,
- unsigned int depth,
- FILE *fp)
-{
- snd_pcm_hw_info_t i, any;
- int err;
- unsigned int fail_mask;
- assert(pcm && fail);
- fail_mask = snd_pcm_hw_info_fail_mask(fail);
- if (fail_mask) {
- unsigned int param;
- for (param = 0; param <= SND_PCM_HW_INFO_LAST; param++) {
- if (!(fail_mask & (1 << param)))
- continue;
- fprintf(fp, "%s: ", snd_pcm_hw_info_names[param]);
- snd_pcm_hw_info_par_dump(fail, param, fp);
- putc('\n', fp);
- }
- return 0;
- }
- i = *fail;
- err = snd_pcm_hw_info(pcm, &i);
- if (err == 0) {
- fprintf(fp, "Too low max badness or configuration temporarily unavailable\n");
- return 0;
- }
- if (!success) {
- snd_pcm_hw_info_any(&any);
- success = &any;
- }
- return snd_pcm_hw_info_try_explain_failure1(pcm, fail, success, depth, fp);
-}
-
size_t _snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm)
{
return *pcm->hw_ptr;
return 0;
}
-static int snd_pcm_adpcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_adpcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_adpcm_t *adpcm = pcm->private;
- unsigned int format_mask, access_mask;
+ snd_pcm_t *slave = adpcm->plug.slave;
int err;
- info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
- SND_PCM_ACCBIT_RW_INTERLEAVED |
- SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
- SND_PCM_ACCBIT_RW_NONINTERLEAVED);
- access_mask = info->access_mask;
- if (access_mask == 0)
- return -EINVAL;
- if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM)
- info->format_mask &= SND_PCM_FMTBIT_LINEAR;
- else
- info->format_mask &= SND_PCM_FMTBIT_IMA_ADPCM;
- format_mask = info->format_mask;
- if (format_mask == 0)
- return -EINVAL;
+ snd_pcm_hw_params_t sparams;
+ mask_t *access_mask = alloca(mask_sizeof());
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+ access_mask);
+ if (err < 0)
+ return err;
+ if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
+ mask_t *format_mask = alloca(mask_sizeof());
+ mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+ err = _snd_pcm_hw_params_mask(params, 1,
+ SND_PCM_HW_PARAM_FORMAT,
+ format_mask);
+ if (err < 0)
+ return err;
+ } else {
+ err = _snd_pcm_hw_params_set(params, 1,
+ SND_PCM_HW_PARAM_FORMAT,
+ SND_PCM_FORMAT_IMA_ADPCM);
+ if (err < 0)
+ return err;
+ }
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ if (err < 0)
+ return err;
- info->format_mask = 1U << adpcm->sformat;
- info->access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_info(adpcm->plug.slave, info);
- info->format_mask = format_mask;
- info->access_mask = access_mask;
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ adpcm->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ err = snd_pcm_hw_refine2(params, &sparams,
+ snd_pcm_hw_refine, slave,
+ SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
if (err < 0)
return err;
- info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
- snd_pcm_hw_info_complete(info);
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
{
snd_pcm_adpcm_t *adpcm = pcm->private;
snd_pcm_t *slave = adpcm->plug.slave;
- snd_pcm_hw_info_t sinfo;
- snd_pcm_hw_params_t sparams;
int err;
- snd_pcm_hw_params_to_info(params, &sinfo);
- sinfo.format_mask = 1 << adpcm->sformat;
- sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
- params->fail_mask = sparams.fail_mask;
+ snd_pcm_hw_params_t sparams;
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ adpcm->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ err = snd_pcm_hw_params2(params, &sparams,
+ snd_pcm_hw_params, slave,
+ SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
if (err < 0)
return err;
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
- adpcm->getput_idx = get_index(params->format, SND_PCM_FORMAT_S16);
+ adpcm->getput_idx = get_index(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT), SND_PCM_FORMAT_S16);
adpcm->func = adpcm_encode;
} else {
adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, adpcm->sformat);
}
} else {
if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
- adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, params->format);
+ adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT));
adpcm->func = adpcm_decode;
} else {
adpcm->getput_idx = get_index(adpcm->sformat, SND_PCM_FORMAT_S16);
}
if (adpcm->states)
free(adpcm->states);
- adpcm->states = malloc(params->channels * sizeof(*adpcm->states));
+ adpcm->states = malloc(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_CHANNELS) * sizeof(*adpcm->states));
return 0;
}
snd_pcm_ops_t snd_pcm_adpcm_ops = {
close: snd_pcm_adpcm_close,
info: snd_pcm_plugin_info,
- hw_info: snd_pcm_adpcm_hw_info,
+ hw_refine: snd_pcm_adpcm_hw_refine,
hw_params: snd_pcm_adpcm_hw_params,
sw_params: snd_pcm_plugin_sw_params,
dig_info: snd_pcm_plugin_dig_info,
}
}
-static int snd_pcm_alaw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_alaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_alaw_t *alaw = pcm->private;
- unsigned int format_mask, access_mask;
+ snd_pcm_t *slave = alaw->plug.slave;
int err;
- info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
- SND_PCM_ACCBIT_RW_INTERLEAVED |
- SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
- SND_PCM_ACCBIT_RW_NONINTERLEAVED);
- access_mask = info->access_mask;
- if (access_mask == 0)
- return -EINVAL;
- if (alaw->sformat == SND_PCM_FORMAT_MU_LAW)
- info->format_mask &= SND_PCM_FMTBIT_LINEAR;
- else
- info->format_mask &= SND_PCM_FMTBIT_MU_LAW;
- format_mask = info->format_mask;
- if (format_mask == 0)
- return -EINVAL;
+ snd_pcm_hw_params_t sparams;
+ mask_t *access_mask = alloca(mask_sizeof());
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+ access_mask);
+ if (err < 0)
+ return err;
+ if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
+ mask_t *format_mask = alloca(mask_sizeof());
+ mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+ err = _snd_pcm_hw_params_mask(params, 1,
+ SND_PCM_HW_PARAM_FORMAT,
+ format_mask);
+ if (err < 0)
+ return err;
+ } else {
+ err = _snd_pcm_hw_params_set(params, 1,
+ SND_PCM_HW_PARAM_FORMAT,
+ SND_PCM_FORMAT_A_LAW);
+ if (err < 0)
+ return err;
+ }
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ if (err < 0)
+ return err;
- info->format_mask = 1U << alaw->sformat;
- info->access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_info(alaw->plug.slave, info);
- info->format_mask = format_mask;
- info->access_mask = access_mask;
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ alaw->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ err = snd_pcm_hw_refine2(params, &sparams,
+ snd_pcm_hw_refine, slave,
+ SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
if (err < 0)
return err;
- info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
- snd_pcm_hw_info_complete(info);
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
{
snd_pcm_alaw_t *alaw = pcm->private;
snd_pcm_t *slave = alaw->plug.slave;
- snd_pcm_hw_info_t sinfo;
- snd_pcm_hw_params_t sparams;
int err;
- snd_pcm_hw_params_to_info(params, &sinfo);
- sinfo.format_mask = 1 << alaw->sformat;
- sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
- params->fail_mask = sparams.fail_mask;
+ snd_pcm_hw_params_t sparams;
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ alaw->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ err = snd_pcm_hw_params2(params, &sparams,
+ snd_pcm_hw_params, slave,
+ SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
if (err < 0)
return err;
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
- if (alaw->sformat == SND_PCM_FORMAT_MU_LAW) {
- alaw->getput_idx = get_index(params->format, SND_PCM_FORMAT_S16);
+ if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
+ alaw->getput_idx = get_index(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT), SND_PCM_FORMAT_S16);
alaw->func = alaw_encode;
} else {
alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, alaw->sformat);
alaw->func = alaw_decode;
}
} else {
- if (alaw->sformat == SND_PCM_FORMAT_MU_LAW) {
- alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, params->format);
+ if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
+ alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT));
alaw->func = alaw_decode;
} else {
alaw->getput_idx = get_index(alaw->sformat, SND_PCM_FORMAT_S16);
snd_pcm_ops_t snd_pcm_alaw_ops = {
close: snd_pcm_plugin_close,
info: snd_pcm_plugin_info,
- hw_info: snd_pcm_alaw_hw_info,
+ hw_refine: snd_pcm_alaw_hw_refine,
hw_params: snd_pcm_alaw_hw_params,
sw_params: snd_pcm_plugin_sw_params,
dig_info: snd_pcm_plugin_dig_info,
snd_pcm_plugin_t plug;
} snd_pcm_copy_t;
-static int snd_pcm_copy_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_copy_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_copy_t *copy = pcm->private;
- unsigned int access_mask;
+ snd_pcm_t *slave = copy->plug.slave;
int err;
- info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
- SND_PCM_ACCBIT_RW_INTERLEAVED |
- SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
- SND_PCM_ACCBIT_RW_NONINTERLEAVED);
- access_mask = info->access_mask;
- if (access_mask == 0)
- return -EINVAL;
-
- info->access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_info(copy->plug.slave, info);
- info->access_mask = access_mask;
+ snd_pcm_hw_params_t sparams;
+ mask_t *access_mask = alloca(mask_sizeof());
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+ access_mask);
if (err < 0)
return err;
- info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
- snd_pcm_hw_info_complete(info);
- return 0;
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ err = snd_pcm_hw_refine2(params, &sparams,
+ snd_pcm_hw_refine, slave,
+ ~SND_PCM_HW_PARBIT_ACCESS);
+ if (err < 0)
+ return err;
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ return err;
}
static int snd_pcm_copy_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_copy_t *copy = pcm->private;
snd_pcm_t *slave = copy->plug.slave;
- snd_pcm_hw_info_t sinfo;
- snd_pcm_hw_params_t sparams;
int err;
- snd_pcm_hw_params_to_info(params, &sinfo);
- sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
- params->fail_mask = sparams.fail_mask;
+ snd_pcm_hw_params_t sparams;
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ err = snd_pcm_hw_params2(params, &sparams,
+ snd_pcm_hw_params, slave,
+ ~SND_PCM_HW_PARBIT_ACCESS);
+ if (err < 0)
+ return err;
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return err;
}
snd_pcm_ops_t snd_pcm_copy_ops = {
close: snd_pcm_plugin_close,
info: snd_pcm_plugin_info,
- hw_info: snd_pcm_copy_hw_info,
+ hw_refine: snd_pcm_copy_hw_refine,
hw_params: snd_pcm_copy_hw_params,
sw_params: snd_pcm_plugin_sw_params,
dig_info: snd_pcm_plugin_dig_info,
return snd_pcm_set_avail_min(file->slave, frames);
}
-static int snd_pcm_file_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_file_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_file_t *file = pcm->private;
- return snd_pcm_hw_info(file->slave, info);
+ return snd_pcm_hw_refine(file->slave, params);
}
static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
snd_pcm_ops_t snd_pcm_file_ops = {
close: snd_pcm_file_close,
info: snd_pcm_file_info,
- hw_info: snd_pcm_file_hw_info,
+ hw_refine: snd_pcm_file_hw_refine,
hw_params: snd_pcm_file_hw_params,
sw_params: snd_pcm_file_sw_params,
dig_info: snd_pcm_file_dig_info,
return 0;
}
-static int _snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
+static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
return 0;
}
-static int snd_pcm_hw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- if (ioctl(fd, SND_PCM_IOCTL_HW_INFO, info) < 0) {
- // SYSERR("SND_PCM_IOCTL_HW_INFO failed");
+ if (ioctl(fd, SND_PCM_IOCTL_HW_REFINE, params) < 0) {
+ // SYSERR("SND_PCM_IOCTL_HW_REFINE failed");
return -errno;
}
return 0;
snd_pcm_ops_t snd_pcm_hw_ops = {
close: snd_pcm_hw_close,
- info: _snd_pcm_hw_info,
- hw_info: snd_pcm_hw_hw_info,
+ info: snd_pcm_hw_info,
+ hw_refine: snd_pcm_hw_hw_refine,
hw_params: snd_pcm_hw_hw_params,
sw_params: snd_pcm_hw_sw_params,
dig_info: snd_pcm_hw_dig_info,
}
}
-static int snd_pcm_linear_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_linear_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_linear_t *linear = pcm->private;
- unsigned int format_mask, access_mask;
+ snd_pcm_t *slave = linear->plug.slave;
int err;
- info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
- SND_PCM_ACCBIT_RW_INTERLEAVED |
- SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
- SND_PCM_ACCBIT_RW_NONINTERLEAVED);
- access_mask = info->access_mask;
- if (access_mask == 0)
- return -EINVAL;
- info->format_mask &= SND_PCM_FMTBIT_LINEAR;
- format_mask = info->format_mask;
- if (format_mask == 0)
- return -EINVAL;
+ snd_pcm_hw_params_t sparams;
+ mask_t *access_mask = alloca(mask_sizeof());
+ mask_t *format_mask = alloca(mask_sizeof());
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+ mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+ access_mask);
+ if (err < 0)
+ return err;
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_FORMAT,
+ format_mask);
+ if (err < 0)
+ return err;
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ if (err < 0)
+ return err;
- info->format_mask = 1U << linear->sformat;
- info->access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_info(linear->plug.slave, info);
- info->format_mask = format_mask;
- info->access_mask = access_mask;
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ linear->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ err = snd_pcm_hw_refine2(params, &sparams,
+ snd_pcm_hw_refine, slave,
+ SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
if (err < 0)
return err;
- info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
- snd_pcm_hw_info_complete(info);
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
{
snd_pcm_linear_t *linear = pcm->private;
snd_pcm_t *slave = linear->plug.slave;
- snd_pcm_hw_info_t sinfo;
- snd_pcm_hw_params_t sparams;
int err;
- snd_pcm_hw_params_to_info(params, &sinfo);
- sinfo.format_mask = 1 << linear->sformat;
- sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
- params->fail_mask = sparams.fail_mask;
+ snd_pcm_hw_params_t sparams;
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ linear->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ err = snd_pcm_hw_params2(params, &sparams,
+ snd_pcm_hw_params, slave,
+ SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
if (err < 0)
return err;
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
- linear->conv_idx = conv_index(params->format,
+ linear->conv_idx = conv_index(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT),
linear->sformat);
else
linear->conv_idx = conv_index(linear->sformat,
- params->format);
+ snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT));
return 0;
}
snd_pcm_ops_t snd_pcm_linear_ops = {
close: snd_pcm_plugin_close,
info: snd_pcm_plugin_info,
- hw_info: snd_pcm_linear_hw_info,
+ hw_refine: snd_pcm_linear_hw_refine,
hw_params: snd_pcm_linear_hw_params,
sw_params: snd_pcm_plugin_sw_params,
dig_info: snd_pcm_plugin_dig_info,
/*
* PCM Interface - local header file
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz>
+ * Abramo Bagnara <abramo@alsa-project.org>
*
*
* This library is free software; you can redistribute it and/or modify
int (*nonblock)(snd_pcm_t *pcm, int nonblock);
int (*async)(snd_pcm_t *pcm, int sig, pid_t pid);
int (*info)(snd_pcm_t *pcm, snd_pcm_info_t *info);
- int (*hw_info)(snd_pcm_t *pcm, snd_pcm_hw_info_t *info);
+ int (*hw_refine)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int (*hw_params)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int (*sw_params)(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
int (*dig_info)(snd_pcm_t *pcm, snd_pcm_dig_info_t *info);
snd_pcm_xfer_areas_func_t func);
ssize_t snd_pcm_read_mmap(snd_pcm_t *pcm, size_t size);
ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size);
-int snd_pcm_hw_info_complete(snd_pcm_hw_info_t *info);
-void snd_pcm_hw_params_to_info(snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info);
-int snd_pcm_hw_info_to_params(snd_pcm_t *pcm, snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params);
+int snd_pcm_hw_info_complete(snd_pcm_hw_params_t *info);
int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info, int shmid);
-int snd_pcm_hw_info_par_nearest_next(const snd_pcm_hw_info_t *info,
- unsigned int param,
- unsigned int best, int value,
- snd_pcm_t *pcm);
static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
{
n++;
return n;
}
+
+int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params);
+void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params);
+int _snd_pcm_hw_params_mask(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var, const mask_t *mask);
+int _snd_pcm_hw_params_first(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var);
+int _snd_pcm_hw_params_last(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var);
+int _snd_pcm_hw_params_set(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var, unsigned int val);
+int _snd_pcm_hw_params_min(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var, unsigned int val);
+int _snd_pcm_hw_params_max(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var, unsigned int val);
+int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_params_t *sparams,
+ int (*func)(snd_pcm_t *slave,
+ snd_pcm_hw_params_t *params),
+ snd_pcm_t *slave,
+ unsigned int links);
+int snd_pcm_hw_params2(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_params_t *sparams,
+ int (*func)(snd_pcm_t *slave,
+ snd_pcm_hw_params_t *sparams),
+ snd_pcm_t *slave,
+ unsigned int links);
+
+#define SND_PCM_HW_PARBIT_ACCESS (1 << SND_PCM_HW_PARAM_ACCESS)
+#define SND_PCM_HW_PARBIT_FORMAT (1 << SND_PCM_HW_PARAM_FORMAT)
+#define SND_PCM_HW_PARBIT_SUBFORMAT (1 << SND_PCM_HW_PARAM_SUBFORMAT)
+#define SND_PCM_HW_PARBIT_CHANNELS (1 << SND_PCM_HW_PARAM_CHANNELS)
+#define SND_PCM_HW_PARBIT_RATE (1 << SND_PCM_HW_PARAM_RATE)
+#define SND_PCM_HW_PARBIT_FRAGMENT_LENGTH (1 << SND_PCM_HW_PARAM_FRAGMENT_LENGTH)
+#define SND_PCM_HW_PARBIT_FRAGMENT_SIZE (1 << SND_PCM_HW_PARAM_FRAGMENT_SIZE)
+#define SND_PCM_HW_PARBIT_FRAGMENTS (1 << SND_PCM_HW_PARAM_FRAGMENTS)
+#define SND_PCM_HW_PARBIT_BUFFER_LENGTH (1 << SND_PCM_HW_PARAM_BUFFER_LENGTH)
+#define SND_PCM_HW_PARBIT_BUFFER_SIZE (1 << SND_PCM_HW_PARAM_BUFFER_SIZE)
+#define SND_PCM_HW_PARBIT_SAMPLE_BITS (1 << SND_PCM_HW_PARAM_SAMPLE_BITS)
+#define SND_PCM_HW_PARBIT_FRAME_BITS (1 << SND_PCM_HW_PARAM_FRAME_BITS)
+#define SND_PCM_HW_PARBIT_FRAGMENT_BYTES (1 << SND_PCM_HW_PARAM_FRAGMENT_BYTES)
+#define SND_PCM_HW_PARBIT_BUFFER_BYTES (1 << SND_PCM_HW_PARAM_BUFFER_BYTES)
+
+
+#define SND_PCM_ACCBIT_MMAP ((1 << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
+ (1 << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
+ (1 << SND_PCM_ACCESS_MMAP_COMPLEX))
}
}
-static int snd_pcm_mulaw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_mulaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_mulaw_t *mulaw = pcm->private;
- unsigned int format_mask, access_mask;
+ snd_pcm_t *slave = mulaw->plug.slave;
int err;
- info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
- SND_PCM_ACCBIT_RW_INTERLEAVED |
- SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
- SND_PCM_ACCBIT_RW_NONINTERLEAVED);
- access_mask = info->access_mask;
- if (access_mask == 0)
- return -EINVAL;
- if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW)
- info->format_mask &= SND_PCM_FMTBIT_LINEAR;
- else
- info->format_mask &= SND_PCM_FMTBIT_MU_LAW;
- format_mask = info->format_mask;
- if (format_mask == 0)
- return -EINVAL;
+ snd_pcm_hw_params_t sparams;
+ mask_t *access_mask = alloca(mask_sizeof());
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+ access_mask);
+ if (err < 0)
+ return err;
+ if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
+ mask_t *format_mask = alloca(mask_sizeof());
+ mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+ err = _snd_pcm_hw_params_mask(params, 1,
+ SND_PCM_HW_PARAM_FORMAT,
+ format_mask);
+ if (err < 0)
+ return err;
+ } else {
+ err = _snd_pcm_hw_params_set(params, 1,
+ SND_PCM_HW_PARAM_FORMAT,
+ SND_PCM_FORMAT_MU_LAW);
+ if (err < 0)
+ return err;
+ }
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ if (err < 0)
+ return err;
- info->format_mask = 1U << mulaw->sformat;
- info->access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_info(mulaw->plug.slave, info);
- info->format_mask = format_mask;
- info->access_mask = access_mask;
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ mulaw->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ err = snd_pcm_hw_refine2(params, &sparams,
+ snd_pcm_hw_refine, slave,
+ SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
if (err < 0)
return err;
- info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
- snd_pcm_hw_info_complete(info);
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
{
snd_pcm_mulaw_t *mulaw = pcm->private;
snd_pcm_t *slave = mulaw->plug.slave;
- snd_pcm_hw_info_t sinfo;
- snd_pcm_hw_params_t sparams;
int err;
- snd_pcm_hw_params_to_info(params, &sinfo);
- sinfo.format_mask = 1 << mulaw->sformat;
- sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
- params->fail_mask = sparams.fail_mask;
+ snd_pcm_hw_params_t sparams;
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ mulaw->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ err = snd_pcm_hw_params2(params, &sparams,
+ snd_pcm_hw_params, slave,
+ SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
if (err < 0)
return err;
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
- mulaw->getput_idx = get_index(params->format, SND_PCM_FORMAT_S16);
+ mulaw->getput_idx = get_index(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT), SND_PCM_FORMAT_S16);
mulaw->func = mulaw_encode;
} else {
mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, mulaw->sformat);
}
} else {
if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
- mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, params->format);
+ mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT));
mulaw->func = mulaw_decode;
} else {
mulaw->getput_idx = get_index(mulaw->sformat, SND_PCM_FORMAT_S16);
snd_pcm_ops_t snd_pcm_mulaw_ops = {
close: snd_pcm_plugin_close,
info: snd_pcm_plugin_info,
- hw_info: snd_pcm_mulaw_hw_info,
+ hw_refine: snd_pcm_mulaw_hw_refine,
hw_params: snd_pcm_mulaw_hw_params,
sw_params: snd_pcm_plugin_sw_params,
dig_info: snd_pcm_plugin_dig_info,
#include <errno.h>
#include <math.h>
#include "pcm_local.h"
+#include "interval.h"
typedef struct {
snd_pcm_t *pcm;
return 0;
}
-static int snd_pcm_multi_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
+static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int k;
- snd_pcm_hw_info_t i;
- unsigned int access_mask, saccess_mask;
+ snd_pcm_hw_params_t sparams;
int changed = 0;
- int err = 0;
- if (info->channels_min < multi->channels_count)
- info->channels_min = multi->channels_count;
- if (info->channels_max > multi->channels_count)
- info->channels_max = multi->channels_count;
- if (info->channels_min > info->channels_max)
- return -EINVAL;
- i = *info;
- saccess_mask = ~0;
+ int err;
+ const mask_t *access_mask = snd_pcm_hw_params_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) ||
+ mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ else {
+ mask_none(saccess_mask);
+ if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
+ multi->slaves_count == 1)
+ mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+ if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
+ mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+ if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX)) {
+ mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
+ if (multi->slaves_count > 1)
+ mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+ }
+ }
+
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_CHANNELS,
+ multi->channels_count);
+ if (err < 0)
+ return err;
changed = 0;
do {
for (k = 0; k < multi->slaves_count; ++k) {
snd_pcm_t *slave = multi->slaves[k].pcm;
- snd_pcm_hw_info_t sinfo = i;
- sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
- sinfo.channels_min = sinfo.channels_max = multi->slaves[k].channels_count;
- err = snd_pcm_hw_info(slave, &sinfo);
- if (err < 0) {
- sinfo.access_mask = info->access_mask;
- sinfo.channels_min = multi->channels_count;
- sinfo.channels_max = multi->channels_count;
- *info = sinfo;
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0,
+ SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0,
+ SND_PCM_HW_PARAM_CHANNELS,
+ multi->slaves[k].channels_count);
+ err = snd_pcm_hw_refine2(params, &sparams,
+ snd_pcm_hw_refine, slave,
+ SND_PCM_HW_PARBIT_FORMAT |
+ SND_PCM_HW_PARBIT_SUBFORMAT |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH |
+ SND_PCM_HW_PARBIT_FRAGMENTS);
+ if (err < 0)
return err;
- }
- if (i.format_mask != sinfo.format_mask ||
- i.subformat_mask != sinfo.subformat_mask ||
- i.rate_min != sinfo.rate_min ||
- i.rate_max != sinfo.rate_max ||
- i.fragment_length_min != sinfo.fragment_length_min ||
- i.fragment_length_max != sinfo.fragment_length_max ||
- i.fragments_min != sinfo.fragments_min ||
- i.fragments_max != sinfo.fragments_max ||
- i.buffer_length_min != sinfo.buffer_length_min ||
- i.buffer_length_max != sinfo.buffer_length_max)
+ if (params->hw_cmask)
changed++;
- saccess_mask &= sinfo.access_mask;
- i = sinfo;
}
} while (changed && multi->slaves_count > 1);
- access_mask = info->access_mask;
- *info = i;
- info->access_mask = access_mask;
- if (!(saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED) ||
- multi->slaves_count > 1)
- info->access_mask &= ~SND_PCM_ACCBIT_MMAP_INTERLEAVED;
- if (!(saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED))
- info->access_mask &= ~SND_PCM_ACCBIT_MMAP_NONINTERLEAVED;
- if (!info->access_mask)
- return -EINVAL;
- info->channels_min = info->channels_max = multi->channels_count;
return 0;
}
static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_multi_t *multi = pcm->private;
- unsigned int i;
+ unsigned int k;
int err;
- for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *slave = multi->slaves[i].pcm;
- snd_pcm_hw_info_t sinfo;
+ const mask_t *access_mask = snd_pcm_hw_params_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) ||
+ mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ else {
+ mask_none(saccess_mask);
+ if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
+ multi->slaves_count == 1)
+ mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+ if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
+ mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+ if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX)) {
+ mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
+ if (multi->slaves_count > 1)
+ mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+ }
+ }
+ for (k = 0; k < multi->slaves_count; ++k) {
+ snd_pcm_t *slave = multi->slaves[k].pcm;
snd_pcm_hw_params_t sparams;
- snd_pcm_hw_params_to_info(params, &sinfo);
- sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
- sinfo.channels_min = sinfo.channels_max = multi->slaves[i].channels_count;
- err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
- if (err < 0) {
- params->fail_mask = sparams.fail_mask;
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_CHANNELS,
+ multi->slaves[k].channels_count);
+ err = snd_pcm_hw_params2(params, &sparams,
+ snd_pcm_hw_params, slave,
+ SND_PCM_HW_PARBIT_FORMAT |
+ SND_PCM_HW_PARBIT_SUBFORMAT |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH |
+ SND_PCM_HW_PARBIT_FRAGMENTS);
+ if (err < 0)
return err;
- }
err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
if (err < 0)
return err;
snd_pcm_ops_t snd_pcm_multi_ops = {
close: snd_pcm_multi_close,
info: snd_pcm_multi_info,
- hw_info: snd_pcm_multi_hw_info,
+ hw_refine: snd_pcm_multi_hw_refine,
hw_params: snd_pcm_multi_hw_params,
sw_params: snd_pcm_multi_sw_params,
dig_info: snd_pcm_multi_dig_info,
return 0;
}
-static int snd_pcm_null_hw_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_info_t * info)
+static int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
{
- snd_pcm_hw_info_complete(info);
- info->fifo_size = 0;
+ _snd_pcm_hw_refine(params);
+ params->fifo_size = 0;
+ params->dig_groups = 0;
return 0;
}
static int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params)
{
if (params->start_mode > SND_PCM_START_LAST) {
- params->fail_mask = SND_PCM_SW_PARBIT_START_MODE;
+ params->fail_mask = 1 << SND_PCM_SW_PARAM_START_MODE;
return -EINVAL;
}
if (params->ready_mode > SND_PCM_READY_LAST) {
- params->fail_mask = SND_PCM_SW_PARBIT_READY_MODE;
+ params->fail_mask = 1 << SND_PCM_SW_PARAM_READY_MODE;
return -EINVAL;
}
if (params->xrun_mode > SND_PCM_XRUN_LAST) {
- params->fail_mask = SND_PCM_SW_PARBIT_XRUN_MODE;
+ params->fail_mask = 1 << SND_PCM_SW_PARAM_XRUN_MODE;
return -EINVAL;
}
return 0;
snd_pcm_ops_t snd_pcm_null_ops = {
close: snd_pcm_null_close,
info: snd_pcm_null_info,
- hw_info: snd_pcm_null_hw_info,
+ hw_refine: snd_pcm_null_hw_refine,
hw_params: snd_pcm_null_hw_params,
sw_params: snd_pcm_null_sw_params,
dig_params: snd_pcm_null_dig_params,
--- /dev/null
+/*
+ * PCM - Params functions
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "pcm_local.h"
+#include "interval_inline.h"
+#include "interval.h"
+#include "mask.h"
+
+static inline unsigned int add(unsigned int a, unsigned int b)
+{
+ if (a >= UINT_MAX - b)
+ return UINT_MAX;
+ return a + b;
+}
+
+static inline unsigned int sub(unsigned int a, unsigned int b)
+{
+ if (a > b)
+ return a - b;
+ return 0;
+}
+
+static inline int is_mask(int var)
+{
+ return var >= SND_PCM_HW_PARAM_FIRST_MASK &&
+ var <= SND_PCM_HW_PARAM_LAST_MASK;
+}
+
+static inline int is_interval(int var)
+{
+ return var >= SND_PCM_HW_PARAM_FIRST_INTERVAL &&
+ var <= SND_PCM_HW_PARAM_LAST_INTERVAL;
+}
+
+static inline mask_t *params_mask(snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ assert(is_mask(var));
+ return (mask_t*)¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK];
+}
+
+static inline interval_t *params_interval(snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ assert(is_interval(var));
+ return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL];
+}
+
+static inline const mask_t *params_mask_c(const snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ return (const mask_t *)params_mask((snd_pcm_hw_params_t*) params, var);
+}
+
+static inline const interval_t *params_interval_c(const snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ return (const interval_t *)params_interval((snd_pcm_hw_params_t*) params, var);
+}
+
+void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
+{
+ unsigned int k;
+ memset(params, 0, sizeof(*params));
+ for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
+ mask_all(params_mask(params, k));
+ params->appl_cmask |= 1 << k;
+ }
+
+ for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) {
+ interval_all(params_interval(params, k));
+ params->appl_cmask |= 1 << k;
+ }
+ interval_setreal(params_interval(params, SND_PCM_HW_PARAM_RATE));
+ interval_setreal(params_interval(params, SND_PCM_HW_PARAM_FRAGMENT_LENGTH));
+ interval_setreal(params_interval(params, SND_PCM_HW_PARAM_BUFFER_LENGTH));
+ params->info = ~0U;
+ params->dig_groups = UINT_MAX;
+}
+
+/* Fill PARAMS with full configuration space boundaries */
+int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+ _snd_pcm_hw_params_any(params);
+ return snd_pcm_hw_refine(pcm, params);
+}
+
+/* Return the value for field PAR if it's fixed in configuration space
+ defined by PARAMS. Return -EINVAL otherwise
+*/
+int snd_pcm_hw_params_value(const snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ if (is_mask(var)) {
+ const mask_t *mask = params_mask_c(params, var);
+ if (!mask_single(mask))
+ return -EINVAL;
+ return mask_value(mask);
+ }
+ if (is_interval(var)) {
+ const interval_t *i = params_interval_c(params, var);
+ if (!interval_single(i))
+ return -EINVAL;
+ return interval_value(i);
+ }
+ assert(0);
+ return -EINVAL;
+}
+
+/* Return the minimum value for field PAR. */
+unsigned int snd_pcm_hw_params_value_min(const snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ if (is_mask(var)) {
+ return mask_min(params_mask_c(params, var));
+ }
+ if (is_interval(var)) {
+ return interval_min(params_interval_c(params, var));
+ }
+ assert(0);
+ return -EINVAL;
+}
+
+/* Return the maximum value for field PAR. */
+unsigned int snd_pcm_hw_params_value_max(const snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ if (is_mask(var)) {
+ return mask_max(params_mask_c(params, var));
+ }
+ if (is_interval(var)) {
+ return interval_max(params_interval_c(params, var));
+ }
+ assert(0);
+ return -EINVAL;
+}
+
+/* Return the mask for field PAR.
+ This function can be called only for SND_PCM_HW_PARAM_ACCESS,
+ SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */
+const mask_t *snd_pcm_hw_params_value_mask(const snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ assert(is_mask(var));
+ return params_mask_c(params, var);
+}
+
+/* Return the interval for field PAR.
+ This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
+ SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */
+const interval_t *snd_pcm_hw_params_value_interval(const snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ assert(is_interval(var));
+ return params_interval_c(params, var);
+}
+
+
+/* --- Refinement functions --- */
+
+int _snd_pcm_hw_params_first(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var)
+{
+ int changed;
+ if (is_mask(var))
+ changed = mask_refine_first(params_mask(params, var));
+ else if (is_interval(var))
+ changed = interval_refine_first(params_interval(params, var));
+ else {
+ assert(0);
+ return -EINVAL;
+ }
+ if (changed) {
+ if (hw)
+ params->hw_cmask |= 1 << var;
+ else
+ params->appl_cmask |= 1 << var;
+ }
+ return changed;
+}
+
+
+/* Inside configuration space defined by PARAMS remove from PAR all
+ values > minimum. Reduce configuration space accordingly.
+ Return the minimum.
+*/
+int snd_pcm_hw_params_first(snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *params, unsigned int var)
+{
+ int changed = _snd_pcm_hw_params_first(params, 0, var);
+ if (changed < 0)
+ return changed;
+ if (changed) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ assert(err >= 0);
+ }
+ return snd_pcm_hw_params_value(params, var);
+}
+
+int _snd_pcm_hw_params_last(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var)
+{
+ int changed;
+ if (is_mask(var))
+ changed = mask_refine_last(params_mask(params, var));
+ else if (is_interval(var))
+ changed = interval_refine_last(params_interval(params, var));
+ else {
+ assert(0);
+ return -EINVAL;
+ }
+ if (changed) {
+ if (hw)
+ params->hw_cmask |= 1 << var;
+ else
+ params->appl_cmask |= 1 << var;
+ }
+ return changed;
+}
+
+
+/* Inside configuration space defined by PARAMS remove from PAR all
+ values < maximum. Reduce configuration space accordingly.
+ Return the maximum.
+*/
+int snd_pcm_hw_params_last(snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *params, unsigned int var)
+{
+ int changed = _snd_pcm_hw_params_last(params, 0, var);
+ if (changed < 0)
+ return changed;
+ if (changed) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ assert(err >= 0);
+ }
+ return snd_pcm_hw_params_value(params, var);
+}
+
+int _snd_pcm_hw_params_min(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var, unsigned int val)
+{
+ int changed;
+ if (is_mask(var))
+ changed = mask_refine_min(params_mask(params, var), val);
+ else if (is_interval(var))
+ changed = interval_refine_min(params_interval(params, var), val);
+ else {
+ assert(0);
+ return -EINVAL;
+ }
+ if (changed) {
+ if (hw)
+ params->hw_cmask |= 1 << var;
+ else
+ params->appl_cmask |= 1 << var;
+ }
+ return changed;
+}
+
+/* Inside configuration space defined by PARAMS remove from PAR all
+ values < VAL. Reduce configuration space accordingly.
+ Return new minimum or -EINVAL if the configuration space is empty
+*/
+int snd_pcm_hw_params_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int var, unsigned int val)
+{
+ int changed = _snd_pcm_hw_params_min(params, 0, var, val);
+ if (changed < 0)
+ return changed;
+ if (changed) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return snd_pcm_hw_params_value_min(params, var);
+}
+
+int _snd_pcm_hw_params_max(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var, unsigned int val)
+{
+ int changed;
+ if (is_mask(var))
+ changed = mask_refine_max(params_mask(params, var), val);
+ else if (is_interval(var))
+ changed = interval_refine_max(params_interval(params, var), val);
+ else {
+ assert(0);
+ return -EINVAL;
+ }
+ if (changed) {
+ if (hw)
+ params->hw_cmask |= 1 << var;
+ else
+ params->appl_cmask |= 1 << var;
+ }
+ return changed;
+}
+
+/* Inside configuration space defined by PARAMS remove from PAR all
+ values >= VAL + 1. Reduce configuration space accordingly.
+ Return new maximum or -EINVAL if the configuration space is empty
+*/
+int snd_pcm_hw_params_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int var, unsigned int val)
+{
+ int changed = _snd_pcm_hw_params_max(params, 0, var, val);
+ if (changed < 0)
+ return changed;
+ if (changed) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return snd_pcm_hw_params_value_max(params, var);
+}
+
+int _snd_pcm_hw_params_minmax(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var,
+ unsigned int min, unsigned int max)
+{
+ int changed, c1, c2;
+ if (is_mask(var)) {
+ mask_t *mask = params_mask(params, var);
+ c1 = mask_refine_min(mask, min);
+ if (c1 < 0)
+ changed = c1;
+ else {
+ c2 = mask_refine_max(mask, max);
+ if (c2 < 0)
+ changed = c2;
+ else
+ changed = (c1 || c2);
+ }
+ }
+ else if (is_interval(var)) {
+ interval_t *i = params_interval(params, var);
+ c1 = interval_refine_min(i, min);
+ if (c1 < 0)
+ changed = c1;
+ else {
+ c2 = interval_refine_max(i, max);
+ if (c2 < 0)
+ changed = c2;
+ else
+ changed = (c1 || c2);
+ }
+ } else {
+ assert(0);
+ return -EINVAL;
+ }
+ if (changed) {
+ if (hw)
+ params->hw_cmask |= 1 << var;
+ else
+ params->appl_cmask |= 1 << var;
+ }
+ return changed;
+}
+
+/* Inside configuration space defined by PARAMS remove from PAR all
+ values < MIN and all values > MAX. Reduce configuration space accordingly.
+ Return 0 or -EINVAL if the configuration space is empty
+*/
+int snd_pcm_hw_params_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int var,
+ unsigned int min, unsigned int max)
+{
+ int changed = _snd_pcm_hw_params_minmax(params, 0, var, min, max);
+ if (changed < 0)
+ return changed;
+ if (changed) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+int _snd_pcm_hw_params_set(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var, unsigned int val)
+{
+ int changed;
+ if (is_mask(var))
+ changed = mask_refine_set(params_mask(params, var), val);
+ else if (is_interval(var))
+ changed = interval_refine_set(params_interval(params, var), val);
+ else {
+ assert(0);
+ return -EINVAL;
+ }
+ if (changed) {
+ if (hw)
+ params->hw_cmask |= 1 << var;
+ else
+ params->appl_cmask |= 1 << var;
+ }
+ return changed;
+}
+
+/* Inside configuration space defined by PARAMS remove from PAR all
+ values < VAL and >= VAL +1. Reduce configuration space accordingly.
+ Return VAL or -EINVAL if the configuration space is empty
+*/
+int snd_pcm_hw_params_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int var, unsigned int val)
+{
+ int changed = _snd_pcm_hw_params_set(params, 0, var, val);
+ if (changed < 0)
+ return changed;
+ if (changed) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return snd_pcm_hw_params_value(params, var);
+}
+
+int _snd_pcm_hw_params_mask(snd_pcm_hw_params_t *params, int hw,
+ unsigned int var, const mask_t *val)
+{
+ int changed;
+ assert(is_mask(var));
+ changed = mask_refine(params_mask(params, var), val);
+ if (changed) {
+ if (hw)
+ params->hw_cmask |= 1 << var;
+ else
+ params->appl_cmask |= 1 << var;
+ }
+ return changed;
+}
+
+/* Inside configuration space defined by PARAMS remove from PAR all values
+ not contained in MASK. Reduce configuration space accordingly.
+ This function can be called only for SND_PCM_HW_PARAM_ACCESS,
+ SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
+ Return 0 on success or -EINVAL
+ if the configuration space is empty
+*/
+int snd_pcm_hw_params_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int var, const mask_t *val)
+{
+ int changed = _snd_pcm_hw_params_mask(params, 0, var, val);
+ if (changed < 0)
+ return changed;
+ if (changed) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+/* Inside configuration space defined by PARAMS set PAR to the available value
+ nearest to VAL. Reduce configuration space accordingly.
+ This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
+ SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
+ Return the value found.
+ */
+int snd_pcm_hw_params_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int var, unsigned int val)
+{
+ snd_pcm_hw_params_t save;
+ int v;
+ unsigned int max1 = val, min2 = add(val, 1);
+ save = *params;
+ v = snd_pcm_hw_params_max(pcm, params, var, max1);
+ if (v >= 0) {
+ int v1;
+ snd_pcm_hw_params_t params1;
+ if (val == (unsigned int)v)
+ goto _end;
+ params1 = save;
+ v1 = snd_pcm_hw_params_min(pcm, ¶ms1, var, min2);
+ if (v1 < 0)
+ goto _end;
+ if (val - v > v1 - val) {
+ *params = params1;
+ v = v1;
+ }
+ } else {
+ *params = save;
+ v = snd_pcm_hw_params_min(pcm, params, var, min2);
+ assert(v >= 0);
+ }
+ _end:
+ v = snd_pcm_hw_params_set(pcm, params, var, v);
+ assert(v >= 0);
+ return v;
+}
+
+/* Inside configuration space defined by PARAMS set PAR to the available value
+ nearest to VAL after OLD (values less than VAL are returned first).
+ Reduce configuration space accordingly.
+ This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
+ SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
+ Return the value found.
+ */
+int snd_pcm_hw_params_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int var, unsigned int val,
+ unsigned int old)
+{
+ snd_pcm_hw_params_t save;
+ int v;
+ unsigned int max1, min2;
+ int diff = old - val;
+ if (diff < 0) {
+ max1 = sub(old, 1);
+ min2 = add(val, -diff);
+ } else {
+ max1 = sub(val, diff + 1);
+ min2 = add(old, 1);
+ }
+ save = *params;
+ v = snd_pcm_hw_params_max(pcm, params, var, max1);
+ if (v >= 0) {
+ int v1;
+ snd_pcm_hw_params_t params1;
+ if (val == (unsigned int)v)
+ goto _end;
+ params1 = save;
+ v1 = snd_pcm_hw_params_min(pcm, ¶ms1, var, min2);
+ if (v1 < 0)
+ goto _end;
+ if (val - v > v1 - val) {
+ *params = params1;
+ v = v1;
+ }
+ } else {
+ *params = save;
+ v = snd_pcm_hw_params_min(pcm, params, var, min2);
+ if (v < 0)
+ return v;
+ }
+ _end:
+ v = snd_pcm_hw_params_set(pcm, params, var, v);
+ return v;
+}
+
+
+/* ---- end of refinement functions ---- */
+
+int snd_pcm_hw_params_empty(const snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ if (is_mask(var))
+ return mask_empty(params_mask_c(params, var));
+ if (is_interval(var))
+ return interval_empty(params_interval_c(params, var));
+ assert(0);
+ return -EINVAL;
+}
+
+/* Return rate numerator/denumerator obtainable for configuration space defined
+ by PARAMS */
+int snd_pcm_hw_params_info_rate(const snd_pcm_hw_params_t *params,
+ unsigned int *rate_num, unsigned int *rate_den)
+{
+ if (params->rate_den == 0)
+ return -EINVAL;
+ *rate_num = params->rate_num;
+ *rate_den = params->rate_den;
+ return 0;
+}
+
+/* Return significative bits in sample for configuration space defined
+ by PARAMS */
+int snd_pcm_hw_params_info_msbits(const snd_pcm_hw_params_t *params)
+{
+ if (params->msbits == 0)
+ return -EINVAL;
+ return params->msbits;
+}
+
+/* Return info for configuration space defined by PARAMS */
+int snd_pcm_hw_params_info_flags(const snd_pcm_hw_params_t *params)
+{
+ if (params->info == ~0U)
+ return -EINVAL;
+ return params->info;
+}
+
+/* Return fifo size for configuration space defined by PARAMS */
+int snd_pcm_hw_params_info_fifo_size(const snd_pcm_hw_params_t *params)
+{
+ if (params->fifo_size == 0)
+ return -EINVAL;
+ return params->fifo_size;
+}
+
+/* Return count of digital groups for configuration space defined by PARAMS */
+int snd_pcm_hw_params_info_dig_groups(const snd_pcm_hw_params_t *params)
+{
+ if (params->dig_groups == UINT_MAX)
+ return -EINVAL;
+ return params->dig_groups;
+}
+
+/* Choose one configuration from configuration space defined by PARAMS
+ The configuration choosen is that obtained fixing in this order:
+ first access
+ first format
+ first subformat
+ min channels
+ min rate
+ min fragment size
+ max fragments
+*/
+void snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+ int err;
+ unsigned int hw_cmask = 0;
+
+ err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_ACCESS);
+ assert(err >= 0);
+ hw_cmask |= params->hw_cmask;
+
+ err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_FORMAT);
+ assert(err >= 0);
+ hw_cmask |= params->hw_cmask;
+
+ err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT);
+ assert(err >= 0);
+ hw_cmask |= params->hw_cmask;
+
+ err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS);
+ assert(err >= 0);
+ hw_cmask |= params->hw_cmask;
+
+ err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_RATE);
+ assert(err >= 0);
+ hw_cmask |= params->hw_cmask;
+
+ err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_FRAGMENT_SIZE);
+ assert(err >= 0);
+ hw_cmask |= params->hw_cmask;
+
+ err = snd_pcm_hw_params_last(pcm, params, SND_PCM_HW_PARAM_FRAGMENTS);
+ assert(err >= 0);
+ hw_cmask |= params->hw_cmask;
+
+ params->hw_cmask = hw_cmask;
+}
+
+int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+ int err;
+ assert(pcm && params);
+ params->hw_cmask = 0;
+ err = pcm->ops->hw_refine(pcm->op_arg, params);
+ params->appl_cmask = 0;
+ return err;
+}
+
+/* Install one of the configurations present in configuration
+ space defined by PARAMS.
+ The configuration choosen is that obtained fixing in this order:
+ first access
+ first format
+ first subformat
+ min channels
+ min rate
+ min fragment_size
+ max fragments
+ Return 0 on success or a negative number expressing the error.
+*/
+int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+ int err;
+ params->hw_cmask = 0;
+ snd_pcm_hw_params_choose(pcm, params);
+ if (pcm->mmap_channels) {
+ err = snd_pcm_munmap(pcm);
+ if (err < 0)
+ return err;
+ }
+ err = pcm->ops->hw_params(pcm->op_arg, params);
+ if (err < 0)
+ goto _mmap;
+
+ pcm->setup = 1;
+ pcm->access = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_ACCESS);
+ pcm->format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
+ pcm->subformat = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_SUBFORMAT);
+ pcm->channels = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_CHANNELS);
+ pcm->rate = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_RATE);
+ pcm->fragment_size = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FRAGMENT_SIZE);
+ pcm->fragments = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FRAGMENTS);
+ pcm->bits_per_sample = snd_pcm_format_physical_width(pcm->format);
+ pcm->bits_per_frame = pcm->bits_per_sample * pcm->channels;
+ pcm->buffer_size = pcm->fragment_size * pcm->fragments;
+
+ pcm->info = params->info;
+ pcm->msbits = params->msbits;
+ pcm->rate_num = params->rate_num;
+ pcm->rate_den = params->rate_den;
+ pcm->fifo_size = params->fifo_size;
+
+ /* Default sw params */
+ pcm->start_mode = SND_PCM_START_DATA;
+ pcm->ready_mode = SND_PCM_READY_FRAGMENT;
+ pcm->xrun_mode = SND_PCM_XRUN_FRAGMENT;
+ pcm->avail_min = pcm->fragment_size;
+ pcm->xfer_min = pcm->fragment_size;
+ pcm->xfer_align = pcm->fragment_size;
+ pcm->time = 0;
+ pcm->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
+
+ _mmap:
+ if (pcm->setup &&
+ (pcm->mmap_rw ||
+ (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
+ pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
+ pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX))) {
+ int err;
+ err = snd_pcm_mmap(pcm);
+ if (err < 0)
+ return err;
+ }
+ if (err >= 0)
+ snd_pcm_prepare(pcm);
+ return err;
+}
+
+/* Strategies */
+
+struct _snd_pcm_strategy {
+ unsigned int badness_min, badness_max;
+ int (*choose_param)(const snd_pcm_hw_params_t *params,
+ snd_pcm_t *pcm,
+ const snd_pcm_strategy_t *strategy);
+ int (*next_value)(snd_pcm_hw_params_t *params,
+ unsigned int param,
+ int value,
+ snd_pcm_t *pcm,
+ const snd_pcm_strategy_t *strategy);
+ int (*min_badness)(const snd_pcm_hw_params_t *params,
+ unsigned int max_badness,
+ snd_pcm_t *pcm,
+ const snd_pcm_strategy_t *strategy);
+ void *private;
+ void (*free)(snd_pcm_strategy_t *strategy);
+};
+
+/* Independent badness */
+typedef struct _snd_pcm_strategy_simple snd_pcm_strategy_simple_t;
+
+struct _snd_pcm_strategy_simple {
+ int valid;
+ unsigned int order;
+ int (*next_value)(snd_pcm_hw_params_t *params,
+ unsigned int param,
+ int value,
+ snd_pcm_t *pcm,
+ const snd_pcm_strategy_simple_t *par);
+ unsigned int (*min_badness)(const snd_pcm_hw_params_t *params,
+ unsigned int param,
+ snd_pcm_t *pcm,
+ const snd_pcm_strategy_simple_t *par);
+ void *private;
+ void (*free)(snd_pcm_strategy_simple_t *strategy);
+};
+
+typedef struct _snd_pcm_strategy_simple_near {
+ int best;
+ unsigned int mul;
+} snd_pcm_strategy_simple_near_t;
+
+typedef struct _snd_pcm_strategy_simple_choices {
+ unsigned int count;
+ /* choices need to be sorted on ascending badness */
+ snd_pcm_strategy_simple_choices_list_t *choices;
+} snd_pcm_strategy_simple_choices_t;
+
+int snd_pcm_hw_params_test(const snd_pcm_hw_params_t *params,
+ unsigned int var, unsigned int val)
+{
+ if (is_mask(var)) {
+ const mask_t *mask = params_mask_c(params, var);
+ return mask_test(mask, val);
+ }
+ if (is_interval(var)) {
+ const interval_t *i = params_interval_c(params, var);
+ return interval_test(i, val);
+ }
+ assert(0);
+ return -EINVAL;
+}
+
+unsigned int snd_pcm_hw_params_count(const snd_pcm_hw_params_t *params,
+ unsigned int var)
+{
+ if (is_mask(var)) {
+ const mask_t *mask = params_mask_c(params, var);
+ return mask_count(mask);
+ }
+ if (is_interval(var)) {
+ const interval_t *i = params_interval_c(params, var);
+ return interval_max(i) - interval_min(i) + 1;
+ }
+ assert(0);
+ return 0;
+}
+
+void snd_pcm_hw_params_copy(snd_pcm_hw_params_t *params, unsigned int var,
+ const snd_pcm_hw_params_t *src)
+{
+ if (is_mask(var)) {
+ mask_t *d = params_mask(params, var);
+ const mask_t *s = params_mask_c(src, var);
+ mask_copy(d, s);
+ }
+ if (is_interval(var)) {
+ interval_t *d = params_interval(params, var);
+ const interval_t *s = params_interval_c(src, var);
+ interval_copy(d, s);
+ }
+ assert(0);
+}
+
+void snd_pcm_hw_params_dump(const snd_pcm_hw_params_t *params,
+ unsigned int var, FILE *fp)
+{
+ if (is_mask(var)) {
+ const mask_t *mask = params_mask_c(params, var);
+ if (mask_empty(mask))
+ fputs(" NONE", fp);
+ else {
+ unsigned int k;
+ for (k = 0; k <= MASK_MAX; ++k) {
+ if (mask_test(mask, k)) {
+ putc(' ', fp);
+ switch (var) {
+ case SND_PCM_HW_PARAM_ACCESS:
+ fputs(snd_pcm_access_name(k), fp);
+ break;
+ case SND_PCM_HW_PARAM_FORMAT:
+ fputs(snd_pcm_format_name(k), fp);
+ break;
+ case SND_PCM_HW_PARAM_SUBFORMAT:
+ fputs(snd_pcm_subformat_name(k), fp);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ }
+ }
+ return;
+ }
+ if (is_interval(var)) {
+ interval_print(params_interval_c(params, var), fp);
+ return;
+ }
+ assert(0);
+}
+
+int snd_pcm_dump_hw_params(snd_pcm_hw_params_t *params, FILE *fp)
+{
+ unsigned int k;
+ for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++) {
+ fprintf(fp, "%s: ", snd_pcm_hw_param_name(k));
+ snd_pcm_hw_params_dump(params, k, fp);
+ putc('\n', fp);
+ }
+ return 0;
+}
+
+int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ const snd_pcm_strategy_t *strategy,
+ unsigned int badness_min,
+ unsigned int badness_max)
+{
+ snd_pcm_hw_params_t best_params;
+ int var;
+ int value;
+ unsigned int best_badness;
+ int badness = strategy->min_badness(params, badness_max, pcm, strategy);
+ snd_pcm_hw_params_t params1;
+#if 0
+ printf("\nBadness: %d\n", badness);
+ snd_pcm_dump_hw_params(params, stdout);
+#endif
+ if (badness < 0)
+ return badness;
+ if ((unsigned int)badness > badness_min)
+ badness_min = badness_min;
+ var = strategy->choose_param(params, pcm, strategy);
+ if (var < 0)
+ return badness;
+ best_badness = UINT_MAX;
+ value = -1;
+ while (1) {
+ unsigned int hw_cmask;
+ params1 = *params;
+ value = strategy->next_value(¶ms1, var, value, pcm, strategy);
+ if (value < 0)
+ break;
+ hw_cmask = params1.hw_cmask;
+ badness = snd_pcm_hw_params_strategy(pcm, ¶ms1, strategy, badness_min, badness_max);
+ params1.hw_cmask |= hw_cmask;
+ if (badness >= 0) {
+ if ((unsigned int) badness <= badness_min) {
+ *params = params1;
+ return badness;
+ }
+ best_badness = badness;
+ best_params = params1;
+ badness_max = badness - 1;
+ }
+ }
+ if (best_badness == UINT_MAX) {
+ return -EINVAL;
+ }
+ *params = best_params;
+ return best_badness;
+}
+
+void snd_pcm_strategy_simple_free(snd_pcm_strategy_t *strategy)
+{
+ snd_pcm_strategy_simple_t *pars = strategy->private;
+ int k;
+ for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+ if (pars[k].valid && pars[k].free)
+ pars[k].free(&pars[k]);
+ }
+ free(pars);
+}
+
+int snd_pcm_strategy_simple_choose_param(const snd_pcm_hw_params_t *params,
+ snd_pcm_t *pcm ATTRIBUTE_UNUSED,
+ const snd_pcm_strategy_t *strategy)
+{
+ unsigned int var;
+ int best_var = -1;
+ const snd_pcm_strategy_simple_t *pars = strategy->private;
+ unsigned int min_choices = UINT_MAX;
+ unsigned int min_order = UINT_MAX;
+ for (var = 0; var <= SND_PCM_HW_PARAM_LAST; ++var) {
+ const snd_pcm_strategy_simple_t *p = &pars[var];
+ unsigned int choices;
+ if (!p->valid)
+ continue;
+ choices = snd_pcm_hw_params_count(params, var);
+ if (choices == 1)
+ continue;
+ assert(choices != 0);
+ if (p->order < min_order ||
+ (p->order == min_order &&
+ choices < min_choices)) {
+ min_order = p->order;
+ min_choices = choices;
+ best_var = var;
+ }
+ }
+ return best_var;
+}
+
+int snd_pcm_strategy_simple_next_value(snd_pcm_hw_params_t *params,
+ unsigned int var,
+ int value,
+ snd_pcm_t *pcm,
+ const snd_pcm_strategy_t *strategy)
+{
+ const snd_pcm_strategy_simple_t *pars = strategy->private;
+ assert(pars[var].valid);
+ return pars[var].next_value(params, var, value, pcm, &pars[var]);
+}
+
+
+int snd_pcm_strategy_simple_min_badness(const snd_pcm_hw_params_t *params,
+ unsigned int max_badness,
+ snd_pcm_t *pcm,
+ const snd_pcm_strategy_t *strategy)
+{
+ unsigned int var;
+ unsigned int badness = 0;
+ const snd_pcm_strategy_simple_t *pars = strategy->private;
+ for (var = 0; var <= SND_PCM_HW_PARAM_LAST; ++var) {
+ unsigned int b;
+ if (!pars[var].valid)
+ continue;
+ b = pars[var].min_badness(params, var, pcm, &pars[var]);
+ if (b > max_badness || max_badness - b < badness)
+ return -E2BIG;
+ badness += b;
+ }
+ return badness;
+}
+
+
+void snd_pcm_strategy_simple_near_free(snd_pcm_strategy_simple_t *par)
+{
+ snd_pcm_strategy_simple_near_t *p = par->private;
+ free(p);
+}
+
+unsigned int snd_pcm_strategy_simple_near_min_badness(const snd_pcm_hw_params_t *params,
+ unsigned int var,
+ snd_pcm_t *pcm,
+ const snd_pcm_strategy_simple_t *par)
+{
+ const snd_pcm_strategy_simple_near_t *p = par->private;
+ snd_pcm_hw_params_t params1 = *params;
+ int value = snd_pcm_hw_params_near(pcm, ¶ms1, var, p->best);
+ int diff;
+ assert(value >= 0);
+ diff = p->best - value;
+ if (diff < 0)
+ diff = -diff;
+ return diff * p->mul;
+}
+
+int snd_pcm_strategy_simple_near_next_value(snd_pcm_hw_params_t *params,
+ unsigned int var,
+ int value,
+ snd_pcm_t *pcm,
+ const snd_pcm_strategy_simple_t *par)
+{
+ const snd_pcm_strategy_simple_near_t *p = par->private;
+ if (value < 0)
+ return snd_pcm_hw_params_near(pcm, params, var, p->best);
+ else
+ return snd_pcm_hw_params_next(pcm, params, var, p->best, value);
+}
+
+void snd_pcm_strategy_simple_choices_free(snd_pcm_strategy_simple_t *par)
+{
+ snd_pcm_strategy_simple_choices_t *p = par->private;
+// free(p->choices);
+ free(p);
+}
+
+unsigned int snd_pcm_strategy_simple_choices_min_badness(const snd_pcm_hw_params_t *params,
+ unsigned int var,
+ snd_pcm_t *pcm ATTRIBUTE_UNUSED,
+ const snd_pcm_strategy_simple_t *par)
+{
+ const snd_pcm_strategy_simple_choices_t *p = par->private;
+ unsigned int k;
+ for (k = 0; k < p->count; ++k) {
+ if (snd_pcm_hw_params_test(params, var, p->choices[k].value))
+ return p->choices[k].badness;
+ }
+ assert(0);
+ return UINT_MAX;
+}
+
+int snd_pcm_strategy_simple_choices_next_value(snd_pcm_hw_params_t *params,
+ unsigned int var,
+ int value,
+ snd_pcm_t *pcm,
+ const snd_pcm_strategy_simple_t *par)
+{
+ const snd_pcm_strategy_simple_choices_t *p = par->private;
+ unsigned int k = 0;
+ if (value >= 0) {
+ for (; k < p->count; ++k) {
+ if (p->choices[k].value == (unsigned int) value) {
+ k++;
+ break;
+ }
+ }
+ }
+ for (; k < p->count; ++k) {
+ unsigned int v = p->choices[k].value;
+ if (snd_pcm_hw_params_test(params, var, v)) {
+ snd_pcm_hw_params_t save = *params;
+ int err = snd_pcm_hw_params_set(pcm, params, var, v);
+ if (err < 0) {
+ *params = save;
+ continue;
+ }
+ return v;
+ }
+ }
+ return -1;
+}
+
+int snd_pcm_strategy_free(snd_pcm_strategy_t *strategy)
+{
+ if (strategy->free)
+ strategy->free(strategy);
+ free(strategy);
+ return 0;
+}
+
+int snd_pcm_strategy_simple(snd_pcm_strategy_t **strategyp,
+ unsigned int badness_min,
+ unsigned int badness_max)
+{
+ snd_pcm_strategy_simple_t *data;
+ snd_pcm_strategy_t *s;
+ assert(strategyp);
+ data = calloc(SND_PCM_HW_PARAM_LAST + 1, sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+ s = calloc(1, sizeof(*s));
+ if (!s) {
+ free(data);
+ return -ENOMEM;
+ }
+ s->choose_param = snd_pcm_strategy_simple_choose_param;
+ s->next_value = snd_pcm_strategy_simple_next_value;
+ s->min_badness = snd_pcm_strategy_simple_min_badness;
+ s->badness_min = badness_min;
+ s->badness_max = badness_max;
+ s->private = data;
+ s->free = snd_pcm_strategy_simple_free;
+ *strategyp = s;
+ return 0;
+}
+
+int snd_pcm_strategy_simple_near(snd_pcm_strategy_t *strategy,
+ int order,
+ unsigned int var,
+ unsigned int best,
+ unsigned int mul)
+{
+ snd_pcm_strategy_simple_t *s = strategy->private;
+ snd_pcm_strategy_simple_near_t *data;
+ assert(strategy);
+ assert(var <= SND_PCM_HW_PARAM_LAST);
+ assert(!s->valid);
+ data = calloc(1, sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+ data->best = best;
+ data->mul = mul;
+ s += var;
+ s->order = order;
+ s->valid = 1;
+ s->next_value = snd_pcm_strategy_simple_near_next_value;
+ s->min_badness = snd_pcm_strategy_simple_near_min_badness;
+ s->private = data;
+ s->free = snd_pcm_strategy_simple_near_free;
+ return 0;
+}
+
+int snd_pcm_strategy_simple_choices(snd_pcm_strategy_t *strategy,
+ int order,
+ unsigned int var,
+ unsigned int count,
+ snd_pcm_strategy_simple_choices_list_t *choices)
+{
+ snd_pcm_strategy_simple_t *s = strategy->private;
+ snd_pcm_strategy_simple_choices_t *data;
+ assert(strategy);
+ assert(var <= SND_PCM_HW_PARAM_LAST);
+ assert(!s->valid);
+ data = calloc(1, sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+ data->count = count;
+ data->choices = choices;
+ s += var;
+ s->valid = 1;
+ s->order = order;
+ s->next_value = snd_pcm_strategy_simple_choices_next_value;
+ s->min_badness = snd_pcm_strategy_simple_choices_min_badness;
+ s->private = data;
+ s->free = snd_pcm_strategy_simple_choices_free;
+ return 0;
+}
+
+int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *fail,
+ snd_pcm_hw_params_t *success,
+ unsigned int depth,
+ FILE *fp)
+{
+ unsigned int var;
+ snd_pcm_hw_params_t i;
+ if (depth < 1)
+ return -ENOENT;
+ for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
+ int err;
+ i = *success;
+ snd_pcm_hw_params_copy(&i, var, fail);
+ err = snd_pcm_hw_refine(pcm, &i);
+ if (err == 0 &&
+ snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, fp) < 0)
+ continue;
+ fprintf(fp, "%s: ", snd_pcm_hw_param_name(var));
+ snd_pcm_hw_params_dump(fail, var, fp);
+ putc('\n', fp);
+ return 0;
+ }
+ return -ENOENT;
+}
+
+int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *fail,
+ snd_pcm_hw_params_t *success,
+ unsigned int depth,
+ FILE *fp)
+{
+ snd_pcm_hw_params_t i, any;
+ int err;
+ unsigned int var;
+ int done = 0;
+ assert(pcm && fail);
+ for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
+ if (!snd_pcm_hw_params_empty(fail, var))
+ continue;
+ fprintf(fp, "%s is empty\n", snd_pcm_hw_param_name(var));
+ done = 1;
+ }
+ if (done)
+ return 0;
+ i = *fail;
+ err = snd_pcm_hw_refine(pcm, &i);
+ if (err == 0) {
+ fprintf(fp, "Configuration is virtually correct\n");
+ return 0;
+ }
+ if (!success) {
+ snd_pcm_hw_params_any(pcm, &any);
+ success = &any;
+ }
+ return snd_pcm_hw_params_try_explain_failure1(pcm, fail, success, depth, fp);
+}
+
+typedef struct _snd_pcm_hw_rule snd_pcm_hw_rule_t;
+
+typedef int (*snd_pcm_hw_rule_func_t)(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_rule_t *rule);
+
+struct _snd_pcm_hw_rule {
+ int var;
+ snd_pcm_hw_rule_func_t func;
+ int deps[4];
+ void *private;
+};
+
+int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_rule_t *rule)
+{
+ return interval_mul(params_interval(params, rule->var),
+ params_interval(params, rule->deps[0]),
+ params_interval(params, rule->deps[1]));
+}
+
+int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_rule_t *rule)
+{
+ return interval_div(params_interval(params, rule->var),
+ params_interval(params, rule->deps[0]),
+ params_interval(params, rule->deps[1]));
+}
+
+int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_rule_t *rule)
+{
+ return interval_muldivk(params_interval(params, rule->var),
+ (unsigned long) rule->private,
+ params_interval(params, rule->deps[0]),
+ params_interval(params, rule->deps[1]));
+}
+
+int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_rule_t *rule)
+{
+ return interval_mulkdiv(params_interval(params, rule->var),
+ (unsigned long) rule->private,
+ params_interval(params, rule->deps[0]),
+ params_interval(params, rule->deps[1]));
+}
+
+int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_rule_t *rule)
+{
+ int changed = 0;
+ unsigned int k;
+ mask_t *mask = params_mask(params, rule->var);
+ interval_t *i = params_interval(params, rule->deps[0]);
+ for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k) {
+ int bits;
+ if (!mask_test(mask, k))
+ continue;
+ bits = snd_pcm_format_physical_width(k);
+ if (bits < 0)
+ continue;
+ if (!interval_test(i, bits)) {
+ mask_reset(mask, k);
+ if (mask_empty(mask))
+ return -EINVAL;
+ changed = 1;
+ }
+ }
+ return changed;
+}
+
+
+int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_rule_t *rule)
+{
+ unsigned int min, max;
+ unsigned int k;
+ interval_t *i = params_interval(params, rule->var);
+ mask_t *mask = params_mask(params, rule->deps[0]);
+ int c, changed = 0;
+ min = UINT_MAX;
+ max = 0;
+ for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k) {
+ int bits;
+ if (!mask_test(mask, k))
+ continue;
+ bits = snd_pcm_format_physical_width(k);
+ if (bits < 0)
+ continue;
+ if (min > (unsigned)bits)
+ min = bits;
+ if (max < (unsigned)bits)
+ max = bits;
+ }
+ c = interval_refine_min(i, min);
+ if (c < 0)
+ return c;
+ if (c)
+ changed = 1;
+ c = interval_refine_max(i, max);
+ if (c < 0)
+ return c;
+ if (c)
+ changed = 1;
+ return changed;
+}
+
+snd_pcm_hw_rule_t snd_pcm_hw_rules[] = {
+ {
+ var: SND_PCM_HW_PARAM_FORMAT,
+ func: snd_pcm_hw_rule_format,
+ deps: { SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
+ private: 0,
+ },
+ {
+ var: SND_PCM_HW_PARAM_SAMPLE_BITS,
+ func: snd_pcm_hw_rule_sample_bits,
+ deps: { SND_PCM_HW_PARAM_FORMAT, -1 },
+ private: 0,
+ },
+ {
+ var: SND_PCM_HW_PARAM_SAMPLE_BITS,
+ func: snd_pcm_hw_rule_div,
+ deps: { SND_PCM_HW_PARAM_FRAME_BITS,
+ SND_PCM_HW_PARAM_CHANNELS, -1 },
+ private: 0,
+ },
+ {
+ var: SND_PCM_HW_PARAM_FRAME_BITS,
+ func: snd_pcm_hw_rule_mul,
+ deps: { SND_PCM_HW_PARAM_SAMPLE_BITS,
+ SND_PCM_HW_PARAM_CHANNELS, -1 },
+ private: 0,
+ },
+ {
+ var: SND_PCM_HW_PARAM_FRAME_BITS,
+ func: snd_pcm_hw_rule_mulkdiv,
+ deps: { SND_PCM_HW_PARAM_FRAGMENT_BYTES,
+ SND_PCM_HW_PARAM_FRAGMENT_SIZE, -1 },
+ private: (void*) 8,
+ },
+ {
+ var: SND_PCM_HW_PARAM_FRAME_BITS,
+ func: snd_pcm_hw_rule_mulkdiv,
+ deps: { SND_PCM_HW_PARAM_BUFFER_BYTES,
+ SND_PCM_HW_PARAM_BUFFER_SIZE, -1 },
+ private: (void*) 8,
+ },
+ {
+ var: SND_PCM_HW_PARAM_CHANNELS,
+ func: snd_pcm_hw_rule_div,
+ deps: { SND_PCM_HW_PARAM_FRAME_BITS,
+ SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
+ private: 0,
+ },
+ {
+ var: SND_PCM_HW_PARAM_RATE,
+ func: snd_pcm_hw_rule_mulkdiv,
+ deps: { SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+ SND_PCM_HW_PARAM_FRAGMENT_LENGTH, -1 },
+ private: (void*) 1000000,
+ },
+ {
+ var: SND_PCM_HW_PARAM_RATE,
+ func: snd_pcm_hw_rule_mulkdiv,
+ deps: { SND_PCM_HW_PARAM_BUFFER_SIZE,
+ SND_PCM_HW_PARAM_BUFFER_LENGTH, -1 },
+ private: (void*) 1000000,
+ },
+ {
+ var: SND_PCM_HW_PARAM_FRAGMENTS,
+ func: snd_pcm_hw_rule_div,
+ deps: { SND_PCM_HW_PARAM_BUFFER_SIZE,
+ SND_PCM_HW_PARAM_FRAGMENT_SIZE, -1 },
+ private: 0,
+ },
+ {
+ var: SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+ func: snd_pcm_hw_rule_div,
+ deps: { SND_PCM_HW_PARAM_BUFFER_SIZE,
+ SND_PCM_HW_PARAM_FRAGMENTS, -1 },
+ private: 0,
+ },
+ {
+ var: SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+ func: snd_pcm_hw_rule_mulkdiv,
+ deps: { SND_PCM_HW_PARAM_FRAGMENT_BYTES,
+ SND_PCM_HW_PARAM_FRAME_BITS, -1 },
+ private: (void*) 8,
+ },
+ {
+ var: SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+ func: snd_pcm_hw_rule_muldivk,
+ deps: { SND_PCM_HW_PARAM_FRAGMENT_LENGTH,
+ SND_PCM_HW_PARAM_RATE, -1 },
+ private: (void*) 1000000,
+ },
+ {
+ var: SND_PCM_HW_PARAM_BUFFER_SIZE,
+ func: snd_pcm_hw_rule_mul,
+ deps: { SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+ SND_PCM_HW_PARAM_FRAGMENTS, -1 },
+ private: 0,
+ },
+ {
+ var: SND_PCM_HW_PARAM_BUFFER_SIZE,
+ func: snd_pcm_hw_rule_mulkdiv,
+ deps: { SND_PCM_HW_PARAM_BUFFER_BYTES,
+ SND_PCM_HW_PARAM_FRAME_BITS, -1 },
+ private: (void*) 8,
+ },
+ {
+ var: SND_PCM_HW_PARAM_BUFFER_SIZE,
+ func: snd_pcm_hw_rule_muldivk,
+ deps: { SND_PCM_HW_PARAM_BUFFER_LENGTH,
+ SND_PCM_HW_PARAM_RATE, -1 },
+ private: (void*) 1000000,
+ },
+ {
+ var: SND_PCM_HW_PARAM_FRAGMENT_BYTES,
+ func: snd_pcm_hw_rule_muldivk,
+ deps: { SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+ SND_PCM_HW_PARAM_FRAME_BITS, -1 },
+ private: (void*) 8,
+ },
+ {
+ var: SND_PCM_HW_PARAM_BUFFER_BYTES,
+ func: snd_pcm_hw_rule_muldivk,
+ deps: { SND_PCM_HW_PARAM_BUFFER_SIZE,
+ SND_PCM_HW_PARAM_FRAME_BITS, -1 },
+ private: (void*) 8,
+ },
+ {
+ var: SND_PCM_HW_PARAM_FRAGMENT_LENGTH,
+ func: snd_pcm_hw_rule_mulkdiv,
+ deps: { SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+ SND_PCM_HW_PARAM_RATE, -1 },
+ private: (void*) 1000000,
+ },
+ {
+ var: SND_PCM_HW_PARAM_BUFFER_LENGTH,
+ func: snd_pcm_hw_rule_mulkdiv,
+ deps: { SND_PCM_HW_PARAM_BUFFER_SIZE,
+ SND_PCM_HW_PARAM_RATE, -1 },
+ private: (void*) 1000000,
+ },
+};
+
+#define RULES (sizeof(snd_pcm_hw_rules) / sizeof(snd_pcm_hw_rules[0]))
+
+int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
+{
+ unsigned int k;
+ interval_t *i;
+ snd_pcm_hw_rule_t *rules = snd_pcm_hw_rules;
+ unsigned int rstamps[RULES];
+ unsigned int vstamps[SND_PCM_HW_PARAM_LAST + 1];
+ unsigned int stamp = 2;
+ int err, changed;
+
+ for (k = 0; k < RULES; k++)
+ rstamps[k] = 0;
+ for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++)
+ vstamps[k] = (params->appl_cmask & (1 << k)) ? 1 : 0;
+ params->appl_cmask = 0;
+ params->hw_cmask = 0;
+ changed = 1;
+ while (changed) {
+ changed = 0;
+ for (k = 0; k < RULES; k++) {
+ snd_pcm_hw_rule_t *r = &rules[k];
+ unsigned int d;
+ int doit = 0;
+#ifdef RULES_DEBUG
+ interval_t *i;
+#endif
+ for (d = 0; r->deps[d] >= 0; d++) {
+ if (vstamps[r->deps[d]] > rstamps[k]) {
+ doit = 1;
+ break;
+ }
+ }
+ if (!doit)
+ continue;
+#ifdef RULES_DEBUG
+ i = params_interval(params, r->var);
+ fprintf(stderr, "Rule %d: %u ", k, r->var);
+ interval_print(i, stderr);
+#endif
+ err = r->func(params, r);
+#ifdef RULES_DEBUG
+ interval_print(i, stderr);
+ putc('\n', stderr);
+#endif
+ rstamps[k] = stamp;
+ if (err && r->var >= 0) {
+ params->hw_cmask |= 1 << r->var;
+ vstamps[r->var] = stamp;
+ changed = 1;
+ }
+ if (err < 0)
+ return err;
+ stamp++;
+ }
+ }
+ if (!params->msbits) {
+ i = params_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
+ if (interval_single(i))
+ params->msbits = interval_value(i);
+ }
+
+ if (!params->rate_den) {
+ i = params_interval(params, SND_PCM_HW_PARAM_RATE);
+ if (interval_single(i)) {
+ params->rate_num = interval_value(i);
+ params->rate_den = 1;
+ }
+ }
+ return 0;
+}
+
+int snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params, unsigned int var,
+ const snd_pcm_hw_params_t *src)
+{
+ if (is_mask(var)) {
+ mask_t *d = params_mask(params, var);
+ const mask_t *s = params_mask_c(src, var);
+ return mask_refine(d, s);
+ }
+ if (is_interval(var)) {
+ interval_t *d = params_interval(params, var);
+ const interval_t *s = params_interval_c(src, var);
+ return interval_refine(d, s);
+ }
+ assert(0);
+ return -EINVAL;
+}
+
+int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_params_t *sparams,
+ int (*func)(snd_pcm_t *slave,
+ snd_pcm_hw_params_t *sparams),
+ snd_pcm_t *slave,
+ unsigned int links)
+{
+ unsigned int k;
+ int err, error = 0;
+ unsigned int client_from_slave = ~0U;
+ unsigned int client_refine = ~0U;
+ unsigned int slave_from_client = ~0U;
+ unsigned int slave_refine = ~0U;
+ unsigned int hw_cmask = params->hw_cmask;
+
+ while (client_from_slave || client_refine) {
+ for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+ int changed;
+ if (!(links & (1 << k)))
+ continue;
+ if (!(client_from_slave & (1 << k)))
+ continue;
+ changed = snd_pcm_hw_params_refine(params, k, sparams);
+ if (changed) {
+ hw_cmask |= 1 << k;
+ slave_from_client |= 1 << k;
+ client_refine |= 1 << k;
+ }
+ if (changed < 0)
+ error = changed;
+ }
+ client_from_slave = 0;
+ if (error)
+ break;
+ if (client_refine) {
+ params->appl_cmask = client_refine;
+ client_refine = 0;
+ err = _snd_pcm_hw_refine(params);
+ hw_cmask |= params->hw_cmask;
+ slave_from_client |= params->hw_cmask;
+ if (err < 0) {
+ error = err;
+ break;
+ }
+ }
+
+ for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+ int changed;
+ if (!(links & (1 << k)))
+ continue;
+ if (!(slave_from_client & (1 << k)))
+ continue;
+ changed = snd_pcm_hw_params_refine(sparams, k, params);
+ if (changed) {
+ slave_refine |= 1 << k;
+ client_from_slave |= 1 << k;
+ }
+ if (changed < 0)
+ error = changed;
+ }
+ slave_from_client = 0;
+ if (error)
+ continue;
+ if (slave_refine) {
+ sparams->appl_cmask = slave_refine;
+ slave_refine = 0;
+ error = func(slave, sparams);
+ client_from_slave |= sparams->hw_cmask;
+ }
+ }
+ params->appl_cmask = 0;
+ params->hw_cmask = hw_cmask;
+ return error;
+}
+
+int snd_pcm_hw_params2(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_params_t *sparams,
+ int (*func)(snd_pcm_t *slave,
+ snd_pcm_hw_params_t *sparams),
+ snd_pcm_t *slave,
+ unsigned int links)
+{
+ unsigned int k;
+ int err;
+ for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+ int changed;
+ if (!(links & (1 << k)))
+ continue;
+ changed = snd_pcm_hw_params_refine(sparams, k, params);
+ if (changed < 0)
+ return changed;
+ }
+ sparams->appl_cmask = ~0U;
+ err = func(slave, sparams);
+ if (err >= 0)
+ return err;
+
+ for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+ int changed;
+ if (!(links & (1 << k)))
+ continue;
+ if (!(sparams->hw_cmask & (1 << k)))
+ continue;
+ changed = snd_pcm_hw_params_refine(params, k, sparams);
+ if (changed)
+ params->hw_cmask |= 1 << k;
+
+ }
+ return err;
+}
+
SND_PCM_FORMAT_IMA_ADPCM,
};
-static int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
+static int snd_pcm_plug_slave_format(int format, const mask_t *format_mask)
{
int w, u, e, wid, w1, dw;
- if (format_mask & (1 << format))
+ mask_t *lin = alloca(mask_sizeof());
+ if (mask_test(format_mask, format))
return format;
- if (!((1 << format) & SND_PCM_FMTBIT_LINEAR)) {
+ mask_load(lin, SND_PCM_FMTBIT_LINEAR);
+ if (!mask_test(lin, format)) {
unsigned int i;
switch (format) {
case SND_PCM_FORMAT_MU_LAW:
case SND_PCM_FORMAT_IMA_ADPCM:
for (i = 0; i < sizeof(linear_preferred_formats) / sizeof(linear_preferred_formats[0]); ++i) {
unsigned int f = linear_preferred_formats[i];
- if (format_mask & (1 << f))
+ if (mask_test(format_mask, f))
return f;
}
/* Fall through */
}
}
- if (!(format_mask & SND_PCM_FMTBIT_LINEAR)) {
+ mask_intersect(lin, format_mask);
+ if (mask_empty(lin)) {
unsigned int i;
for (i = 0; i < sizeof(nonlinear_preferred_formats) / sizeof(nonlinear_preferred_formats[0]); ++i) {
unsigned int f = nonlinear_preferred_formats[i];
- if (format_mask & (1 << f))
+ if (mask_test(format_mask, f))
return f;
}
return -EINVAL;
for (sgn = 0; sgn < 2; ++sgn) {
int f;
f = snd_pcm_build_linear_format(w1, u1, e1);
- if (f >= 0 && format_mask & (1 << f))
+ if (f >= 0 && mask_test(format_mask, f))
return f;
u1 = !u1;
}
return -EINVAL;
}
-static int snd_pcm_plug_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
+#define SND_PCM_FMTBIT_PLUG (SND_PCM_FMTBIT_LINEAR | \
+ (1 << SND_PCM_FORMAT_MU_LAW) | \
+ (1 << SND_PCM_FORMAT_A_LAW) | \
+ (1 << SND_PCM_FORMAT_IMA_ADPCM))
+
+static int snd_pcm_plug_hw_refine1(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_hw_params_t *sparams)
{
snd_pcm_plug_t *plug = pcm->private;
snd_pcm_t *slave = plug->req_slave;
- snd_pcm_hw_info_t sinfo;
- int rate_min, rate_max;
- int channels_min, channels_max;
- unsigned int format, format_mask;
int err;
+ const mask_t *format_mask, *sformat_mask;
+ unsigned int rate_min, rate_max, srate_min, srate_max;
+ unsigned int channels_min, channels_max, schannels_min, schannels_max;
+ unsigned int format;
+ int same_rate, same_channels, same_format;
+ snd_pcm_hw_params_t tmp;
+ unsigned int links = (SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
+ mask_t *tmp_mask = alloca(mask_sizeof());
+ mask_t *accplug_mask = alloca(mask_sizeof());
+ mask_t *mmap_mask = alloca(mask_sizeof());
+ mask_t *fmtplug_mask = alloca(mask_sizeof());
+ mask_load(accplug_mask, SND_PCM_ACCBIT_PLUGIN);
+ mask_load(mmap_mask, SND_PCM_ACCBIT_MMAP);
+ mask_load(fmtplug_mask, SND_PCM_FMTBIT_PLUG);
- info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
- SND_PCM_ACCBIT_RW_INTERLEAVED |
- SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
- SND_PCM_ACCBIT_RW_NONINTERLEAVED);
- if (info->access_mask == 0)
- return -EINVAL;
-
- info->format_mask &= (SND_PCM_FMTBIT_LINEAR | SND_PCM_FMTBIT_MU_LAW |
- SND_PCM_FMTBIT_A_LAW | SND_PCM_FMTBIT_IMA_ADPCM);
- if (info->format_mask == 0)
- return -EINVAL;
-
- info->subformat_mask &= SND_PCM_SUBFMTBIT_STD;
- if (info->subformat_mask == 0)
- return -EINVAL;
-
- if (info->rate_min < RATE_MIN)
- info->rate_min = RATE_MIN;
- if (info->rate_max > RATE_MAX)
- info->rate_max = RATE_MAX;
- if (info->rate_max < info->rate_min)
- return -EINVAL;
-
- if (info->channels_min < 1)
- info->channels_min = 1;
- if (info->channels_max < info->channels_min)
- return -EINVAL;
-
- sinfo = *info;
- sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
- sinfo.format_mask = (SND_PCM_FMTBIT_LINEAR | SND_PCM_FMTBIT_MU_LAW |
- SND_PCM_FMTBIT_A_LAW | SND_PCM_FMTBIT_IMA_ADPCM);
- sinfo.channels_min = 1;
- sinfo.channels_max = UINT_MAX;
- sinfo.rate_min = RATE_MIN;
- sinfo.rate_max = RATE_MAX;
+ err = _snd_pcm_hw_params_min(params, 1, SND_PCM_HW_PARAM_CHANNELS, 1);
+ if (err < 0)
+ return err;
+ err = _snd_pcm_hw_params_min(params, 1, SND_PCM_HW_PARAM_RATE, RATE_MIN);
+ if (err < 0)
+ return err;
+ err = _snd_pcm_hw_params_max(params, 1, SND_PCM_HW_PARAM_RATE, RATE_MAX);
+ if (err < 0)
+ return err;
- err = snd_pcm_hw_info(slave, &sinfo);
+ _snd_pcm_hw_params_any(sparams);
+ err = snd_pcm_hw_refine2(params, sparams,
+ snd_pcm_hw_refine, slave, links);
if (err < 0)
- goto _err;
+ return err;
- rate_min = snd_pcm_hw_info_par_nearest_next(&sinfo,
- SND_PCM_HW_INFO_RATE,
- info->rate_min, -1,
- slave);
- assert(rate_min >= 0);
- if ((int)info->rate_max - rate_min > 1) {
- rate_max = snd_pcm_hw_info_par_nearest_next(&sinfo,
- SND_PCM_HW_INFO_RATE,
- info->rate_max, -1,
- slave);
- assert(rate_max >= 0);
- } else
- rate_max = rate_min;
- sinfo.rate_min = rate_min;
- sinfo.rate_max = rate_max;
-
- err = snd_pcm_hw_info(slave, &sinfo);
+ rate_min = snd_pcm_hw_params_value_min(params, SND_PCM_HW_PARAM_RATE);
+ rate_max = snd_pcm_hw_params_value_max(params, SND_PCM_HW_PARAM_RATE);
+ tmp = *sparams;
+ srate_min = snd_pcm_hw_params_near(slave, &tmp,
+ SND_PCM_HW_PARAM_RATE, rate_min);
+ if (srate_min < rate_max) {
+ tmp = *sparams;
+ srate_max = snd_pcm_hw_params_near(slave, &tmp,
+ SND_PCM_HW_PARAM_RATE, rate_max);
+ } else
+ srate_max = srate_min;
+ err = snd_pcm_hw_params_minmax(slave, sparams,
+ SND_PCM_HW_PARAM_RATE,
+ srate_min, srate_max);
assert(err >= 0);
- channels_min = snd_pcm_hw_info_par_nearest_next(&sinfo,
- SND_PCM_HW_INFO_CHANNELS,
- info->channels_min, -1,
- slave);
- assert(channels_min >= 0);
- if ((int)info->channels_max - channels_min > 1) {
- channels_max = snd_pcm_hw_info_par_nearest_next(&sinfo,
- SND_PCM_HW_INFO_CHANNELS,
- info->channels_max, -1,
- slave);
- assert(channels_max >= 0);
- } else
- channels_max = channels_min;
- sinfo.channels_min = channels_min;
- sinfo.channels_max = channels_max;
-
- err = snd_pcm_hw_info(slave, &sinfo);
+ channels_min = snd_pcm_hw_params_value_min(params, SND_PCM_HW_PARAM_CHANNELS);
+ channels_max = snd_pcm_hw_params_value_max(params, SND_PCM_HW_PARAM_CHANNELS);
+ tmp = *sparams;
+ schannels_min = snd_pcm_hw_params_near(slave, &tmp,
+ SND_PCM_HW_PARAM_CHANNELS, channels_min);
+ if (schannels_min < channels_max) {
+ tmp = *sparams;
+ schannels_max = snd_pcm_hw_params_near(slave, &tmp,
+ SND_PCM_HW_PARAM_CHANNELS, channels_max);
+ } else
+ schannels_max = schannels_min;
+ err = snd_pcm_hw_params_minmax(slave, sparams,
+ SND_PCM_HW_PARAM_CHANNELS,
+ schannels_min, schannels_max);
assert(err >= 0);
- format_mask = 0;
+ format_mask = snd_pcm_hw_params_value_mask(params,
+ SND_PCM_HW_PARAM_FORMAT);
+ sformat_mask = snd_pcm_hw_params_value_mask(sparams,
+ SND_PCM_HW_PARAM_FORMAT);
+ mask_none(tmp_mask);
for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
int f;
- if (!(info->format_mask & (1 << format)))
+ if (!mask_test(format_mask, format))
continue;
- f = snd_pcm_plug_slave_format(format, sinfo.format_mask);
- assert(f >= 0);
- format_mask |= (1 << f);
+ if (mask_test(sformat_mask, format))
+ f = format;
+ else {
+ f = snd_pcm_plug_slave_format(format, sformat_mask);
+ if (f < 0) {
+ mask_t *m = alloca(mask_sizeof());
+ mask_all(m);
+ mask_reset(m, format);
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_FORMAT, m);
+ if (err < 0)
+ return err;
+ continue;
+ }
+ }
+ mask_set(tmp_mask, f);
}
- sinfo.format_mask = format_mask;
- err = snd_pcm_hw_info(slave, &sinfo);
+ err = _snd_pcm_hw_params_mask(sparams, 0,
+ SND_PCM_HW_PARAM_FORMAT, tmp_mask);
assert(err >= 0);
-
- _err:
- info->subformat_mask = sinfo.subformat_mask;
- info->fragment_length_min = sinfo.fragment_length_min;
- info->fragment_length_max = sinfo.fragment_length_max;
- info->fragments_min = sinfo.fragments_min;
- info->fragments_max = sinfo.fragments_max;
- info->buffer_length_min = sinfo.buffer_length_min;
- info->buffer_length_max = sinfo.buffer_length_max;
-
+ sformat_mask = snd_pcm_hw_params_value_mask(sparams,
+ SND_PCM_HW_PARAM_FORMAT);
+
+ same_rate = (rate_min == rate_max &&
+ rate_min == srate_min &&
+ rate_min == srate_max);
+ same_channels = (channels_min == channels_max &&
+ channels_min == schannels_min &&
+ channels_min == schannels_max);
+ same_format = (mask_single(format_mask) &&
+ mask_eq(format_mask, sformat_mask));
+ if (same_rate)
+ links |= (SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE);
+ if (same_channels) {
+ links |= SND_PCM_HW_PARBIT_CHANNELS;
+ if (same_format)
+ links |= (SND_PCM_HW_PARBIT_FRAME_BITS |
+ SND_PCM_HW_PARBIT_FRAGMENT_BYTES |
+ SND_PCM_HW_PARBIT_BUFFER_BYTES);
+ }
+ if (same_format)
+ links |= (SND_PCM_HW_PARBIT_FORMAT |
+ SND_PCM_HW_PARBIT_SUBFORMAT |
+ SND_PCM_HW_PARBIT_SAMPLE_BITS);
+
+ if (same_rate && same_channels && same_format) {
+ const mask_t *access_mask = snd_pcm_hw_params_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+ mask_copy(tmp_mask, snd_pcm_hw_params_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS));
+ mask_intersect(tmp_mask, access_mask);
+ if (!mask_empty(tmp_mask))
+ _snd_pcm_hw_params_mask(sparams, 0,
+ SND_PCM_HW_PARAM_ACCESS,
+ access_mask);
+ else
+ _snd_pcm_hw_params_mask(sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ mmap_mask);
+ } else {
+ err = _snd_pcm_hw_params_mask(params, 1,
+ SND_PCM_HW_PARAM_ACCESS,
+ accplug_mask);
+ if (err < 0)
+ return err;
+ err = _snd_pcm_hw_params_mask(params, 1,
+ SND_PCM_HW_PARAM_FORMAT,
+ fmtplug_mask);
+ if (err < 0)
+ return err;
+ _snd_pcm_hw_params_mask(sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ mmap_mask);
+ _snd_pcm_hw_params_mask(sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ fmtplug_mask);
+ }
+ err = snd_pcm_hw_refine2(params, sparams,
+ snd_pcm_hw_refine, slave, links);
if (err < 0)
return err;
- info->info = sinfo.info & ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
- snd_pcm_hw_info_complete(info);
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
+
+
+static int snd_pcm_plug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+ snd_pcm_hw_params_t sparams;
+ return snd_pcm_plug_hw_refine1(pcm, params, &sparams);
+}
+
static void snd_pcm_plug_clear(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
}
}
-static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
+typedef struct {
+ unsigned int access;
+ unsigned int format;
+ unsigned int channels;
+ unsigned int rate;
+} snd_pcm_plug_params_t;
+
+static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
{
snd_pcm_plug_t *plug = pcm->private;
int err;
return 1;
}
-static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
+static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
{
snd_pcm_plug_t *plug = pcm->private;
unsigned int tt_ssize, tt_cused, tt_sused;
return 1;
}
-static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
+static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
{
snd_pcm_plug_t *plug = pcm->private;
int err, cfmt;
return 1;
}
-static int snd_pcm_plug_change_access(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
+static int snd_pcm_plug_change_access(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
{
snd_pcm_plug_t *plug = pcm->private;
int err;
}
static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
- snd_pcm_hw_params_t *client,
- snd_pcm_hw_params_t *slave)
+ snd_pcm_plug_params_t *client,
+ snd_pcm_plug_params_t *slave)
{
snd_pcm_plug_t *plug = pcm->private;
- int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *s, snd_pcm_hw_params_t *d) = {
+ int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *s, snd_pcm_plug_params_t *d) = {
snd_pcm_plug_change_format,
snd_pcm_plug_change_channels,
snd_pcm_plug_change_rate,
snd_pcm_plug_change_format,
snd_pcm_plug_change_access
};
- snd_pcm_hw_params_t p = *slave;
+ snd_pcm_plug_params_t p = *slave;
unsigned int k = 0;
while (client->format != p.format ||
client->channels != p.channels ||
{
snd_pcm_plug_t *plug = pcm->private;
snd_pcm_t *slave = plug->req_slave;
- snd_pcm_hw_info_t sinfo;
+ snd_pcm_plug_params_t clt_params, slv_params;
snd_pcm_hw_params_t sparams;
- int format;
- int err;
-
- sparams = *params;
- snd_pcm_hw_params_to_info(&sparams, &sinfo);
- sinfo.access_mask = ~0U;
- sinfo.format_mask = (SND_PCM_FMTBIT_LINEAR | SND_PCM_FMTBIT_MU_LAW |
- SND_PCM_FMTBIT_A_LAW | SND_PCM_FMTBIT_IMA_ADPCM);
- sinfo.subformat_mask = SND_PCM_SUBFMTBIT_STD;
- sinfo.channels_min = 1;
- sinfo.channels_max = UINT_MAX;
- sinfo.rate_min = RATE_MIN;
- sinfo.rate_max = RATE_MAX;
-
- err = snd_pcm_hw_info(slave, &sinfo);
- if (err < 0)
- return err;
-
- err = snd_pcm_hw_info_par_nearest_next(&sinfo,
- SND_PCM_HW_INFO_RATE,
- params->rate, -1,
- slave);
- if (err < 0)
- return err;
- sinfo.rate_min = sinfo.rate_max = err;
-
- err = snd_pcm_hw_info(slave, &sinfo);
- assert(err >= 0);
-
- err = snd_pcm_hw_info_par_nearest_next(&sinfo,
- SND_PCM_HW_INFO_CHANNELS,
- params->channels, -1,
- slave);
- if (err < 0)
- return err;
- sinfo.channels_min = sinfo.channels_max = err;
-
- err = snd_pcm_hw_info(slave, &sinfo);
+ int err = snd_pcm_plug_hw_refine1(pcm, params, &sparams);
assert(err >= 0);
- format = snd_pcm_plug_slave_format(params->format, sinfo.format_mask);
- assert(format >= 0);
+ clt_params.access = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_ACCESS);
+ clt_params.format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
+ clt_params.channels = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_CHANNELS);
+ clt_params.rate = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_RATE);
- sparams.format = format;
- assert(sinfo.rate_min == sinfo.rate_max);
- sparams.rate = sinfo.rate_min;
- assert(sinfo.channels_min == sinfo.channels_max);
- sparams.channels = sinfo.channels_min;
+ slv_params.access = snd_pcm_hw_params_first(slave, &sparams, SND_PCM_HW_PARAM_ACCESS);
+ slv_params.format = snd_pcm_hw_params_value(&sparams, SND_PCM_HW_PARAM_FORMAT);
+ slv_params.channels = snd_pcm_hw_params_value(&sparams, SND_PCM_HW_PARAM_CHANNELS);
+ slv_params.rate = snd_pcm_hw_params_value(&sparams, SND_PCM_HW_PARAM_RATE);
snd_pcm_plug_clear(pcm);
- if (params->format != sparams.format ||
- params->channels != sparams.channels ||
- params->rate != sparams.rate ||
- !(sinfo.access_mask & (1 << params->access))) {
- sinfo.access_mask &= SND_PCM_ACCBIT_MMAP;
- assert(sinfo.access_mask);
- sparams.access = ffs(sinfo.access_mask) - 1;
- err = snd_pcm_plug_insert_plugins(pcm, params, &sparams);
- if (err < 0)
- return err;
- }
-
+ err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params);
+ if (err < 0)
+ return err;
err = snd_pcm_hw_params(plug->slave, params);
if (err < 0) {
snd_pcm_plug_clear(pcm);
snd_pcm_ops_t snd_pcm_plug_ops = {
close: snd_pcm_plug_close,
info: snd_pcm_plug_info,
- hw_info: snd_pcm_plug_hw_info,
+ hw_refine: snd_pcm_plug_hw_refine,
hw_params: snd_pcm_plug_hw_params,
sw_params: snd_pcm_plug_sw_params,
dig_info: snd_pcm_plug_dig_info,
int put_index(int src_format, int dst_format);
int conv_index(int src_format, int dst_format);
-#define SND_PCM_FMTBIT_LINEAR (SND_PCM_FMTBIT_S8 |SND_PCM_FMTBIT_U8 | \
- SND_PCM_FMTBIT_S16_LE|SND_PCM_FMTBIT_S16_BE | \
- SND_PCM_FMTBIT_U16_LE|SND_PCM_FMTBIT_U16_BE | \
- SND_PCM_FMTBIT_S24_LE|SND_PCM_FMTBIT_S24_BE | \
- SND_PCM_FMTBIT_U24_LE|SND_PCM_FMTBIT_U24_BE | \
- SND_PCM_FMTBIT_S32_LE|SND_PCM_FMTBIT_S32_BE | \
- SND_PCM_FMTBIT_U32_LE|SND_PCM_FMTBIT_U32_BE)
+#define SND_PCM_FMTBIT_LINEAR \
+ ((1 << SND_PCM_FORMAT_S8 ) | (1 << SND_PCM_FORMAT_U8) | \
+ (1 << SND_PCM_FORMAT_S16_LE) | (1 << SND_PCM_FORMAT_S16_BE) | \
+ (1 << SND_PCM_FORMAT_U16_LE) | (1 << SND_PCM_FORMAT_U16_BE) | \
+ (1 << SND_PCM_FORMAT_S24_LE) | (1 << SND_PCM_FORMAT_S24_BE) | \
+ (1 << SND_PCM_FORMAT_U24_LE) | (1 << SND_PCM_FORMAT_U24_BE) | \
+ (1 << SND_PCM_FORMAT_S32_LE) | (1 << SND_PCM_FORMAT_S32_BE) | \
+ (1 << SND_PCM_FORMAT_U32_LE) | (1 << SND_PCM_FORMAT_U32_BE))
extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops;
snd_pcm_t *slave, int close_slave);
int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave);
+
+#define SND_PCM_ACCBIT_PLUGIN ((1 << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
+ (1 << SND_PCM_ACCESS_RW_INTERLEAVED) | \
+ (1 << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
+ (1 << SND_PCM_ACCESS_RW_NONINTERLEAVED))
+
return 0;
}
-static int snd_pcm_rate_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_rate_t *rate = pcm->private;
- unsigned int access_mask, format_mask;
- unsigned int rate_min, rate_max;
+ snd_pcm_t *slave = rate->plug.slave;
int err;
- info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
- SND_PCM_ACCBIT_RW_INTERLEAVED |
- SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
- SND_PCM_ACCBIT_RW_NONINTERLEAVED);
- access_mask = info->access_mask;
- if (access_mask == 0)
- return -EINVAL;
-
- info->format_mask &= SND_PCM_FMTBIT_LINEAR;
- format_mask = info->format_mask;
- if (format_mask == 0)
- return -EINVAL;
+ snd_pcm_hw_params_t sparams;
+ unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
+ mask_t *access_mask = alloca(mask_sizeof());
+ mask_t *format_mask = alloca(mask_sizeof());
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+ mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+ access_mask);
+ if (err < 0)
+ return err;
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_FORMAT,
+ format_mask);
+ if (err < 0)
+ return err;
+ err = _snd_pcm_hw_params_min(params, 1,
+ SND_PCM_HW_PARAM_RATE, RATE_MIN);
+ if (err < 0)
+ return err;
+ err = _snd_pcm_hw_params_max(params, 1,
+ SND_PCM_HW_PARAM_RATE, RATE_MAX);
+ if (err < 0)
+ return err;
- if (info->rate_min < RATE_MIN)
- info->rate_min = RATE_MIN;
- if (info->rate_max > RATE_MAX)
- info->rate_max = RATE_MAX;
- rate_min = info->rate_min;
- rate_max = info->rate_max;
- if (rate_max < rate_min)
- return -EINVAL;
-
- info->access_mask = SND_PCM_ACCBIT_MMAP;
- if (rate->sformat >= 0)
- info->format_mask = 1U << rate->sformat;
- info->rate_min = rate->srate;
- info->rate_max = rate->srate;
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ if (rate->sformat >= 0) {
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ rate->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ } else
+ links |= (SND_PCM_HW_PARBIT_FORMAT |
+ SND_PCM_HW_PARBIT_SUBFORMAT |
+ SND_PCM_HW_PARBIT_SAMPLE_BITS |
+ SND_PCM_HW_PARBIT_FRAME_BITS);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_RATE,
+ rate->srate);
- err = snd_pcm_hw_info(rate->plug.slave, info);
- if (rate->sformat >= 0)
- info->format_mask = format_mask;
- info->rate_min = rate_min;
- info->rate_max = rate_max;
-
+ err = snd_pcm_hw_refine2(params, &sparams,
+ snd_pcm_hw_refine, slave, links);
if (err < 0)
return err;
- info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
- snd_pcm_hw_info_complete(info);
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
{
snd_pcm_rate_t *rate = pcm->private;
snd_pcm_t *slave = rate->plug.slave;
- snd_pcm_hw_info_t sinfo;
+ int err;
snd_pcm_hw_params_t sparams;
+ unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
unsigned int src_format, dst_format;
unsigned int src_rate, dst_rate;
- int mul, div;
- int err;
- snd_pcm_hw_params_to_info(params, &sinfo);
- if (rate->sformat >= 0)
- sinfo.format_mask = 1 << rate->sformat;
- sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
- sinfo.rate_min = rate->srate;
- sinfo.rate_max = rate->srate;
- err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
- params->fail_mask = sparams.fail_mask;
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ if (rate->sformat >= 0) {
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ rate->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ } else
+ links |= (SND_PCM_HW_PARBIT_FORMAT |
+ SND_PCM_HW_PARBIT_SUBFORMAT |
+ SND_PCM_HW_PARBIT_SAMPLE_BITS |
+ SND_PCM_HW_PARBIT_FRAME_BITS);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_RATE,
+ rate->srate);
+
+ err = snd_pcm_hw_params2(params, &sparams,
+ snd_pcm_hw_params, slave, links);
if (err < 0)
return err;
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
- src_format = params->format;
+ src_format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
dst_format = slave->format;
- src_rate = params->rate;
+ src_rate = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_RATE);
dst_rate = slave->rate;
} else {
src_format = slave->format;
- dst_format = params->format;
+ dst_format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
src_rate = slave->rate;
- dst_rate = params->rate;
+ dst_rate = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_RATE);
}
rate->get_idx = get_index(src_format, SND_PCM_FORMAT_S16);
rate->put_idx = put_index(SND_PCM_FORMAT_S16, dst_format);
/* pitch is get_increment */
}
rate->pitch = (((u_int64_t)dst_rate * DIV) + src_rate / 2) / src_rate;
- if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
- mul = DIV;
- div = rate->pitch;
- } else {
- mul = rate->pitch;
- div = DIV;
- }
if (rate->states)
free(rate->states);
- rate->states = malloc(params->channels * sizeof(*rate->states));
+ rate->states = malloc(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_CHANNELS) * sizeof(*rate->states));
return 0;
}
snd_pcm_ops_t snd_pcm_rate_ops = {
close: snd_pcm_rate_close,
info: snd_pcm_plugin_info,
- hw_info: snd_pcm_rate_hw_info,
+ hw_refine: snd_pcm_rate_hw_refine,
hw_params: snd_pcm_rate_hw_params,
sw_params: snd_pcm_rate_sw_params,
dig_info: snd_pcm_plugin_dig_info,
return 0;
}
-static int snd_pcm_route_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
+static int snd_pcm_route_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_route_t *route = pcm->private;
- unsigned int format_mask, access_mask;
- unsigned int channels_min, channels_max;
+ snd_pcm_t *slave = route->plug.slave;
int err;
- info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
- SND_PCM_ACCBIT_RW_INTERLEAVED |
- SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
- SND_PCM_ACCBIT_RW_NONINTERLEAVED);
- access_mask = info->access_mask;
- if (access_mask == 0)
- return -EINVAL;
-
- info->format_mask &= SND_PCM_FMTBIT_LINEAR;
- format_mask = info->format_mask;
- if (format_mask == 0)
- return -EINVAL;
-
- if (info->channels_min < 1)
- info->channels_min = 1;
- channels_min = info->channels_min;
- channels_max = info->channels_max;
- if (channels_min > channels_max)
- return -EINVAL;
+ snd_pcm_hw_params_t sparams;
+ unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+ SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
+ mask_t *access_mask = alloca(mask_sizeof());
+ mask_t *format_mask = alloca(mask_sizeof());
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+ mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+ access_mask);
+ if (err < 0)
+ return err;
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_FORMAT,
+ format_mask);
+ if (err < 0)
+ return err;
+ err = _snd_pcm_hw_params_min(params, 1, SND_PCM_HW_PARAM_CHANNELS, 1);
+ if (err < 0)
+ return err;
- if (route->sformat >= 0)
- info->format_mask = 1U << route->sformat;
- if (route->schannels >= 0)
- info->channels_min = info->channels_max = route->schannels;
-
- info->access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_info(route->plug.slave, info);
- info->access_mask = access_mask;
- if (route->sformat >= 0)
- info->format_mask = format_mask;
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ if (route->sformat >= 0) {
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ route->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ } else
+ links |= (SND_PCM_HW_PARBIT_FORMAT |
+ SND_PCM_HW_PARBIT_SUBFORMAT |
+ SND_PCM_HW_PARBIT_SAMPLE_BITS);
if (route->schannels >= 0) {
- info->channels_min = channels_min;
- info->channels_max = channels_max;
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_CHANNELS,
+ route->schannels);
+ } else {
+ links |= SND_PCM_HW_PARBIT_CHANNELS;
+ if (route->sformat < 0)
+ links |= (SND_PCM_HW_PARBIT_FRAME_BITS |
+ SND_PCM_HW_PARBIT_FRAGMENT_BYTES |
+ SND_PCM_HW_PARBIT_BUFFER_BYTES);
}
+
+ err = snd_pcm_hw_refine2(params, &sparams,
+ snd_pcm_hw_refine, slave, links);
if (err < 0)
return err;
- info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
- snd_pcm_hw_info_complete(info);
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
{
snd_pcm_route_t *route = pcm->private;
snd_pcm_t *slave = route->plug.slave;
- unsigned int src_format, dst_format;
- snd_pcm_hw_info_t sinfo;
- snd_pcm_hw_params_t sparams;
int err;
- snd_pcm_hw_params_to_info(params, &sinfo);
- if (route->sformat >= 0)
- sinfo.format_mask = 1 << route->sformat;
- if (route->schannels >= 0)
- sinfo.channels_min = sinfo.channels_max = route->schannels;
- sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
- params->fail_mask = sparams.fail_mask;
+ snd_pcm_hw_params_t sparams;
+ unsigned int links = (SND_PCM_HW_PARBIT_FRAGMENTS |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH);
+ unsigned int src_format, dst_format;
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ if (route->sformat >= 0) {
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+ route->sformat);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+ SND_PCM_SUBFORMAT_STD);
+ } else
+ links |= (SND_PCM_HW_PARBIT_FORMAT |
+ SND_PCM_HW_PARBIT_SUBFORMAT |
+ SND_PCM_HW_PARBIT_SAMPLE_BITS);
+ if (route->schannels >= 0) {
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_CHANNELS,
+ route->schannels);
+ } else {
+ links |= SND_PCM_HW_PARBIT_CHANNELS;
+ if (route->sformat < 0)
+ links |= (SND_PCM_HW_PARBIT_FRAME_BITS |
+ SND_PCM_HW_PARBIT_FRAGMENT_BYTES |
+ SND_PCM_HW_PARBIT_BUFFER_BYTES);
+ }
+
+ err = snd_pcm_hw_params2(params, &sparams,
+ snd_pcm_hw_params, slave, links);
if (err < 0)
return err;
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
- src_format = params->format;
+ src_format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
dst_format = slave->format;
} else {
src_format = slave->format;
- dst_format = params->format;
+ dst_format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
}
route->params.get_idx = get_index(src_format, SND_PCM_FORMAT_U16);
route->params.put_idx = put_index(SND_PCM_FORMAT_U32, dst_format);
snd_pcm_ops_t snd_pcm_route_ops = {
close: snd_pcm_route_close,
info: snd_pcm_plugin_info,
- hw_info: snd_pcm_route_hw_info,
+ hw_refine: snd_pcm_route_hw_refine,
hw_params: snd_pcm_route_hw_params,
sw_params: snd_pcm_plugin_sw_params,
dig_info: snd_pcm_plugin_dig_info,
return snd_pcm_info(share->slave->pcm, info);
}
-static int snd_pcm_share_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
+static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
- unsigned int access_mask;
- int err = 0;
- info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
- SND_PCM_ACCBIT_RW_INTERLEAVED |
- SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
- SND_PCM_ACCBIT_RW_NONINTERLEAVED);
- access_mask = info->access_mask;
- if (access_mask == 0)
- return -EINVAL;
+ snd_pcm_hw_params_t sparams;
+ int err;
+ mask_t *access_mask = alloca(mask_sizeof());
+ const mask_t *mmap_mask;
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_CHANNELS,
+ share->channels_count);
+ if (err < 0)
+ return err;
if (slave->format >= 0) {
- info->format_mask &= 1U << slave->format;
- if (!info->format_mask)
- return -EINVAL;
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_FORMAT,
+ slave->format);
+ if (err < 0)
+ return err;
}
- if (info->channels_min < share->channels_count)
- info->channels_min = share->channels_count;
- if (info->channels_max > share->channels_count)
- info->channels_max = share->channels_count;
- if (info->channels_min > info->channels_max)
- return -EINVAL;
-
if (slave->rate >= 0) {
- if (info->rate_min < (unsigned)slave->rate)
- info->rate_min = slave->rate;
- if (info->rate_max > (unsigned)slave->rate)
- info->rate_max = slave->rate;
- if (info->rate_min > info->rate_max)
- return -EINVAL;
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_RATE,
+ slave->rate);
+ if (err < 0)
+ return err;
}
- info->access_mask = SND_PCM_ACCBIT_MMAP;
- info->channels_min = info->channels_max = slave->channels_count;
- err = snd_pcm_hw_info(slave->pcm, info);
- info->access_mask = access_mask;
- info->channels_min = info->channels_max = share->channels_count;
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_CHANNELS,
+ slave->channels_count);
+ err = snd_pcm_hw_refine2(params, &sparams,
+ snd_pcm_hw_refine, slave->pcm,
+ SND_PCM_HW_PARBIT_FORMAT |
+ SND_PCM_HW_PARBIT_SUBFORMAT |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH |
+ SND_PCM_HW_PARBIT_FRAGMENTS);
+ if (err < 0)
+ return err;
+ mmap_mask = snd_pcm_hw_params_value_mask(&sparams, SND_PCM_HW_PARAM_ACCESS);
+ mask_all(access_mask);
+ mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+ if (!mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
+ mask_reset(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+ if (!mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_COMPLEX) &&
+ !mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
+ mask_reset(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
+ err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+ access_mask);
if (err < 0)
return err;
- info->info |= SND_PCM_INFO_DOUBLE;
+ params->info |= SND_PCM_INFO_DOUBLE;
return 0;
}
Pthread_mutex_lock(&slave->mutex);
if (slave->setup_count > 1 ||
(slave->setup_count == 1 && !pcm->setup)) {
- if (params->format != spcm->format)
- params->fail_mask |= SND_PCM_HW_PARBIT_FORMAT;
- if (params->subformat != spcm->subformat)
- params->fail_mask |= SND_PCM_HW_PARBIT_SUBFORMAT;
- if (params->rate != spcm->rate)
- params->fail_mask |= SND_PCM_HW_PARBIT_RATE;
- if (params->fragments != spcm->fragments)
- params->fail_mask |= SND_PCM_HW_PARBIT_FRAGMENTS;
- if (params->fragment_size != spcm->fragment_size)
- params->fail_mask |= SND_PCM_HW_PARBIT_FRAGMENT_SIZE;
- if (params->fail_mask) {
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_FORMAT,
+ spcm->format);
+ if (err < 0)
+ goto _err;
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_SUBFORMAT,
+ spcm->subformat);
+ if (err < 0)
+ goto _err;
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_RATE,
+ spcm->rate);
+ if (err < 0)
+ goto _err;
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+ spcm->fragment_size);
+ if (err < 0)
+ goto _err;
+ err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_FRAGMENTS,
+ spcm->fragments);
+ _err:
+ if (err < 0) {
ERR("slave is already running with different setup");
err = -EBUSY;
goto _end;
}
} else {
- snd_pcm_hw_params_t sparams = *params;
- sparams.channels = slave->channels_count;
- err = snd_pcm_hw_params(slave->pcm, &sparams);
+ snd_pcm_hw_params_t sparams;
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ _snd_pcm_hw_params_any(&sparams);
+ _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_CHANNELS,
+ share->channels_count);
+ err = snd_pcm_hw_params2(params, &sparams,
+ snd_pcm_hw_params, slave->pcm,
+ SND_PCM_HW_PARBIT_FORMAT |
+ SND_PCM_HW_PARBIT_SUBFORMAT |
+ SND_PCM_HW_PARBIT_RATE |
+ SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+ SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+ SND_PCM_HW_PARBIT_BUFFER_SIZE |
+ SND_PCM_HW_PARBIT_BUFFER_LENGTH |
+ SND_PCM_HW_PARBIT_FRAGMENTS);
if (err < 0)
goto _end;
/* >= 30 ms */
- slave->safety_threshold = sparams.rate * 30 / 1000;
- slave->safety_threshold += sparams.fragment_size - 1;
- slave->safety_threshold -= slave->safety_threshold % sparams.fragment_size;
+ slave->safety_threshold = slave->pcm->rate * 30 / 1000;
+ slave->safety_threshold += slave->pcm->fragment_size - 1;
+ slave->safety_threshold -= slave->safety_threshold % slave->pcm->fragment_size;
slave->silence_frames = slave->safety_threshold;
if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->channels, slave->pcm->buffer_size, slave->pcm->format);
static int snd_pcm_share_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params)
{
if (params->start_mode > SND_PCM_START_LAST) {
- params->fail_mask = SND_PCM_SW_PARBIT_START_MODE;
+ params->fail_mask = 1 << SND_PCM_SW_PARAM_START_MODE;
return -EINVAL;
}
if (params->ready_mode > SND_PCM_READY_LAST) {
- params->fail_mask = SND_PCM_SW_PARBIT_READY_MODE;
+ params->fail_mask = 1 << SND_PCM_SW_PARAM_READY_MODE;
return -EINVAL;
}
if (params->xrun_mode > SND_PCM_XRUN_LAST) {
- params->fail_mask = SND_PCM_SW_PARBIT_XRUN_MODE;
+ params->fail_mask = 1 << SND_PCM_SW_PARAM_XRUN_MODE;
return -EINVAL;
}
return 0;
snd_pcm_ops_t snd_pcm_share_ops = {
close: snd_pcm_share_close,
info: snd_pcm_share_info,
- hw_info: snd_pcm_share_hw_info,
+ hw_refine: snd_pcm_share_hw_refine,
hw_params: snd_pcm_share_hw_params,
sw_params: snd_pcm_share_sw_params,
dig_info: snd_pcm_share_dig_info,
typedef struct {
int socket;
volatile snd_pcm_shm_ctrl_t *ctrl;
- unsigned int access_mask;
} snd_pcm_shm_t;
int receive_fd(int socket, void *data, size_t len, int *fd)
return err;
}
-static int snd_pcm_shm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int _snd_pcm_shm_hw_refine(snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
{
snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
- int err;
- unsigned int access_mask = info->access_mask;
- ctrl->cmd = SND_PCM_IOCTL_HW_INFO;
- ctrl->u.hw_info = *info;
- ctrl->u.hw_info.access_mask = SND_PCM_ACCBIT_MMAP;
- err = snd_pcm_shm_action(pcm);
- if (err < 0)
- return err;
- access_mask &= (SND_PCM_ACCESS_RW_INTERLEAVED |
- SND_PCM_ACCESS_RW_NONINTERLEAVED |
- ctrl->u.hw_info.access_mask);
- if (!access_mask)
- return -EINVAL;
- *info = ctrl->u.hw_info;
- shm->access_mask = info->access_mask;
- info->access_mask = access_mask;
- return 0;
+ ctrl->cmd = SND_PCM_IOCTL_HW_REFINE;
+ return snd_pcm_shm_action(pcm);
}
-static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
+static int snd_pcm_shm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+ snd_pcm_shm_t *shm = pcm->private;
+ volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
+ snd_pcm_hw_params_t *sparams = (snd_pcm_hw_params_t *) &ctrl->u.hw_refine;
+ const mask_t *access_mask = snd_pcm_hw_params_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
+ !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
+ mask_intersect(saccess_mask, access_mask);
+ _snd_pcm_hw_params_any(sparams);
+ _snd_pcm_hw_params_mask(sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ return snd_pcm_hw_refine2(params, sparams,
+ _snd_pcm_shm_hw_refine, pcm,
+ ~SND_PCM_HW_PARBIT_ACCESS);
+}
+
+static int _snd_pcm_shm_hw_params(snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
{
snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
- unsigned int access = params->access;
- int err;
ctrl->cmd = SND_PCM_IOCTL_HW_PARAMS;
- ctrl->u.hw_params = *params;
- if (shm->access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
- ctrl->u.hw_params.access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
- else if (shm->access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
- ctrl->u.hw_params.access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
- else
- assert(0);
- err = snd_pcm_shm_action(pcm);
- params->access = access;
- *params = ctrl->u.hw_params;
- if (err < 0)
- return err;
- return err;
+ return snd_pcm_shm_action(pcm);
+}
+
+static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
+{
+ snd_pcm_shm_t *shm = pcm->private;
+ volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
+ snd_pcm_hw_params_t *sparams = (snd_pcm_hw_params_t *) &ctrl->u.hw_refine;
+ const mask_t *access_mask = snd_pcm_hw_params_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+ mask_t *saccess_mask = alloca(mask_sizeof());
+ mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+ if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
+ !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
+ mask_intersect(saccess_mask, access_mask);
+ _snd_pcm_hw_params_any(sparams);
+ _snd_pcm_hw_params_mask(sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+ saccess_mask);
+ return snd_pcm_hw_params2(params, sparams,
+ _snd_pcm_shm_hw_params, pcm,
+ ~SND_PCM_HW_PARBIT_ACCESS);
}
static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
snd_pcm_ops_t snd_pcm_shm_ops = {
close: snd_pcm_shm_close,
info: snd_pcm_shm_info,
- hw_info: snd_pcm_shm_hw_info,
+ hw_refine: snd_pcm_shm_hw_refine,
hw_params: snd_pcm_shm_hw_params,
sw_params: snd_pcm_shm_sw_params,
dig_info: snd_pcm_shm_dig_info,