All of lore.kernel.org
 help / color / mirror / Atom feed
* pcm_multi broken in alsa-lib - no duplex mode with jackd
@ 2007-03-08 17:16 Simon Lewis
  2007-03-08 17:22 ` Lee Revell
                   ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Simon Lewis @ 2007-03-08 17:16 UTC (permalink / raw)
  To: alsa-devel

Dear ALSA Developers

When I attempted to combine several device drivers using the pcm_multi
function in .asound.conf I learned the hardway that pcm_multi doesn't
work in duplex mode with jackd. Apparently pcm_multi was broken in
alsa-lib 1.0.9rc1 and has never been fixed.

Many JACK users have successfully used the following patch:

http://www.sound-man.co.uk/linuxaudio/pcm_multi-patch

I have since learned that many studio64 users have been bitten by this bug.

Please, please, please add the above patch to version 1.014 of ALSA libs
before they are finally released as stable.


With many thanks, Simon.


-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-08 17:16 pcm_multi broken in alsa-lib - no duplex mode with jackd Simon Lewis
@ 2007-03-08 17:22 ` Lee Revell
  2007-03-08 18:58 ` Takashi Iwai
  2007-03-08 19:02 ` John Rigg
  2 siblings, 0 replies; 19+ messages in thread
From: Lee Revell @ 2007-03-08 17:22 UTC (permalink / raw)
  To: simon.lewis; +Cc: alsa-devel

On 3/8/07, Simon Lewis <simon.lewis@mnet-online.de> wrote:
> Many JACK users have successfully used the following patch:
>
> http://www.sound-man.co.uk/linuxaudio/pcm_multi-patch
>
> I have since learned that many studio64 users have been bitten by this bug.
>
> Please, please, please add the above patch to version 1.014 of ALSA libs
> before they are finally released as stable.

+1

*Something* has to be done about this issue ASAP.  I don't think it's
valid to blame JACK because the code worked perfectly until alsa-lib
was changed.

Lee

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-08 17:16 pcm_multi broken in alsa-lib - no duplex mode with jackd Simon Lewis
  2007-03-08 17:22 ` Lee Revell
@ 2007-03-08 18:58 ` Takashi Iwai
  2007-03-08 21:51   ` John Rigg
  2007-03-09  0:57   ` pcm_multi broken in alsa-lib - no duplex mode with jackd Lee Revell
  2007-03-08 19:02 ` John Rigg
  2 siblings, 2 replies; 19+ messages in thread
From: Takashi Iwai @ 2007-03-08 18:58 UTC (permalink / raw)
  To: simon.lewis; +Cc: alsa-devel

At Thu, 08 Mar 2007 18:16:02 +0100,
Simon Lewis wrote:
> 
> Dear ALSA Developers
> 
> When I attempted to combine several device drivers using the pcm_multi
> function in .asound.conf I learned the hardway that pcm_multi doesn't
> work in duplex mode with jackd. Apparently pcm_multi was broken in
> alsa-lib 1.0.9rc1 and has never been fixed.
> 
> 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.

> I have since learned that many studio64 users have been bitten by this bug.
> 
> Please, please, please add the above patch to version 1.014 of ALSA libs
> before they are finally released as stable.

I just thought this bug got fixed long time ago as I haven't seen
often on this list for long time...  Pinging here is often the best
way to trigger bug fixing.


Takashi

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-08 17:16 pcm_multi broken in alsa-lib - no duplex mode with jackd Simon Lewis
  2007-03-08 17:22 ` Lee Revell
  2007-03-08 18:58 ` Takashi Iwai
@ 2007-03-08 19:02 ` John Rigg
  2 siblings, 0 replies; 19+ messages in thread
From: John Rigg @ 2007-03-08 19:02 UTC (permalink / raw)
  To: alsa-devel

On Thu, Mar 08, 2007 at 06:16:02PM +0100, Simon Lewis wrote:
> Dear ALSA Developers
> 
> When I attempted to combine several device drivers using the pcm_multi
> function in .asound.conf I learned the hardway that pcm_multi doesn't
> work in duplex mode with jackd. Apparently pcm_multi was broken in
> alsa-lib 1.0.9rc1 and has never been fixed.
> 
> Many JACK users have successfully used the following patch:
> 
> http://www.sound-man.co.uk/linuxaudio/pcm_multi-patch
> 
> I have since learned that many studio64 users have been bitten by this bug.
> 
> Please, please, please add the above patch to version 1.014 of ALSA libs
> before they are finally released as stable.

vote ++1

There are actually quite a few of us using multi-card setups
for high channel counts these days. The extra linking code
added to pcm_multi.c in 1.0.9rc1 stopped this from working
with jackd (which anybody using a Linux system as a serious
audio workstation will be using). I haven't noticed any problem
caused by removing it, and I've done many hours of multitrack
recording since then.

John

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-08 18:58 ` Takashi Iwai
@ 2007-03-08 21:51   ` John Rigg
  2007-03-09 16:38     ` Takashi Iwai
  2007-03-09  0:57   ` pcm_multi broken in alsa-lib - no duplex mode with jackd Lee Revell
  1 sibling, 1 reply; 19+ messages in thread
From: John Rigg @ 2007-03-08 21:51 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

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.
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.

John

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-08 18:58 ` Takashi Iwai
  2007-03-08 21:51   ` John Rigg
@ 2007-03-09  0:57   ` Lee Revell
  1 sibling, 0 replies; 19+ messages in thread
From: Lee Revell @ 2007-03-09  0:57 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

On 3/8/07, Takashi Iwai <tiwai@suse.de> 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.

I think ALSA should have the same policy as the kernel - that any
change which breaks existing apps must be considered a regression,
even if the change is a bug fix.  So if the real fix can't be found,
the change that broke JACK must be reverted.

What bug was the change that broke JACK supposed to fix?

Lee

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-08 21:51   ` John Rigg
@ 2007-03-09 16:38     ` Takashi Iwai
  2007-03-09 17:02       ` Achim_Kuntz
                         ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Takashi Iwai @ 2007-03-09 16:38 UTC (permalink / raw)
  To: John Rigg; +Cc: alsa-devel

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.

> 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.


thanks,

Takashi

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-09 16:38     ` Takashi Iwai
@ 2007-03-09 17:02       ` Achim_Kuntz
  2007-03-10 14:17       ` John Rigg
  2007-03-11 18:33       ` pcm_multi broken in alsa-lib - no duplex mode Simon Lewis
  2 siblings, 0 replies; 19+ messages in thread
From: Achim_Kuntz @ 2007-03-09 17:02 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

on 03/09/2007 05:38 PM, Takashi Iwai wrote:
...
> 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.
> 
> 
> thanks,
> 
> Takashi
> 
You can find a description and some discussion here:
http://thread.gmane.org/gmane.comp.audio.jackit/12096
http://thread.gmane.org/gmane.linux.alsa.devel/29213

Thanks for tackling this problem!
--Achim

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-09 16:38     ` Takashi Iwai
  2007-03-09 17:02       ` Achim_Kuntz
@ 2007-03-10 14:17       ` John Rigg
  2007-03-12 23:46         ` Takashi Iwai
  2007-03-11 18:33       ` pcm_multi broken in alsa-lib - no duplex mode Simon Lewis
  2 siblings, 1 reply; 19+ messages in thread
From: John Rigg @ 2007-03-10 14:17 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

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

John

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode
  2007-03-09 16:38     ` Takashi Iwai
  2007-03-09 17:02       ` Achim_Kuntz
  2007-03-10 14:17       ` John Rigg
@ 2007-03-11 18:33       ` Simon Lewis
  2007-03-12 11:44         ` Takashi Iwai
  2 siblings, 1 reply; 19+ messages in thread
From: Simon Lewis @ 2007-03-11 18:33 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

Dear Takashi

I think I have another pointer which may help solve this problem.

The libasound.so.2.0.0 compiled using the pcm_multi in alsa-lib-1.0.13
has a compiled size of 719.6 kB on openSUSE 10.2.

The patched pcm_multi (that is the unlinked version from
alsa-lib-1.0.8)  has a complied size of 2.6 MB.

To my naive way of thinking, the current pcm_multi forgets to compile
63% of the code..!


Further, no complicated hardware is needed to test the pcm_multi in
duplex mode.

Any sound card can be used that has an alsa-driver similar to ca0106
whereby the surround sound outputs are assigned to two or more devices -
each device being a stereo pair. Use the function type "multi" in
asound.conf to combine all the devices back to one virtual hardware and
then try using the "combined" virtual driver in duplex mode, e.g from
QJackCtl.


Best reagrds, Simon



Takashi Iwai schrieb:
> 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.
>
>   
>> 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.
>
>
> thanks,
>
> Takashi
>
>
>   


-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode
  2007-03-11 18:33       ` pcm_multi broken in alsa-lib - no duplex mode Simon Lewis
@ 2007-03-12 11:44         ` Takashi Iwai
  0 siblings, 0 replies; 19+ messages in thread
From: Takashi Iwai @ 2007-03-12 11:44 UTC (permalink / raw)
  To: simon.lewis; +Cc: alsa-devel

At Sun, 11 Mar 2007 19:33:37 +0100,
Simon Lewis wrote:
> 
> Dear Takashi
> 
> I think I have another pointer which may help solve this problem.
> 
> The libasound.so.2.0.0 compiled using the pcm_multi in alsa-lib-1.0.13
> has a compiled size of 719.6 kB on openSUSE 10.2.
> 
> The patched pcm_multi (that is the unlinked version from
> alsa-lib-1.0.8)  has a complied size of 2.6 MB.
> 
> To my naive way of thinking, the current pcm_multi forgets to compile
> 63% of the code..!

Did you count debuginfo?


Takashi

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-10 14:17       ` John Rigg
@ 2007-03-12 23:46         ` Takashi Iwai
  2007-03-13  2:01           ` Takashi Iwai
  0 siblings, 1 reply; 19+ messages in thread
From: Takashi Iwai @ 2007-03-12 23:46 UTC (permalink / raw)
  To: John Rigg; +Cc: alsa-devel

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...


Takashi


diff -r 7d4862b9780b src/pcm/pcm_multi.c
--- a/src/pcm/pcm_multi.c	Mon Mar 12 08:27:15 2007 +0100
+++ b/src/pcm/pcm_multi.c	Tue Mar 13 00:33:24 2007 +0100
@@ -621,7 +621,8 @@ static int snd_pcm_multi_link_fd(snd_pcm
 		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;
+		if (i > 0)
+			multi->slaves[i].linked = 1;
 	}
 	*failed = snd_pcm_multi_link_fd_failed;
 	return multi->slaves_count;

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-12 23:46         ` Takashi Iwai
@ 2007-03-13  2:01           ` Takashi Iwai
  2007-03-13  2:07             ` Takashi Iwai
                               ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Takashi Iwai @ 2007-03-13  2:01 UTC (permalink / raw)
  To: John Rigg; +Cc: alsa-devel

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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-13  2:01           ` Takashi Iwai
@ 2007-03-13  2:07             ` Takashi Iwai
  2007-03-13  9:05             ` Simon Lewis
  2007-03-13 15:34             ` John Rigg
  2 siblings, 0 replies; 19+ messages in thread
From: Takashi Iwai @ 2007-03-13  2:07 UTC (permalink / raw)
  To: John Rigg; +Cc: alsa-devel

At Tue, 13 Mar 2007 03:01:17 +0100,
I wrote:
> 
> 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.)

BTW, while debugging this, I found some potential problems in the
current alsa support in JACK:

- The arguments of snd_pcm_link() is master, slave.  And, the master
  PCM should be used as a trigger.  In the case of JACK, it should
  call like snd_pcm_link(playback_handle, capture_handle).
 
- Mangles of poll revents are sometimes needed (e.g. dmix) by calling
  snd_pcm_poll_descriptor_revents() after poll.  JACK might work
  without this, though, because it checks only revents !=0 or not.
  Once if it checks the direction (IN/OUT), there could be a problem.


Takashi

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-13  2:01           ` Takashi Iwai
  2007-03-13  2:07             ` Takashi Iwai
@ 2007-03-13  9:05             ` Simon Lewis
  2007-03-13  9:18               ` Takashi Iwai
  2007-03-13 15:34             ` John Rigg
  2 siblings, 1 reply; 19+ messages in thread
From: Simon Lewis @ 2007-03-13  9:05 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

Dear Takashi

Can I use the two patchs with alsa-lib 1.0.13 ?

If yes, please let me know the terminal commands assuming that I have
already cd'ed into the unpacked alsa-lib folder.

Many thanks, Simon


Takashi Iwai schrieb:
> 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@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/alsa-devel
>
>
>   


-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-13  9:05             ` Simon Lewis
@ 2007-03-13  9:18               ` Takashi Iwai
  2007-03-14 18:41                 ` Simon Lewis
  0 siblings, 1 reply; 19+ messages in thread
From: Takashi Iwai @ 2007-03-13  9:18 UTC (permalink / raw)
  To: simon.lewis; +Cc: alsa-devel

At Tue, 13 Mar 2007 10:05:06 +0100,
Simon Lewis wrote:
> 
> Dear Takashi
> 
> Can I use the two patchs with alsa-lib 1.0.13 ?

Might work, but don't try.  It simply increases another unknown
factors.  First try the latest HG version with the patch to confirm
that it works.  After that, try any version you like.

> If yes, please let me know the terminal commands assuming that I have
> already cd'ed into the unpacked alsa-lib folder.

	% patch -p1 -i this_patch

In doubt, wait until tomorrow, then grab the latest daily snapshot
tarball from 
	ftp://ftp.suse.com/pub/projects/alsa/snapshot/

which will include the all patches.


Takashi
> 
> 
> Takashi Iwai schrieb:
> > 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@lists.sourceforge.net
> > https://lists.sourceforge.net/lists/listinfo/alsa-devel
> >
> >
> >   
> 

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-13  2:01           ` Takashi Iwai
  2007-03-13  2:07             ` Takashi Iwai
  2007-03-13  9:05             ` Simon Lewis
@ 2007-03-13 15:34             ` John Rigg
  2 siblings, 0 replies; 19+ messages in thread
From: John Rigg @ 2007-03-13 15:34 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

On Tue, Mar 13, 2007 at 03:01:17AM +0100, Takashi Iwai wrote:
> More complete fix is below.  Apply after the previous patch.
> (Or more easily use the HG version.)

Both patches work with alsa-lib-1.0.13. I'll have to upgrade to
latest code to test it properly but too busy today (hope
to try in next few days). It looks good so far!

Thanks,
John

-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: pcm_multi broken in alsa-lib - no duplex mode with jackd
  2007-03-13  9:18               ` Takashi Iwai
@ 2007-03-14 18:41                 ` Simon Lewis
  0 siblings, 0 replies; 19+ messages in thread
From: Simon Lewis @ 2007-03-14 18:41 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

Nice one Takashi!

I tested the new alsa-lib snapshot on a  "virgin" openSUSE 10.2 today.
Jack started with no errors in duplex mode with my sound card using
separate pcm_multi functions to group the inputs and outputs respectively.

Naturally John Rigg and the others at Jack-Devel will test the
corrections more thoroughly but for me at least it appears to be working
fine.

Best regards, Simon

Simon Lewis
Lautensackstrasse 12
80687 München

Tel.: +49 89 57869412
Fax: +49 89 57869411
e-mail: simon.lewis@mnet-online.de

Takashi Iwai wrote:
> At Tue, 13 Mar 2007 10:05:06 +0100,
> Simon Lewis wrote:
>   
>> Dear Takashi
>>
>> Can I use the two patchs with alsa-lib 1.0.13 ?
>>     
>
> Might work, but don't try.  It simply increases another unknown
> factors.  First try the latest HG version with the patch to confirm
> that it works.  After that, try any version you like.
>
>   
>> If yes, please let me know the terminal commands assuming that I have
>> already cd'ed into the unpacked alsa-lib folder.
>>     
>
> 	% patch -p1 -i this_patch
>
> In doubt, wait until tomorrow, then grab the latest daily snapshot
> tarball from 
> 	ftp://ftp.suse.com/pub/projects/alsa/snapshot/
>
> which will include the all patches.
>
>
> Takashi
>   
>> Takashi Iwai schrieb:
>>     
>>> 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@lists.sourceforge.net
>>> https://lists.sourceforge.net/lists/listinfo/alsa-devel
>>>
>>>
>>>   
>>>       
>
>
>   


-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* pcm_multi broken in alsa-lib - no duplex mode with jackd
@ 2007-03-08 17:17 Simon Lewis
  0 siblings, 0 replies; 19+ messages in thread
From: Simon Lewis @ 2007-03-08 17:17 UTC (permalink / raw)
  To: alsa-devel

Dear ALSA Developers

When I attempted to combine several device drivers using the pcm_multi
function in .asound.conf I learned the hardway that pcm_multi doesn't
work in duplex mode with jackd. Apparently pcm_multi was broken in
alsa-lib 1.0.9rc1 and has never been fixed.

Many JACK users have successfully used the following patch:

http://www.sound-man.co.uk/linuxaudio/pcm_multi-patch

I have since learned that many studio64 users have been bitten by this bug.

Please, please, please add the above patch to version 1.014 of ALSA libs
before they are finally released as stable.


With many thanks, Simon.



-------------------------------------------------------------------------
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

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2007-03-14 18:41 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-03-08 17:16 pcm_multi broken in alsa-lib - no duplex mode with jackd Simon Lewis
2007-03-08 17:22 ` Lee Revell
2007-03-08 18:58 ` Takashi Iwai
2007-03-08 21:51   ` John Rigg
2007-03-09 16:38     ` Takashi Iwai
2007-03-09 17:02       ` Achim_Kuntz
2007-03-10 14:17       ` John Rigg
2007-03-12 23:46         ` Takashi Iwai
2007-03-13  2:01           ` Takashi Iwai
2007-03-13  2:07             ` Takashi Iwai
2007-03-13  9:05             ` Simon Lewis
2007-03-13  9:18               ` Takashi Iwai
2007-03-14 18:41                 ` Simon Lewis
2007-03-13 15:34             ` John Rigg
2007-03-11 18:33       ` pcm_multi broken in alsa-lib - no duplex mode Simon Lewis
2007-03-12 11:44         ` Takashi Iwai
2007-03-09  0:57   ` pcm_multi broken in alsa-lib - no duplex mode with jackd Lee Revell
2007-03-08 19:02 ` John Rigg
2007-03-08 17:17 Simon Lewis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.