From: Jaroslav Kysela Date: Tue, 17 Apr 2001 10:01:57 +0000 (+0000) Subject: More complete code X-Git-Tag: v1.0.3~885 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=13fb68344e933046cbc4c15ff48bfb48ccf2b874;p=alsa-lib.git More complete code --- diff --git a/src/pcm/pcm_surr.c b/src/pcm/pcm_surr.c index 66231bd6..af5be6e6 100644 --- a/src/pcm/pcm_surr.c +++ b/src/pcm/pcm_surr.c @@ -31,6 +31,7 @@ #include #include #include +#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;