mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-05 13:30:00 -05:00
More complete code
This commit is contained in:
parent
2879321023
commit
13fb68344e
1 changed files with 157 additions and 30 deletions
|
|
@ -31,6 +31,7 @@
|
||||||
#include <byteswap.h>
|
#include <byteswap.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <sys/shm.h>
|
#include <sys/shm.h>
|
||||||
|
#include "../control/control_local.h"
|
||||||
#include "pcm_local.h"
|
#include "pcm_local.h"
|
||||||
#include "pcm_plugin.h"
|
#include "pcm_plugin.h"
|
||||||
|
|
||||||
|
|
@ -40,16 +41,15 @@ typedef struct {
|
||||||
unsigned int channels; /* count of channels (4 or 6) */
|
unsigned int channels; /* count of channels (4 or 6) */
|
||||||
int pcms; /* count of PCM channels */
|
int pcms; /* count of PCM channels */
|
||||||
snd_pcm_t *pcm[3]; /* up to three PCM stereo streams */
|
snd_pcm_t *pcm[3]; /* up to three PCM stereo streams */
|
||||||
|
int linked[3]; /* streams are linked */
|
||||||
} snd_pcm_surround_t;
|
} snd_pcm_surround_t;
|
||||||
|
|
||||||
|
static int snd_pcm_surround_free(snd_pcm_surround_t *surr);
|
||||||
|
|
||||||
static int snd_pcm_surround_close(snd_pcm_t *pcm)
|
static int snd_pcm_surround_close(snd_pcm_t *pcm)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
snd_pcm_surround_t *surr = pcm->private_data;
|
snd_pcm_surround_t *surr = pcm->private_data;
|
||||||
for (i = 0; i < surr->pcms; i++)
|
return snd_pcm_surround_free(surr);
|
||||||
snd_pcm_close(surr->pcm[i]);
|
|
||||||
free(surr);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_surround_nonblock(snd_pcm_t *pcm, int nonblock)
|
static int snd_pcm_surround_nonblock(snd_pcm_t *pcm, int nonblock)
|
||||||
|
|
@ -86,12 +86,21 @@ static int snd_pcm_surround_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
|
||||||
static int snd_pcm_surround_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
|
static int snd_pcm_surround_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
|
||||||
{
|
{
|
||||||
snd_pcm_surround_t *surr = pcm->private_data;
|
snd_pcm_surround_t *surr = pcm->private_data;
|
||||||
|
int err;
|
||||||
if (surr->pcms == 1 || info->channel == 0 || info->channel == 1)
|
if (surr->pcms == 1 || info->channel == 0 || info->channel == 1)
|
||||||
return snd_pcm_channel_info(surr->pcm[0], info);
|
return snd_pcm_channel_info(surr->pcm[0], info);
|
||||||
if (surr->pcms > 1 && (info->channel == 2 || info->channel == 3))
|
if (surr->pcms > 1 && (info->channel == 2 || info->channel == 3)) {
|
||||||
return snd_pcm_channel_info(surr->pcm[1], info);
|
info->channel -= 2;
|
||||||
if (surr->pcms > 2 && (info->channel == 3 || info->channel == 4))
|
err = snd_pcm_channel_info(surr->pcm[1], info);
|
||||||
return snd_pcm_channel_info(surr->pcm[2], info);
|
info->channel += 2;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (surr->pcms > 2 && (info->channel == 3 || info->channel == 4)) {
|
||||||
|
info->channel -= 4;
|
||||||
|
err = snd_pcm_channel_info(surr->pcm[2], info);
|
||||||
|
info->channel += 4;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,53 +248,83 @@ static int snd_pcm_surround_interval_channels(snd_pcm_surround_t *surr,
|
||||||
if (interval->empty)
|
if (interval->empty)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (interval->openmin) {
|
if (interval->openmin) {
|
||||||
if (!refine)
|
if (!refine) {
|
||||||
|
interval->empty = 1;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
interval->min = surr->channels;
|
interval->min = surr->channels;
|
||||||
interval->openmin = 0;
|
interval->openmin = 0;
|
||||||
}
|
}
|
||||||
if (interval->openmax) {
|
if (interval->openmax) {
|
||||||
if (!refine)
|
if (!refine) {
|
||||||
|
interval->empty = 1;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
interval->max = surr->channels;
|
interval->max = surr->channels;
|
||||||
interval->openmax = 0;
|
interval->openmax = 0;
|
||||||
}
|
}
|
||||||
if (refine && interval->min <= surr->channels && interval->max >= surr->channels)
|
if (refine && interval->min <= surr->channels && interval->max >= surr->channels)
|
||||||
interval->min = interval->max = surr->channels;
|
interval->min = interval->max = surr->channels;
|
||||||
if (interval->min != interval->max || interval->min != surr->channels)
|
if (interval->min != interval->max || interval->min != surr->channels) {
|
||||||
|
interval->empty = 1;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
if (surr->pcms != 1)
|
if (surr->pcms != 1)
|
||||||
interval->min = interval->max = 2;
|
interval->min = interval->max = 2;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void snd_pcm_surround_interval_channels_fixup(snd_pcm_surround_t *surr,
|
||||||
|
snd_pcm_hw_params_t *params)
|
||||||
|
{
|
||||||
|
snd_interval_t *interval;
|
||||||
|
interval = ¶ms->intervals[SND_PCM_HW_PARAM_CHANNELS-SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
|
||||||
|
interval->min = interval->max = surr->channels;
|
||||||
|
}
|
||||||
|
|
||||||
static int snd_pcm_surround_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
|
static int snd_pcm_surround_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
|
||||||
{
|
{
|
||||||
snd_pcm_surround_t *surr = pcm->private_data;
|
snd_pcm_surround_t *surr = pcm->private_data;
|
||||||
int i, err = snd_pcm_surround_interval_channels(surr, params, 1);
|
int i, err;
|
||||||
|
|
||||||
|
err = snd_pcm_surround_interval_channels(surr, params, 1);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
if (surr->pcms == 1)
|
if (surr->pcms == 1)
|
||||||
return snd_pcm_hw_refine(surr->pcm[0], params);
|
return snd_pcm_hw_refine(surr->pcm[0], params);
|
||||||
for (i = 0; i < surr->pcms; i++) {
|
for (i = 0; i < surr->pcms; i++) {
|
||||||
err = snd_pcm_hw_refine(surr->pcm[i], params);
|
err = snd_pcm_hw_refine(surr->pcm[i], params);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
|
snd_pcm_surround_interval_channels_fixup(surr, params);
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
snd_pcm_surround_interval_channels_fixup(surr, params);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_surround_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
|
static int snd_pcm_surround_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
|
||||||
{
|
{
|
||||||
snd_pcm_surround_t *surr = pcm->private_data;
|
snd_pcm_surround_t *surr = pcm->private_data;
|
||||||
int i, err = snd_pcm_surround_interval_channels(surr, params, 0);
|
int i, err;
|
||||||
|
|
||||||
|
err = snd_pcm_surround_interval_channels(surr, params, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
if (surr->pcms == 1)
|
if (surr->pcms == 1)
|
||||||
return snd_pcm_hw_params(surr->pcm[0], params);
|
return snd_pcm_hw_params(surr->pcm[0], params);
|
||||||
for (i = 0; i < surr->pcms; i++) {
|
for (i = 0; i < surr->pcms; i++) {
|
||||||
err = snd_pcm_hw_params(surr->pcm[i], params);
|
err = snd_pcm_hw_params(surr->pcm[i], params);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
|
snd_pcm_surround_interval_channels_fixup(surr, params);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snd_pcm_surround_interval_channels_fixup(surr, params);
|
||||||
|
surr->linked[0] = 0;
|
||||||
|
for (i = 1; i < surr->pcms; i++) {
|
||||||
|
err = snd_pcm_link(surr->pcm[0], surr->pcm[1]);
|
||||||
|
if ((surr->linked[1] = (err >= 0)) == 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -293,14 +332,20 @@ static int snd_pcm_surround_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * para
|
||||||
|
|
||||||
static int snd_pcm_surround_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
static int snd_pcm_surround_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
int i, err;
|
int i, err, res = 0;
|
||||||
snd_pcm_surround_t *surr = pcm->private_data;
|
snd_pcm_surround_t *surr = pcm->private_data;
|
||||||
for (i = 0; i < surr->pcms; i++) {
|
for (i = 0; i < surr->pcms; i++) {
|
||||||
err = snd_pcm_hw_free(surr->pcm[i]);
|
err = snd_pcm_hw_free(surr->pcm[i]);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
res = err;
|
||||||
|
if (!surr->linked[i])
|
||||||
|
continue;
|
||||||
|
surr->linked[i] = 0;
|
||||||
|
err = snd_pcm_unlink(surr->pcm[i]);
|
||||||
|
if (err < 0)
|
||||||
|
res = err;
|
||||||
}
|
}
|
||||||
return 0;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_surround_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
static int snd_pcm_surround_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
||||||
|
|
@ -315,15 +360,15 @@ static int snd_pcm_surround_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * para
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_surround_mmap(snd_pcm_t *pcm)
|
static int snd_pcm_surround_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
snd_pcm_surround_t *surr = pcm->private_data;
|
// snd_pcm_surround_t *surr = pcm->private_data;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_surround_munmap(snd_pcm_t *pcm)
|
static int snd_pcm_surround_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
snd_pcm_surround_t *surr = pcm->private_data;
|
// snd_pcm_surround_t *surr = pcm->private_data;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -370,23 +415,104 @@ snd_pcm_fast_ops_t snd_pcm_surround_fast_ops = {
|
||||||
mmap_commit: snd_pcm_surround_mmap_commit,
|
mmap_commit: snd_pcm_surround_mmap_commit,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int snd_pcm_surround_free(snd_pcm_surround_t *surr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
assert(surr);
|
||||||
|
for (i = 2; i >= 0; i--) {
|
||||||
|
if (surr->pcm[i] == NULL)
|
||||||
|
continue;
|
||||||
|
snd_pcm_close(surr->pcm[i]);
|
||||||
|
surr->pcm[i] = NULL;
|
||||||
|
}
|
||||||
|
free(surr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_surround_three_streams(snd_pcm_surround_t *surr,
|
||||||
|
snd_pcm_surround_type_t type,
|
||||||
|
int card,
|
||||||
|
int dev0, int subdev0,
|
||||||
|
int dev1, int subdev1,
|
||||||
|
int dev2, int subdev2,
|
||||||
|
int mode)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if ((err = snd_pcm_hw_open(&surr->pcm[0], "Surround L/R", card, dev0,
|
||||||
|
subdev0, SND_PCM_STREAM_PLAYBACK, mode)) < 0)
|
||||||
|
return err;
|
||||||
|
surr->pcms++;
|
||||||
|
if ((err = snd_pcm_hw_open(&surr->pcm[1], "Surround Rear L/R", card, dev1,
|
||||||
|
subdev1, SND_PCM_STREAM_PLAYBACK, mode)) < 0)
|
||||||
|
return err;
|
||||||
|
surr->pcms++;
|
||||||
|
if (type == SND_PCM_SURROUND_51) {
|
||||||
|
if ((err = snd_pcm_hw_open(&surr->pcm[2], "Surround Center/LFE", card, dev2,
|
||||||
|
subdev2, SND_PCM_STREAM_PLAYBACK, mode)) < 0)
|
||||||
|
return err;
|
||||||
|
surr->pcms++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int snd_pcm_surround_open(snd_pcm_t **pcmp, const char *name, int card, int dev,
|
int snd_pcm_surround_open(snd_pcm_t **pcmp, const char *name, int card, int dev,
|
||||||
snd_pcm_surround_type_t type,
|
snd_pcm_surround_type_t type,
|
||||||
snd_pcm_stream_t stream, int mode)
|
snd_pcm_stream_t stream, int mode)
|
||||||
{
|
{
|
||||||
snd_pcm_t *pcm;
|
snd_pcm_t *pcm;
|
||||||
snd_pcm_surround_t *surr;
|
snd_pcm_surround_t *surr;
|
||||||
|
snd_ctl_t *ctl;
|
||||||
|
snd_ctl_card_info_t *info;
|
||||||
|
int err;
|
||||||
|
|
||||||
assert(pcmp);
|
assert(pcmp);
|
||||||
if (stream == SND_PCM_STREAM_CAPTURE)
|
if (stream == SND_PCM_STREAM_CAPTURE)
|
||||||
return -EINVAL; /* not supported at the time */
|
return -EINVAL; /* not supported at the time */
|
||||||
|
if (dev != 0)
|
||||||
|
return -EINVAL; /* not supported at the time */
|
||||||
surr = calloc(1, sizeof(snd_pcm_surround_t));
|
surr = calloc(1, sizeof(snd_pcm_surround_t));
|
||||||
if (!surr) {
|
if (!surr)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
switch (type) {
|
||||||
|
case SND_PCM_SURROUND_40:
|
||||||
|
surr->channels = 4;
|
||||||
|
break;
|
||||||
|
case SND_PCM_SURROUND_51:
|
||||||
|
surr->channels = 6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snd_pcm_surround_free(surr);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
if ((err = snd_ctl_hw_open(&ctl, "Surround", card, 0)) < 0) {
|
||||||
|
snd_pcm_surround_free(surr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
snd_ctl_card_info_alloca(&info);
|
||||||
|
if ((err = snd_ctl_card_info(ctl, info)) < 0) {
|
||||||
|
snd_ctl_close(ctl);
|
||||||
|
snd_pcm_surround_free(surr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
switch (snd_ctl_card_info_get_type(info)) {
|
||||||
|
case SND_CARD_TYPE_SI_7018:
|
||||||
|
if ((err = snd_pcm_surround_three_streams(surr, type, card,
|
||||||
|
0, -1, 0, -1, 0, -1, mode)) < 0) {
|
||||||
|
snd_pcm_surround_free(surr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snd_ctl_close(ctl);
|
||||||
|
snd_pcm_surround_free(surr);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
snd_ctl_close(ctl);
|
||||||
pcm = calloc(1, sizeof(snd_pcm_t));
|
pcm = calloc(1, sizeof(snd_pcm_t));
|
||||||
if (!pcm) {
|
if (!pcm) {
|
||||||
free(surr);
|
snd_pcm_surround_free(surr);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
if (name)
|
if (name)
|
||||||
|
|
@ -399,9 +525,9 @@ int snd_pcm_surround_open(snd_pcm_t **pcmp, const char *name, int card, int dev,
|
||||||
pcm->fast_ops = &snd_pcm_surround_fast_ops;
|
pcm->fast_ops = &snd_pcm_surround_fast_ops;
|
||||||
pcm->fast_op_arg = pcm;
|
pcm->fast_op_arg = pcm;
|
||||||
pcm->private_data = surr;
|
pcm->private_data = surr;
|
||||||
pcm->poll_fd = -1; /* FIXME */
|
pcm->poll_fd = surr->pcm[0]->poll_fd;
|
||||||
pcm->hw_ptr = NULL; /* FIXME */
|
pcm->hw_ptr = surr->pcm[0]->hw_ptr;
|
||||||
pcm->appl_ptr = NULL; /* FIXME */
|
pcm->appl_ptr = surr->pcm[0]->appl_ptr;
|
||||||
*pcmp = pcm;
|
*pcmp = pcm;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -456,12 +582,13 @@ int _snd_pcm_surround_open(snd_pcm_t **pcmp, const char *name, snd_config_t *con
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (strcmp(id, "type") == 0) {
|
if (strcmp(id, "stype") == 0) {
|
||||||
err = snd_config_get_string(n, &str);
|
err = snd_config_get_string(n, &str);
|
||||||
if (strcmp(str, "40") == 0 || strcmp(str, "4.0") == 0)
|
if (strcmp(str, "40") == 0 || strcmp(str, "4.0") == 0)
|
||||||
type = SND_PCM_SURROUND_40;
|
type = SND_PCM_SURROUND_40;
|
||||||
else if (strcmp(str, "51") == 0 || strcmp(str, "5.1") == 0)
|
else if (strcmp(str, "51") == 0 || strcmp(str, "5.1") == 0)
|
||||||
type = SND_PCM_SURROUND_51;
|
type = SND_PCM_SURROUND_51;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
SNDERR("Unknown field %s", id);
|
SNDERR("Unknown field %s", id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue