mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-12-28 08:57:30 -05:00
Merged pcmfinal branch.
This commit is contained in:
parent
3cc2b957fb
commit
41bb7068f2
57 changed files with 5189 additions and 3088 deletions
1895
src/pcm/pcm.c
1895
src/pcm/pcm.c
File diff suppressed because it is too large
Load diff
|
|
@ -69,8 +69,6 @@ typedef struct {
|
|||
int getput_idx;
|
||||
adpcm_f func;
|
||||
int sformat;
|
||||
int cformat;
|
||||
int cxfer_mode, cmmap_shape;
|
||||
adpcm_state_t *states;
|
||||
} snd_pcm_adpcm_t;
|
||||
|
||||
|
|
@ -331,102 +329,82 @@ static int snd_pcm_adpcm_close(snd_pcm_t *pcm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_adpcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
|
||||
static int snd_pcm_adpcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
|
||||
{
|
||||
snd_pcm_adpcm_t *adpcm = pcm->private;
|
||||
unsigned int req_mask = info->req_mask;
|
||||
unsigned int sfmt = info->req.format.sfmt;
|
||||
unsigned int format_mask, access_mask;
|
||||
int err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT) {
|
||||
if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
|
||||
!snd_pcm_format_linear(sfmt) :
|
||||
sfmt != SND_PCM_SFMT_IMA_ADPCM) {
|
||||
info->req.fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
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);
|
||||
if (info->format_mask)
|
||||
info->format_mask = format_mask;
|
||||
if (info->access_mask) {
|
||||
adpcm->plug.saccess_mask = info->access_mask;
|
||||
info->access_mask = access_mask;
|
||||
}
|
||||
info->req_mask |= SND_PCM_PARAMS_SFMT;
|
||||
info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
|
||||
SND_PCM_PARAMS_XFER_MODE);
|
||||
info->req.format.sfmt = adpcm->sformat;
|
||||
err = snd_pcm_params_info(adpcm->plug.slave, info);
|
||||
info->req_mask = req_mask;
|
||||
info->req.format.sfmt = sfmt;
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT)
|
||||
info->formats = 1 << sfmt;
|
||||
else
|
||||
info->formats = adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
|
||||
SND_PCM_LINEAR_FORMATS : 1 << SND_PCM_SFMT_IMA_ADPCM;
|
||||
info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
|
||||
return err;
|
||||
info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
snd_pcm_hw_info_complete(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||
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;
|
||||
unsigned int format, access;
|
||||
int err;
|
||||
if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
|
||||
!snd_pcm_format_linear(params->format.sfmt) :
|
||||
params->format.sfmt != SND_PCM_SFMT_IMA_ADPCM) {
|
||||
params->fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
adpcm->cformat = params->format.sfmt;
|
||||
adpcm->cxfer_mode = params->xfer_mode;
|
||||
adpcm->cmmap_shape = params->mmap_shape;
|
||||
params->format.sfmt = adpcm->sformat;
|
||||
params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
|
||||
err = snd_pcm_params_mmap(slave, params);
|
||||
params->format.sfmt = adpcm->cformat;
|
||||
params->xfer_mode = adpcm->cxfer_mode;
|
||||
params->mmap_shape = adpcm->cmmap_shape;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_adpcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
||||
{
|
||||
snd_pcm_adpcm_t *adpcm = pcm->private;
|
||||
int err = snd_pcm_setup(adpcm->plug.slave, setup);
|
||||
format = params->format;
|
||||
access = params->access;
|
||||
params->format = adpcm->sformat;
|
||||
if (adpcm->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
|
||||
else if (adpcm->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
assert(0);
|
||||
err = snd_pcm_hw_params(slave, params);
|
||||
params->format = format;
|
||||
params->access = access;
|
||||
if (err < 0)
|
||||
return err;
|
||||
assert(adpcm->sformat == setup->format.sfmt);
|
||||
if (adpcm->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
|
||||
setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
|
||||
else
|
||||
setup->xfer_mode = adpcm->cxfer_mode;
|
||||
if (adpcm->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
|
||||
setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
setup->mmap_shape = adpcm->cmmap_shape;
|
||||
setup->format.sfmt = adpcm->cformat;
|
||||
setup->mmap_bytes = 0;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM) {
|
||||
adpcm->getput_idx = get_index(adpcm->cformat, SND_PCM_SFMT_S16);
|
||||
if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
|
||||
adpcm->getput_idx = get_index(format, SND_PCM_FORMAT_S16);
|
||||
adpcm->func = adpcm_encode;
|
||||
} else {
|
||||
adpcm->getput_idx = put_index(SND_PCM_SFMT_S16, adpcm->sformat);
|
||||
adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, adpcm->sformat);
|
||||
adpcm->func = adpcm_decode;
|
||||
}
|
||||
} else {
|
||||
if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM) {
|
||||
adpcm->getput_idx = put_index(SND_PCM_SFMT_S16, adpcm->cformat);
|
||||
if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
|
||||
adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, format);
|
||||
adpcm->func = adpcm_decode;
|
||||
} else {
|
||||
adpcm->getput_idx = get_index(adpcm->sformat, SND_PCM_SFMT_S16);
|
||||
adpcm->getput_idx = get_index(adpcm->sformat, SND_PCM_FORMAT_S16);
|
||||
adpcm->func = adpcm_encode;
|
||||
}
|
||||
}
|
||||
if (adpcm->states)
|
||||
free(adpcm->states);
|
||||
adpcm->states = malloc(setup->format.channels * sizeof(*adpcm->states));
|
||||
adpcm->states = malloc(params->channels * sizeof(*adpcm->states));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -434,7 +412,7 @@ static int snd_pcm_adpcm_init(snd_pcm_t *pcm)
|
|||
{
|
||||
snd_pcm_adpcm_t *adpcm = pcm->private;
|
||||
unsigned int k;
|
||||
for (k = 0; k < pcm->setup.format.channels; ++k) {
|
||||
for (k = 0; k < pcm->channels; ++k) {
|
||||
adpcm->states[k].pred_val = 0;
|
||||
adpcm->states[k].step_idx = 0;
|
||||
}
|
||||
|
|
@ -458,7 +436,7 @@ static ssize_t snd_pcm_adpcm_write_areas(snd_pcm_t *pcm,
|
|||
size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
|
||||
adpcm->func(areas, offset,
|
||||
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
frames, pcm->setup.format.channels,
|
||||
frames, pcm->channels,
|
||||
adpcm->getput_idx, adpcm->states);
|
||||
err = snd_pcm_mmap_forward(slave, frames);
|
||||
if (err < 0)
|
||||
|
|
@ -493,7 +471,7 @@ static ssize_t snd_pcm_adpcm_read_areas(snd_pcm_t *pcm,
|
|||
size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
|
||||
adpcm->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
areas, offset,
|
||||
frames, pcm->setup.format.channels,
|
||||
frames, pcm->channels,
|
||||
adpcm->getput_idx, adpcm->states);
|
||||
err = snd_pcm_mmap_forward(slave, frames);
|
||||
if (err < 0)
|
||||
|
|
@ -516,7 +494,7 @@ static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, FILE *fp)
|
|||
snd_pcm_adpcm_t *adpcm = pcm->private;
|
||||
fprintf(fp, "Ima-ADPCM conversion PCM (%s)\n",
|
||||
snd_pcm_format_name(adpcm->sformat));
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "Its setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -527,12 +505,12 @@ 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,
|
||||
params_info: snd_pcm_adpcm_params_info,
|
||||
params: snd_pcm_adpcm_params,
|
||||
setup: snd_pcm_adpcm_setup,
|
||||
hw_info: snd_pcm_adpcm_hw_info,
|
||||
hw_params: snd_pcm_adpcm_hw_params,
|
||||
sw_params: snd_pcm_plugin_sw_params,
|
||||
dig_info: snd_pcm_plugin_dig_info,
|
||||
dig_params: snd_pcm_plugin_dig_params,
|
||||
channel_info: snd_pcm_plugin_channel_info,
|
||||
channel_params: snd_pcm_plugin_channel_params,
|
||||
channel_setup: snd_pcm_plugin_channel_setup,
|
||||
dump: snd_pcm_adpcm_dump,
|
||||
nonblock: snd_pcm_plugin_nonblock,
|
||||
async: snd_pcm_plugin_async,
|
||||
|
|
@ -546,7 +524,7 @@ int snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *sla
|
|||
snd_pcm_adpcm_t *adpcm;
|
||||
assert(pcmp && slave);
|
||||
if (snd_pcm_format_linear(sformat) != 1 &&
|
||||
sformat != SND_PCM_SFMT_IMA_ADPCM)
|
||||
sformat != SND_PCM_FORMAT_IMA_ADPCM)
|
||||
return -EINVAL;
|
||||
adpcm = calloc(1, sizeof(snd_pcm_adpcm_t));
|
||||
if (!adpcm) {
|
||||
|
|
@ -614,7 +592,7 @@ int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name,
|
|||
if (sformat < 0)
|
||||
return -EINVAL;
|
||||
if (snd_pcm_format_linear(sformat) != 1 &&
|
||||
sformat != SND_PCM_SFMT_IMA_ADPCM)
|
||||
sformat != SND_PCM_FORMAT_IMA_ADPCM)
|
||||
return -EINVAL;
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,8 +35,6 @@ typedef struct {
|
|||
int getput_idx;
|
||||
alaw_f func;
|
||||
int sformat;
|
||||
int cformat;
|
||||
int cxfer_mode, cmmap_shape;
|
||||
} snd_pcm_alaw_t;
|
||||
|
||||
static inline int val_seg(int val)
|
||||
|
|
@ -213,96 +211,76 @@ static void alaw_encode(snd_pcm_channel_area_t *src_areas,
|
|||
}
|
||||
}
|
||||
|
||||
static int snd_pcm_alaw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
|
||||
static int snd_pcm_alaw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
|
||||
{
|
||||
snd_pcm_alaw_t *alaw = pcm->private;
|
||||
unsigned int req_mask = info->req_mask;
|
||||
unsigned int sfmt = info->req.format.sfmt;
|
||||
unsigned int format_mask, access_mask;
|
||||
int err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT) {
|
||||
if (alaw->sformat == SND_PCM_SFMT_A_LAW ?
|
||||
!snd_pcm_format_linear(sfmt) :
|
||||
sfmt != SND_PCM_SFMT_A_LAW) {
|
||||
info->req.fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
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);
|
||||
if (info->format_mask)
|
||||
info->format_mask = format_mask;
|
||||
if (info->access_mask) {
|
||||
alaw->plug.saccess_mask = info->access_mask;
|
||||
info->access_mask = access_mask;
|
||||
}
|
||||
info->req_mask |= SND_PCM_PARAMS_SFMT;
|
||||
info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
|
||||
SND_PCM_PARAMS_XFER_MODE);
|
||||
info->req.format.sfmt = alaw->sformat;
|
||||
err = snd_pcm_params_info(alaw->plug.slave, info);
|
||||
info->req_mask = req_mask;
|
||||
info->req.format.sfmt = sfmt;
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT)
|
||||
info->formats = 1 << sfmt;
|
||||
else
|
||||
info->formats = alaw->sformat == SND_PCM_SFMT_A_LAW ?
|
||||
SND_PCM_LINEAR_FORMATS : 1 << SND_PCM_SFMT_A_LAW;
|
||||
info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
|
||||
return err;
|
||||
info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
snd_pcm_hw_info_complete(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||
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;
|
||||
unsigned int format, access;
|
||||
int err;
|
||||
if (alaw->sformat == SND_PCM_SFMT_A_LAW ?
|
||||
!snd_pcm_format_linear(params->format.sfmt) :
|
||||
params->format.sfmt != SND_PCM_SFMT_A_LAW) {
|
||||
params->fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
alaw->cformat = params->format.sfmt;
|
||||
alaw->cxfer_mode = params->xfer_mode;
|
||||
alaw->cmmap_shape = params->mmap_shape;
|
||||
params->format.sfmt = alaw->sformat;
|
||||
params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
|
||||
err = snd_pcm_params_mmap(slave, params);
|
||||
params->format.sfmt = alaw->cformat;
|
||||
params->xfer_mode = alaw->cxfer_mode;
|
||||
params->mmap_shape = alaw->cmmap_shape;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_alaw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
||||
{
|
||||
snd_pcm_alaw_t *alaw = pcm->private;
|
||||
int err = snd_pcm_setup(alaw->plug.slave, setup);
|
||||
format = params->format;
|
||||
access = params->access;
|
||||
params->format = alaw->sformat;
|
||||
if (alaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
|
||||
else if (alaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
assert(0);
|
||||
err = snd_pcm_hw_params(slave, params);
|
||||
params->format = format;
|
||||
params->access = access;
|
||||
if (err < 0)
|
||||
return err;
|
||||
assert(alaw->sformat == setup->format.sfmt);
|
||||
if (alaw->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
|
||||
setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
|
||||
else
|
||||
setup->xfer_mode = alaw->cxfer_mode;
|
||||
if (alaw->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
|
||||
setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
setup->mmap_shape = alaw->cmmap_shape;
|
||||
setup->format.sfmt = alaw->cformat;
|
||||
setup->mmap_bytes = 0;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
if (alaw->sformat == SND_PCM_SFMT_A_LAW) {
|
||||
alaw->getput_idx = get_index(alaw->cformat, SND_PCM_SFMT_S16);
|
||||
if (alaw->sformat == SND_PCM_FORMAT_MU_LAW) {
|
||||
alaw->getput_idx = get_index(format, SND_PCM_FORMAT_S16);
|
||||
alaw->func = alaw_encode;
|
||||
} else {
|
||||
alaw->getput_idx = put_index(SND_PCM_SFMT_S16, alaw->sformat);
|
||||
alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, alaw->sformat);
|
||||
alaw->func = alaw_decode;
|
||||
}
|
||||
} else {
|
||||
if (alaw->sformat == SND_PCM_SFMT_A_LAW) {
|
||||
alaw->getput_idx = put_index(SND_PCM_SFMT_S16, alaw->cformat);
|
||||
if (alaw->sformat == SND_PCM_FORMAT_MU_LAW) {
|
||||
alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, format);
|
||||
alaw->func = alaw_decode;
|
||||
} else {
|
||||
alaw->getput_idx = get_index(alaw->sformat, SND_PCM_SFMT_S16);
|
||||
alaw->getput_idx = get_index(alaw->sformat, SND_PCM_FORMAT_S16);
|
||||
alaw->func = alaw_encode;
|
||||
}
|
||||
}
|
||||
|
|
@ -326,7 +304,7 @@ static ssize_t snd_pcm_alaw_write_areas(snd_pcm_t *pcm,
|
|||
size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
|
||||
alaw->func(areas, offset,
|
||||
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
frames, pcm->setup.format.channels,
|
||||
frames, pcm->channels,
|
||||
alaw->getput_idx);
|
||||
err = snd_pcm_mmap_forward(slave, frames);
|
||||
if (err < 0)
|
||||
|
|
@ -361,7 +339,7 @@ static ssize_t snd_pcm_alaw_read_areas(snd_pcm_t *pcm,
|
|||
size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
|
||||
alaw->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
areas, offset,
|
||||
frames, pcm->setup.format.channels,
|
||||
frames, pcm->channels,
|
||||
alaw->getput_idx);
|
||||
err = snd_pcm_mmap_forward(slave, frames);
|
||||
if (err < 0)
|
||||
|
|
@ -384,7 +362,7 @@ static void snd_pcm_alaw_dump(snd_pcm_t *pcm, FILE *fp)
|
|||
snd_pcm_alaw_t *alaw = pcm->private;
|
||||
fprintf(fp, "A-Law conversion PCM (%s)\n",
|
||||
snd_pcm_format_name(alaw->sformat));
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "Its setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -395,12 +373,12 @@ 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,
|
||||
params_info: snd_pcm_alaw_params_info,
|
||||
params: snd_pcm_alaw_params,
|
||||
setup: snd_pcm_alaw_setup,
|
||||
hw_info: snd_pcm_alaw_hw_info,
|
||||
hw_params: snd_pcm_alaw_hw_params,
|
||||
sw_params: snd_pcm_plugin_sw_params,
|
||||
dig_info: snd_pcm_plugin_dig_info,
|
||||
dig_params: snd_pcm_plugin_dig_params,
|
||||
channel_info: snd_pcm_plugin_channel_info,
|
||||
channel_params: snd_pcm_plugin_channel_params,
|
||||
channel_setup: snd_pcm_plugin_channel_setup,
|
||||
dump: snd_pcm_alaw_dump,
|
||||
nonblock: snd_pcm_plugin_nonblock,
|
||||
async: snd_pcm_plugin_async,
|
||||
|
|
@ -414,7 +392,7 @@ int snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slav
|
|||
snd_pcm_alaw_t *alaw;
|
||||
assert(pcmp && slave);
|
||||
if (snd_pcm_format_linear(sformat) != 1 &&
|
||||
sformat != SND_PCM_SFMT_A_LAW)
|
||||
sformat != SND_PCM_FORMAT_A_LAW)
|
||||
return -EINVAL;
|
||||
alaw = calloc(1, sizeof(snd_pcm_alaw_t));
|
||||
if (!alaw) {
|
||||
|
|
@ -481,7 +459,7 @@ int _snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name,
|
|||
if (sformat < 0)
|
||||
return -EINVAL;
|
||||
if (snd_pcm_format_linear(sformat) != 1 &&
|
||||
sformat != SND_PCM_SFMT_A_LAW)
|
||||
sformat != SND_PCM_FORMAT_A_LAW)
|
||||
return -EINVAL;
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,11 +23,16 @@
|
|||
#include "pcm_local.h"
|
||||
#include "pcm_plugin.h"
|
||||
|
||||
enum {
|
||||
SND_PCM_FILE_FORMAT_RAW
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
snd_pcm_t *slave;
|
||||
int close_slave;
|
||||
char *fname;
|
||||
int fd;
|
||||
int format;
|
||||
} snd_pcm_file_t;
|
||||
|
||||
static int snd_pcm_file_close(snd_pcm_t *pcm)
|
||||
|
|
@ -68,18 +73,6 @@ static int snd_pcm_file_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * in
|
|||
return snd_pcm_channel_info(file->slave, info);
|
||||
}
|
||||
|
||||
static int snd_pcm_file_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
return snd_pcm_channel_params(file->slave, params);
|
||||
}
|
||||
|
||||
static int snd_pcm_file_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
return snd_pcm_channel_setup(file->slave, setup);
|
||||
}
|
||||
|
||||
static int snd_pcm_file_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
|
|
@ -148,11 +141,16 @@ static void snd_pcm_file_write_areas(snd_pcm_t *pcm,
|
|||
snd_pcm_file_t *file = pcm->private;
|
||||
size_t bytes = snd_pcm_frames_to_bytes(pcm, frames);
|
||||
char *buf;
|
||||
size_t channels = pcm->setup.format.channels;
|
||||
size_t channels = pcm->channels;
|
||||
snd_pcm_channel_area_t buf_areas[channels];
|
||||
size_t channel;
|
||||
ssize_t r;
|
||||
if (pcm->setup.mmap_shape != SND_PCM_MMAP_INTERLEAVED) {
|
||||
switch (pcm->access) {
|
||||
case SND_PCM_ACCESS_MMAP_INTERLEAVED:
|
||||
case SND_PCM_ACCESS_RW_INTERLEAVED:
|
||||
buf = snd_pcm_channel_area_addr(areas, offset);
|
||||
break;
|
||||
default:
|
||||
buf = alloca(bytes);
|
||||
for (channel = 0; channel < channels; ++channel) {
|
||||
snd_pcm_channel_area_t *a = &buf_areas[channel];
|
||||
|
|
@ -161,9 +159,8 @@ static void snd_pcm_file_write_areas(snd_pcm_t *pcm,
|
|||
a->step = pcm->bits_per_frame;
|
||||
}
|
||||
snd_pcm_areas_copy(areas, offset, buf_areas, 0,
|
||||
channels, frames, pcm->setup.format.sfmt);
|
||||
} else
|
||||
buf = snd_pcm_channel_area_addr(areas, offset);
|
||||
channels, frames, pcm->format);
|
||||
}
|
||||
r = write(file->fd, buf, bytes);
|
||||
assert(r == (ssize_t)bytes);
|
||||
}
|
||||
|
|
@ -183,7 +180,7 @@ static ssize_t snd_pcm_file_writei(snd_pcm_t *pcm, const void *buffer, size_t si
|
|||
static ssize_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, size_t size)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
snd_pcm_channel_area_t areas[pcm->setup.format.channels];
|
||||
snd_pcm_channel_area_t areas[pcm->channels];
|
||||
ssize_t n = snd_pcm_writen(file->slave, bufs, size);
|
||||
if (n > 0) {
|
||||
snd_pcm_areas_from_bufs(pcm, areas, bufs);
|
||||
|
|
@ -207,7 +204,7 @@ static ssize_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, size_t size)
|
|||
static ssize_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, size_t size)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
snd_pcm_channel_area_t areas[pcm->setup.format.channels];
|
||||
snd_pcm_channel_area_t areas[pcm->channels];
|
||||
ssize_t n = snd_pcm_writen(file->slave, bufs, size);
|
||||
if (n > 0) {
|
||||
snd_pcm_areas_from_bufs(pcm, areas, bufs);
|
||||
|
|
@ -226,12 +223,12 @@ static ssize_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, size_t size)
|
|||
return n;
|
||||
while (xfer < (size_t)n) {
|
||||
size_t frames = size - xfer;
|
||||
size_t cont = pcm->setup.buffer_size - ofs;
|
||||
size_t cont = pcm->buffer_size - ofs;
|
||||
if (cont < frames)
|
||||
frames = cont;
|
||||
snd_pcm_file_write_areas(pcm, snd_pcm_mmap_areas(file->slave), ofs, frames);
|
||||
ofs += frames;
|
||||
if (ofs == pcm->setup.buffer_size)
|
||||
if (ofs == pcm->buffer_size)
|
||||
ofs = 0;
|
||||
xfer += frames;
|
||||
}
|
||||
|
|
@ -250,44 +247,46 @@ 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_mmap(snd_pcm_t *pcm)
|
||||
static int snd_pcm_file_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
int err = snd_pcm_mmap(file->slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
pcm->mmap_info_count = file->slave->mmap_info_count;
|
||||
pcm->mmap_info = file->slave->mmap_info;
|
||||
return 0;
|
||||
return snd_pcm_hw_info(file->slave, info);
|
||||
}
|
||||
|
||||
static int snd_pcm_file_munmap(snd_pcm_t *pcm)
|
||||
static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
int err = snd_pcm_munmap(file->slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
pcm->mmap_info_count = 0;
|
||||
pcm->mmap_info = 0;
|
||||
return 0;
|
||||
return snd_pcm_hw_params(file->slave, params);
|
||||
}
|
||||
|
||||
static int snd_pcm_file_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
|
||||
static int snd_pcm_file_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
return snd_pcm_params_info(file->slave, info);
|
||||
return snd_pcm_sw_params(file->slave, params);
|
||||
}
|
||||
|
||||
static int snd_pcm_file_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||
static int snd_pcm_file_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
return snd_pcm_params(file->slave, params);
|
||||
return snd_pcm_dig_info(file->slave, info);
|
||||
}
|
||||
|
||||
static int snd_pcm_file_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
||||
static int snd_pcm_file_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
return snd_pcm_setup(file->slave, setup);
|
||||
return snd_pcm_dig_params(file->slave, params);
|
||||
}
|
||||
|
||||
static int snd_pcm_file_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
return snd_pcm_mmap(file->slave);
|
||||
}
|
||||
|
||||
static int snd_pcm_file_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||
{
|
||||
snd_pcm_file_t *file = pcm->private;
|
||||
return snd_pcm_munmap(file->slave);
|
||||
}
|
||||
|
||||
static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
|
||||
|
|
@ -297,7 +296,7 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
|
|||
fprintf(fp, "File PCM (file=%s)\n", file->fname);
|
||||
else
|
||||
fprintf(fp, "File PCM (fd=%d)\n", file->fd);
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "Its setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -308,12 +307,12 @@ 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,
|
||||
params_info: snd_pcm_file_params_info,
|
||||
params: snd_pcm_file_params,
|
||||
setup: snd_pcm_file_setup,
|
||||
hw_info: snd_pcm_file_hw_info,
|
||||
hw_params: snd_pcm_file_hw_params,
|
||||
sw_params: snd_pcm_file_sw_params,
|
||||
dig_info: snd_pcm_file_dig_info,
|
||||
dig_params: snd_pcm_file_dig_params,
|
||||
channel_info: snd_pcm_file_channel_info,
|
||||
channel_params: snd_pcm_file_channel_params,
|
||||
channel_setup: snd_pcm_file_channel_setup,
|
||||
dump: snd_pcm_file_dump,
|
||||
nonblock: snd_pcm_file_nonblock,
|
||||
async: snd_pcm_file_async,
|
||||
|
|
@ -340,11 +339,11 @@ snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
|
|||
set_avail_min: snd_pcm_file_set_avail_min,
|
||||
};
|
||||
|
||||
int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, snd_pcm_t *slave, int close_slave)
|
||||
int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, char *fmt, snd_pcm_t *slave, int close_slave)
|
||||
{
|
||||
snd_pcm_t *pcm;
|
||||
snd_pcm_file_t *file;
|
||||
assert(pcmp && slave);
|
||||
assert(pcmp);
|
||||
if (fname) {
|
||||
fd = open(fname, O_WRONLY|O_CREAT, 0666);
|
||||
if (fd < 0) {
|
||||
|
|
@ -354,8 +353,16 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, snd_pcm
|
|||
}
|
||||
file = calloc(1, sizeof(snd_pcm_file_t));
|
||||
if (!file) {
|
||||
if (fname)
|
||||
close(fd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (fmt == NULL ||
|
||||
strcmp(fmt, "raw") == 0)
|
||||
file->format = SND_PCM_FILE_FORMAT_RAW;
|
||||
else
|
||||
ERR("file format %s is unknown", fmt);
|
||||
|
||||
file->fname = fname;
|
||||
file->fd = fd;
|
||||
file->slave = slave;
|
||||
|
|
@ -393,6 +400,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
|
|||
int err;
|
||||
snd_pcm_t *spcm;
|
||||
char *fname = NULL;
|
||||
char *format = NULL;
|
||||
long fd = -1;
|
||||
snd_config_foreach(i, conf) {
|
||||
snd_config_t *n = snd_config_entry(i);
|
||||
|
|
@ -408,6 +416,12 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
|
|||
return -EINVAL;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(n->id, "format") == 0) {
|
||||
err = snd_config_string_get(n, &format);
|
||||
if (err < 0)
|
||||
return -EINVAL;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(n->id, "file") == 0) {
|
||||
err = snd_config_string_get(n, &fname);
|
||||
if (err < 0) {
|
||||
|
|
@ -434,7 +448,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
|
|||
free(sname);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_file_open(pcmp, name, fname, fd, spcm, 1);
|
||||
err = snd_pcm_file_open(pcmp, name, fname, fd, format, spcm, 1);
|
||||
if (err < 0)
|
||||
snd_pcm_close(spcm);
|
||||
return err;
|
||||
|
|
|
|||
196
src/pcm/pcm_hw.c
196
src/pcm/pcm_hw.c
|
|
@ -29,17 +29,24 @@
|
|||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <asm/page.h>
|
||||
#include "pcm_local.h"
|
||||
#include "../control/control_local.h"
|
||||
|
||||
#ifndef F_SETSIG
|
||||
#define F_SETSIG 10
|
||||
#endif
|
||||
|
||||
#ifndef PAGE_ALIGN
|
||||
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
int card, device, subdevice;
|
||||
volatile snd_pcm_mmap_status_t *mmap_status;
|
||||
snd_pcm_mmap_control_t *mmap_control;
|
||||
int shmid;
|
||||
} snd_pcm_hw_t;
|
||||
|
||||
#define SND_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
|
||||
|
|
@ -102,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;
|
||||
|
|
@ -113,41 +120,57 @@ static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
|
||||
static int snd_pcm_hw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
int fd = hw->fd;
|
||||
if (ioctl(fd, SND_PCM_IOCTL_PARAMS_INFO, info) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_PARAMS_INFO failed");
|
||||
if (ioctl(fd, SND_PCM_IOCTL_HW_INFO, info) < 0) {
|
||||
// SYSERR("SND_PCM_IOCTL_HW_INFO failed");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||
static int snd_pcm_hw_hw_params(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_PARAMS, params) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_PARAMS failed");
|
||||
if (ioctl(fd, SND_PCM_IOCTL_HW_PARAMS, params) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_HW_PARAMS failed");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
||||
static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
int fd = hw->fd;
|
||||
if (ioctl(fd, SND_PCM_IOCTL_SETUP, setup) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_SETUP failed");
|
||||
if (ioctl(fd, SND_PCM_IOCTL_SW_PARAMS, params) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_SW_PARAMS failed");
|
||||
return -errno;
|
||||
}
|
||||
if (setup->mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
|
||||
if (setup->xfer_mode == SND_PCM_XFER_INTERLEAVED)
|
||||
setup->mmap_shape = SND_PCM_MMAP_INTERLEAVED;
|
||||
else
|
||||
setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
int fd = hw->fd;
|
||||
if (ioctl(fd, SND_PCM_IOCTL_DIG_INFO, info) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_DIG_INFO failed");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
int fd = hw->fd;
|
||||
if (ioctl(fd, SND_PCM_IOCTL_DIG_PARAMS, params) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_DIG_PARAMS failed");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -155,51 +178,24 @@ static int snd_pcm_hw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
|||
static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
snd_pcm_hw_channel_info_t hw_info;
|
||||
int fd = hw->fd;
|
||||
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, info) < 0) {
|
||||
hw_info.channel = info->channel;
|
||||
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, &hw_info) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_CHANNEL_INFO failed");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
int fd = hw->fd;
|
||||
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_PARAMS, params) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_CHANNEL_PARAMS failed");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
int fd = hw->fd;
|
||||
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_CHANNEL_SETUP failed");
|
||||
return -errno;
|
||||
}
|
||||
if (!pcm->mmap_info)
|
||||
info->channel = hw_info.channel;
|
||||
if (pcm->info & SND_PCM_INFO_MMAP) {
|
||||
info->addr = 0;
|
||||
info->first = hw_info.first;
|
||||
info->step = hw_info.step;
|
||||
info->type = SND_PCM_AREA_MMAP;
|
||||
info->u.mmap.fd = fd;
|
||||
info->u.mmap.offset = hw_info.offset;
|
||||
return 0;
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
|
||||
if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
|
||||
setup->running_area.addr = pcm->mmap_info->addr;
|
||||
setup->running_area.first = setup->channel * pcm->bits_per_sample;
|
||||
setup->running_area.step = pcm->bits_per_frame;
|
||||
} else {
|
||||
setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
|
||||
setup->running_area.first = 0;
|
||||
setup->running_area.step = pcm->bits_per_sample;
|
||||
}
|
||||
setup->stopped_area = setup->running_area;
|
||||
} else {
|
||||
setup->running_area.addr = pcm->mmap_info->addr + (long)setup->running_area.addr;
|
||||
setup->stopped_area.addr = setup->running_area.addr;
|
||||
}
|
||||
return 0;
|
||||
return snd_pcm_channel_info_shm(pcm, info, hw->shmid);
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
|
||||
|
|
@ -245,6 +241,8 @@ static int snd_pcm_hw_start(snd_pcm_t *pcm)
|
|||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
int fd = hw->fd;
|
||||
assert(pcm->stream != SND_PCM_STREAM_PLAYBACK ||
|
||||
snd_pcm_mmap_playback_hw_avail(pcm) > 0);
|
||||
if (ioctl(fd, SND_PCM_IOCTL_START) < 0) {
|
||||
SYSERR("SND_PCM_IOCTL_START failed");
|
||||
return -errno;
|
||||
|
|
@ -288,7 +286,7 @@ static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable)
|
|||
static ssize_t snd_pcm_hw_rewind(snd_pcm_t *pcm, size_t frames)
|
||||
{
|
||||
ssize_t hw_avail;
|
||||
if (pcm->setup.xrun_mode == SND_PCM_XRUN_ASAP) {
|
||||
if (pcm->xrun_mode == SND_PCM_XRUN_ASAP) {
|
||||
ssize_t d;
|
||||
int err = snd_pcm_hw_delay(pcm, &d);
|
||||
if (err < 0)
|
||||
|
|
@ -363,7 +361,7 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
|
|||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
void *ptr;
|
||||
ptr = mmap(NULL, sizeof(snd_pcm_mmap_status_t), PROT_READ, MAP_FILE|MAP_SHARED,
|
||||
ptr = mmap(NULL, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)), PROT_READ, MAP_FILE|MAP_SHARED,
|
||||
hw->fd, SND_PCM_MMAP_OFFSET_STATUS);
|
||||
if (ptr == MAP_FAILED || ptr == NULL) {
|
||||
SYSERR("status mmap failed");
|
||||
|
|
@ -378,7 +376,7 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
|
|||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
void *ptr;
|
||||
ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
|
||||
ptr = mmap(NULL, PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t)), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
|
||||
hw->fd, SND_PCM_MMAP_OFFSET_CONTROL);
|
||||
if (ptr == MAP_FAILED || ptr == NULL) {
|
||||
SYSERR("control mmap failed");
|
||||
|
|
@ -389,31 +387,6 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
snd_pcm_mmap_info_t *i = calloc(1, sizeof(*i));
|
||||
int err;
|
||||
if (!i)
|
||||
return -ENOMEM;
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
|
||||
err = snd_pcm_alloc_user_mmap(pcm, i);
|
||||
if (err < 0) {
|
||||
free(i);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
err = snd_pcm_alloc_kernel_mmap(pcm, i, hw->fd);
|
||||
if (err < 0) {
|
||||
free(i);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
pcm->mmap_info = i;
|
||||
pcm->mmap_info_count = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
|
|
@ -434,34 +407,50 @@ static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
if (!(pcm->info & SND_PCM_INFO_MMAP)) {
|
||||
size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
|
||||
int id = shmget(IPC_PRIVATE, size, 0666);
|
||||
if (id < 0) {
|
||||
SYSERR("shmget failed");
|
||||
return -errno;
|
||||
}
|
||||
hw->shmid = id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_munmap(snd_pcm_t *pcm)
|
||||
{
|
||||
int err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
|
||||
if (err < 0)
|
||||
return err;
|
||||
pcm->mmap_info_count = 0;
|
||||
free(pcm->mmap_info);
|
||||
pcm->mmap_info = 0;
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
if (!(pcm->info & SND_PCM_INFO_MMAP)) {
|
||||
if (shmctl(hw->shmid, IPC_RMID, 0) < 0) {
|
||||
SYSERR("shmctl IPC_RMID failed");
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_close(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
int fd = hw->fd;
|
||||
free(hw);
|
||||
if (close(fd)) {
|
||||
if (close(hw->fd)) {
|
||||
SYSERR("close failed\n");
|
||||
return -errno;
|
||||
}
|
||||
snd_pcm_hw_munmap_status(pcm);
|
||||
snd_pcm_hw_munmap_control(pcm);
|
||||
free(hw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size)
|
||||
{
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED && pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
if (!(pcm->info & SND_PCM_INFO_MMAP) &&
|
||||
pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
return snd_pcm_write_mmap(pcm, size);
|
||||
snd_pcm_mmap_appl_forward(pcm, size);
|
||||
return size;
|
||||
|
|
@ -471,8 +460,8 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
|
|||
{
|
||||
size_t avail;
|
||||
ssize_t err;
|
||||
if (pcm->setup.ready_mode == SND_PCM_READY_ASAP ||
|
||||
pcm->setup.xrun_mode == SND_PCM_XRUN_ASAP) {
|
||||
if (pcm->ready_mode == SND_PCM_READY_ASAP ||
|
||||
pcm->xrun_mode == SND_PCM_XRUN_ASAP) {
|
||||
ssize_t d;
|
||||
int err = snd_pcm_hw_delay(pcm, &d);
|
||||
if (err < 0)
|
||||
|
|
@ -482,7 +471,8 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
|
|||
avail = snd_pcm_mmap_playback_avail(pcm);
|
||||
} else {
|
||||
avail = snd_pcm_mmap_capture_avail(pcm);
|
||||
if (avail > 0 && pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
|
||||
if (avail > 0 &&
|
||||
!(pcm->info & SND_PCM_INFO_MMAP)) {
|
||||
err = snd_pcm_read_mmap(pcm, avail);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
@ -490,7 +480,7 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
|
|||
return err;
|
||||
}
|
||||
}
|
||||
if (avail > pcm->setup.buffer_size)
|
||||
if (avail > pcm->buffer_size)
|
||||
return -EPIPE;
|
||||
return avail;
|
||||
}
|
||||
|
|
@ -510,7 +500,7 @@ static void snd_pcm_hw_dump(snd_pcm_t *pcm, FILE *fp)
|
|||
fprintf(fp, "Hardware PCM card %d '%s' device %d subdevice %d\n",
|
||||
hw->card, name, hw->device, hw->subdevice);
|
||||
free(name);
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "\nIts setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -518,13 +508,13 @@ 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,
|
||||
params_info: snd_pcm_hw_params_info,
|
||||
params: snd_pcm_hw_params,
|
||||
setup: snd_pcm_hw_setup,
|
||||
info: _snd_pcm_hw_info,
|
||||
hw_info: snd_pcm_hw_hw_info,
|
||||
hw_params: snd_pcm_hw_hw_params,
|
||||
sw_params: snd_pcm_hw_sw_params,
|
||||
dig_info: snd_pcm_hw_dig_info,
|
||||
dig_params: snd_pcm_hw_dig_params,
|
||||
channel_info: snd_pcm_hw_channel_info,
|
||||
channel_params: snd_pcm_hw_channel_params,
|
||||
channel_setup: snd_pcm_hw_channel_setup,
|
||||
dump: snd_pcm_hw_dump,
|
||||
nonblock: snd_pcm_hw_nonblock,
|
||||
async: snd_pcm_hw_async,
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@ typedef struct {
|
|||
snd_pcm_plugin_t plug;
|
||||
int conv_idx;
|
||||
int sformat;
|
||||
int cformat;
|
||||
int cxfer_mode, cmmap_shape;
|
||||
} snd_pcm_linear_t;
|
||||
|
||||
static void linear_transfer(snd_pcm_channel_area_t *src_areas, size_t src_offset,
|
||||
|
|
@ -74,83 +72,65 @@ static void linear_transfer(snd_pcm_channel_area_t *src_areas, size_t src_offset
|
|||
}
|
||||
}
|
||||
|
||||
static int snd_pcm_linear_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
|
||||
static int snd_pcm_linear_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
|
||||
{
|
||||
snd_pcm_linear_t *linear = pcm->private;
|
||||
unsigned int req_mask = info->req_mask;
|
||||
unsigned int sfmt = info->req.format.sfmt;
|
||||
unsigned int format_mask, access_mask;
|
||||
int err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT &&
|
||||
!snd_pcm_format_linear(sfmt)) {
|
||||
info->req.fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
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);
|
||||
if (info->format_mask)
|
||||
info->format_mask = format_mask;
|
||||
if (info->access_mask) {
|
||||
linear->plug.saccess_mask = info->access_mask;
|
||||
info->access_mask = access_mask;
|
||||
}
|
||||
info->req_mask |= SND_PCM_PARAMS_SFMT;
|
||||
info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
|
||||
SND_PCM_PARAMS_XFER_MODE);
|
||||
info->req.format.sfmt = linear->sformat;
|
||||
err = snd_pcm_params_info(linear->plug.slave, info);
|
||||
info->req_mask = req_mask;
|
||||
info->req.format.sfmt = sfmt;
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT)
|
||||
info->formats = 1 << sfmt;
|
||||
else
|
||||
info->formats = SND_PCM_LINEAR_FORMATS;
|
||||
info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
|
||||
return err;
|
||||
info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
snd_pcm_hw_info_complete(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||
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;
|
||||
unsigned int format, access;
|
||||
int err;
|
||||
if (!snd_pcm_format_linear(params->format.sfmt)) {
|
||||
params->fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
linear->cformat = params->format.sfmt;
|
||||
linear->cxfer_mode = params->xfer_mode;
|
||||
linear->cmmap_shape = params->mmap_shape;
|
||||
params->format.sfmt = linear->sformat;
|
||||
params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
|
||||
err = snd_pcm_params_mmap(slave, params);
|
||||
params->format.sfmt = linear->cformat;
|
||||
params->xfer_mode = linear->cxfer_mode;
|
||||
params->mmap_shape = linear->cmmap_shape;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_linear_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
||||
{
|
||||
snd_pcm_linear_t *linear = pcm->private;
|
||||
int err = snd_pcm_setup(linear->plug.slave, setup);
|
||||
format = params->format;
|
||||
access = params->access;
|
||||
params->format = linear->sformat;
|
||||
if (linear->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
|
||||
else if (linear->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
assert(0);
|
||||
err = snd_pcm_hw_params(slave, params);
|
||||
params->format = format;
|
||||
params->access = access;
|
||||
if (err < 0)
|
||||
return err;
|
||||
assert(linear->sformat == setup->format.sfmt);
|
||||
|
||||
if (linear->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
|
||||
setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
|
||||
else
|
||||
setup->xfer_mode = linear->cxfer_mode;
|
||||
if (linear->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
|
||||
setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
setup->mmap_shape = linear->cmmap_shape;
|
||||
setup->format.sfmt = linear->cformat;
|
||||
setup->mmap_bytes = 0;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
linear->conv_idx = conv_index(linear->cformat,
|
||||
linear->conv_idx = conv_index(format,
|
||||
linear->sformat);
|
||||
else
|
||||
linear->conv_idx = conv_index(linear->sformat,
|
||||
linear->cformat);
|
||||
format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -171,7 +151,7 @@ static ssize_t snd_pcm_linear_write_areas(snd_pcm_t *pcm,
|
|||
size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
|
||||
linear_transfer(areas, offset,
|
||||
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
frames, pcm->setup.format.channels, linear->conv_idx);
|
||||
frames, pcm->channels, linear->conv_idx);
|
||||
err = snd_pcm_mmap_forward(slave, frames);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
|
@ -205,7 +185,7 @@ static ssize_t snd_pcm_linear_read_areas(snd_pcm_t *pcm,
|
|||
size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
|
||||
linear_transfer(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
areas, offset,
|
||||
frames, pcm->setup.format.channels, linear->conv_idx);
|
||||
frames, pcm->channels, linear->conv_idx);
|
||||
err = snd_pcm_mmap_forward(slave, frames);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
|
@ -227,7 +207,7 @@ static void snd_pcm_linear_dump(snd_pcm_t *pcm, FILE *fp)
|
|||
snd_pcm_linear_t *linear = pcm->private;
|
||||
fprintf(fp, "Linear conversion PCM (%s)\n",
|
||||
snd_pcm_format_name(linear->sformat));
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "Its setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -238,12 +218,12 @@ 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,
|
||||
params_info: snd_pcm_linear_params_info,
|
||||
params: snd_pcm_linear_params,
|
||||
setup: snd_pcm_linear_setup,
|
||||
hw_info: snd_pcm_linear_hw_info,
|
||||
hw_params: snd_pcm_linear_hw_params,
|
||||
sw_params: snd_pcm_plugin_sw_params,
|
||||
dig_info: snd_pcm_plugin_dig_info,
|
||||
dig_params: snd_pcm_plugin_dig_params,
|
||||
channel_info: snd_pcm_plugin_channel_info,
|
||||
channel_params: snd_pcm_plugin_channel_params,
|
||||
channel_setup: snd_pcm_plugin_channel_setup,
|
||||
dump: snd_pcm_linear_dump,
|
||||
nonblock: snd_pcm_plugin_nonblock,
|
||||
async: snd_pcm_plugin_async,
|
||||
|
|
|
|||
|
|
@ -22,29 +22,48 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
#include "asoundlib.h"
|
||||
|
||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
|
||||
#define ERR(...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
|
||||
#define SYSERR(...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
|
||||
#define ERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
|
||||
#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
|
||||
#else
|
||||
#define ERR(args...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
|
||||
#define SYSERR(args...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
|
||||
#define ERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
|
||||
#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
|
||||
#endif
|
||||
|
||||
typedef struct _snd_pcm_channel_info {
|
||||
unsigned int channel;
|
||||
void *addr; /* base address of channel samples */
|
||||
unsigned int first; /* offset to first sample in bits */
|
||||
unsigned int step; /* samples distance in bits */
|
||||
enum { SND_PCM_AREA_SHM, SND_PCM_AREA_MMAP } type;
|
||||
union {
|
||||
struct {
|
||||
int shmid;
|
||||
} shm;
|
||||
struct {
|
||||
int fd;
|
||||
off_t offset;
|
||||
} mmap;
|
||||
} u;
|
||||
char reserved[64];
|
||||
} snd_pcm_channel_info_t;
|
||||
|
||||
typedef struct {
|
||||
int (*close)(snd_pcm_t *pcm);
|
||||
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 (*params_info)(snd_pcm_t *pcm, snd_pcm_params_info_t *info);
|
||||
int (*params)(snd_pcm_t *pcm, snd_pcm_params_t *params);
|
||||
int (*setup)(snd_pcm_t *pcm, snd_pcm_setup_t *setup);
|
||||
int (*hw_info)(snd_pcm_t *pcm, snd_pcm_hw_info_t *info);
|
||||
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);
|
||||
int (*dig_params)(snd_pcm_t *pcm, snd_pcm_dig_params_t *params);
|
||||
int (*channel_info)(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
|
||||
int (*channel_params)(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
|
||||
int (*channel_setup)(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
|
||||
void (*dump)(snd_pcm_t *pcm, FILE *fp);
|
||||
int (*mmap)(snd_pcm_t *pcm);
|
||||
int (*munmap)(snd_pcm_t *pcm);
|
||||
|
|
@ -69,38 +88,43 @@ typedef struct {
|
|||
int (*set_avail_min)(snd_pcm_t *pcm, size_t frames);
|
||||
} snd_pcm_fast_ops_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int index;
|
||||
enum { SND_PCM_MMAP_KERNEL, SND_PCM_MMAP_USER } type;
|
||||
void *addr;
|
||||
size_t size;
|
||||
union {
|
||||
struct {
|
||||
int shmid;
|
||||
} user;
|
||||
struct {
|
||||
int fd;
|
||||
} kernel;
|
||||
} u;
|
||||
} snd_pcm_mmap_info_t;
|
||||
|
||||
struct snd_pcm {
|
||||
struct _snd_pcm {
|
||||
char *name;
|
||||
snd_pcm_type_t type;
|
||||
int stream;
|
||||
int mode;
|
||||
int poll_fd;
|
||||
int valid_setup;
|
||||
snd_pcm_setup_t setup;
|
||||
int setup;
|
||||
unsigned int access; /* access mode */
|
||||
unsigned int format; /* SND_PCM_FORMAT_* */
|
||||
unsigned int subformat; /* subformat */
|
||||
unsigned int rate; /* rate in Hz */
|
||||
unsigned int channels; /* channels */
|
||||
size_t fragment_size; /* fragment size */
|
||||
unsigned int fragments; /* fragments */
|
||||
unsigned int start_mode; /* start mode */
|
||||
unsigned int ready_mode; /* ready detection mode */
|
||||
unsigned int xrun_mode; /* xrun detection mode */
|
||||
size_t avail_min; /* min avail frames for wakeup */
|
||||
size_t xfer_min; /* xfer min size */
|
||||
size_t xfer_align; /* xfer size need to be a multiple */
|
||||
unsigned int time: 1; /* timestamp switch */
|
||||
size_t boundary; /* pointers wrap point */
|
||||
unsigned int info; /* Info for returned setup */
|
||||
unsigned int msbits; /* used most significant bits */
|
||||
unsigned int rate_master; /* Exact rate is rate_master / */
|
||||
unsigned int rate_divisor; /* rate_divisor */
|
||||
size_t fifo_size; /* chip FIFO size in frames */
|
||||
size_t buffer_size;
|
||||
size_t bits_per_sample;
|
||||
size_t bits_per_frame;
|
||||
size_t *appl_ptr;
|
||||
volatile size_t *hw_ptr;
|
||||
int mmap_auto;
|
||||
size_t mmap_info_count;
|
||||
snd_pcm_mmap_info_t *mmap_info;
|
||||
int mmap_rw;
|
||||
snd_pcm_channel_info_t *mmap_channels;
|
||||
snd_pcm_channel_area_t *running_areas;
|
||||
snd_pcm_channel_area_t *stopped_areas;
|
||||
void *stopped;
|
||||
snd_pcm_ops_t *ops;
|
||||
snd_pcm_fast_ops_t *fast_ops;
|
||||
snd_pcm_t *op_arg;
|
||||
|
|
@ -108,10 +132,18 @@ struct snd_pcm {
|
|||
void *private;
|
||||
};
|
||||
|
||||
int snd_pcm_hw_open(snd_pcm_t **pcm, char *name, int card, int device, int subdevice, int stream, int mode);
|
||||
int snd_pcm_plug_open_hw(snd_pcm_t **pcm, char *name, int card, int device, int subdevice, int stream, int mode);
|
||||
int snd_pcm_shm_open(snd_pcm_t **pcmp, char *name, char *socket, char *sname, int stream, int mode);
|
||||
int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, char *fmt, snd_pcm_t *slave, int close_slave);
|
||||
int snd_pcm_null_open(snd_pcm_t **pcmp, char *name, int stream, int mode);
|
||||
|
||||
|
||||
void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf);
|
||||
void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs);
|
||||
|
||||
int snd_pcm_params_mmap(snd_pcm_t *pcm, snd_pcm_params_t *params);
|
||||
int snd_pcm_mmap(snd_pcm_t *pcm);
|
||||
int snd_pcm_munmap(snd_pcm_t *pcm);
|
||||
int snd_pcm_mmap_ready(snd_pcm_t *pcm);
|
||||
ssize_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset);
|
||||
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames);
|
||||
|
|
@ -135,16 +167,19 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, 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_alloc_user_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i);
|
||||
int snd_pcm_alloc_kernel_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i, int fd);
|
||||
int snd_pcm_free_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i);
|
||||
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);
|
||||
void snd_pcm_hw_info_to_params(snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params);
|
||||
void snd_pcm_hw_info_to_params_fail(snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params);
|
||||
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);
|
||||
|
||||
static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
|
||||
{
|
||||
ssize_t avail;
|
||||
avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr;
|
||||
avail = *pcm->hw_ptr + pcm->buffer_size - *pcm->appl_ptr;
|
||||
if (avail < 0)
|
||||
avail += pcm->setup.boundary;
|
||||
avail += pcm->boundary;
|
||||
return avail;
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +188,7 @@ static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
|
|||
ssize_t avail;
|
||||
avail = *pcm->hw_ptr - *pcm->appl_ptr;
|
||||
if (avail < 0)
|
||||
avail += pcm->setup.boundary;
|
||||
avail += pcm->boundary;
|
||||
return avail;
|
||||
}
|
||||
|
||||
|
|
@ -162,19 +197,19 @@ static inline size_t snd_pcm_mmap_avail(snd_pcm_t *pcm)
|
|||
ssize_t avail;
|
||||
avail = *pcm->hw_ptr - *pcm->appl_ptr;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
avail += pcm->setup.buffer_size;
|
||||
avail += pcm->buffer_size;
|
||||
if (avail < 0)
|
||||
avail += pcm->setup.boundary;
|
||||
avail += pcm->boundary;
|
||||
return avail;
|
||||
}
|
||||
|
||||
static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
|
||||
{
|
||||
ssize_t avail;
|
||||
avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr;
|
||||
avail = *pcm->hw_ptr + pcm->buffer_size - *pcm->appl_ptr;
|
||||
if (avail < 0)
|
||||
avail += pcm->setup.boundary;
|
||||
return pcm->setup.buffer_size - avail;
|
||||
avail += pcm->boundary;
|
||||
return pcm->buffer_size - avail;
|
||||
}
|
||||
|
||||
static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
|
||||
|
|
@ -182,8 +217,8 @@ static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
|
|||
ssize_t avail;
|
||||
avail = *pcm->hw_ptr - *pcm->appl_ptr;
|
||||
if (avail < 0)
|
||||
avail += pcm->setup.boundary;
|
||||
return pcm->setup.buffer_size - avail;
|
||||
avail += pcm->boundary;
|
||||
return pcm->buffer_size - avail;
|
||||
}
|
||||
|
||||
static inline ssize_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
|
||||
|
|
@ -191,10 +226,10 @@ static inline ssize_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
|
|||
ssize_t avail;
|
||||
avail = *pcm->hw_ptr - *pcm->appl_ptr;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
avail += pcm->setup.buffer_size;
|
||||
avail += pcm->buffer_size;
|
||||
if (avail < 0)
|
||||
avail += pcm->setup.boundary;
|
||||
return pcm->setup.buffer_size - avail;
|
||||
avail += pcm->boundary;
|
||||
return pcm->buffer_size - avail;
|
||||
}
|
||||
|
||||
#define snd_pcm_mmap_playback_delay snd_pcm_mmap_playback_hw_avail
|
||||
|
|
|
|||
|
|
@ -39,21 +39,21 @@
|
|||
int snd_pcm_format_signed(int format)
|
||||
{
|
||||
switch (format) {
|
||||
case SND_PCM_SFMT_S8:
|
||||
case SND_PCM_SFMT_S16_LE:
|
||||
case SND_PCM_SFMT_S16_BE:
|
||||
case SND_PCM_SFMT_S24_LE:
|
||||
case SND_PCM_SFMT_S24_BE:
|
||||
case SND_PCM_SFMT_S32_LE:
|
||||
case SND_PCM_SFMT_S32_BE:
|
||||
case SND_PCM_FORMAT_S8:
|
||||
case SND_PCM_FORMAT_S16_LE:
|
||||
case SND_PCM_FORMAT_S16_BE:
|
||||
case SND_PCM_FORMAT_S24_LE:
|
||||
case SND_PCM_FORMAT_S24_BE:
|
||||
case SND_PCM_FORMAT_S32_LE:
|
||||
case SND_PCM_FORMAT_S32_BE:
|
||||
return 1;
|
||||
case SND_PCM_SFMT_U8:
|
||||
case SND_PCM_SFMT_U16_LE:
|
||||
case SND_PCM_SFMT_U16_BE:
|
||||
case SND_PCM_SFMT_U24_LE:
|
||||
case SND_PCM_SFMT_U24_BE:
|
||||
case SND_PCM_SFMT_U32_LE:
|
||||
case SND_PCM_SFMT_U32_BE:
|
||||
case SND_PCM_FORMAT_U8:
|
||||
case SND_PCM_FORMAT_U16_LE:
|
||||
case SND_PCM_FORMAT_U16_BE:
|
||||
case SND_PCM_FORMAT_U24_LE:
|
||||
case SND_PCM_FORMAT_U24_BE:
|
||||
case SND_PCM_FORMAT_U32_LE:
|
||||
case SND_PCM_FORMAT_U32_BE:
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
@ -78,25 +78,25 @@ int snd_pcm_format_linear(int format)
|
|||
int snd_pcm_format_little_endian(int format)
|
||||
{
|
||||
switch (format) {
|
||||
case SND_PCM_SFMT_S16_LE:
|
||||
case SND_PCM_SFMT_U16_LE:
|
||||
case SND_PCM_SFMT_S24_LE:
|
||||
case SND_PCM_SFMT_U24_LE:
|
||||
case SND_PCM_SFMT_S32_LE:
|
||||
case SND_PCM_SFMT_U32_LE:
|
||||
case SND_PCM_SFMT_FLOAT_LE:
|
||||
case SND_PCM_SFMT_FLOAT64_LE:
|
||||
case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
|
||||
case SND_PCM_FORMAT_S16_LE:
|
||||
case SND_PCM_FORMAT_U16_LE:
|
||||
case SND_PCM_FORMAT_S24_LE:
|
||||
case SND_PCM_FORMAT_U24_LE:
|
||||
case SND_PCM_FORMAT_S32_LE:
|
||||
case SND_PCM_FORMAT_U32_LE:
|
||||
case SND_PCM_FORMAT_FLOAT_LE:
|
||||
case SND_PCM_FORMAT_FLOAT64_LE:
|
||||
case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
|
||||
return 1;
|
||||
case SND_PCM_SFMT_S16_BE:
|
||||
case SND_PCM_SFMT_U16_BE:
|
||||
case SND_PCM_SFMT_S24_BE:
|
||||
case SND_PCM_SFMT_U24_BE:
|
||||
case SND_PCM_SFMT_S32_BE:
|
||||
case SND_PCM_SFMT_U32_BE:
|
||||
case SND_PCM_SFMT_FLOAT_BE:
|
||||
case SND_PCM_SFMT_FLOAT64_BE:
|
||||
case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
|
||||
case SND_PCM_FORMAT_S16_BE:
|
||||
case SND_PCM_FORMAT_U16_BE:
|
||||
case SND_PCM_FORMAT_S24_BE:
|
||||
case SND_PCM_FORMAT_U24_BE:
|
||||
case SND_PCM_FORMAT_S32_BE:
|
||||
case SND_PCM_FORMAT_U32_BE:
|
||||
case SND_PCM_FORMAT_FLOAT_BE:
|
||||
case SND_PCM_FORMAT_FLOAT64_BE:
|
||||
case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
@ -116,36 +116,36 @@ int snd_pcm_format_big_endian(int format)
|
|||
int snd_pcm_format_width(int format)
|
||||
{
|
||||
switch (format) {
|
||||
case SND_PCM_SFMT_S8:
|
||||
case SND_PCM_SFMT_U8:
|
||||
case SND_PCM_FORMAT_S8:
|
||||
case SND_PCM_FORMAT_U8:
|
||||
return 8;
|
||||
case SND_PCM_SFMT_S16_LE:
|
||||
case SND_PCM_SFMT_S16_BE:
|
||||
case SND_PCM_SFMT_U16_LE:
|
||||
case SND_PCM_SFMT_U16_BE:
|
||||
case SND_PCM_FORMAT_S16_LE:
|
||||
case SND_PCM_FORMAT_S16_BE:
|
||||
case SND_PCM_FORMAT_U16_LE:
|
||||
case SND_PCM_FORMAT_U16_BE:
|
||||
return 16;
|
||||
case SND_PCM_SFMT_S24_LE:
|
||||
case SND_PCM_SFMT_S24_BE:
|
||||
case SND_PCM_SFMT_U24_LE:
|
||||
case SND_PCM_SFMT_U24_BE:
|
||||
case SND_PCM_FORMAT_S24_LE:
|
||||
case SND_PCM_FORMAT_S24_BE:
|
||||
case SND_PCM_FORMAT_U24_LE:
|
||||
case SND_PCM_FORMAT_U24_BE:
|
||||
return 24;
|
||||
case SND_PCM_SFMT_S32_LE:
|
||||
case SND_PCM_SFMT_S32_BE:
|
||||
case SND_PCM_SFMT_U32_LE:
|
||||
case SND_PCM_SFMT_U32_BE:
|
||||
case SND_PCM_SFMT_FLOAT_LE:
|
||||
case SND_PCM_SFMT_FLOAT_BE:
|
||||
case SND_PCM_FORMAT_S32_LE:
|
||||
case SND_PCM_FORMAT_S32_BE:
|
||||
case SND_PCM_FORMAT_U32_LE:
|
||||
case SND_PCM_FORMAT_U32_BE:
|
||||
case SND_PCM_FORMAT_FLOAT_LE:
|
||||
case SND_PCM_FORMAT_FLOAT_BE:
|
||||
return 32;
|
||||
case SND_PCM_SFMT_FLOAT64_LE:
|
||||
case SND_PCM_SFMT_FLOAT64_BE:
|
||||
case SND_PCM_FORMAT_FLOAT64_LE:
|
||||
case SND_PCM_FORMAT_FLOAT64_BE:
|
||||
return 64;
|
||||
case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
|
||||
case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
|
||||
case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
|
||||
case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
|
||||
return 24;
|
||||
case SND_PCM_SFMT_MU_LAW:
|
||||
case SND_PCM_SFMT_A_LAW:
|
||||
case SND_PCM_FORMAT_MU_LAW:
|
||||
case SND_PCM_FORMAT_A_LAW:
|
||||
return 8;
|
||||
case SND_PCM_SFMT_IMA_ADPCM:
|
||||
case SND_PCM_FORMAT_IMA_ADPCM:
|
||||
return 4;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
@ -155,34 +155,34 @@ int snd_pcm_format_width(int format)
|
|||
int snd_pcm_format_physical_width(int format)
|
||||
{
|
||||
switch (format) {
|
||||
case SND_PCM_SFMT_S8:
|
||||
case SND_PCM_SFMT_U8:
|
||||
case SND_PCM_FORMAT_S8:
|
||||
case SND_PCM_FORMAT_U8:
|
||||
return 8;
|
||||
case SND_PCM_SFMT_S16_LE:
|
||||
case SND_PCM_SFMT_S16_BE:
|
||||
case SND_PCM_SFMT_U16_LE:
|
||||
case SND_PCM_SFMT_U16_BE:
|
||||
case SND_PCM_FORMAT_S16_LE:
|
||||
case SND_PCM_FORMAT_S16_BE:
|
||||
case SND_PCM_FORMAT_U16_LE:
|
||||
case SND_PCM_FORMAT_U16_BE:
|
||||
return 16;
|
||||
case SND_PCM_SFMT_S24_LE:
|
||||
case SND_PCM_SFMT_S24_BE:
|
||||
case SND_PCM_SFMT_U24_LE:
|
||||
case SND_PCM_SFMT_U24_BE:
|
||||
case SND_PCM_SFMT_S32_LE:
|
||||
case SND_PCM_SFMT_S32_BE:
|
||||
case SND_PCM_SFMT_U32_LE:
|
||||
case SND_PCM_SFMT_U32_BE:
|
||||
case SND_PCM_SFMT_FLOAT_LE:
|
||||
case SND_PCM_SFMT_FLOAT_BE:
|
||||
case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
|
||||
case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
|
||||
case SND_PCM_FORMAT_S24_LE:
|
||||
case SND_PCM_FORMAT_S24_BE:
|
||||
case SND_PCM_FORMAT_U24_LE:
|
||||
case SND_PCM_FORMAT_U24_BE:
|
||||
case SND_PCM_FORMAT_S32_LE:
|
||||
case SND_PCM_FORMAT_S32_BE:
|
||||
case SND_PCM_FORMAT_U32_LE:
|
||||
case SND_PCM_FORMAT_U32_BE:
|
||||
case SND_PCM_FORMAT_FLOAT_LE:
|
||||
case SND_PCM_FORMAT_FLOAT_BE:
|
||||
case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
|
||||
case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
|
||||
return 32;
|
||||
case SND_PCM_SFMT_FLOAT64_LE:
|
||||
case SND_PCM_SFMT_FLOAT64_BE:
|
||||
case SND_PCM_FORMAT_FLOAT64_LE:
|
||||
case SND_PCM_FORMAT_FLOAT64_BE:
|
||||
return 64;
|
||||
case SND_PCM_SFMT_MU_LAW:
|
||||
case SND_PCM_SFMT_A_LAW:
|
||||
case SND_PCM_FORMAT_MU_LAW:
|
||||
case SND_PCM_FORMAT_A_LAW:
|
||||
return 8;
|
||||
case SND_PCM_SFMT_IMA_ADPCM:
|
||||
case SND_PCM_FORMAT_IMA_ADPCM:
|
||||
return 4;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
@ -192,35 +192,35 @@ int snd_pcm_format_physical_width(int format)
|
|||
ssize_t snd_pcm_format_size(int format, size_t samples)
|
||||
{
|
||||
switch (format) {
|
||||
case SND_PCM_SFMT_S8:
|
||||
case SND_PCM_SFMT_U8:
|
||||
case SND_PCM_FORMAT_S8:
|
||||
case SND_PCM_FORMAT_U8:
|
||||
return samples;
|
||||
case SND_PCM_SFMT_S16_LE:
|
||||
case SND_PCM_SFMT_S16_BE:
|
||||
case SND_PCM_SFMT_U16_LE:
|
||||
case SND_PCM_SFMT_U16_BE:
|
||||
case SND_PCM_FORMAT_S16_LE:
|
||||
case SND_PCM_FORMAT_S16_BE:
|
||||
case SND_PCM_FORMAT_U16_LE:
|
||||
case SND_PCM_FORMAT_U16_BE:
|
||||
return samples * 2;
|
||||
case SND_PCM_SFMT_S24_LE:
|
||||
case SND_PCM_SFMT_S24_BE:
|
||||
case SND_PCM_SFMT_U24_LE:
|
||||
case SND_PCM_SFMT_U24_BE:
|
||||
case SND_PCM_SFMT_S32_LE:
|
||||
case SND_PCM_SFMT_S32_BE:
|
||||
case SND_PCM_SFMT_U32_LE:
|
||||
case SND_PCM_SFMT_U32_BE:
|
||||
case SND_PCM_SFMT_FLOAT_LE:
|
||||
case SND_PCM_SFMT_FLOAT_BE:
|
||||
case SND_PCM_FORMAT_S24_LE:
|
||||
case SND_PCM_FORMAT_S24_BE:
|
||||
case SND_PCM_FORMAT_U24_LE:
|
||||
case SND_PCM_FORMAT_U24_BE:
|
||||
case SND_PCM_FORMAT_S32_LE:
|
||||
case SND_PCM_FORMAT_S32_BE:
|
||||
case SND_PCM_FORMAT_U32_LE:
|
||||
case SND_PCM_FORMAT_U32_BE:
|
||||
case SND_PCM_FORMAT_FLOAT_LE:
|
||||
case SND_PCM_FORMAT_FLOAT_BE:
|
||||
return samples * 4;
|
||||
case SND_PCM_SFMT_FLOAT64_LE:
|
||||
case SND_PCM_SFMT_FLOAT64_BE:
|
||||
case SND_PCM_FORMAT_FLOAT64_LE:
|
||||
case SND_PCM_FORMAT_FLOAT64_BE:
|
||||
return samples * 8;
|
||||
case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
|
||||
case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
|
||||
case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
|
||||
case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
|
||||
return samples * 4;
|
||||
case SND_PCM_SFMT_MU_LAW:
|
||||
case SND_PCM_SFMT_A_LAW:
|
||||
case SND_PCM_FORMAT_MU_LAW:
|
||||
case SND_PCM_FORMAT_A_LAW:
|
||||
return samples;
|
||||
case SND_PCM_SFMT_IMA_ADPCM:
|
||||
case SND_PCM_FORMAT_IMA_ADPCM:
|
||||
if (samples & 1)
|
||||
return -EINVAL;
|
||||
return samples / 2;
|
||||
|
|
@ -232,44 +232,44 @@ ssize_t snd_pcm_format_size(int format, size_t samples)
|
|||
u_int64_t snd_pcm_format_silence_64(int format)
|
||||
{
|
||||
switch (format) {
|
||||
case SND_PCM_SFMT_S8:
|
||||
case SND_PCM_SFMT_S16_LE:
|
||||
case SND_PCM_SFMT_S16_BE:
|
||||
case SND_PCM_SFMT_S24_LE:
|
||||
case SND_PCM_SFMT_S24_BE:
|
||||
case SND_PCM_SFMT_S32_LE:
|
||||
case SND_PCM_SFMT_S32_BE:
|
||||
case SND_PCM_FORMAT_S8:
|
||||
case SND_PCM_FORMAT_S16_LE:
|
||||
case SND_PCM_FORMAT_S16_BE:
|
||||
case SND_PCM_FORMAT_S24_LE:
|
||||
case SND_PCM_FORMAT_S24_BE:
|
||||
case SND_PCM_FORMAT_S32_LE:
|
||||
case SND_PCM_FORMAT_S32_BE:
|
||||
return 0;
|
||||
case SND_PCM_SFMT_U8:
|
||||
case SND_PCM_FORMAT_U8:
|
||||
return 0x8080808080808080ULL;
|
||||
#ifdef SND_LITTLE_ENDIAN
|
||||
case SND_PCM_SFMT_U16_LE:
|
||||
case SND_PCM_FORMAT_U16_LE:
|
||||
return 0x8000800080008000ULL;
|
||||
case SND_PCM_SFMT_U24_LE:
|
||||
case SND_PCM_FORMAT_U24_LE:
|
||||
return 0x0080000000800000ULL;
|
||||
case SND_PCM_SFMT_U32_LE:
|
||||
case SND_PCM_FORMAT_U32_LE:
|
||||
return 0x8000000080000000ULL;
|
||||
case SND_PCM_SFMT_U16_BE:
|
||||
case SND_PCM_FORMAT_U16_BE:
|
||||
return 0x0080008000800080ULL;
|
||||
case SND_PCM_SFMT_U24_BE:
|
||||
case SND_PCM_FORMAT_U24_BE:
|
||||
return 0x0000800000008000ULL;
|
||||
case SND_PCM_SFMT_U32_BE:
|
||||
case SND_PCM_FORMAT_U32_BE:
|
||||
return 0x0000008000000080ULL;
|
||||
#else
|
||||
case SND_PCM_SFMT_U16_LE:
|
||||
case SND_PCM_FORMAT_U16_LE:
|
||||
return 0x0080008000800080ULL;
|
||||
case SND_PCM_SFMT_U24_LE:
|
||||
case SND_PCM_FORMAT_U24_LE:
|
||||
return 0x0000800000008000ULL;
|
||||
case SND_PCM_SFMT_U32_LE:
|
||||
case SND_PCM_FORMAT_U32_LE:
|
||||
return 0x0000008000000080ULL;
|
||||
case SND_PCM_SFMT_U16_BE:
|
||||
case SND_PCM_FORMAT_U16_BE:
|
||||
return 0x8000800080008000ULL;
|
||||
case SND_PCM_SFMT_U24_BE:
|
||||
case SND_PCM_FORMAT_U24_BE:
|
||||
return 0x0080000000800000ULL;
|
||||
case SND_PCM_SFMT_U32_BE:
|
||||
case SND_PCM_FORMAT_U32_BE:
|
||||
return 0x8000000080000000ULL;
|
||||
#endif
|
||||
case SND_PCM_SFMT_FLOAT_LE:
|
||||
case SND_PCM_FORMAT_FLOAT_LE:
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
|
|
@ -282,7 +282,7 @@ u_int64_t snd_pcm_format_silence_64(int format)
|
|||
return bswap_32(u.i);
|
||||
#endif
|
||||
}
|
||||
case SND_PCM_SFMT_FLOAT64_LE:
|
||||
case SND_PCM_FORMAT_FLOAT64_LE:
|
||||
{
|
||||
union {
|
||||
double f;
|
||||
|
|
@ -295,7 +295,7 @@ u_int64_t snd_pcm_format_silence_64(int format)
|
|||
return bswap_64(u.i);
|
||||
#endif
|
||||
}
|
||||
case SND_PCM_SFMT_FLOAT_BE:
|
||||
case SND_PCM_FORMAT_FLOAT_BE:
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
|
|
@ -308,7 +308,7 @@ u_int64_t snd_pcm_format_silence_64(int format)
|
|||
return u.i;
|
||||
#endif
|
||||
}
|
||||
case SND_PCM_SFMT_FLOAT64_BE:
|
||||
case SND_PCM_FORMAT_FLOAT64_BE:
|
||||
{
|
||||
union {
|
||||
double f;
|
||||
|
|
@ -321,16 +321,16 @@ u_int64_t snd_pcm_format_silence_64(int format)
|
|||
return u.i;
|
||||
#endif
|
||||
}
|
||||
case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
|
||||
case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
|
||||
case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
|
||||
case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
|
||||
return 0;
|
||||
case SND_PCM_SFMT_MU_LAW:
|
||||
case SND_PCM_FORMAT_MU_LAW:
|
||||
return 0x7f7f7f7f7f7f7f7fULL;
|
||||
case SND_PCM_SFMT_A_LAW:
|
||||
case SND_PCM_FORMAT_A_LAW:
|
||||
return 0x5555555555555555ULL;
|
||||
case SND_PCM_SFMT_IMA_ADPCM: /* special case */
|
||||
case SND_PCM_SFMT_MPEG:
|
||||
case SND_PCM_SFMT_GSM:
|
||||
case SND_PCM_FORMAT_IMA_ADPCM: /* special case */
|
||||
case SND_PCM_FORMAT_MPEG:
|
||||
case SND_PCM_FORMAT_GSM:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -395,22 +395,22 @@ ssize_t snd_pcm_format_set_silence(int format, void *data, size_t samples)
|
|||
}
|
||||
|
||||
static int linear_formats[4*2*2] = {
|
||||
SND_PCM_SFMT_S8,
|
||||
SND_PCM_SFMT_U8,
|
||||
SND_PCM_SFMT_S8,
|
||||
SND_PCM_SFMT_U8,
|
||||
SND_PCM_SFMT_S16_LE,
|
||||
SND_PCM_SFMT_S16_BE,
|
||||
SND_PCM_SFMT_U16_LE,
|
||||
SND_PCM_SFMT_U16_BE,
|
||||
SND_PCM_SFMT_S24_LE,
|
||||
SND_PCM_SFMT_S24_BE,
|
||||
SND_PCM_SFMT_U24_LE,
|
||||
SND_PCM_SFMT_U24_BE,
|
||||
SND_PCM_SFMT_S32_LE,
|
||||
SND_PCM_SFMT_S32_BE,
|
||||
SND_PCM_SFMT_U32_LE,
|
||||
SND_PCM_SFMT_U32_BE
|
||||
SND_PCM_FORMAT_S8,
|
||||
SND_PCM_FORMAT_U8,
|
||||
SND_PCM_FORMAT_S8,
|
||||
SND_PCM_FORMAT_U8,
|
||||
SND_PCM_FORMAT_S16_LE,
|
||||
SND_PCM_FORMAT_S16_BE,
|
||||
SND_PCM_FORMAT_U16_LE,
|
||||
SND_PCM_FORMAT_U16_BE,
|
||||
SND_PCM_FORMAT_S24_LE,
|
||||
SND_PCM_FORMAT_S24_BE,
|
||||
SND_PCM_FORMAT_U24_LE,
|
||||
SND_PCM_FORMAT_U24_BE,
|
||||
SND_PCM_FORMAT_S32_LE,
|
||||
SND_PCM_FORMAT_S32_BE,
|
||||
SND_PCM_FORMAT_U32_LE,
|
||||
SND_PCM_FORMAT_U32_BE
|
||||
};
|
||||
|
||||
int snd_pcm_build_linear_format(int width, int unsignd, int big_endian)
|
||||
|
|
|
|||
|
|
@ -23,15 +23,23 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <asm/page.h>
|
||||
#include "pcm_local.h"
|
||||
|
||||
|
||||
#ifndef PAGE_ALIGN
|
||||
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
|
||||
#endif
|
||||
|
||||
|
||||
snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
|
||||
{
|
||||
int state = snd_pcm_state(pcm);
|
||||
if (state == SND_PCM_STATE_RUNNING)
|
||||
return pcm->running_areas;
|
||||
else
|
||||
return pcm->stopped_areas;
|
||||
if (pcm->stopped_areas &&
|
||||
snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING)
|
||||
return pcm->stopped_areas;
|
||||
return pcm->running_areas;
|
||||
}
|
||||
|
||||
size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
|
||||
|
|
@ -40,7 +48,7 @@ size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
|
|||
size_t avail = snd_pcm_mmap_playback_avail(pcm);
|
||||
if (avail < frames)
|
||||
frames = avail;
|
||||
cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size;
|
||||
cont = pcm->buffer_size - *pcm->appl_ptr % pcm->buffer_size;
|
||||
if (cont < frames)
|
||||
frames = cont;
|
||||
return frames;
|
||||
|
|
@ -52,7 +60,7 @@ size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames)
|
|||
size_t avail = snd_pcm_mmap_capture_avail(pcm);
|
||||
if (avail < frames)
|
||||
frames = avail;
|
||||
cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size;
|
||||
cont = pcm->buffer_size - *pcm->appl_ptr % pcm->buffer_size;
|
||||
if (cont < frames)
|
||||
frames = cont;
|
||||
return frames;
|
||||
|
|
@ -70,13 +78,13 @@ size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames)
|
|||
size_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
|
||||
{
|
||||
assert(pcm);
|
||||
return *pcm->appl_ptr % pcm->setup.buffer_size;
|
||||
return *pcm->appl_ptr % pcm->buffer_size;
|
||||
}
|
||||
|
||||
size_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
|
||||
{
|
||||
assert(pcm);
|
||||
return *pcm->hw_ptr % pcm->setup.buffer_size;
|
||||
return *pcm->hw_ptr % pcm->buffer_size;
|
||||
}
|
||||
|
||||
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames)
|
||||
|
|
@ -84,7 +92,7 @@ void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames)
|
|||
ssize_t appl_ptr = *pcm->appl_ptr;
|
||||
appl_ptr -= frames;
|
||||
if (appl_ptr < 0)
|
||||
appl_ptr += pcm->setup.boundary;
|
||||
appl_ptr += pcm->boundary;
|
||||
*pcm->appl_ptr = appl_ptr;
|
||||
}
|
||||
|
||||
|
|
@ -92,8 +100,8 @@ void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, size_t frames)
|
|||
{
|
||||
size_t appl_ptr = *pcm->appl_ptr;
|
||||
appl_ptr += frames;
|
||||
if (appl_ptr >= pcm->setup.boundary)
|
||||
appl_ptr -= pcm->setup.boundary;
|
||||
if (appl_ptr >= pcm->boundary)
|
||||
appl_ptr -= pcm->boundary;
|
||||
*pcm->appl_ptr = appl_ptr;
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +110,7 @@ void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, size_t frames)
|
|||
ssize_t hw_ptr = *pcm->hw_ptr;
|
||||
hw_ptr -= frames;
|
||||
if (hw_ptr < 0)
|
||||
hw_ptr += pcm->setup.boundary;
|
||||
hw_ptr += pcm->boundary;
|
||||
*pcm->hw_ptr = hw_ptr;
|
||||
}
|
||||
|
||||
|
|
@ -110,8 +118,8 @@ void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, size_t frames)
|
|||
{
|
||||
size_t hw_ptr = *pcm->hw_ptr;
|
||||
hw_ptr += frames;
|
||||
if (hw_ptr >= pcm->setup.boundary)
|
||||
hw_ptr -= pcm->setup.boundary;
|
||||
if (hw_ptr >= pcm->boundary)
|
||||
hw_ptr -= pcm->boundary;
|
||||
*pcm->hw_ptr = hw_ptr;
|
||||
}
|
||||
|
||||
|
|
@ -127,11 +135,13 @@ ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
|
|||
xfer = 0;
|
||||
while (xfer < size) {
|
||||
size_t frames = snd_pcm_mmap_playback_xfer(pcm, size - xfer);
|
||||
ssize_t err;
|
||||
snd_pcm_areas_copy(areas, offset,
|
||||
snd_pcm_mmap_areas(pcm), snd_pcm_mmap_offset(pcm),
|
||||
pcm->setup.format.channels,
|
||||
frames, pcm->setup.format.sfmt);
|
||||
snd_pcm_mmap_forward(pcm, frames);
|
||||
pcm->channels,
|
||||
frames, pcm->format);
|
||||
err = snd_pcm_mmap_forward(pcm, frames);
|
||||
assert(err == (ssize_t)frames);
|
||||
offset += frames;
|
||||
xfer += frames;
|
||||
}
|
||||
|
|
@ -152,11 +162,13 @@ ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm,
|
|||
xfer = 0;
|
||||
while (xfer < size) {
|
||||
size_t frames = snd_pcm_mmap_capture_xfer(pcm, size - xfer);
|
||||
ssize_t err;
|
||||
snd_pcm_areas_copy(snd_pcm_mmap_areas(pcm), snd_pcm_mmap_offset(pcm),
|
||||
areas, offset,
|
||||
pcm->setup.format.channels,
|
||||
frames, pcm->setup.format.sfmt);
|
||||
snd_pcm_mmap_forward(pcm, frames);
|
||||
pcm->channels,
|
||||
frames, pcm->format);
|
||||
err = snd_pcm_mmap_forward(pcm, frames);
|
||||
assert(err == (ssize_t)frames);
|
||||
offset += frames;
|
||||
xfer += frames;
|
||||
}
|
||||
|
|
@ -167,7 +179,7 @@ ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm,
|
|||
|
||||
ssize_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
|
||||
{
|
||||
snd_pcm_channel_area_t areas[pcm->setup.format.channels];
|
||||
snd_pcm_channel_area_t areas[pcm->channels];
|
||||
snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
|
||||
return snd_pcm_write_areas(pcm, areas, 0, size,
|
||||
snd_pcm_mmap_write_areas);
|
||||
|
|
@ -175,7 +187,7 @@ ssize_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
|
|||
|
||||
ssize_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, size_t size)
|
||||
{
|
||||
snd_pcm_channel_area_t areas[pcm->setup.format.channels];
|
||||
snd_pcm_channel_area_t areas[pcm->channels];
|
||||
snd_pcm_areas_from_bufs(pcm, areas, bufs);
|
||||
return snd_pcm_write_areas(pcm, areas, 0, size,
|
||||
snd_pcm_mmap_write_areas);
|
||||
|
|
@ -183,7 +195,7 @@ ssize_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, size_t size)
|
|||
|
||||
ssize_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, size_t size)
|
||||
{
|
||||
snd_pcm_channel_area_t areas[pcm->setup.format.channels];
|
||||
snd_pcm_channel_area_t areas[pcm->channels];
|
||||
snd_pcm_areas_from_buf(pcm, areas, buffer);
|
||||
return snd_pcm_read_areas(pcm, areas, 0, size,
|
||||
snd_pcm_mmap_read_areas);
|
||||
|
|
@ -191,71 +203,204 @@ ssize_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, size_t size)
|
|||
|
||||
ssize_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, size_t size)
|
||||
{
|
||||
snd_pcm_channel_area_t areas[pcm->setup.format.channels];
|
||||
snd_pcm_channel_area_t areas[pcm->channels];
|
||||
snd_pcm_areas_from_bufs(pcm, areas, bufs);
|
||||
return snd_pcm_read_areas(pcm, areas, 0, size,
|
||||
snd_pcm_mmap_read_areas);
|
||||
}
|
||||
|
||||
int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas)
|
||||
int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
|
||||
{
|
||||
snd_pcm_channel_setup_t setup;
|
||||
snd_pcm_channel_area_t *r, *rp, *s, *sp;
|
||||
unsigned int channel;
|
||||
int err;
|
||||
assert(pcm);
|
||||
assert(pcm->mmap_info);
|
||||
if (!pcm->running_areas) {
|
||||
r = calloc(pcm->setup.format.channels, sizeof(*r));
|
||||
s = calloc(pcm->setup.format.channels, sizeof(*s));
|
||||
for (channel = 0, rp = r, sp = s; channel < pcm->setup.format.channels; ++channel, ++rp, ++sp) {
|
||||
setup.channel = channel;
|
||||
err = snd_pcm_channel_setup(pcm, &setup);
|
||||
if (err < 0) {
|
||||
free(r);
|
||||
free(s);
|
||||
return err;
|
||||
}
|
||||
*rp = setup.running_area;
|
||||
*sp = setup.stopped_area;
|
||||
}
|
||||
pcm->running_areas = r;
|
||||
pcm->stopped_areas = s;
|
||||
}
|
||||
if (running_areas)
|
||||
memcpy(running_areas, pcm->running_areas, pcm->setup.format.channels * sizeof(*running_areas));
|
||||
if (stopped_areas)
|
||||
memcpy(stopped_areas, pcm->stopped_areas, pcm->setup.format.channels * sizeof(*stopped_areas));
|
||||
return 0;
|
||||
return pcm->ops->channel_info(pcm, info);
|
||||
}
|
||||
|
||||
int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info,
|
||||
int shmid)
|
||||
{
|
||||
switch (pcm->access) {
|
||||
case SND_PCM_ACCESS_MMAP_INTERLEAVED:
|
||||
case SND_PCM_ACCESS_RW_INTERLEAVED:
|
||||
info->first = info->channel * pcm->bits_per_sample;
|
||||
info->step = pcm->bits_per_frame;
|
||||
break;
|
||||
case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
|
||||
case SND_PCM_ACCESS_RW_NONINTERLEAVED:
|
||||
info->first = 0;
|
||||
info->step = pcm->bits_per_sample;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
info->addr = 0;
|
||||
info->type = SND_PCM_AREA_SHM;
|
||||
info->u.shm.shmid = shmid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_pcm_mmap(snd_pcm_t *pcm)
|
||||
{
|
||||
int err;
|
||||
unsigned int c;
|
||||
assert(pcm);
|
||||
assert(pcm->valid_setup);
|
||||
if (pcm->mmap_info)
|
||||
return 0;
|
||||
|
||||
if ((err = pcm->ops->mmap(pcm->op_arg)) < 0)
|
||||
return err;
|
||||
err = snd_pcm_mmap_get_areas(pcm, NULL, NULL);
|
||||
assert(pcm->setup);
|
||||
assert(!pcm->mmap_channels);
|
||||
err = pcm->ops->mmap(pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
pcm->mmap_channels = calloc(pcm->channels, sizeof(pcm->mmap_channels[0]));
|
||||
if (!pcm->mmap_channels)
|
||||
return -ENOMEM;
|
||||
assert(!pcm->running_areas);
|
||||
pcm->running_areas = calloc(pcm->channels, sizeof(pcm->running_areas[0]));
|
||||
if (!pcm->running_areas) {
|
||||
free(pcm->mmap_channels);
|
||||
pcm->mmap_channels = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (c = 0; c < pcm->channels; ++c) {
|
||||
snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
|
||||
i->channel = c;
|
||||
err = snd_pcm_channel_info(pcm, i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
for (c = 0; c < pcm->channels; ++c) {
|
||||
snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
|
||||
snd_pcm_channel_area_t *a = &pcm->running_areas[c];
|
||||
unsigned int c1;
|
||||
if (!i->addr) {
|
||||
char *ptr;
|
||||
size_t size = i->first + i->step * pcm->buffer_size;
|
||||
for (c1 = c + 1; c1 < pcm->channels; ++c1) {
|
||||
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
|
||||
size_t s;
|
||||
if (i1->type != i->type)
|
||||
continue;
|
||||
switch (i1->type) {
|
||||
case SND_PCM_AREA_MMAP:
|
||||
if (i1->u.mmap.fd != i->u.mmap.fd ||
|
||||
i1->u.mmap.offset != i->u.mmap.offset)
|
||||
continue;
|
||||
break;
|
||||
case SND_PCM_AREA_SHM:
|
||||
if (i1->u.shm.shmid != i->u.shm.shmid)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
s = i1->first + i1->step * pcm->buffer_size;
|
||||
if (s > size)
|
||||
size = s;
|
||||
}
|
||||
size = (size + 7) / 8;
|
||||
size = PAGE_ALIGN(size);
|
||||
switch (i->type) {
|
||||
case SND_PCM_AREA_MMAP:
|
||||
ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset);
|
||||
if (ptr == MAP_FAILED) {
|
||||
SYSERR("mmap failed");
|
||||
return -errno;
|
||||
}
|
||||
i->addr = ptr;
|
||||
break;
|
||||
case SND_PCM_AREA_SHM:
|
||||
if (i->u.shm.shmid < 0) {
|
||||
int id;
|
||||
id = shmget(IPC_PRIVATE, size, 0666);
|
||||
if (id < 0) {
|
||||
SYSERR("shmget failed");
|
||||
return -errno;
|
||||
}
|
||||
i->u.shm.shmid = id;
|
||||
}
|
||||
ptr = shmat(i->u.shm.shmid, 0, 0);
|
||||
if (ptr == (void*) -1) {
|
||||
SYSERR("shmat failed");
|
||||
return -errno;
|
||||
}
|
||||
i->addr = ptr;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
for (c1 = c + 1; c1 < pcm->channels; ++c1) {
|
||||
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
|
||||
if (i1->type != i->type)
|
||||
continue;
|
||||
switch (i1->type) {
|
||||
case SND_PCM_AREA_MMAP:
|
||||
if (i1->u.mmap.fd != i->u.mmap.fd ||
|
||||
i1->u.mmap.offset != i->u.mmap.offset)
|
||||
continue;
|
||||
break;
|
||||
case SND_PCM_AREA_SHM:
|
||||
if (i1->u.shm.shmid != i->u.shm.shmid)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
i1->addr = i->addr;
|
||||
}
|
||||
a->addr = i->addr;
|
||||
a->first = i->first;
|
||||
a->step = i->step;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_pcm_munmap(snd_pcm_t *pcm)
|
||||
{
|
||||
int err;
|
||||
unsigned int c;
|
||||
assert(pcm);
|
||||
assert(pcm->mmap_info);
|
||||
if ((err = pcm->ops->munmap(pcm->op_arg)) < 0)
|
||||
assert(pcm->mmap_channels);
|
||||
for (c = 0; c < pcm->channels; ++c) {
|
||||
snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
|
||||
unsigned int c1;
|
||||
size_t size = i->first + i->step * pcm->buffer_size;
|
||||
if (!i->addr)
|
||||
continue;
|
||||
for (c1 = c + 1; c1 < pcm->channels; ++c1) {
|
||||
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
|
||||
size_t s;
|
||||
if (i1->addr != i->addr)
|
||||
continue;
|
||||
i1->addr = NULL;
|
||||
s = i1->first + i1->step * pcm->buffer_size;
|
||||
if (s > size)
|
||||
size = s;
|
||||
}
|
||||
size = (size + 7) / 8;
|
||||
size = PAGE_ALIGN(size);
|
||||
switch (i->type) {
|
||||
case SND_PCM_AREA_MMAP:
|
||||
err = munmap(i->addr, size);
|
||||
if (err < 0) {
|
||||
SYSERR("mmap failed");
|
||||
return -errno;
|
||||
}
|
||||
break;
|
||||
case SND_PCM_AREA_SHM:
|
||||
err = shmdt(i->addr);
|
||||
if (err < 0) {
|
||||
SYSERR("shmdt failed");
|
||||
return -errno;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
i->addr = NULL;
|
||||
}
|
||||
err = pcm->ops->munmap(pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
free(pcm->stopped_areas);
|
||||
free(pcm->running_areas);
|
||||
pcm->stopped_areas = 0;
|
||||
pcm->running_areas = 0;
|
||||
free(pcm->mmap_channels);
|
||||
pcm->mmap_channels = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -267,25 +412,34 @@ ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size)
|
|||
while (xfer < size) {
|
||||
size_t frames = size - xfer;
|
||||
size_t offset = snd_pcm_mmap_hw_offset(pcm);
|
||||
size_t cont = pcm->setup.buffer_size - offset;
|
||||
size_t cont = pcm->buffer_size - offset;
|
||||
if (cont < frames)
|
||||
frames = cont;
|
||||
if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
|
||||
switch (pcm->access) {
|
||||
case SND_PCM_ACCESS_MMAP_INTERLEAVED:
|
||||
{
|
||||
snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm);
|
||||
char *buf = snd_pcm_channel_area_addr(a, offset);
|
||||
assert(pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED);
|
||||
err = _snd_pcm_writei(pcm, buf, size);
|
||||
} else {
|
||||
size_t channels = pcm->setup.format.channels;
|
||||
break;
|
||||
}
|
||||
case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
|
||||
{
|
||||
size_t channels = pcm->channels;
|
||||
unsigned int c;
|
||||
void *bufs[channels];
|
||||
snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm);
|
||||
assert(pcm->setup.mmap_shape == SND_PCM_MMAP_NONINTERLEAVED);
|
||||
for (c = 0; c < channels; ++c) {
|
||||
snd_pcm_channel_area_t *a = &areas[c];
|
||||
bufs[c] = snd_pcm_channel_area_addr(a, offset);
|
||||
}
|
||||
err = _snd_pcm_writen(pcm, bufs, size);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (err < 0)
|
||||
break;
|
||||
|
|
@ -304,26 +458,34 @@ ssize_t snd_pcm_read_mmap(snd_pcm_t *pcm, size_t size)
|
|||
while (xfer < size) {
|
||||
size_t frames = size - xfer;
|
||||
size_t offset = snd_pcm_mmap_hw_offset(pcm);
|
||||
size_t cont = pcm->setup.buffer_size - offset;
|
||||
size_t cont = pcm->buffer_size - offset;
|
||||
if (cont < frames)
|
||||
frames = cont;
|
||||
if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
|
||||
switch (pcm->access) {
|
||||
case SND_PCM_ACCESS_MMAP_INTERLEAVED:
|
||||
{
|
||||
snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm);
|
||||
char *buf = snd_pcm_channel_area_addr(a, offset);
|
||||
assert(pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED);
|
||||
err = _snd_pcm_readi(pcm, buf, size);
|
||||
} else {
|
||||
size_t channels = pcm->setup.format.channels;
|
||||
break;
|
||||
}
|
||||
case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
|
||||
{
|
||||
size_t channels = pcm->channels;
|
||||
unsigned int c;
|
||||
void *bufs[channels];
|
||||
snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm);
|
||||
assert(pcm->setup.mmap_shape == SND_PCM_MMAP_NONINTERLEAVED);
|
||||
for (c = 0; c < channels; ++c) {
|
||||
snd_pcm_channel_area_t *a = &areas[c];
|
||||
bufs[c] = snd_pcm_channel_area_addr(a, offset);
|
||||
}
|
||||
err = _snd_pcm_readn(pcm->fast_op_arg, bufs, size);
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (err < 0)
|
||||
break;
|
||||
xfer += frames;
|
||||
|
|
|
|||
|
|
@ -35,8 +35,6 @@ typedef struct {
|
|||
int getput_idx;
|
||||
mulaw_f func;
|
||||
int sformat;
|
||||
int cformat;
|
||||
int cxfer_mode, cmmap_shape;
|
||||
} snd_pcm_mulaw_t;
|
||||
|
||||
static inline int val_seg(int val)
|
||||
|
|
@ -230,96 +228,76 @@ static void mulaw_encode(snd_pcm_channel_area_t *src_areas,
|
|||
}
|
||||
}
|
||||
|
||||
static int snd_pcm_mulaw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
|
||||
static int snd_pcm_mulaw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
|
||||
{
|
||||
snd_pcm_mulaw_t *mulaw = pcm->private;
|
||||
unsigned int req_mask = info->req_mask;
|
||||
unsigned int sfmt = info->req.format.sfmt;
|
||||
unsigned int format_mask, access_mask;
|
||||
int err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT) {
|
||||
if (mulaw->sformat == SND_PCM_SFMT_MU_LAW ?
|
||||
!snd_pcm_format_linear(sfmt) :
|
||||
sfmt != SND_PCM_SFMT_MU_LAW) {
|
||||
info->req.fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
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);
|
||||
if (info->format_mask)
|
||||
info->format_mask = format_mask;
|
||||
if (info->access_mask) {
|
||||
mulaw->plug.saccess_mask = info->access_mask;
|
||||
info->access_mask = access_mask;
|
||||
}
|
||||
info->req_mask |= SND_PCM_PARAMS_SFMT;
|
||||
info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
|
||||
SND_PCM_PARAMS_XFER_MODE);
|
||||
info->req.format.sfmt = mulaw->sformat;
|
||||
err = snd_pcm_params_info(mulaw->plug.slave, info);
|
||||
info->req_mask = req_mask;
|
||||
info->req.format.sfmt = sfmt;
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT)
|
||||
info->formats = 1 << sfmt;
|
||||
else
|
||||
info->formats = mulaw->sformat == SND_PCM_SFMT_MU_LAW ?
|
||||
SND_PCM_LINEAR_FORMATS : 1 << SND_PCM_SFMT_MU_LAW;
|
||||
info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
|
||||
return err;
|
||||
info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
snd_pcm_hw_info_complete(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||
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;
|
||||
unsigned int format, access;
|
||||
int err;
|
||||
if (mulaw->sformat == SND_PCM_SFMT_MU_LAW ?
|
||||
!snd_pcm_format_linear(params->format.sfmt) :
|
||||
params->format.sfmt != SND_PCM_SFMT_MU_LAW) {
|
||||
params->fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
mulaw->cformat = params->format.sfmt;
|
||||
mulaw->cxfer_mode = params->xfer_mode;
|
||||
mulaw->cmmap_shape = params->mmap_shape;
|
||||
params->format.sfmt = mulaw->sformat;
|
||||
params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
|
||||
err = snd_pcm_params_mmap(slave, params);
|
||||
params->format.sfmt = mulaw->cformat;
|
||||
params->xfer_mode = mulaw->cxfer_mode;
|
||||
params->mmap_shape = mulaw->cmmap_shape;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_mulaw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
||||
{
|
||||
snd_pcm_mulaw_t *mulaw = pcm->private;
|
||||
int err = snd_pcm_setup(mulaw->plug.slave, setup);
|
||||
format = params->format;
|
||||
access = params->access;
|
||||
params->format = mulaw->sformat;
|
||||
if (mulaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
|
||||
else if (mulaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
assert(0);
|
||||
err = snd_pcm_hw_params(slave, params);
|
||||
params->format = format;
|
||||
params->access = access;
|
||||
if (err < 0)
|
||||
return err;
|
||||
assert(mulaw->sformat == setup->format.sfmt);
|
||||
if (mulaw->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
|
||||
setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
|
||||
else
|
||||
setup->xfer_mode = mulaw->cxfer_mode;
|
||||
if (mulaw->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
|
||||
setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
setup->mmap_shape = mulaw->cmmap_shape;
|
||||
setup->format.sfmt = mulaw->cformat;
|
||||
setup->mmap_bytes = 0;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
if (mulaw->sformat == SND_PCM_SFMT_MU_LAW) {
|
||||
mulaw->getput_idx = get_index(mulaw->cformat, SND_PCM_SFMT_S16);
|
||||
if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
|
||||
mulaw->getput_idx = get_index(format, SND_PCM_FORMAT_S16);
|
||||
mulaw->func = mulaw_encode;
|
||||
} else {
|
||||
mulaw->getput_idx = put_index(SND_PCM_SFMT_S16, mulaw->sformat);
|
||||
mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, mulaw->sformat);
|
||||
mulaw->func = mulaw_decode;
|
||||
}
|
||||
} else {
|
||||
if (mulaw->sformat == SND_PCM_SFMT_MU_LAW) {
|
||||
mulaw->getput_idx = put_index(SND_PCM_SFMT_S16, mulaw->cformat);
|
||||
if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
|
||||
mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, format);
|
||||
mulaw->func = mulaw_decode;
|
||||
} else {
|
||||
mulaw->getput_idx = get_index(mulaw->sformat, SND_PCM_SFMT_S16);
|
||||
mulaw->getput_idx = get_index(mulaw->sformat, SND_PCM_FORMAT_S16);
|
||||
mulaw->func = mulaw_encode;
|
||||
}
|
||||
}
|
||||
|
|
@ -343,7 +321,7 @@ static ssize_t snd_pcm_mulaw_write_areas(snd_pcm_t *pcm,
|
|||
size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
|
||||
mulaw->func(areas, offset,
|
||||
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
frames, pcm->setup.format.channels,
|
||||
frames, pcm->channels,
|
||||
mulaw->getput_idx);
|
||||
err = snd_pcm_mmap_forward(slave, frames);
|
||||
if (err < 0)
|
||||
|
|
@ -378,7 +356,7 @@ static ssize_t snd_pcm_mulaw_read_areas(snd_pcm_t *pcm,
|
|||
size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
|
||||
mulaw->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
areas, offset,
|
||||
frames, pcm->setup.format.channels,
|
||||
frames, pcm->channels,
|
||||
mulaw->getput_idx);
|
||||
err = snd_pcm_mmap_forward(slave, frames);
|
||||
if (err < 0)
|
||||
|
|
@ -401,7 +379,7 @@ static void snd_pcm_mulaw_dump(snd_pcm_t *pcm, FILE *fp)
|
|||
snd_pcm_mulaw_t *mulaw = pcm->private;
|
||||
fprintf(fp, "Mu-Law conversion PCM (%s)\n",
|
||||
snd_pcm_format_name(mulaw->sformat));
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "Its setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -412,12 +390,12 @@ 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,
|
||||
params_info: snd_pcm_mulaw_params_info,
|
||||
params: snd_pcm_mulaw_params,
|
||||
setup: snd_pcm_mulaw_setup,
|
||||
hw_info: snd_pcm_mulaw_hw_info,
|
||||
hw_params: snd_pcm_mulaw_hw_params,
|
||||
sw_params: snd_pcm_plugin_sw_params,
|
||||
dig_info: snd_pcm_plugin_dig_info,
|
||||
dig_params: snd_pcm_plugin_dig_params,
|
||||
channel_info: snd_pcm_plugin_channel_info,
|
||||
channel_params: snd_pcm_plugin_channel_params,
|
||||
channel_setup: snd_pcm_plugin_channel_setup,
|
||||
dump: snd_pcm_mulaw_dump,
|
||||
nonblock: snd_pcm_plugin_nonblock,
|
||||
async: snd_pcm_plugin_async,
|
||||
|
|
@ -431,7 +409,7 @@ int snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *sla
|
|||
snd_pcm_mulaw_t *mulaw;
|
||||
assert(pcmp && slave);
|
||||
if (snd_pcm_format_linear(sformat) != 1 &&
|
||||
sformat != SND_PCM_SFMT_MU_LAW)
|
||||
sformat != SND_PCM_FORMAT_MU_LAW)
|
||||
return -EINVAL;
|
||||
mulaw = calloc(1, sizeof(snd_pcm_mulaw_t));
|
||||
if (!mulaw) {
|
||||
|
|
@ -498,7 +476,7 @@ int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name,
|
|||
if (sformat < 0)
|
||||
return -EINVAL;
|
||||
if (snd_pcm_format_linear(sformat) != 1 &&
|
||||
sformat != SND_PCM_SFMT_MU_LAW)
|
||||
sformat != SND_PCM_FORMAT_MU_LAW)
|
||||
return -EINVAL;
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ typedef struct {
|
|||
snd_pcm_t *pcm;
|
||||
unsigned int channels_count;
|
||||
int close_slave;
|
||||
unsigned int access_mask;
|
||||
} snd_pcm_multi_slave_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -43,7 +44,6 @@ typedef struct {
|
|||
snd_pcm_multi_slave_t *slaves;
|
||||
size_t channels_count;
|
||||
snd_pcm_multi_channel_t *channels;
|
||||
int xfer_mode;
|
||||
} snd_pcm_multi_t;
|
||||
|
||||
static int snd_pcm_multi_close(snd_pcm_t *pcm)
|
||||
|
|
@ -91,178 +91,106 @@ static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
|
||||
static int snd_pcm_multi_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
|
||||
{
|
||||
snd_pcm_multi_t *multi = pcm->private;
|
||||
unsigned int i;
|
||||
int err;
|
||||
snd_pcm_t *slave_0 = multi->slaves[0].pcm;
|
||||
unsigned int req_mask = info->req_mask;
|
||||
unsigned int channels = info->req.format.channels;
|
||||
if ((req_mask & SND_PCM_PARAMS_CHANNELS) &&
|
||||
channels != multi->channels_count) {
|
||||
info->req.fail_mask |= SND_PCM_PARAMS_CHANNELS;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
info->req_mask |= SND_PCM_PARAMS_CHANNELS;
|
||||
info->req.format.channels = multi->slaves[0].channels_count;
|
||||
err = snd_pcm_params_info(slave_0, info);
|
||||
info->req_mask = req_mask;
|
||||
info->req.format.channels = channels;
|
||||
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 *slave_i = multi->slaves[i].pcm;
|
||||
snd_pcm_params_info_t info_i;
|
||||
info_i = *info;
|
||||
info_i.req_mask |= SND_PCM_PARAMS_CHANNELS;
|
||||
info_i.req.format.channels = multi->slaves[i].channels_count;
|
||||
err = snd_pcm_params_info(slave_i, &info_i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
info->formats &= info_i.formats;
|
||||
info->rates &= info_i.rates;
|
||||
if (info_i.min_rate > info->min_rate)
|
||||
info->min_rate = info_i.min_rate;
|
||||
if (info_i.max_rate < info->max_rate)
|
||||
info->max_rate = info_i.max_rate;
|
||||
if (info_i.buffer_size < info->buffer_size)
|
||||
info->buffer_size = info_i.buffer_size;
|
||||
if (info_i.min_fragment_size > info->min_fragment_size)
|
||||
info->min_fragment_size = info_i.min_fragment_size;
|
||||
if (info_i.max_fragment_size < info->max_fragment_size)
|
||||
info->max_fragment_size = info_i.max_fragment_size;
|
||||
if (info_i.min_fragments > info->min_fragments)
|
||||
info->min_fragments = info_i.min_fragments;
|
||||
if (info_i.max_fragments < info->max_fragments)
|
||||
info->max_fragments = info_i.max_fragments;
|
||||
info->flags &= info_i.flags;
|
||||
}
|
||||
if (info->flags & SND_PCM_INFO_INTERLEAVED) {
|
||||
if (multi->slaves_count > 0) {
|
||||
info->flags &= ~SND_PCM_INFO_INTERLEAVED;
|
||||
info->flags |= SND_PCM_INFO_COMPLEX;
|
||||
}
|
||||
} else if (!(info->flags & SND_PCM_INFO_NONINTERLEAVED))
|
||||
info->flags |= SND_PCM_INFO_COMPLEX;
|
||||
info->req_mask = req_mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_multi_t *multi = pcm->private;
|
||||
unsigned int i;
|
||||
size_t count = 0;
|
||||
for (i = 0; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_t *slave = multi->slaves[i].pcm;
|
||||
snd_pcm_setup_t *setup;
|
||||
int err = snd_pcm_mmap(slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
count += slave->mmap_info_count;
|
||||
setup = &slave->setup;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
snd_pcm_channel_area_t r[setup->format.channels];
|
||||
snd_pcm_channel_area_t s[setup->format.channels];
|
||||
err = snd_pcm_mmap_get_areas(slave, s, r);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
pcm->mmap_info_count = count;
|
||||
pcm->mmap_info = malloc(count * sizeof(*pcm->mmap_info));
|
||||
count = 0;
|
||||
for (i = 0; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_t *slave = multi->slaves[i].pcm;
|
||||
memcpy(&pcm->mmap_info[count], slave->mmap_info, slave->mmap_info_count * sizeof(*pcm->mmap_info));
|
||||
count += slave->mmap_info_count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_munmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_multi_t *multi = pcm->private;
|
||||
unsigned int i;
|
||||
for (i = 0; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_t *slave = multi->slaves[i].pcm;
|
||||
int err = snd_pcm_munmap(slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
pcm->mmap_info_count = 0;
|
||||
free(pcm->mmap_info);
|
||||
pcm->mmap_info = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
||||
{
|
||||
snd_pcm_multi_t *multi = pcm->private;
|
||||
unsigned int i;
|
||||
snd_pcm_params_t p;
|
||||
unsigned int k;
|
||||
snd_pcm_hw_info_t i;
|
||||
unsigned int access_mask = ~0;
|
||||
int err = 0;
|
||||
if (params->format.channels != multi->channels_count) {
|
||||
params->fail_mask = SND_PCM_PARAMS_CHANNELS;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
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_max > info->channels_max)
|
||||
return -EINVAL;
|
||||
i = *info;
|
||||
for (k = 0; k < multi->slaves_count; ++k) {
|
||||
snd_pcm_t *slave = multi->slaves[k].pcm;
|
||||
i.access_mask = SND_PCM_ACCBIT_MMAP;
|
||||
i.channels_min = i.channels_max = multi->slaves[k].channels_count;
|
||||
err = snd_pcm_hw_info(slave, &i);
|
||||
access_mask &= i.access_mask;
|
||||
if (err < 0)
|
||||
break;
|
||||
multi->slaves[k].access_mask = i.access_mask;
|
||||
}
|
||||
*info = i;
|
||||
if (i.channels_min <= i.channels_max)
|
||||
info->channels_min = info->channels_max = multi->channels_count;
|
||||
if (i.access_mask) {
|
||||
if (!(access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED) ||
|
||||
multi->slaves_count > 1)
|
||||
info->access_mask &= ~SND_PCM_ACCBIT_MMAP_INTERLEAVED;
|
||||
if (!(access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED))
|
||||
info->access_mask &= ~SND_PCM_ACCBIT_MMAP_NONINTERLEAVED;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
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;
|
||||
snd_pcm_hw_params_t p;
|
||||
int err;
|
||||
if (params->channels != multi->channels_count) {
|
||||
params->fail_mask = SND_PCM_HW_PARBIT_CHANNELS;
|
||||
return -EINVAL;
|
||||
}
|
||||
p = *params;
|
||||
for (i = 0; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_t *slave = multi->slaves[i].pcm;
|
||||
p.format.channels = multi->slaves[i].channels_count;
|
||||
err = snd_pcm_params_mmap(slave, &p);
|
||||
if (multi->slaves[i].access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
|
||||
p.access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
|
||||
else if (multi->slaves[i].access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
|
||||
p.access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
assert(0);
|
||||
p.channels = multi->slaves[i].channels_count;
|
||||
err = snd_pcm_hw_params(slave, &p);
|
||||
if (err < 0) {
|
||||
params->fail_mask = p.fail_mask;
|
||||
params->fail_reason = p.fail_reason;
|
||||
break;
|
||||
return err;
|
||||
}
|
||||
err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (slave->stopped_areas) {
|
||||
err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (err == 0)
|
||||
multi->xfer_mode = params->xfer_mode;
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
|
||||
static int snd_pcm_multi_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
|
||||
{
|
||||
snd_pcm_multi_t *multi = pcm->private;
|
||||
unsigned int i;
|
||||
int err;
|
||||
err = snd_pcm_setup(multi->slaves[0].pcm, setup);
|
||||
if (err < 0)
|
||||
return err;
|
||||
for (i = 1; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_setup_t s;
|
||||
snd_pcm_t *sh = multi->slaves[i].pcm;
|
||||
err = snd_pcm_setup(sh, &s);
|
||||
for (i = 0; i < multi->slaves_count; ++i) {
|
||||
snd_pcm_t *slave = multi->slaves[i].pcm;
|
||||
err = snd_pcm_sw_params(slave, params);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (setup->format.rate != s.format.rate)
|
||||
return -EINVAL;
|
||||
if (setup->buffer_size != s.buffer_size)
|
||||
return -EINVAL;
|
||||
if (setup->mmap_shape != SND_PCM_MMAP_NONINTERLEAVED ||
|
||||
s.mmap_shape != SND_PCM_MMAP_NONINTERLEAVED)
|
||||
setup->mmap_shape = SND_PCM_MMAP_COMPLEX;
|
||||
}
|
||||
setup->format.channels = multi->channels_count;
|
||||
if (multi->xfer_mode == SND_PCM_XFER_UNSPECIFIED)
|
||||
setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
|
||||
else
|
||||
setup->xfer_mode = multi->xfer_mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_dig_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_info_t *info ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* FIXME */
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_dig_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_params_t *params ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* FIXME */
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
|
||||
{
|
||||
snd_pcm_multi_t *multi = pcm->private;
|
||||
|
|
@ -335,34 +263,6 @@ static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *in
|
|||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
|
||||
{
|
||||
snd_pcm_multi_t *multi = pcm->private;
|
||||
unsigned int channel = params->channel;
|
||||
snd_pcm_multi_channel_t *c = &multi->channels[channel];
|
||||
int err;
|
||||
if (c->slave_idx < 0)
|
||||
return -ENXIO;
|
||||
params->channel = c->slave_channel;
|
||||
err = snd_pcm_channel_params(multi->slaves[c->slave_idx].pcm, params);
|
||||
params->channel = channel;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
|
||||
{
|
||||
snd_pcm_multi_t *multi = pcm->private;
|
||||
unsigned int channel = setup->channel;
|
||||
snd_pcm_multi_channel_t *c = &multi->channels[channel];
|
||||
int err;
|
||||
if (c->slave_idx < 0)
|
||||
return -ENXIO;
|
||||
setup->channel = c->slave_channel;
|
||||
err = snd_pcm_channel_setup(multi->slaves[c->slave_idx].pcm, setup);
|
||||
setup->channel = channel;
|
||||
return err;
|
||||
}
|
||||
|
||||
static ssize_t snd_pcm_multi_rewind(snd_pcm_t *pcm, size_t frames)
|
||||
{
|
||||
snd_pcm_multi_t *multi = pcm->private;
|
||||
|
|
@ -413,6 +313,16 @@ static int snd_pcm_multi_set_avail_min(snd_pcm_t *pcm, size_t frames)
|
|||
return snd_pcm_set_avail_min(multi->slaves[0].pcm, frames);
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_multi_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_pcm_multi_poll_descriptor(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_multi_t *multi = pcm->private;
|
||||
|
|
@ -433,7 +343,7 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp)
|
|||
fprintf(fp, "%d: slave %d, channel %d\n",
|
||||
k, c->slave_idx, c->slave_channel);
|
||||
}
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "\nIts setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -446,12 +356,12 @@ 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,
|
||||
params_info: snd_pcm_multi_params_info,
|
||||
params: snd_pcm_multi_params,
|
||||
setup: snd_pcm_multi_setup,
|
||||
hw_info: snd_pcm_multi_hw_info,
|
||||
hw_params: snd_pcm_multi_hw_params,
|
||||
sw_params: snd_pcm_multi_sw_params,
|
||||
dig_info: snd_pcm_multi_dig_info,
|
||||
dig_params: snd_pcm_multi_dig_params,
|
||||
channel_info: snd_pcm_multi_channel_info,
|
||||
channel_params: snd_pcm_multi_channel_params,
|
||||
channel_setup: snd_pcm_multi_channel_setup,
|
||||
dump: snd_pcm_multi_dump,
|
||||
nonblock: snd_pcm_multi_nonblock,
|
||||
async: snd_pcm_multi_async,
|
||||
|
|
@ -538,7 +448,7 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, char *name,
|
|||
pcm->type = SND_PCM_TYPE_MULTI;
|
||||
pcm->stream = stream;
|
||||
pcm->mode = multi->slaves[0].pcm->mode;
|
||||
pcm->mmap_auto = 1;
|
||||
pcm->mmap_rw = 1;
|
||||
pcm->ops = &snd_pcm_multi_ops;
|
||||
pcm->op_arg = pcm;
|
||||
pcm->fast_ops = &snd_pcm_multi_fast_ops;
|
||||
|
|
|
|||
|
|
@ -21,13 +21,14 @@
|
|||
|
||||
#include <byteswap.h>
|
||||
#include <limits.h>
|
||||
#include <sys/shm.h>
|
||||
#include "pcm_local.h"
|
||||
#include "pcm_plugin.h"
|
||||
|
||||
typedef struct {
|
||||
snd_pcm_setup_t setup;
|
||||
snd_timestamp_t trigger_time;
|
||||
int state;
|
||||
int shmid;
|
||||
size_t appl_ptr;
|
||||
size_t hw_ptr;
|
||||
int poll_fd;
|
||||
|
|
@ -58,25 +59,10 @@ static int snd_pcm_null_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_info_t * i
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_channel_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_info_t * info)
|
||||
static int snd_pcm_null_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
|
||||
{
|
||||
int channel = info->channel;
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->channel = channel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_channel_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_params_t * params ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_channel_setup(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_setup_t * setup)
|
||||
{
|
||||
int channel = setup->channel;
|
||||
memset(setup, 0, sizeof(*setup));
|
||||
setup->channel = channel;
|
||||
return 0;
|
||||
snd_pcm_null_t *null = pcm->private;
|
||||
return snd_pcm_channel_info_shm(pcm, info, null->shmid);
|
||||
}
|
||||
|
||||
static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
|
||||
|
|
@ -86,7 +72,7 @@ static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
|
|||
status->state = null->state;
|
||||
status->trigger_time = null->trigger_time;
|
||||
gettimeofday(&status->tstamp, 0);
|
||||
status->avail = pcm->setup.buffer_size;
|
||||
status->avail = pcm->buffer_size;
|
||||
status->avail_max = status->avail;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -118,7 +104,7 @@ static int snd_pcm_null_start(snd_pcm_t *pcm)
|
|||
assert(null->state == SND_PCM_STATE_PREPARED);
|
||||
null->state = SND_PCM_STATE_RUNNING;
|
||||
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
|
||||
snd_pcm_mmap_appl_forward(pcm, pcm->setup.buffer_size);
|
||||
snd_pcm_mmap_appl_forward(pcm, pcm->buffer_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -182,7 +168,7 @@ static ssize_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_
|
|||
{
|
||||
snd_pcm_null_t *null = pcm->private;
|
||||
if (null->state == SND_PCM_STATE_PREPARED &&
|
||||
pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
|
||||
pcm->start_mode != SND_PCM_START_EXPLICIT) {
|
||||
null->state = SND_PCM_STATE_RUNNING;
|
||||
}
|
||||
return snd_pcm_null_fwd(pcm, size);
|
||||
|
|
@ -192,7 +178,7 @@ static ssize_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED,
|
|||
{
|
||||
snd_pcm_null_t *null = pcm->private;
|
||||
if (null->state == SND_PCM_STATE_PREPARED &&
|
||||
pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
|
||||
pcm->start_mode != SND_PCM_START_EXPLICIT) {
|
||||
null->state = SND_PCM_STATE_RUNNING;
|
||||
}
|
||||
return snd_pcm_null_fwd(pcm, size);
|
||||
|
|
@ -202,9 +188,9 @@ static ssize_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED,
|
|||
{
|
||||
snd_pcm_null_t *null = pcm->private;
|
||||
if (null->state == SND_PCM_STATE_PREPARED &&
|
||||
pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
|
||||
pcm->start_mode != SND_PCM_START_EXPLICIT) {
|
||||
null->state = SND_PCM_STATE_RUNNING;
|
||||
snd_pcm_mmap_hw_forward(pcm, pcm->setup.buffer_size);
|
||||
snd_pcm_mmap_hw_forward(pcm, pcm->buffer_size);
|
||||
}
|
||||
return snd_pcm_null_fwd(pcm, size);
|
||||
}
|
||||
|
|
@ -213,9 +199,9 @@ static ssize_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED,
|
|||
{
|
||||
snd_pcm_null_t *null = pcm->private;
|
||||
if (null->state == SND_PCM_STATE_PREPARED &&
|
||||
pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
|
||||
pcm->start_mode != SND_PCM_START_EXPLICIT) {
|
||||
null->state = SND_PCM_STATE_RUNNING;
|
||||
snd_pcm_mmap_hw_forward(pcm, pcm->setup.buffer_size);
|
||||
snd_pcm_mmap_hw_forward(pcm, pcm->buffer_size);
|
||||
}
|
||||
return snd_pcm_null_fwd(pcm, size);
|
||||
}
|
||||
|
|
@ -227,111 +213,83 @@ static ssize_t snd_pcm_null_mmap_forward(snd_pcm_t *pcm, size_t size)
|
|||
|
||||
static ssize_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
|
||||
{
|
||||
return pcm->setup.buffer_size;
|
||||
return pcm->buffer_size;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_set_avail_min(snd_pcm_t *pcm, size_t frames)
|
||||
{
|
||||
pcm->setup.buffer_size = frames;
|
||||
pcm->avail_min = frames;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_hw_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_info_t * info)
|
||||
{
|
||||
snd_pcm_hw_info_complete(info);
|
||||
info->fifo_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params)
|
||||
{
|
||||
if (params->start_mode > SND_PCM_START_LAST) {
|
||||
params->fail_mask = SND_PCM_SW_PARBIT_START_MODE;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (params->ready_mode > SND_PCM_READY_LAST) {
|
||||
params->fail_mask = SND_PCM_SW_PARBIT_READY_MODE;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (params->xrun_mode > SND_PCM_XRUN_LAST) {
|
||||
params->fail_mask = SND_PCM_SW_PARBIT_XRUN_MODE;
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_dig_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_params_t *params ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_dig_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_info_t *info ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_mmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_mmap_info_t *i;
|
||||
int err;
|
||||
i = calloc(1, sizeof(*i));
|
||||
if (!i)
|
||||
return -ENOMEM;
|
||||
err = snd_pcm_alloc_user_mmap(pcm, i);
|
||||
if (err < 0) {
|
||||
free(i);
|
||||
return err;
|
||||
snd_pcm_null_t *null = pcm->private;
|
||||
if (!(pcm->info & SND_PCM_INFO_MMAP)) {
|
||||
size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
|
||||
int id = shmget(IPC_PRIVATE, size, 0666);
|
||||
if (id < 0) {
|
||||
SYSERR("shmget failed");
|
||||
return -errno;
|
||||
}
|
||||
null->shmid = id;
|
||||
}
|
||||
pcm->mmap_info = i;
|
||||
pcm->mmap_info_count = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_munmap(snd_pcm_t *pcm)
|
||||
{
|
||||
int err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
|
||||
if (err < 0)
|
||||
return err;
|
||||
free(pcm->mmap_info);
|
||||
pcm->mmap_info_count = 0;
|
||||
pcm->mmap_info = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_params_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_params_info_t * info)
|
||||
{
|
||||
int sizes = ((info->req_mask & SND_PCM_PARAMS_SFMT) &&
|
||||
(info->req_mask & SND_PCM_PARAMS_CHANNELS));
|
||||
info->flags = SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID |
|
||||
SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED |
|
||||
SND_PCM_INFO_PAUSE;
|
||||
info->formats = ~0;
|
||||
info->rates = SND_PCM_RATE_CONTINUOUS | SND_PCM_RATE_8000_192000;
|
||||
info->min_rate = 4000;
|
||||
info->max_rate = 192000;
|
||||
info->min_channels = 1;
|
||||
info->max_channels = 32;
|
||||
info->min_fragments = 1;
|
||||
info->max_fragments = 1024 * 1024;
|
||||
if (sizes) {
|
||||
info->buffer_size = 1024 * 1024;
|
||||
info->min_fragment_size = 1;
|
||||
info->max_fragment_size = 1024 * 1024;
|
||||
info->fragment_align = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||
{
|
||||
snd_pcm_null_t *null = pcm->private;
|
||||
snd_pcm_setup_t *s = &null->setup;
|
||||
int w = snd_pcm_format_width(s->format.sfmt);
|
||||
if (w < 0) {
|
||||
params->fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
return -EINVAL;
|
||||
if (shmctl(null->shmid, IPC_RMID, 0) < 0) {
|
||||
SYSERR("shmctl IPC_RMID failed");
|
||||
return -errno;
|
||||
}
|
||||
s->msbits = w;
|
||||
s->format = params->format;
|
||||
s->start_mode = params->start_mode;
|
||||
s->ready_mode = params->ready_mode;
|
||||
s->avail_min = params->avail_min;
|
||||
s->xfer_mode = params->xfer_mode;
|
||||
s->xfer_min = params->xfer_min;
|
||||
s->xfer_align = params->xfer_align;
|
||||
s->xrun_mode = params->xrun_mode;
|
||||
s->mmap_shape = params->mmap_shape;
|
||||
s->frag_size = params->frag_size;
|
||||
s->frags = s->buffer_size / s->frag_size;
|
||||
if (s->frags < 1)
|
||||
s->frags = 1;
|
||||
s->buffer_size = s->frag_size * s->frags;
|
||||
s->boundary = LONG_MAX - LONG_MAX % s->buffer_size;
|
||||
s->time = params->time;
|
||||
s->rate_master = s->format.rate;
|
||||
s->rate_divisor = 1;
|
||||
s->mmap_bytes = 0;
|
||||
s->fifo_size = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_null_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
||||
{
|
||||
snd_pcm_null_t *null = pcm->private;
|
||||
*setup = null->setup;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void snd_pcm_null_dump(snd_pcm_t *pcm, FILE *fp)
|
||||
{
|
||||
fprintf(fp, "Null PCM\n");
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "Its setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -340,12 +298,12 @@ 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,
|
||||
params_info: snd_pcm_null_params_info,
|
||||
params: snd_pcm_null_params,
|
||||
setup: snd_pcm_null_setup,
|
||||
hw_info: snd_pcm_null_hw_info,
|
||||
hw_params: snd_pcm_null_hw_params,
|
||||
sw_params: snd_pcm_null_sw_params,
|
||||
dig_params: snd_pcm_null_dig_params,
|
||||
dig_info: snd_pcm_null_dig_info,
|
||||
channel_info: snd_pcm_null_channel_info,
|
||||
channel_params: snd_pcm_null_channel_params,
|
||||
channel_setup: snd_pcm_null_channel_setup,
|
||||
dump: snd_pcm_null_dump,
|
||||
nonblock: snd_pcm_null_nonblock,
|
||||
async: snd_pcm_null_async,
|
||||
|
|
|
|||
|
|
@ -32,37 +32,25 @@ typedef struct {
|
|||
} snd_pcm_plug_t;
|
||||
|
||||
|
||||
unsigned int snd_pcm_plug_formats(unsigned int formats)
|
||||
{
|
||||
int fmts = (SND_PCM_LINEAR_FORMATS | SND_PCM_FMT_MU_LAW |
|
||||
SND_PCM_FMT_A_LAW | SND_PCM_FMT_IMA_ADPCM);
|
||||
if (formats & fmts)
|
||||
formats |= fmts;
|
||||
return formats;
|
||||
}
|
||||
|
||||
static int preferred_formats[] = {
|
||||
SND_PCM_SFMT_S16_LE,
|
||||
SND_PCM_SFMT_S16_BE,
|
||||
SND_PCM_SFMT_U16_LE,
|
||||
SND_PCM_SFMT_U16_BE,
|
||||
SND_PCM_SFMT_S24_LE,
|
||||
SND_PCM_SFMT_S24_BE,
|
||||
SND_PCM_SFMT_U24_LE,
|
||||
SND_PCM_SFMT_U24_BE,
|
||||
SND_PCM_SFMT_S32_LE,
|
||||
SND_PCM_SFMT_S32_BE,
|
||||
SND_PCM_SFMT_U32_LE,
|
||||
SND_PCM_SFMT_U32_BE,
|
||||
SND_PCM_SFMT_S8,
|
||||
SND_PCM_SFMT_U8
|
||||
SND_PCM_FORMAT_S16_LE,
|
||||
SND_PCM_FORMAT_S16_BE,
|
||||
SND_PCM_FORMAT_U16_LE,
|
||||
SND_PCM_FORMAT_U16_BE,
|
||||
SND_PCM_FORMAT_S24_LE,
|
||||
SND_PCM_FORMAT_S24_BE,
|
||||
SND_PCM_FORMAT_U24_LE,
|
||||
SND_PCM_FORMAT_U24_BE,
|
||||
SND_PCM_FORMAT_S32_LE,
|
||||
SND_PCM_FORMAT_S32_BE,
|
||||
SND_PCM_FORMAT_U32_LE,
|
||||
SND_PCM_FORMAT_U32_BE,
|
||||
SND_PCM_FORMAT_S8,
|
||||
SND_PCM_FORMAT_U8
|
||||
};
|
||||
|
||||
static int snd_pcm_plug_slave_fmt(int format,
|
||||
snd_pcm_params_info_t *slave_info)
|
||||
static int snd_pcm_plug_slave_fmt(int format, unsigned int format_mask)
|
||||
{
|
||||
if ((snd_pcm_plug_formats(slave_info->formats) & (1 << format)) == 0)
|
||||
return -EINVAL;
|
||||
if (snd_pcm_format_linear(format)) {
|
||||
int width = snd_pcm_format_width(format);
|
||||
int unsignd = snd_pcm_format_unsigned(format);
|
||||
|
|
@ -77,8 +65,8 @@ static int snd_pcm_plug_slave_fmt(int format,
|
|||
for (sgn = 0; sgn < 2; ++sgn) {
|
||||
format1 = snd_pcm_build_linear_format(width1, unsignd1, big1);
|
||||
if (format1 >= 0 &&
|
||||
slave_info->formats & (1 << format1))
|
||||
goto _found;
|
||||
format_mask & (1U << format1))
|
||||
return format1;
|
||||
unsignd1 = !unsignd1;
|
||||
}
|
||||
big1 = !big1;
|
||||
|
|
@ -89,80 +77,24 @@ static int snd_pcm_plug_slave_fmt(int format,
|
|||
}
|
||||
width1 += dwidth1;
|
||||
}
|
||||
return -EINVAL;
|
||||
_found:
|
||||
return format1;
|
||||
return ffs(format_mask) - 1;
|
||||
} else {
|
||||
unsigned int i;
|
||||
switch (format) {
|
||||
case SND_PCM_SFMT_MU_LAW:
|
||||
case SND_PCM_SFMT_A_LAW:
|
||||
case SND_PCM_SFMT_IMA_ADPCM:
|
||||
case SND_PCM_FORMAT_MU_LAW:
|
||||
case SND_PCM_FORMAT_A_LAW:
|
||||
case SND_PCM_FORMAT_IMA_ADPCM:
|
||||
for (i = 0; i < sizeof(preferred_formats) / sizeof(preferred_formats[0]); ++i) {
|
||||
int format1 = preferred_formats[i];
|
||||
if (slave_info->formats & (1 << format1))
|
||||
if (format_mask & (1U << format1))
|
||||
return format1;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
return ffs(format_mask) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct {
|
||||
unsigned int rate;
|
||||
unsigned int flag;
|
||||
} snd_pcm_rates[] = {
|
||||
{ 8000, SND_PCM_RATE_8000 },
|
||||
{ 11025, SND_PCM_RATE_11025 },
|
||||
{ 16000, SND_PCM_RATE_16000 },
|
||||
{ 22050, SND_PCM_RATE_22050 },
|
||||
{ 32000, SND_PCM_RATE_32000 },
|
||||
{ 44100, SND_PCM_RATE_44100 },
|
||||
{ 48000, SND_PCM_RATE_48000 },
|
||||
{ 88200, SND_PCM_RATE_88200 },
|
||||
{ 96000, SND_PCM_RATE_96000 },
|
||||
{ 176400, SND_PCM_RATE_176400 },
|
||||
{ 192000, SND_PCM_RATE_192000 }
|
||||
};
|
||||
|
||||
static int snd_pcm_plug_slave_rate(unsigned int rate,
|
||||
snd_pcm_params_info_t *slave_info)
|
||||
{
|
||||
if (rate <= slave_info->min_rate)
|
||||
return slave_info->min_rate;
|
||||
else if (rate >= slave_info->max_rate)
|
||||
return slave_info->max_rate;
|
||||
else if (!(slave_info->rates & (SND_PCM_RATE_CONTINUOUS |
|
||||
SND_PCM_RATE_KNOT))) {
|
||||
unsigned int k;
|
||||
unsigned int rate1 = 0, rate2 = 0;
|
||||
int delta1, delta2;
|
||||
for (k = 0; k < sizeof(snd_pcm_rates) /
|
||||
sizeof(snd_pcm_rates[0]); ++k) {
|
||||
if (!(snd_pcm_rates[k].flag & slave_info->rates))
|
||||
continue;
|
||||
if (snd_pcm_rates[k].rate < rate) {
|
||||
rate1 = snd_pcm_rates[k].rate;
|
||||
} else if (snd_pcm_rates[k].rate >= rate) {
|
||||
rate2 = snd_pcm_rates[k].rate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rate1 == 0)
|
||||
return rate2;
|
||||
if (rate2 == 0)
|
||||
return rate1;
|
||||
delta1 = rate - rate1;
|
||||
delta2 = rate2 - rate;
|
||||
if (delta1 < delta2)
|
||||
return rate1;
|
||||
else
|
||||
return rate2;
|
||||
}
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_close(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
|
|
@ -206,97 +138,156 @@ static int snd_pcm_plug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
|
||||
static int snd_pcm_plug_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
|
||||
{
|
||||
int err;
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
snd_pcm_t *slave = plug->req_slave;
|
||||
snd_pcm_params_info_t slave_info;
|
||||
int sformat, srate;
|
||||
unsigned int schannels;
|
||||
int crate;
|
||||
|
||||
info->req.fail_reason = 0;
|
||||
info->req.fail_mask = 0;
|
||||
|
||||
if (info->req_mask & SND_PCM_PARAMS_RATE) {
|
||||
info->min_rate = info->req.format.rate;
|
||||
info->max_rate = info->req.format.rate;
|
||||
} else {
|
||||
info->min_rate = 4000;
|
||||
info->max_rate = 192000;
|
||||
}
|
||||
info->rates = SND_PCM_RATE_CONTINUOUS | SND_PCM_RATE_8000_192000;
|
||||
|
||||
if (info->req_mask & SND_PCM_PARAMS_CHANNELS) {
|
||||
info->min_channels = info->req.format.channels;
|
||||
info->max_channels = info->req.format.channels;
|
||||
} else {
|
||||
info->min_channels = 1;
|
||||
info->max_channels = 32;
|
||||
}
|
||||
|
||||
memset(&slave_info, 0, sizeof(slave_info));
|
||||
if ((err = snd_pcm_params_info(slave, &slave_info)) < 0)
|
||||
return err;
|
||||
|
||||
info->flags = slave_info.flags;
|
||||
info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
|
||||
|
||||
info->min_fragments = slave_info.min_fragments;
|
||||
info->max_fragments = slave_info.max_fragments;
|
||||
snd_pcm_hw_info_t sinfo, i;
|
||||
snd_pcm_hw_params_t sparams;
|
||||
unsigned int rate_min, rate_max;
|
||||
unsigned int channels_min, channels_max;
|
||||
unsigned int format, format_mask;
|
||||
size_t fragment_size_min, fragment_size_max;
|
||||
|
||||
if (info->req_mask & SND_PCM_PARAMS_SFMT)
|
||||
info->formats = 1 << info->req.format.sfmt;
|
||||
else {
|
||||
info->formats = snd_pcm_plug_formats(slave_info.formats);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sformat = snd_pcm_plug_slave_fmt(info->req.format.sfmt, &slave_info);
|
||||
if (sformat < 0) {
|
||||
info->req.fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(info->req_mask & SND_PCM_PARAMS_RATE))
|
||||
return 0;
|
||||
crate = info->req.format.rate;
|
||||
srate = snd_pcm_plug_slave_rate(crate, &slave_info);
|
||||
if (srate < 0) {
|
||||
info->req.fail_mask = SND_PCM_PARAMS_RATE;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(info->req_mask & SND_PCM_PARAMS_CHANNELS))
|
||||
return 0;
|
||||
schannels = info->req.format.channels;
|
||||
if (schannels < info->min_channels)
|
||||
schannels = info->min_channels;
|
||||
else if (schannels > info->max_channels)
|
||||
schannels = info->max_channels;
|
||||
if (info->rate_min < 4000)
|
||||
info->rate_min = 4000;
|
||||
if (info->rate_max > 192000)
|
||||
info->rate_max = 192000;
|
||||
if (info->rate_max < info->rate_min)
|
||||
return -EINVAL;
|
||||
|
||||
slave_info.req_mask = (SND_PCM_PARAMS_SFMT |
|
||||
SND_PCM_PARAMS_CHANNELS |
|
||||
SND_PCM_PARAMS_RATE);
|
||||
slave_info.req.format.sfmt = sformat;
|
||||
slave_info.req.format.channels = schannels;
|
||||
slave_info.req.format.rate = srate;
|
||||
if ((err = snd_pcm_params_info(slave, &slave_info)) < 0) {
|
||||
info->req.fail_mask = slave_info.req.fail_mask;
|
||||
info->req.fail_reason = slave_info.req.fail_reason;
|
||||
if (info->channels_min < 1)
|
||||
info->channels_min = 1;
|
||||
if (info->channels_max > 1024)
|
||||
info->channels_max = 1024;
|
||||
if (info->channels_max < info->channels_min)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->fragment_size_max > 1024 * 1024)
|
||||
info->fragment_size_max = 1024 * 1024;
|
||||
if (info->fragment_size_max < info->fragment_size_min)
|
||||
return -EINVAL;
|
||||
|
||||
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.subformat_mask = SND_PCM_SUBFMTBIT_STD;
|
||||
sinfo.channels_min = 1;
|
||||
sinfo.channels_max = 1024;
|
||||
sinfo.rate_min = 4000;
|
||||
sinfo.rate_max = 192000;
|
||||
sinfo.fragments_min = 1;
|
||||
sinfo.fragments_max = UINT_MAX;
|
||||
sinfo.fragment_size_min = 1;
|
||||
sinfo.fragment_size_max = ULONG_MAX;
|
||||
|
||||
/* Formats */
|
||||
err = snd_pcm_hw_info(slave, &sinfo);
|
||||
if (err < 0) {
|
||||
*info = i;
|
||||
return err;
|
||||
}
|
||||
info->buffer_size = muldiv64(slave_info.buffer_size, crate, srate);
|
||||
info->min_fragment_size = muldiv64(slave_info.min_fragment_size, crate, srate);
|
||||
info->max_fragment_size = muldiv64(slave_info.max_fragment_size, crate, srate);
|
||||
info->fragment_align = muldiv64(slave_info.fragment_align, crate, srate);
|
||||
if (sformat != info->req.format.sfmt ||
|
||||
(unsigned int) srate != info->req.format.rate ||
|
||||
schannels != info->req.format.channels)
|
||||
info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
format_mask = 0;
|
||||
for (format = 0; format < SND_PCM_FORMAT_LAST; ++format) {
|
||||
if (!(info->format_mask & (1 << format)))
|
||||
continue;
|
||||
err = snd_pcm_plug_slave_fmt(format, sinfo.format_mask);
|
||||
if (err < 0)
|
||||
info->format_mask &= ~(1 << format);
|
||||
else
|
||||
format_mask |= (1 << err);
|
||||
}
|
||||
sinfo.format_mask = format_mask;
|
||||
|
||||
/* Rate (and fragment_size) */
|
||||
i = sinfo;
|
||||
sparams.rate = info->rate_min;
|
||||
err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
|
||||
SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_RATE,
|
||||
-1);
|
||||
if (err < 0) {
|
||||
*info = i;
|
||||
return err;
|
||||
}
|
||||
rate_min = i.rate_min;
|
||||
if (info->rate_max != info->rate_min) {
|
||||
i = sinfo;
|
||||
sparams.rate = info->rate_max;
|
||||
err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
|
||||
SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_RATE,
|
||||
-1);
|
||||
if (err < 0) {
|
||||
*info = i;
|
||||
return err;
|
||||
}
|
||||
rate_max = i.rate_min;
|
||||
} else
|
||||
rate_max = rate_min;
|
||||
sinfo.rate_min = rate_min;
|
||||
sinfo.rate_max = rate_max;
|
||||
|
||||
/* Channels */
|
||||
i = sinfo;
|
||||
sparams.channels = info->channels_min;
|
||||
err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
|
||||
SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_CHANNELS,
|
||||
-1);
|
||||
if (err < 0) {
|
||||
*info = i;
|
||||
return err;
|
||||
}
|
||||
channels_min = i.channels_min;
|
||||
if (info->channels_max != info->channels_min) {
|
||||
i = sinfo;
|
||||
sparams.channels = info->channels_max;
|
||||
err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
|
||||
SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_CHANNELS,
|
||||
-1);
|
||||
if (err < 0) {
|
||||
*info = i;
|
||||
return err;
|
||||
}
|
||||
channels_max = i.channels_min;
|
||||
} else
|
||||
channels_max = channels_min;
|
||||
sinfo.channels_min = channels_min;
|
||||
sinfo.channels_max = channels_max;
|
||||
|
||||
sinfo.fragments_min = info->fragments_min;
|
||||
sinfo.fragments_max = info->fragments_max;
|
||||
sinfo.fragment_size_min = muldiv_down(info->fragment_size_min, sinfo.rate_min, info->rate_max);
|
||||
sinfo.fragment_size_max = muldiv_up(info->fragment_size_max, sinfo.rate_max, info->rate_min);
|
||||
err = snd_pcm_hw_info(slave, &sinfo);
|
||||
if (err < 0) {
|
||||
*info = sinfo;
|
||||
return err;
|
||||
}
|
||||
|
||||
info->subformat_mask = sinfo.subformat_mask;
|
||||
info->fragments_min = sinfo.fragments_min;
|
||||
info->fragments_max = sinfo.fragments_max;
|
||||
|
||||
fragment_size_min = muldiv_down(sinfo.fragment_size_min, info->rate_min, sinfo.rate_max);
|
||||
fragment_size_max = muldiv_up(sinfo.fragment_size_max, info->rate_max, sinfo.rate_min);
|
||||
if (fragment_size_min > info->fragment_size_min)
|
||||
info->fragment_size_min = fragment_size_min;
|
||||
if (fragment_size_max < info->fragment_size_max)
|
||||
info->fragment_size_max = fragment_size_max;
|
||||
info->info = sinfo.info & ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
snd_pcm_hw_info_complete(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -313,29 +304,29 @@ 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_format_t *clt, snd_pcm_format_t *slv)
|
||||
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)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
int err;
|
||||
assert(snd_pcm_format_linear(slv->sfmt));
|
||||
assert(snd_pcm_format_linear(slv->format));
|
||||
if (clt->rate == slv->rate)
|
||||
return 0;
|
||||
err = snd_pcm_rate_open(new, NULL, slv->sfmt, slv->rate, plug->slave, plug->slave != plug->req_slave);
|
||||
err = snd_pcm_rate_open(new, NULL, slv->format, slv->rate, plug->slave, plug->slave != plug->req_slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
slv->rate = clt->rate;
|
||||
if (snd_pcm_format_linear(clt->sfmt))
|
||||
slv->sfmt = clt->sfmt;
|
||||
if (snd_pcm_format_linear(clt->format))
|
||||
slv->format = clt->format;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *clt, snd_pcm_format_t *slv)
|
||||
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)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
unsigned int tt_ssize, tt_cused, tt_sused;
|
||||
ttable_entry_t *ttable;
|
||||
int err;
|
||||
assert(snd_pcm_format_linear(slv->sfmt));
|
||||
assert(snd_pcm_format_linear(slv->format));
|
||||
if (clt->channels == slv->channels)
|
||||
return 0;
|
||||
if (clt->rate != slv->rate &&
|
||||
|
|
@ -384,100 +375,100 @@ static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm
|
|||
s = 0;
|
||||
}
|
||||
}
|
||||
err = snd_pcm_route_open(new, NULL, slv->sfmt, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
|
||||
err = snd_pcm_route_open(new, NULL, slv->format, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
slv->channels = clt->channels;
|
||||
if (snd_pcm_format_linear(clt->sfmt))
|
||||
slv->sfmt = clt->sfmt;
|
||||
if (snd_pcm_format_linear(clt->format))
|
||||
slv->format = clt->format;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *clt, snd_pcm_format_t *slv)
|
||||
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)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
int err, cfmt;
|
||||
int (*f)(snd_pcm_t **pcm, char *name, int sformat, snd_pcm_t *slave, int close_slave);
|
||||
if (snd_pcm_format_linear(slv->sfmt)) {
|
||||
if (snd_pcm_format_linear(slv->format)) {
|
||||
/* Conversion is done in another plugin */
|
||||
if (clt->sfmt == slv->sfmt ||
|
||||
if (clt->format == slv->format ||
|
||||
clt->rate != slv->rate ||
|
||||
clt->channels != slv->channels)
|
||||
return 0;
|
||||
} else {
|
||||
/* No conversion is needed */
|
||||
if (clt->sfmt == slv->sfmt &&
|
||||
if (clt->format == slv->format &&
|
||||
clt->rate == slv->rate &&
|
||||
clt->channels == clt->channels)
|
||||
return 0;
|
||||
}
|
||||
if (snd_pcm_format_linear(slv->sfmt)) {
|
||||
cfmt = clt->sfmt;
|
||||
switch (clt->sfmt) {
|
||||
case SND_PCM_SFMT_MU_LAW:
|
||||
if (snd_pcm_format_linear(slv->format)) {
|
||||
cfmt = clt->format;
|
||||
switch (clt->format) {
|
||||
case SND_PCM_FORMAT_MU_LAW:
|
||||
f = snd_pcm_mulaw_open;
|
||||
break;
|
||||
case SND_PCM_SFMT_A_LAW:
|
||||
case SND_PCM_FORMAT_A_LAW:
|
||||
f = snd_pcm_alaw_open;
|
||||
break;
|
||||
case SND_PCM_SFMT_IMA_ADPCM:
|
||||
case SND_PCM_FORMAT_IMA_ADPCM:
|
||||
f = snd_pcm_adpcm_open;
|
||||
break;
|
||||
default:
|
||||
assert(snd_pcm_format_linear(clt->sfmt));
|
||||
assert(snd_pcm_format_linear(clt->format));
|
||||
f = snd_pcm_linear_open;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (slv->sfmt) {
|
||||
case SND_PCM_SFMT_MU_LAW:
|
||||
switch (slv->format) {
|
||||
case SND_PCM_FORMAT_MU_LAW:
|
||||
f = snd_pcm_mulaw_open;
|
||||
break;
|
||||
case SND_PCM_SFMT_A_LAW:
|
||||
case SND_PCM_FORMAT_A_LAW:
|
||||
f = snd_pcm_alaw_open;
|
||||
break;
|
||||
case SND_PCM_SFMT_IMA_ADPCM:
|
||||
case SND_PCM_FORMAT_IMA_ADPCM:
|
||||
f = snd_pcm_adpcm_open;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (snd_pcm_format_linear(clt->sfmt))
|
||||
cfmt = clt->sfmt;
|
||||
if (snd_pcm_format_linear(clt->format))
|
||||
cfmt = clt->format;
|
||||
else
|
||||
cfmt = SND_PCM_SFMT_S16;
|
||||
cfmt = SND_PCM_FORMAT_S16;
|
||||
}
|
||||
err = f(new, NULL, slv->sfmt, plug->slave, plug->slave != plug->req_slave);
|
||||
err = f(new, NULL, slv->format, plug->slave, plug->slave != plug->req_slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
slv->sfmt = cfmt;
|
||||
slv->format = cfmt;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
|
||||
snd_pcm_format_t *client_fmt,
|
||||
snd_pcm_format_t *slave_fmt)
|
||||
snd_pcm_hw_params_t *client,
|
||||
snd_pcm_hw_params_t *slave)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *s, snd_pcm_format_t *d) = {
|
||||
int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *s, snd_pcm_hw_params_t *d) = {
|
||||
snd_pcm_plug_change_format,
|
||||
snd_pcm_plug_change_channels,
|
||||
snd_pcm_plug_change_rate,
|
||||
snd_pcm_plug_change_channels,
|
||||
snd_pcm_plug_change_format
|
||||
};
|
||||
snd_pcm_format_t sfmt = *slave_fmt;
|
||||
snd_pcm_hw_params_t p = *slave;
|
||||
unsigned int k = 0;
|
||||
while (1) {
|
||||
snd_pcm_t *new;
|
||||
int err;
|
||||
if (client_fmt->sfmt == sfmt.sfmt &&
|
||||
client_fmt->channels == sfmt.channels &&
|
||||
client_fmt->rate == sfmt.rate)
|
||||
if (client->format == p.format &&
|
||||
client->channels == p.channels &&
|
||||
client->rate == p.rate)
|
||||
return 0;
|
||||
assert(k < sizeof(funcs)/sizeof(*funcs));
|
||||
err = funcs[k](pcm, &new, client_fmt, &sfmt);
|
||||
err = funcs[k](pcm, &new, client, &p);
|
||||
if (err < 0) {
|
||||
snd_pcm_plug_clear(pcm);
|
||||
return err;
|
||||
|
|
@ -493,134 +484,118 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
||||
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_format_t *slave_format, *format;
|
||||
snd_pcm_params_info_t slave_info;
|
||||
int srate;
|
||||
snd_pcm_hw_info_t sinfo;
|
||||
snd_pcm_hw_params_t sparams;
|
||||
int err;
|
||||
|
||||
memset(&slave_info, 0, sizeof(slave_info));
|
||||
err = snd_pcm_params_info(slave, &slave_info);
|
||||
assert(err >= 0);
|
||||
if (err < 0)
|
||||
sparams = *params;
|
||||
snd_pcm_hw_params_to_info(&sparams, &sinfo);
|
||||
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.subformat_mask = SND_PCM_SUBFMTBIT_STD;
|
||||
sinfo.channels_min = 1;
|
||||
sinfo.channels_max = 1024;
|
||||
sinfo.rate_min = 4000;
|
||||
sinfo.rate_max = 192000;
|
||||
sinfo.fragment_size_min = 1;
|
||||
sinfo.fragment_size_max = ULONG_MAX;
|
||||
err = snd_pcm_hw_info_rulesv(slave, &sinfo, params,
|
||||
SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_RATE,
|
||||
SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_CHANNELS,
|
||||
-1);
|
||||
if (err < 0) {
|
||||
snd_pcm_hw_info_to_params_fail(&sinfo, params);
|
||||
return err;
|
||||
|
||||
slave_info.req = *params;
|
||||
format = ¶ms->format;
|
||||
slave_format = &slave_info.req.format;
|
||||
|
||||
srate = snd_pcm_plug_slave_rate(format->rate, &slave_info);
|
||||
if (srate < 0) {
|
||||
params->fail_mask = SND_PCM_PARAMS_RATE;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return srate;
|
||||
}
|
||||
slave_format->rate = srate;
|
||||
slave_info.req_mask |= SND_PCM_PARAMS_RATE;
|
||||
err = snd_pcm_params_info(slave, &slave_info);
|
||||
assert(err >= 0);
|
||||
err = snd_pcm_plug_slave_fmt(sparams.format, sinfo.format_mask);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (slave_format->rate - slave_info.min_rate < slave_info.max_rate - slave_format->rate)
|
||||
slave_format->rate = slave_info.min_rate;
|
||||
sparams.format = err;
|
||||
sinfo.format_mask = 1U << err;
|
||||
sparams.fragment_size = muldiv_near(params->fragment_size, sparams.rate, params->rate);
|
||||
err = snd_pcm_hw_info_rulesv(slave, &sinfo, &sparams,
|
||||
SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_FRAGMENT_SIZE,
|
||||
-1);
|
||||
if (err < 0) {
|
||||
snd_pcm_hw_info_to_params_fail(&sinfo, params);
|
||||
return err;
|
||||
}
|
||||
if (sinfo.access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
|
||||
sparams.access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
|
||||
else if (sinfo.access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
|
||||
sparams.access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
slave_format->rate = slave_info.max_rate;
|
||||
assert(0);
|
||||
|
||||
if (format->channels < slave_info.min_channels)
|
||||
slave_format->channels = slave_info.min_channels;
|
||||
else if (format->channels > slave_info.max_channels)
|
||||
slave_format->channels = slave_info.max_channels;
|
||||
slave_info.req_mask |= SND_PCM_PARAMS_CHANNELS;
|
||||
err = snd_pcm_params_info(slave, &slave_info);
|
||||
assert(err >= 0);
|
||||
err = snd_pcm_plug_insert_plugins(pcm, params, &sparams);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if ((slave_info.formats & (1 << format->sfmt)) == 0) {
|
||||
int slave_fmt = snd_pcm_plug_slave_fmt(format->sfmt, &slave_info);
|
||||
if (slave_fmt < 0) {
|
||||
params->fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return slave_fmt;
|
||||
}
|
||||
slave_format->sfmt = slave_fmt;
|
||||
}
|
||||
slave_info.req_mask |= SND_PCM_PARAMS_SFMT;
|
||||
|
||||
if (slave_info.formats != 1U << slave_format->sfmt) {
|
||||
err = snd_pcm_params_info(slave, &slave_info);
|
||||
assert(err >= 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_pcm_plug_insert_plugins(pcm, format, slave_format);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_pcm_params(plug->slave, params);
|
||||
err = snd_pcm_hw_params(plug->slave, params);
|
||||
if (err < 0) {
|
||||
snd_pcm_plug_clear(pcm);
|
||||
return err;
|
||||
}
|
||||
assert(slave->setup.format.sfmt == slave_format->sfmt);
|
||||
assert(slave->setup.format.channels == slave_format->channels);
|
||||
assert(slave->setup.format.rate == slave_format->rate);
|
||||
pcm->hw_ptr = slave->hw_ptr;
|
||||
pcm->appl_ptr = slave->appl_ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
|
||||
static int snd_pcm_plug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
return snd_pcm_setup(plug->slave, setup);
|
||||
snd_pcm_t *slave = plug->req_slave;
|
||||
size_t avail_min, xfer_min, xfer_align;
|
||||
int err;
|
||||
avail_min = params->avail_min;
|
||||
xfer_min = params->xfer_min;
|
||||
xfer_align = params->xfer_align;
|
||||
params->avail_min = muldiv_near(params->avail_min, slave->rate, pcm->rate);
|
||||
params->xfer_min = muldiv_near(params->xfer_min, slave->rate, pcm->rate);
|
||||
params->xfer_align = muldiv_near(params->xfer_align, slave->rate, pcm->rate);
|
||||
err = snd_pcm_sw_params(slave, params);
|
||||
params->avail_min = avail_min;
|
||||
params->xfer_min = xfer_min;
|
||||
params->xfer_align = xfer_align;
|
||||
params->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
return snd_pcm_dig_info(plug->slave, info);
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
return snd_pcm_dig_params(plug->slave, params);
|
||||
}
|
||||
|
||||
|
||||
static int snd_pcm_plug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
return snd_pcm_channel_info(plug->slave, info);
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
return snd_pcm_channel_params(plug->slave, params);
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
return snd_pcm_channel_setup(plug->slave, setup);
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_mmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
int err = snd_pcm_mmap(plug->slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
pcm->mmap_info_count = plug->slave->mmap_info_count;
|
||||
pcm->mmap_info = plug->slave->mmap_info;
|
||||
return 0;
|
||||
snd_pcm_plugin_t *plug = pcm->private;
|
||||
return snd_pcm_mmap(plug->slave);
|
||||
}
|
||||
|
||||
static int snd_pcm_plug_munmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
int err = snd_pcm_munmap(plug->slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
pcm->mmap_info_count = 0;
|
||||
pcm->mmap_info = 0;
|
||||
return 0;
|
||||
snd_pcm_plugin_t *plug = pcm->private;
|
||||
return snd_pcm_munmap(plug->slave);
|
||||
}
|
||||
|
||||
|
||||
static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
|
||||
{
|
||||
snd_pcm_plug_t *plug = pcm->private;
|
||||
|
|
@ -631,12 +606,12 @@ 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,
|
||||
params_info: snd_pcm_plug_params_info,
|
||||
params: snd_pcm_plug_params,
|
||||
setup: snd_pcm_plug_setup,
|
||||
hw_info: snd_pcm_plug_hw_info,
|
||||
hw_params: snd_pcm_plug_hw_params,
|
||||
sw_params: snd_pcm_plug_sw_params,
|
||||
dig_info: snd_pcm_plug_dig_info,
|
||||
dig_params: snd_pcm_plug_dig_params,
|
||||
channel_info: snd_pcm_plug_channel_info,
|
||||
channel_params: snd_pcm_plug_channel_params,
|
||||
channel_setup: snd_pcm_plug_channel_setup,
|
||||
dump: snd_pcm_plug_dump,
|
||||
nonblock: snd_pcm_plug_nonblock,
|
||||
async: snd_pcm_plug_async,
|
||||
|
|
@ -687,19 +662,14 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int snd_pcm_plug_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, int stream, int mode)
|
||||
int snd_pcm_plug_open_hw(snd_pcm_t **pcmp, char *name, int card, int device, int subdevice, int stream, int mode)
|
||||
{
|
||||
snd_pcm_t *slave;
|
||||
int err;
|
||||
err = snd_pcm_hw_open_subdevice(&slave, card, device, subdevice, stream, mode);
|
||||
err = snd_pcm_hw_open(&slave, NULL, card, device, subdevice, stream, mode);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return snd_pcm_plug_open(pcmp, NULL, 0, 0, 0, 0, slave, 1);
|
||||
}
|
||||
|
||||
int snd_pcm_plug_open_device(snd_pcm_t **pcmp, int card, int device, int stream, int mode)
|
||||
{
|
||||
return snd_pcm_plug_open_subdevice(pcmp, card, device, -1, stream, mode);
|
||||
return snd_pcm_plug_open(pcmp, name, 0, 0, 0, 0, slave, 1);
|
||||
}
|
||||
|
||||
#define MAX_CHANNELS 32
|
||||
|
|
|
|||
|
|
@ -52,38 +52,28 @@ int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
|
|||
return snd_pcm_info(plugin->slave, info);
|
||||
}
|
||||
|
||||
int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
|
||||
int snd_pcm_plugin_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
|
||||
{
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
return snd_pcm_channel_info(plugin->slave, info);
|
||||
return snd_pcm_sw_params(plugin->slave, params);
|
||||
}
|
||||
|
||||
int snd_pcm_plugin_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
|
||||
int snd_pcm_plugin_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info)
|
||||
{
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
return snd_pcm_channel_params(plugin->slave, params);
|
||||
return snd_pcm_dig_info(plugin->slave, info);
|
||||
}
|
||||
|
||||
int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
|
||||
int snd_pcm_plugin_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params)
|
||||
{
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
int err;
|
||||
err = snd_pcm_channel_setup(plugin->slave, setup);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!pcm->mmap_info)
|
||||
return 0;
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
|
||||
setup->running_area.addr = pcm->mmap_info->addr;
|
||||
setup->running_area.first = setup->channel * pcm->bits_per_sample;
|
||||
setup->running_area.step = pcm->bits_per_frame;
|
||||
} else {
|
||||
setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
|
||||
setup->running_area.first = 0;
|
||||
setup->running_area.step = pcm->bits_per_sample;
|
||||
}
|
||||
setup->stopped_area = setup->running_area;
|
||||
return 0;
|
||||
return snd_pcm_dig_params(plugin->slave, params);
|
||||
}
|
||||
|
||||
int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
|
||||
{
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
return snd_pcm_channel_info_shm(pcm, info, plugin->shmid);
|
||||
}
|
||||
|
||||
int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
|
||||
|
|
@ -185,7 +175,7 @@ ssize_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, size_t frames)
|
|||
ssize_t snd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
|
||||
{
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
snd_pcm_channel_area_t areas[pcm->setup.format.channels];
|
||||
snd_pcm_channel_area_t areas[pcm->channels];
|
||||
ssize_t frames;
|
||||
snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
|
||||
frames = snd_pcm_write_areas(pcm, areas, 0, size, plugin->write);
|
||||
|
|
@ -197,7 +187,7 @@ ssize_t snd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
|
|||
ssize_t snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, size_t size)
|
||||
{
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
snd_pcm_channel_area_t areas[pcm->setup.format.channels];
|
||||
snd_pcm_channel_area_t areas[pcm->channels];
|
||||
ssize_t frames;
|
||||
snd_pcm_areas_from_bufs(pcm, areas, bufs);
|
||||
frames = snd_pcm_write_areas(pcm, areas, 0, size, plugin->write);
|
||||
|
|
@ -209,7 +199,7 @@ ssize_t snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, size_t size)
|
|||
ssize_t snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, size_t size)
|
||||
{
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
snd_pcm_channel_area_t areas[pcm->setup.format.channels];
|
||||
snd_pcm_channel_area_t areas[pcm->channels];
|
||||
ssize_t frames;
|
||||
snd_pcm_areas_from_buf(pcm, areas, buffer);
|
||||
frames = snd_pcm_read_areas(pcm, areas, 0, size, plugin->read);
|
||||
|
|
@ -221,7 +211,7 @@ ssize_t snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, size_t size)
|
|||
ssize_t snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, size_t size)
|
||||
{
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
snd_pcm_channel_area_t areas[pcm->setup.format.channels];
|
||||
snd_pcm_channel_area_t areas[pcm->channels];
|
||||
ssize_t frames;
|
||||
snd_pcm_areas_from_bufs(pcm, areas, bufs);
|
||||
frames = snd_pcm_read_areas(pcm, areas, 0, size, plugin->read);
|
||||
|
|
@ -251,7 +241,7 @@ ssize_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, size_t client_size)
|
|||
size_t slave_frames = slave_size - slave_xfer;
|
||||
size_t client_frames = client_size - client_xfer;
|
||||
size_t offset = snd_pcm_mmap_hw_offset(pcm);
|
||||
size_t cont = pcm->setup.buffer_size - offset;
|
||||
size_t cont = pcm->buffer_size - offset;
|
||||
if (cont < client_frames)
|
||||
client_frames = cont;
|
||||
err = plugin->write(pcm, pcm->running_areas, offset,
|
||||
|
|
@ -279,17 +269,18 @@ ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
|
|||
if (slave_size <= 0)
|
||||
return slave_size;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK ||
|
||||
!pcm->mmap_info)
|
||||
pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
|
||||
pcm->access == SND_PCM_ACCESS_RW_NONINTERLEAVED)
|
||||
return plugin->client_frames ?
|
||||
plugin->client_frames(pcm, slave_size) : slave_size;
|
||||
client_xfer = snd_pcm_mmap_capture_avail(pcm);
|
||||
client_size = pcm->setup.buffer_size;
|
||||
client_size = pcm->buffer_size;
|
||||
while (slave_xfer < (size_t)slave_size &&
|
||||
client_xfer < client_size) {
|
||||
size_t slave_frames = slave_size - slave_xfer;
|
||||
size_t client_frames = client_size - client_xfer;
|
||||
size_t offset = snd_pcm_mmap_hw_offset(pcm);
|
||||
size_t cont = pcm->setup.buffer_size - offset;
|
||||
size_t cont = pcm->buffer_size - offset;
|
||||
if (cont < client_frames)
|
||||
client_frames = cont;
|
||||
err = plugin->read(pcm, pcm->running_areas, offset,
|
||||
|
|
@ -313,38 +304,26 @@ int snd_pcm_plugin_set_avail_min(snd_pcm_t *pcm, size_t frames)
|
|||
|
||||
int snd_pcm_plugin_mmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
snd_pcm_t *slave = plugin->slave;
|
||||
snd_pcm_mmap_info_t *i;
|
||||
int err = snd_pcm_mmap(slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
i = calloc(1, sizeof(*i));
|
||||
if (!i)
|
||||
return -ENOMEM;
|
||||
err = snd_pcm_alloc_user_mmap(pcm, i);
|
||||
if (err < 0) {
|
||||
free(i);
|
||||
return err;
|
||||
snd_pcm_plugin_t *plug = pcm->private;
|
||||
if (!(pcm->info & SND_PCM_INFO_MMAP)) {
|
||||
size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
|
||||
int id = shmget(IPC_PRIVATE, size, 0666);
|
||||
if (id < 0) {
|
||||
SYSERR("shmget failed");
|
||||
return -errno;
|
||||
}
|
||||
plug->shmid = id;
|
||||
}
|
||||
pcm->mmap_info = i;
|
||||
pcm->mmap_info_count = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_pcm_plugin_munmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
snd_pcm_t *slave = plugin->slave;
|
||||
int err = snd_pcm_munmap(slave);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
|
||||
if (err < 0)
|
||||
return err;
|
||||
free(pcm->mmap_info);
|
||||
pcm->mmap_info_count = 0;
|
||||
pcm->mmap_info = 0;
|
||||
snd_pcm_plugin_t *plug = pcm->private;
|
||||
if (shmctl(plug->shmid, IPC_RMID, 0) < 0) {
|
||||
SYSERR("shmctl IPC_RMID failed");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,18 +24,21 @@ typedef struct {
|
|||
int close_slave;
|
||||
snd_pcm_xfer_areas_func_t read;
|
||||
snd_pcm_xfer_areas_func_t write;
|
||||
size_t (*client_frames)(snd_pcm_t *pcm, size_t frames);
|
||||
ssize_t (*client_frames)(snd_pcm_t *pcm, ssize_t frames);
|
||||
int (*init)(snd_pcm_t *pcm);
|
||||
int shmid;
|
||||
size_t appl_ptr, hw_ptr;
|
||||
unsigned int saccess_mask;
|
||||
} snd_pcm_plugin_t;
|
||||
|
||||
int snd_pcm_plugin_close(snd_pcm_t *pcm);
|
||||
int snd_pcm_plugin_nonblock(snd_pcm_t *pcm, int nonblock);
|
||||
int snd_pcm_plugin_async(snd_pcm_t *pcm, int sig, pid_t pid);
|
||||
int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
|
||||
int snd_pcm_plugin_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
|
||||
int snd_pcm_plugin_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info);
|
||||
int snd_pcm_plugin_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params);
|
||||
int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
|
||||
int snd_pcm_plugin_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params);
|
||||
int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup);
|
||||
int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status);
|
||||
int snd_pcm_plugin_state(snd_pcm_t *pcm);
|
||||
int snd_pcm_plugin_delay(snd_pcm_t *pcm, ssize_t *delayp);
|
||||
|
|
@ -58,22 +61,34 @@ int snd_pcm_plugin_munmap_status(snd_pcm_t *pcm);
|
|||
int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm);
|
||||
int snd_pcm_plugin_munmap(snd_pcm_t *pcm);
|
||||
int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm);
|
||||
int snd_pcm_plugin_channels_mask(snd_pcm_t *pcm, bitset_t *cmask);
|
||||
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_LINEAR_FORMATS (SND_PCM_FMT_S8 | SND_PCM_FMT_U8 | \
|
||||
SND_PCM_FMT_S16_LE | SND_PCM_FMT_S16_BE | \
|
||||
SND_PCM_FMT_U16_LE | SND_PCM_FMT_U16_BE | \
|
||||
SND_PCM_FMT_S24_LE | SND_PCM_FMT_S24_BE | \
|
||||
SND_PCM_FMT_U24_LE | SND_PCM_FMT_U24_BE | \
|
||||
SND_PCM_FMT_S32_LE | SND_PCM_FMT_S32_BE | \
|
||||
SND_PCM_FMT_U32_LE | SND_PCM_FMT_U32_BE)
|
||||
#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)
|
||||
|
||||
extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops;
|
||||
|
||||
#define muldiv64(a,b,d) (((int64_t)(a) * (b) + (b) / 2) / (d))
|
||||
static inline ssize_t muldiv_down(ssize_t a, ssize_t b, ssize_t d)
|
||||
{
|
||||
return (int64_t) (a * b) / d;
|
||||
}
|
||||
|
||||
static inline ssize_t muldiv_up(ssize_t a, ssize_t b, ssize_t d)
|
||||
{
|
||||
return (int64_t) (a * b + (d - 1)) / d;
|
||||
}
|
||||
|
||||
static inline ssize_t muldiv_near(ssize_t a, ssize_t b, ssize_t d)
|
||||
{
|
||||
return (int64_t) (a * b + (d / 2)) / d;
|
||||
}
|
||||
|
||||
#define ROUTE_PLUGIN_FLOAT 1
|
||||
#define ROUTE_PLUGIN_RESOLUTION 16
|
||||
|
|
|
|||
|
|
@ -48,13 +48,8 @@ typedef struct {
|
|||
int put_idx;
|
||||
unsigned int pitch;
|
||||
rate_f func;
|
||||
int req_sformat;
|
||||
int req_srate;
|
||||
int sformat;
|
||||
int cformat;
|
||||
int srate;
|
||||
int crate;
|
||||
int cxfer_mode, cmmap_shape;
|
||||
rate_state_t *states;
|
||||
} snd_pcm_rate_t;
|
||||
|
||||
|
|
@ -93,7 +88,7 @@ static size_t resample_expand(snd_pcm_channel_area_t *src_areas,
|
|||
#if 0
|
||||
if (!src_area->enabled) {
|
||||
if (dst_area->wanted)
|
||||
snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format.sfmt);
|
||||
snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format);
|
||||
dst_area->enabled = 0;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -177,7 +172,7 @@ static size_t resample_shrink(snd_pcm_channel_area_t *src_areas,
|
|||
#if 0
|
||||
if (!src_area->enabled) {
|
||||
if (dst_area->wanted)
|
||||
snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format.sfmt);
|
||||
snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format);
|
||||
dst_area->enabled = 0;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -238,142 +233,132 @@ static int snd_pcm_rate_close(snd_pcm_t *pcm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_rate_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
|
||||
static int snd_pcm_rate_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
|
||||
{
|
||||
snd_pcm_rate_t *rate = pcm->private;
|
||||
unsigned int req_mask = info->req_mask;
|
||||
unsigned int sfmt = info->req.format.sfmt;
|
||||
unsigned int crate = info->req.format.rate;
|
||||
unsigned int srate;
|
||||
snd_pcm_hw_info_t sinfo;
|
||||
unsigned int access_mask;
|
||||
size_t fragment_size_min, fragment_size_max;
|
||||
int err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT &&
|
||||
!snd_pcm_format_linear(sfmt)) {
|
||||
info->req.fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
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;
|
||||
if (info->format_mask == 0)
|
||||
return -EINVAL;
|
||||
if (info->rate_min < 4000)
|
||||
info->rate_min = 4000;
|
||||
if (info->rate_max > 192000)
|
||||
info->rate_max = 192000;
|
||||
if (info->rate_max < info->rate_min)
|
||||
return -EINVAL;
|
||||
if (info->fragment_size_max > 1024 * 1024)
|
||||
info->fragment_size_max = 1024 * 1024;
|
||||
if (info->fragment_size_max < info->fragment_size_min)
|
||||
return -EINVAL;
|
||||
sinfo = *info;
|
||||
|
||||
sinfo.rate_min = rate->srate;
|
||||
sinfo.rate_max = rate->srate;
|
||||
if (rate->sformat >= 0)
|
||||
sinfo.format_mask = 1U << rate->sformat;
|
||||
sinfo.fragment_size_min = muldiv_down(info->fragment_size_min, sinfo.rate_min, info->rate_max);
|
||||
sinfo.fragment_size_max = muldiv_up(info->fragment_size_max, sinfo.rate_max, info->rate_min);
|
||||
|
||||
sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
|
||||
err = snd_pcm_hw_info(rate->plug.slave, &sinfo);
|
||||
info->subformat_mask = sinfo.subformat_mask;
|
||||
info->channels_min = sinfo.channels_min;
|
||||
info->channels_max = sinfo.channels_max;
|
||||
info->fragments_min = sinfo.fragments_min;
|
||||
info->fragments_max = sinfo.fragments_max;
|
||||
|
||||
if (!sinfo.access_mask) {
|
||||
info->access_mask = 0;
|
||||
}
|
||||
if (rate->req_sformat >= 0) {
|
||||
info->req_mask |= SND_PCM_PARAMS_SFMT;
|
||||
info->req.format.sfmt = rate->req_sformat;
|
||||
if (!sinfo.format_mask) {
|
||||
info->format_mask = 0;
|
||||
}
|
||||
if (sinfo.rate_min > sinfo.rate_max) {
|
||||
info->rate_min = UINT_MAX;
|
||||
info->rate_max = 0;
|
||||
}
|
||||
if (sinfo.fragment_size_min > sinfo.fragment_size_max) {
|
||||
info->fragment_size_min = ULONG_MAX;
|
||||
info->fragment_size_max = 0;
|
||||
}
|
||||
info->req_mask |= SND_PCM_PARAMS_RATE;
|
||||
info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
|
||||
SND_PCM_PARAMS_XFER_MODE);
|
||||
info->req.format.rate = rate->req_srate;
|
||||
err = snd_pcm_params_info(rate->plug.slave, info);
|
||||
info->req_mask = req_mask;
|
||||
info->req.format.sfmt = sfmt;
|
||||
info->req.format.rate = crate;
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT)
|
||||
info->formats = 1 << sfmt;
|
||||
else
|
||||
info->formats = SND_PCM_LINEAR_FORMATS;
|
||||
if (!(req_mask & SND_PCM_PARAMS_RATE)) {
|
||||
info->min_rate = 4000;
|
||||
info->max_rate = 192000;
|
||||
return 0;
|
||||
}
|
||||
if (rate->req_srate - info->min_rate < info->max_rate - rate->req_srate)
|
||||
srate = info->min_rate;
|
||||
else
|
||||
srate = info->max_rate;
|
||||
info->min_rate = crate;
|
||||
info->max_rate = crate;
|
||||
if (info->buffer_size)
|
||||
info->buffer_size = muldiv64(info->buffer_size, crate, srate);
|
||||
if (info->min_fragment_size)
|
||||
info->min_fragment_size = muldiv64(info->min_fragment_size, crate, srate);
|
||||
if (info->max_fragment_size)
|
||||
info->max_fragment_size = muldiv64(info->max_fragment_size, crate, srate);
|
||||
if (info->fragment_align)
|
||||
info->fragment_align = muldiv64(info->fragment_align, crate, srate);
|
||||
info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
|
||||
|
||||
fragment_size_min = muldiv_down(sinfo.fragment_size_min, info->rate_min, sinfo.rate_max);
|
||||
fragment_size_max = muldiv_up(sinfo.fragment_size_max, info->rate_max, sinfo.rate_min);
|
||||
if (fragment_size_min > info->fragment_size_min)
|
||||
info->fragment_size_min = fragment_size_min;
|
||||
if (fragment_size_max < info->fragment_size_max)
|
||||
info->fragment_size_max = fragment_size_max;
|
||||
rate->plug.saccess_mask = sinfo.access_mask;
|
||||
info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
snd_pcm_hw_info_complete(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||
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_params_t slave_params;
|
||||
snd_pcm_params_info_t slave_info;
|
||||
int srate, crate;
|
||||
int err;
|
||||
if (!snd_pcm_format_linear(params->format.sfmt)) {
|
||||
params->fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
slave_params = *params;
|
||||
rate->cformat = params->format.sfmt;
|
||||
rate->crate = crate = params->format.rate;
|
||||
rate->cxfer_mode = params->xfer_mode;
|
||||
rate->cmmap_shape = params->mmap_shape;
|
||||
|
||||
memset(&slave_info, 0, sizeof(slave_info));
|
||||
slave_info.req = *params;
|
||||
if (rate->req_sformat >= 0) {
|
||||
slave_info.req.format.sfmt = rate->req_sformat;
|
||||
slave_params.format.sfmt = rate->req_sformat;
|
||||
}
|
||||
slave_info.req.format.rate = rate->req_srate;
|
||||
slave_info.req_mask = ~0;
|
||||
err = snd_pcm_params_info(slave, &slave_info);
|
||||
if (err < 0) {
|
||||
params->fail_mask = slave_info.req.fail_mask;
|
||||
params->fail_reason = slave_info.req.fail_reason;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (rate->req_srate - slave_info.min_rate < slave_info.max_rate - rate->req_srate)
|
||||
srate = slave_info.min_rate;
|
||||
else
|
||||
srate = slave_info.max_rate;
|
||||
|
||||
slave_params.format.rate = srate;
|
||||
slave_params.avail_min = muldiv64(params->avail_min, srate, crate);
|
||||
slave_params.xfer_min = muldiv64(params->xfer_min, srate, crate);
|
||||
slave_params.buffer_size = muldiv64(params->buffer_size, srate, crate);
|
||||
slave_params.frag_size = muldiv64(params->frag_size, srate, crate);
|
||||
slave_params.xfer_align = muldiv64(params->xfer_align, srate, crate);
|
||||
/* FIXME: boundary? */
|
||||
slave_params.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
slave_params.mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
|
||||
err = snd_pcm_params_mmap(slave, &slave_params);
|
||||
params->fail_mask = slave_params.fail_mask;
|
||||
params->fail_reason = slave_params.fail_reason;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_rate_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
||||
{
|
||||
snd_pcm_rate_t *rate = pcm->private;
|
||||
int src_format, dst_format;
|
||||
int src_rate, dst_rate;
|
||||
snd_pcm_hw_info_t sinfo;
|
||||
unsigned int format, access, crate;
|
||||
unsigned int src_format, dst_format;
|
||||
unsigned int src_rate, dst_rate;
|
||||
size_t fragment_size;
|
||||
int mul, div;
|
||||
int err = snd_pcm_setup(rate->plug.slave, setup);
|
||||
int err;
|
||||
crate = params->rate;
|
||||
format = params->format;
|
||||
fragment_size = params->fragment_size;
|
||||
access = params->access;
|
||||
params->rate = rate->srate;
|
||||
if (rate->sformat >= 0)
|
||||
params->format = rate->sformat;
|
||||
if (rate->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
|
||||
else if (rate->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
assert(0);
|
||||
params->fragment_size = muldiv_near(params->fragment_size, params->rate, crate);
|
||||
snd_pcm_hw_params_to_info(params, &sinfo);
|
||||
sinfo.fragment_size_min = 0;
|
||||
sinfo.fragment_size_max = ULONG_MAX;
|
||||
err = snd_pcm_hw_info_rulesv(slave, &sinfo, params,
|
||||
SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_FRAGMENT_SIZE,
|
||||
-1);
|
||||
snd_pcm_hw_info_to_params(&sinfo, params);
|
||||
if (err >= 0)
|
||||
err = snd_pcm_hw_params(slave, params);
|
||||
params->format = format;
|
||||
params->rate = crate;
|
||||
params->access = access;
|
||||
params->fragment_size = fragment_size;
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (rate->req_sformat >= 0)
|
||||
assert(rate->req_sformat == setup->format.sfmt);
|
||||
rate->sformat = setup->format.sfmt;
|
||||
rate->srate = setup->format.rate;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
src_format = rate->cformat;
|
||||
dst_format = rate->sformat;
|
||||
src_rate = rate->crate;
|
||||
dst_rate = rate->srate;
|
||||
src_format = format;
|
||||
dst_format = slave->format;
|
||||
src_rate = crate;
|
||||
dst_rate = slave->rate;
|
||||
} else {
|
||||
src_format = rate->sformat;
|
||||
dst_format = rate->cformat;
|
||||
src_rate = rate->srate;
|
||||
dst_rate = rate->crate;
|
||||
src_format = slave->format;
|
||||
dst_format = format;
|
||||
src_rate = slave->rate;
|
||||
dst_rate = crate;
|
||||
}
|
||||
rate->get_idx = get_index(src_format, SND_PCM_SFMT_S16);
|
||||
rate->put_idx = put_index(SND_PCM_SFMT_S16, dst_format);
|
||||
rate->get_idx = get_index(src_format, SND_PCM_FORMAT_S16);
|
||||
rate->put_idx = put_index(SND_PCM_FORMAT_S16, dst_format);
|
||||
if (src_rate < dst_rate) {
|
||||
rate->func = resample_expand;
|
||||
/* pitch is get_threshold */
|
||||
|
|
@ -389,43 +374,37 @@ static int snd_pcm_rate_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
|||
mul = rate->pitch;
|
||||
div = DIV;
|
||||
}
|
||||
rate->crate = muldiv64(rate->srate, mul, div);
|
||||
if (rate->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
|
||||
setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
|
||||
else
|
||||
setup->xfer_mode = rate->cxfer_mode;
|
||||
if (rate->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
|
||||
setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
setup->mmap_shape = rate->cmmap_shape;
|
||||
setup->format.sfmt = rate->cformat;
|
||||
setup->format.rate = rate->crate;
|
||||
/* FIXME */
|
||||
setup->rate_master = rate->crate;
|
||||
setup->rate_divisor = 1;
|
||||
setup->mmap_bytes = 0;
|
||||
setup->avail_min = muldiv64(setup->avail_min, mul, div);
|
||||
setup->xfer_min = muldiv64(setup->xfer_min, mul, div);
|
||||
|
||||
/* FIXME: the three above are not a lot sensible */
|
||||
setup->buffer_size = muldiv64(setup->buffer_size, mul, div);
|
||||
setup->frag_size = muldiv64(setup->frag_size, mul, div);
|
||||
setup->xfer_align = muldiv64(setup->xfer_align, mul, div);
|
||||
|
||||
/* FIXME */
|
||||
setup->boundary = LONG_MAX - LONG_MAX % setup->buffer_size;
|
||||
|
||||
if (rate->states)
|
||||
free(rate->states);
|
||||
rate->states = malloc(setup->format.channels * sizeof(*rate->states));
|
||||
rate->states = malloc(params->channels * sizeof(*rate->states));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_rate_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
||||
{
|
||||
snd_pcm_rate_t *rate = pcm->private;
|
||||
snd_pcm_t *slave = rate->plug.slave;
|
||||
size_t avail_min, xfer_min, xfer_align;
|
||||
int err;
|
||||
avail_min = params->avail_min;
|
||||
xfer_min = params->xfer_min;
|
||||
xfer_align = params->xfer_align;
|
||||
params->avail_min = muldiv_near(params->avail_min, slave->rate, pcm->rate);
|
||||
params->xfer_min = muldiv_near(params->xfer_min, slave->rate, pcm->rate);
|
||||
params->xfer_align = muldiv_near(params->xfer_align, slave->rate, pcm->rate);
|
||||
err = snd_pcm_sw_params(slave, params);
|
||||
params->avail_min = avail_min;
|
||||
params->xfer_min = xfer_min;
|
||||
params->xfer_align = xfer_align;
|
||||
params->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_rate_init(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_rate_t *rate = pcm->private;
|
||||
unsigned int k;
|
||||
for (k = 0; k < pcm->setup.format.channels; ++k) {
|
||||
for (k = 0; k < pcm->channels; ++k) {
|
||||
rate->states[k].sum = 0;
|
||||
rate->states[k].sample = 0;
|
||||
if (rate->func == resample_expand) {
|
||||
|
|
@ -463,7 +442,7 @@ static ssize_t snd_pcm_rate_write_areas(snd_pcm_t *pcm,
|
|||
src_frames = rate->func(areas, client_offset, src_frames,
|
||||
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
&dst_frames,
|
||||
pcm->setup.format.channels,
|
||||
pcm->channels,
|
||||
rate->get_idx, rate->put_idx,
|
||||
rate->pitch, rate->states);
|
||||
err = snd_pcm_mmap_forward(slave, dst_frames);
|
||||
|
|
@ -509,7 +488,7 @@ static ssize_t snd_pcm_rate_read_areas(snd_pcm_t *pcm,
|
|||
src_frames = rate->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
src_frames,
|
||||
areas, client_offset, &dst_frames,
|
||||
pcm->setup.format.channels,
|
||||
pcm->channels,
|
||||
rate->get_idx, rate->put_idx,
|
||||
rate->pitch, rate->states);
|
||||
err = snd_pcm_mmap_forward(slave, src_frames);
|
||||
|
|
@ -529,27 +508,27 @@ static ssize_t snd_pcm_rate_read_areas(snd_pcm_t *pcm,
|
|||
return err;
|
||||
}
|
||||
|
||||
size_t snd_pcm_rate_client_frames(snd_pcm_t *pcm, size_t frames)
|
||||
ssize_t snd_pcm_rate_client_frames(snd_pcm_t *pcm, ssize_t frames)
|
||||
{
|
||||
snd_pcm_rate_t *rate = pcm->private;
|
||||
/* Round toward zero */
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
return (int64_t)frames * DIV / rate->pitch;
|
||||
return muldiv_down(frames, DIV, rate->pitch);
|
||||
else
|
||||
return (int64_t)frames * rate->pitch / DIV;
|
||||
return muldiv_down(frames, rate->pitch, DIV);
|
||||
}
|
||||
|
||||
static void snd_pcm_rate_dump(snd_pcm_t *pcm, FILE *fp)
|
||||
{
|
||||
snd_pcm_rate_t *rate = pcm->private;
|
||||
if (rate->req_sformat < 0)
|
||||
if (rate->sformat < 0)
|
||||
fprintf(fp, "Rate conversion PCM (%d)\n",
|
||||
rate->req_srate);
|
||||
rate->srate);
|
||||
else
|
||||
fprintf(fp, "Rate conversion PCM (%d, sformat=%s)\n",
|
||||
rate->req_srate,
|
||||
snd_pcm_format_name(rate->req_sformat));
|
||||
if (pcm->valid_setup) {
|
||||
rate->srate,
|
||||
snd_pcm_format_name(rate->sformat));
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "Its setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -560,12 +539,12 @@ 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,
|
||||
params_info: snd_pcm_rate_params_info,
|
||||
params: snd_pcm_rate_params,
|
||||
setup: snd_pcm_rate_setup,
|
||||
hw_info: snd_pcm_rate_hw_info,
|
||||
hw_params: snd_pcm_rate_hw_params,
|
||||
sw_params: snd_pcm_rate_sw_params,
|
||||
dig_info: snd_pcm_plugin_dig_info,
|
||||
dig_params: snd_pcm_plugin_dig_params,
|
||||
channel_info: snd_pcm_plugin_channel_info,
|
||||
channel_params: snd_pcm_plugin_channel_params,
|
||||
channel_setup: snd_pcm_plugin_channel_setup,
|
||||
dump: snd_pcm_rate_dump,
|
||||
nonblock: snd_pcm_plugin_nonblock,
|
||||
async: snd_pcm_plugin_async,
|
||||
|
|
@ -584,8 +563,8 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_
|
|||
if (!rate) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
rate->req_srate = srate;
|
||||
rate->req_sformat = sformat;
|
||||
rate->srate = srate;
|
||||
rate->sformat = sformat;
|
||||
rate->plug.read = snd_pcm_rate_read_areas;
|
||||
rate->plug.write = snd_pcm_rate_write_areas;
|
||||
rate->plug.client_frames = snd_pcm_rate_client_frames;
|
||||
|
|
|
|||
|
|
@ -81,12 +81,8 @@ typedef union {
|
|||
typedef struct {
|
||||
/* This field need to be the first */
|
||||
snd_pcm_plugin_t plug;
|
||||
int req_sformat, req_schannels;
|
||||
int sformat;
|
||||
int cformat;
|
||||
int schannels;
|
||||
int cchannels;
|
||||
int cxfer_mode, cmmap_shape;
|
||||
route_params_t params;
|
||||
} snd_pcm_route_t;
|
||||
|
||||
|
|
@ -429,110 +425,91 @@ static int snd_pcm_route_close(snd_pcm_t *pcm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_route_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
|
||||
static int snd_pcm_route_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
|
||||
{
|
||||
snd_pcm_route_t *route = pcm->private;
|
||||
unsigned int req_mask = info->req_mask;
|
||||
unsigned int sfmt = info->req.format.sfmt;
|
||||
unsigned int channels = info->req.format.channels;
|
||||
unsigned int format_mask, access_mask, channels_min, channels_max;
|
||||
int err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT &&
|
||||
!snd_pcm_format_linear(sfmt)) {
|
||||
info->req.fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
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;
|
||||
if (info->channels_max > 1024)
|
||||
info->channels_max = 1024;
|
||||
if (info->channels_max < info->channels_min)
|
||||
return -EINVAL;
|
||||
channels_min = info->channels_min;
|
||||
channels_max = info->channels_max;
|
||||
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);
|
||||
if (info->format_mask)
|
||||
info->format_mask = format_mask;
|
||||
if (info->channels_min <= info->channels_max) {
|
||||
info->channels_min = channels_min;
|
||||
info->channels_max = channels_max;
|
||||
}
|
||||
if (route->req_sformat >= 0) {
|
||||
info->req_mask |= SND_PCM_PARAMS_SFMT;
|
||||
info->req.format.sfmt = route->req_sformat;
|
||||
if (info->access_mask) {
|
||||
route->plug.saccess_mask = info->access_mask;
|
||||
info->access_mask = access_mask;
|
||||
}
|
||||
if (route->req_schannels >= 0) {
|
||||
info->req_mask |= SND_PCM_PARAMS_CHANNELS;
|
||||
info->req.format.channels = route->req_schannels;
|
||||
}
|
||||
info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
|
||||
SND_PCM_PARAMS_XFER_MODE);
|
||||
err = snd_pcm_params_info(route->plug.slave, info);
|
||||
info->req_mask = req_mask;
|
||||
info->req.format.sfmt = sfmt;
|
||||
info->req.format.channels = channels;
|
||||
if (info->format_mask)
|
||||
info->format_mask = format_mask;
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (req_mask & SND_PCM_PARAMS_SFMT)
|
||||
info->formats = 1 << sfmt;
|
||||
else
|
||||
info->formats = SND_PCM_LINEAR_FORMATS;
|
||||
if (req_mask & SND_PCM_PARAMS_CHANNELS) {
|
||||
info->min_channels = channels;
|
||||
info->max_channels = channels;
|
||||
} else {
|
||||
info->min_channels = 1;
|
||||
info->max_channels = 1024;
|
||||
}
|
||||
info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
|
||||
return err;
|
||||
info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
||||
snd_pcm_hw_info_complete(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||
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 format, access, channels;
|
||||
unsigned int src_format, dst_format;
|
||||
int err;
|
||||
if (!snd_pcm_format_linear(params->format.sfmt)) {
|
||||
params->fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
route->cformat = params->format.sfmt;
|
||||
route->cchannels = params->format.channels;
|
||||
route->cxfer_mode = params->xfer_mode;
|
||||
route->cmmap_shape = params->mmap_shape;
|
||||
if (route->req_sformat >= 0)
|
||||
params->format.sfmt = route->req_sformat;
|
||||
if (route->req_schannels >= 0)
|
||||
params->format.channels = route->req_schannels;
|
||||
params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
|
||||
err = snd_pcm_params_mmap(slave, params);
|
||||
params->format.sfmt = route->cformat;
|
||||
params->format.channels = route->cchannels;
|
||||
params->xfer_mode = route->cxfer_mode;
|
||||
params->mmap_shape = route->cmmap_shape;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_route_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
||||
{
|
||||
snd_pcm_route_t *route = pcm->private;
|
||||
int src_format, dst_format;
|
||||
int err = snd_pcm_setup(route->plug.slave, setup);
|
||||
format = params->format;
|
||||
channels = params->channels;
|
||||
access = params->access;
|
||||
if (route->sformat >= 0)
|
||||
params->format = route->sformat;
|
||||
if (route->schannels >= 0)
|
||||
params->channels = route->schannels;
|
||||
if (route->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
|
||||
else if (route->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
|
||||
params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
assert(0);
|
||||
err = snd_pcm_hw_params(slave, params);
|
||||
params->format = format;
|
||||
params->channels = channels;
|
||||
params->access = access;
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (route->req_sformat >= 0)
|
||||
assert(route->req_sformat == setup->format.sfmt);
|
||||
route->sformat = setup->format.sfmt;
|
||||
route->schannels = setup->format.channels;
|
||||
if (route->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
|
||||
setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
|
||||
else
|
||||
setup->xfer_mode = route->cxfer_mode;
|
||||
if (route->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
|
||||
setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
|
||||
else
|
||||
setup->mmap_shape = route->cmmap_shape;
|
||||
setup->format.sfmt = route->cformat;
|
||||
setup->format.channels = route->cchannels;
|
||||
setup->mmap_bytes = 0;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
src_format = route->cformat;
|
||||
dst_format = route->sformat;
|
||||
src_format = format;
|
||||
dst_format = slave->format;
|
||||
} else {
|
||||
src_format = route->sformat;
|
||||
dst_format = route->cformat;
|
||||
src_format = slave->format;
|
||||
dst_format = format;
|
||||
}
|
||||
route->params.get_idx = get_index(src_format, SND_PCM_SFMT_U16);
|
||||
route->params.put_idx = put_index(SND_PCM_SFMT_U32, dst_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);
|
||||
route->params.conv_idx = conv_index(src_format, dst_format);
|
||||
route->params.src_size = snd_pcm_format_width(src_format) / 8;
|
||||
route->params.dst_sfmt = dst_format;
|
||||
|
|
@ -547,30 +524,6 @@ static int snd_pcm_route_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_route_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
|
||||
{
|
||||
#if 0
|
||||
snd_pcm_plugin_t *plugin = pcm->private;
|
||||
int err;
|
||||
err = snd_pcm_channel_setup(plugin->slave, setup);
|
||||
if (err < 0)
|
||||
return err;
|
||||
#endif
|
||||
if (!pcm->mmap_info)
|
||||
return 0;
|
||||
if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
|
||||
setup->running_area.addr = pcm->mmap_info->addr;
|
||||
setup->running_area.first = setup->channel * pcm->bits_per_sample;
|
||||
setup->running_area.step = pcm->bits_per_frame;
|
||||
} else {
|
||||
setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
|
||||
setup->running_area.first = 0;
|
||||
setup->running_area.step = pcm->bits_per_sample;
|
||||
}
|
||||
setup->stopped_area = setup->running_area;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t snd_pcm_route_write_areas(snd_pcm_t *pcm,
|
||||
snd_pcm_channel_area_t *areas,
|
||||
size_t offset,
|
||||
|
|
@ -588,7 +541,7 @@ static ssize_t snd_pcm_route_write_areas(snd_pcm_t *pcm,
|
|||
size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
|
||||
route_transfer(areas, offset,
|
||||
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
frames, route->schannels, &route->params);
|
||||
frames, slave->channels, &route->params);
|
||||
err = snd_pcm_mmap_forward(slave, frames);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
|
@ -622,7 +575,7 @@ static ssize_t snd_pcm_route_read_areas(snd_pcm_t *pcm,
|
|||
size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
|
||||
route_transfer(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
|
||||
areas, offset,
|
||||
frames, route->cchannels, &route->params);
|
||||
frames, pcm->channels, &route->params);
|
||||
err = snd_pcm_mmap_forward(slave, frames);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
|
@ -643,11 +596,11 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
|
|||
{
|
||||
snd_pcm_route_t *route = pcm->private;
|
||||
unsigned int dst;
|
||||
if (route->req_sformat < 0)
|
||||
if (route->sformat < 0)
|
||||
fprintf(fp, "Route conversion PCM\n");
|
||||
else
|
||||
fprintf(fp, "Route conversion PCM (sformat=%s)\n",
|
||||
snd_pcm_format_name(route->req_sformat));
|
||||
snd_pcm_format_name(route->sformat));
|
||||
fputs("Transformation table:\n", fp);
|
||||
for (dst = 0; dst < route->params.ndsts; dst++) {
|
||||
ttable_dst_t *d = &route->params.dsts[dst];
|
||||
|
|
@ -669,7 +622,7 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
|
|||
}
|
||||
putc('\n', fp);
|
||||
}
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "Its setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -680,12 +633,12 @@ 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,
|
||||
params_info: snd_pcm_route_params_info,
|
||||
params: snd_pcm_route_params,
|
||||
setup: snd_pcm_route_setup,
|
||||
hw_info: snd_pcm_route_hw_info,
|
||||
hw_params: snd_pcm_route_hw_params,
|
||||
sw_params: snd_pcm_plugin_sw_params,
|
||||
dig_info: snd_pcm_plugin_dig_info,
|
||||
dig_params: snd_pcm_plugin_dig_params,
|
||||
channel_info: snd_pcm_plugin_channel_info,
|
||||
channel_params: snd_pcm_plugin_channel_params,
|
||||
channel_setup: snd_pcm_route_channel_setup,
|
||||
dump: snd_pcm_route_dump,
|
||||
nonblock: snd_pcm_plugin_nonblock,
|
||||
async: snd_pcm_plugin_async,
|
||||
|
|
@ -782,8 +735,8 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, char *name,
|
|||
if (!route) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
route->req_sformat = sformat;
|
||||
route->req_schannels = schannels;
|
||||
route->sformat = sformat;
|
||||
route->schannels = schannels;
|
||||
route->plug.read = snd_pcm_route_read_areas;
|
||||
route->plug.write = snd_pcm_route_write_areas;
|
||||
route->plug.slave = slave;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -66,8 +67,8 @@ typedef struct {
|
|||
struct list_head clients;
|
||||
struct list_head list;
|
||||
snd_pcm_t *pcm;
|
||||
int sformat;
|
||||
int srate;
|
||||
int format;
|
||||
int rate;
|
||||
size_t channels_count;
|
||||
size_t open_count;
|
||||
size_t setup_count;
|
||||
|
|
@ -104,7 +105,6 @@ typedef struct {
|
|||
int ready;
|
||||
int client_socket;
|
||||
int slave_socket;
|
||||
void *stopped_data;
|
||||
} snd_pcm_share_t;
|
||||
|
||||
static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state);
|
||||
|
|
@ -115,9 +115,9 @@ static size_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave)
|
|||
snd_pcm_t *pcm = slave->pcm;
|
||||
avail = slave->hw_ptr - *pcm->appl_ptr;
|
||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
avail += pcm->setup.buffer_size;
|
||||
avail += pcm->buffer_size;
|
||||
if (avail < 0)
|
||||
avail += pcm->setup.boundary;
|
||||
avail += pcm->boundary;
|
||||
return avail;
|
||||
}
|
||||
|
||||
|
|
@ -133,8 +133,8 @@ static size_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
|
|||
size_t avail, slave_avail;
|
||||
size_t slave_hw_avail;
|
||||
slave_avail = snd_pcm_share_slave_avail(slave);
|
||||
boundary = slave->pcm->setup.boundary;
|
||||
buffer_size = slave->pcm->setup.buffer_size;
|
||||
boundary = slave->pcm->boundary;
|
||||
buffer_size = slave->pcm->buffer_size;
|
||||
min_frames = slave_avail;
|
||||
max_frames = 0;
|
||||
slave_appl_ptr = *slave->pcm->appl_ptr;
|
||||
|
|
@ -191,7 +191,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
|
|||
snd_pcm_share_t *share = pcm->private;
|
||||
snd_pcm_share_slave_t *slave = share->slave;
|
||||
snd_pcm_t *spcm = slave->pcm;
|
||||
size_t buffer_size = spcm->setup.buffer_size;
|
||||
size_t buffer_size = spcm->buffer_size;
|
||||
int ready = 1, running = 0;
|
||||
size_t avail = 0, slave_avail;
|
||||
ssize_t hw_avail;
|
||||
|
|
@ -208,7 +208,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
|
|||
default:
|
||||
return INT_MAX;
|
||||
}
|
||||
if (slave_xrun && pcm->setup.xrun_mode != SND_PCM_XRUN_NONE) {
|
||||
if (slave_xrun && pcm->xrun_mode != SND_PCM_XRUN_NONE) {
|
||||
_snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
|
||||
goto update_poll;
|
||||
}
|
||||
|
|
@ -251,7 +251,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
|
|||
}
|
||||
break;
|
||||
case SND_PCM_STATE_RUNNING:
|
||||
if (pcm->setup.xrun_mode != SND_PCM_XRUN_NONE) {
|
||||
if (pcm->xrun_mode != SND_PCM_XRUN_NONE) {
|
||||
if (hw_avail <= 0) {
|
||||
_snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
|
||||
break;
|
||||
|
|
@ -300,7 +300,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
|
|||
size_t cont = buffer_size - offset;
|
||||
if (cont < frames)
|
||||
frames = cont;
|
||||
snd_pcm_areas_silence(pcm->running_areas, offset, pcm->setup.format.channels, frames, pcm->setup.format.sfmt);
|
||||
snd_pcm_areas_silence(pcm->running_areas, offset, pcm->channels, frames, pcm->format);
|
||||
offset += frames;
|
||||
if (offset >= buffer_size)
|
||||
offset = 0;
|
||||
|
|
@ -357,17 +357,17 @@ void *snd_pcm_share_slave_thread(void *data)
|
|||
size_t hw_ptr;
|
||||
ssize_t avail_min;
|
||||
hw_ptr = slave->hw_ptr + missing;
|
||||
hw_ptr += spcm->setup.frag_size - 1;
|
||||
if (hw_ptr >= spcm->setup.boundary)
|
||||
hw_ptr -= spcm->setup.boundary;
|
||||
hw_ptr -= hw_ptr % spcm->setup.frag_size;
|
||||
hw_ptr += spcm->fragment_size - 1;
|
||||
if (hw_ptr >= spcm->boundary)
|
||||
hw_ptr -= spcm->boundary;
|
||||
hw_ptr -= hw_ptr % spcm->fragment_size;
|
||||
avail_min = hw_ptr - *spcm->appl_ptr;
|
||||
if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
avail_min += spcm->setup.buffer_size;
|
||||
avail_min += spcm->buffer_size;
|
||||
if (avail_min < 0)
|
||||
avail_min += spcm->setup.boundary;
|
||||
avail_min += spcm->boundary;
|
||||
// printf("avail_min=%d\n", avail_min);
|
||||
if ((size_t)avail_min != spcm->setup.avail_min)
|
||||
if ((size_t)avail_min != spcm->avail_min)
|
||||
snd_pcm_set_avail_min(spcm, avail_min);
|
||||
slave->polling = 1;
|
||||
Pthread_mutex_unlock(&slave->mutex);
|
||||
|
|
@ -403,16 +403,16 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm)
|
|||
size_t hw_ptr;
|
||||
ssize_t avail_min;
|
||||
hw_ptr = slave->hw_ptr + missing;
|
||||
hw_ptr += spcm->setup.frag_size - 1;
|
||||
if (hw_ptr >= spcm->setup.boundary)
|
||||
hw_ptr -= spcm->setup.boundary;
|
||||
hw_ptr -= hw_ptr % spcm->setup.frag_size;
|
||||
hw_ptr += spcm->fragment_size - 1;
|
||||
if (hw_ptr >= spcm->boundary)
|
||||
hw_ptr -= spcm->boundary;
|
||||
hw_ptr -= hw_ptr % spcm->fragment_size;
|
||||
avail_min = hw_ptr - *spcm->appl_ptr;
|
||||
if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
avail_min += spcm->setup.buffer_size;
|
||||
avail_min += spcm->buffer_size;
|
||||
if (avail_min < 0)
|
||||
avail_min += spcm->setup.boundary;
|
||||
if ((size_t)avail_min < spcm->setup.avail_min)
|
||||
avail_min += spcm->boundary;
|
||||
if ((size_t)avail_min < spcm->avail_min)
|
||||
snd_pcm_set_avail_min(spcm, avail_min);
|
||||
}
|
||||
}
|
||||
|
|
@ -442,183 +442,81 @@ 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_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
|
||||
static int snd_pcm_share_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
|
||||
{
|
||||
snd_pcm_share_t *share = pcm->private;
|
||||
snd_pcm_share_slave_t *slave = share->slave;
|
||||
unsigned int access_mask;
|
||||
int err = 0;
|
||||
unsigned int req_mask = info->req_mask;
|
||||
unsigned int channels = info->req.format.channels;
|
||||
if ((req_mask & SND_PCM_PARAMS_CHANNELS) &&
|
||||
channels != share->channels_count) {
|
||||
info->req.fail_mask |= SND_PCM_PARAMS_CHANNELS;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
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 (slave->sformat >= 0) {
|
||||
if ((req_mask & SND_PCM_PARAMS_SFMT) &&
|
||||
info->req.format.sfmt != slave->sformat) {
|
||||
info->req.fail_mask |= SND_PCM_PARAMS_SFMT;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
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_max > info->channels_max)
|
||||
return -EINVAL;
|
||||
if (slave->format >= 0) {
|
||||
info->format_mask &= 1U << slave->format;
|
||||
if (!info->format_mask)
|
||||
return -EINVAL;
|
||||
}
|
||||
info->req.format.sfmt = slave->sformat;
|
||||
info->req_mask |= SND_PCM_PARAMS_SFMT;
|
||||
}
|
||||
if (slave->srate >= 0) {
|
||||
info->req.format.rate = slave->srate;
|
||||
info->req_mask |= SND_PCM_PARAMS_RATE;
|
||||
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_max > info->rate_max)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info->req_mask |= SND_PCM_PARAMS_CHANNELS;
|
||||
info->req.format.channels = slave->channels_count;
|
||||
err = snd_pcm_params_info(slave->pcm, info);
|
||||
info->req.format.channels = channels;
|
||||
info->req_mask = req_mask;
|
||||
Pthread_mutex_lock(&slave->mutex);
|
||||
if (slave->setup_count > 1 ||
|
||||
(slave->setup_count == 1 && !pcm->valid_setup)) {
|
||||
snd_pcm_setup_t *s = &slave->pcm->setup;
|
||||
if ((req_mask & SND_PCM_PARAMS_SFMT) &&
|
||||
info->req.format.sfmt != s->format.sfmt) {
|
||||
info->req.fail_mask |= SND_PCM_PARAMS_SFMT;
|
||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
err = -EINVAL;
|
||||
goto _end;
|
||||
}
|
||||
info->formats = 1 << s->format.sfmt;
|
||||
info->rates = SND_PCM_RATE_CONTINUOUS;
|
||||
info->min_rate = info->max_rate = s->format.rate;
|
||||
info->buffer_size = s->buffer_size;
|
||||
info->min_fragment_size = info->max_fragment_size = s->frag_size;
|
||||
info->min_fragments = info->max_fragments = s->frags;
|
||||
info->fragment_align = s->frag_size;
|
||||
info->req.fail_mask = 0;
|
||||
}
|
||||
|
||||
info->min_channels = info->max_channels = share->channels_count;
|
||||
if (info->flags & SND_PCM_INFO_INTERLEAVED) {
|
||||
info->flags &= ~SND_PCM_INFO_INTERLEAVED;
|
||||
info->flags |= SND_PCM_INFO_COMPLEX;
|
||||
}
|
||||
_end:
|
||||
Pthread_mutex_unlock(&slave->mutex);
|
||||
info->access_mask = SND_PCM_ACCBIT_MMAP;
|
||||
info->channels_min = info->channels_max = slave->channels_count;
|
||||
err = snd_pcm_hw_info(slave->pcm, info);
|
||||
if (info->channels_min <= info->channels_max)
|
||||
info->channels_min = info->channels_max = share->channels_count;
|
||||
if (info->access_mask)
|
||||
info->access_mask = access_mask;
|
||||
info->info |= SND_PCM_INFO_DOUBLE;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_mmap(snd_pcm_t *pcm)
|
||||
static int snd_pcm_share_hw_params(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;
|
||||
snd_pcm_mmap_info_t *i;
|
||||
size_t count;
|
||||
snd_pcm_t *spcm = slave->pcm;
|
||||
int err = 0;
|
||||
Pthread_mutex_lock(&slave->mutex);
|
||||
if (slave->mmap_count == 0) {
|
||||
err = snd_pcm_mmap(slave->pcm);
|
||||
if (err < 0)
|
||||
goto _end;
|
||||
if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt);
|
||||
}
|
||||
slave->mmap_count++;
|
||||
count = slave->pcm->mmap_info_count;
|
||||
i = malloc((count + 1) * sizeof(*i));
|
||||
if (!i) {
|
||||
err = -ENOMEM;
|
||||
goto _end;
|
||||
}
|
||||
err = snd_pcm_alloc_user_mmap(pcm, i);
|
||||
if (err < 0) {
|
||||
free(i);
|
||||
return err;
|
||||
}
|
||||
share->stopped_data = i->addr;
|
||||
memcpy(i + 1, slave->pcm->mmap_info, count * sizeof(*pcm->mmap_info));
|
||||
pcm->mmap_info_count = count + 1;
|
||||
pcm->mmap_info = i;
|
||||
_end:
|
||||
Pthread_mutex_unlock(&slave->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||
{
|
||||
snd_pcm_share_t *share = pcm->private;
|
||||
snd_pcm_share_slave_t *slave = share->slave;
|
||||
snd_pcm_mmap_info_t *i = pcm->mmap_info;
|
||||
int err = 0;
|
||||
Pthread_mutex_lock(&slave->mutex);
|
||||
slave->mmap_count--;
|
||||
if (slave->mmap_count == 0) {
|
||||
err = snd_pcm_munmap(slave->pcm);
|
||||
if (err < 0)
|
||||
goto _end;
|
||||
}
|
||||
err = snd_pcm_free_mmap(pcm, i);
|
||||
if (err < 0)
|
||||
goto _end;
|
||||
free(i);
|
||||
pcm->mmap_info_count = 0;
|
||||
pcm->mmap_info = 0;
|
||||
_end:
|
||||
Pthread_mutex_unlock(&slave->mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
||||
{
|
||||
snd_pcm_share_t *share = pcm->private;
|
||||
snd_pcm_share_slave_t *slave = share->slave;
|
||||
unsigned int channels = params->format.channels;
|
||||
int err = 0;
|
||||
if (channels != share->channels_count) {
|
||||
params->fail_mask = SND_PCM_PARAMS_CHANNELS;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
ERR("channels requested (%d) differs from configuration (%ld)", channels, (long)share->channels_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
share->xfer_mode = params->xfer_mode;
|
||||
share->xrun_mode = params->xrun_mode;
|
||||
share->avail_min = params->avail_min;
|
||||
Pthread_mutex_lock(&slave->mutex);
|
||||
if (slave->setup_count > 1 ||
|
||||
(slave->setup_count == 1 && !pcm->valid_setup)) {
|
||||
snd_pcm_setup_t *s = &slave->pcm->setup;
|
||||
if (params->format.sfmt != s->format.sfmt) {
|
||||
ERR("slave is already running with different format");
|
||||
params->fail_mask |= SND_PCM_PARAMS_SFMT;
|
||||
}
|
||||
if (params->fail_mask) {
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
err = -EINVAL;
|
||||
goto _end;
|
||||
(slave->setup_count == 1 && !pcm->setup)) {
|
||||
if (params->access != spcm->access ||
|
||||
params->format != spcm->format ||
|
||||
params->subformat != spcm->subformat ||
|
||||
params->rate != spcm->rate ||
|
||||
params->fragments != spcm->fragments ||
|
||||
params->fragment_size != spcm->fragment_size) {
|
||||
ERR("slave is already running with different setup");
|
||||
params->fail_mask |= SND_PCM_HW_PARBIT_FORMAT;
|
||||
return -EBUSY;
|
||||
}
|
||||
} else {
|
||||
snd_pcm_params_t sp = *params;
|
||||
snd_pcm_setup_t *ss;
|
||||
if (slave->sformat >= 0 &&
|
||||
params->format.sfmt != slave->sformat) {
|
||||
params->fail_mask = SND_PCM_PARAMS_SFMT;
|
||||
params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||
ERR("format requested (%d) differs from configuration (%d)", params->format.sfmt, slave->sformat);
|
||||
err = -EINVAL;
|
||||
goto _end;
|
||||
}
|
||||
if (slave->srate >= 0)
|
||||
sp.format.rate = slave->srate;
|
||||
sp.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
|
||||
sp.xrun_mode = SND_PCM_XRUN_NONE;
|
||||
sp.format.channels = slave->channels_count;
|
||||
err = snd_pcm_params_mmap(slave->pcm, &sp);
|
||||
snd_pcm_hw_params_t sparams = *params;
|
||||
sparams.channels = slave->channels_count;
|
||||
err = snd_pcm_hw_params(slave->pcm, &sparams);
|
||||
if (err < 0)
|
||||
goto _end;
|
||||
ss = &slave->pcm->setup;
|
||||
/* >= 30 ms */
|
||||
slave->safety_threshold = ss->format.rate * 30 / 1000;
|
||||
slave->safety_threshold += ss->frag_size - 1;
|
||||
slave->safety_threshold -= slave->safety_threshold % ss->frag_size;
|
||||
slave->safety_threshold = sparams.rate * 30 / 1000;
|
||||
slave->safety_threshold += sparams.fragment_size - 1;
|
||||
slave->safety_threshold -= slave->safety_threshold % sparams.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);
|
||||
}
|
||||
share->state = SND_PCM_STATE_SETUP;
|
||||
slave->setup_count++;
|
||||
|
|
@ -627,26 +525,45 @@ static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
|
||||
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;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (params->ready_mode > SND_PCM_READY_LAST) {
|
||||
params->fail_mask = SND_PCM_SW_PARBIT_READY_MODE;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (params->xrun_mode > SND_PCM_XRUN_LAST) {
|
||||
params->fail_mask = SND_PCM_SW_PARBIT_XRUN_MODE;
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info)
|
||||
{
|
||||
snd_pcm_share_t *share = pcm->private;
|
||||
snd_pcm_share_slave_t *slave = share->slave;
|
||||
int err;
|
||||
err = snd_pcm_setup(slave->pcm, setup);
|
||||
if (err < 0)
|
||||
return err;
|
||||
setup->xrun_mode = share->xrun_mode;
|
||||
setup->format.channels = share->channels_count;
|
||||
if (share->avail_min > setup->buffer_size)
|
||||
share->avail_min = setup->buffer_size;
|
||||
setup->avail_min = share->avail_min;
|
||||
if (share->xfer_mode == SND_PCM_XFER_UNSPECIFIED)
|
||||
setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
|
||||
else
|
||||
setup->xfer_mode = share->xfer_mode;
|
||||
if (setup->mmap_shape != SND_PCM_MMAP_INTERLEAVED)
|
||||
setup->mmap_shape = SND_PCM_MMAP_COMPLEX;
|
||||
return 0;
|
||||
/* FIXME */
|
||||
Pthread_mutex_lock(&slave->mutex);
|
||||
err = snd_pcm_dig_info(slave->pcm, info);
|
||||
Pthread_mutex_unlock(&slave->mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params)
|
||||
{
|
||||
snd_pcm_share_t *share = pcm->private;
|
||||
snd_pcm_share_slave_t *slave = share->slave;
|
||||
int err;
|
||||
/* FIXME */
|
||||
Pthread_mutex_lock(&slave->mutex);
|
||||
err = snd_pcm_dig_params(slave->pcm, params);
|
||||
Pthread_mutex_unlock(&slave->mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
|
||||
|
|
@ -661,7 +578,7 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
|
|||
if (share->state != SND_PCM_STATE_RUNNING &&
|
||||
share->state != SND_PCM_STATE_DRAINING)
|
||||
goto _notrunning;
|
||||
d = pcm->setup.buffer_size - status->avail;
|
||||
d = pcm->buffer_size - status->avail;
|
||||
} else {
|
||||
status->avail = snd_pcm_mmap_capture_avail(pcm);
|
||||
if (share->state != SND_PCM_STATE_RUNNING)
|
||||
|
|
@ -738,7 +655,7 @@ static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
|
|||
}
|
||||
Pthread_mutex_unlock(&slave->mutex);
|
||||
avail = snd_pcm_mmap_avail(pcm);
|
||||
if ((size_t)avail > pcm->setup.buffer_size)
|
||||
if ((size_t)avail > pcm->buffer_size)
|
||||
return -EPIPE;
|
||||
return avail;
|
||||
}
|
||||
|
|
@ -753,10 +670,10 @@ static ssize_t _snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
|
|||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
|
||||
share->state == SND_PCM_STATE_RUNNING) {
|
||||
frames = *slave->pcm->appl_ptr - share->appl_ptr;
|
||||
if (frames > (ssize_t)pcm->setup.buffer_size)
|
||||
frames -= pcm->setup.boundary;
|
||||
else if (frames < -(ssize_t)pcm->setup.buffer_size)
|
||||
frames += pcm->setup.boundary;
|
||||
if (frames > (ssize_t)pcm->buffer_size)
|
||||
frames -= pcm->boundary;
|
||||
else if (frames < -(ssize_t)pcm->buffer_size)
|
||||
frames += pcm->boundary;
|
||||
if (frames > 0) {
|
||||
/* Latecomer PCM */
|
||||
ret = snd_pcm_rewind(slave->pcm, frames);
|
||||
|
|
@ -839,13 +756,13 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
|
|||
while (xfer < hw_avail) {
|
||||
size_t frames = hw_avail - xfer;
|
||||
size_t offset = snd_pcm_mmap_offset(pcm);
|
||||
size_t cont = pcm->setup.buffer_size - offset;
|
||||
size_t cont = pcm->buffer_size - offset;
|
||||
if (cont < frames)
|
||||
frames = cont;
|
||||
snd_pcm_areas_copy(pcm->stopped_areas, xfer,
|
||||
pcm->running_areas, offset,
|
||||
pcm->setup.format.channels, frames,
|
||||
pcm->setup.format.sfmt);
|
||||
pcm->channels, frames,
|
||||
pcm->format);
|
||||
xfer += frames;
|
||||
}
|
||||
snd_pcm_mmap_appl_forward(pcm, hw_avail);
|
||||
|
|
@ -883,51 +800,6 @@ static int snd_pcm_share_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *in
|
|||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
|
||||
{
|
||||
snd_pcm_share_t *share = pcm->private;
|
||||
snd_pcm_share_slave_t *slave = share->slave;
|
||||
unsigned int channel = params->channel;
|
||||
int c = share->slave_channels[channel];
|
||||
int err;
|
||||
params->channel = c;
|
||||
err = snd_pcm_channel_params(slave->pcm, params);
|
||||
params->channel = channel;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
|
||||
{
|
||||
snd_pcm_share_t *share = pcm->private;
|
||||
snd_pcm_share_slave_t *slave = share->slave;
|
||||
unsigned int channel = setup->channel;
|
||||
int c = share->slave_channels[channel];
|
||||
int err;
|
||||
setup->channel = c;
|
||||
err = snd_pcm_channel_setup(slave->pcm, setup);
|
||||
setup->channel = channel;
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!pcm->mmap_info)
|
||||
return 0;
|
||||
switch (pcm->setup.mmap_shape) {
|
||||
case SND_PCM_MMAP_INTERLEAVED:
|
||||
case SND_PCM_MMAP_COMPLEX:
|
||||
setup->stopped_area.addr = share->stopped_data;
|
||||
setup->stopped_area.first = channel * pcm->bits_per_sample;
|
||||
setup->stopped_area.step = pcm->bits_per_frame;
|
||||
break;
|
||||
case SND_PCM_MMAP_NONINTERLEAVED:
|
||||
setup->stopped_area.addr = share->stopped_data + c * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
|
||||
setup->stopped_area.first = 0;
|
||||
setup->stopped_area.step = pcm->bits_per_sample;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t _snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
|
||||
{
|
||||
snd_pcm_share_t *share = pcm->private;
|
||||
|
|
@ -984,7 +856,7 @@ static int snd_pcm_share_set_avail_min(snd_pcm_t *pcm, size_t frames)
|
|||
snd_pcm_share_t *share = pcm->private;
|
||||
snd_pcm_share_slave_t *slave = share->slave;
|
||||
Pthread_mutex_lock(&slave->mutex);
|
||||
pcm->setup.avail_min = frames;
|
||||
pcm->avail_min = frames;
|
||||
share->avail_min = frames;
|
||||
_snd_pcm_share_update(pcm);
|
||||
Pthread_mutex_unlock(&slave->mutex);
|
||||
|
|
@ -996,7 +868,7 @@ static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state)
|
|||
{
|
||||
snd_pcm_share_t *share = pcm->private;
|
||||
snd_pcm_share_slave_t *slave = share->slave;
|
||||
if (!pcm->mmap_info) {
|
||||
if (!pcm->mmap_channels) {
|
||||
/* PCM closing already begun in the main thread */
|
||||
return;
|
||||
}
|
||||
|
|
@ -1004,13 +876,13 @@ static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state)
|
|||
if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
|
||||
snd_pcm_areas_copy(pcm->running_areas, 0,
|
||||
pcm->stopped_areas, 0,
|
||||
pcm->setup.format.channels, pcm->setup.buffer_size,
|
||||
pcm->setup.format.sfmt);
|
||||
pcm->channels, pcm->buffer_size,
|
||||
pcm->format);
|
||||
} else if (slave->running_count > 1) {
|
||||
int err;
|
||||
ssize_t delay;
|
||||
snd_pcm_areas_silence(pcm->running_areas, 0, pcm->setup.format.channels,
|
||||
pcm->setup.buffer_size, pcm->setup.format.sfmt);
|
||||
snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels,
|
||||
pcm->buffer_size, pcm->format);
|
||||
err = snd_pcm_delay(slave->pcm, &delay);
|
||||
if (err >= 0 && delay > 0)
|
||||
snd_pcm_rewind(slave->pcm, delay);
|
||||
|
|
@ -1116,7 +988,7 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
|
|||
int err = 0;
|
||||
Pthread_mutex_lock(&slaves_mutex);
|
||||
Pthread_mutex_lock(&slave->mutex);
|
||||
if (pcm->valid_setup)
|
||||
if (pcm->setup)
|
||||
slave->setup_count--;
|
||||
slave->open_count--;
|
||||
if (slave->open_count == 0) {
|
||||
|
|
@ -1142,6 +1014,16 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
|
||||
{
|
||||
snd_pcm_share_t *share = pcm->private;
|
||||
|
|
@ -1151,7 +1033,7 @@ static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
|
|||
fprintf(fp, "\nChannel bindings:\n");
|
||||
for (k = 0; k < share->channels_count; ++k)
|
||||
fprintf(fp, "%d: %d\n", k, share->slave_channels[k]);
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "\nIts setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -1162,12 +1044,12 @@ 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,
|
||||
params_info: snd_pcm_share_params_info,
|
||||
params: snd_pcm_share_params,
|
||||
setup: snd_pcm_share_setup,
|
||||
hw_info: snd_pcm_share_hw_info,
|
||||
hw_params: snd_pcm_share_hw_params,
|
||||
sw_params: snd_pcm_share_sw_params,
|
||||
dig_info: snd_pcm_share_dig_info,
|
||||
dig_params: snd_pcm_share_dig_params,
|
||||
channel_info: snd_pcm_share_channel_info,
|
||||
channel_params: snd_pcm_share_channel_params,
|
||||
channel_setup: snd_pcm_share_channel_setup,
|
||||
dump: snd_pcm_share_dump,
|
||||
nonblock: snd_pcm_share_nonblock,
|
||||
async: snd_pcm_share_async,
|
||||
|
|
@ -1311,8 +1193,8 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname,
|
|||
INIT_LIST_HEAD(&slave->clients);
|
||||
slave->pcm = spcm;
|
||||
slave->channels_count = schannels_count;
|
||||
slave->sformat = sformat;
|
||||
slave->srate = srate;
|
||||
slave->format = sformat;
|
||||
slave->rate = srate;
|
||||
pthread_mutex_init(&slave->mutex, NULL);
|
||||
pthread_cond_init(&slave->poll_cond, NULL);
|
||||
list_add_tail(&slave->list, &slaves);
|
||||
|
|
@ -1353,7 +1235,7 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname,
|
|||
pcm->type = SND_PCM_TYPE_SHARE;
|
||||
pcm->stream = stream;
|
||||
pcm->mode = mode;
|
||||
pcm->mmap_auto = 1;
|
||||
pcm->mmap_rw = 1;
|
||||
pcm->ops = &snd_pcm_share_ops;
|
||||
pcm->op_arg = pcm;
|
||||
pcm->fast_ops = &snd_pcm_share_fast_ops;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -40,8 +41,8 @@
|
|||
|
||||
typedef struct {
|
||||
int socket;
|
||||
unsigned int access_mask;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl;
|
||||
snd_pcm_mmap_info_t *slave_mmap_info;
|
||||
} snd_pcm_shm_t;
|
||||
|
||||
int receive_fd(int socket, void *data, size_t len, int *fd)
|
||||
|
|
@ -147,108 +148,147 @@ static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
|
||||
static int snd_pcm_shm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
|
||||
{
|
||||
snd_pcm_shm_t *shm = pcm->private;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
||||
int err;
|
||||
ctrl->cmd = SND_PCM_IOCTL_PARAMS_INFO;
|
||||
ctrl->u.params_info = *info;
|
||||
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);
|
||||
*info = ctrl->u.hw_info;
|
||||
if (info->access_mask) {
|
||||
shm->access_mask = info->access_mask;
|
||||
info->access_mask |= (SND_PCM_ACCESS_RW_INTERLEAVED |
|
||||
SND_PCM_ACCESS_RW_NONINTERLEAVED);
|
||||
info->access_mask &= access_mask;
|
||||
}
|
||||
if (err < 0)
|
||||
return err;
|
||||
*info = ctrl->u.params_info;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||
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_PARAMS;
|
||||
ctrl->u.params = *params;
|
||||
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;
|
||||
*params = ctrl->u.params;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
|
||||
static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
||||
{
|
||||
snd_pcm_shm_t *shm = pcm->private;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
||||
int err;
|
||||
ctrl->cmd = SND_PCM_IOCTL_SETUP;
|
||||
// ctrl->u.setup = *setup;
|
||||
ctrl->cmd = SND_PCM_IOCTL_SW_PARAMS;
|
||||
ctrl->u.sw_params = *params;
|
||||
err = snd_pcm_shm_action(pcm);
|
||||
*params = ctrl->u.sw_params;
|
||||
if (err < 0)
|
||||
return err;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
|
||||
{
|
||||
snd_pcm_shm_t *shm = pcm->private;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
||||
int err;
|
||||
ctrl->cmd = SND_PCM_IOCTL_DIG_INFO;
|
||||
ctrl->u.dig_info = *info;
|
||||
err = snd_pcm_shm_action(pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
*setup = ctrl->u.setup;
|
||||
*info = ctrl->u.dig_info;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
|
||||
{
|
||||
snd_pcm_shm_t *shm = pcm->private;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
||||
int err;
|
||||
ctrl->cmd = SND_PCM_IOCTL_DIG_PARAMS;
|
||||
ctrl->u.dig_params = *params;
|
||||
err = snd_pcm_shm_action(pcm);
|
||||
*params = ctrl->u.dig_params;
|
||||
if (err < 0)
|
||||
return err;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_munmap(snd_pcm_t *pcm)
|
||||
{
|
||||
unsigned int c;
|
||||
for (c = 0; c < pcm->channels; ++c) {
|
||||
snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
|
||||
unsigned int c1;
|
||||
int err;
|
||||
if (i->type != SND_PCM_AREA_MMAP)
|
||||
continue;
|
||||
if (i->u.mmap.fd < 0)
|
||||
continue;
|
||||
for (c1 = c + 1; c1 < pcm->channels; ++c1) {
|
||||
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
|
||||
if (i1->type != SND_PCM_AREA_MMAP)
|
||||
continue;
|
||||
if (i1->u.mmap.fd != i->u.mmap.fd)
|
||||
continue;
|
||||
i1->u.mmap.fd = -1;
|
||||
}
|
||||
err = close(i->u.mmap.fd);
|
||||
if (err < 0) {
|
||||
SYSERR("close failed");
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
|
||||
{
|
||||
snd_pcm_shm_t *shm = pcm->private;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
||||
int err;
|
||||
int fd;
|
||||
ctrl->cmd = SND_PCM_IOCTL_CHANNEL_INFO;
|
||||
ctrl->u.channel_info = *info;
|
||||
err = snd_pcm_shm_action(pcm);
|
||||
err = snd_pcm_shm_action_fd(pcm, &fd);
|
||||
if (err < 0)
|
||||
return err;
|
||||
*info = ctrl->u.channel_info;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
|
||||
{
|
||||
snd_pcm_shm_t *shm = pcm->private;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
||||
int err;
|
||||
ctrl->cmd = SND_PCM_IOCTL_CHANNEL_PARAMS;
|
||||
ctrl->u.channel_params = *params;
|
||||
err = snd_pcm_shm_action(pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
*params = ctrl->u.channel_params;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void *convert_addr(void *addr, size_t count, snd_pcm_mmap_info_t *old, snd_pcm_mmap_info_t *new)
|
||||
{
|
||||
size_t k;
|
||||
size_t mindist = ULONG_MAX;
|
||||
int idx = -1;
|
||||
for (k = 0; k < count; ++k) {
|
||||
if (addr >= old[k].addr) {
|
||||
size_t dist = addr - old[k].addr;
|
||||
if (dist < mindist) {
|
||||
mindist = dist;
|
||||
idx = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(idx >= 0);
|
||||
return new[idx].addr + mindist;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
|
||||
{
|
||||
snd_pcm_shm_t *shm = pcm->private;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
||||
int err;
|
||||
ctrl->cmd = SND_PCM_IOCTL_CHANNEL_SETUP;
|
||||
ctrl->u.channel_setup = *setup;
|
||||
err = snd_pcm_shm_action(pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
*setup = ctrl->u.channel_setup;
|
||||
if (pcm->mmap_info) {
|
||||
setup->running_area.addr = convert_addr(setup->running_area.addr, pcm->mmap_info_count, shm->slave_mmap_info, pcm->mmap_info);
|
||||
setup->stopped_area.addr = convert_addr(setup->stopped_area.addr, pcm->mmap_info_count, shm->slave_mmap_info, pcm->mmap_info);
|
||||
info->addr = 0;
|
||||
switch (info->type) {
|
||||
case SND_PCM_AREA_MMAP:
|
||||
info->u.mmap.fd = fd;
|
||||
break;
|
||||
case SND_PCM_AREA_SHM:
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
@ -356,86 +396,6 @@ static ssize_t snd_pcm_shm_rewind(snd_pcm_t *pcm, size_t frames)
|
|||
return snd_pcm_shm_action(pcm);
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_mmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_shm_t *shm = pcm->private;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
||||
int count, k, err, fd;
|
||||
ctrl->cmd = SND_PCM_IOCTL_MMAP;
|
||||
count = snd_pcm_shm_action(pcm);
|
||||
if (count < 0)
|
||||
return count;
|
||||
pcm->mmap_info_count = count;
|
||||
pcm->mmap_info = malloc(count * sizeof(*pcm->mmap_info));
|
||||
shm->slave_mmap_info = malloc(count * sizeof(*shm->slave_mmap_info));
|
||||
for (k = 0; k < count; ++k) {
|
||||
snd_pcm_mmap_info_t *i = &pcm->mmap_info[k];
|
||||
void *ptr;
|
||||
ctrl->cmd = SND_PCM_IOCTL_MMAP_INFO;
|
||||
ctrl->u.mmap_info.index = k;
|
||||
err = snd_pcm_shm_action_fd(pcm, &fd);
|
||||
if (err < 0)
|
||||
return err;
|
||||
shm->slave_mmap_info[k] = ctrl->u.mmap_info;
|
||||
*i = ctrl->u.mmap_info;
|
||||
if (i->type == SND_PCM_MMAP_KERNEL) {
|
||||
i->u.kernel.fd = fd;
|
||||
ptr = mmap(NULL, i->size, PROT_WRITE | PROT_READ,
|
||||
MAP_FILE | MAP_SHARED,
|
||||
fd, SND_PCM_MMAP_OFFSET_DATA);
|
||||
close(fd);
|
||||
if (ptr == MAP_FAILED || ptr == NULL) {
|
||||
SYSERR("mmap failed");
|
||||
free(pcm->mmap_info);
|
||||
return -errno;
|
||||
}
|
||||
} else {
|
||||
ptr = shmat(i->u.user.shmid, 0, 0);
|
||||
if (ptr == (void*)-1) {
|
||||
SYSERR("shmat failed");
|
||||
free(pcm->mmap_info);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
i->addr = ptr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_shm_munmap(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_shm_t *shm = pcm->private;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
||||
int err;
|
||||
unsigned int k;
|
||||
ctrl->cmd = SND_PCM_IOCTL_MUNMAP;
|
||||
err = snd_pcm_shm_action(pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
for (k = 0; k < pcm->mmap_info_count; ++k) {
|
||||
snd_pcm_mmap_info_t *i = &pcm->mmap_info[k];
|
||||
if (i->type == SND_PCM_MMAP_KERNEL) {
|
||||
err = munmap(i->addr, i->size);
|
||||
if (err < 0) {
|
||||
SYSERR("munmap failed");
|
||||
return -errno;
|
||||
}
|
||||
} else {
|
||||
err = shmdt(i->addr);
|
||||
if (err < 0) {
|
||||
SYSERR("shmdt failed");
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
pcm->mmap_info_count = 0;
|
||||
free(pcm->mmap_info);
|
||||
free(shm->slave_mmap_info);
|
||||
pcm->mmap_info = 0;
|
||||
shm->slave_mmap_info = 0;
|
||||
return ctrl->result;
|
||||
}
|
||||
|
||||
static ssize_t snd_pcm_shm_mmap_forward(snd_pcm_t *pcm, size_t size)
|
||||
{
|
||||
snd_pcm_shm_t *shm = pcm->private;
|
||||
|
|
@ -483,7 +443,7 @@ static int snd_pcm_shm_close(snd_pcm_t *pcm)
|
|||
static void snd_pcm_shm_dump(snd_pcm_t *pcm, FILE *fp)
|
||||
{
|
||||
fprintf(fp, "Shm PCM\n");
|
||||
if (pcm->valid_setup) {
|
||||
if (pcm->setup) {
|
||||
fprintf(fp, "\nIts setup is:\n");
|
||||
snd_pcm_dump_setup(pcm, fp);
|
||||
}
|
||||
|
|
@ -492,12 +452,12 @@ 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,
|
||||
params_info: snd_pcm_shm_params_info,
|
||||
params: snd_pcm_shm_params,
|
||||
setup: snd_pcm_shm_setup,
|
||||
hw_info: snd_pcm_shm_hw_info,
|
||||
hw_params: snd_pcm_shm_hw_params,
|
||||
sw_params: snd_pcm_shm_sw_params,
|
||||
dig_info: snd_pcm_shm_dig_info,
|
||||
dig_params: snd_pcm_shm_dig_params,
|
||||
channel_info: snd_pcm_shm_channel_info,
|
||||
channel_params: snd_pcm_shm_channel_params,
|
||||
channel_setup: snd_pcm_shm_channel_setup,
|
||||
dump: snd_pcm_shm_dump,
|
||||
nonblock: snd_pcm_shm_nonblock,
|
||||
async: snd_pcm_shm_async,
|
||||
|
|
@ -656,7 +616,7 @@ int snd_pcm_shm_open(snd_pcm_t **pcmp, char *name, char *socket, char *sname, in
|
|||
pcm->type = SND_PCM_TYPE_SHM;
|
||||
pcm->stream = stream;
|
||||
pcm->mode = mode;
|
||||
pcm->mmap_auto = 1;
|
||||
pcm->mmap_rw = 1;
|
||||
pcm->ops = &snd_pcm_shm_ops;
|
||||
pcm->op_arg = pcm;
|
||||
pcm->fast_ops = &snd_pcm_shm_fast_ops;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue