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