[alsa-devel] M-Audio FTU issues
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
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
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
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
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
Daniel Mack wrote:
- 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.
- 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
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
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
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
On Tue, Jun 28, 2011 at 10:37 PM, Aur=E9lien 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
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!).
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
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
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 */
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
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
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
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
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
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
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
(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
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
[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
participants (6)
-
Aurélien Leblond
-
Clemens Ladisch
-
Daniel Mack
-
Felix Homann
-
Grant Diffey
-
Juan Pablo Bouza