New hw_params implementation

This commit is contained in:
Abramo Bagnara 2000-12-21 20:44:10 +00:00
parent 2fe1219099
commit 8dd927e97f
28 changed files with 3550 additions and 1899 deletions

View File

@ -379,8 +379,8 @@ int pcm_shm_cmd(client_t *client)
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);

View File

@ -42,7 +42,7 @@ typedef struct {
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;

View File

@ -35,18 +35,6 @@ typedef enum _snd_pcm_type {
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 */
@ -69,8 +57,7 @@ int snd_pcm_poll_descriptor(snd_pcm_t *pcm);
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);
@ -92,7 +79,7 @@ ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size);
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);
@ -103,8 +90,58 @@ int snd_pcm_unlink(snd_pcm_t *pcm);
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;
@ -114,7 +151,7 @@ typedef struct _snd_pcm_strategy_simple_choices_list {
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);
@ -129,9 +166,9 @@ 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);
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);
@ -147,7 +184,12 @@ ssize_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, size_t size);
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);

View File

@ -1,11 +1,13 @@
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

297
src/pcm/interval.c Normal file
View File

@ -0,0 +1,297 @@
/*
* 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 ? ')' : ']');
}
}

50
src/pcm/interval.h Normal file
View File

@ -0,0 +1,50 @@
/*
* 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);

93
src/pcm/interval_inline.h Normal file
View File

@ -0,0 +1,93 @@
/*
* 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;
}

30
src/pcm/mask.c Normal file
View File

@ -0,0 +1,30 @@
/*
* 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"

57
src/pcm/mask.h Normal file
View File

@ -0,0 +1,57 @@
/*
* 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);

233
src/pcm/mask_inline.h Normal file
View File

@ -0,0 +1,233 @@
/*
* 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);
}

File diff suppressed because it is too large Load Diff

View File

@ -329,35 +329,59 @@ static int snd_pcm_adpcm_close(snd_pcm_t *pcm)
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;
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_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);
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;
_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;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
@ -365,19 +389,33 @@ static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
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);
@ -385,7 +423,7 @@ static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
}
} 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);
@ -394,7 +432,7 @@ static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
}
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;
}
@ -495,7 +533,7 @@ static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -211,35 +211,59 @@ static void alaw_encode(const snd_pcm_channel_area_t *src_areas,
}
}
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;
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_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);
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;
_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;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
@ -247,27 +271,41 @@ static int snd_pcm_alaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
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);
@ -363,7 +401,7 @@ static void snd_pcm_alaw_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -28,40 +28,50 @@ typedef struct {
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;
}
@ -149,7 +159,7 @@ static void snd_pcm_copy_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -254,10 +254,10 @@ static int snd_pcm_file_set_avail_min(snd_pcm_t *pcm, size_t frames)
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)
@ -314,7 +314,7 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -109,7 +109,7 @@ static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid)
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;
@ -120,12 +120,12 @@ static int _snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
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;
@ -521,8 +521,8 @@ static void snd_pcm_hw_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -72,32 +72,50 @@ static void linear_transfer(const snd_pcm_channel_area_t *src_areas, size_t src_
}
}
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;
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_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;
info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
snd_pcm_hw_info_complete(info);
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;
_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;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
@ -105,22 +123,36 @@ static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
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;
}
@ -208,7 +240,7 @@ static void snd_pcm_linear_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -1,6 +1,7 @@
/*
* 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
@ -58,7 +59,7 @@ typedef struct {
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);
@ -168,15 +169,9 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas,
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)
{
@ -316,3 +311,50 @@ static inline int muldiv_near(int a, int b, int c)
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))

View File

@ -228,35 +228,59 @@ static void mulaw_encode(const snd_pcm_channel_area_t *src_areas,
}
}
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;
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_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);
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;
_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;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
@ -264,19 +288,33 @@ static int snd_pcm_mulaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
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);
@ -284,7 +322,7 @@ static int snd_pcm_mulaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
}
} 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);
@ -380,7 +418,7 @@ static void snd_pcm_mulaw_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -26,6 +26,7 @@
#include <errno.h>
#include <math.h>
#include "pcm_local.h"
#include "interval.h"
typedef struct {
snd_pcm_t *pcm;
@ -90,83 +91,109 @@ static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
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;
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;
return 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);
}
}
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_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;
@ -376,7 +403,7 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -230,10 +230,11 @@ static int snd_pcm_null_set_avail_min(snd_pcm_t *pcm, size_t frames)
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;
}
@ -245,15 +246,15 @@ static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_pa
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;
@ -306,7 +307,7 @@ static void snd_pcm_null_dump(snd_pcm_t *pcm, FILE *fp)
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,

1689
src/pcm/pcm_params.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -118,12 +118,14 @@ static unsigned int nonlinear_preferred_formats[] = {
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:
@ -131,7 +133,7 @@ static int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
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 */
@ -140,11 +142,12 @@ static int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
}
}
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;
@ -161,7 +164,7 @@ static int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
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;
}
@ -177,125 +180,181 @@ static int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
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_info(slave, &sinfo);
if (err < 0)
goto _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);
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);
assert(err >= 0);
format_mask = 0;
for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
int f;
if (!(info->format_mask & (1 << format)))
continue;
f = snd_pcm_plug_slave_format(format, sinfo.format_mask);
assert(f >= 0);
format_mask |= (1 << f);
}
sinfo.format_mask = format_mask;
err = snd_pcm_hw_info(slave, &sinfo);
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;
err = _snd_pcm_hw_params_min(params, 1, SND_PCM_HW_PARAM_CHANNELS, 1);
if (err < 0)
return err;
info->info = sinfo.info & ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
snd_pcm_hw_info_complete(info);
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;
_snd_pcm_hw_params_any(sparams);
err = snd_pcm_hw_refine2(params, sparams,
snd_pcm_hw_refine, slave, links);
if (err < 0)
return err;
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_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 = 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 (!mask_test(format_mask, format))
continue;
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);
}
err = _snd_pcm_hw_params_mask(sparams, 0,
SND_PCM_HW_PARAM_FORMAT, tmp_mask);
assert(err >= 0);
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;
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;
@ -309,7 +368,14 @@ static void snd_pcm_plug_clear(snd_pcm_t *pcm)
}
}
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;
@ -326,7 +392,7 @@ static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_
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;
@ -391,7 +457,7 @@ static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm
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;
@ -451,7 +517,7 @@ static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_h
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;
@ -465,11 +531,11 @@ static int snd_pcm_plug_change_access(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_h
}
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,
@ -477,7 +543,7 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
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 ||
@ -505,70 +571,25 @@ static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
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);
int err = snd_pcm_plug_hw_refine1(pcm, params, &sparams);
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;
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);
err = snd_pcm_hw_info(slave, &sinfo);
assert(err >= 0);
format = snd_pcm_plug_slave_format(params->format, sinfo.format_mask);
assert(format >= 0);
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);
@ -638,7 +659,7 @@ static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -64,13 +64,14 @@ int get_index(int src_format, int dst_format);
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;
@ -107,3 +108,9 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, char *name,
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))

View File

@ -233,50 +233,60 @@ static int snd_pcm_rate_close(snd_pcm_t *pcm)
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;
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;
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;
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;
info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
snd_pcm_hw_info_complete(info);
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;
_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_refine2(params, &sparams,
snd_pcm_hw_refine, slave, links);
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
@ -284,32 +294,48 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
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);
@ -321,16 +347,9 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
/* 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;
}
@ -493,7 +512,7 @@ static void snd_pcm_rate_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -425,50 +425,64 @@ static int snd_pcm_route_close(snd_pcm_t *pcm)
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;
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;
if (route->schannels >= 0) {
info->channels_min = channels_min;
info->channels_max = channels_max;
}
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;
info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
snd_pcm_hw_info_complete(info);
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;
_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_refine2(params, &sparams,
snd_pcm_hw_refine, slave, links);
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
@ -476,26 +490,51 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
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);
@ -622,7 +661,7 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -442,50 +442,66 @@ static int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *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);
if (slave->format >= 0) {
info->format_mask &= 1U << slave->format;
if (!info->format_mask)
return -EINVAL;
}
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;
}
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;
err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_CHANNELS,
share->channels_count);
if (err < 0)
return err;
info->info |= SND_PCM_INFO_DOUBLE;
if (slave->format >= 0) {
err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_FORMAT,
slave->format);
if (err < 0)
return err;
}
if (slave->rate >= 0) {
err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_RATE,
slave->rate);
if (err < 0)
return err;
}
_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;
params->info |= SND_PCM_INFO_DOUBLE;
return 0;
}
@ -498,31 +514,55 @@ static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
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);
@ -537,15 +577,15 @@ static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
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;
@ -1067,7 +1107,7 @@ static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
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,

View File

@ -42,7 +42,6 @@
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)
@ -148,49 +147,60 @@ static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
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_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;
ctrl->cmd = SND_PCM_IOCTL_HW_PARAMS;
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;
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;
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)
@ -461,7 +471,7 @@ static void snd_pcm_shm_dump(snd_pcm_t *pcm, FILE *fp)
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,