Instead of link_fd, more generic callback link_slaves is introduced.
This is called for linking the slave streams as the source to the
given master stream.
#ifndef DOC_HIDDEN
-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, fds, count, failed);
- return -ENOSYS;
-}
-
int _snd_pcm_poll_descriptor(snd_pcm_t *pcm)
{
assert(pcm);
.rewind = snd_pcm_dmix_rewind,
.forward = snd_pcm_dmix_forward,
.resume = snd_pcm_direct_resume,
- .link_fd = NULL,
.link = NULL,
+ .link_slaves = NULL,
.unlink = NULL,
.writei = snd_pcm_mmap_writei,
.writen = snd_pcm_mmap_writen,
.rewind = snd_pcm_dshare_rewind,
.forward = snd_pcm_dshare_forward,
.resume = snd_pcm_direct_resume,
- .link_fd = NULL,
.link = NULL,
+ .link_slaves = NULL,
.unlink = NULL,
.writei = snd_pcm_mmap_writei,
.writen = snd_pcm_mmap_writen,
.rewind = snd_pcm_dsnoop_rewind,
.forward = snd_pcm_dsnoop_forward,
.resume = snd_pcm_direct_resume,
- .link_fd = NULL,
.link = NULL,
+ .link_slaves = NULL,
.unlink = NULL,
.writei = snd_pcm_dsnoop_writei,
.writen = snd_pcm_dsnoop_writen,
.rewind = snd_pcm_file_rewind,
.forward = snd_pcm_file_forward,
.resume = snd_pcm_generic_resume,
- .link_fd = snd_pcm_generic_link_fd,
.link = snd_pcm_generic_link,
+ .link_slaves = snd_pcm_generic_link_slaves,
.unlink = snd_pcm_generic_unlink,
.writei = snd_pcm_file_writei,
.writen = snd_pcm_file_writen,
return snd_pcm_rewind(generic->slave, frames);
}
-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, fds, count, failed);
- return -ENOSYS;
-}
-
int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
{
snd_pcm_generic_t *generic = pcm1->private_data;
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_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
+{
+ snd_pcm_generic_t *generic = pcm->private_data;
+ if (generic->slave->fast_ops->link_slaves)
+ return generic->slave->fast_ops->link_slaves(generic->slave->fast_op_arg, master);
+ return -ENOSYS;
}
int snd_pcm_generic_unlink(snd_pcm_t *pcm)
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_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_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master);
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);
.rewind = snd_pcm_generic_rewind,
.forward = snd_pcm_generic_forward,
.resume = snd_pcm_generic_resume,
- .link_fd = snd_pcm_generic_link_fd,
.link = snd_pcm_generic_link,
+ .link_slaves = snd_pcm_generic_link_slaves,
.unlink = snd_pcm_generic_unlink,
.writei = snd_pcm_generic_writei,
.writen = snd_pcm_generic_writen,
return 0;
}
-static int snd_pcm_hw_link_fd(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *, int))
+static int hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
{
- snd_pcm_hw_t *hw = pcm->private_data;
+ snd_pcm_hw_t *hw1 = pcm1->private_data;
+ snd_pcm_hw_t *hw2 = pcm2->private_data;
+ if (ioctl(hw1->fd, SNDRV_PCM_IOCTL_LINK, hw2->fd) < 0) {
+ SYSMSG("SNDRV_PCM_IOCTL_LINK failed");
+ return -errno;
+ }
+ return 0;
+}
- if (count < 1)
+static int snd_pcm_hw_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
+{
+ if (master->type != SND_PCM_TYPE_HW) {
+ SYSMSG("Invalid type for SNDRV_PCM_IOCTL_LINK");
return -EINVAL;
- *failed = NULL;
- fds[0] = hw->fd;
- return 1;
+ }
+ return hw_link(master, pcm);
}
static int snd_pcm_hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
{
- snd_pcm_hw_t *hw = pcm1->private_data;
- 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;
- }
- }
+ if (pcm2->type != SND_PCM_TYPE_HW) {
+ if (pcm2->fast_ops->link_slaves)
+ return pcm2->fast_ops->link_slaves(pcm2, pcm1);
+ return -ENOSYS;
}
- return err;
-}
+ return hw_link(pcm1, pcm2);
+ }
static int snd_pcm_hw_unlink(snd_pcm_t *pcm)
{
.rewind = snd_pcm_hw_rewind,
.forward = snd_pcm_hw_forward,
.resume = snd_pcm_hw_resume,
- .link_fd = snd_pcm_hw_link_fd,
.link = snd_pcm_hw_link,
+ .link_slaves = snd_pcm_hw_link_slaves,
.unlink = snd_pcm_hw_unlink,
.writei = snd_pcm_hw_writei,
.writen = snd_pcm_hw_writen,
.hwsync = snd_pcm_ioplug_hwsync,
.delay = snd_pcm_ioplug_delay,
.resume = snd_pcm_ioplug_resume,
- .link_fd = NULL,
.link = NULL,
+ .link_slaves = NULL,
.unlink = NULL,
.rewind = snd_pcm_ioplug_rewind,
.forward = snd_pcm_ioplug_forward,
int (*hwsync)(snd_pcm_t *pcm);
int (*delay)(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp);
int (*resume)(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 (*link_slaves)(snd_pcm_t *pcm, snd_pcm_t *master);
int (*unlink)(snd_pcm_t *pcm);
snd_pcm_sframes_t (*rewind)(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
snd_pcm_sframes_t (*forward)(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
snd_pcm_t *pcm;
unsigned int channels_count;
int close_slave;
- int linked;
+ snd_pcm_t *linked;
} snd_pcm_multi_slave_t;
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;
return 0;
}
+static void reset_links(snd_pcm_multi_t *multi)
+{
+ unsigned int i;
+
+ for (i = 0; i < multi->slaves_count; ++i) {
+ if (multi->slaves[i].linked)
+ snd_pcm_unlink(multi->slaves[i].linked);
+ multi->slaves[0].linked = NULL;
+ if (! i)
+ continue;
+ if (snd_pcm_link(multi->slaves[0].pcm, multi->slaves[i].pcm) >= 0)
+ multi->slaves[i].linked = multi->slaves[0].pcm;
+ }
+}
+
static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_multi_t *multi = pcm->private_data;
return err;
}
}
- 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);
- }
+ reset_links(multi);
return 0;
}
err = e;
if (!multi->slaves[i].linked)
continue;
- multi->slaves[i].linked = 0;
e = snd_pcm_unlink(slave);
if (e < 0)
err = e;
+ multi->slaves[i].linked = NULL;
}
return err;
}
static int snd_pcm_multi_prepare(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- int err = 0;
+ int result = 0, err;
unsigned int i;
for (i = 0; i < multi->slaves_count; ++i) {
/* We call prepare to each slave even if it's linked.
*/
err = snd_pcm_prepare(multi->slaves[i].pcm);
if (err < 0)
- return err;
+ result = err;
}
- return err;
+ return result;
}
static int snd_pcm_multi_reset(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- int err = 0;
+ int result = 0, err;
unsigned int i;
for (i = 0; i < multi->slaves_count; ++i) {
/* Reset each slave, as well as in prepare */
err = snd_pcm_reset(multi->slaves[i].pcm);
- if (err < 0)
- return err;
+ if (err < 0)
+ result = err;
}
- return err;
+ return result;
}
static int snd_pcm_multi_start(snd_pcm_t *pcm)
snd_pcm_multi_t *multi = pcm->private_data;
int err = 0;
unsigned int i;
+ if (multi->slaves[0].linked)
+ return snd_pcm_start(multi->slaves[0].linked);
for (i = 0; i < multi->slaves_count; ++i) {
if (multi->slaves[i].linked)
continue;
snd_pcm_multi_t *multi = pcm->private_data;
int err = 0;
unsigned int i;
+ if (multi->slaves[0].linked)
+ return snd_pcm_drop(multi->slaves[0].linked);
for (i = 0; i < multi->slaves_count; ++i) {
if (multi->slaves[i].linked)
continue;
snd_pcm_multi_t *multi = pcm->private_data;
int err = 0;
unsigned int i;
+ if (multi->slaves[0].linked)
+ return snd_pcm_drain(multi->slaves[0].linked);
for (i = 0; i < multi->slaves_count; ++i) {
if (multi->slaves[i].linked)
continue;
snd_pcm_multi_t *multi = pcm->private_data;
int err = 0;
unsigned int i;
+ if (multi->slaves[0].linked)
+ return snd_pcm_pause(multi->slaves[0].linked, enable);
for (i = 0; i < multi->slaves_count; ++i) {
if (multi->slaves[i].linked)
continue;
snd_pcm_multi_t *multi = pcm->private_data;
int err = 0;
unsigned int i;
+ if (multi->slaves[0].linked)
+ return snd_pcm_resume(multi->slaves[0].linked);
for (i = 0; i < multi->slaves_count; ++i) {
if (multi->slaves[i].linked)
continue;
return err;
}
-static int snd_pcm_multi_link_fd_failed(snd_pcm_t *pcm, int fd)
-{
+static int snd_pcm_multi_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
+{
snd_pcm_multi_t *multi = pcm->private_data;
- unsigned int i;
+ unsigned int i, j;
+ int err;
for (i = 0; i < multi->slaves_count; ++i) {
- if (_snd_pcm_link_descriptor(multi->slaves[i].pcm) != fd)
- continue;
- multi->slaves[i].linked = 0;
+ snd_pcm_unlink(multi->slaves[i].pcm);
+ multi->slaves[i].linked = NULL;
+ err = snd_pcm_link(master, multi->slaves[i].pcm);
+ if (err < 0) {
+ reset_links(multi);
+ return err;
+ }
+ multi->slaves[i].linked = master;
}
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);
- if (i > 0)
- multi->slaves[i].linked = 1;
- }
- *failed = snd_pcm_multi_link_fd_failed;
- return multi->slaves_count;
+static int snd_pcm_multi_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
+{
+ snd_pcm_multi_t *multi = pcm1->private_data;
+ if (multi->slaves[0].pcm->fast_ops->link)
+ return multi->slaves[0].pcm->fast_ops->link(multi->slaves[0].pcm, pcm2);
+ return -ENOSYS;
}
static int snd_pcm_multi_unlink(snd_pcm_t *pcm)
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;
+ snd_pcm_unlink(multi->slaves[i].linked);
+ multi->slaves[0].linked = NULL;
}
return 0;
}
.rewind = snd_pcm_multi_rewind,
.forward = snd_pcm_multi_forward,
.resume = snd_pcm_multi_resume,
- .link_fd = snd_pcm_multi_link_fd,
- .link = snd_pcm_generic_link2,
+ .link = snd_pcm_multi_link,
+ .link_slaves = snd_pcm_multi_link_slaves,
.unlink = snd_pcm_multi_unlink,
.avail_update = snd_pcm_multi_avail_update,
.mmap_commit = snd_pcm_multi_mmap_commit,
.rewind = snd_pcm_plugin_rewind,
.forward = snd_pcm_plugin_forward,
.resume = snd_pcm_generic_resume,
- .link_fd = snd_pcm_generic_link_fd,
.link = snd_pcm_generic_link,
+ .link_slaves = snd_pcm_generic_link_slaves,
.unlink = snd_pcm_generic_unlink,
.writei = snd_pcm_plugin_writei,
.writen = snd_pcm_plugin_writen,