All of lore.kernel.org
 help / color / mirror / Atom feed
* M-Audio FTU issues
@ 2011-06-24  1:14 Daniel Mack
  2011-06-24  3:27 ` Grant Diffey
                   ` (3 more replies)
  0 siblings, 4 replies; 24+ messages in thread
From: Daniel Mack @ 2011-06-24  1:14 UTC (permalink / raw)
  To: Aurélien Leblond; +Cc: alsa-devel, Felix Homann

So, I've looked into this today and as expected, the device normally
operates in implicit feedback mode. After installing a proprietary
driver on Mac OS X (that regularily crashed my kernel), the analyzer
shows that for every inbound packet, an out packet is sent back with
the same amount of data in it. And there are no feedback endpoints.


On Tue, Jun 14, 2011 at 11:21 AM, Aurélien Leblond <blablack@gmail.com> wrote:
> There are still the issue of samples dropping.
>
> Tto reproduce it:
> - Open Audacity and set it up to be using Jack.
> - Click Generate -> Tone -> Ok.
>
> "Normally" you should hear very regular pops...
>

What surprises me though, is that I can't hear the clicks and pops you
guys describe. Instead, I hear a quite annoying distortion for both
44100 and 48000 Hz which I can't explain either. My spontanous guess
is that there is a resampler in the chain which compensates the sample
drift and notably reduces the audio quality.

I patched the driver so that it supports implicit feedback, but that
didn't change anything in that regard.

Hence my question is: How do you guys test? I renderened a sine tone
in different samplerates and bit depths to .wav files and play them
with aplay (no pulseaudio or anything in the chain). Could you try the
same and report what happens?


Daniel

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

* Re: M-Audio FTU issues
  2011-06-24  1:14 M-Audio FTU issues Daniel Mack
@ 2011-06-24  3:27 ` Grant Diffey
  2011-06-24  7:35 ` Felix Homann
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 24+ messages in thread
From: Grant Diffey @ 2011-06-24  3:27 UTC (permalink / raw)
  To: Daniel Mack; +Cc: Aurélien Leblond, alsa-devel, Felix Homann

On Fri, Jun 24, 2011 at 11:14 AM, Daniel Mack <zonque@gmail.com> wrote:

> So, I've looked into this today and as expected, the device normally
> operates in implicit feedback mode. After installing a proprietary
> driver on Mac OS X (that regularily crashed my kernel), the analyzer
> shows that for every inbound packet, an out packet is sent back with
> the same amount of data in it. And there are no feedback endpoints.
>
>
> yeah m-audio can't write software or design hardware we know ;)



> On Tue, Jun 14, 2011 at 11:21 AM, Aurélien Leblond <blablack@gmail.com>
> wrote:
> > There are still the issue of samples dropping.
> >
> > Tto reproduce it:
> > - Open Audacity and set it up to be using Jack.
> > - Click Generate -> Tone -> Ok.
> >
> > "Normally" you should hear very regular pops...
> >
>
> What surprises me though, is that I can't hear the clicks and pops you
> guys describe. Instead, I hear a quite annoying distortion for both
> 44100 and 48000 Hz which I can't explain either. My spontanous guess
> is that there is a resampler in the chain which compensates the sample
> drift and notably reduces the audio quality.
>
>
eww that's uncool.

Silly question In the mac controlcentre ensure you've turned off/bypassed
the reverb/dsp capabilities?

I've previously replicated this with audacity and jack. (at 24bit 96kHz) but
when I get home I'll give aplay a go after generating the sine.

I'll see if I can capture it and make some waveform's or something and I've
tested my other usb soundcard and it doesn't have the clicking.

Grant.



> Daniel
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>

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

* Re: M-Audio FTU issues
  2011-06-24  1:14 M-Audio FTU issues Daniel Mack
  2011-06-24  3:27 ` Grant Diffey
@ 2011-06-24  7:35 ` Felix Homann
  2011-06-24  8:52 ` Felix Homann
  2011-06-24  9:08 ` Felix Homann
  3 siblings, 0 replies; 24+ messages in thread
From: Felix Homann @ 2011-06-24  7:35 UTC (permalink / raw)
  To: Daniel Mack; +Cc: Aurélien Leblond, alsa-devel

[-- Attachment #1: Type: text/plain, Size: 2190 bytes --]

Hi Daniel,


Am 24.06.2011 03:14, schrieb Daniel Mack:
> So, I've looked into this today and as expected, the device normally
> operates in implicit feedback mode. After installing a proprietary
> driver on Mac OS X (that regularily crashed my kernel), the analyzer
> shows that for every inbound packet, an out packet is sent back with
> the same amount of data in it. And there are no feedback endpoints.

Thank you very much!


>
> What surprises me though, is that I can't hear the clicks and pops you
> guys describe. Instead, I hear a quite annoying distortion for both
> 44100 and 48000 Hz which I can't explain either.

As Grant wrote, I only experienced something like this when I accidently 
had turned on some reverb effects in the Windows control center. But if 
it sounds as if the output was completely "chopped" then it would rather 
remind me of the days when it only worked at 48/96 kHz and I tried 
playing back at 44.1/88.2 kHz.

> I patched the driver so that it supports implicit feedback, but that
> didn't change anything in that regard.

Great, that you could already do the implicit feedback part! (BTW, don't 
hesitate to send me early experimental patches.)


> Hence my question is: How do you guys test?

I'm usually using puredata for this. I've attached the very simple pd 
file. I've always tested with JACK, never with ALSA directly. But as I 
said earlier: If I boot an old kernel with "initial support" (i.e. the 
one using just QUIRK_AUDIO_STANDARD_INTERFACE; only working at 48/96 
kHz) the clicks go away. Hence it doesn't seem related to using JACK. 
(Using my internal soundcard I don't hear clicks using pd/JACK either).

I even "ported" back the initial support to a current kernel a month or 
so ago and could reliably switch between "Clicks at all sampliing rates" 
and "No clicks at 48/96 kHz; kernel crash at 44.1/88.2 kHz".

Initially though I generated a sine in audacity, too.

>   I renderened a sine tone
> in different samplerates and bit depths to .wav files and play them
> with aplay (no pulseaudio or anything in the chain). Could you try the
> same and report what happens?

I will try this morning and report.

Kind regards,

Felix

[-- Attachment #2: pd-sine.pd --]
[-- Type: text/plain, Size: 96 bytes --]

#N canvas 736 426 450 300 10;
#X obj 150 143 dac~;
#X obj 87 60 osc~ 10000;
#X connect 1 0 0 0;

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



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

* Re: M-Audio FTU issues
  2011-06-24  1:14 M-Audio FTU issues Daniel Mack
  2011-06-24  3:27 ` Grant Diffey
  2011-06-24  7:35 ` Felix Homann
@ 2011-06-24  8:52 ` Felix Homann
  2011-06-24 15:23   ` Daniel Mack
  2011-06-24  9:08 ` Felix Homann
  3 siblings, 1 reply; 24+ messages in thread
From: Felix Homann @ 2011-06-24  8:52 UTC (permalink / raw)
  To: Daniel Mack; +Cc: Aurélien Leblond, alsa-devel

[-- Attachment #1: Type: text/plain, Size: 1326 bytes --]

Hi again,

Am 24.06.2011 03:14, schrieb Daniel Mack:
>
> Hence my question is: How do you guys test? I renderened a sine tone
> in different samplerates and bit depths to .wav files and play them
> with aplay (no pulseaudio or anything in the chain). Could you try the
> same and report what happens?
>


OK, I've rendered a sine to a .wav (well, in audacity), played it via 
aplay on the FTU8R and could hear the clicks. I've been using plughw 
though, cause I don't remember right now how to convert bit-depths.

I even played sines directly from puredata and audacity without JACK and 
could still hear the clicks.

Please, make sure you have the routing "diagonal", i.e. "DIn i - Out j" 
is set to 0% if i !=j and 100% if i == j. I've attached a small bash 
script to accomplish this. After plugging the device in all playback 
volumes are initially at 100%. I could not notice the clicks then unless 
it turned the volume very very loud (I guess aplay plays back on all 
channels, which blurs the clicks).

If you still can't hear the clicks please try using a headphone? 
Sometimes the clicks are hardly noticable when there's minimal 
background noise. You might even have turn the volume higher than 
convenient for your ears...

I hope this helps hearing the clicks using the unmodified driver.

Kind regards,

Felix

[-- Attachment #2: ftu-diagonal-routing.sh --]
[-- Type: application/x-shellscript, Size: 371 bytes --]

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



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

* Re: M-Audio FTU issues
  2011-06-24  1:14 M-Audio FTU issues Daniel Mack
                   ` (2 preceding siblings ...)
  2011-06-24  8:52 ` Felix Homann
@ 2011-06-24  9:08 ` Felix Homann
  3 siblings, 0 replies; 24+ messages in thread
From: Felix Homann @ 2011-06-24  9:08 UTC (permalink / raw)
  To: Daniel Mack; +Cc: Aurélien Leblond, alsa-devel

[I've received an Attachement Blocking Notification for the below 
message. Since I don't know if it was blocked for all recipients this is 
the same mail without the attachement.]


Hi again,

Am 24.06.2011 03:14, schrieb Daniel Mack:
>
> Hence my question is: How do you guys test? I renderened a sine tone
> in different samplerates and bit depths to .wav files and play them
> with aplay (no pulseaudio or anything in the chain). Could you try the
> same and report what happens?
>


OK, I've rendered a sine to a .wav (well, in audacity), played it via 
aplay on the FTU8R and could hear the clicks. I've been using plughw 
though, cause I don't remember right now how to convert bit-depths.

I even played sines directly from puredata and audacity without JACK and 
could still hear the clicks.

Please, make sure you have the routing "diagonal", i.e. "DIn i - Out j" 
is set to 0% if i !=j and 100% if i == j. I've attached a small bash 
script to accomplish this. After plugging the device in all playback 
volumes are initially at 100%. I could not notice the clicks then unless 
it turned the volume very very loud (I guess aplay plays back on all 
channels, which blurs the clicks).

If you still can't hear the clicks please try using a headphone? 
Sometimes the clicks are hardly noticable when there's minimal 
background noise. You might even have turn the volume higher than 
convenient for your ears...

I hope this helps hearing the clicks using the unmodified driver.

Kind regards,

Felix

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

* Re: M-Audio FTU issues
  2011-06-24  8:52 ` Felix Homann
@ 2011-06-24 15:23   ` Daniel Mack
  2011-06-24 15:58     ` Clemens Ladisch
  2011-06-27  8:52     ` Felix Homann
  0 siblings, 2 replies; 24+ messages in thread
From: Daniel Mack @ 2011-06-24 15:23 UTC (permalink / raw)
  To: Felix Homann
  Cc: Takashi Iwai, Aurélien Leblond, alsa-devel, Clemens Ladisch,
	Grant Diffey

[-- Attachment #1: Type: text/plain, Size: 3450 bytes --]

On Fri, Jun 24, 2011 at 10:52 AM, Felix Homann <linuxaudio@showlabor.de> wrote:
> Please, make sure you have the routing "diagonal", i.e. "DIn i - Out j" is
> set to 0% if i !=j and 100% if i == j. I've attached a small bash script to
> accomplish this. After plugging the device in all playback volumes are
> initially at 100%. I could not notice the clicks then unless it turned the
> volume very very loud (I guess aplay plays back on all channels, which blurs
> the clicks).

Thanks, that helped. It was indeed the mixer settings that caused the
distortion and hid the streaming errors. I can now hear the clicks
with the current mainline driver.

Attached is a preliminary patch that implements implicit feedback
mode, and it works fine for the playback channel (without any clicks
now). However, there are still some corner cases that need attention,
and currently, the kernel crashes when you start playback and capture
streams at the same time. So please don't use it in full-duplex more
for now, you have been warned.


I've investigated in many ways to implement this nicely, but it's
quite tricky as it breaks the current driver layout in multiple ways,
regardless which way I go.

These were the approaches:

1. Like I posted last year, I wanted to just collect the number of
received frames when capturing data and modify
snd_audio_next_packet_size() so that it approximates to the number of
samples received in the record stream. This didn't work as easily
because the streaming loop ended up queueing 0-byte packets which the
hardware doesn't like at all. It will stop streaming and won't recover
after the first empty packet was sent. Hence, sending data at a fix
urb rate seems no way to go, at least for the FTU.

2. I tried to treat the record stream as sync endpoint and trick
around with the callbacks for sync urbs, but that breaks several
assumptions made in the code all over, mostly regarding the maximum
packet size.

3. The most promising approach (the one implemented in the attached
patch) splits the urb's size calculation from the actual ops.prepare()
handler and re-uses the ops.prepare() from a new function called
queue_next_out_urb(). For this, our complete_urb function must be
modified to not automatically requeue the next out urb but leave it to
the capture stream's retire callbacks when to fire the next out packet
(and here, we will ignore 0-byte input packets and not send out 0-byte
out urbs). A new counter variable (next_out_urb) is needed for that.

The problem, however, is that we now have to check when to actually
start and stop the capture stream:

- We have to start it (and put it to pause mode) once the playback
starts and switch over to the real callback once the user starts the
capture PCM stream
- We also have to start it if the user only wants to capture PCM,
without playback.
- We can stop it if the user was only using capture PCM or playback PCM streams.
- But we cannot stop it if it still serves as feedback source for a
running playback PCM.


I started to implement some logic for this, but I'm not really happy
with it yet. Some reference counting would be much better than what I
currently have, but I don't see a good solution yet. Maybe I've been
looking at this for too long now, and someone else has an idea?

I have a split version of this patchset here locally, but I think the
consolidated version is easier to test for now.

Feedback more than welcome.


Thanks,
Daniel

[-- Attachment #2: ftu.diff --]
[-- Type: application/octet-stream, Size: 22595 bytes --]

diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 0fd3fbd..0f138de 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -377,6 +377,11 @@ struct usb_endpoint_descriptor {
 #define USB_ENDPOINT_NUMBER_MASK	0x0f	/* in bEndpointAddress */
 #define USB_ENDPOINT_DIR_MASK		0x80
 
+#define USB_ENDPOINT_USAGE_MASK		0x30
+#define USB_ENDPOINT_USAGE_DATA		0x00
+#define USB_ENDPOINT_USAGE_FEEDBACK	0x10
+#define USB_ENDPOINT_USAGE_IMPLICIT_FB	0x20	/* Implicit feedback Data endpoint */
+
 #define USB_ENDPOINT_SYNCTYPE		0x0c
 #define USB_ENDPOINT_SYNC_NONE		(0 << 2)
 #define USB_ENDPOINT_SYNC_ASYNC		(1 << 2)
diff --git a/sound/usb/card.h b/sound/usb/card.h
index ae4251d..b9ba132 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -3,7 +3,7 @@
 
 #define MAX_PACKS	20
 #define MAX_PACKS_HS	(MAX_PACKS * 8)	/* in high speed mode */
-#define MAX_URBS	8
+#define MAX_URBS	16
 #define SYNC_URBS	4	/* always four urbs for sync */
 #define MAX_QUEUE	24	/* try not to exceed this queue length, in ms */
 
@@ -36,9 +36,11 @@ struct snd_urb_ctx {
 	struct snd_usb_substream *subs;
 	int index;	/* index for urb array */
 	int packets;	/* number of packets per urb */
+	int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */
 };
 
 struct snd_urb_ops {
+	int (*prepare_size)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
 	int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
 	int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
 	int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
@@ -73,6 +75,8 @@ struct snd_usb_substream {
 	unsigned int fill_max: 1;	/* fill max packet size always */
 	unsigned int txfr_quirk:1;	/* allow sub-frame alignment */
 	unsigned int fmt_type;		/* USB audio format type (1-3) */
+	unsigned int next_out_urb;	/* index of next URB to use for output
+					   (implicit feedback mode only) */
 
 	unsigned int running: 1;	/* running status */
 
@@ -103,6 +107,8 @@ struct snd_usb_stream {
 	unsigned int fmt_type;		/* USB audio format type (1-3) */
 	struct snd_usb_substream substream[2];
 	struct list_head list;
+	unsigned int implicit_feedback: 1; 	/* stream uses its capture data
+						   substream to clock its playback substream */
 };
 
 #endif /* __USBAUDIO_CARD_H */
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index b8dcbf4..1cd1db2 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -185,7 +185,8 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
 /*
  * find a matching format and set up the interface
  */
-static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
+int snd_usb_set_pcm_format(struct snd_usb_substream *subs,
+			   struct audioformat *fmt)
 {
 	struct usb_device *dev = subs->dev;
 	struct usb_host_interface *alts;
@@ -206,6 +207,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
 	if (fmt == subs->cur_audiofmt)
 		return 0;
 
+printk(KERN_ERR "%s() :%d\n", __func__, __LINE__);
+
 	/* close the old interface */
 	if (subs->interface >= 0 && subs->interface != fmt->iface) {
 		if (usb_set_interface(subs->dev, subs->interface, 0) < 0) {
@@ -292,6 +295,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
 	if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX)
 		subs->fill_max = 1;
 
+	if (!is_playback &&
+	    (fmt->ep_attr & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC &&
+	    (fmt->ep_attr & USB_ENDPOINT_USAGE_MASK) == USB_ENDPOINT_USAGE_IMPLICIT_FB)
+		subs->stream->implicit_feedback = 1;
+
 	if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0)
 		return err;
 
@@ -299,6 +307,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
 
 	snd_usb_set_format_quirk(subs, fmt);
 
+	if (subs->stream->implicit_feedback)
+		snd_printk(KERN_INFO "operating in implicit feedback mode\n");
+
 #if 0
 	printk(KERN_DEBUG
 	       "setting done: format = %d, rate = %d..%d, channels = %d\n",
@@ -347,7 +358,16 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 	changed = subs->cur_audiofmt != fmt ||
 		subs->period_bytes != params_period_bytes(hw_params) ||
 		subs->cur_rate != rate;
-	if ((ret = set_format(subs, fmt)) < 0)
+
+	if (subs->stream->implicit_feedback) {
+		struct snd_usb_substream *other =
+			&subs->stream->substream[!subs->direction];
+
+		if (other && other->running && changed)
+			return -EBUSY;
+	}
+
+	if ((ret = snd_usb_set_pcm_format(subs, fmt)) < 0)
 		return ret;
 
 	if (subs->cur_rate != rate) {
@@ -815,6 +835,9 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
 	struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
 	struct snd_usb_substream *subs = &as->substream[direction];
 
+	if (snd_usb_capture_subs_used_by_playback(subs))
+		return 0;
+
 	if (!as->chip->shutdown && subs->interface >= 0) {
 		usb_set_interface(subs->dev, subs->interface, 0);
 		subs->interface = -1;
diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h
index ed3e283..9e02cf8 100644
--- a/sound/usb/pcm.h
+++ b/sound/usb/pcm.h
@@ -3,6 +3,9 @@
 
 void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream);
 
+int snd_usb_set_pcm_format(struct snd_usb_substream *subs,
+			   struct audioformat *fmt);
+
 int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
 		       struct usb_host_interface *alts,
 		       struct audioformat *fmt);
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 090e193..1353663 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -644,6 +644,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
 	case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */
 		set_format_emu_quirk(subs, fmt);
 		break;
+	case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
+	case USB_ID(0x0763, 0x2081):
+		subs->stream->implicit_feedback = 1;
+		break;
 	}
 }
 
diff --git a/sound/usb/urb.c b/sound/usb/urb.c
index e184349..3b7a81b 100644
--- a/sound/usb/urb.c
+++ b/sound/usb/urb.c
@@ -29,6 +29,25 @@
 #include "urb.h"
 #include "pcm.h"
 
+/* Streaming modes
+ *
+ * This driver can operate in different streaming modes which use the internal
+ * functions of this file differently.
+ *
+ * One is independent input and output streaming which is the default and most
+ * usual for USB audio devices. IN endpoints (device sinks) can either take any
+ * amount of data that is sent or provide a sync endpoint to tell the host at
+ * which data rate the stream runs at. This streaming model allows playback and
+ * capture streams to be started independently.
+ *
+ * The other is an 'implicit feedback mode' in which the device does not tell
+ * the host its speed through an sync endpoint but expects the driver to always
+ * receive the record stream and use the data rate to determine the actual
+ * device speed. For the USB side, this means that the driver has to queue
+ * capture URBs even if the userspace is not interested in actual capture data.
+ *
+ */
+
 /*
  * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
  * this will overflow at approx 524 kHz
@@ -135,10 +154,26 @@ static int wait_clear_urbs(struct snd_usb_substream *subs)
 		schedule_timeout_uninterruptible(1);
 	} while (time_before(jiffies, end_time));
 	if (alive)
-		snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
+		snd_printk(KERN_ERR "timeout: still %d active urbs (%s)\n",
+			   alive, subs->direction == SNDRV_PCM_STREAM_CAPTURE ?
+						"capture" : "playback");
 	return 0;
 }
 
+int snd_usb_capture_subs_used_by_playback(struct snd_usb_substream *capture)
+{
+	struct snd_usb_stream *stream = capture->stream;
+	struct snd_usb_substream *playback = &stream->substream[SNDRV_PCM_STREAM_PLAYBACK];
+
+	if (!playback)
+		return 0;
+
+	if (capture->direction != SNDRV_PCM_STREAM_CAPTURE)
+		return 0;
+
+	return stream->implicit_feedback && playback->running;
+}
+
 /*
  * release a substream
  */
@@ -146,6 +181,9 @@ void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
 {
 	int i;
 
+	if (snd_usb_capture_subs_used_by_playback(subs))
+		return;
+
 	/* stop urbs (to be sure) */
 	deactivate_urbs(subs, force, 1);
 	wait_clear_urbs(subs);
@@ -168,17 +206,34 @@ static void snd_complete_urb(struct urb *urb)
 	struct snd_urb_ctx *ctx = urb->context;
 	struct snd_usb_substream *subs = ctx->subs;
 	struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
+	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
 	int err = 0;
 
 	if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
-	    !subs->running || /* can be stopped during retire callback */
-	    (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
-	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
-		clear_bit(ctx->index, &subs->active_mask);
-		if (err < 0) {
-			snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
-			snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-		}
+	    !subs->running /* can be stopped during retire callback */)
+		goto exit_clear_bit;
+
+	/*
+	 * For devices that operate in implicit feedback mode, we won't requeue
+	 * the URB at this point. Instead, we will wait for the next record
+	 * input packet to arrive and queue a packet from the corresponding
+	 * retire callback.
+	 */
+	if (is_playback && subs->stream->implicit_feedback)
+		goto exit_clear_bit;
+
+	if ((err = subs->ops.prepare(subs, substream->runtime, urb)) == 0 &&
+	    (err = subs->ops.prepare_size(subs, substream->runtime, urb)) == 0 &&
+	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0)
+		return;
+
+	/* fall through */
+
+exit_clear_bit:
+	clear_bit(ctx->index, &subs->active_mask);
+	if (err < 0) {
+		snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
 	}
 }
 
@@ -250,7 +305,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
 	else
 		packs_per_ms = 1;
 
-	if (is_playback) {
+	if (is_playback && !subs->stream->implicit_feedback) {
 		urb_packs = max(chip->nrpacks, 1);
 		urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
 	} else
@@ -260,7 +315,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
 		urb_packs = min(urb_packs, 1U << subs->syncinterval);
 
 	/* decide how many packets to be used */
-	if (is_playback) {
+	if (is_playback && !subs->stream->implicit_feedback) {
 		unsigned int minsize, maxpacks;
 		/* determine how small a packet can be */
 		minsize = (subs->freqn >> (16 - subs->datainterval))
@@ -320,6 +375,9 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
 		u->urb->complete = snd_complete_urb;
 	}
 
+	if (subs->stream->implicit_feedback)
+		subs->syncpipe = 0;
+
 	if (subs->syncpipe) {
 		/* allocate and initialize sync urbs */
 		subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4,
@@ -410,6 +468,15 @@ static int retire_capture_sync_urb(struct snd_usb_substream *subs,
 }
 
 /*
+ * prepare data sizes for caputure urbs. nothing to do. */
+static int prepare_capture_size_urb(struct snd_usb_substream *subs,
+				    struct snd_pcm_runtime *runtime,
+				    struct urb *urb)
+{
+	return 0;
+}
+
+/*
  * prepare urb for capture data pipe
  *
  * fill the offset and length of each descriptor.
@@ -438,11 +505,93 @@ static int prepare_capture_urb(struct snd_usb_substream *subs,
 	return 0;
 }
 
+static int queue_next_playback_urb(struct snd_usb_substream *capture,
+				   struct snd_pcm_runtime *runtime,
+				   struct urb *in_urb)
+{
+	unsigned int stride = runtime->frame_bits >> 3;
+	unsigned int bytes = 0, i;
+	unsigned long flags;
+	struct snd_urb_ctx *in_ctx = in_urb->context;
+	struct snd_usb_substream *playback =
+		&capture->stream->substream[SNDRV_PCM_STREAM_PLAYBACK];
+	struct snd_urb_ctx *out_ctx;
+	struct urb *out_urb;
+	int err;
+
+	/* this may happen during substream transitions */
+	if (stride == 0)
+		return 0;
+
+	if (!playback->running)
+		return 0;
+
+	/* Count overall packet size */
+	for (i = 0; i < in_ctx->packets; i++)
+		if (in_urb->iso_frame_desc[i].status == 0)
+			bytes += in_urb->iso_frame_desc[i].actual_length;
+
+	/* skip empty packets. At least M-Audio's Fast Track Ultra stops
+	 * streaming once it received a 0-byte OUT URB */
+	if (bytes == 0)
+		return 0;
+
+	spin_lock_irqsave(&capture->lock, flags);
+	out_ctx = &playback->dataurb[playback->next_out_urb];
+	spin_unlock_irqrestore(&capture->lock, flags);
+
+	out_urb = out_ctx->urb;
+
+	/* If the output urb is still in use, we have to drop this packet.
+	 * This usually only occurs when the stream is starting */
+	if (test_bit(out_ctx->index, &playback->active_mask))
+		return 0;
+
+	/*
+	 * Iterate through the inbound packet and prepare the lengths
+	 * for output packets. The OUT packet we are about to send will
+	 * have the same amount of payload than the IN packet we just
+	 * received.
+	 */
+
+	out_ctx->packets = in_ctx->packets;
+	for (i = 0; i < in_ctx->packets; i++) {
+		if (in_urb->iso_frame_desc[i].status == 0)
+			out_ctx->packet_size[i] =
+				in_urb->iso_frame_desc[i].actual_length / stride;
+		else
+			out_ctx->packet_size[i] = 0;
+	}
+
+	err = playback->ops.prepare(playback, playback->pcm_substream->runtime, out_urb);
+	if (err < 0)
+		return err;
+
+	err = usb_submit_urb(out_urb, GFP_ATOMIC);
+	if (err < 0) {
+		snd_printk(KERN_ERR "%s(): Unable to submit urb #%d: %d\n",
+				__func__, out_ctx->index, err);
+		snd_pcm_stop(capture->pcm_substream, SNDRV_PCM_STATE_XRUN);
+		snd_pcm_stop(playback->pcm_substream, SNDRV_PCM_STATE_XRUN);
+		return err;
+	} else {
+		spin_lock_irqsave(&capture->lock, flags);
+		set_bit(out_ctx->index, &playback->active_mask);
+		playback->next_out_urb++;
+		playback->next_out_urb %= playback->nurbs;
+		spin_unlock_irqrestore(&capture->lock, flags);
+	}
+
+	return 0;
+}
+
 /*
  * process after capture complete
  *
  * copy the data from each desctiptor to the pcm buffer, and
  * update the current position.
+ *
+ * For implicit feedback mode, eventually call queue_next_playback_urb().
  */
 static int retire_capture_urb(struct snd_usb_substream *subs,
 			      struct snd_pcm_runtime *runtime,
@@ -499,16 +648,24 @@ static int retire_capture_urb(struct snd_usb_substream *subs,
 	}
 	if (period_elapsed)
 		snd_pcm_period_elapsed(subs->pcm_substream);
+
+	if (subs->stream->implicit_feedback)
+		return queue_next_playback_urb(subs, runtime, urb);
+
 	return 0;
 }
 
 /*
- * Process after capture complete when paused.  Nothing to do.
+ * Process after capture complete when paused.
+ * For implicit feedback mode, eventually call queue_next_playback_urb().
  */
 static int retire_paused_capture_urb(struct snd_usb_substream *subs,
 				     struct snd_pcm_runtime *runtime,
 				     struct urb *urb)
 {
+	if (subs->stream->implicit_feedback)
+		return queue_next_playback_urb(subs, runtime, urb);
+
 	return 0;
 }
 
@@ -615,6 +772,25 @@ static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
 }
 
 /*
+ * Prepare urb data sizes for asynchronous output streaming.
+ * This is seperated from the code that fills the data because syncronous
+ * streaming (in implicit feedback mode) uses a different method to determine
+ * the output data packet sizes.
+ */
+static int prepare_playback_size_urb(struct snd_usb_substream *subs,
+				     struct snd_pcm_runtime *runtime,
+				     struct urb *urb)
+{
+	int i;
+	struct snd_urb_ctx *ctx = urb->context;
+
+	for (i = 0; i < ctx->packets; ++i)
+		ctx->packet_size[i] = snd_usb_audio_next_packet_size(subs);
+
+	return 0;
+}
+
+/*
  * Prepare urb for streaming before playback starts or when paused.
  *
  * We don't have any data, so we send silence.
@@ -630,7 +806,7 @@ static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
 	offs = 0;
 	urb->dev = ctx->subs->dev;
 	for (i = 0; i < ctx->packets; ++i) {
-		counts = snd_usb_audio_next_packet_size(subs);
+		counts = ctx->packet_size[i];
 		urb->iso_frame_desc[i].offset = offs * stride;
 		urb->iso_frame_desc[i].length = counts * stride;
 		offs += counts;
@@ -668,7 +844,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
 	urb->number_of_packets = 0;
 	spin_lock_irqsave(&subs->lock, flags);
 	for (i = 0; i < ctx->packets; i++) {
-		counts = snd_usb_audio_next_packet_size(subs);
+		counts = ctx->packet_size[i];
 		/* set up descriptor */
 		urb->iso_frame_desc[i].offset = frames * stride;
 		urb->iso_frame_desc[i].length = counts * stride;
@@ -786,6 +962,10 @@ static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *ru
 	for (i = 0; i < subs->nurbs; i++) {
 		if (snd_BUG_ON(!subs->dataurb[i].urb))
 			return -EINVAL;
+		if (subs->ops.prepare_size(subs, runtime, subs->dataurb[i].urb) < 0) {
+			snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
+			goto __error;
+		}
 		if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
 			snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
 			goto __error;
@@ -805,6 +985,7 @@ static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *ru
 	subs->active_mask = 0;
 	subs->unlink_mask = 0;
 	subs->running = 1;
+
 	for (i = 0; i < subs->nurbs; i++) {
 		err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
 		if (err < 0) {
@@ -840,12 +1021,14 @@ static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *ru
  */
 static struct snd_urb_ops audio_urb_ops[2] = {
 	{
+		.prepare_size =	prepare_playback_size_urb,
 		.prepare =	prepare_nodata_playback_urb,
 		.retire =	retire_playback_urb,
 		.prepare_sync =	prepare_playback_sync_urb,
 		.retire_sync =	retire_playback_sync_urb,
 	},
 	{
+		.prepare_size =	prepare_capture_size_urb,
 		.prepare =	prepare_capture_urb,
 		.retire =	retire_capture_urb,
 		.prepare_sync =	prepare_capture_sync_urb,
@@ -892,6 +1075,18 @@ int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int
 		subs->ops.prepare = prepare_playback_urb;
 		return 0;
 	case SNDRV_PCM_TRIGGER_STOP:
+		if (subs->stream->implicit_feedback) {
+			struct snd_usb_substream *capture =
+				&subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE];
+			if (capture &&
+			    capture->pcm_substream &&
+			    capture->pcm_substream->runtime) {
+				struct snd_pcm_runtime *runtime =
+					capture->pcm_substream->runtime;
+				if (runtime->status->state != SNDRV_PCM_STATE_OPEN)
+					deactivate_urbs(capture, 0, 0);
+			}
+		}
 		return deactivate_urbs(subs, 0, 0);
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		subs->ops.prepare = prepare_nodata_playback_urb;
@@ -908,8 +1103,15 @@ int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int c
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		subs->ops.retire = retire_capture_urb;
-		return start_urbs(subs, substream->runtime);
+		if (!subs->running)
+			return start_urbs(subs, substream->runtime);
+
+		return 0;
 	case SNDRV_PCM_TRIGGER_STOP:
+		if (snd_usb_capture_subs_used_by_playback(subs)) {
+			subs->ops.retire = retire_paused_capture_urb;
+			return 0;
+		}
 		return deactivate_urbs(subs, 0, 0);
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		subs->ops.retire = retire_paused_capture_urb;
@@ -922,18 +1124,90 @@ int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int c
 	return -EINVAL;
 }
 
+/*
+ * Fake a start for the capture stream.
+ * Only used for implicit feedback mode.
+ */
+static int start_capture_stream(struct snd_usb_substream *playback,
+				struct snd_usb_substream *capture,
+				struct snd_pcm_runtime *runtime)
+{
+	int err;
+
+
+usb_set_interface(capture->dev, 2, 1);
+
+	capture->ops.prepare = prepare_capture_urb;
+	capture->ops.retire = retire_paused_capture_urb;
+	capture->pcm_substream = playback->pcm_substream;
+	err = snd_usb_set_pcm_format(capture, playback->cur_audiofmt);
+	if (err)
+		return err;
+
+	err = snd_usb_init_substream_urbs(capture, playback->period_bytes,
+					  playback->cur_rate,
+					  (playback->curpacksize /
+					   playback->curframesize) * 8);
+	if (err)
+		return err;
+
+	return start_urbs(capture, runtime);
+}
+
 int snd_usb_substream_prepare(struct snd_usb_substream *subs,
 			      struct snd_pcm_runtime *runtime)
 {
 	/* clear urbs (to be sure) */
-	deactivate_urbs(subs, 0, 1);
-	wait_clear_urbs(subs);
+	if (!snd_usb_capture_subs_used_by_playback(subs)) {
+		deactivate_urbs(subs, 0, 1);
+		wait_clear_urbs(subs);
+	}
 
-	/* for playback, submit the URBs now; otherwise, the first hwptr_done
-	 * updates for all URBs would happen at the same time when starting */
 	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
 		subs->ops.prepare = prepare_nodata_playback_urb;
-		return start_urbs(subs, runtime);
+
+		if (subs->stream->implicit_feedback) {
+			struct snd_usb_substream *capture =
+				&subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE];
+
+			if (!capture) {
+				snd_printk(KERN_ERR "Unable to start implicit feedback mode "
+					   "without capture stream\n");
+				return -EINVAL;
+			}
+
+			/*
+			 * Mark the stream running without calling start_urbs().
+			 * We don't want to queue any URBs yet at this point
+			 */
+			subs->active_mask = 0;
+			subs->unlink_mask = 0;
+			subs->running = 1;
+
+			/*
+			 * if this stream is in implicit feedback mode, start the
+			 * capture stream now as the playback stream relies on the
+			 * amount of data we see on the capture IN endpoint.
+			 */
+			if (!capture->running) {
+				int err = start_capture_stream(subs, capture, runtime);
+				if (err < 0) {
+					deactivate_urbs(subs, 0, 0);
+					return err;
+				}
+			}
+		} else {
+			/*
+			 * For playback, submit the URBs now; otherwise, the
+			 * first hwptr_done updates for all URBs would happen
+			 * at the same time when starting.
+			 * However, don't start the stream here if we are in
+			 * implicit feedback stream mode - all OUT URBs will
+			 * be queued once data is received on the IN endpooint
+			 * in this case.
+			 */
+			return start_urbs(subs, runtime);
+		}
 	}
 
 	return 0;
diff --git a/sound/usb/urb.h b/sound/usb/urb.h
index 888da38..593a9e1 100644
--- a/sound/usb/urb.h
+++ b/sound/usb/urb.h
@@ -17,5 +17,6 @@ int snd_usb_substream_prepare(struct snd_usb_substream *subs,
 
 int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
 int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
+int snd_usb_capture_subs_used_by_playback(struct snd_usb_substream *substream);
 
 #endif /* __USBAUDIO_URB_H */

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



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

* Re: M-Audio FTU issues
  2011-06-24 15:23   ` Daniel Mack
@ 2011-06-24 15:58     ` Clemens Ladisch
  2011-06-24 16:10       ` Daniel Mack
  2011-06-27  8:52     ` Felix Homann
  1 sibling, 1 reply; 24+ messages in thread
From: Clemens Ladisch @ 2011-06-24 15:58 UTC (permalink / raw)
  To: Daniel Mack
  Cc: alsa-devel, =?UTF-8?B?QXVyw6lsaWVuIExlYmxv?=,
	Takashi Iwai, Grant Diffey, Felix Homann, nd

Daniel Mack wrote:
> 1. Like I posted last year, I wanted to just collect the number of
> received frames when capturing data and modify
> snd_audio_next_packet_size() so that it approximates to the number of
> samples received in the record stream. This didn't work as easily
> because the streaming loop ended up queueing 0-byte packets which the
> hardware doesn't like at all. It will stop streaming and won't recover
> after the first empty packet was sent.

There are other devices with the same bug.

> 3. The most promising approach (the one implemented in the attached
> patch) splits the urb's size calculation from the actual ops.prepare()
> handler and re-uses the ops.prepare() from a new function called
> queue_next_out_urb(). For this, our complete_urb function must be
> modified to not automatically requeue the next out urb but leave it to
> the capture stream's retire callbacks when to fire the next out packet
> (and here, we will ignore 0-byte input packets and not send out 0-byte
> out urbs). A new counter variable (next_out_urb) is needed for that.
> 
> The problem, however, is that we now have to check when to actually
> start and stop the capture stream:
> 
> - We have to start it (and put it to pause mode) once the playback
> starts and switch over to the real callback once the user starts the
> capture PCM stream
> - We also have to start it if the user only wants to capture PCM,
> without playback.
> - We can stop it if the user was only using capture PCM or playback PCM streams.
> - But we cannot stop it if it still serves as feedback source for a
> running playback PCM.

The same logic is implemented in ua101.c.

> I started to implement some logic for this, but I'm not really happy
> with it yet. Some reference counting would be much better than what I
> currently have, but I don't see a good solution yet. Maybe I've been
> looking at this for too long now, and someone else has an idea?

The overall structure of the code handling the PCM streams becomes
different: not only must the starting/stopping of the USB capture stream
be decoupled from the ALSA stream, but the handling of audio formats and
URB buffers changes because capturing can be started before the ALSA PCM
capture stream is configured.

I think the best solution would be to move the USB streaming into
a module, add implicit feedback support there, and create a separate
driver for the FTU and similar devices.  (I'm doing this for FireWire
streaming right now, and always wanted to do the same for USB.  Many
thanks for volunteering!  :-)


Regards,
Clemens

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

* Re: M-Audio FTU issues
  2011-06-24 15:58     ` Clemens Ladisch
@ 2011-06-24 16:10       ` Daniel Mack
  2011-06-28 20:37         ` Aurélien Leblond
  2011-07-25 13:07         ` Clemens Ladisch
  0 siblings, 2 replies; 24+ messages in thread
From: Daniel Mack @ 2011-06-24 16:10 UTC (permalink / raw)
  To: Clemens Ladisch
  Cc: Takashi Iwai, Aurélien Leblond, alsa-devel, Grant Diffey,
	Felix Homann

On Fri, Jun 24, 2011 at 5:58 PM, Clemens Ladisch <clemens@ladisch.de> wrote:
> Daniel Mack wrote:
>> I started to implement some logic for this, but I'm not really happy
>> with it yet. Some reference counting would be much better than what I
>> currently have, but I don't see a good solution yet. Maybe I've been
>> looking at this for too long now, and someone else has an idea?
>
> The overall structure of the code handling the PCM streams becomes
> different: not only must the starting/stopping of the USB capture stream
> be decoupled from the ALSA stream, but the handling of audio formats and
> URB buffers changes because capturing can be started before the ALSA PCM
> capture stream is configured.

Yes, I've seen this, too.

> I think the best solution would be to move the USB streaming into
> a module, add implicit feedback support there, and create a separate
> driver for the FTU and similar devices.  (I'm doing this for FireWire
> streaming right now, and always wanted to do the same for USB.  Many
> thanks for volunteering!  :-)

Can you outline how the API will look like?

However, I'm not sure whether making a special driver for the FTU is
really the way to go. Even though I haven't seen any device around yet
that implements this in a class-compliant way, this type of streaming
model is in fact part of the USB Audio specification, at least in
version 2. It's more than likely that there will be more devices
around in the future, and so it would be good to have support for it
in the standard driver.

Could you outline how you would do the decoupling?


Thanks,
Daniel

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

* Re: M-Audio FTU issues
  2011-06-24 15:23   ` Daniel Mack
  2011-06-24 15:58     ` Clemens Ladisch
@ 2011-06-27  8:52     ` Felix Homann
  1 sibling, 0 replies; 24+ messages in thread
From: Felix Homann @ 2011-06-27  8:52 UTC (permalink / raw)
  To: Daniel Mack; +Cc: alsa-devel

Hi Daniel,

just a quick note to confirm that the clicks are gone at all sampling 
rates with your patch applied. Thanks!

Am 24.06.2011 17:23, schrieb Daniel Mack:
> the kernel crashes when you start playback and capture
> streams at the same time.

Yes, that's true ;-)

Regards,

Felix

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

* Re: M-Audio FTU issues
  2011-06-24 16:10       ` Daniel Mack
@ 2011-06-28 20:37         ` Aurélien Leblond
  2011-06-29  8:08           ` Daniel Mack
  2011-07-25 13:07         ` Clemens Ladisch
  1 sibling, 1 reply; 24+ messages in thread
From: Aurélien Leblond @ 2011-06-28 20:37 UTC (permalink / raw)
  To: Daniel Mack
  Cc: Takashi Iwai, alsa-devel, Grant Diffey, Clemens Ladisch, Felix Homann

Hi Daniel,

All clicks gone as Felix already said :)

And confirmed, the kernel crashed with playback and capture streams
started at the same time :)

Aurélien

On Fri, Jun 24, 2011 at 5:10 PM, Daniel Mack <zonque@gmail.com> wrote:
> On Fri, Jun 24, 2011 at 5:58 PM, Clemens Ladisch <clemens@ladisch.de> wrote:
>> Daniel Mack wrote:
>>> I started to implement some logic for this, but I'm not really happy
>>> with it yet. Some reference counting would be much better than what I
>>> currently have, but I don't see a good solution yet. Maybe I've been
>>> looking at this for too long now, and someone else has an idea?
>>
>> The overall structure of the code handling the PCM streams becomes
>> different: not only must the starting/stopping of the USB capture stream
>> be decoupled from the ALSA stream, but the handling of audio formats and
>> URB buffers changes because capturing can be started before the ALSA PCM
>> capture stream is configured.
>
> Yes, I've seen this, too.
>
>> I think the best solution would be to move the USB streaming into
>> a module, add implicit feedback support there, and create a separate
>> driver for the FTU and similar devices.  (I'm doing this for FireWire
>> streaming right now, and always wanted to do the same for USB.  Many
>> thanks for volunteering!  :-)
>
> Can you outline how the API will look like?
>
> However, I'm not sure whether making a special driver for the FTU is
> really the way to go. Even though I haven't seen any device around yet
> that implements this in a class-compliant way, this type of streaming
> model is in fact part of the USB Audio specification, at least in
> version 2. It's more than likely that there will be more devices
> around in the future, and so it would be good to have support for it
> in the standard driver.
>
> Could you outline how you would do the decoupling?
>
>
> Thanks,
> Daniel
>

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

* Re: M-Audio FTU issues
  2011-06-28 20:37         ` Aurélien Leblond
@ 2011-06-29  8:08           ` Daniel Mack
  2011-07-03 11:52             ` Grant Diffey
  0 siblings, 1 reply; 24+ messages in thread
From: Daniel Mack @ 2011-06-29  8:08 UTC (permalink / raw)
  To: Aurélien Leblond
  Cc: Takashi Iwai, alsa-devel, Grant Diffey, Clemens Ladisch, Felix Homann

On Tue, Jun 28, 2011 at 10:37 PM, Aurélien Leblond <blablack@gmail.com> wrote:
> Hi Daniel,
>
> All clicks gone as Felix already said :)

Good.

> And confirmed, the kernel crashed with playback and capture streams
> started at the same time :)

I'd like to discuss the API for the ALSA/USB decoupling as suggested
by Clemens, which will solve this problem then.

Thanks,
Daniel

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

* Re: M-Audio FTU issues
  2011-06-29  8:08           ` Daniel Mack
@ 2011-07-03 11:52             ` Grant Diffey
  2011-07-04 17:14               ` Aurélien Leblond
                                 ` (3 more replies)
  0 siblings, 4 replies; 24+ messages in thread
From: Grant Diffey @ 2011-07-03 11:52 UTC (permalink / raw)
  To: Daniel Mack
  Cc: Takashi Iwai, Aurélien Leblond, alsa-devel, Clemens Ladisch,
	Felix Homann

>
> On Tue, Jun 28, 2011 at 10:37 PM, Aurélien Leblond <blablack@gmail.com>
> wrote:
> > Hi Daniel,
> >
> > All clicks gone as Felix already said :)
>
> Good.
>
>

So it works. yay


> > And confirmed, the kernel crashed with playback and capture streams
> > started at the same time :)
>
> I'd like to discuss the API for the ALSA/USB decoupling as suggested
> by Clemens, which will solve this problem then.
>

Nobody has any ideas what this interface might look like?

>From what I understand this would lead to re-unifying the ua101 driver into
snd-usb-audio as well?

Grant

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

* Re: M-Audio FTU issues
  2011-07-03 11:52             ` Grant Diffey
@ 2011-07-04 17:14               ` Aurélien Leblond
  2011-07-04 17:23               ` Daniel Mack
                                 ` (2 subsequent siblings)
  3 siblings, 0 replies; 24+ messages in thread
From: Aurélien Leblond @ 2011-07-04 17:14 UTC (permalink / raw)
  To: Grant Diffey
  Cc: Takashi Iwai, alsa-devel, Clemens Ladisch, Felix Homann, Daniel Mack

On Sun, Jul 3, 2011 at 12:52 PM, Grant Diffey <gdiffey@gmail.com> wrote:
>> On Tue, Jun 28, 2011 at 10:37 PM, Aurélien Leblond <blablack@gmail.com>
>> wrote:
>> > Hi Daniel,
>> >
>> > All clicks gone as Felix already said :)
>>
>> Good.
>>
>
> So it works. yay

The main bug which was samples being dropped is fixed (thanks to
Daniel), as long as the playback and capture streams are not started
at the same time.

>> > And confirmed, the kernel crashed with playback and capture streams
>> > started at the same time :)
>>
>> I'd like to discuss the API for the ALSA/USB decoupling as suggested
>> by Clemens, which will solve this problem then.
>
>
> Nobody has any ideas what this interface might look like?
>
> From what I understand this would lead to re-unifying the ua101 driver into
> snd-usb-audio as well?

Looks like the general consensus is that more and more of these type
of USB sound card will come up,
so it might not be the best to create a specific driver for the FTU.

To be honest, Daniel would be the best to answer the question (as he's
the only one with the knowledge and the device!).

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

* Re: M-Audio FTU issues
  2011-07-03 11:52             ` Grant Diffey
  2011-07-04 17:14               ` Aurélien Leblond
@ 2011-07-04 17:23               ` Daniel Mack
  2011-07-13 21:18               ` Juan Pablo Bouza
  2011-07-21  5:08               ` Juan Pablo Bouza
  3 siblings, 0 replies; 24+ messages in thread
From: Daniel Mack @ 2011-07-04 17:23 UTC (permalink / raw)
  To: Grant Diffey
  Cc: Takashi Iwai, Aurélien Leblond, alsa-devel, Clemens Ladisch,
	Felix Homann

On Sun, Jul 3, 2011 at 1:52 PM, Grant Diffey <gdiffey@gmail.com> wrote:
>> I'd like to discuss the API for the ALSA/USB decoupling as suggested
>> by Clemens, which will solve this problem then.
>
>
> Nobody has any ideas what this interface might look like?
>
> From what I understand this would lead to re-unifying the ua101 driver into
> snd-usb-audio as well?

As I've said, my understanding of the USB audio standard covers a
feedback model for which the capture stream implicitly defines the
pace the driver is supposed to deliver audio samples to the playback
endpoint (most devices do have sync endpoint for that). Considering
that, there might be more devices coming up which do it that way, and
we should have support for this model in the generic driver IMO.

So at least, my patch shows that it's not too hard to support it, and
we just need a way to sort out how to incorporate the new logic in a
way that it doesn't break the concept of the generic driver. Let me
think about it for some more days. In the meantime, it sounded like
Clemens already brooded on that topic for FireWire devices, and it
might make sense to benefit from the results (and keep the API
similar).


Daniel

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

* Re: M-Audio FTU issues
  2011-07-03 11:52             ` Grant Diffey
  2011-07-04 17:14               ` Aurélien Leblond
  2011-07-04 17:23               ` Daniel Mack
@ 2011-07-13 21:18               ` Juan Pablo Bouza
  2011-07-21  5:08               ` Juan Pablo Bouza
  3 siblings, 0 replies; 24+ messages in thread
From: Juan Pablo Bouza @ 2011-07-13 21:18 UTC (permalink / raw)
  To: alsa-devel


Hi! Sorry for the dull question, but I'm new to this mailing list and to alsa development in general.
I was looking for the latest patch for the FTU, can anyone send me the link to it, or point me out to a location where alsa patches are stored?

Thanks!


> Date: Sun, 3 Jul 2011 21:52:06 +1000
> From: gdiffey@gmail.com
> To: zonque@gmail.com
> CC: tiwai@suse.de; blablack@gmail.com; alsa-devel@alsa-project.org; clemens@ladisch.de; linuxaudio@showlabor.de
> Subject: Re: [alsa-devel] M-Audio FTU issues
> 
> >
> > On Tue, Jun 28, 2011 at 10:37 PM, Aurélien Leblond <blablack@gmail.com>
> > wrote:
> > > Hi Daniel,
> > >
> > > All clicks gone as Felix already said :)
> >
> > Good.
> >
> >
> 
> So it works. yay
> 
> 
> > > And confirmed, the kernel crashed with playback and capture streams
> > > started at the same time :)
> >
> > I'd like to discuss the API for the ALSA/USB decoupling as suggested
> > by Clemens, which will solve this problem then.
> >
> 
> Nobody has any ideas what this interface might look like?
> 
> From what I understand this would lead to re-unifying the ua101 driver into
> snd-usb-audio as well?
> 
> Grant
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
 		 	   		  

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

* Re: M-Audio FTU issues
  2011-07-03 11:52             ` Grant Diffey
                                 ` (2 preceding siblings ...)
  2011-07-13 21:18               ` Juan Pablo Bouza
@ 2011-07-21  5:08               ` Juan Pablo Bouza
  2011-07-21  7:55                 ` Daniel Mack
  3 siblings, 1 reply; 24+ messages in thread
From: Juan Pablo Bouza @ 2011-07-21  5:08 UTC (permalink / raw)
  To: gdiffey, zonque; +Cc: tiwai, blablack, alsa-devel, clemens, linuxaudio


Hi! I've patched kernel 3 rc7 and playback does not work...

Capture works perfectly fine.

Playback does not work with alsa apps  or with jack. 

 This is my /proc/asound/cards output

 0 [SB             ]: HDA-Intel - HDA ATI SB
                      HDA ATI SB at 0xf9ff4000 irq 16
 1 [Ultra          ]: USB-Audio - Fast Track Ultra
                      M-Audio Fast Track Ultra at usb-0000:00:13.5-1, high speed


This is what happens when trying to playback a sound file with aplay -D plughw:Ultra /media/Edipo/Triangulo/Hadas\ por\ ahora.mp3 

Playing raw data '/media/Edipo/Triangulo/Hadas por ahora.mp3' : Unsigned 8 bit, Rate 8000 Hz, Mono
aplay: set_params:1137: Unable to install hw params:
ACCESS:  RW_INTERLEAVED
FORMAT:  U8
SUBFORMAT:  STD
SAMPLE_BITS: 8
FRAME_BITS: 8
CHANNELS: 1
RATE: 8000
PERIOD_TIME: 125000
PERIOD_SIZE: 1000
PERIOD_BYTES: 1000
PERIODS: 4
BUFFER_TIME: 500000
BUFFER_SIZE: 4000
BUFFER_BYTES: 4000
TICK_TIME: 0

Is there any extra option I need to activate in the kernel in order to make playback work?

I compiled the kernel without the patch and I do have playback, so my conclusion is that the problem is with the patch applied

Thanks!

PS: just to make sure, this is the patch I applied:

diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 0fd3fbd..0f138de 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -377,6 +377,11 @@ struct usb_endpoint_descriptor {
 #define USB_ENDPOINT_NUMBER_MASK    0x0f    /* in bEndpointAddress */
 #define USB_ENDPOINT_DIR_MASK        0x80
 
+#define USB_ENDPOINT_USAGE_MASK        0x30
+#define USB_ENDPOINT_USAGE_DATA        0x00
+#define USB_ENDPOINT_USAGE_FEEDBACK    0x10
+#define USB_ENDPOINT_USAGE_IMPLICIT_FB    0x20    /* Implicit feedback Data endpoint */
+
 #define USB_ENDPOINT_SYNCTYPE        0x0c
 #define USB_ENDPOINT_SYNC_NONE        (0 << 2)
 #define USB_ENDPOINT_SYNC_ASYNC        (1 << 2)
diff --git a/sound/usb/card.h b/sound/usb/card.h
index ae4251d..b9ba132 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -3,7 +3,7 @@
 
 #define MAX_PACKS    20
 #define MAX_PACKS_HS    (MAX_PACKS * 8)    /* in high speed mode */
-#define MAX_URBS    8
+#define MAX_URBS    16
 #define SYNC_URBS    4    /* always four urbs for sync */
 #define MAX_QUEUE    24    /* try not to exceed this queue length, in ms */
 
@@ -36,9 +36,11 @@ struct snd_urb_ctx {
     struct snd_usb_substream *subs;
     int index;    /* index for urb array */
     int packets;    /* number of packets per urb */
+    int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */
 };
 
 struct snd_urb_ops {
+    int (*prepare_size)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
     int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
     int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
     int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
@@ -73,6 +75,8 @@ struct snd_usb_substream {
     unsigned int fill_max: 1;    /* fill max packet size always */
     unsigned int txfr_quirk:1;    /* allow sub-frame alignment */
     unsigned int fmt_type;        /* USB audio format type (1-3) */
+    unsigned int next_out_urb;    /* index of next URB to use for output
+                       (implicit feedback mode only) */
 
     unsigned int running: 1;    /* running status */
 
@@ -103,6 +107,8 @@ struct snd_usb_stream {
     unsigned int fmt_type;        /* USB audio format type (1-3) */
     struct snd_usb_substream substream[2];
     struct list_head list;
+    unsigned int implicit_feedback: 1;     /* stream uses its capture data
+                           substream to clock its playback substream */
 };
 
 #endif /* __USBAUDIO_CARD_H */
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index b8dcbf4..1cd1db2 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -185,7 +185,8 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
 /*
  * find a matching format and set up the interface
  */
-static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
+int snd_usb_set_pcm_format(struct snd_usb_substream *subs,
+               struct audioformat *fmt)
 {
     struct usb_device *dev = subs->dev;
     struct usb_host_interface *alts;
@@ -206,6 +207,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
     if (fmt == subs->cur_audiofmt)
         return 0;
 
+printk(KERN_ERR "%s() :%d\n", __func__, __LINE__);
+
     /* close the old interface */
     if (subs->interface >= 0 && subs->interface != fmt->iface) {
         if (usb_set_interface(subs->dev, subs->interface, 0) < 0) {
@@ -292,6 +295,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
     if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX)
         subs->fill_max = 1;
 
+    if (!is_playback &&
+        (fmt->ep_attr & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC &&
+        (fmt->ep_attr & USB_ENDPOINT_USAGE_MASK) == USB_ENDPOINT_USAGE_IMPLICIT_FB)
+        subs->stream->implicit_feedback = 1;
+
     if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0)
         return err;
 
@@ -299,6 +307,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
 
     snd_usb_set_format_quirk(subs, fmt);
 
+    if (subs->stream->implicit_feedback)
+        snd_printk(KERN_INFO "operating in implicit feedback mode\n");
+
 #if 0
     printk(KERN_DEBUG
            "setting done: format = %d, rate = %d..%d, channels = %d\n",
@@ -347,7 +358,16 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
     changed = subs->cur_audiofmt != fmt ||
         subs->period_bytes != params_period_bytes(hw_params) ||
         subs->cur_rate != rate;
-    if ((ret = set_format(subs, fmt)) < 0)
+
+    if (subs->stream->implicit_feedback) {
+        struct snd_usb_substream *other =
+            &subs->stream->substream[!subs->direction];
+
+        if (other && other->running && changed)
+            return -EBUSY;
+    }
+
+    if ((ret = snd_usb_set_pcm_format(subs, fmt)) < 0)
         return ret;
 
     if (subs->cur_rate != rate) {
@@ -815,6 +835,9 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
     struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
     struct snd_usb_substream *subs = &as->substream[direction];
 
+    if (snd_usb_capture_subs_used_by_playback(subs))
+        return 0;
+
     if (!as->chip->shutdown && subs->interface >= 0) {
         usb_set_interface(subs->dev, subs->interface, 0);
         subs->interface = -1;
diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h
index ed3e283..9e02cf8 100644
--- a/sound/usb/pcm.h
+++ b/sound/usb/pcm.h
@@ -3,6 +3,9 @@
 
 void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream);
 
+int snd_usb_set_pcm_format(struct snd_usb_substream *subs,
+               struct audioformat *fmt);
+
 int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
                struct usb_host_interface *alts,
                struct audioformat *fmt);
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 090e193..1353663 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -644,6 +644,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
     case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */
         set_format_emu_quirk(subs, fmt);
         break;
+    case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
+    case USB_ID(0x0763, 0x2081):
+        subs->stream->implicit_feedback = 1;
+        break;
     }
 }
 
diff --git a/sound/usb/urb.c b/sound/usb/urb.c
index e184349..3b7a81b 100644
--- a/sound/usb/urb.c
+++ b/sound/usb/urb.c
@@ -29,6 +29,25 @@
 #include "urb.h"
 #include "pcm.h"
 
+/* Streaming modes
+ *
+ * This driver can operate in different streaming modes which use the internal
+ * functions of this file differently.
+ *
+ * One is independent input and output streaming which is the default and most
+ * usual for USB audio devices. IN endpoints (device sinks) can either take any
+ * amount of data that is sent or provide a sync endpoint to tell the host at
+ * which data rate the stream runs at. This streaming model allows playback and
+ * capture streams to be started independently.
+ *
+ * The other is an 'implicit feedback mode' in which the device does not tell
+ * the host its speed through an sync endpoint but expects the driver to always
+ * receive the record stream and use the data rate to determine the actual
+ * device speed. For the USB side, this means that the driver has to queue
+ * capture URBs even if the userspace is not interested in actual capture data.
+ *
+ */
+
 /*
  * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
  * this will overflow at approx 524 kHz
@@ -135,10 +154,26 @@ static int wait_clear_urbs(struct snd_usb_substream *subs)
         schedule_timeout_uninterruptible(1);
     } while (time_before(jiffies, end_time));
     if (alive)
-        snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
+        snd_printk(KERN_ERR "timeout: still %d active urbs (%s)\n",
+               alive, subs->direction == SNDRV_PCM_STREAM_CAPTURE ?
+                        "capture" : "playback");
     return 0;
 }
 
+int snd_usb_capture_subs_used_by_playback(struct snd_usb_substream *capture)
+{
+    struct snd_usb_stream *stream = capture->stream;
+    struct snd_usb_substream *playback = &stream->substream[SNDRV_PCM_STREAM_PLAYBACK];
+
+    if (!playback)
+        return 0;
+
+    if (capture->direction != SNDRV_PCM_STREAM_CAPTURE)
+        return 0;
+
+    return stream->implicit_feedback && playback->running;
+}
+
 /*
  * release a substream
  */
@@ -146,6 +181,9 @@ void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
 {
     int i;
 
+    if (snd_usb_capture_subs_used_by_playback(subs))
+        return;
+
     /* stop urbs (to be sure) */
     deactivate_urbs(subs, force, 1);
     wait_clear_urbs(subs);
@@ -168,17 +206,34 @@ static void snd_complete_urb(struct urb *urb)
     struct snd_urb_ctx *ctx = urb->context;
     struct snd_usb_substream *subs = ctx->subs;
     struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
+    int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
     int err = 0;
 
     if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
-        !subs->running || /* can be stopped during retire callback */
-        (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
-        (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
-        clear_bit(ctx->index, &subs->active_mask);
-        if (err < 0) {
-            snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
-            snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-        }
+        !subs->running /* can be stopped during retire callback */)
+        goto exit_clear_bit;
+
+    /*
+     * For devices that operate in implicit feedback mode, we won't requeue
+     * the URB at this point. Instead, we will wait for the next record
+     * input packet to arrive and queue a packet from the corresponding
+     * retire callback.
+     */
+    if (is_playback && subs->stream->implicit_feedback)
+        goto exit_clear_bit;
+
+    if ((err = subs->ops.prepare(subs, substream->runtime, urb)) == 0 &&
+        (err = subs->ops.prepare_size(subs, substream->runtime, urb)) == 0 &&
+        (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0)
+        return;
+
+    /* fall through */
+
+exit_clear_bit:
+    clear_bit(ctx->index, &subs->active_mask);
+    if (err < 0) {
+        snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
+        snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
     }
 }
 
@@ -250,7 +305,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
     else
         packs_per_ms = 1;
 
-    if (is_playback) {
+    if (is_playback && !subs->stream->implicit_feedback) {
         urb_packs = max(chip->nrpacks, 1);
         urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
     } else
@@ -260,7 +315,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
         urb_packs = min(urb_packs, 1U << subs->syncinterval);
 
     /* decide how many packets to be used */
-    if (is_playback) {
+    if (is_playback && !subs->stream->implicit_feedback) {
         unsigned int minsize, maxpacks;
         /* determine how small a packet can be */
         minsize = (subs->freqn >> (16 - subs->datainterval))
@@ -320,6 +375,9 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
         u->urb->complete = snd_complete_urb;
     }
 
+    if (subs->stream->implicit_feedback)
+        subs->syncpipe = 0;
+
     if (subs->syncpipe) {
         /* allocate and initialize sync urbs */
         subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4,
@@ -410,6 +468,15 @@ static int retire_capture_sync_urb(struct snd_usb_substream *subs,
 }
 
 /*
+ * prepare data sizes for caputure urbs. nothing to do. */
+static int prepare_capture_size_urb(struct snd_usb_substream *subs,
+                    struct snd_pcm_runtime *runtime,
+                    struct urb *urb)
+{
+    return 0;
+}
+
+/*
  * prepare urb for capture data pipe
  *
  * fill the offset and length of each descriptor.
@@ -438,11 +505,93 @@ static int prepare_capture_urb(struct snd_usb_substream *subs,
     return 0;
 }
 
+static int queue_next_playback_urb(struct snd_usb_substream *capture,
+                   struct snd_pcm_runtime *runtime,
+                   struct urb *in_urb)
+{
+    unsigned int stride = runtime->frame_bits >> 3;
+    unsigned int bytes = 0, i;
+    unsigned long flags;
+    struct snd_urb_ctx *in_ctx = in_urb->context;
+    struct snd_usb_substream *playback =
+        &capture->stream->substream[SNDRV_PCM_STREAM_PLAYBACK];
+    struct snd_urb_ctx *out_ctx;
+    struct urb *out_urb;
+    int err;
+
+    /* this may happen during substream transitions */
+    if (stride == 0)
+        return 0;
+
+    if (!playback->running)
+        return 0;
+
+    /* Count overall packet size */
+    for (i = 0; i < in_ctx->packets; i++)
+        if (in_urb->iso_frame_desc[i].status == 0)
+            bytes += in_urb->iso_frame_desc[i].actual_length;
+
+    /* skip empty packets. At least M-Audio's Fast Track Ultra stops
+     * streaming once it received a 0-byte OUT URB */
+    if (bytes == 0)
+        return 0;
+
+    spin_lock_irqsave(&capture->lock, flags);
+    out_ctx = &playback->dataurb[playback->next_out_urb];
+    spin_unlock_irqrestore(&capture->lock, flags);
+
+    out_urb = out_ctx->urb;
+
+    /* If the output urb is still in use, we have to drop this packet.
+     * This usually only occurs when the stream is starting */
+    if (test_bit(out_ctx->index, &playback->active_mask))
+        return 0;
+
+    /*
+     * Iterate through the inbound packet and prepare the lengths
+     * for output packets. The OUT packet we are about to send will
+     * have the same amount of payload than the IN packet we just
+     * received.
+     */
+
+    out_ctx->packets = in_ctx->packets;
+    for (i = 0; i < in_ctx->packets; i++) {
+        if (in_urb->iso_frame_desc[i].status == 0)
+            out_ctx->packet_size[i] =
+                in_urb->iso_frame_desc[i].actual_length / stride;
+        else
+            out_ctx->packet_size[i] = 0;
+    }
+
+    err = playback->ops.prepare(playback, playback->pcm_substream->runtime, out_urb);
+    if (err < 0)
+        return err;
+
+    err = usb_submit_urb(out_urb, GFP_ATOMIC);
+    if (err < 0) {
+        snd_printk(KERN_ERR "%s(): Unable to submit urb #%d: %d\n",
+                __func__, out_ctx->index, err);
+        snd_pcm_stop(capture->pcm_substream, SNDRV_PCM_STATE_XRUN);
+        snd_pcm_stop(playback->pcm_substream, SNDRV_PCM_STATE_XRUN);
+        return err;
+    } else {
+        spin_lock_irqsave(&capture->lock, flags);
+        set_bit(out_ctx->index, &playback->active_mask);
+        playback->next_out_urb++;
+        playback->next_out_urb %= playback->nurbs;
+        spin_unlock_irqrestore(&capture->lock, flags);
+    }
+
+    return 0;
+}
+
 /*
  * process after capture complete
  *
  * copy the data from each desctiptor to the pcm buffer, and
  * update the current position.
+ *
+ * For implicit feedback mode, eventually call queue_next_playback_urb().
  */
 static int retire_capture_urb(struct snd_usb_substream *subs,
                   struct snd_pcm_runtime *runtime,
@@ -499,16 +648,24 @@ static int retire_capture_urb(struct snd_usb_substream *subs,
     }
     if (period_elapsed)
         snd_pcm_period_elapsed(subs->pcm_substream);
+
+    if (subs->stream->implicit_feedback)
+        return queue_next_playback_urb(subs, runtime, urb);
+
     return 0;
 }
 
 /*
- * Process after capture complete when paused.  Nothing to do.
+ * Process after capture complete when paused.
+ * For implicit feedback mode, eventually call queue_next_playback_urb().
  */
 static int retire_paused_capture_urb(struct snd_usb_substream *subs,
                      struct snd_pcm_runtime *runtime,
                      struct urb *urb)
 {
+    if (subs->stream->implicit_feedback)
+        return queue_next_playback_urb(subs, runtime, urb);
+
     return 0;
 }
 
@@ -615,6 +772,25 @@ static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
 }
 
 /*
+ * Prepare urb data sizes for asynchronous output streaming.
+ * This is seperated from the code that fills the data because syncronous
+ * streaming (in implicit feedback mode) uses a different method to determine
+ * the output data packet sizes.
+ */
+static int prepare_playback_size_urb(struct snd_usb_substream *subs,
+                     struct snd_pcm_runtime *runtime,
+                     struct urb *urb)
+{
+    int i;
+    struct snd_urb_ctx *ctx = urb->context;
+
+    for (i = 0; i < ctx->packets; ++i)
+        ctx->packet_size[i] = snd_usb_audio_next_packet_size(subs);
+
+    return 0;
+}
+
+/*
  * Prepare urb for streaming before playback starts or when paused.
  *
  * We don't have any data, so we send silence.
@@ -630,7 +806,7 @@ static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
     offs = 0;
     urb->dev = ctx->subs->dev;
     for (i = 0; i < ctx->packets; ++i) {
-        counts = snd_usb_audio_next_packet_size(subs);
+        counts = ctx->packet_size[i];
         urb->iso_frame_desc[i].offset = offs * stride;
         urb->iso_frame_desc[i].length = counts * stride;
         offs += counts;
@@ -668,7 +844,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
     urb->number_of_packets = 0;
     spin_lock_irqsave(&subs->lock, flags);
     for (i = 0; i < ctx->packets; i++) {
-        counts = snd_usb_audio_next_packet_size(subs);
+        counts = ctx->packet_size[i];
         /* set up descriptor */
         urb->iso_frame_desc[i].offset = frames * stride;
         urb->iso_frame_desc[i].length = counts * stride;
@@ -786,6 +962,10 @@ static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *ru
     for (i = 0; i < subs->nurbs; i++) {
         if (snd_BUG_ON(!subs->dataurb[i].urb))
             return -EINVAL;
+        if (subs->ops.prepare_size(subs, runtime, subs->dataurb[i].urb) < 0) {
+            snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
+            goto __error;
+        }
         if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
             snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
             goto __error;
@@ -805,6 +985,7 @@ static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *ru
     subs->active_mask = 0;
     subs->unlink_mask = 0;
     subs->running = 1;
+
     for (i = 0; i < subs->nurbs; i++) {
         err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
         if (err < 0) {
@@ -840,12 +1021,14 @@ static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *ru
  */
 static struct snd_urb_ops audio_urb_ops[2] = {
     {
+        .prepare_size =    prepare_playback_size_urb,
         .prepare =    prepare_nodata_playback_urb,
         .retire =    retire_playback_urb,
         .prepare_sync =    prepare_playback_sync_urb,
         .retire_sync =    retire_playback_sync_urb,
     },
     {
+        .prepare_size =    prepare_capture_size_urb,
         .prepare =    prepare_capture_urb,
         .retire =    retire_capture_urb,
         .prepare_sync =    prepare_capture_sync_urb,
@@ -892,6 +1075,18 @@ int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int
         subs->ops.prepare = prepare_playback_urb;
         return 0;
     case SNDRV_PCM_TRIGGER_STOP:
+        if (subs->stream->implicit_feedback) {
+            struct snd_usb_substream *capture =
+                &subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE];
+            if (capture &&
+                capture->pcm_substream &&
+                capture->pcm_substream->runtime) {
+                struct snd_pcm_runtime *runtime =
+                    capture->pcm_substream->runtime;
+                if (runtime->status->state != SNDRV_PCM_STATE_OPEN)
+                    deactivate_urbs(capture, 0, 0);
+            }
+        }
         return deactivate_urbs(subs, 0, 0);
     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
         subs->ops.prepare = prepare_nodata_playback_urb;
@@ -908,8 +1103,15 @@ int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int c
     switch (cmd) {
     case SNDRV_PCM_TRIGGER_START:
         subs->ops.retire = retire_capture_urb;
-        return start_urbs(subs, substream->runtime);
+        if (!subs->running)
+            return start_urbs(subs, substream->runtime);
+
+        return 0;
     case SNDRV_PCM_TRIGGER_STOP:
+        if (snd_usb_capture_subs_used_by_playback(subs)) {
+            subs->ops.retire = retire_paused_capture_urb;
+            return 0;
+        }
         return deactivate_urbs(subs, 0, 0);
     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
         subs->ops.retire = retire_paused_capture_urb;
@@ -922,18 +1124,90 @@ int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int c
     return -EINVAL;
 }
 
+/*
+ * Fake a start for the capture stream.
+ * Only used for implicit feedback mode.
+ */
+static int start_capture_stream(struct snd_usb_substream *playback,
+                struct snd_usb_substream *capture,
+                struct snd_pcm_runtime *runtime)
+{
+    int err;
+
+
+usb_set_interface(capture->dev, 2, 1);
+
+    capture->ops.prepare = prepare_capture_urb;
+    capture->ops.retire = retire_paused_capture_urb;
+    capture->pcm_substream = playback->pcm_substream;
+    err = snd_usb_set_pcm_format(capture, playback->cur_audiofmt);
+    if (err)
+        return err;
+
+    err = snd_usb_init_substream_urbs(capture, playback->period_bytes,
+                      playback->cur_rate,
+                      (playback->curpacksize /
+                       playback->curframesize) * 8);
+    if (err)
+        return err;
+
+    return start_urbs(capture, runtime);
+}
+
 int snd_usb_substream_prepare(struct snd_usb_substream *subs,
                   struct snd_pcm_runtime *runtime)
 {
     /* clear urbs (to be sure) */
-    deactivate_urbs(subs, 0, 1);
-    wait_clear_urbs(subs);
+    if (!snd_usb_capture_subs_used_by_playback(subs)) {
+        deactivate_urbs(subs, 0, 1);
+        wait_clear_urbs(subs);
+    }
 
-    /* for playback, submit the URBs now; otherwise, the first hwptr_done
-     * updates for all URBs would happen at the same time when starting */
     if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
         subs->ops.prepare = prepare_nodata_playback_urb;
-        return start_urbs(subs, runtime);
+
+        if (subs->stream->implicit_feedback) {
+            struct snd_usb_substream *capture =
+                &subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE];
+
+            if (!capture) {
+                snd_printk(KERN_ERR "Unable to start implicit feedback mode "
+                       "without capture stream\n");
+                return -EINVAL;
+            }
+
+            /*
+             * Mark the stream running without calling start_urbs().
+             * We don't want to queue any URBs yet at this point
+             */
+            subs->active_mask = 0;
+            subs->unlink_mask = 0;
+            subs->running = 1;
+
+            /*
+             * if this stream is in implicit feedback mode, start the
+             * capture stream now as the playback stream relies on the
+             * amount of data we see on the capture IN endpoint.
+             */
+            if (!capture->running) {
+                int err = start_capture_stream(subs, capture, runtime);
+                if (err < 0) {
+                    deactivate_urbs(subs, 0, 0);
+                    return err;
+                }
+            }
+        } else {
+            /*
+             * For playback, submit the URBs now; otherwise, the
+             * first hwptr_done updates for all URBs would happen
+             * at the same time when starting.
+             * However, don't start the stream here if we are in
+             * implicit feedback stream mode - all OUT URBs will
+             * be queued once data is received on the IN endpooint
+             * in this case.
+             */
+            return start_urbs(subs, runtime);
+        }
     }
 
     return 0;
diff --git a/sound/usb/urb.h b/sound/usb/urb.h
index 888da38..593a9e1 100644
--- a/sound/usb/urb.h
+++ b/sound/usb/urb.h
@@ -17,5 +17,6 @@ int snd_usb_substream_prepare(struct snd_usb_substream *subs,
 
 int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
 int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
+int snd_usb_capture_subs_used_by_playback(struct snd_usb_substream *substream);
 
 #endif /* __USBAUDIO_URB_H */

 		 	   		  

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

* Re: M-Audio FTU issues
  2011-07-21  5:08               ` Juan Pablo Bouza
@ 2011-07-21  7:55                 ` Daniel Mack
  2011-07-21  8:25                   ` Felix Homann
  2011-07-21 20:31                   ` Juan Pablo Bouza
  0 siblings, 2 replies; 24+ messages in thread
From: Daniel Mack @ 2011-07-21  7:55 UTC (permalink / raw)
  To: Juan Pablo Bouza
  Cc: gdiffey, tiwai, clemens, alsa-devel, linuxaudio, blablack

On Thu, Jul 21, 2011 at 7:08 AM, Juan Pablo Bouza <jpbouza@hotmail.com> wrote:
> Capture works perfectly fine.
>
> Playback does not work with alsa apps  or with jack.
>
>  This is my /proc/asound/cards output
>
>  0 [SB             ]: HDA-Intel - HDA ATI SB
>                       HDA ATI SB at 0xf9ff4000 irq 16
>  1 [Ultra          ]: USB-Audio - Fast Track Ultra
>                       M-Audio Fast Track Ultra at usb-0000:00:13.5-1, high
> speed
>
>
> This is what happens when trying to playback a sound file with aplay -D
> plughw:Ultra /media/Edipo/Triangulo/Hadas\ por\ ahora.mp3

aplay is not capable of playing mp3 files. Try a .wav.

Also, note that the patch you tried is preliminary and not intended
for productive use. It might crash your kernel.

We need some conscenus about how to decouple the USB stream from the
ALSA stream internally to finish it.


Daniel

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

* Re: M-Audio FTU issues
  2011-07-21  7:55                 ` Daniel Mack
@ 2011-07-21  8:25                   ` Felix Homann
  2011-07-24 14:12                     ` Aurélien Leblond
  2011-07-21 20:31                   ` Juan Pablo Bouza
  1 sibling, 1 reply; 24+ messages in thread
From: Felix Homann @ 2011-07-21  8:25 UTC (permalink / raw)
  To: Daniel Mack
  Cc: gdiffey, Juan Pablo Bouza, tiwai, clemens, alsa-devel, blablack

2011/7/21 Daniel Mack <zonque@gmail.com>

>
> We need some conscenus about how to decouple the USB stream from the
> ALSA stream internally to finish it.
>
>
> Daniel
>

Have you and Clemens made any progress towards a consensus?

Regards,

Felix

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

* Re: M-Audio FTU issues
  2011-07-21  7:55                 ` Daniel Mack
  2011-07-21  8:25                   ` Felix Homann
@ 2011-07-21 20:31                   ` Juan Pablo Bouza
  2011-07-22  8:42                     ` Daniel Mack
  1 sibling, 1 reply; 24+ messages in thread
From: Juan Pablo Bouza @ 2011-07-21 20:31 UTC (permalink / raw)
  To: zonque; +Cc: gdiffey, tiwai, clemens, alsa-devel, linuxaudio, blablack


Yes, I know about the duplex mode kernel crash... But anyway, playback is just broken with the patch and my compilation...

Against what version of kernel 3 is the patch supposed to work?

Is there any additional kernel configuration option I should or should not use in order to make the patch work??

> Date: Thu, 21 Jul 2011 09:55:16 +0200
> Subject: Re: [alsa-devel] M-Audio FTU issues
> From: zonque@gmail.com
> To: jpbouza@hotmail.com
> CC: gdiffey@gmail.com; tiwai@suse.de; blablack@gmail.com; alsa-devel@alsa-project.org; clemens@ladisch.de; linuxaudio@showlabor.de
> 
> On Thu, Jul 21, 2011 at 7:08 AM, Juan Pablo Bouza <jpbouza@hotmail.com> wrote:
> > Capture works perfectly fine.
> >
> > Playback does not work with alsa apps  or with jack.
> >
> >  This is my /proc/asound/cards output
> >
> >  0 [SB             ]: HDA-Intel - HDA ATI SB
> >                       HDA ATI SB at 0xf9ff4000 irq 16
> >  1 [Ultra          ]: USB-Audio - Fast Track Ultra
> >                       M-Audio Fast Track Ultra at usb-0000:00:13.5-1, high
> > speed
> >
> >
> > This is what happens when trying to playback a sound file with aplay -D
> > plughw:Ultra /media/Edipo/Triangulo/Hadas\ por\ ahora.mp3
> 
> aplay is not capable of playing mp3 files. Try a .wav.
> 
> Also, note that the patch you tried is preliminary and not intended
> for productive use. It might crash your kernel.
> 
> We need some conscenus about how to decouple the USB stream from the
> ALSA stream internally to finish it.
> 
> 
> Daniel
 		 	   		  

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

* Re: M-Audio FTU issues
  2011-07-21 20:31                   ` Juan Pablo Bouza
@ 2011-07-22  8:42                     ` Daniel Mack
  2011-07-23  4:25                       ` Juan Pablo Bouza
  0 siblings, 1 reply; 24+ messages in thread
From: Daniel Mack @ 2011-07-22  8:42 UTC (permalink / raw)
  To: Juan Pablo Bouza
  Cc: gdiffey, tiwai, clemens, alsa-devel, linuxaudio, blablack

On Thu, Jul 21, 2011 at 10:31 PM, Juan Pablo Bouza <jpbouza@hotmail.com> wrote:
>
> Yes, I know about the duplex mode kernel crash... But anyway, playback is just broken with the patch and my compilation...

All others reported success on this. Are you really playing a plain .wav file?

> Against what version of kernel 3 is the patch supposed to work?

On top of Takashi's master branch:
git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git

> Is there any additional kernel configuration option I should or should not use in order to make the patch work??

You should have of course have a kernel which does in general support
the FTU, but nothing more.


Daniel

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

* Re: M-Audio FTU issues
  2011-07-22  8:42                     ` Daniel Mack
@ 2011-07-23  4:25                       ` Juan Pablo Bouza
  0 siblings, 0 replies; 24+ messages in thread
From: Juan Pablo Bouza @ 2011-07-23  4:25 UTC (permalink / raw)
  To: zonque; +Cc: gdiffey, tiwai, clemens, alsa-devel, linuxaudio, blablack


Thanks for the reply Daniel!

Well, I've patched and compiled Takashi's kernel... still no luck, no playback.
The good thing is that I also compiled this same kernel without patching and playback did work, so I assume there's something wrong with the patch I'm applying??

What I do is simply opening Audacity and trying to play a sound file. With the patched kernel Audacity says that it can't open the device for playback. I also tried jack and it won't start in playback or duplex mode.
As I said, recording does work ok.... And also, the kernel without patching works in all modes.

So... can you give me a link to the patch, just in case the patch I'm using has something wrong (although no errors are displayed when patching)

Secondly, is there a way I can debug the playback error? Some command line that could tell me why it can't open the device?

By the way, I'm in Kubuntu 10.04 and I'm compiling the kernel with kernel-package 12.036.

Sorry for being such a pain!! Thanks!!



PS: here's the output of the patching process:

root@ARTURITO:/usr/src/sound-2.6# patch -p1 <86547-001.bin 
patching file include/linux/usb/ch9.h
patching file sound/usb/card.h
patching file sound/usb/pcm.c
patching file sound/usb/pcm.h
patching file sound/usb/quirks.c
Hunk #1 succeeded at 753 (offset 109 lines).
patching file sound/usb/urb.c
patching file sound/usb/urb.h
root@ARTURITO:/usr/src/sound-2.6# 




> Date: Fri, 22 Jul 2011 10:42:26 +0200
> From: zonque@gmail.com
> To: jpbouza@hotmail.com
> CC: gdiffey@gmail.com; tiwai@suse.de; clemens@ladisch.de; alsa-devel@alsa-project.org; linuxaudio@showlabor.de; blablack@gmail.com
> Subject: Re: [alsa-devel] M-Audio FTU issues
> 
> On Thu, Jul 21, 2011 at 10:31 PM, Juan Pablo Bouza <jpbouza@hotmail.com> wrote:
> >
> > Yes, I know about the duplex mode kernel crash... But anyway, playback is just broken with the patch and my compilation...
> 
> All others reported success on this. Are you really playing a plain .wav file?
> 
> > Against what version of kernel 3 is the patch supposed to work?
> 
> On top of Takashi's master branch:
> git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
> 
> > Is there any additional kernel configuration option I should or should not use in order to make the patch work??
> 
> You should have of course have a kernel which does in general support
> the FTU, but nothing more.
> 
> 
> Daniel
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
 		 	   		  

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

* Re: M-Audio FTU issues
  2011-07-21  8:25                   ` Felix Homann
@ 2011-07-24 14:12                     ` Aurélien Leblond
  2011-07-24 14:46                       ` Daniel Mack
  0 siblings, 1 reply; 24+ messages in thread
From: Aurélien Leblond @ 2011-07-24 14:12 UTC (permalink / raw)
  To: Felix Homann
  Cc: gdiffey, Juan Pablo Bouza, tiwai, clemens, alsa-devel, Daniel Mack

On Thu, Jul 21, 2011 at 9:25 AM, Felix Homann <linuxaudio@showlabor.de> wrote:
>
>
> 2011/7/21 Daniel Mack <zonque@gmail.com>
>>
>> We need some conscenus about how to decouple the USB stream from the
>> ALSA stream internally to finish it.
>>
>>
>> Daniel
>
> Have you and Clemens made any progress towards a consensus?
> Regards,
> Felix

I second that question!
Aurélien

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

* Re: M-Audio FTU issues
  2011-07-24 14:12                     ` Aurélien Leblond
@ 2011-07-24 14:46                       ` Daniel Mack
  0 siblings, 0 replies; 24+ messages in thread
From: Daniel Mack @ 2011-07-24 14:46 UTC (permalink / raw)
  To: Aurélien Leblond
  Cc: gdiffey, Juan Pablo Bouza, alsa-devel, tiwai, clemens, Felix Homann

On Sun, Jul 24, 2011 at 4:12 PM, Aurélien Leblond <blablack@gmail.com> wrote:
> On Thu, Jul 21, 2011 at 9:25 AM, Felix Homann <linuxaudio@showlabor.de> wrote:
>> Have you and Clemens made any progress towards a consensus?
>> Regards,
>> Felix
>
> I second that question!

Haven't heard back yet, so I'll come up wih an own proposal sooner or
later. Sorry for the delay on this, but that topic is not forgotten.

Daniel

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

* Re: M-Audio FTU issues
  2011-06-24 16:10       ` Daniel Mack
  2011-06-28 20:37         ` Aurélien Leblond
@ 2011-07-25 13:07         ` Clemens Ladisch
  1 sibling, 0 replies; 24+ messages in thread
From: Clemens Ladisch @ 2011-07-25 13:07 UTC (permalink / raw)
  To: Daniel Mack
  Cc: alsa-devel, =?UTF-8?B?QXVyw6lsaWVuIExlYmxv?=,
	Takashi Iwai, Grant Diffey, Felix Homann, nd

(Sorry for the delay, I don't have much free time.)

Daniel Mack wrote:
> On Fri, Jun 24, 2011 at 5:58 PM, Clemens Ladisch <clemens@ladisch.de> wrote:
> > I think the best solution would be to move the USB streaming into
> > a module, add implicit feedback support there, and create a separate
> > driver for the FTU and similar devices.
> 
> However, I'm not sure whether making a special driver for the FTU is
> really the way to go. Even though I haven't seen any device around yet
> that implements this in a class-compliant way, this type of streaming
> model is in fact part of the USB Audio specification, at least in
> version 2. It's more than likely that there will be more devices
> around in the future, and so it would be good to have support for it
> in the standard driver.

Only the parts that are different would go into the separate drivers.
This would be device detection, parsing of the descriptors, stream
management and configuration (i.e., choosing and setting alternate
settings, and class-specific interface/endpoint requests), and most of
the interfacing with the ALSA framework.  (USB Audio 1.0 and 2.0 are not
really compatible, so the latter might become a separate driver, too.)

Common parts (snd-usb-lib) would be the actual streaming (sending/
receiving packets, buffer handling), and whatever random stuff turns
out to be needed by multiple drivers.

> Can you outline how the API will look like?

Something like this:

	struct usb_pcm_stream;

	usb_pcm_stream_init(stream, snd_pcm_stream, usb_device, flags);
	usb_pcm_stream_destroy(stream);

	usb_pcm_stream_configure(stream, endpoint, rate, format);
	usb_pcm_stream_set_clock_source(stream, master_stream);

	usb_pcm_stream_start(stream);
	usb_pcm_stream_stop(stream);

	// helpers to implement ALSA PCM callbacks
	usb_pcm_stream_pcm_prepare(stream);
	usb_pcm_stream_pcm_trigger(stream, start);
	usb_pcm_stream_pcm_pointer(stream);

(There are obvious similarities with firewire/amdtp.c.)

As far as I can tell, this affects mostly urb.c.


Regards,
Clemens

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

end of thread, other threads:[~2011-07-25 13:04 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-24  1:14 M-Audio FTU issues Daniel Mack
2011-06-24  3:27 ` Grant Diffey
2011-06-24  7:35 ` Felix Homann
2011-06-24  8:52 ` Felix Homann
2011-06-24 15:23   ` Daniel Mack
2011-06-24 15:58     ` Clemens Ladisch
2011-06-24 16:10       ` Daniel Mack
2011-06-28 20:37         ` Aurélien Leblond
2011-06-29  8:08           ` Daniel Mack
2011-07-03 11:52             ` Grant Diffey
2011-07-04 17:14               ` Aurélien Leblond
2011-07-04 17:23               ` Daniel Mack
2011-07-13 21:18               ` Juan Pablo Bouza
2011-07-21  5:08               ` Juan Pablo Bouza
2011-07-21  7:55                 ` Daniel Mack
2011-07-21  8:25                   ` Felix Homann
2011-07-24 14:12                     ` Aurélien Leblond
2011-07-24 14:46                       ` Daniel Mack
2011-07-21 20:31                   ` Juan Pablo Bouza
2011-07-22  8:42                     ` Daniel Mack
2011-07-23  4:25                       ` Juan Pablo Bouza
2011-07-25 13:07         ` Clemens Ladisch
2011-06-27  8:52     ` Felix Homann
2011-06-24  9:08 ` Felix Homann

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.