unsigned int channels; /* count of channels (4 or 6) */
int pcms; /* count of PCM channels */
int use_fd; /* use this FD for the direct access */
- snd_pcm_t *pcm[3]; /* up to three PCM stereo streams */
+ snd_pcm_t *pcm[3]; /* up to three PCM stereo streams */
+ int use_route: 1; /* route is used */
+ int route[6]; /* channel route */
int linked[3]; /* streams are linked */
snd_ctl_t *ctl; /* CTL handle */
unsigned int caps; /* capabilities */
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)) {
- info->channel -= 2;
- err = snd_pcm_channel_info(surr->pcm[1], info);
- info->channel += 2;
- return err;
- }
- if (surr->pcms > 2 && (info->channel == 4 || info->channel == 5)) {
- info->channel -= 4;
- err = snd_pcm_channel_info(surr->pcm[2], info);
- info->channel += 4;
- return err;
- }
- return -EINVAL;
+ int err, old_channel;
+
+ old_channel = info->channel;
+ if (old_channel < 0 || old_channel > 5)
+ return -EINVAL;
+ if (surr->pcm[old_channel / 2] == NULL)
+ return -EINVAL;
+ info->channel = surr->route[old_channel] % 2;
+ err = snd_pcm_channel_info(surr->pcm[surr->pcms == 1 ? 0 : surr->route[old_channel] / 2], info);
+ info->channel = old_channel;
+ return err;
}
static int snd_pcm_surround_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
static snd_pcm_sframes_t snd_pcm_surround_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
{
snd_pcm_surround_t *surr = pcm->private_data;
- if (surr->pcms == 1)
+ if (surr->pcms == 1 && !surr->use_route)
return snd_pcm_writei(surr->pcm[0], buffer, size);
if (pcm->running_areas == NULL) {
int err;
int i;
snd_pcm_sframes_t res = -1, res1;
snd_pcm_surround_t *surr = pcm->private_data;
+ if (surr->use_route) {
+ if (pcm->running_areas == NULL) {
+ int err;
+ if ((err = snd_pcm_mmap(pcm)) < 0)
+ return err;
+ }
+ return snd_pcm_mmap_writen(pcm, bufs, size);
+ }
for (i = 0; i < surr->pcms; i++, bufs += 2) {
res1 = snd_pcm_writen(pcm, bufs, size);
if (res1 < 0)
static snd_pcm_sframes_t snd_pcm_surround_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
{
snd_pcm_surround_t *surr = pcm->private_data;
- if (surr->pcms == 1)
+ if (surr->pcms == 1 && !surr->use_route)
return snd_pcm_readi(surr->pcm[0], buffer, size);
if (pcm->running_areas == NULL) {
int err;
int i;
snd_pcm_sframes_t res = -1, res1;
snd_pcm_surround_t *surr = pcm->private_data;
+ if (surr->use_route) {
+ if (pcm->running_areas == NULL) {
+ int err;
+ if ((err = snd_pcm_mmap(pcm)) < 0)
+ return err;
+ }
+ return snd_pcm_mmap_readn(pcm, bufs, size);
+ }
for (i = 0; i < surr->pcms; i++) {
res1 = snd_pcm_writen(pcm, bufs, size);
if (res1 < 0)
}
err = 0;
__error:
- snd_pcm_access_mask_copy(access_mask, access_mask1);
+ snd_pcm_access_mask_none(access_mask);
+ if (snd_pcm_access_mask_test(access_mask1, SND_PCM_ACCESS_RW_INTERLEAVED))
+ snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (snd_pcm_access_mask_test(access_mask1, SND_PCM_ACCESS_RW_NONINTERLEAVED))
+ snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED);
+ if (snd_pcm_access_mask_test(access_mask1, SND_PCM_ACCESS_MMAP_COMPLEX))
+ snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
snd_pcm_surround_interval_channels_fixup(surr, params);
return err;
}
goto __error;
}
}
+ if (snd_config_search(n, "route", &n1) >= 0) {
+ snd_config_iterator_t i, next;
+ if (snd_config_get_type(n1) != SND_CONFIG_TYPE_COMPOUND) {
+ SNDERR("compound type expected");
+ goto __error;
+ }
+ snd_config_for_each(i, next, n1) {
+ snd_config_t *n = snd_config_iterator_entry(i);
+ int idx = atoi(snd_config_get_id(n));
+ unsigned long i;
+ int err = snd_config_get_integer(n, &i);
+ if (err < 0) {
+ SNDERR("Invalid field channel.%s", id);
+ goto __error;
+ }
+ if (idx < 0 || idx >= 6) {
+ SNDERR("Index is out of range (0-5): %i", idx);
+ goto __error;
+ }
+ if (idx != (int)i)
+ surr->use_route = 1;
+ surr->route[idx] = i;
+ }
+ }
if (snd_config_search(n, "open_single", &n1) >= 0) {
snd_config_iterator_t i, next;
int device = 0, subdevice = -1;
snd_ctl_t *ctl = NULL;
snd_ctl_card_info_t *info;
snd_card_type_t ctype;
- int err;
+ int err, idx;
assert(pcmp);
surr = calloc(1, sizeof(snd_pcm_surround_t));
surr->card = card;
surr->device = dev;
surr->caps = SURR_CAP_4CH;
+ for (idx = 0; idx < 6; idx++)
+ surr->route[idx] = idx;
snd_ctl_card_info_alloca(&info);
if ((err = snd_ctl_card_info(ctl, info)) < 0)
goto __error;