At Tue, 13 Mar 2007 00:46:52 +0100, I wrote: > > At Sat, 10 Mar 2007 14:17:13 +0000, > John Rigg wrote: > > > > On Fri, Mar 09, 2007 at 05:38:34PM +0100, Takashi Iwai wrote: > > > At Thu, 8 Mar 2007 21:51:28 +0000, > > > John Rigg wrote: > > > > > > > > On Thu, Mar 08, 2007 at 07:58:23PM +0100, Takashi Iwai wrote: > > > > > At Thu, 08 Mar 2007 18:16:02 +0100, > > > > > Simon Lewis wrote: > > > > > > Many JACK users have successfully used the following patch: > > > > > > > > > > > > http://www.sound-man.co.uk/linuxaudio/pcm_multi-patch > > > > > > > > > > Well, the patch is no real fix. It's likely a workaround for JACK, > > > > > though. Someone has to take time to track down this bug more deeply. > > > > > > > > True, the patch is just a workaround for JACK. However, I would > > > > argue that most users of pcm_multi are probably JACK users. > > > > > > No, multi plugin is used in many surround PCM definitions as default. > > > It's pretty hidden, but multi streams are no rare case. > > > > I hadn't noticed that. Thanks for pointing it out (and thank you for > > looking at this problem!) > > > > > > Surely adding code that breaks something for the majority of users (no > > > > matter how correct that code is in isolation) is not a good thing. > > > > > > Sure. However, this code addition was for bugfixes of major other use > > > cases like above, IIRC. The regression should be avoided and should > > > be fixed. But the point is, we (at least, I) haven't been enough > > > informed, unfortunately (or simply burried in a big TODO list :) > > > > > > Now, let's back to the original problem: Could someone give a pointer > > > describing for this problem, or just explain a bit details here? > > > I vaguely remember but not precisely at all now... > > > I'm willing to dig down after knowing how I can reproduce the bug. > > > > To summarise, using multiple sound cards with pcm_multi and jackd > > no longer works in duplex mode ever since extra linking code was > > added to pcm_multi.c in alsa-lib-1.0.9rc1. > > > > Trying to start jackd in duplex fails with a poll timeout message. > > It still works in playback-only or capture-only modes. > > The lack of duplex operation makes overdubbing in a recording studio, > > for example, impossible. > > > > A configuration which produces the problem with two ice1712 cards > > set up as a 16 channel multi device is shown here: > > http://www.sound-man.co.uk/linuxaudio/ice1712multi.html > > > > With the .asoundrc described in the above link the following > > command fails with a poll timeout message: > > > > jackd -d alsa -P multi_playback -C multi_capture > > > > The following still work: > > jackd -d alsa -P multi_playback > > jackd -d alsa -C multi_capture > > OK, played a bit around this bug. A temporary fix is attached below. > It's applied to HG tree now, too. Please give it a try. > > The real fix will come later... More complete fix is below. Apply after the previous patch. (Or more easily use the HG version.) Takashi # HG changeset patch # User tiwai # Date 1173750753 -3600 # Node ID 4883f0ba21df769cea44345f35dcdd3b6214b8e7 # Parent 78c78fa6c41db913484d6e3cff2f1e31e5fc6075 More better fix for linked start/stop 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. diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm.c --- a/src/pcm/pcm.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm.c Tue Mar 13 02:52:33 2007 +0100 @@ -6313,15 +6313,6 @@ snd_pcm_sframes_t snd_pcm_mmap_commit(sn } #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) { diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_dmix.c --- a/src/pcm/pcm_dmix.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_dmix.c Tue Mar 13 02:52:33 2007 +0100 @@ -757,8 +757,8 @@ static snd_pcm_fast_ops_t snd_pcm_dmix_f .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, diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_dshare.c --- a/src/pcm/pcm_dshare.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_dshare.c Tue Mar 13 02:52:33 2007 +0100 @@ -562,8 +562,8 @@ static snd_pcm_fast_ops_t snd_pcm_dshare .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, diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_dsnoop.c --- a/src/pcm/pcm_dsnoop.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_dsnoop.c Tue Mar 13 02:52:33 2007 +0100 @@ -452,8 +452,8 @@ static snd_pcm_fast_ops_t snd_pcm_dsnoop .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, diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_file.c --- a/src/pcm/pcm_file.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_file.c Tue Mar 13 02:52:33 2007 +0100 @@ -373,8 +373,8 @@ static snd_pcm_fast_ops_t snd_pcm_file_f .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, diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_generic.c --- a/src/pcm/pcm_generic.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_generic.c Tue Mar 13 02:52:33 2007 +0100 @@ -197,14 +197,6 @@ snd_pcm_sframes_t snd_pcm_generic_rewind 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; @@ -213,44 +205,12 @@ int snd_pcm_generic_link(snd_pcm_t *pcm1 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) diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_generic.h --- a/src/pcm/pcm_generic.h Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_generic.h Tue Mar 13 02:52:33 2007 +0100 @@ -50,9 +50,8 @@ int snd_pcm_generic_delay(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); diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_hooks.c --- a/src/pcm/pcm_hooks.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_hooks.c Tue Mar 13 02:52:33 2007 +0100 @@ -151,8 +151,8 @@ static snd_pcm_fast_ops_t snd_pcm_hooks_ .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, diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_hw.c --- a/src/pcm/pcm_hw.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_hw.c Tue Mar 13 02:52:33 2007 +0100 @@ -686,41 +686,35 @@ static int snd_pcm_hw_resume(snd_pcm_t * return 0; } -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; - - if (count < 1) +static int hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) +{ + 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; +} + +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; - } - } - } - return err; -} + if (pcm2->type != SND_PCM_TYPE_HW) { + if (pcm2->fast_ops->link_slaves) + return pcm2->fast_ops->link_slaves(pcm2, pcm1); + return -ENOSYS; + } + return hw_link(pcm1, pcm2); + } static int snd_pcm_hw_unlink(snd_pcm_t *pcm) { @@ -1045,8 +1039,8 @@ static snd_pcm_fast_ops_t snd_pcm_hw_fas .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, diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_ioplug.c --- a/src/pcm/pcm_ioplug.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_ioplug.c Tue Mar 13 02:52:33 2007 +0100 @@ -747,8 +747,8 @@ static snd_pcm_fast_ops_t snd_pcm_ioplug .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, diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_local.h --- a/src/pcm/pcm_local.h Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_local.h Tue Mar 13 02:52:33 2007 +0100 @@ -152,8 +152,8 @@ typedef struct { 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); diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_multi.c --- a/src/pcm/pcm_multi.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_multi.c Tue Mar 13 02:52:33 2007 +0100 @@ -45,7 +45,7 @@ typedef struct { snd_pcm_t *pcm; unsigned int channels_count; int close_slave; - int linked; + snd_pcm_t *linked; } snd_pcm_multi_slave_t; typedef struct { @@ -57,7 +57,6 @@ 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; @@ -314,6 +313,21 @@ static int snd_pcm_multi_hw_params_slave 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; @@ -331,12 +345,7 @@ static int snd_pcm_multi_hw_params(snd_p 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; } @@ -352,10 +361,10 @@ static int snd_pcm_multi_hw_free(snd_pcm 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; } @@ -421,7 +430,7 @@ static int snd_pcm_multi_prepare(snd_pcm 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. @@ -429,75 +438,83 @@ static int snd_pcm_multi_prepare(snd_pcm */ err = snd_pcm_prepare(multi->slaves[i].pcm); if (err < 0) - return err; - } - return err; + result = 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) + result = 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; + err = snd_pcm_start(multi->slaves[i].pcm); if (err < 0) return err; } return err; } -static int snd_pcm_multi_start(snd_pcm_t *pcm) +static int snd_pcm_multi_drop(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_drop(multi->slaves[0].linked); for (i = 0; i < multi->slaves_count; ++i) { if (multi->slaves[i].linked) continue; - err = snd_pcm_start(multi->slaves[i].pcm); + err = snd_pcm_drop(multi->slaves[i].pcm); if (err < 0) return err; } return err; } -static int snd_pcm_multi_drop(snd_pcm_t *pcm) +static int snd_pcm_multi_drain(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_drain(multi->slaves[0].linked); for (i = 0; i < multi->slaves_count; ++i) { if (multi->slaves[i].linked) continue; - err = snd_pcm_drop(multi->slaves[i].pcm); + err = snd_pcm_drain(multi->slaves[i].pcm); if (err < 0) return err; } return err; } -static int snd_pcm_multi_drain(snd_pcm_t *pcm) +static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable) { snd_pcm_multi_t *multi = pcm->private_data; int err = 0; unsigned int i; - for (i = 0; i < multi->slaves_count; ++i) { - if (multi->slaves[i].linked) - continue; - err = snd_pcm_drain(multi->slaves[i].pcm); - if (err < 0) - return err; - } - return err; -} - -static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable) -{ - 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; @@ -587,6 +604,8 @@ static int snd_pcm_multi_resume(snd_pcm_ 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; @@ -597,46 +616,42 @@ static int snd_pcm_multi_resume(snd_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)) +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; - - if (count < (int)multi->slaves_count) - return -ENOMEM; + unsigned int i, j; + int err; + + for (i = 0; i < multi->slaves_count; ++i) { + 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(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) +{ + 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); - 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_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; + snd_pcm_unlink(multi->slaves[i].linked); + multi->slaves[0].linked = NULL; } return 0; } @@ -727,8 +742,8 @@ static snd_pcm_fast_ops_t snd_pcm_multi_ .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, diff -r 78c78fa6c41d -r 4883f0ba21df src/pcm/pcm_plugin.c --- a/src/pcm/pcm_plugin.c Tue Mar 13 00:40:22 2007 +0100 +++ b/src/pcm/pcm_plugin.c Tue Mar 13 02:52:33 2007 +0100 @@ -566,8 +566,8 @@ snd_pcm_fast_ops_t snd_pcm_plugin_fast_o .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, ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.sourceforge.net/lists/listinfo/alsa-devel