#include <stdarg.h>
#include <signal.h>
#include <dlfcn.h>
-#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/shm.h>
#include <sys/mman.h>
#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;
}
*/
#include <sys/shm.h>
+#include <sys/ioctl.h>
#include <limits.h>
#include "pcm_local.h"
#include "pcm_generic.h"
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;
}
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;
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);
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)
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);
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 */
#include <string.h>
#include <math.h>
#include "pcm_local.h"
+#include "pcm_generic.h"
#ifndef PIC
/* entry for static linking */
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;
}
}
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);
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)
.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,
};