mirror of
https://gitee.com/openharmony/third_party_alsa-lib
synced 2024-11-27 01:31:08 +00:00
New hw_params implementation
This commit is contained in:
parent
2fe1219099
commit
8dd927e97f
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
297
src/pcm/interval.c
Normal 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
50
src/pcm/interval.h
Normal 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
93
src/pcm/interval_inline.h
Normal 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
30
src/pcm/mask.c
Normal 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
57
src/pcm/mask.h
Normal 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
233
src/pcm/mask_inline.h
Normal 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);
|
||||
}
|
1254
src/pcm/pcm.c
1254
src/pcm/pcm.c
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
1689
src/pcm/pcm_params.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user