From a5831c7300414a6368c00a1371fdec5bdd2d6e2f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 20 Jan 2005 18:37:13 +0000 Subject: [PATCH] The stream linking problem for pcm_multi.c should be fixed now - extended link_fd callback - added snd_pcm_generic_link2() - added _snd_pcm_link_descriptors() --- src/pcm/pcm.c | 6 +++--- src/pcm/pcm_generic.c | 45 +++++++++++++++++++++++++++++++++++++-- src/pcm/pcm_generic.h | 3 ++- src/pcm/pcm_hw.c | 35 ++++++++++++++++++++++--------- src/pcm/pcm_local.h | 5 +++-- src/pcm/pcm_multi.c | 49 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 18 deletions(-) diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 13af3942..a4df4698 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -603,7 +603,6 @@ playback devices. #include #include #include -#include #include #include #include @@ -6140,11 +6139,12 @@ snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm, #ifndef DOC_HIDDEN -int _snd_pcm_link_descriptor(snd_pcm_t *pcm) +int _snd_pcm_link_descriptors(snd_pcm_t *pcm, int *fds, int count, + int (**failed)(snd_pcm_t *, int)) { assert(pcm); if (pcm->fast_ops->link_fd) - return pcm->fast_ops->link_fd(pcm); + return pcm->fast_ops->link_fd(pcm, fds, count, failed); return -ENOSYS; } diff --git a/src/pcm/pcm_generic.c b/src/pcm/pcm_generic.c index 44aae856..9cf2505f 100644 --- a/src/pcm/pcm_generic.c +++ b/src/pcm/pcm_generic.c @@ -27,6 +27,7 @@ */ #include +#include #include #include "pcm_local.h" #include "pcm_generic.h" @@ -182,11 +183,11 @@ int snd_pcm_generic_poll_ask(snd_pcm_t *pcm) return 0; } -int snd_pcm_generic_link_fd(snd_pcm_t *pcm) +int snd_pcm_generic_link_fd(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *, int)) { snd_pcm_generic_t *generic = pcm->private_data; if (generic->slave->fast_ops->link_fd) - return generic->slave->fast_ops->link_fd(generic->slave->fast_op_arg); + return generic->slave->fast_ops->link_fd(generic->slave->fast_op_arg, fds, count, failed); return -ENOSYS; } @@ -198,6 +199,46 @@ int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) return -ENOSYS; } +int snd_pcm_generic_link2(snd_pcm_t *pcm1, snd_pcm_t *pcm2) +{ + int fds1[16], fds2[16]; + int (*failed1)(snd_pcm_t *, int) = NULL; + int (*failed2)(snd_pcm_t *, int) = NULL; + int count1 = _snd_pcm_link_descriptors(pcm1, fds1, 16, &failed1); + int count2 = _snd_pcm_link_descriptors(pcm2, fds2, 16, &failed2); + int i, err = 0; + + if (count1 < 0) + return count1; + if (count2 < 0) + return count2; + for (i = 1; i < count1; i++) { + if (fds1[i] < 0) + return 0; + if (ioctl(fds1[0], SNDRV_PCM_IOCTL_LINK, fds1[i]) < 0) { + if (failed1 != NULL) { + err = failed1(pcm2, fds1[i]); + } else { + SYSMSG("SNDRV_PCM_IOCTL_LINK failed"); + err = -errno; + } + } + } + for (i = 0; i < count2; i++) { + if (fds2[i] < 0) + return 0; + if (ioctl(fds1[0], SNDRV_PCM_IOCTL_LINK, fds2[i]) < 0) { + if (failed1 != NULL) { + err = failed2(pcm2, fds2[i]); + } else { + SYSMSG("SNDRV_PCM_IOCTL_LINK failed"); + err = -errno; + } + } + } + return err; +} + int snd_pcm_generic_unlink(snd_pcm_t *pcm) { snd_pcm_generic_t *generic = pcm->private_data; diff --git a/src/pcm/pcm_generic.h b/src/pcm/pcm_generic.h index 202a9fb5..bb086c9d 100644 --- a/src/pcm/pcm_generic.h +++ b/src/pcm/pcm_generic.h @@ -48,8 +48,9 @@ int snd_pcm_generic_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); snd_pcm_sframes_t snd_pcm_generic_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); snd_pcm_sframes_t snd_pcm_generic_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames); int snd_pcm_generic_poll_ask(snd_pcm_t *pcm); -int snd_pcm_generic_link_fd(snd_pcm_t *pcm); +int snd_pcm_generic_link_fd(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *, int)); int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2); +int snd_pcm_generic_link2(snd_pcm_t *pcm1, snd_pcm_t *pcm2); int snd_pcm_generic_unlink(snd_pcm_t *pcm); snd_pcm_sframes_t snd_pcm_generic_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); snd_pcm_sframes_t snd_pcm_generic_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index b3b02800..499bd0cc 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -656,25 +656,40 @@ static int snd_pcm_hw_resume(snd_pcm_t *pcm) return 0; } -static int snd_pcm_hw_link_fd(snd_pcm_t *pcm) +static int snd_pcm_hw_link_fd(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *, int)) { snd_pcm_hw_t *hw = pcm->private_data; - return hw->fd; + if (count < 1) + return -EINVAL; + *failed = NULL; + fds[0] = hw->fd; + return 1; } static int snd_pcm_hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) { snd_pcm_hw_t *hw = pcm1->private_data; - int fd2 = _snd_pcm_link_descriptor(pcm2); - - if (fd2 < 0) - return -ENOSYS; - if (ioctl(hw->fd, SNDRV_PCM_IOCTL_LINK, fd2) < 0) { - SYSMSG("SNDRV_PCM_IOCTL_LINK failed"); - return -errno; + int fds[16]; + int (*failed)(snd_pcm_t *, int) = NULL; + int count = _snd_pcm_link_descriptors(pcm2, fds, 16, &failed); + int i, err = 0; + + if (count < 0) + return count; + for (i = 0; i < count; i++) { + if (fds[i] < 0) + return 0; + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_LINK, fds[i]) < 0) { + if (failed != NULL) { + err = failed(pcm2, fds[i]); + } else { + SYSMSG("SNDRV_PCM_IOCTL_LINK failed"); + err = -errno; + } + } } - return 0; + return err; } static int snd_pcm_hw_unlink(snd_pcm_t *pcm) diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 5b9ef3b2..5d7569bb 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -152,7 +152,7 @@ typedef struct { int (*delay)(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); int (*resume)(snd_pcm_t *pcm); int (*poll_ask)(snd_pcm_t *pcm); - int (*link_fd)(snd_pcm_t *pcm); + int (*link_fd)(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *, int)); int (*link)(snd_pcm_t *pcm1, snd_pcm_t *pcm2); int (*unlink)(snd_pcm_t *pcm); snd_pcm_sframes_t (*rewind)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); @@ -265,7 +265,8 @@ snd_pcm_sframes_t snd_pcm_write_mmap(snd_pcm_t *pcm, snd_pcm_uframes_t size); 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); int _snd_pcm_poll_descriptor(snd_pcm_t *pcm); -int _snd_pcm_link_descriptor(snd_pcm_t *pcm); +int _snd_pcm_link_descriptors(snd_pcm_t *pcm, int *fds, int size, int (**failed)(snd_pcm_t *, int)); +#define _snd_pcm_link_descriptor _snd_pcm_poll_descriptor /* FIXME */ #define _snd_pcm_async_descriptor _snd_pcm_poll_descriptor /* FIXME */ /* handle special error cases */ diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index b23b2861..ce3fc5ea 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -32,6 +32,7 @@ #include #include #include "pcm_local.h" +#include "pcm_generic.h" #ifndef PIC /* entry for static linking */ @@ -56,6 +57,7 @@ typedef struct { unsigned int slaves_count; unsigned int master_slave; snd_pcm_multi_slave_t *slaves; + int slave_link_master; unsigned int channels_count; snd_pcm_multi_channel_t *channels; } snd_pcm_multi_t; @@ -296,6 +298,7 @@ static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) } } multi->slaves[0].linked = 0; + multi->slave_link_master = 0; for (i = 1; i < multi->slaves_count; ++i) { err = snd_pcm_link(multi->slaves[0].pcm, multi->slaves[i].pcm); multi->slaves[i].linked = (err >= 0); @@ -577,6 +580,49 @@ static int snd_pcm_multi_poll_ask(snd_pcm_t *pcm) return err; } +static int snd_pcm_multi_link_fd_failed(snd_pcm_t *pcm, int fd) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + + for (i = 0; i < multi->slaves_count; ++i) { + if (_snd_pcm_link_descriptor(multi->slaves[i].pcm) != fd) + continue; + multi->slaves[i].linked = 0; + } + return 0; +} + +static int snd_pcm_multi_link_fd(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *pcm, int fd)) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + + if (count < (int)multi->slaves_count) + return -ENOMEM; + for (i = 0; i < multi->slaves_count; ++i) { + if (multi->slaves[i].linked) + snd_pcm_unlink(multi->slaves[i].pcm); + fds[i] = _snd_pcm_link_descriptor(multi->slaves[i].pcm); + multi->slaves[i].linked = 1; + } + *failed = snd_pcm_multi_link_fd_failed; + return multi->slaves_count; +} + +static int snd_pcm_multi_unlink(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + + for (i = 0; i < multi->slaves_count; ++i) { + if (multi->slaves[i].linked) + snd_pcm_unlink(multi->slaves[i].pcm); + multi->slaves[i].linked = 0; + } + return 0; +} + static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size) @@ -664,6 +710,9 @@ static snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = { .forward = snd_pcm_multi_forward, .resume = snd_pcm_multi_resume, .poll_ask = snd_pcm_multi_poll_ask, + .link_fd = snd_pcm_multi_link_fd, + .link = snd_pcm_generic_link2, + .unlink = snd_pcm_multi_unlink, .avail_update = snd_pcm_multi_avail_update, .mmap_commit = snd_pcm_multi_mmap_commit, }; -- 2.47.1