mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-04 13:30:08 -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 <limits.h>
|
||||
#include <sys/shm.h>
|
||||
#include "../control/control_local.h"
|
||||
#include "pcm_local.h"
|
||||
#include "pcm_plugin.h"
|
||||
|
||||
|
|
@ -40,16 +41,15 @@ typedef struct {
|
|||
unsigned int channels; /* count of channels (4 or 6) */
|
||||
int pcms; /* count of PCM channels */
|
||||
snd_pcm_t *pcm[3]; /* up to three PCM stereo streams */
|
||||
int linked[3]; /* streams are linked */
|
||||
} 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)
|
||||
{
|
||||
int i;
|
||||
snd_pcm_surround_t *surr = pcm->private_data;
|
||||
for (i = 0; i < surr->pcms; i++)
|
||||
snd_pcm_close(surr->pcm[i]);
|
||||
free(surr);
|
||||
return 0;
|
||||
return snd_pcm_surround_free(surr);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
snd_pcm_surround_t *surr = pcm->private_data;
|
||||
int err;
|
||||
if (surr->pcms == 1 || info->channel == 0 || info->channel == 1)
|
||||
return snd_pcm_channel_info(surr->pcm[0], info);
|
||||
if (surr->pcms > 1 && (info->channel == 2 || info->channel == 3))
|
||||
return snd_pcm_channel_info(surr->pcm[1], info);
|
||||
if (surr->pcms > 2 && (info->channel == 3 || info->channel == 4))
|
||||
return snd_pcm_channel_info(surr->pcm[2], info);
|
||||
if (surr->pcms > 1 && (info->channel == 2 || info->channel == 3)) {
|
||||
info->channel -= 2;
|
||||
err = snd_pcm_channel_info(surr->pcm[1], 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;
|
||||
}
|
||||
|
||||
|
|
@ -239,53 +248,83 @@ static int snd_pcm_surround_interval_channels(snd_pcm_surround_t *surr,
|
|||
if (interval->empty)
|
||||
return -EINVAL;
|
||||
if (interval->openmin) {
|
||||
if (!refine)
|
||||
if (!refine) {
|
||||
interval->empty = 1;
|
||||
return -EINVAL;
|
||||
}
|
||||
interval->min = surr->channels;
|
||||
interval->openmin = 0;
|
||||
}
|
||||
if (interval->openmax) {
|
||||
if (!refine)
|
||||
if (!refine) {
|
||||
interval->empty = 1;
|
||||
return -EINVAL;
|
||||
}
|
||||
interval->max = surr->channels;
|
||||
interval->openmax = 0;
|
||||
}
|
||||
if (refine && interval->min <= surr->channels && 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;
|
||||
}
|
||||
if (surr->pcms != 1)
|
||||
interval->min = interval->max = 2;
|
||||
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)
|
||||
{
|
||||
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)
|
||||
return err;
|
||||
if (surr->pcms == 1)
|
||||
return snd_pcm_hw_refine(surr->pcm[0], params);
|
||||
for (i = 0; i < surr->pcms; i++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
snd_pcm_surround_interval_channels_fixup(surr, params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
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)
|
||||
return err;
|
||||
if (surr->pcms == 1)
|
||||
return snd_pcm_hw_params(surr->pcm[0], params);
|
||||
for (i = 0; i < surr->pcms; i++) {
|
||||
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 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)
|
||||
{
|
||||
int i, err;
|
||||
int i, err, res = 0;
|
||||
snd_pcm_surround_t *surr = pcm->private_data;
|
||||
for (i = 0; i < surr->pcms; i++) {
|
||||
err = snd_pcm_hw_free(surr->pcm[i]);
|
||||
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)
|
||||
|
|
@ -315,15 +360,15 @@ static int snd_pcm_surround_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * para
|
|||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -370,23 +415,104 @@ snd_pcm_fast_ops_t snd_pcm_surround_fast_ops = {
|
|||
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,
|
||||
snd_pcm_surround_type_t type,
|
||||
snd_pcm_stream_t stream, int mode)
|
||||
{
|
||||
snd_pcm_t *pcm;
|
||||
snd_pcm_surround_t *surr;
|
||||
snd_ctl_t *ctl;
|
||||
snd_ctl_card_info_t *info;
|
||||
int err;
|
||||
|
||||
assert(pcmp);
|
||||
if (stream == SND_PCM_STREAM_CAPTURE)
|
||||
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));
|
||||
if (!surr) {
|
||||
if (!surr)
|
||||
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));
|
||||
if (!pcm) {
|
||||
free(surr);
|
||||
snd_pcm_surround_free(surr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
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_op_arg = pcm;
|
||||
pcm->private_data = surr;
|
||||
pcm->poll_fd = -1; /* FIXME */
|
||||
pcm->hw_ptr = NULL; /* FIXME */
|
||||
pcm->appl_ptr = NULL; /* FIXME */
|
||||
pcm->poll_fd = surr->pcm[0]->poll_fd;
|
||||
pcm->hw_ptr = surr->pcm[0]->hw_ptr;
|
||||
pcm->appl_ptr = surr->pcm[0]->appl_ptr;
|
||||
*pcmp = pcm;
|
||||
|
||||
return 0;
|
||||
|
|
@ -456,12 +582,13 @@ int _snd_pcm_surround_open(snd_pcm_t **pcmp, const char *name, snd_config_t *con
|
|||
continue;
|
||||
}
|
||||
#endif
|
||||
if (strcmp(id, "type") == 0) {
|
||||
if (strcmp(id, "stype") == 0) {
|
||||
err = snd_config_get_string(n, &str);
|
||||
if (strcmp(str, "40") == 0 || strcmp(str, "4.0") == 0)
|
||||
type = SND_PCM_SURROUND_40;
|
||||
else if (strcmp(str, "51") == 0 || strcmp(str, "5.1") == 0)
|
||||
type = SND_PCM_SURROUND_51;
|
||||
continue;
|
||||
}
|
||||
SNDERR("Unknown field %s", id);
|
||||
return -EINVAL;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue