mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Added dump facility. Continued pcm_multi implementation
This commit is contained in:
parent
d379686996
commit
84cb338f83
9 changed files with 360 additions and 68 deletions
|
|
@ -146,6 +146,7 @@ ssize_t snd_pcm_read(snd_pcm_t *handle, void *buffer, size_t size);
|
|||
ssize_t snd_pcm_writev(snd_pcm_t *handle, const struct iovec *vector, unsigned long count);
|
||||
ssize_t snd_pcm_readv(snd_pcm_t *handle, const struct iovec *vector, unsigned long count);
|
||||
int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp);
|
||||
int snd_pcm_dump(snd_pcm_t *handle, FILE *fp);
|
||||
|
||||
int snd_pcm_channels_mask(snd_pcm_t *handle, bitset_t *client_vmask);
|
||||
|
||||
|
|
@ -176,9 +177,9 @@ ssize_t snd_pcm_mmap_read_frames(snd_pcm_t *handle, const void *buffer, size_t f
|
|||
int snd_pcm_mmap_get_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *areas);
|
||||
|
||||
|
||||
const char *snd_pcm_get_format_name(int format);
|
||||
const char *snd_pcm_get_format_description(int format);
|
||||
int snd_pcm_get_format_value(const char* name);
|
||||
const char *snd_pcm_format_name(int format);
|
||||
const char *snd_pcm_format_description(int format);
|
||||
int snd_pcm_format_value(const char* name);
|
||||
|
||||
int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
|
||||
size_t samples, int format);
|
||||
|
|
@ -274,6 +275,7 @@ struct snd_stru_pcm_plugin {
|
|||
int (*parameter_get)(snd_pcm_plugin_t *plugin,
|
||||
const char *name,
|
||||
unsigned long *value);
|
||||
void (*dump)(snd_pcm_plugin_t *plugin, FILE *fp);
|
||||
snd_pcm_plugin_t *prev;
|
||||
snd_pcm_plugin_t *next;
|
||||
snd_pcm_plug_t *plug;
|
||||
|
|
@ -290,15 +292,11 @@ struct snd_stru_pcm_plugin {
|
|||
int snd_pcm_plug_create(snd_pcm_t **handle, snd_pcm_t *slave, int close_slave);
|
||||
int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode);
|
||||
int snd_pcm_plug_open(snd_pcm_t **handle, int card, int device, int stream, int mode);
|
||||
int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
|
||||
snd_pcm_t **slaves_handle, size_t *slaves_channels_count,
|
||||
size_t binds_count, unsigned int *binds_client_channel,
|
||||
unsigned int *binds_slave, unsigned int *binds_slave_channel,
|
||||
int close_slaves);
|
||||
|
||||
int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin);
|
||||
int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin);
|
||||
int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin);
|
||||
void snd_pcm_plugin_dump(snd_pcm_plugin_t *plugin, FILE *fp);
|
||||
int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, size_t frames);
|
||||
int snd_pcm_plug_clear(snd_pcm_plug_t *plug);
|
||||
snd_pcm_plugin_t *snd_pcm_plug_first(snd_pcm_plug_t *plug);
|
||||
|
|
@ -371,6 +369,12 @@ int snd_pcm_plugin_build_copy(snd_pcm_plug_t *plug,
|
|||
snd_pcm_format_t *dst_format,
|
||||
snd_pcm_plugin_t **r_plugin);
|
||||
|
||||
int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
|
||||
snd_pcm_t **slaves_handle, size_t *slaves_channels_count,
|
||||
size_t binds_count, unsigned int *binds_client_channel,
|
||||
unsigned int *binds_slave, unsigned int *binds_slave_channel,
|
||||
int close_slaves);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ ssize_t snd_pcm_writev(snd_pcm_t *handle, const struct iovec *vector, unsigned l
|
|||
assert(handle);
|
||||
assert(count == 0 || vector);
|
||||
assert(handle->valid_setup);
|
||||
assert(handle->setup.format.interleave ||
|
||||
count % handle->setup.format.channels == 0);
|
||||
return handle->ops->writev(handle->op_arg, -1, vector, count);
|
||||
}
|
||||
|
||||
|
|
@ -366,6 +368,7 @@ int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp)
|
|||
{
|
||||
snd_pcm_setup_t *setup;
|
||||
assert(handle);
|
||||
assert(fp);
|
||||
assert(handle->valid_setup);
|
||||
setup = &handle->setup;
|
||||
fprintf(fp, "stream: %s\n", assoc(handle->stream, streams));
|
||||
|
|
@ -392,7 +395,15 @@ int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const char *snd_pcm_get_format_name(int format)
|
||||
int snd_pcm_dump(snd_pcm_t *handle, FILE *fp)
|
||||
{
|
||||
assert(handle);
|
||||
assert(fp);
|
||||
handle->ops->dump(handle->op_arg, fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *snd_pcm_format_name(int format)
|
||||
{
|
||||
assoc_t *a = assoc_value(format, fmts);
|
||||
if (a)
|
||||
|
|
@ -400,7 +411,7 @@ const char *snd_pcm_get_format_name(int format)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const char *snd_pcm_get_format_description(int format)
|
||||
const char *snd_pcm_format_description(int format)
|
||||
{
|
||||
assoc_t *a = assoc_value(format, fmts);
|
||||
if (a)
|
||||
|
|
@ -408,7 +419,7 @@ const char *snd_pcm_get_format_description(int format)
|
|||
return "Unknown";
|
||||
}
|
||||
|
||||
int snd_pcm_get_format_value(const char* name)
|
||||
int snd_pcm_format_value(const char* name)
|
||||
{
|
||||
assoc_t *a = assoc_name(name, fmts);
|
||||
if (a)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
typedef struct {
|
||||
snd_pcm_t *handle;
|
||||
int fd;
|
||||
int card, device, subdevice;
|
||||
} snd_pcm_hw_t;
|
||||
|
||||
#define SND_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
|
||||
|
|
@ -330,6 +331,21 @@ static int snd_pcm_hw_channels_mask(void *private UNUSED,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void snd_pcm_hw_dump(void *private, FILE *fp)
|
||||
{
|
||||
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
|
||||
snd_pcm_t *handle = hw->handle;
|
||||
char *name = "Unknown";
|
||||
snd_card_get_name(hw->card, &name);
|
||||
fprintf(fp, "Hardware PCM card %d '%s' device %d subdevice %d\n",
|
||||
hw->card, name, hw->device, hw->subdevice);
|
||||
free(name);
|
||||
if (handle->valid_setup) {
|
||||
fprintf(fp, "\nIts setup is:\n");
|
||||
snd_pcm_dump_setup(handle, fp);
|
||||
}
|
||||
}
|
||||
|
||||
struct snd_pcm_ops snd_pcm_hw_ops = {
|
||||
close: snd_pcm_hw_close,
|
||||
nonblock: snd_pcm_hw_nonblock,
|
||||
|
|
@ -359,6 +375,7 @@ struct snd_pcm_ops snd_pcm_hw_ops = {
|
|||
munmap_data: snd_pcm_hw_munmap_data,
|
||||
file_descriptor: snd_pcm_hw_file_descriptor,
|
||||
channels_mask: snd_pcm_hw_channels_mask,
|
||||
dump: snd_pcm_hw_dump,
|
||||
};
|
||||
|
||||
int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int subdevice, int stream, int mode)
|
||||
|
|
@ -436,6 +453,9 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
|
|||
goto __end;
|
||||
}
|
||||
hw->handle = handle;
|
||||
hw->card = card;
|
||||
hw->device = device;
|
||||
hw->subdevice = subdevice;
|
||||
hw->fd = fd;
|
||||
handle->type = SND_PCM_TYPE_HW;
|
||||
handle->stream = stream;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ struct snd_pcm_ops {
|
|||
int (*munmap_data)(void *private, void *buffer, size_t bsize);
|
||||
int (*file_descriptor)(void *private);
|
||||
int (*channels_mask)(void *private, bitset_t *client_vmask);
|
||||
void (*dump)(void *private, FILE *fp);
|
||||
};
|
||||
|
||||
struct snd_pcm {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ typedef struct {
|
|||
size_t binds_count;
|
||||
snd_pcm_multi_bind_t *binds;
|
||||
size_t channels_count;
|
||||
size_t frames_alloc;
|
||||
int interleave;
|
||||
int one_to_many;
|
||||
} snd_pcm_multi_t;
|
||||
|
|
@ -99,6 +100,7 @@ static int snd_pcm_multi_info(void *private, snd_pcm_info_t *info)
|
|||
for (i = 1; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_t *handle_i = multi->slaves[i].handle;
|
||||
snd_pcm_info_t info_i;
|
||||
memset(&info_i, 0, sizeof(info_i));
|
||||
err = snd_pcm_info(handle_i, &info_i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
@ -115,12 +117,17 @@ static int snd_pcm_multi_params_info(void *private, snd_pcm_params_info_t *info)
|
|||
unsigned int i;
|
||||
int err;
|
||||
snd_pcm_t *handle_0 = multi->slaves[0].handle;
|
||||
unsigned int old_mask = info->req_mask;
|
||||
info->req_mask &= ~SND_PCM_PARAMS_CHANNELS;
|
||||
err = snd_pcm_params_info(handle_0, info);
|
||||
if (err < 0)
|
||||
return err;
|
||||
info->min_channels = multi->channels_count;
|
||||
info->max_channels = multi->channels_count;
|
||||
for (i = 1; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_t *handle_i = multi->slaves[i].handle;
|
||||
snd_pcm_params_info_t info_i;
|
||||
info_i = *info;
|
||||
err = snd_pcm_params_info(handle_i, &info_i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
@ -141,6 +148,7 @@ static int snd_pcm_multi_params_info(void *private, snd_pcm_params_info_t *info)
|
|||
if (info_i.max_fragments < info->max_fragments)
|
||||
info->max_fragments = info_i.max_fragments;
|
||||
}
|
||||
info->req_mask = old_mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +174,9 @@ static int snd_pcm_multi_params(void *private, snd_pcm_params_t *params)
|
|||
else if (!(info.flags & SND_PCM_INFO_NONINTERLEAVE))
|
||||
p.format.interleave = 1;
|
||||
p.format.channels = multi->slaves[i].channels_total;
|
||||
#if 1
|
||||
p.frames_xrun_max = ~0;
|
||||
#endif
|
||||
err = snd_pcm_params(handle, &p);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
@ -186,9 +197,12 @@ static int snd_pcm_multi_setup(void *private, snd_pcm_setup_t *setup)
|
|||
snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
|
||||
unsigned int i;
|
||||
int err;
|
||||
size_t frames_alloc;
|
||||
err = snd_pcm_setup(multi->slaves[0].handle, setup);
|
||||
if (err < 0)
|
||||
return err;
|
||||
frames_alloc = multi->slaves[0].handle->setup.frag_size;
|
||||
multi->frames_alloc = 0;
|
||||
for (i = 1; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_setup_t s;
|
||||
snd_pcm_t *sh = multi->slaves[i].handle;
|
||||
|
|
@ -219,7 +233,7 @@ static int snd_pcm_multi_setup(void *private, snd_pcm_setup_t *setup)
|
|||
if (!multi->handle->setup.format.interleave)
|
||||
continue;
|
||||
}
|
||||
s->buf = malloc(sh->setup.frag_size * sh->bits_per_frame / 8);
|
||||
s->buf = malloc(frames_alloc * sh->bits_per_frame / 8);
|
||||
if (!s->buf)
|
||||
return -ENOMEM;
|
||||
snd_pcm_format_set_silence(sh->setup.format.format, s->buf,
|
||||
|
|
@ -237,9 +251,11 @@ static int snd_pcm_multi_setup(void *private, snd_pcm_setup_t *setup)
|
|||
a->addr = s->buf + sh->setup.frag_size * sh->bits_per_sample / 8;
|
||||
a->first = 0;
|
||||
a->step = sh->bits_per_sample;
|
||||
s->iovec[c].iov_base = a->addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
multi->frames_alloc = frames_alloc;
|
||||
/* Loaded with a value != 0 if mmap is feasible */
|
||||
setup->mmap_bytes = !multi->one_to_many;
|
||||
return 0;
|
||||
|
|
@ -376,14 +392,14 @@ static ssize_t snd_pcm_multi_frame_data(void *private, off_t offset)
|
|||
}
|
||||
return newpos;
|
||||
}
|
||||
|
||||
ssize_t snd_pcm_multi_write(void *private, snd_timestamp_t timestamp UNUSED, const void *buf, size_t count)
|
||||
|
||||
static int snd_pcm_multi_write_copy(snd_pcm_multi_t *multi, const void *buf,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
|
||||
snd_pcm_t *handle = multi->handle;
|
||||
unsigned int i;
|
||||
snd_pcm_channel_area_t area;
|
||||
area.addr = (void *) buf;
|
||||
snd_pcm_t *handle = multi->handle;
|
||||
area.addr = (void *) buf + offset * handle->bits_per_frame;
|
||||
area.step = handle->bits_per_frame;
|
||||
for (i = 0; i < multi->binds_count; ++i) {
|
||||
snd_pcm_multi_bind_t *bind = &multi->binds[i];
|
||||
|
|
@ -394,41 +410,147 @@ ssize_t snd_pcm_multi_write(void *private, snd_timestamp_t timestamp UNUSED, con
|
|||
err = snd_pcm_area_copy(&area, 0, &slave->areas[bind->slave_channel], 0, count, handle->setup.format.format);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!slave->handle->setup.format.interleave)
|
||||
slave->iovec[bind->slave_channel].iov_base = slave->areas[bind->slave_channel].addr;
|
||||
if (!slave->handle->setup.format.interleave) {
|
||||
struct iovec *vec = &slave->iovec[bind->slave_channel];
|
||||
vec->iov_len = count;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_writev_copy(snd_pcm_multi_t *multi, const struct iovec *vec,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
unsigned int i;
|
||||
snd_pcm_channel_area_t area;
|
||||
snd_pcm_t *handle = multi->handle;
|
||||
area.first = 0;
|
||||
area.step = handle->bits_per_sample;
|
||||
for (i = 0; i < multi->binds_count; ++i) {
|
||||
snd_pcm_multi_bind_t *bind = &multi->binds[i];
|
||||
snd_pcm_multi_slave_t *slave = &multi->slaves[bind->slave];
|
||||
int err;
|
||||
area.addr = vec[bind->client_channel].iov_base +
|
||||
offset * handle->bits_per_sample;
|
||||
if (slave->handle->setup.format.interleave) {
|
||||
assert(slave->buf);
|
||||
err = snd_pcm_area_copy(&area, 0, &slave->areas[bind->slave_channel], 0, count, handle->setup.format.format);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
struct iovec *vec = &slave->iovec[bind->slave_channel];
|
||||
vec->iov_base = area.addr;
|
||||
vec->iov_len = count;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t snd_pcm_multi_write_io(snd_pcm_multi_t *multi, size_t count)
|
||||
{
|
||||
unsigned int i;
|
||||
ssize_t frames = count;
|
||||
for (i = 0; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_multi_slave_t *slave = &multi->slaves[i];
|
||||
snd_pcm_t *sh = slave->handle;
|
||||
if (sh->setup.format.interleave) {
|
||||
count = snd_pcm_write(sh, slave->buf, count);
|
||||
frames = snd_pcm_write(sh, slave->buf, frames);
|
||||
} else {
|
||||
int channels = sh->setup.format.channels;
|
||||
struct iovec vec[channels];
|
||||
int c;
|
||||
for (c = 0; c < channels; ++c)
|
||||
vec[c].iov_len = count;
|
||||
count = snd_pcm_writev(sh, vec, channels);
|
||||
frames = snd_pcm_writev(sh, slave->iovec, channels);
|
||||
}
|
||||
if (count <= 0)
|
||||
if (frames <= 0)
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
return frames;
|
||||
}
|
||||
|
||||
ssize_t snd_pcm_multi_read(void *private, snd_timestamp_t timestamp UNUSED, void *buf, size_t count)
|
||||
static ssize_t snd_pcm_multi_write(void *private, snd_timestamp_t timestamp UNUSED, const void *buf, size_t count)
|
||||
{
|
||||
snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
|
||||
size_t result = 0;
|
||||
while (count > 0) {
|
||||
int err;
|
||||
ssize_t ret;
|
||||
size_t frames = count;
|
||||
if (frames > multi->frames_alloc)
|
||||
frames = multi->frames_alloc;
|
||||
err = snd_pcm_multi_write_copy(multi, buf, result, frames);
|
||||
if (err < 0)
|
||||
return err;
|
||||
ret = snd_pcm_multi_write_io(multi, frames);
|
||||
if (ret > 0)
|
||||
result += ret;
|
||||
if (ret != (ssize_t)frames) {
|
||||
if (result > 0)
|
||||
return result;
|
||||
return ret;
|
||||
}
|
||||
count -= ret;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t snd_pcm_multi_writev1(snd_pcm_multi_t *multi, const struct iovec *vector, size_t count)
|
||||
{
|
||||
size_t result = 0;
|
||||
while (count > 0) {
|
||||
int err;
|
||||
ssize_t ret;
|
||||
size_t frames = count;
|
||||
if (frames > multi->frames_alloc)
|
||||
frames = multi->frames_alloc;
|
||||
err = snd_pcm_multi_writev_copy(multi, vector, result, frames);
|
||||
if (err < 0)
|
||||
return err;
|
||||
ret = snd_pcm_multi_write_io(multi, frames);
|
||||
if (ret > 0)
|
||||
result += ret;
|
||||
if (ret != (ssize_t) frames) {
|
||||
if (result > 0)
|
||||
return result;
|
||||
return ret;
|
||||
}
|
||||
count -= ret;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t snd_pcm_multi_writev(void *private, snd_timestamp_t timestamp UNUSED, const struct iovec *vector, unsigned long count)
|
||||
{
|
||||
snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
|
||||
snd_pcm_t *handle = multi->handle;
|
||||
unsigned int k, step;
|
||||
size_t result = 0;
|
||||
if (handle->setup.format.interleave)
|
||||
step = 1;
|
||||
else
|
||||
step = handle->setup.format.channels;
|
||||
for (k = 0; k < count; k += step) {
|
||||
ssize_t ret;
|
||||
if (handle->setup.format.interleave)
|
||||
ret = snd_pcm_multi_write(private, timestamp, vector->iov_base, vector->iov_len);
|
||||
else
|
||||
ret = snd_pcm_multi_writev1(multi, vector, vector->iov_len);
|
||||
if (ret > 0)
|
||||
result += ret;
|
||||
if (ret != (ssize_t) vector->iov_len) {
|
||||
if (result > 0)
|
||||
return result;
|
||||
return ret;
|
||||
}
|
||||
vector += step;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t snd_pcm_multi_read(void *private, snd_timestamp_t timestamp UNUSED, void *buf, size_t count)
|
||||
{
|
||||
snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ssize_t snd_pcm_multi_writev(void *private, snd_timestamp_t timestamp UNUSED, const struct iovec *vector, unsigned long count)
|
||||
{
|
||||
snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ssize_t snd_pcm_multi_readv(void *private, snd_timestamp_t timestamp UNUSED, const struct iovec *vector, unsigned long count)
|
||||
static ssize_t snd_pcm_multi_readv(void *private, snd_timestamp_t timestamp UNUSED, const struct iovec *vector, unsigned long count)
|
||||
{
|
||||
snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
|
||||
return -ENOSYS;
|
||||
|
|
@ -577,6 +699,29 @@ int snd_pcm_multi_file_descriptor(void *private)
|
|||
return snd_pcm_file_descriptor(handle);
|
||||
}
|
||||
|
||||
static void snd_pcm_multi_dump(void *private, FILE *fp)
|
||||
{
|
||||
snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
|
||||
snd_pcm_t *handle = multi->handle;
|
||||
unsigned int k;
|
||||
fprintf(fp, "Multi PCM\n");
|
||||
if (handle->valid_setup) {
|
||||
fprintf(fp, "\nIts setup is:\n");
|
||||
snd_pcm_dump_setup(handle, fp);
|
||||
}
|
||||
for (k = 0; k < multi->slaves_count; ++k) {
|
||||
fprintf(fp, "\nSlave #%d: ", k);
|
||||
snd_pcm_dump(multi->slaves[k].handle, fp);
|
||||
}
|
||||
fprintf(fp, "\nBindings:\n");
|
||||
for (k = 0; k < multi->binds_count; ++k) {
|
||||
fprintf(fp, "Channel #%d: slave %d[%d]\n",
|
||||
multi->binds[k].client_channel,
|
||||
multi->binds[k].slave,
|
||||
multi->binds[k].slave_channel);
|
||||
}
|
||||
}
|
||||
|
||||
struct snd_pcm_ops snd_pcm_multi_ops = {
|
||||
close: snd_pcm_multi_close,
|
||||
nonblock: snd_pcm_multi_nonblock,
|
||||
|
|
@ -606,6 +751,7 @@ struct snd_pcm_ops snd_pcm_multi_ops = {
|
|||
munmap_data: snd_pcm_multi_munmap_data,
|
||||
file_descriptor: snd_pcm_multi_file_descriptor,
|
||||
channels_mask: snd_pcm_multi_channels_mask,
|
||||
dump: snd_pcm_multi_dump,
|
||||
};
|
||||
|
||||
int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
|
||||
|
|
|
|||
|
|
@ -65,6 +65,35 @@ int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void snd_pcm_plugin_dump(snd_pcm_plugin_t *plugin, FILE *fp)
|
||||
{
|
||||
fprintf(fp, "----------- %s\n", plugin->name);
|
||||
fprintf(fp, "Buffer: %d frames\n", plugin->buf_frames);
|
||||
if (plugin->src_format.interleave != plugin->dst_format.interleave) {
|
||||
if (plugin->src_format.interleave)
|
||||
fprintf(fp, "Interleaved -> Non interleaved\n");
|
||||
else
|
||||
fprintf(fp, "Non interleaved -> Interleaved\n");
|
||||
}
|
||||
if (plugin->src_format.channels != plugin->dst_format.channels) {
|
||||
fprintf(fp, "Channels: %d -> %d\n",
|
||||
plugin->src_format.channels,
|
||||
plugin->dst_format.channels);
|
||||
}
|
||||
if (plugin->src_format.format != plugin->dst_format.format) {
|
||||
fprintf(fp, "Format: %s -> %s\n",
|
||||
snd_pcm_format_name(plugin->src_format.format),
|
||||
snd_pcm_format_name(plugin->dst_format.format));
|
||||
}
|
||||
if (plugin->src_format.rate != plugin->dst_format.rate) {
|
||||
fprintf(fp, "Rate: %d -> %d\n",
|
||||
plugin->src_format.rate,
|
||||
plugin->dst_format.rate);
|
||||
}
|
||||
if (plugin->dump)
|
||||
plugin->dump(plugin, fp);
|
||||
}
|
||||
|
||||
/* snd_pcm_plug externs */
|
||||
|
||||
int snd_pcm_plug_clear(snd_pcm_plug_t *plug)
|
||||
|
|
@ -378,22 +407,22 @@ ssize_t snd_pcm_plug_writev(void *private, snd_timestamp_t tstamp UNUSED, const
|
|||
{
|
||||
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) private;
|
||||
snd_pcm_t *handle = plug->handle;
|
||||
unsigned int k, step, channels;
|
||||
size_t size = 0;
|
||||
unsigned int k, step;
|
||||
size_t result = 0;
|
||||
assert(plug->frames_alloc);
|
||||
channels = handle->setup.format.channels;
|
||||
if (handle->setup.format.interleave)
|
||||
step = 1;
|
||||
else {
|
||||
step = channels;
|
||||
assert(count % channels == 0);
|
||||
}
|
||||
else
|
||||
step = handle->setup.format.channels;
|
||||
for (k = 0; k < count; k += step) {
|
||||
snd_pcm_plugin_channel_t *channels;
|
||||
ssize_t frames;
|
||||
frames = snd_pcm_plug_client_channels_iovec(plug, vector, count, &channels);
|
||||
if (frames < 0)
|
||||
frames = snd_pcm_plug_client_channels_iovec(plug, vector, step, &channels);
|
||||
if (frames < 0) {
|
||||
if (result > 0)
|
||||
return result;
|
||||
return frames;
|
||||
}
|
||||
while (1) {
|
||||
unsigned int c;
|
||||
ssize_t ret;
|
||||
|
|
@ -402,41 +431,42 @@ ssize_t snd_pcm_plug_writev(void *private, snd_timestamp_t tstamp UNUSED, const
|
|||
frames1 = plug->frames_alloc;
|
||||
ret = snd_pcm_plug_write_transfer(plug, channels, frames1);
|
||||
if (ret < 0) {
|
||||
if (size > 0)
|
||||
return size;
|
||||
if (result > 0)
|
||||
return result;
|
||||
return ret;
|
||||
}
|
||||
size += ret;
|
||||
result += ret;
|
||||
frames -= ret;
|
||||
if (frames == 0)
|
||||
break;
|
||||
for (c = 0; c < handle->setup.format.channels; ++c)
|
||||
channels[c].area.addr += ret * channels[c].area.step / 8;
|
||||
}
|
||||
vector += step;
|
||||
}
|
||||
return size;
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t snd_pcm_plug_readv(void *private, snd_timestamp_t tstamp UNUSED, const struct iovec *vector, unsigned long count)
|
||||
{
|
||||
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) private;
|
||||
snd_pcm_t *handle = plug->handle;
|
||||
unsigned int k, step, channels;
|
||||
size_t size = 0;
|
||||
unsigned int k, step;
|
||||
size_t result = 0;
|
||||
assert(plug->frames_alloc);
|
||||
channels = handle->setup.format.channels;
|
||||
if (handle->setup.format.interleave)
|
||||
step = 1;
|
||||
else {
|
||||
step = channels;
|
||||
assert(count % channels == 0);
|
||||
}
|
||||
else
|
||||
step = handle->setup.format.channels;
|
||||
for (k = 0; k < count; k += step) {
|
||||
snd_pcm_plugin_channel_t *channels;
|
||||
ssize_t frames;
|
||||
frames = snd_pcm_plug_client_channels_iovec(plug, vector, count, &channels);
|
||||
if (frames < 0)
|
||||
frames = snd_pcm_plug_client_channels_iovec(plug, vector, step, &channels);
|
||||
if (frames < 0) {
|
||||
if (result > 0)
|
||||
return result;
|
||||
return frames;
|
||||
}
|
||||
while (1) {
|
||||
unsigned int c;
|
||||
ssize_t ret;
|
||||
|
|
@ -445,19 +475,20 @@ ssize_t snd_pcm_plug_readv(void *private, snd_timestamp_t tstamp UNUSED, const s
|
|||
frames1 = plug->frames_alloc;
|
||||
ret = snd_pcm_plug_read_transfer(plug, channels, frames1);
|
||||
if (ret < 0) {
|
||||
if (size > 0)
|
||||
return size;
|
||||
if (result > 0)
|
||||
return result;
|
||||
return ret;
|
||||
}
|
||||
size += ret;
|
||||
result += ret;
|
||||
frames -= ret;
|
||||
if (frames == 0)
|
||||
break;
|
||||
for (c = 0; c < handle->setup.format.channels; ++c)
|
||||
channels[c].area.addr += ret * channels[c].area.step / 8;
|
||||
}
|
||||
vector += step;
|
||||
}
|
||||
return size;
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t snd_pcm_plug_write(void *private, snd_timestamp_t tstamp UNUSED, const void *buf, size_t count)
|
||||
|
|
@ -574,6 +605,25 @@ int snd_pcm_plug_file_descriptor(void *private)
|
|||
return snd_pcm_file_descriptor(plug->slave);
|
||||
}
|
||||
|
||||
static void snd_pcm_plug_dump(void *private, FILE *fp)
|
||||
{
|
||||
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) private;
|
||||
snd_pcm_t *handle = plug->handle;
|
||||
snd_pcm_plugin_t *plugin;
|
||||
fprintf(fp, "Plug PCM\n");
|
||||
if (handle->valid_setup) {
|
||||
fprintf(fp, "\nIts setup is:\n");
|
||||
snd_pcm_dump_setup(handle, fp);
|
||||
}
|
||||
fprintf(fp, "\nPlugins:\n");
|
||||
plugin = plug->first;
|
||||
while (plugin) {
|
||||
snd_pcm_plugin_dump(plugin, fp);
|
||||
plugin = plugin->next;
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_params(void *private, snd_pcm_params_t *params);
|
||||
|
||||
struct snd_pcm_ops snd_pcm_plug_ops = {
|
||||
|
|
@ -605,6 +655,7 @@ struct snd_pcm_ops snd_pcm_plug_ops = {
|
|||
munmap_data: snd_pcm_plug_munmap_data,
|
||||
file_descriptor: snd_pcm_plug_file_descriptor,
|
||||
channels_mask: snd_pcm_plug_channels_mask,
|
||||
dump: snd_pcm_plug_dump,
|
||||
};
|
||||
|
||||
static void snd_pcm_plug_slave_params(snd_pcm_plug_t *plug,
|
||||
|
|
|
|||
|
|
@ -118,6 +118,17 @@ static ssize_t io_src_channels(snd_pcm_plugin_t *plugin,
|
|||
return frames;
|
||||
}
|
||||
|
||||
#ifndef __KERNEL__
|
||||
static void io_dump(snd_pcm_plugin_t *plugin, FILE *fp)
|
||||
{
|
||||
snd_pcm_t *slave = plugin->plug->slave;
|
||||
if (slave->valid_setup) {
|
||||
fprintf(fp, "Slave: ");
|
||||
snd_pcm_dump(slave, fp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int snd_pcm_plugin_build_io(snd_pcm_plug_t *plug,
|
||||
snd_pcm_format_t *format,
|
||||
snd_pcm_plugin_t **r_plugin)
|
||||
|
|
@ -141,6 +152,9 @@ int snd_pcm_plugin_build_io(snd_pcm_plug_t *plug,
|
|||
} else {
|
||||
plugin->transfer = io_capture_transfer;
|
||||
}
|
||||
#ifndef __KERNEL__
|
||||
plugin->dump = io_dump;
|
||||
#endif
|
||||
|
||||
*r_plugin = plugin;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ typedef struct mmap_private_data {
|
|||
|
||||
|
||||
static ssize_t mmap_src_channels(snd_pcm_plugin_t *plugin,
|
||||
size_t frames,
|
||||
snd_pcm_plugin_channel_t **channels)
|
||||
size_t frames,
|
||||
snd_pcm_plugin_channel_t **channels)
|
||||
{
|
||||
mmap_t *data;
|
||||
snd_pcm_plugin_channel_t *sv;
|
||||
|
|
@ -272,7 +272,16 @@ static void mmap_free(snd_pcm_plugin_t *plugin, void *private_data UNUSED)
|
|||
if (data->buffer)
|
||||
snd_pcm_munmap(plugin->plug->slave);
|
||||
}
|
||||
|
||||
|
||||
static void mmap_dump(snd_pcm_plugin_t *plugin, FILE *fp)
|
||||
{
|
||||
snd_pcm_t *slave = plugin->plug->slave;
|
||||
if (slave->valid_setup) {
|
||||
fprintf(fp, "Slave: ");
|
||||
snd_pcm_dump(slave, fp);
|
||||
}
|
||||
}
|
||||
|
||||
int snd_pcm_plugin_build_mmap(snd_pcm_plug_t *plug,
|
||||
snd_pcm_format_t *format,
|
||||
snd_pcm_plugin_t **r_plugin)
|
||||
|
|
@ -300,6 +309,7 @@ int snd_pcm_plugin_build_mmap(snd_pcm_plug_t *plug,
|
|||
}
|
||||
plugin->action = mmap_action;
|
||||
plugin->private_free = mmap_free;
|
||||
plugin->dump = mmap_dump;
|
||||
*r_plugin = plugin;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ typedef struct {
|
|||
|
||||
struct ttable_dst {
|
||||
int att; /* Attenuated */
|
||||
int nsrcs;
|
||||
unsigned int nsrcs;
|
||||
ttable_src_t* srcs;
|
||||
route_channel_f func;
|
||||
};
|
||||
|
|
@ -104,7 +104,7 @@ static void route_to_channel_from_one(snd_pcm_plugin_t *plugin,
|
|||
route_t *data = (route_t *)plugin->extra_data;
|
||||
void *conv;
|
||||
const snd_pcm_plugin_channel_t *src_channel = 0;
|
||||
int srcidx;
|
||||
unsigned int srcidx;
|
||||
char *src, *dst;
|
||||
int src_step, dst_step;
|
||||
for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
|
||||
|
|
@ -373,7 +373,7 @@ int route_src_channels_mask(snd_pcm_plugin_t *plugin,
|
|||
ttable_dst_t *dp = data->ttable;
|
||||
bitset_zero(vmask, schannels);
|
||||
for (channel = 0; channel < dchannels; channel++, dp++) {
|
||||
int src;
|
||||
unsigned int src;
|
||||
ttable_src_t *sp;
|
||||
if (!bitset_get(dst_vmask, channel))
|
||||
continue;
|
||||
|
|
@ -396,7 +396,7 @@ int route_dst_channels_mask(snd_pcm_plugin_t *plugin,
|
|||
ttable_dst_t *dp = data->ttable;
|
||||
bitset_zero(vmask, dchannels);
|
||||
for (channel = 0; channel < dchannels; channel++, dp++) {
|
||||
int src;
|
||||
unsigned int src;
|
||||
ttable_src_t *sp;
|
||||
sp = dp->srcs;
|
||||
for (src = 0; src < dp->nsrcs; src++, sp++) {
|
||||
|
|
@ -535,6 +535,38 @@ int getput_index(int format)
|
|||
return width * 4 + endian * 2 + sign;
|
||||
}
|
||||
|
||||
#ifndef __KERNEL__
|
||||
static void route_dump(snd_pcm_plugin_t *plugin, FILE *fp)
|
||||
{
|
||||
route_t *data;
|
||||
ttable_dst_t *tdp;
|
||||
unsigned int dst_channel, dst_nchannels;
|
||||
data = (route_t *)plugin->extra_data;
|
||||
tdp = data->ttable;
|
||||
dst_nchannels = plugin->dst_format.channels;
|
||||
for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
|
||||
unsigned int k;
|
||||
ttable_src_t *tsp = tdp->srcs;
|
||||
fprintf(fp, "Channel %d = ", dst_channel);
|
||||
for (k = 0; k < tdp->nsrcs; ++k) {
|
||||
if (k > 0)
|
||||
fprintf(fp, " + ");
|
||||
fprintf(fp, "[%d]", tsp->channel);
|
||||
if (tdp->att) {
|
||||
#if ROUTE_PLUGIN_USE_FLOAT
|
||||
fprintf(fp, "*%g", tsp->as_float);
|
||||
#else
|
||||
fprintf(fp, "*%d/%d", tsp->as_int, ROUTE_PLUGIN_RESOLUTION);
|
||||
#endif
|
||||
}
|
||||
++tsp;
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
++tdp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int snd_pcm_plugin_build_route(snd_pcm_plug_t *plug,
|
||||
snd_pcm_format_t *src_format,
|
||||
snd_pcm_format_t *dst_format,
|
||||
|
|
@ -581,6 +613,9 @@ int snd_pcm_plugin_build_route(snd_pcm_plug_t *plug,
|
|||
plugin->transfer = route_transfer;
|
||||
plugin->src_channels_mask = route_src_channels_mask;
|
||||
plugin->dst_channels_mask = route_dst_channels_mask;
|
||||
#ifndef __KERNEL__
|
||||
plugin->dump = route_dump;
|
||||
#endif
|
||||
*r_plugin = plugin;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue