All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [Alsa-user] Ticks when playing to USB DAC at high sample rates
       [not found]     ` <2168981.L00zyKDK9R@quintet>
@ 2012-11-04 10:39       ` Daniel Mack
  2012-11-05  1:53         ` Jeffrey Barish
  2012-11-05 14:20         ` Jeffrey Barish
  0 siblings, 2 replies; 14+ messages in thread
From: Daniel Mack @ 2012-11-04 10:39 UTC (permalink / raw)
  To: Jeffrey Barish; +Cc: alsa-user, alsa-devel

[cc alsa-devel]

On 04.11.2012 02:25, Jeffrey Barish wrote:
> On Fri 26 October 2012 15:21:06 Jeffrey Barish wrote:
>> On Fri 26 October 2012 21:47:05 Daniel Mack wrote:
>>> On 26.10.2012 21:43, Jeffrey Barish wrote:
>>>> On Thu 25 October 2012 19:10:45 Daniel Mack wrote:
>>>>> On 25.10.2012 17:18, Jeffrey Barish wrote:
>>>>>> I found something in the snd_usb_audio code (in endpoint.c) that could
>>>>>> explain one of the problems I have observed (the ticks). I would
>>>>>> normally test my theory by modifying the code. In this case, I would
>>>>>> like to stick in a print statement to see what values are being
>>>>>> assigned
>>>>>> to certain variables. Unfortunately, I am too ignorant to do something
>>>>>> even this trivial as I have never worked on kernel code. I think I am
>>>>>> supposed to use printk,
>>>>>
>>>>> printk is nice for simple debugging, yes. But note that this call is
>>>>> timing critical and should not be used in "fast path" code. Introducing
>>>>> a printk for each received packet for example will almost certainly
>>>>> make
>>>>> the driver behave quite differently.
>>>>>
>>>>>> but beyond that I am lost. Can someone provide
>>>>>> me with some directions? I need to know how to make the driver. To
>>>>>> that
>>>>>> end, I probably will have to install additional packages. After making
>>>>>> the driver, I need to know how to install it over the existing driver.
>>>>>
>>>>> Here's one way to do it:
>>>>>
>>>>> 1. git clone
>>>>> git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git (your
>>>>> patch should apply on top of this tree eventually)
>>>>> 2. cd sound
>>>>> 3. zcat /proc/config.gz >.config
>>>>> 4. build and install the kernel image. How that is done depends on the
>>>>> distribution you're using. For Ubuntu follow the docs at [1] (start at
>>>>> point #5). For Fedora and others, something like "make && make install"
>>>>> should do
>>>>> 5. reboot and check that the new kernel is running
>>>>> 6. hack on sound/usb
>>>>> 7. make M=sound/usb
>>>>> 8. reload the module with "sudo rmmod snd_usb_audio; sudo insmod
>>>>> sound/usb/snd-usb-audio.ko" (better plug out the device before so you
>>>>> always have the same defined point of start)
>>>>>
>>>>>
>>>>> Hope that works for you.
>>>>>
>>>>>
>>>>> Daniel
>>>>>
>>>>> [1] https://wiki.ubuntu.com/KernelTeam/GitKernelBuild
>>>>
>>>> Your directions were almost perfect, so even I was able to build the
>>>> kernel. I made a discovery using the new kernel that might help someone
>>>> more familiar with the code than I am to localize the problem.  I am
>>>> still hearing the blip when I play audio sampled at 88.2 kHz, but I just
>>>> noticed that the blip is perfectly periodic, with a period of about 16.4
>>>> seconds.  I am playing a sine wave synthesized using GStreamer using the
>>>> following command:
>>>>
>>>> gst-launch audiotestsrc volume=0.01 ! audio/x-raw-float, width=64,
>>>> rate=88200, channels=2, endianness=1234 ! audioconvert ! alsasink
>>>>
>>>> A sine wave makes it easier to hear the blip.  Does this clue suggest
>>>> anything?
>>>>
>>>> I also want to mention that when I use the new kernel, I do not get the
>>>> ticks at either 88.2 or 96 kHz even when I do not use the external USB
>>>> hub.  I plan next to back up to the 3.6.2 kernel to see whether I still
>>>> get ticks there.
>>>
>>> Which kernel did you use when you heard the 'blibs'?
>>
>> The latest news is bad.  I am on 3.2.0 now.  The USB DAC is working
>> perfectly at this moment at both 96 kHz and 88.2 kHz without the external
>> USB hub (imagine calling that bad news).  If I set the srate to 88.2 kHz
>> and stop and start the sine wave, sometimes I get the blip.  Forget about
>> its being periodic.  It was definitely periodic before lunch; now I usually
>> get random intervals if I get any blips at all.  As I am typing this
>> message, I can't get blips at all.  There was some correlation between
>> changing sample rates and blips, but I can't reproduce that behavior now. 
>> What is most weird is that I haven't gotten any ticks since lunch with any
>> kernel or with either sample rate, yet they were reliable earlier today
>> unless I used the external USB hub. I obviously need to experiment some
>> more to see whether I can observe a pattern.
> 
> To conclude (?) this thread, I am now convinced that the anomalies I observed 
> were unrelated to the device driver.  I had two theories remaining.  One was 
> that the problem was somehow related to an overheating problem.  I used a heat 
> gun to convince myself that the theory was wrong.  The other was that the 
> problem had something to do with services running in the background that 
> interfered with the device driver.  I removed or disabled all services that I 
> could identify as superfluous.  Removed services include zeitgeist, apparmor, 
> modemmanager, mdadm, and bluetooth.  Disabled services include atd, dns-clean, 
> and pppd-dns.  The system has been running perfectly with an 88.2 kHz sample 
> rate and no external USB hub for 2 days.  However, I tried booting the system 
> with a copy of the OS from before I removed superfluous services.  It still ran 
> perfectly.  Thus, I cannot convince myself that removing superfluous services 
> actually solved the problem.  I suppose it's possible that some service was 
> running sporadically, which could explain why the problem seemed to come and 
> go and also why the problem did not occur when I booted the copy of the OS.  
> As long as the problem remains dormant I have no alternative but to move on 
> and see whether the problem eventually recurs.  Only time will tell.
> 
> Thanks for all the help.  Hey, I built a kernel and got my own version of the 
> device driver to run.  That was exciting.
> 
> ------------------------------------------------------------------------------
> 
> I'm back.  The USB DAC continued to work for two more days after my last 
> message and then the blips resumed.  I've been digging into the driver code 
> for two days.  I spent today trying to convince myself that the driver is 
> actually using an asynchronous protocol.  The blips are almost certainly buffer 
> underruns, which I could account for if the driver were not responding to 
> asynchronous feedback from the DAC.  I expected to see a deviation from the 
> pattern of one frame with 89 samples followed by 4 frames with 88 (which 
> results in 88,200 samples per second).  That sequence would work perfectly if 
> the clocks in the computer and in the USB DAC were exactly the same frequency, 
> but of course they are not.  Consequently, I would expect to see requests for 
> one sample more or less once in a while, depending on whether the clock in the 
> computer is slower or faster than the one in the DAC.  What I see is 89 + 4 * 
> 88 almost all the time, as expected .  Once in a while there is a request for 
> an additional frame of 88 and then the pattern of 89 + 4 * 88 resumes.  I 
> presume that the break in the usual pattern indicates that the device driver 
> is responding to a request from the DAC for fewer samples, which confirms that 
> the driver is using the asynchronous protocol.  That's good, if I am right.  
> However, sticking in an extra packet of only 88 would be the expected 
> deviation if the host were getting a little ahead of the DAC, yet the blip is 
> almost certainly a buffer underrun, which means that the host is actually 
> falling behind.  Thus, an extra packet of 89 would make more sense.  I should 
> also mention that there is no correlation between the timing of the extra 
> packet of 88 and the audible blip.  Something seems wrong here, but I'm not 
> sure where to go next.
> 
> On a related topic, to confirm that the blip is a buffer underrun, I would like 
> to synthesize a waveform that is DC.  With DC, an overrun would not produce 
> any audible anomalies whereas an underrun would be audible.  I am using 
> GStreamer to synthesize the test waveform.  Does anyone know of a way to 
> synthesize a DC waveform using GStreamer?  If not, is there any other tool 
> available in Linux?
> 
> By the way, I bought another USB DAC from a different manufacturer to be sure 
> that the anomalies I am observing were not due to a defect in the DAC.  They 
> both display the same problem.
> 
> -----------------------------------------------------
> 
> I modified the device driver to output a constant instead of the incoming 
> waveform.  I get blips, as I expected, so I am now certain that the blips are 
> caused by a buffer underrun.  The blips occur periodically again -- period of 
> about 16.5 seconds.  I presume that the period is related to the difference in 
> clock rates between the host and DAC.  Roughly every 3-4 blips, I get an extra 
> packet of 88 samples.  To prevent buffer underrun, I ought to be getting an 
> extra packet of 89 samples every 16.5 seconds, but I never do.

Thanks for all your investigation on this! Sending computed data instead
of the payload delivered by the ALSA stack is in fact a very good way to
isolate the issue.

The question is: if the algorithm in the USB driver miscalculates the
number of samples to send over time, what't the reason for that? Does
the device report bogus values or is there this a bug in the driver?

Did you read chapter 5.4.12.1 of the USB2.0 spec, and can you explain
where you suspect the bug to be? The current implementation in the
driver is quite straight forward, mapping all feedback values to Q16.16
and keeping the lower 16bits around for phase compensation between the
calculation of the packet sizes.

If you find a better solution, please share it here, preferably in the
form of a patch :)


Thanks,
Daniel

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

* Re: Ticks when playing to USB DAC at high sample rates
  2012-11-04 10:39       ` [Alsa-user] Ticks when playing to USB DAC at high sample rates Daniel Mack
@ 2012-11-05  1:53         ` Jeffrey Barish
  2012-11-05 15:03           ` [Alsa-user] " Daniel Mack
  2012-11-05 14:20         ` Jeffrey Barish
  1 sibling, 1 reply; 14+ messages in thread
From: Jeffrey Barish @ 2012-11-05  1:53 UTC (permalink / raw)
  To: Daniel Mack; +Cc: alsa-user, alsa-devel

On Sun 04 November 2012 11:39:48 Daniel Mack wrote:
> [cc alsa-devel]
> 
> On 04.11.2012 02:25, Jeffrey Barish wrote:
> > On Fri 26 October 2012 15:21:06 Jeffrey Barish wrote:
> >> On Fri 26 October 2012 21:47:05 Daniel Mack wrote:
> >>> On 26.10.2012 21:43, Jeffrey Barish wrote:
> >>>> On Thu 25 October 2012 19:10:45 Daniel Mack wrote:
> >>>>> On 25.10.2012 17:18, Jeffrey Barish wrote:
> >>>>>> I found something in the snd_usb_audio code (in endpoint.c) that
> >>>>>> could
> >>>>>> explain one of the problems I have observed (the ticks). I would
> >>>>>> normally test my theory by modifying the code. In this case, I would
> >>>>>> like to stick in a print statement to see what values are being
> >>>>>> assigned
> >>>>>> to certain variables. Unfortunately, I am too ignorant to do
> >>>>>> something
> >>>>>> even this trivial as I have never worked on kernel code. I think I am
> >>>>>> supposed to use printk,
> >>>>> 
> >>>>> printk is nice for simple debugging, yes. But note that this call is
> >>>>> timing critical and should not be used in "fast path" code.
> >>>>> Introducing
> >>>>> a printk for each received packet for example will almost certainly
> >>>>> make
> >>>>> the driver behave quite differently.
> >>>>> 
> >>>>>> but beyond that I am lost. Can someone provide
> >>>>>> me with some directions? I need to know how to make the driver. To
> >>>>>> that
> >>>>>> end, I probably will have to install additional packages. After
> >>>>>> making
> >>>>>> the driver, I need to know how to install it over the existing
> >>>>>> driver.
> >>>>> 
> >>>>> Here's one way to do it:
> >>>>> 
> >>>>> 1. git clone
> >>>>> git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git (your
> >>>>> patch should apply on top of this tree eventually)
> >>>>> 2. cd sound
> >>>>> 3. zcat /proc/config.gz >.config
> >>>>> 4. build and install the kernel image. How that is done depends on the
> >>>>> distribution you're using. For Ubuntu follow the docs at [1] (start at
> >>>>> point #5). For Fedora and others, something like "make && make
> >>>>> install"
> >>>>> should do
> >>>>> 5. reboot and check that the new kernel is running
> >>>>> 6. hack on sound/usb
> >>>>> 7. make M=sound/usb
> >>>>> 8. reload the module with "sudo rmmod snd_usb_audio; sudo insmod
> >>>>> sound/usb/snd-usb-audio.ko" (better plug out the device before so you
> >>>>> always have the same defined point of start)
> >>>>> 
> >>>>> 
> >>>>> Hope that works for you.
> >>>>> 
> >>>>> 
> >>>>> Daniel
> >>>>> 
> >>>>> [1] https://wiki.ubuntu.com/KernelTeam/GitKernelBuild
> >>>> 
> >>>> Your directions were almost perfect, so even I was able to build the
> >>>> kernel. I made a discovery using the new kernel that might help someone
> >>>> more familiar with the code than I am to localize the problem.  I am
> >>>> still hearing the blip when I play audio sampled at 88.2 kHz, but I
> >>>> just
> >>>> noticed that the blip is perfectly periodic, with a period of about
> >>>> 16.4
> >>>> seconds.  I am playing a sine wave synthesized using GStreamer using
> >>>> the
> >>>> following command:
> >>>> 
> >>>> gst-launch audiotestsrc volume=0.01 ! audio/x-raw-float, width=64,
> >>>> rate=88200, channels=2, endianness=1234 ! audioconvert ! alsasink
> >>>> 
> >>>> A sine wave makes it easier to hear the blip.  Does this clue suggest
> >>>> anything?
> >>>> 
> >>>> I also want to mention that when I use the new kernel, I do not get the
> >>>> ticks at either 88.2 or 96 kHz even when I do not use the external USB
> >>>> hub.  I plan next to back up to the 3.6.2 kernel to see whether I still
> >>>> get ticks there.
> >>> 
> >>> Which kernel did you use when you heard the 'blibs'?
> >> 
> >> The latest news is bad.  I am on 3.2.0 now.  The USB DAC is working
> >> perfectly at this moment at both 96 kHz and 88.2 kHz without the external
> >> USB hub (imagine calling that bad news).  If I set the srate to 88.2 kHz
> >> and stop and start the sine wave, sometimes I get the blip.  Forget about
> >> its being periodic.  It was definitely periodic before lunch; now I
> >> usually
> >> get random intervals if I get any blips at all.  As I am typing this
> >> message, I can't get blips at all.  There was some correlation between
> >> changing sample rates and blips, but I can't reproduce that behavior now.
> >> What is most weird is that I haven't gotten any ticks since lunch with
> >> any
> >> kernel or with either sample rate, yet they were reliable earlier today
> >> unless I used the external USB hub. I obviously need to experiment some
> >> more to see whether I can observe a pattern.
> > 
> > To conclude (?) this thread, I am now convinced that the anomalies I
> > observed were unrelated to the device driver.  I had two theories
> > remaining.  One was that the problem was somehow related to an
> > overheating problem.  I used a heat gun to convince myself that the
> > theory was wrong.  The other was that the problem had something to do
> > with services running in the background that interfered with the device
> > driver.  I removed or disabled all services that I could identify as
> > superfluous.  Removed services include zeitgeist, apparmor, modemmanager,
> > mdadm, and bluetooth.  Disabled services include atd, dns-clean, and
> > pppd-dns.  The system has been running perfectly with an 88.2 kHz sample
> > rate and no external USB hub for 2 days.  However, I tried booting the
> > system with a copy of the OS from before I removed superfluous services. 
> > It still ran perfectly.  Thus, I cannot convince myself that removing
> > superfluous services actually solved the problem.  I suppose it's
> > possible that some service was running sporadically, which could explain
> > why the problem seemed to come and go and also why the problem did not
> > occur when I booted the copy of the OS. As long as the problem remains
> > dormant I have no alternative but to move on and see whether the problem
> > eventually recurs.  Only time will tell.
> > 
> > Thanks for all the help.  Hey, I built a kernel and got my own version of
> > the device driver to run.  That was exciting.
> > 
> > --------------------------------------------------------------------------
> > ----
> > 
> > I'm back.  The USB DAC continued to work for two more days after my last
> > message and then the blips resumed.  I've been digging into the driver
> > code
> > for two days.  I spent today trying to convince myself that the driver is
> > actually using an asynchronous protocol.  The blips are almost certainly
> > buffer underruns, which I could account for if the driver were not
> > responding to asynchronous feedback from the DAC.  I expected to see a
> > deviation from the pattern of one frame with 89 samples followed by 4
> > frames with 88 (which results in 88,200 samples per second).  That
> > sequence would work perfectly if the clocks in the computer and in the
> > USB DAC were exactly the same frequency, but of course they are not. 
> > Consequently, I would expect to see requests for one sample more or less
> > once in a while, depending on whether the clock in the computer is slower
> > or faster than the one in the DAC.  What I see is 89 + 4 * 88 almost all
> > the time, as expected .  Once in a while there is a request for an
> > additional frame of 88 and then the pattern of 89 + 4 * 88 resumes.  I
> > presume that the break in the usual pattern indicates that the device
> > driver is responding to a request from the DAC for fewer samples, which
> > confirms that the driver is using the asynchronous protocol.  That's
> > good, if I am right. However, sticking in an extra packet of only 88
> > would be the expected deviation if the host were getting a little ahead
> > of the DAC, yet the blip is almost certainly a buffer underrun, which
> > means that the host is actually falling behind.  Thus, an extra packet of
> > 89 would make more sense.  I should also mention that there is no
> > correlation between the timing of the extra packet of 88 and the audible
> > blip.  Something seems wrong here, but I'm not sure where to go next.
> > 
> > On a related topic, to confirm that the blip is a buffer underrun, I would
> > like to synthesize a waveform that is DC.  With DC, an overrun would not
> > produce any audible anomalies whereas an underrun would be audible.  I am
> > using GStreamer to synthesize the test waveform.  Does anyone know of a
> > way to synthesize a DC waveform using GStreamer?  If not, is there any
> > other tool available in Linux?
> > 
> > By the way, I bought another USB DAC from a different manufacturer to be
> > sure that the anomalies I am observing were not due to a defect in the
> > DAC.  They both display the same problem.
> > 
> > -----------------------------------------------------
> > 
> > I modified the device driver to output a constant instead of the incoming
> > waveform.  I get blips, as I expected, so I am now certain that the blips
> > are caused by a buffer underrun.  The blips occur periodically again --
> > period of about 16.5 seconds.  I presume that the period is related to
> > the difference in clock rates between the host and DAC.  Roughly every
> > 3-4 blips, I get an extra packet of 88 samples.  To prevent buffer
> > underrun, I ought to be getting an extra packet of 89 samples every 16.5
> > seconds, but I never do.
> 
> Thanks for all your investigation on this! Sending computed data instead
> of the payload delivered by the ALSA stack is in fact a very good way to
> isolate the issue.
> 
> The question is: if the algorithm in the USB driver miscalculates the
> number of samples to send over time, what't the reason for that? Does
> the device report bogus values or is there this a bug in the driver?

Well, I have two DACs, each from a different manufacturer.  Both experience 
underruns (though not at the same rate).  It's possible that they are both 
reporting bogus values, but unlikely, so I'm leaning toward the bug theory.

> Did you read chapter 5.4.12.1 of the USB2.0 spec, and can you explain
> where you suspect the bug to be? The current implementation in the
> driver is quite straight forward, mapping all feedback values to Q16.16
> and keeping the lower 16bits around for phase compensation between the
> calculation of the packet sizes.

Do you perhaps mean chapter 5.12.4.1 (Synchronization Type)?  I'm not finding a 
5.4.12.1 in usb_20.pdf from a zip dated 102512.

Please tell me whether I have this right:

You start transferring the sound in snd_usb_endpoint_start using 
usb_submit_urb to submit 2 urbs to the USB core.  The urbs specify that on 
completion, the USB core should call snd_complete_urb.  snd_complete_urb 
resubmits the urb after calling retire_playback_urb (by way of 
retire_outbound_urb which calls retire_data_urb which is retire_playback_urb), 
which updates its estimate of delay (what's that?  It seems to be 0 always) 
and prepare_playback_urb (by way of prepare_outbound_urb which calls 
prepare_data_urb which is prepare_playback_urb), which fills the transfer_buffer 
in the urb with the audio data (from a DMA buffer, I guess).

Before filling transfer_buffer, prepare_playback_urb calls 
snd_usb_endpoint_next_packet_size to compute the number of samples to send.  
This code appears to be the crux of what I need to understand because the 
value returned from this function is what is supposed to adjust to prevent 
buffer underruns.  It isn't clear to me how this function gets information 
about the state of the buffer in the device.  The only argument to 
snd_usb_endpoint_next_packet_size is ep, which is a pointer to the 
snd_usb_endpoint structure.  I see that ep->phase is the Q16.16 value you 
mentioned, so the lower 16 bits are for "phase compensation between the 
calculation of the packet sizes".  I don't completely understand that phrase.  
freqm is an unchanging value (5780275) and datainterval is an unchanging value 
(0).  phase fluctuates in a narrow range (roughly 5792282 to 5832702), but it 
is fluctuating only as a consequence of this calculation: we take the bottom 16 
bits of its value and add a fixed value.  If I understand this calculation 
correctly, I can almost see how it could provide the sequence of packet sizes 
(the 89 + 4 * 88 sequence) necessary to produce the correct number of samples 
per second, but I don't see how it adjusts that number to the slightly 
different concept of time at the device.  However, even in that understanding I 
am perplexed because I occasionally see an extra packet of 88.

Also, I think I understand why you start the transfer with 2 urbs:  When the 
device finishes with the first urb, the next urb has to be there already to 
avoid a period when no urb is present.  However, right away an alarm goes off.  
When the device finishes processing the first urb, it provides feedback about 
the state of the buffer.  However, the host cannot respond to this feedback 
until after the second urb is processed.  Have we convinced ourselves that the 
lag doesn't matter?  I don't know because I don't understand what happens to 
the urb after we send it to the USB core.  What do you know about the nature 
of the buffering in the device?  Is there a place for the USB hardware to store 
the contents of transfer_buffer independently of a buffer that feeds the actual 
DAC?  When does the USB hardware transfer the second urb to the device?  Who 
tells the DAC to start playing the contents of the buffer?  I would like to 
hear that the device has a FIFO whose size is sufficient to hold the contents of 
at least two transfer_buffers.  The first two urbs would fill it before 
activating the DAC.  Every time the DAC finishes outputting the contents of one 
urb, it provides feedback with the amount of space remaining in the FIFO.  We 
would send that many samples in the next urb.  I am fantasizing this solution.  
Tell me how it really works.

> If you find a better solution, please share it here, preferably in the
> form of a patch :)

Of course.  I would be honored to provide a patch, but I am so far out of my 
depth I advise that you not hold your breath.
-- 
Jeffrey Barish

------------------------------------------------------------------------------
LogMeIn Central: Instant, anywhere, Remote PC access and management.
Stay in control, update software, and manage PCs from one command center
Diagnose problems and improve visibility into emerging IT issues
Automate, monitor and manage. Do more in less time with Central
http://p.sf.net/sfu/logmein12331_d2d

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

* Re: Ticks when playing to USB DAC at high sample rates
  2012-11-04 10:39       ` [Alsa-user] Ticks when playing to USB DAC at high sample rates Daniel Mack
  2012-11-05  1:53         ` Jeffrey Barish
@ 2012-11-05 14:20         ` Jeffrey Barish
  1 sibling, 0 replies; 14+ messages in thread
From: Jeffrey Barish @ 2012-11-05 14:20 UTC (permalink / raw)
  To: Daniel Mack; +Cc: alsa-user, alsa-devel

On Sun 04 November 2012 11:39:48 Daniel Mack wrote:
> [cc alsa-devel]
> 
> On 04.11.2012 02:25, Jeffrey Barish wrote:
> > On Fri 26 October 2012 15:21:06 Jeffrey Barish wrote:
> >> On Fri 26 October 2012 21:47:05 Daniel Mack wrote:
> >>> On 26.10.2012 21:43, Jeffrey Barish wrote:
> >>>> On Thu 25 October 2012 19:10:45 Daniel Mack wrote:
> >>>>> On 25.10.2012 17:18, Jeffrey Barish wrote:
> >>>>>> I found something in the snd_usb_audio code (in endpoint.c) that
> >>>>>> could
> >>>>>> explain one of the problems I have observed (the ticks). I would
> >>>>>> normally test my theory by modifying the code. In this case, I would
> >>>>>> like to stick in a print statement to see what values are being
> >>>>>> assigned
> >>>>>> to certain variables. Unfortunately, I am too ignorant to do
> >>>>>> something
> >>>>>> even this trivial as I have never worked on kernel code. I think I am
> >>>>>> supposed to use printk,
> >>>>> 
> >>>>> printk is nice for simple debugging, yes. But note that this call is
> >>>>> timing critical and should not be used in "fast path" code.
> >>>>> Introducing
> >>>>> a printk for each received packet for example will almost certainly
> >>>>> make
> >>>>> the driver behave quite differently.
> >>>>> 
> >>>>>> but beyond that I am lost. Can someone provide
> >>>>>> me with some directions? I need to know how to make the driver. To
> >>>>>> that
> >>>>>> end, I probably will have to install additional packages. After
> >>>>>> making
> >>>>>> the driver, I need to know how to install it over the existing
> >>>>>> driver.
> >>>>> 
> >>>>> Here's one way to do it:
> >>>>> 
> >>>>> 1. git clone
> >>>>> git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git (your
> >>>>> patch should apply on top of this tree eventually)
> >>>>> 2. cd sound
> >>>>> 3. zcat /proc/config.gz >.config
> >>>>> 4. build and install the kernel image. How that is done depends on the
> >>>>> distribution you're using. For Ubuntu follow the docs at [1] (start at
> >>>>> point #5). For Fedora and others, something like "make && make
> >>>>> install"
> >>>>> should do
> >>>>> 5. reboot and check that the new kernel is running
> >>>>> 6. hack on sound/usb
> >>>>> 7. make M=sound/usb
> >>>>> 8. reload the module with "sudo rmmod snd_usb_audio; sudo insmod
> >>>>> sound/usb/snd-usb-audio.ko" (better plug out the device before so you
> >>>>> always have the same defined point of start)
> >>>>> 
> >>>>> 
> >>>>> Hope that works for you.
> >>>>> 
> >>>>> 
> >>>>> Daniel
> >>>>> 
> >>>>> [1] https://wiki.ubuntu.com/KernelTeam/GitKernelBuild
> >>>> 
> >>>> Your directions were almost perfect, so even I was able to build the
> >>>> kernel. I made a discovery using the new kernel that might help someone
> >>>> more familiar with the code than I am to localize the problem.  I am
> >>>> still hearing the blip when I play audio sampled at 88.2 kHz, but I
> >>>> just
> >>>> noticed that the blip is perfectly periodic, with a period of about
> >>>> 16.4
> >>>> seconds.  I am playing a sine wave synthesized using GStreamer using
> >>>> the
> >>>> following command:
> >>>> 
> >>>> gst-launch audiotestsrc volume=0.01 ! audio/x-raw-float, width=64,
> >>>> rate=88200, channels=2, endianness=1234 ! audioconvert ! alsasink
> >>>> 
> >>>> A sine wave makes it easier to hear the blip.  Does this clue suggest
> >>>> anything?
> >>>> 
> >>>> I also want to mention that when I use the new kernel, I do not get the
> >>>> ticks at either 88.2 or 96 kHz even when I do not use the external USB
> >>>> hub.  I plan next to back up to the 3.6.2 kernel to see whether I still
> >>>> get ticks there.
> >>> 
> >>> Which kernel did you use when you heard the 'blibs'?
> >> 
> >> The latest news is bad.  I am on 3.2.0 now.  The USB DAC is working
> >> perfectly at this moment at both 96 kHz and 88.2 kHz without the external
> >> USB hub (imagine calling that bad news).  If I set the srate to 88.2 kHz
> >> and stop and start the sine wave, sometimes I get the blip.  Forget about
> >> its being periodic.  It was definitely periodic before lunch; now I
> >> usually
> >> get random intervals if I get any blips at all.  As I am typing this
> >> message, I can't get blips at all.  There was some correlation between
> >> changing sample rates and blips, but I can't reproduce that behavior now.
> >> What is most weird is that I haven't gotten any ticks since lunch with
> >> any
> >> kernel or with either sample rate, yet they were reliable earlier today
> >> unless I used the external USB hub. I obviously need to experiment some
> >> more to see whether I can observe a pattern.
> > 
> > To conclude (?) this thread, I am now convinced that the anomalies I
> > observed were unrelated to the device driver.  I had two theories
> > remaining.  One was that the problem was somehow related to an
> > overheating problem.  I used a heat gun to convince myself that the
> > theory was wrong.  The other was that the problem had something to do
> > with services running in the background that interfered with the device
> > driver.  I removed or disabled all services that I could identify as
> > superfluous.  Removed services include zeitgeist, apparmor, modemmanager,
> > mdadm, and bluetooth.  Disabled services include atd, dns-clean, and
> > pppd-dns.  The system has been running perfectly with an 88.2 kHz sample
> > rate and no external USB hub for 2 days.  However, I tried booting the
> > system with a copy of the OS from before I removed superfluous services. 
> > It still ran perfectly.  Thus, I cannot convince myself that removing
> > superfluous services actually solved the problem.  I suppose it's
> > possible that some service was running sporadically, which could explain
> > why the problem seemed to come and go and also why the problem did not
> > occur when I booted the copy of the OS. As long as the problem remains
> > dormant I have no alternative but to move on and see whether the problem
> > eventually recurs.  Only time will tell.
> > 
> > Thanks for all the help.  Hey, I built a kernel and got my own version of
> > the device driver to run.  That was exciting.
> > 
> > --------------------------------------------------------------------------
> > ----
> > 
> > I'm back.  The USB DAC continued to work for two more days after my last
> > message and then the blips resumed.  I've been digging into the driver
> > code
> > for two days.  I spent today trying to convince myself that the driver is
> > actually using an asynchronous protocol.  The blips are almost certainly
> > buffer underruns, which I could account for if the driver were not
> > responding to asynchronous feedback from the DAC.  I expected to see a
> > deviation from the pattern of one frame with 89 samples followed by 4
> > frames with 88 (which results in 88,200 samples per second).  That
> > sequence would work perfectly if the clocks in the computer and in the
> > USB DAC were exactly the same frequency, but of course they are not. 
> > Consequently, I would expect to see requests for one sample more or less
> > once in a while, depending on whether the clock in the computer is slower
> > or faster than the one in the DAC.  What I see is 89 + 4 * 88 almost all
> > the time, as expected .  Once in a while there is a request for an
> > additional frame of 88 and then the pattern of 89 + 4 * 88 resumes.  I
> > presume that the break in the usual pattern indicates that the device
> > driver is responding to a request from the DAC for fewer samples, which
> > confirms that the driver is using the asynchronous protocol.  That's
> > good, if I am right. However, sticking in an extra packet of only 88
> > would be the expected deviation if the host were getting a little ahead
> > of the DAC, yet the blip is almost certainly a buffer underrun, which
> > means that the host is actually falling behind.  Thus, an extra packet of
> > 89 would make more sense.  I should also mention that there is no
> > correlation between the timing of the extra packet of 88 and the audible
> > blip.  Something seems wrong here, but I'm not sure where to go next.
> > 
> > On a related topic, to confirm that the blip is a buffer underrun, I would
> > like to synthesize a waveform that is DC.  With DC, an overrun would not
> > produce any audible anomalies whereas an underrun would be audible.  I am
> > using GStreamer to synthesize the test waveform.  Does anyone know of a
> > way to synthesize a DC waveform using GStreamer?  If not, is there any
> > other tool available in Linux?
> > 
> > By the way, I bought another USB DAC from a different manufacturer to be
> > sure that the anomalies I am observing were not due to a defect in the
> > DAC.  They both display the same problem.
> > 
> > -----------------------------------------------------
> > 
> > I modified the device driver to output a constant instead of the incoming
> > waveform.  I get blips, as I expected, so I am now certain that the blips
> > are caused by a buffer underrun.  The blips occur periodically again --
> > period of about 16.5 seconds.  I presume that the period is related to
> > the difference in clock rates between the host and DAC.  Roughly every
> > 3-4 blips, I get an extra packet of 88 samples.  To prevent buffer
> > underrun, I ought to be getting an extra packet of 89 samples every 16.5
> > seconds, but I never do.
> 
> Thanks for all your investigation on this! Sending computed data instead
> of the payload delivered by the ALSA stack is in fact a very good way to
> isolate the issue.
> 
> The question is: if the algorithm in the USB driver miscalculates the
> number of samples to send over time, what't the reason for that? Does
> the device report bogus values or is there this a bug in the driver?

Well, I have two DACs, each from a different manufacturer.  Both experience 
underruns (though not at the same rate).  It's possible that they are both 
reporting bogus values, but unlikely, so I'm leaning toward the bug theory.

> Did you read chapter 5.4.12.1 of the USB2.0 spec, and can you explain
> where you suspect the bug to be? The current implementation in the
> driver is quite straight forward, mapping all feedback values to Q16.16
> and keeping the lower 16bits around for phase compensation between the
> calculation of the packet sizes.

Do you perhaps mean chapter 5.12.4.1 (Synchronization Type)?  I'm not finding a 
5.4.12.1 in usb_20.pdf from a zip dated 102512.

Please tell me whether I have this right:

You start transferring the sound in snd_usb_endpoint_start using 
usb_submit_urb to submit 2 urbs to the USB core.  The urbs specify that on 
completion, the USB core should call snd_complete_urb.  snd_complete_urb 
resubmits the urb after calling retire_playback_urb (by way of 
retire_outbound_urb which calls retire_data_urb which is retire_playback_urb), 
which updates its estimate of delay (what's that?  It seems to be 0 always) 
and prepare_playback_urb (by way of prepare_outbound_urb which calls 
prepare_data_urb which is prepare_playback_urb), which fills the transfer_buffer 
in the urb with the audio data (from a DMA buffer, I guess).

Before filling transfer_buffer, prepare_playback_urb calls 
snd_usb_endpoint_next_packet_size to compute the number of samples to send.  
This code appears to be the crux of what I need to understand because the 
value returned from this function is what is supposed to adjust to prevent 
buffer underruns.  It isn't clear to me how this function gets information 
about the state of the buffer in the device.  The only argument to 
snd_usb_endpoint_next_packet_size is ep, which is a pointer to the 
snd_usb_endpoint structure.  I see that ep->phase is the Q16.16 value you 
mentioned, so the lower 16 bits are for "phase compensation between the 
calculation of the packet sizes".  I don't completely understand that phrase.  
freqm is an unchanging value (5780275) and datainterval is an unchanging value 
(0).  phase fluctuates in a narrow range (roughly 5792282 to 5832702), but it 
is fluctuating only as a consequence of this calculation: we take the bottom 16 
bits of its value and add a fixed value.  If I understand this calculation 
correctly, I can almost see how it could provide the sequence of packet sizes 
(the 89 + 4 * 88 sequence) necessary to produce the correct number of samples 
per second, but I don't see how it adjusts that number to the slightly 
different concept of time at the device.  However, even in that understanding I 
am perplexed because I occasionally see an extra packet of 88.

Also, I think I understand why you start the transfer with 2 urbs:  When the 
device finishes with the first urb, the next urb has to be there already to 
avoid a period when no urb is present.  However, right away an alarm goes off.  
When the device finishes processing the first urb, it provides feedback about 
the state of the buffer.  However, the host cannot respond to this feedback 
until after the second urb is processed.  Have we convinced ourselves that the 
lag doesn't matter?  I don't know because I don't understand what happens to 
the urb after we send it to the USB core.  What do you know about the nature 
of the buffering in the device?  Is there a place for the USB hardware to store 
the contents of transfer_buffer independently of a buffer that feeds the actual 
DAC?  When does the USB hardware transfer the second urb to the device?  Who 
tells the DAC to start playing the contents of the buffer?  I would like to 
hear that the device has a FIFO whose size is sufficient to hold the contents of 
at least two transfer_buffers.  The first two urbs would fill it before 
activating the DAC.  Every time the DAC finishes outputting the contents of one 
urb, it provides feedback with the amount of space remaining in the FIFO.  We 
would send that many samples in the next urb.  I am fantasizing this solution.  
Tell me how it really works.

> If you find a better solution, please share it here, preferably in the
> form of a patch :)

Of course.  I would be honored to provide a patch, but I am so far out of my 
depth I advise that you not hold your breath.

---------------------------------------------------------------

Wait.  I think I got it.  Instead of changing the number of samples sent per 
constant unit of time, the driver changes the unit of time in which it sends a 
constant number of samples.  When the device finishes processing an urb, it 
calls snd_complete_urb.  It doesn't matter whether the device is running 
faster or slower than the host, when it finishes an urb it sends a request for 
the next urb.  All the host has to do is respond with the correct number of 
samples whenever it gets the request for the next urb.  The host is oblivious 
to time.

With this approach, the pattern of payload sizes should be 89 + 4 * 88 (for a 
sample rate of 88.2 kHz).  It isn't.  I am seeing an occasional extra packet 
of 88.  That deviation from the correct pattern means that the buffer will 
gradually drain, leading to a buffer underflow.  Buffer underflow is what is 
causing the audible anomalies.

As a test, I am going to try hardwiring the pattern 89 + 4 * 88.
-- 
Jeffrey Barish

------------------------------------------------------------------------------
LogMeIn Central: Instant, anywhere, Remote PC access and management.
Stay in control, update software, and manage PCs from one command center
Diagnose problems and improve visibility into emerging IT issues
Automate, monitor and manage. Do more in less time with Central
http://p.sf.net/sfu/logmein12331_d2d

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

* Re: [Alsa-user] Ticks when playing to USB DAC at high sample rates
  2012-11-05  1:53         ` Jeffrey Barish
@ 2012-11-05 15:03           ` Daniel Mack
  2012-11-05 22:29             ` Jeffrey Barish
  0 siblings, 1 reply; 14+ messages in thread
From: Daniel Mack @ 2012-11-05 15:03 UTC (permalink / raw)
  To: Jeffrey Barish; +Cc: alsa-user, alsa-devel

Hi Jeff,

On 05.11.2012 02:53, Jeffrey Barish wrote:
> On Sun 04 November 2012 11:39:48 Daniel Mack wrote:
>> [cc alsa-devel]
>>
>> On 04.11.2012 02:25, Jeffrey Barish wrote:
>>> On Fri 26 October 2012 15:21:06 Jeffrey Barish wrote:
>>>> On Fri 26 October 2012 21:47:05 Daniel Mack wrote:
>>>>> On 26.10.2012 21:43, Jeffrey Barish wrote:
>>>>>> On Thu 25 October 2012 19:10:45 Daniel Mack wrote:
>>>>>>> On 25.10.2012 17:18, Jeffrey Barish wrote:
>>>>>>>> I found something in the snd_usb_audio code (in endpoint.c) that
>>>>>>>> could
>>>>>>>> explain one of the problems I have observed (the ticks). I would
>>>>>>>> normally test my theory by modifying the code. In this case, I would
>>>>>>>> like to stick in a print statement to see what values are being
>>>>>>>> assigned
>>>>>>>> to certain variables. Unfortunately, I am too ignorant to do
>>>>>>>> something
>>>>>>>> even this trivial as I have never worked on kernel code. I think I am
>>>>>>>> supposed to use printk,
>>>>>>>
>>>>>>> printk is nice for simple debugging, yes. But note that this call is
>>>>>>> timing critical and should not be used in "fast path" code.
>>>>>>> Introducing
>>>>>>> a printk for each received packet for example will almost certainly
>>>>>>> make
>>>>>>> the driver behave quite differently.
>>>>>>>
>>>>>>>> but beyond that I am lost. Can someone provide
>>>>>>>> me with some directions? I need to know how to make the driver. To
>>>>>>>> that
>>>>>>>> end, I probably will have to install additional packages. After
>>>>>>>> making
>>>>>>>> the driver, I need to know how to install it over the existing
>>>>>>>> driver.
>>>>>>>
>>>>>>> Here's one way to do it:
>>>>>>>
>>>>>>> 1. git clone
>>>>>>> git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git (your
>>>>>>> patch should apply on top of this tree eventually)
>>>>>>> 2. cd sound
>>>>>>> 3. zcat /proc/config.gz >.config
>>>>>>> 4. build and install the kernel image. How that is done depends on the
>>>>>>> distribution you're using. For Ubuntu follow the docs at [1] (start at
>>>>>>> point #5). For Fedora and others, something like "make && make
>>>>>>> install"
>>>>>>> should do
>>>>>>> 5. reboot and check that the new kernel is running
>>>>>>> 6. hack on sound/usb
>>>>>>> 7. make M=sound/usb
>>>>>>> 8. reload the module with "sudo rmmod snd_usb_audio; sudo insmod
>>>>>>> sound/usb/snd-usb-audio.ko" (better plug out the device before so you
>>>>>>> always have the same defined point of start)
>>>>>>>
>>>>>>>
>>>>>>> Hope that works for you.
>>>>>>>
>>>>>>>
>>>>>>> Daniel
>>>>>>>
>>>>>>> [1] https://wiki.ubuntu.com/KernelTeam/GitKernelBuild
>>>>>>
>>>>>> Your directions were almost perfect, so even I was able to build the
>>>>>> kernel. I made a discovery using the new kernel that might help someone
>>>>>> more familiar with the code than I am to localize the problem.  I am
>>>>>> still hearing the blip when I play audio sampled at 88.2 kHz, but I
>>>>>> just
>>>>>> noticed that the blip is perfectly periodic, with a period of about
>>>>>> 16.4
>>>>>> seconds.  I am playing a sine wave synthesized using GStreamer using
>>>>>> the
>>>>>> following command:
>>>>>>
>>>>>> gst-launch audiotestsrc volume=0.01 ! audio/x-raw-float, width=64,
>>>>>> rate=88200, channels=2, endianness=1234 ! audioconvert ! alsasink
>>>>>>
>>>>>> A sine wave makes it easier to hear the blip.  Does this clue suggest
>>>>>> anything?
>>>>>>
>>>>>> I also want to mention that when I use the new kernel, I do not get the
>>>>>> ticks at either 88.2 or 96 kHz even when I do not use the external USB
>>>>>> hub.  I plan next to back up to the 3.6.2 kernel to see whether I still
>>>>>> get ticks there.
>>>>>
>>>>> Which kernel did you use when you heard the 'blibs'?
>>>>
>>>> The latest news is bad.  I am on 3.2.0 now.  The USB DAC is working
>>>> perfectly at this moment at both 96 kHz and 88.2 kHz without the external
>>>> USB hub (imagine calling that bad news).  If I set the srate to 88.2 kHz
>>>> and stop and start the sine wave, sometimes I get the blip.  Forget about
>>>> its being periodic.  It was definitely periodic before lunch; now I
>>>> usually
>>>> get random intervals if I get any blips at all.  As I am typing this
>>>> message, I can't get blips at all.  There was some correlation between
>>>> changing sample rates and blips, but I can't reproduce that behavior now.
>>>> What is most weird is that I haven't gotten any ticks since lunch with
>>>> any
>>>> kernel or with either sample rate, yet they were reliable earlier today
>>>> unless I used the external USB hub. I obviously need to experiment some
>>>> more to see whether I can observe a pattern.
>>>
>>> To conclude (?) this thread, I am now convinced that the anomalies I
>>> observed were unrelated to the device driver.  I had two theories
>>> remaining.  One was that the problem was somehow related to an
>>> overheating problem.  I used a heat gun to convince myself that the
>>> theory was wrong.  The other was that the problem had something to do
>>> with services running in the background that interfered with the device
>>> driver.  I removed or disabled all services that I could identify as
>>> superfluous.  Removed services include zeitgeist, apparmor, modemmanager,
>>> mdadm, and bluetooth.  Disabled services include atd, dns-clean, and
>>> pppd-dns.  The system has been running perfectly with an 88.2 kHz sample
>>> rate and no external USB hub for 2 days.  However, I tried booting the
>>> system with a copy of the OS from before I removed superfluous services. 
>>> It still ran perfectly.  Thus, I cannot convince myself that removing
>>> superfluous services actually solved the problem.  I suppose it's
>>> possible that some service was running sporadically, which could explain
>>> why the problem seemed to come and go and also why the problem did not
>>> occur when I booted the copy of the OS. As long as the problem remains
>>> dormant I have no alternative but to move on and see whether the problem
>>> eventually recurs.  Only time will tell.
>>>
>>> Thanks for all the help.  Hey, I built a kernel and got my own version of
>>> the device driver to run.  That was exciting.
>>>
>>> --------------------------------------------------------------------------
>>> ----
>>>
>>> I'm back.  The USB DAC continued to work for two more days after my last
>>> message and then the blips resumed.  I've been digging into the driver
>>> code
>>> for two days.  I spent today trying to convince myself that the driver is
>>> actually using an asynchronous protocol.  The blips are almost certainly
>>> buffer underruns, which I could account for if the driver were not
>>> responding to asynchronous feedback from the DAC.  I expected to see a
>>> deviation from the pattern of one frame with 89 samples followed by 4
>>> frames with 88 (which results in 88,200 samples per second).  That
>>> sequence would work perfectly if the clocks in the computer and in the
>>> USB DAC were exactly the same frequency, but of course they are not. 
>>> Consequently, I would expect to see requests for one sample more or less
>>> once in a while, depending on whether the clock in the computer is slower
>>> or faster than the one in the DAC.  What I see is 89 + 4 * 88 almost all
>>> the time, as expected .  Once in a while there is a request for an
>>> additional frame of 88 and then the pattern of 89 + 4 * 88 resumes.  I
>>> presume that the break in the usual pattern indicates that the device
>>> driver is responding to a request from the DAC for fewer samples, which
>>> confirms that the driver is using the asynchronous protocol.  That's
>>> good, if I am right. However, sticking in an extra packet of only 88
>>> would be the expected deviation if the host were getting a little ahead
>>> of the DAC, yet the blip is almost certainly a buffer underrun, which
>>> means that the host is actually falling behind.  Thus, an extra packet of
>>> 89 would make more sense.  I should also mention that there is no
>>> correlation between the timing of the extra packet of 88 and the audible
>>> blip.  Something seems wrong here, but I'm not sure where to go next.
>>>
>>> On a related topic, to confirm that the blip is a buffer underrun, I would
>>> like to synthesize a waveform that is DC.  With DC, an overrun would not
>>> produce any audible anomalies whereas an underrun would be audible.  I am
>>> using GStreamer to synthesize the test waveform.  Does anyone know of a
>>> way to synthesize a DC waveform using GStreamer?  If not, is there any
>>> other tool available in Linux?
>>>
>>> By the way, I bought another USB DAC from a different manufacturer to be
>>> sure that the anomalies I am observing were not due to a defect in the
>>> DAC.  They both display the same problem.
>>>
>>> -----------------------------------------------------
>>>
>>> I modified the device driver to output a constant instead of the incoming
>>> waveform.  I get blips, as I expected, so I am now certain that the blips
>>> are caused by a buffer underrun.  The blips occur periodically again --
>>> period of about 16.5 seconds.  I presume that the period is related to
>>> the difference in clock rates between the host and DAC.  Roughly every
>>> 3-4 blips, I get an extra packet of 88 samples.  To prevent buffer
>>> underrun, I ought to be getting an extra packet of 89 samples every 16.5
>>> seconds, but I never do.
>>
>> Thanks for all your investigation on this! Sending computed data instead
>> of the payload delivered by the ALSA stack is in fact a very good way to
>> isolate the issue.
>>
>> The question is: if the algorithm in the USB driver miscalculates the
>> number of samples to send over time, what't the reason for that? Does
>> the device report bogus values or is there this a bug in the driver?
> 
> Well, I have two DACs, each from a different manufacturer.  Both experience 
> underruns (though not at the same rate).  It's possible that they are both 
> reporting bogus values, but unlikely, so I'm leaning toward the bug theory.
> 
>> Did you read chapter 5.4.12.1 of the USB2.0 spec, and can you explain
>> where you suspect the bug to be? The current implementation in the
>> driver is quite straight forward, mapping all feedback values to Q16.16
>> and keeping the lower 16bits around for phase compensation between the
>> calculation of the packet sizes.
> 
> Do you perhaps mean chapter 5.12.4.1 (Synchronization Type)?  I'm not finding a 
> 5.4.12.1 in usb_20.pdf from a zip dated 102512.

Yes, sorry.

> Please tell me whether I have this right:
> 
> You start transferring the sound in snd_usb_endpoint_start using 
> usb_submit_urb to submit 2 urbs to the USB core.  The urbs specify that on 
> completion, the USB core should call snd_complete_urb.  snd_complete_urb 
> resubmits the urb after calling retire_playback_urb (by way of 
> retire_outbound_urb which calls retire_data_urb which is retire_playback_urb), 
> which updates its estimate of delay (what's that?  It seems to be 0 always) 

That's just an information that is passed to userspace for latency
compensation matters. As you don't stream data that ALSA passes up the
stack anymore in your tests (but static data), you can ignore this
detail for now.

> and prepare_playback_urb (by way of prepare_outbound_urb which calls 
> prepare_data_urb which is prepare_playback_urb), which fills the transfer_buffer 
> in the urb with the audio data (from a DMA buffer, I guess).
> 
> Before filling transfer_buffer, prepare_playback_urb calls 
> snd_usb_endpoint_next_packet_size to compute the number of samples to send.  
> This code appears to be the crux of what I need to understand because the 
> value returned from this function is what is supposed to adjust to prevent 
> buffer underruns.

That's correct.

> It isn't clear to me how this function gets information 
> about the state of the buffer in the device.

Via the callback of the feedback data endpoint - the momentary frequency
is updated there and referred to again in
snd_usb_endpoint_next_packet_size().

> The only argument to 
> snd_usb_endpoint_next_packet_size is ep, which is a pointer to the 
> snd_usb_endpoint structure.

Yes, the endpoint structure hold all runtime streaming details. Once a
sync urb is given back from the host controller, retire_inbound_urb() is
called and snd_usb_handle_sync_urb() cares for updating the momentary
frequency of the slave of the sync endpoint, which is the data endpoint
that is later on used by next_packet_size(). Makes sense?

> I see that ep->phase is the Q16.16 value you 
> mentioned, so the lower 16 bits are for "phase compensation between the 
> calculation of the packet sizes".  I don't completely understand that phrase.  
> freqm is an unchanging value (5780275)

freqm shouldn't be unchanging. Are you sure it really is? If so, is
snd_usb_handle_sync_urb() ever called in your setup?

> and datainterval is an unchanging value 
> (0).  phase fluctuates in a narrow range (roughly 5792282 to 5832702), but it 
> is fluctuating only as a consequence of this calculation: we take the bottom 16 
> bits of its value and add a fixed value.  If I understand this calculation 
> correctly, I can almost see how it could provide the sequence of packet sizes 
> (the 89 + 4 * 88 sequence) necessary to produce the correct number of samples 
> per second, but I don't see how it adjusts that number to the slightly 
> different concept of time at the device.  However, even in that understanding I 
> am perplexed because I occasionally see an extra packet of 88.

The device reports its buffer state by providing feedback information in
a perioc manner, as letting the host know about what the device think is
its correct data rate is the only way to compensate clock drifts.

> Also, I think I understand why you start the transfer with 2 urbs:  When the 
> device finishes with the first urb, the next urb has to be there already to 
> avoid a period when no urb is present.  However, right away an alarm goes off.  
> When the device finishes processing the first urb, it provides feedback about 
> the state of the buffer.  However, the host cannot respond to this feedback 
> until after the second urb is processed. Have we convinced ourselves that the
> lag doesn't matter?  I don't know because I don't understand what happens to 
> the urb after we send it to the USB core. What do you know about the nature
> of the buffering in the device?  Is there a place for the USB hardware to store 
> the contents of transfer_buffer independently of a buffer that feeds the actual 
> DAC?  When does the USB hardware transfer the second urb to the device? 

Isochronous transfers are scheduled on the bus and sent in the
configured time slot (or as soon as possible, if the ASAP flag is set).
Data payload should be distributed as evenly as possible over the
microframes to not blast the device's internal buffers due to bursts.

> Who 
> tells the DAC to start playing the contents of the buffer?

Ususally, once it has its buffers filled with data.

>  I would like to 
> hear that the device has a FIFO whose size is sufficient to hold the contents of 
> at least two transfer_buffers.  The first two urbs would fill it before 
> activating the DAC.  Every time the DAC finishes outputting the contents of one 
> urb, it provides feedback with the amount of space remaining in the FIFO.

Not quite. It does report the momentary frequency in periodic packets
(like every 16ms), not after each packet.

>  We 
> would send that many samples in the next urb.  I am fantasizing this solution.  
> Tell me how it really works.

It's described in 5.12.4.1 (Synchronization Type). The driver aims to be
as close the the actual data rate that is reported by the device every
couple of milliseconds.

Does that answer your questions?


Daniel

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

* Re: Ticks when playing to USB DAC at high sample rates
  2012-11-05 15:03           ` [Alsa-user] " Daniel Mack
@ 2012-11-05 22:29             ` Jeffrey Barish
  2012-11-06  0:12               ` [Alsa-user] " Daniel Mack
  0 siblings, 1 reply; 14+ messages in thread
From: Jeffrey Barish @ 2012-11-05 22:29 UTC (permalink / raw)
  To: Daniel Mack; +Cc: alsa-user, alsa-devel

On Mon 05 November 2012 16:03:00 Daniel Mack wrote:
> Hi Jeff,
> 
> On 05.11.2012 02:53, Jeffrey Barish wrote:
> > On Sun 04 November 2012 11:39:48 Daniel Mack wrote:
> >> [cc alsa-devel]
> >> 
> >> On 04.11.2012 02:25, Jeffrey Barish wrote:
> >>> On Fri 26 October 2012 15:21:06 Jeffrey Barish wrote:
> >>>> On Fri 26 October 2012 21:47:05 Daniel Mack wrote:
> >>>>> On 26.10.2012 21:43, Jeffrey Barish wrote:
> >>>>>> On Thu 25 October 2012 19:10:45 Daniel Mack wrote:
> >>>>>>> On 25.10.2012 17:18, Jeffrey Barish wrote:
> >>>>>>>> I found something in the snd_usb_audio code (in endpoint.c) that
> >>>>>>>> could
> >>>>>>>> explain one of the problems I have observed (the ticks). I would
> >>>>>>>> normally test my theory by modifying the code. In this case, I
> >>>>>>>> would
> >>>>>>>> like to stick in a print statement to see what values are being
> >>>>>>>> assigned
> >>>>>>>> to certain variables. Unfortunately, I am too ignorant to do
> >>>>>>>> something
> >>>>>>>> even this trivial as I have never worked on kernel code. I think I
> >>>>>>>> am
> >>>>>>>> supposed to use printk,
> >>>>>>> 
> >>>>>>> printk is nice for simple debugging, yes. But note that this call is
> >>>>>>> timing critical and should not be used in "fast path" code.
> >>>>>>> Introducing
> >>>>>>> a printk for each received packet for example will almost certainly
> >>>>>>> make
> >>>>>>> the driver behave quite differently.
> >>>>>>> 
> >>>>>>>> but beyond that I am lost. Can someone provide
> >>>>>>>> me with some directions? I need to know how to make the driver. To
> >>>>>>>> that
> >>>>>>>> end, I probably will have to install additional packages. After
> >>>>>>>> making
> >>>>>>>> the driver, I need to know how to install it over the existing
> >>>>>>>> driver.
> >>>>>>> 
> >>>>>>> Here's one way to do it:
> >>>>>>> 
> >>>>>>> 1. git clone
> >>>>>>> git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git (your
> >>>>>>> patch should apply on top of this tree eventually)
> >>>>>>> 2. cd sound
> >>>>>>> 3. zcat /proc/config.gz >.config
> >>>>>>> 4. build and install the kernel image. How that is done depends on
> >>>>>>> the
> >>>>>>> distribution you're using. For Ubuntu follow the docs at [1] (start
> >>>>>>> at
> >>>>>>> point #5). For Fedora and others, something like "make && make
> >>>>>>> install"
> >>>>>>> should do
> >>>>>>> 5. reboot and check that the new kernel is running
> >>>>>>> 6. hack on sound/usb
> >>>>>>> 7. make M=sound/usb
> >>>>>>> 8. reload the module with "sudo rmmod snd_usb_audio; sudo insmod
> >>>>>>> sound/usb/snd-usb-audio.ko" (better plug out the device before so
> >>>>>>> you
> >>>>>>> always have the same defined point of start)
> >>>>>>> 
> >>>>>>> 
> >>>>>>> Hope that works for you.
> >>>>>>> 
> >>>>>>> 
> >>>>>>> Daniel
> >>>>>>> 
> >>>>>>> [1] https://wiki.ubuntu.com/KernelTeam/GitKernelBuild
> >>>>>> 
> >>>>>> Your directions were almost perfect, so even I was able to build the
> >>>>>> kernel. I made a discovery using the new kernel that might help
> >>>>>> someone
> >>>>>> more familiar with the code than I am to localize the problem.  I am
> >>>>>> still hearing the blip when I play audio sampled at 88.2 kHz, but I
> >>>>>> just
> >>>>>> noticed that the blip is perfectly periodic, with a period of about
> >>>>>> 16.4
> >>>>>> seconds.  I am playing a sine wave synthesized using GStreamer using
> >>>>>> the
> >>>>>> following command:
> >>>>>> 
> >>>>>> gst-launch audiotestsrc volume=0.01 ! audio/x-raw-float, width=64,
> >>>>>> rate=88200, channels=2, endianness=1234 ! audioconvert ! alsasink
> >>>>>> 
> >>>>>> A sine wave makes it easier to hear the blip.  Does this clue suggest
> >>>>>> anything?
> >>>>>> 
> >>>>>> I also want to mention that when I use the new kernel, I do not get
> >>>>>> the
> >>>>>> ticks at either 88.2 or 96 kHz even when I do not use the external
> >>>>>> USB
> >>>>>> hub.  I plan next to back up to the 3.6.2 kernel to see whether I
> >>>>>> still
> >>>>>> get ticks there.
> >>>>> 
> >>>>> Which kernel did you use when you heard the 'blibs'?
> >>>> 
> >>>> The latest news is bad.  I am on 3.2.0 now.  The USB DAC is working
> >>>> perfectly at this moment at both 96 kHz and 88.2 kHz without the
> >>>> external
> >>>> USB hub (imagine calling that bad news).  If I set the srate to 88.2
> >>>> kHz
> >>>> and stop and start the sine wave, sometimes I get the blip.  Forget
> >>>> about
> >>>> its being periodic.  It was definitely periodic before lunch; now I
> >>>> usually
> >>>> get random intervals if I get any blips at all.  As I am typing this
> >>>> message, I can't get blips at all.  There was some correlation between
> >>>> changing sample rates and blips, but I can't reproduce that behavior
> >>>> now.
> >>>> What is most weird is that I haven't gotten any ticks since lunch with
> >>>> any
> >>>> kernel or with either sample rate, yet they were reliable earlier today
> >>>> unless I used the external USB hub. I obviously need to experiment some
> >>>> more to see whether I can observe a pattern.
> >>> 
> >>> To conclude (?) this thread, I am now convinced that the anomalies I
> >>> observed were unrelated to the device driver.  I had two theories
> >>> remaining.  One was that the problem was somehow related to an
> >>> overheating problem.  I used a heat gun to convince myself that the
> >>> theory was wrong.  The other was that the problem had something to do
> >>> with services running in the background that interfered with the device
> >>> driver.  I removed or disabled all services that I could identify as
> >>> superfluous.  Removed services include zeitgeist, apparmor,
> >>> modemmanager,
> >>> mdadm, and bluetooth.  Disabled services include atd, dns-clean, and
> >>> pppd-dns.  The system has been running perfectly with an 88.2 kHz sample
> >>> rate and no external USB hub for 2 days.  However, I tried booting the
> >>> system with a copy of the OS from before I removed superfluous services.
> >>> It still ran perfectly.  Thus, I cannot convince myself that removing
> >>> superfluous services actually solved the problem.  I suppose it's
> >>> possible that some service was running sporadically, which could explain
> >>> why the problem seemed to come and go and also why the problem did not
> >>> occur when I booted the copy of the OS. As long as the problem remains
> >>> dormant I have no alternative but to move on and see whether the problem
> >>> eventually recurs.  Only time will tell.
> >>> 
> >>> Thanks for all the help.  Hey, I built a kernel and got my own version
> >>> of
> >>> the device driver to run.  That was exciting.
> >>> 
> >>> ------------------------------------------------------------------------
> >>> --
> >>> ----
> >>> 
> >>> I'm back.  The USB DAC continued to work for two more days after my last
> >>> message and then the blips resumed.  I've been digging into the driver
> >>> code
> >>> for two days.  I spent today trying to convince myself that the driver
> >>> is
> >>> actually using an asynchronous protocol.  The blips are almost certainly
> >>> buffer underruns, which I could account for if the driver were not
> >>> responding to asynchronous feedback from the DAC.  I expected to see a
> >>> deviation from the pattern of one frame with 89 samples followed by 4
> >>> frames with 88 (which results in 88,200 samples per second).  That
> >>> sequence would work perfectly if the clocks in the computer and in the
> >>> USB DAC were exactly the same frequency, but of course they are not.
> >>> Consequently, I would expect to see requests for one sample more or less
> >>> once in a while, depending on whether the clock in the computer is
> >>> slower
> >>> or faster than the one in the DAC.  What I see is 89 + 4 * 88 almost all
> >>> the time, as expected .  Once in a while there is a request for an
> >>> additional frame of 88 and then the pattern of 89 + 4 * 88 resumes.  I
> >>> presume that the break in the usual pattern indicates that the device
> >>> driver is responding to a request from the DAC for fewer samples, which
> >>> confirms that the driver is using the asynchronous protocol.  That's
> >>> good, if I am right. However, sticking in an extra packet of only 88
> >>> would be the expected deviation if the host were getting a little ahead
> >>> of the DAC, yet the blip is almost certainly a buffer underrun, which
> >>> means that the host is actually falling behind.  Thus, an extra packet
> >>> of
> >>> 89 would make more sense.  I should also mention that there is no
> >>> correlation between the timing of the extra packet of 88 and the audible
> >>> blip.  Something seems wrong here, but I'm not sure where to go next.
> >>> 
> >>> On a related topic, to confirm that the blip is a buffer underrun, I
> >>> would
> >>> like to synthesize a waveform that is DC.  With DC, an overrun would not
> >>> produce any audible anomalies whereas an underrun would be audible.  I
> >>> am
> >>> using GStreamer to synthesize the test waveform.  Does anyone know of a
> >>> way to synthesize a DC waveform using GStreamer?  If not, is there any
> >>> other tool available in Linux?
> >>> 
> >>> By the way, I bought another USB DAC from a different manufacturer to be
> >>> sure that the anomalies I am observing were not due to a defect in the
> >>> DAC.  They both display the same problem.
> >>> 
> >>> -----------------------------------------------------
> >>> 
> >>> I modified the device driver to output a constant instead of the
> >>> incoming
> >>> waveform.  I get blips, as I expected, so I am now certain that the
> >>> blips
> >>> are caused by a buffer underrun.  The blips occur periodically again --
> >>> period of about 16.5 seconds.  I presume that the period is related to
> >>> the difference in clock rates between the host and DAC.  Roughly every
> >>> 3-4 blips, I get an extra packet of 88 samples.  To prevent buffer
> >>> underrun, I ought to be getting an extra packet of 89 samples every 16.5
> >>> seconds, but I never do.
> >> 
> >> Thanks for all your investigation on this! Sending computed data instead
> >> of the payload delivered by the ALSA stack is in fact a very good way to
> >> isolate the issue.
> >> 
> >> The question is: if the algorithm in the USB driver miscalculates the
> >> number of samples to send over time, what't the reason for that? Does
> >> the device report bogus values or is there this a bug in the driver?
> > 
> > Well, I have two DACs, each from a different manufacturer.  Both
> > experience
> > underruns (though not at the same rate).  It's possible that they are both
> > reporting bogus values, but unlikely, so I'm leaning toward the bug
> > theory.
> > 
> >> Did you read chapter 5.4.12.1 of the USB2.0 spec, and can you explain
> >> where you suspect the bug to be? The current implementation in the
> >> driver is quite straight forward, mapping all feedback values to Q16.16
> >> and keeping the lower 16bits around for phase compensation between the
> >> calculation of the packet sizes.
> > 
> > Do you perhaps mean chapter 5.12.4.1 (Synchronization Type)?  I'm not
> > finding a 5.4.12.1 in usb_20.pdf from a zip dated 102512.
> 
> Yes, sorry.
> 
> > Please tell me whether I have this right:
> > 
> > You start transferring the sound in snd_usb_endpoint_start using
> > usb_submit_urb to submit 2 urbs to the USB core.  The urbs specify that on
> > completion, the USB core should call snd_complete_urb.  snd_complete_urb
> > resubmits the urb after calling retire_playback_urb (by way of
> > retire_outbound_urb which calls retire_data_urb which is
> > retire_playback_urb), which updates its estimate of delay (what's that? 
> > It seems to be 0 always)
> That's just an information that is passed to userspace for latency
> compensation matters. As you don't stream data that ALSA passes up the
> stack anymore in your tests (but static data), you can ignore this
> detail for now.
> 
> > and prepare_playback_urb (by way of prepare_outbound_urb which calls
> > prepare_data_urb which is prepare_playback_urb), which fills the
> > transfer_buffer in the urb with the audio data (from a DMA buffer, I
> > guess).
> > 
> > Before filling transfer_buffer, prepare_playback_urb calls
> > snd_usb_endpoint_next_packet_size to compute the number of samples to
> > send.
> > This code appears to be the crux of what I need to understand because the
> > value returned from this function is what is supposed to adjust to prevent
> > buffer underruns.
> 
> That's correct.
> 
> > It isn't clear to me how this function gets information
> > about the state of the buffer in the device.
> 
> Via the callback of the feedback data endpoint - the momentary frequency
> is updated there and referred to again in
> snd_usb_endpoint_next_packet_size().
> 
> > The only argument to
> > snd_usb_endpoint_next_packet_size is ep, which is a pointer to the
> > snd_usb_endpoint structure.
> 
> Yes, the endpoint structure hold all runtime streaming details. Once a
> sync urb is given back from the host controller, retire_inbound_urb() is
> called and snd_usb_handle_sync_urb() cares for updating the momentary
> frequency of the slave of the sync endpoint, which is the data endpoint
> that is later on used by next_packet_size(). Makes sense?
> 
> > I see that ep->phase is the Q16.16 value you
> > mentioned, so the lower 16 bits are for "phase compensation between the
> > calculation of the packet sizes".  I don't completely understand that
> > phrase. freqm is an unchanging value (5780275)
> 
> freqm shouldn't be unchanging. Are you sure it really is? If so, is
> snd_usb_handle_sync_urb() ever called in your setup?

Yes.  freqm is always 5780275.  snd_usb_handle_sync_urb is never called.

snd_usb_handle_sync_urb is called from only one place, retire_inbound_urb, so 
the latter is never called.  I suppose that an inbound urb would never need to 
be retired if one were never submitted.  How about prepare_inbound_urb?  Also 
never called.  It is called from snd_usb_endpoint_start and snd_complete_urb, 
but only when usb_pipeout(ep->pipe) is false.  I can't find a definition for 
usb_pipeout, but I'm finding that usb_pipeout(ep->pipe) is always true.  I see 
ep->pipe being set in only place, in snd_usb_add_endpoint.  This function is 
called twice, once with is_playback 1 and once with it 0.  I'm not finding a 
definition for usb_sndisocpipe or usb_rcvisocpipe either, so I'm not sure why 
usb_pipeout(ep->pipe) is always true.  Nevertheless, what I'm seeing seems to 
be different from what you expected.  Note that snd_usb_add_endpoint does get 
called twice in set_format, once to create a data endpoint and once to create 
a sync endpoint.

These discrepancies may explain part of the puzzle I was missing yesterday.  I 
could not see where the driver was supposed to be getting feedback from the 
device.  Now I gather from your comments that there are supposed to be inbound 
urbs, presumably carrying information about the state of the device.

Since puzzling over the apparent absence of feedback about the state of the 
device, I had an epiphany this morning that such feedback is not necessary.  
The pattern of payload sizes should not change if the payloads are sent in 
response to a request from the device.  The device makes this request by 
calling snd_complete_urb when it finishes an urb.  As the device defines time, 
the host is responsible only for having the next urb ready when the device 
requests it.  Could it be that the missing feedback provides nonessential 
information about the state of the device, such as confirmation that the 
previous payload was successfully processed?

I repeated the test with a different DAC.  With that DAC it is still the case 
that snd_usb_handle_sync_urb is never called.

> > and datainterval is an unchanging value
> > (0).  phase fluctuates in a narrow range (roughly 5792282 to 5832702), but
> > it is fluctuating only as a consequence of this calculation: we take the
> > bottom 16 bits of its value and add a fixed value.  If I understand this
> > calculation correctly, I can almost see how it could provide the sequence
> > of packet sizes (the 89 + 4 * 88 sequence) necessary to produce the
> > correct number of samples per second, but I don't see how it adjusts that
> > number to the slightly different concept of time at the device.  However,
> > even in that understanding I am perplexed because I occasionally see an
> > extra packet of 88.
> 
> The device reports its buffer state by providing feedback information in
> a perioc manner, as letting the host know about what the device think is
> its correct data rate is the only way to compensate clock drifts.

In case I wasn't clear about my epiphany, let me explain it a different way.  
The host knows the sample rate that the device is trying to achieve -- let's 
say it's 88.2 kHz.  In order to achieve this sample rate, the host knows that 
it needs to send a packet of 89 samples followed by 4 packets of 88.  Every 5 
packets, the host sends 441 samples per channel or 882 samples total.  1000 
frames per second gets us to the required number of samples.  The device 
defines time.  It doesn't matter that its clock is a different frequency than 
the host's or that it drifts relative to the host's.  All that matters is that 
it tell the host when if finishes processing a packet.  The first time that 
happens, the host sends 89 samples.  The next time it sends 88.  Then it sends 
3 more packets of 88 followed by another packet of 89.  And so on.  The host 
doesn't need to know anything about time  because the sequence of packet sizes 
is defined by the nominal sample rate, which the host knows because it 
configured the DAC.  The actual timing is controlled by the device, but the 
sequence of packet sizes never changes.  If the clock in the device is a 
little slow, it will ask for the next packet a little late, but as far as the 
device is concerned, it is converting the requested number of samples per 
second, so the sequence of packet sizes that it requires is no different than 
it would be if its clock were running a little fast.

> > Also, I think I understand why you start the transfer with 2 urbs:  When
> > the device finishes with the first urb, the next urb has to be there
> > already to avoid a period when no urb is present.  However, right away an
> > alarm goes off. When the device finishes processing the first urb, it
> > provides feedback about the state of the buffer.  However, the host
> > cannot respond to this feedback until after the second urb is processed.
> > Have we convinced ourselves that the lag doesn't matter?  I don't know
> > because I don't understand what happens to the urb after we send it to
> > the USB core. What do you know about the nature of the buffering in the
> > device?  Is there a place for the USB hardware to store the contents of
> > transfer_buffer independently of a buffer that feeds the actual DAC? 
> > When does the USB hardware transfer the second urb to the device?
> Isochronous transfers are scheduled on the bus and sent in the
> configured time slot (or as soon as possible, if the ASAP flag is set).
> Data payload should be distributed as evenly as possible over the
> microframes to not blast the device's internal buffers due to bursts.
> 
> > Who
> > tells the DAC to start playing the contents of the buffer?
> 
> Ususally, once it has its buffers filled with data.
> 
> >  I would like to
> > 
> > hear that the device has a FIFO whose size is sufficient to hold the
> > contents of at least two transfer_buffers.  The first two urbs would fill
> > it before activating the DAC.  Every time the DAC finishes outputting the
> > contents of one urb, it provides feedback with the amount of space
> > remaining in the FIFO.
> Not quite. It does report the momentary frequency in periodic packets
> (like every 16ms), not after each packet.
> 
> >  We
> > would send that many samples in the next urb.  I am fantasizing this
> > solution. Tell me how it really works.
> 
> It's described in 5.12.4.1 (Synchronization Type). The driver aims to be
> as close the the actual data rate that is reported by the device every
> couple of milliseconds.
> 
> Does that answer your questions?

I still haven't found the cause of the problem, so no doubt there will be 
more.  I appreciate the help.

> Daniel
-- 
Jeffrey Barish

------------------------------------------------------------------------------
LogMeIn Central: Instant, anywhere, Remote PC access and management.
Stay in control, update software, and manage PCs from one command center
Diagnose problems and improve visibility into emerging IT issues
Automate, monitor and manage. Do more in less time with Central
http://p.sf.net/sfu/logmein12331_d2d

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

* Re: [Alsa-user] Ticks when playing to USB DAC at high sample rates
  2012-11-05 22:29             ` Jeffrey Barish
@ 2012-11-06  0:12               ` Daniel Mack
  2012-11-06 23:54                 ` Jeffrey Barish
  0 siblings, 1 reply; 14+ messages in thread
From: Daniel Mack @ 2012-11-06  0:12 UTC (permalink / raw)
  To: Jeffrey Barish; +Cc: alsa-user, alsa-devel

On 05.11.2012 23:29, Jeffrey Barish wrote:
> On Mon 05 November 2012 16:03:00 Daniel Mack wrote:
>> Hi Jeff,
>>
>> On 05.11.2012 02:53, Jeffrey Barish wrote:
>>> On Sun 04 November 2012 11:39:48 Daniel Mack wrote:
>>>> [cc alsa-devel]
>>>>
>>>> On 04.11.2012 02:25, Jeffrey Barish wrote:
>>>>> On Fri 26 October 2012 15:21:06 Jeffrey Barish wrote:
>>>>>> On Fri 26 October 2012 21:47:05 Daniel Mack wrote:
>>>>>>> On 26.10.2012 21:43, Jeffrey Barish wrote:
>>>>>>>> On Thu 25 October 2012 19:10:45 Daniel Mack wrote:
>>>>>>>>> On 25.10.2012 17:18, Jeffrey Barish wrote:
>>>>>>>>>> I found something in the snd_usb_audio code (in endpoint.c) that
>>>>>>>>>> could
>>>>>>>>>> explain one of the problems I have observed (the ticks). I would
>>>>>>>>>> normally test my theory by modifying the code. In this case, I
>>>>>>>>>> would
>>>>>>>>>> like to stick in a print statement to see what values are being
>>>>>>>>>> assigned
>>>>>>>>>> to certain variables. Unfortunately, I am too ignorant to do
>>>>>>>>>> something
>>>>>>>>>> even this trivial as I have never worked on kernel code. I think I
>>>>>>>>>> am
>>>>>>>>>> supposed to use printk,
>>>>>>>>>
>>>>>>>>> printk is nice for simple debugging, yes. But note that this call is
>>>>>>>>> timing critical and should not be used in "fast path" code.
>>>>>>>>> Introducing
>>>>>>>>> a printk for each received packet for example will almost certainly
>>>>>>>>> make
>>>>>>>>> the driver behave quite differently.
>>>>>>>>>
>>>>>>>>>> but beyond that I am lost. Can someone provide
>>>>>>>>>> me with some directions? I need to know how to make the driver. To
>>>>>>>>>> that
>>>>>>>>>> end, I probably will have to install additional packages. After
>>>>>>>>>> making
>>>>>>>>>> the driver, I need to know how to install it over the existing
>>>>>>>>>> driver.
>>>>>>>>>
>>>>>>>>> Here's one way to do it:
>>>>>>>>>
>>>>>>>>> 1. git clone
>>>>>>>>> git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git (your
>>>>>>>>> patch should apply on top of this tree eventually)
>>>>>>>>> 2. cd sound
>>>>>>>>> 3. zcat /proc/config.gz >.config
>>>>>>>>> 4. build and install the kernel image. How that is done depends on
>>>>>>>>> the
>>>>>>>>> distribution you're using. For Ubuntu follow the docs at [1] (start
>>>>>>>>> at
>>>>>>>>> point #5). For Fedora and others, something like "make && make
>>>>>>>>> install"
>>>>>>>>> should do
>>>>>>>>> 5. reboot and check that the new kernel is running
>>>>>>>>> 6. hack on sound/usb
>>>>>>>>> 7. make M=sound/usb
>>>>>>>>> 8. reload the module with "sudo rmmod snd_usb_audio; sudo insmod
>>>>>>>>> sound/usb/snd-usb-audio.ko" (better plug out the device before so
>>>>>>>>> you
>>>>>>>>> always have the same defined point of start)
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Hope that works for you.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Daniel
>>>>>>>>>
>>>>>>>>> [1] https://wiki.ubuntu.com/KernelTeam/GitKernelBuild
>>>>>>>>
>>>>>>>> Your directions were almost perfect, so even I was able to build the
>>>>>>>> kernel. I made a discovery using the new kernel that might help
>>>>>>>> someone
>>>>>>>> more familiar with the code than I am to localize the problem.  I am
>>>>>>>> still hearing the blip when I play audio sampled at 88.2 kHz, but I
>>>>>>>> just
>>>>>>>> noticed that the blip is perfectly periodic, with a period of about
>>>>>>>> 16.4
>>>>>>>> seconds.  I am playing a sine wave synthesized using GStreamer using
>>>>>>>> the
>>>>>>>> following command:
>>>>>>>>
>>>>>>>> gst-launch audiotestsrc volume=0.01 ! audio/x-raw-float, width=64,
>>>>>>>> rate=88200, channels=2, endianness=1234 ! audioconvert ! alsasink
>>>>>>>>
>>>>>>>> A sine wave makes it easier to hear the blip.  Does this clue suggest
>>>>>>>> anything?
>>>>>>>>
>>>>>>>> I also want to mention that when I use the new kernel, I do not get
>>>>>>>> the
>>>>>>>> ticks at either 88.2 or 96 kHz even when I do not use the external
>>>>>>>> USB
>>>>>>>> hub.  I plan next to back up to the 3.6.2 kernel to see whether I
>>>>>>>> still
>>>>>>>> get ticks there.
>>>>>>>
>>>>>>> Which kernel did you use when you heard the 'blibs'?
>>>>>>
>>>>>> The latest news is bad.  I am on 3.2.0 now.  The USB DAC is working
>>>>>> perfectly at this moment at both 96 kHz and 88.2 kHz without the
>>>>>> external
>>>>>> USB hub (imagine calling that bad news).  If I set the srate to 88.2
>>>>>> kHz
>>>>>> and stop and start the sine wave, sometimes I get the blip.  Forget
>>>>>> about
>>>>>> its being periodic.  It was definitely periodic before lunch; now I
>>>>>> usually
>>>>>> get random intervals if I get any blips at all.  As I am typing this
>>>>>> message, I can't get blips at all.  There was some correlation between
>>>>>> changing sample rates and blips, but I can't reproduce that behavior
>>>>>> now.
>>>>>> What is most weird is that I haven't gotten any ticks since lunch with
>>>>>> any
>>>>>> kernel or with either sample rate, yet they were reliable earlier today
>>>>>> unless I used the external USB hub. I obviously need to experiment some
>>>>>> more to see whether I can observe a pattern.
>>>>>
>>>>> To conclude (?) this thread, I am now convinced that the anomalies I
>>>>> observed were unrelated to the device driver.  I had two theories
>>>>> remaining.  One was that the problem was somehow related to an
>>>>> overheating problem.  I used a heat gun to convince myself that the
>>>>> theory was wrong.  The other was that the problem had something to do
>>>>> with services running in the background that interfered with the device
>>>>> driver.  I removed or disabled all services that I could identify as
>>>>> superfluous.  Removed services include zeitgeist, apparmor,
>>>>> modemmanager,
>>>>> mdadm, and bluetooth.  Disabled services include atd, dns-clean, and
>>>>> pppd-dns.  The system has been running perfectly with an 88.2 kHz sample
>>>>> rate and no external USB hub for 2 days.  However, I tried booting the
>>>>> system with a copy of the OS from before I removed superfluous services.
>>>>> It still ran perfectly.  Thus, I cannot convince myself that removing
>>>>> superfluous services actually solved the problem.  I suppose it's
>>>>> possible that some service was running sporadically, which could explain
>>>>> why the problem seemed to come and go and also why the problem did not
>>>>> occur when I booted the copy of the OS. As long as the problem remains
>>>>> dormant I have no alternative but to move on and see whether the problem
>>>>> eventually recurs.  Only time will tell.
>>>>>
>>>>> Thanks for all the help.  Hey, I built a kernel and got my own version
>>>>> of
>>>>> the device driver to run.  That was exciting.
>>>>>
>>>>> ------------------------------------------------------------------------
>>>>> --
>>>>> ----
>>>>>
>>>>> I'm back.  The USB DAC continued to work for two more days after my last
>>>>> message and then the blips resumed.  I've been digging into the driver
>>>>> code
>>>>> for two days.  I spent today trying to convince myself that the driver
>>>>> is
>>>>> actually using an asynchronous protocol.  The blips are almost certainly
>>>>> buffer underruns, which I could account for if the driver were not
>>>>> responding to asynchronous feedback from the DAC.  I expected to see a
>>>>> deviation from the pattern of one frame with 89 samples followed by 4
>>>>> frames with 88 (which results in 88,200 samples per second).  That
>>>>> sequence would work perfectly if the clocks in the computer and in the
>>>>> USB DAC were exactly the same frequency, but of course they are not.
>>>>> Consequently, I would expect to see requests for one sample more or less
>>>>> once in a while, depending on whether the clock in the computer is
>>>>> slower
>>>>> or faster than the one in the DAC.  What I see is 89 + 4 * 88 almost all
>>>>> the time, as expected .  Once in a while there is a request for an
>>>>> additional frame of 88 and then the pattern of 89 + 4 * 88 resumes.  I
>>>>> presume that the break in the usual pattern indicates that the device
>>>>> driver is responding to a request from the DAC for fewer samples, which
>>>>> confirms that the driver is using the asynchronous protocol.  That's
>>>>> good, if I am right. However, sticking in an extra packet of only 88
>>>>> would be the expected deviation if the host were getting a little ahead
>>>>> of the DAC, yet the blip is almost certainly a buffer underrun, which
>>>>> means that the host is actually falling behind.  Thus, an extra packet
>>>>> of
>>>>> 89 would make more sense.  I should also mention that there is no
>>>>> correlation between the timing of the extra packet of 88 and the audible
>>>>> blip.  Something seems wrong here, but I'm not sure where to go next.
>>>>>
>>>>> On a related topic, to confirm that the blip is a buffer underrun, I
>>>>> would
>>>>> like to synthesize a waveform that is DC.  With DC, an overrun would not
>>>>> produce any audible anomalies whereas an underrun would be audible.  I
>>>>> am
>>>>> using GStreamer to synthesize the test waveform.  Does anyone know of a
>>>>> way to synthesize a DC waveform using GStreamer?  If not, is there any
>>>>> other tool available in Linux?
>>>>>
>>>>> By the way, I bought another USB DAC from a different manufacturer to be
>>>>> sure that the anomalies I am observing were not due to a defect in the
>>>>> DAC.  They both display the same problem.
>>>>>
>>>>> -----------------------------------------------------
>>>>>
>>>>> I modified the device driver to output a constant instead of the
>>>>> incoming
>>>>> waveform.  I get blips, as I expected, so I am now certain that the
>>>>> blips
>>>>> are caused by a buffer underrun.  The blips occur periodically again --
>>>>> period of about 16.5 seconds.  I presume that the period is related to
>>>>> the difference in clock rates between the host and DAC.  Roughly every
>>>>> 3-4 blips, I get an extra packet of 88 samples.  To prevent buffer
>>>>> underrun, I ought to be getting an extra packet of 89 samples every 16.5
>>>>> seconds, but I never do.
>>>>
>>>> Thanks for all your investigation on this! Sending computed data instead
>>>> of the payload delivered by the ALSA stack is in fact a very good way to
>>>> isolate the issue.
>>>>
>>>> The question is: if the algorithm in the USB driver miscalculates the
>>>> number of samples to send over time, what't the reason for that? Does
>>>> the device report bogus values or is there this a bug in the driver?
>>>
>>> Well, I have two DACs, each from a different manufacturer.  Both
>>> experience
>>> underruns (though not at the same rate).  It's possible that they are both
>>> reporting bogus values, but unlikely, so I'm leaning toward the bug
>>> theory.
>>>
>>>> Did you read chapter 5.4.12.1 of the USB2.0 spec, and can you explain
>>>> where you suspect the bug to be? The current implementation in the
>>>> driver is quite straight forward, mapping all feedback values to Q16.16
>>>> and keeping the lower 16bits around for phase compensation between the
>>>> calculation of the packet sizes.
>>>
>>> Do you perhaps mean chapter 5.12.4.1 (Synchronization Type)?  I'm not
>>> finding a 5.4.12.1 in usb_20.pdf from a zip dated 102512.
>>
>> Yes, sorry.
>>
>>> Please tell me whether I have this right:
>>>
>>> You start transferring the sound in snd_usb_endpoint_start using
>>> usb_submit_urb to submit 2 urbs to the USB core.  The urbs specify that on
>>> completion, the USB core should call snd_complete_urb.  snd_complete_urb
>>> resubmits the urb after calling retire_playback_urb (by way of
>>> retire_outbound_urb which calls retire_data_urb which is
>>> retire_playback_urb), which updates its estimate of delay (what's that? 
>>> It seems to be 0 always)
>> That's just an information that is passed to userspace for latency
>> compensation matters. As you don't stream data that ALSA passes up the
>> stack anymore in your tests (but static data), you can ignore this
>> detail for now.
>>
>>> and prepare_playback_urb (by way of prepare_outbound_urb which calls
>>> prepare_data_urb which is prepare_playback_urb), which fills the
>>> transfer_buffer in the urb with the audio data (from a DMA buffer, I
>>> guess).
>>>
>>> Before filling transfer_buffer, prepare_playback_urb calls
>>> snd_usb_endpoint_next_packet_size to compute the number of samples to
>>> send.
>>> This code appears to be the crux of what I need to understand because the
>>> value returned from this function is what is supposed to adjust to prevent
>>> buffer underruns.
>>
>> That's correct.
>>
>>> It isn't clear to me how this function gets information
>>> about the state of the buffer in the device.
>>
>> Via the callback of the feedback data endpoint - the momentary frequency
>> is updated there and referred to again in
>> snd_usb_endpoint_next_packet_size().
>>
>>> The only argument to
>>> snd_usb_endpoint_next_packet_size is ep, which is a pointer to the
>>> snd_usb_endpoint structure.
>>
>> Yes, the endpoint structure hold all runtime streaming details. Once a
>> sync urb is given back from the host controller, retire_inbound_urb() is
>> called and snd_usb_handle_sync_urb() cares for updating the momentary
>> frequency of the slave of the sync endpoint, which is the data endpoint
>> that is later on used by next_packet_size(). Makes sense?
>>
>>> I see that ep->phase is the Q16.16 value you
>>> mentioned, so the lower 16 bits are for "phase compensation between the
>>> calculation of the packet sizes".  I don't completely understand that
>>> phrase. freqm is an unchanging value (5780275)
>>
>> freqm shouldn't be unchanging. Are you sure it really is? If so, is
>> snd_usb_handle_sync_urb() ever called in your setup?
> 
> Yes.  freqm is always 5780275.  snd_usb_handle_sync_urb is never called.

Ok, we can probably stop debugging here already, because if that
function is never called, something's badly wrong. No question the data
endpoint will run out of bounds at some point if it doesn't get any
usable feedback data.

> snd_usb_handle_sync_urb is called from only one place, retire_inbound_urb, so 
> the latter is never called.  I suppose that an inbound urb would never need to 
> be retired if one were never submitted.

Trace whteher usb_submit_urb() is called on the sync endpoint. There
must be a reason why the completion routing is never callsed, and that's
most probably also the solution of your problem.

[..]

> Since puzzling over the apparent absence of feedback about the state of the 
> device, I had an epiphany this morning that such feedback is not necessary.

It's always necessary, as two osciallators will drift from each other,
no matter what. Without a feedback, there's no way the host can know how
many data to send over the wire.

> The pattern of payload sizes should not change if the payloads are sent in 
> response to a request from the device.  The device makes this request by 
> calling snd_complete_urb when it finishes an urb.  As the device defines time, 
> the host is responsible only for having the next urb ready when the device 
> requests it.  Could it be that the missing feedback provides nonessential 
> information about the state of the device, such as confirmation that the 
> previous payload was successfully processed?
> 
> I repeated the test with a different DAC.  With that DAC it is still the case 
> that snd_usb_handle_sync_urb is never called.

How exactly did you make sure? There's something really wrong if what
you describe happens, and we need to find the cause for it.

Unless you're dealing with a device that uses one data endpoint as clock
source for another data endpoint (which is called an "implicit feedback"
mechanism), you need to have a dedicated sync endpoint.


Daniel

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

* Re: Ticks when playing to USB DAC at high sample rates
  2012-11-06  0:12               ` [Alsa-user] " Daniel Mack
@ 2012-11-06 23:54                 ` Jeffrey Barish
  2012-11-07  9:01                   ` [Alsa-user] " Daniel Mack
  0 siblings, 1 reply; 14+ messages in thread
From: Jeffrey Barish @ 2012-11-06 23:54 UTC (permalink / raw)
  To: Daniel Mack; +Cc: alsa-user, alsa-devel

On Tue 06 November 2012 01:12:42 Daniel Mack wrote:
> On 05.11.2012 23:29, Jeffrey Barish wrote:
> > On Mon 05 November 2012 16:03:00 Daniel Mack wrote:
> >> Hi Jeff,
> >> 
> >> On 05.11.2012 02:53, Jeffrey Barish wrote:
> >>> On Sun 04 November 2012 11:39:48 Daniel Mack wrote:
> >>>> [cc alsa-devel]
> >>>> 
> >>>> On 04.11.2012 02:25, Jeffrey Barish wrote:
> >>>>> On Fri 26 October 2012 15:21:06 Jeffrey Barish wrote:
> >>>>>> On Fri 26 October 2012 21:47:05 Daniel Mack wrote:
> >>>>>>> On 26.10.2012 21:43, Jeffrey Barish wrote:
> >>>>>>>> On Thu 25 October 2012 19:10:45 Daniel Mack wrote:
> >>>>>>>>> On 25.10.2012 17:18, Jeffrey Barish wrote:
> >>>>>>>>>> I found something in the snd_usb_audio code (in endpoint.c) that
> >>>>>>>>>> could
> >>>>>>>>>> explain one of the problems I have observed (the ticks). I would
> >>>>>>>>>> normally test my theory by modifying the code. In this case, I
> >>>>>>>>>> would
> >>>>>>>>>> like to stick in a print statement to see what values are being
> >>>>>>>>>> assigned
> >>>>>>>>>> to certain variables. Unfortunately, I am too ignorant to do
> >>>>>>>>>> something
> >>>>>>>>>> even this trivial as I have never worked on kernel code. I think
> >>>>>>>>>> I
> >>>>>>>>>> am
> >>>>>>>>>> supposed to use printk,
> >>>>>>>>> 
> >>>>>>>>> printk is nice for simple debugging, yes. But note that this call
> >>>>>>>>> is
> >>>>>>>>> timing critical and should not be used in "fast path" code.
> >>>>>>>>> Introducing
> >>>>>>>>> a printk for each received packet for example will almost
> >>>>>>>>> certainly
> >>>>>>>>> make
> >>>>>>>>> the driver behave quite differently.
> >>>>>>>>> 
> >>>>>>>>>> but beyond that I am lost. Can someone provide
> >>>>>>>>>> me with some directions? I need to know how to make the driver.
> >>>>>>>>>> To
> >>>>>>>>>> that
> >>>>>>>>>> end, I probably will have to install additional packages. After
> >>>>>>>>>> making
> >>>>>>>>>> the driver, I need to know how to install it over the existing
> >>>>>>>>>> driver.
> >>>>>>>>> 
> >>>>>>>>> Here's one way to do it:
> >>>>>>>>> 
> >>>>>>>>> 1. git clone
> >>>>>>>>> git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
> >>>>>>>>> (your
> >>>>>>>>> patch should apply on top of this tree eventually)
> >>>>>>>>> 2. cd sound
> >>>>>>>>> 3. zcat /proc/config.gz >.config
> >>>>>>>>> 4. build and install the kernel image. How that is done depends on
> >>>>>>>>> the
> >>>>>>>>> distribution you're using. For Ubuntu follow the docs at [1]
> >>>>>>>>> (start
> >>>>>>>>> at
> >>>>>>>>> point #5). For Fedora and others, something like "make && make
> >>>>>>>>> install"
> >>>>>>>>> should do
> >>>>>>>>> 5. reboot and check that the new kernel is running
> >>>>>>>>> 6. hack on sound/usb
> >>>>>>>>> 7. make M=sound/usb
> >>>>>>>>> 8. reload the module with "sudo rmmod snd_usb_audio; sudo insmod
> >>>>>>>>> sound/usb/snd-usb-audio.ko" (better plug out the device before so
> >>>>>>>>> you
> >>>>>>>>> always have the same defined point of start)
> >>>>>>>>> 
> >>>>>>>>> 
> >>>>>>>>> Hope that works for you.
> >>>>>>>>> 
> >>>>>>>>> 
> >>>>>>>>> Daniel
> >>>>>>>>> 
> >>>>>>>>> [1] https://wiki.ubuntu.com/KernelTeam/GitKernelBuild
> >>>>>>>> 
> >>>>>>>> Your directions were almost perfect, so even I was able to build
> >>>>>>>> the
> >>>>>>>> kernel. I made a discovery using the new kernel that might help
> >>>>>>>> someone
> >>>>>>>> more familiar with the code than I am to localize the problem.  I
> >>>>>>>> am
> >>>>>>>> still hearing the blip when I play audio sampled at 88.2 kHz, but I
> >>>>>>>> just
> >>>>>>>> noticed that the blip is perfectly periodic, with a period of about
> >>>>>>>> 16.4
> >>>>>>>> seconds.  I am playing a sine wave synthesized using GStreamer
> >>>>>>>> using
> >>>>>>>> the
> >>>>>>>> following command:
> >>>>>>>> 
> >>>>>>>> gst-launch audiotestsrc volume=0.01 ! audio/x-raw-float, width=64,
> >>>>>>>> rate=88200, channels=2, endianness=1234 ! audioconvert ! alsasink
> >>>>>>>> 
> >>>>>>>> A sine wave makes it easier to hear the blip.  Does this clue
> >>>>>>>> suggest
> >>>>>>>> anything?
> >>>>>>>> 
> >>>>>>>> I also want to mention that when I use the new kernel, I do not get
> >>>>>>>> the
> >>>>>>>> ticks at either 88.2 or 96 kHz even when I do not use the external
> >>>>>>>> USB
> >>>>>>>> hub.  I plan next to back up to the 3.6.2 kernel to see whether I
> >>>>>>>> still
> >>>>>>>> get ticks there.
> >>>>>>> 
> >>>>>>> Which kernel did you use when you heard the 'blibs'?
> >>>>>> 
> >>>>>> The latest news is bad.  I am on 3.2.0 now.  The USB DAC is working
> >>>>>> perfectly at this moment at both 96 kHz and 88.2 kHz without the
> >>>>>> external
> >>>>>> USB hub (imagine calling that bad news).  If I set the srate to 88.2
> >>>>>> kHz
> >>>>>> and stop and start the sine wave, sometimes I get the blip.  Forget
> >>>>>> about
> >>>>>> its being periodic.  It was definitely periodic before lunch; now I
> >>>>>> usually
> >>>>>> get random intervals if I get any blips at all.  As I am typing this
> >>>>>> message, I can't get blips at all.  There was some correlation
> >>>>>> between
> >>>>>> changing sample rates and blips, but I can't reproduce that behavior
> >>>>>> now.
> >>>>>> What is most weird is that I haven't gotten any ticks since lunch
> >>>>>> with
> >>>>>> any
> >>>>>> kernel or with either sample rate, yet they were reliable earlier
> >>>>>> today
> >>>>>> unless I used the external USB hub. I obviously need to experiment
> >>>>>> some
> >>>>>> more to see whether I can observe a pattern.
> >>>>> 
> >>>>> To conclude (?) this thread, I am now convinced that the anomalies I
> >>>>> observed were unrelated to the device driver.  I had two theories
> >>>>> remaining.  One was that the problem was somehow related to an
> >>>>> overheating problem.  I used a heat gun to convince myself that the
> >>>>> theory was wrong.  The other was that the problem had something to do
> >>>>> with services running in the background that interfered with the
> >>>>> device
> >>>>> driver.  I removed or disabled all services that I could identify as
> >>>>> superfluous.  Removed services include zeitgeist, apparmor,
> >>>>> modemmanager,
> >>>>> mdadm, and bluetooth.  Disabled services include atd, dns-clean, and
> >>>>> pppd-dns.  The system has been running perfectly with an 88.2 kHz
> >>>>> sample
> >>>>> rate and no external USB hub for 2 days.  However, I tried booting the
> >>>>> system with a copy of the OS from before I removed superfluous
> >>>>> services.
> >>>>> It still ran perfectly.  Thus, I cannot convince myself that removing
> >>>>> superfluous services actually solved the problem.  I suppose it's
> >>>>> possible that some service was running sporadically, which could
> >>>>> explain
> >>>>> why the problem seemed to come and go and also why the problem did not
> >>>>> occur when I booted the copy of the OS. As long as the problem remains
> >>>>> dormant I have no alternative but to move on and see whether the
> >>>>> problem
> >>>>> eventually recurs.  Only time will tell.
> >>>>> 
> >>>>> Thanks for all the help.  Hey, I built a kernel and got my own version
> >>>>> of
> >>>>> the device driver to run.  That was exciting.
> >>>>> 
> >>>>> ----------------------------------------------------------------------
> >>>>> --
> >>>>> --
> >>>>> ----
> >>>>> 
> >>>>> I'm back.  The USB DAC continued to work for two more days after my
> >>>>> last
> >>>>> message and then the blips resumed.  I've been digging into the driver
> >>>>> code
> >>>>> for two days.  I spent today trying to convince myself that the driver
> >>>>> is
> >>>>> actually using an asynchronous protocol.  The blips are almost
> >>>>> certainly
> >>>>> buffer underruns, which I could account for if the driver were not
> >>>>> responding to asynchronous feedback from the DAC.  I expected to see a
> >>>>> deviation from the pattern of one frame with 89 samples followed by 4
> >>>>> frames with 88 (which results in 88,200 samples per second).  That
> >>>>> sequence would work perfectly if the clocks in the computer and in the
> >>>>> USB DAC were exactly the same frequency, but of course they are not.
> >>>>> Consequently, I would expect to see requests for one sample more or
> >>>>> less
> >>>>> once in a while, depending on whether the clock in the computer is
> >>>>> slower
> >>>>> or faster than the one in the DAC.  What I see is 89 + 4 * 88 almost
> >>>>> all
> >>>>> the time, as expected .  Once in a while there is a request for an
> >>>>> additional frame of 88 and then the pattern of 89 + 4 * 88 resumes.  I
> >>>>> presume that the break in the usual pattern indicates that the device
> >>>>> driver is responding to a request from the DAC for fewer samples,
> >>>>> which
> >>>>> confirms that the driver is using the asynchronous protocol.  That's
> >>>>> good, if I am right. However, sticking in an extra packet of only 88
> >>>>> would be the expected deviation if the host were getting a little
> >>>>> ahead
> >>>>> of the DAC, yet the blip is almost certainly a buffer underrun, which
> >>>>> means that the host is actually falling behind.  Thus, an extra packet
> >>>>> of
> >>>>> 89 would make more sense.  I should also mention that there is no
> >>>>> correlation between the timing of the extra packet of 88 and the
> >>>>> audible
> >>>>> blip.  Something seems wrong here, but I'm not sure where to go next.
> >>>>> 
> >>>>> On a related topic, to confirm that the blip is a buffer underrun, I
> >>>>> would
> >>>>> like to synthesize a waveform that is DC.  With DC, an overrun would
> >>>>> not
> >>>>> produce any audible anomalies whereas an underrun would be audible.  I
> >>>>> am
> >>>>> using GStreamer to synthesize the test waveform.  Does anyone know of
> >>>>> a
> >>>>> way to synthesize a DC waveform using GStreamer?  If not, is there any
> >>>>> other tool available in Linux?
> >>>>> 
> >>>>> By the way, I bought another USB DAC from a different manufacturer to
> >>>>> be
> >>>>> sure that the anomalies I am observing were not due to a defect in the
> >>>>> DAC.  They both display the same problem.
> >>>>> 
> >>>>> -----------------------------------------------------
> >>>>> 
> >>>>> I modified the device driver to output a constant instead of the
> >>>>> incoming
> >>>>> waveform.  I get blips, as I expected, so I am now certain that the
> >>>>> blips
> >>>>> are caused by a buffer underrun.  The blips occur periodically again
> >>>>> --
> >>>>> period of about 16.5 seconds.  I presume that the period is related to
> >>>>> the difference in clock rates between the host and DAC.  Roughly every
> >>>>> 3-4 blips, I get an extra packet of 88 samples.  To prevent buffer
> >>>>> underrun, I ought to be getting an extra packet of 89 samples every
> >>>>> 16.5
> >>>>> seconds, but I never do.
> >>>> 
> >>>> Thanks for all your investigation on this! Sending computed data
> >>>> instead
> >>>> of the payload delivered by the ALSA stack is in fact a very good way
> >>>> to
> >>>> isolate the issue.
> >>>> 
> >>>> The question is: if the algorithm in the USB driver miscalculates the
> >>>> number of samples to send over time, what't the reason for that? Does
> >>>> the device report bogus values or is there this a bug in the driver?
> >>> 
> >>> Well, I have two DACs, each from a different manufacturer.  Both
> >>> experience
> >>> underruns (though not at the same rate).  It's possible that they are
> >>> both
> >>> reporting bogus values, but unlikely, so I'm leaning toward the bug
> >>> theory.
> >>> 
> >>>> Did you read chapter 5.4.12.1 of the USB2.0 spec, and can you explain
> >>>> where you suspect the bug to be? The current implementation in the
> >>>> driver is quite straight forward, mapping all feedback values to Q16.16
> >>>> and keeping the lower 16bits around for phase compensation between the
> >>>> calculation of the packet sizes.
> >>> 
> >>> Do you perhaps mean chapter 5.12.4.1 (Synchronization Type)?  I'm not
> >>> finding a 5.4.12.1 in usb_20.pdf from a zip dated 102512.
> >> 
> >> Yes, sorry.
> >> 
> >>> Please tell me whether I have this right:
> >>> 
> >>> You start transferring the sound in snd_usb_endpoint_start using
> >>> usb_submit_urb to submit 2 urbs to the USB core.  The urbs specify that
> >>> on
> >>> completion, the USB core should call snd_complete_urb.  snd_complete_urb
> >>> resubmits the urb after calling retire_playback_urb (by way of
> >>> retire_outbound_urb which calls retire_data_urb which is
> >>> retire_playback_urb), which updates its estimate of delay (what's that?
> >>> It seems to be 0 always)
> >> 
> >> That's just an information that is passed to userspace for latency
> >> compensation matters. As you don't stream data that ALSA passes up the
> >> stack anymore in your tests (but static data), you can ignore this
> >> detail for now.
> >> 
> >>> and prepare_playback_urb (by way of prepare_outbound_urb which calls
> >>> prepare_data_urb which is prepare_playback_urb), which fills the
> >>> transfer_buffer in the urb with the audio data (from a DMA buffer, I
> >>> guess).
> >>> 
> >>> Before filling transfer_buffer, prepare_playback_urb calls
> >>> snd_usb_endpoint_next_packet_size to compute the number of samples to
> >>> send.
> >>> This code appears to be the crux of what I need to understand because
> >>> the
> >>> value returned from this function is what is supposed to adjust to
> >>> prevent
> >>> buffer underruns.
> >> 
> >> That's correct.
> >> 
> >>> It isn't clear to me how this function gets information
> >>> about the state of the buffer in the device.
> >> 
> >> Via the callback of the feedback data endpoint - the momentary frequency
> >> is updated there and referred to again in
> >> snd_usb_endpoint_next_packet_size().
> >> 
> >>> The only argument to
> >>> snd_usb_endpoint_next_packet_size is ep, which is a pointer to the
> >>> snd_usb_endpoint structure.
> >> 
> >> Yes, the endpoint structure hold all runtime streaming details. Once a
> >> sync urb is given back from the host controller, retire_inbound_urb() is
> >> called and snd_usb_handle_sync_urb() cares for updating the momentary
> >> frequency of the slave of the sync endpoint, which is the data endpoint
> >> that is later on used by next_packet_size(). Makes sense?
> >> 
> >>> I see that ep->phase is the Q16.16 value you
> >>> mentioned, so the lower 16 bits are for "phase compensation between the
> >>> calculation of the packet sizes".  I don't completely understand that
> >>> phrase. freqm is an unchanging value (5780275)
> >> 
> >> freqm shouldn't be unchanging. Are you sure it really is? If so, is
> >> snd_usb_handle_sync_urb() ever called in your setup?
> > 
> > Yes.  freqm is always 5780275.  snd_usb_handle_sync_urb is never called.
> 
> Ok, we can probably stop debugging here already, because if that
> function is never called, something's badly wrong. No question the data
> endpoint will run out of bounds at some point if it doesn't get any
> usable feedback data.
> 
> > snd_usb_handle_sync_urb is called from only one place, retire_inbound_urb,
> > so the latter is never called.  I suppose that an inbound urb would never
> > need to be retired if one were never submitted.
> 
> Trace whteher usb_submit_urb() is called on the sync endpoint. There
> must be a reason why the completion routing is never callsed, and that's
> most probably also the solution of your problem.
> 
> [..]
> 
> > Since puzzling over the apparent absence of feedback about the state of
> > the
> > device, I had an epiphany this morning that such feedback is not
> > necessary.
> 
> It's always necessary, as two osciallators will drift from each other,
> no matter what. Without a feedback, there's no way the host can know how
> many data to send over the wire.
> 
> > The pattern of payload sizes should not change if the payloads are sent in
> > response to a request from the device.  The device makes this request by
> > calling snd_complete_urb when it finishes an urb.  As the device defines
> > time, the host is responsible only for having the next urb ready when the
> > device requests it.  Could it be that the missing feedback provides
> > nonessential information about the state of the device, such as
> > confirmation that the previous payload was successfully processed?
> > 
> > I repeated the test with a different DAC.  With that DAC it is still the
> > case that snd_usb_handle_sync_urb is never called.
> 
> How exactly did you make sure? There's something really wrong if what
> you describe happens, and we need to find the cause for it.
> 
> Unless you're dealing with a device that uses one data endpoint as clock
> source for another data endpoint (which is called an "implicit feedback"
> mechanism), you need to have a dedicated sync endpoint.
> 
> 
> Daniel

I guess that snd_usb_pcm_prepare is called by the core usb system to prepare 
the snd driver.  Anyway, snd_usb_pcm_prepare calls configure_endpoint with a 
substream.  Then configure_endpoint calls snd_usb_endpoint_set_params with the 
data endpoint that corresponds to the substream.  snd_usb_endpoint_set_params 
calls data_ep_set_params with the data ep and data_ep_set_params sets nurbs to 
2 for the data endpoint.

snd_usb_endpoint_set_params has code to call sync_ep_set_params when the 
endpoint is type sync.  sync_ep_set_params sets nurbs to 4 (why?).  However, 
snd_usb_endpoint_set_params never invokes the call to sync_ep_set_params 
because ep->type is always data.  Back up: snd_usb_endpoint_set_params is 
called from configure_endpoint.  It is called from an if block contingent on 
the substream's having a sync endpoint.  It does.  However, the call to 
snd_usb_endpoint_set_params passes subs->data_endpoint as the first argument, 
so snd_usb_endpoint_set_params simply repeats the operations it performed as a 
result of the previous invocation.  I presume that the first argument to the 
second call to snd_usb_endpoint_set_params should be subs->sync_endpoint.  I 
made that change.  Now freqm does change.  However, I am getting tons of 
ticks.  Now it sounds as if the payload size is always wrong.

Oh, 44.1 kHz works.  48 kHz works.  88.2 and 96 don't work.

Oh, we're back to the behavior I described many emails ago: If I keep 
restarting the playback at 88.2 or 96, eventually it will start and not 
produce machine-gun fire.  Previously, I would still hear sporadic "blips", as 
I called them.  I am not hearing blips anymore.  If playback starts clean, it 
stays clean -- and without blips.  If I use the external hub trick, I don't 
get machine-gun fire ever, but I do get sporadic blips again at both 88.2 and 
96 kHz.  I guess that I now have to figure out what is causing the machine-gun 
fire on about 90% of the starts at 88.2 or 96 kHz.  Any suggestions 
appreciated.  I have no idea where to start.  Seems like a timing issue.

Here is the only clue I can offer: I noticed that when I ^C the gst-launch 
command I use to play a sine wave (which actually plays DC because I replaced 
the memcpy commands in pcm.c with memset), I get the error message in kern.log 
"cannot submit urb 0, error -28: not enough bandwidth" only when I get 
machine-gun fire.  When playback works properly, terminating the gst-launch 
command with ^C produces no message in kern.log.  Mean anything to you?
-- 
Jeffrey Barish

------------------------------------------------------------------------------
LogMeIn Central: Instant, anywhere, Remote PC access and management.
Stay in control, update software, and manage PCs from one command center
Diagnose problems and improve visibility into emerging IT issues
Automate, monitor and manage. Do more in less time with Central
http://p.sf.net/sfu/logmein12331_d2d

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

* Re: [Alsa-user] Ticks when playing to USB DAC at high sample rates
  2012-11-06 23:54                 ` Jeffrey Barish
@ 2012-11-07  9:01                   ` Daniel Mack
  2012-11-07  9:04                     ` Daniel Mack
  2012-11-08 18:54                     ` Jeffrey Barish
  0 siblings, 2 replies; 14+ messages in thread
From: Daniel Mack @ 2012-11-07  9:01 UTC (permalink / raw)
  To: Jeffrey Barish; +Cc: alsa-user, alsa-devel

On 07.11.2012 00:54, Jeffrey Barish wrote:
> I guess that snd_usb_pcm_prepare is called by the core usb system to prepare 
> the snd driver.  Anyway, snd_usb_pcm_prepare calls configure_endpoint with a 
> substream.  Then configure_endpoint calls snd_usb_endpoint_set_params with the 
> data endpoint that corresponds to the substream.  snd_usb_endpoint_set_params 
> calls data_ep_set_params with the data ep and data_ep_set_params sets nurbs to 
> 2 for the data endpoint.
> 
> snd_usb_endpoint_set_params has code to call sync_ep_set_params when the 
> endpoint is type sync.  sync_ep_set_params sets nurbs to 4 (why?).  However, 
> snd_usb_endpoint_set_params never invokes the call to sync_ep_set_params 
> because ep->type is always data.  Back up: snd_usb_endpoint_set_params is 
> called from configure_endpoint.  It is called from an if block contingent on 
> the substream's having a sync endpoint.  It does.  However, the call to 
> snd_usb_endpoint_set_params passes subs->data_endpoint as the first argument, 
> so snd_usb_endpoint_set_params simply repeats the operations it performed as a 
> result of the previous invocation.  I presume that the first argument to the 
> second call to snd_usb_endpoint_set_params should be subs->sync_endpoint.

Eh. You clearly spotted a bug here. The rally interesting thing is that
that it didn't bite us earlier, as it's in since 3.6.

>  I 
> made that change.  Now freqm does change.  However, I am getting tons of 
> ticks.  Now it sounds as if the payload size is always wrong.
> 
> Oh, 44.1 kHz works.  48 kHz works.  88.2 and 96 don't work.

That's a different issue. Would you like to prepare a patch for the
issue above please?


Thanks,
Daniel

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

* Re: [Alsa-user] Ticks when playing to USB DAC at high sample rates
  2012-11-07  9:01                   ` [Alsa-user] " Daniel Mack
@ 2012-11-07  9:04                     ` Daniel Mack
  2012-11-07 17:05                       ` Jeffrey Barish
  2012-11-08 18:54                     ` Jeffrey Barish
  1 sibling, 1 reply; 14+ messages in thread
From: Daniel Mack @ 2012-11-07  9:04 UTC (permalink / raw)
  To: Jeffrey Barish; +Cc: alsa-user, alsa-devel

On 07.11.2012 10:01, Daniel Mack wrote:
> On 07.11.2012 00:54, Jeffrey Barish wrote:
>> I guess that snd_usb_pcm_prepare is called by the core usb system to prepare 
>> the snd driver.  Anyway, snd_usb_pcm_prepare calls configure_endpoint with a 
>> substream.  Then configure_endpoint calls snd_usb_endpoint_set_params with the 
>> data endpoint that corresponds to the substream.  snd_usb_endpoint_set_params 
>> calls data_ep_set_params with the data ep and data_ep_set_params sets nurbs to 
>> 2 for the data endpoint.
>>
>> snd_usb_endpoint_set_params has code to call sync_ep_set_params when the 
>> endpoint is type sync.  sync_ep_set_params sets nurbs to 4 (why?).  However, 
>> snd_usb_endpoint_set_params never invokes the call to sync_ep_set_params 
>> because ep->type is always data.  Back up: snd_usb_endpoint_set_params is 
>> called from configure_endpoint.  It is called from an if block contingent on 
>> the substream's having a sync endpoint.  It does.  However, the call to 
>> snd_usb_endpoint_set_params passes subs->data_endpoint as the first argument, 
>> so snd_usb_endpoint_set_params simply repeats the operations it performed as a 
>> result of the previous invocation.  I presume that the first argument to the 
>> second call to snd_usb_endpoint_set_params should be subs->sync_endpoint.
> 
> Eh. You clearly spotted a bug here. The rally interesting thing is that
> that it didn't bite us earlier, as it's in since 3.6.
> 
>>  I 
>> made that change.  Now freqm does change.  However, I am getting tons of 
>> ticks.  Now it sounds as if the payload size is always wrong.
>>
>> Oh, 44.1 kHz works.  48 kHz works.  88.2 and 96 don't work.
> 
> That's a different issue. Would you like to prepare a patch for the
> issue above please?

Thinking about it further, that could also explain the memory corruption
we've revently seen in that driver ...

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

* Re: Ticks when playing to USB DAC at high sample rates
  2012-11-07  9:04                     ` Daniel Mack
@ 2012-11-07 17:05                       ` Jeffrey Barish
  2012-11-22 19:40                         ` [Alsa-user] " Daniel Mack
  0 siblings, 1 reply; 14+ messages in thread
From: Jeffrey Barish @ 2012-11-07 17:05 UTC (permalink / raw)
  To: Daniel Mack; +Cc: alsa-user, alsa-devel

On Wed 07 November 2012 10:04:14 Daniel Mack wrote:
> On 07.11.2012 10:01, Daniel Mack wrote:
> > On 07.11.2012 00:54, Jeffrey Barish wrote:
> >> I guess that snd_usb_pcm_prepare is called by the core usb system to
> >> prepare the snd driver.  Anyway, snd_usb_pcm_prepare calls
> >> configure_endpoint with a substream.  Then configure_endpoint calls
> >> snd_usb_endpoint_set_params with the data endpoint that corresponds to
> >> the substream.  snd_usb_endpoint_set_params calls data_ep_set_params
> >> with the data ep and data_ep_set_params sets nurbs to 2 for the data
> >> endpoint.
> >> 
> >> snd_usb_endpoint_set_params has code to call sync_ep_set_params when the
> >> endpoint is type sync.  sync_ep_set_params sets nurbs to 4 (why?). 
> >> However, snd_usb_endpoint_set_params never invokes the call to
> >> sync_ep_set_params because ep->type is always data.  Back up:
> >> snd_usb_endpoint_set_params is called from configure_endpoint.  It is
> >> called from an if block contingent on the substream's having a sync
> >> endpoint.  It does.  However, the call to snd_usb_endpoint_set_params
> >> passes subs->data_endpoint as the first argument, so
> >> snd_usb_endpoint_set_params simply repeats the operations it performed
> >> as a result of the previous invocation.  I presume that the first
> >> argument to the second call to snd_usb_endpoint_set_params should be
> >> subs->sync_endpoint.> 
> > Eh. You clearly spotted a bug here. The rally interesting thing is that
> > that it didn't bite us earlier, as it's in since 3.6.
> > 
> >>  I
> >> 
> >> made that change.  Now freqm does change.  However, I am getting tons of
> >> ticks.  Now it sounds as if the payload size is always wrong.
> >> 
> >> Oh, 44.1 kHz works.  48 kHz works.  88.2 and 96 don't work.
> > 
> > That's a different issue. Would you like to prepare a patch for the
> > issue above please?

I don't know how to prepare a patch, so I'm inclined to fix the remaining 
problem before stopping to figure out the patch problem.

I didn't get your previous email.  I hope that it contained some suggestions 
on what to look for to solve the remaining problem.  Please send it again.  
The problem seems to be related to timing considering that the driver works 
perfectly 5-10% of the time, but timing of what?  I don't know what to look 
for.

> Thinking about it further, that could also explain the memory corruption
> we've revently seen in that driver ...
-- 
Jeffrey Barish

------------------------------------------------------------------------------
LogMeIn Central: Instant, anywhere, Remote PC access and management.
Stay in control, update software, and manage PCs from one command center
Diagnose problems and improve visibility into emerging IT issues
Automate, monitor and manage. Do more in less time with Central
http://p.sf.net/sfu/logmein12331_d2d

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

* Re: Ticks when playing to USB DAC at high sample rates
  2012-11-07  9:01                   ` [Alsa-user] " Daniel Mack
  2012-11-07  9:04                     ` Daniel Mack
@ 2012-11-08 18:54                     ` Jeffrey Barish
  2012-11-22 19:29                       ` [Alsa-user] " Daniel Mack
  1 sibling, 1 reply; 14+ messages in thread
From: Jeffrey Barish @ 2012-11-08 18:54 UTC (permalink / raw)
  To: Daniel Mack; +Cc: alsa-user, alsa-devel

On Wed 07 November 2012 10:01:14 Daniel Mack wrote:
> On 07.11.2012 00:54, Jeffrey Barish wrote:
> > I guess that snd_usb_pcm_prepare is called by the core usb system to
> > prepare the snd driver.  Anyway, snd_usb_pcm_prepare calls
> > configure_endpoint with a substream.  Then configure_endpoint calls
> > snd_usb_endpoint_set_params with the data endpoint that corresponds to
> > the substream.  snd_usb_endpoint_set_params calls data_ep_set_params with
> > the data ep and data_ep_set_params sets nurbs to 2 for the data endpoint.
> > 
> > snd_usb_endpoint_set_params has code to call sync_ep_set_params when the
> > endpoint is type sync.  sync_ep_set_params sets nurbs to 4 (why?). 
> > However, snd_usb_endpoint_set_params never invokes the call to
> > sync_ep_set_params because ep->type is always data.  Back up:
> > snd_usb_endpoint_set_params is called from configure_endpoint.  It is
> > called from an if block contingent on the substream's having a sync
> > endpoint.  It does.  However, the call to snd_usb_endpoint_set_params
> > passes subs->data_endpoint as the first argument, so
> > snd_usb_endpoint_set_params simply repeats the operations it performed as
> > a result of the previous invocation.  I presume that the first argument
> > to the second call to snd_usb_endpoint_set_params should be
> > subs->sync_endpoint.
> Eh. You clearly spotted a bug here. The rally interesting thing is that
> that it didn't bite us earlier, as it's in since 3.6.

Here's the diff.  I can't figure out how to submit a patch.

--- sound/usb/pcm.c.orig        2012-11-08 11:43:57.309732860 -0700
+++ sound/usb/pcm.c     2012-11-08 11:41:06.512420658 -0700
@@ -456,7 +456,7 @@ static int configure_endpoint(struct snd
                return ret;
 
        if (subs->sync_endpoint)
-               ret = snd_usb_endpoint_set_params(subs->data_endpoint,
+               ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
                                                  subs->pcm_format,
                                                  subs->channels,
                                                  subs->period_bytes,

-- 
Jeffrey Barish

------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_nov

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

* Re: [Alsa-user] Ticks when playing to USB DAC at high sample rates
  2012-11-08 18:54                     ` Jeffrey Barish
@ 2012-11-22 19:29                       ` Daniel Mack
  0 siblings, 0 replies; 14+ messages in thread
From: Daniel Mack @ 2012-11-22 19:29 UTC (permalink / raw)
  To: Jeffrey Barish; +Cc: alsa-user, alsa-devel

Hi Jeffrey,

sorry for the late reply.

On 08.11.2012 19:54, Jeffrey Barish wrote:
> On Wed 07 November 2012 10:01:14 Daniel Mack wrote:
>> On 07.11.2012 00:54, Jeffrey Barish wrote:
>>> I guess that snd_usb_pcm_prepare is called by the core usb system to
>>> prepare the snd driver.  Anyway, snd_usb_pcm_prepare calls
>>> configure_endpoint with a substream.  Then configure_endpoint calls
>>> snd_usb_endpoint_set_params with the data endpoint that corresponds to
>>> the substream.  snd_usb_endpoint_set_params calls data_ep_set_params with
>>> the data ep and data_ep_set_params sets nurbs to 2 for the data endpoint.
>>>
>>> snd_usb_endpoint_set_params has code to call sync_ep_set_params when the
>>> endpoint is type sync.  sync_ep_set_params sets nurbs to 4 (why?). 
>>> However, snd_usb_endpoint_set_params never invokes the call to
>>> sync_ep_set_params because ep->type is always data.  Back up:
>>> snd_usb_endpoint_set_params is called from configure_endpoint.  It is
>>> called from an if block contingent on the substream's having a sync
>>> endpoint.  It does.  However, the call to snd_usb_endpoint_set_params
>>> passes subs->data_endpoint as the first argument, so
>>> snd_usb_endpoint_set_params simply repeats the operations it performed as
>>> a result of the previous invocation.  I presume that the first argument
>>> to the second call to snd_usb_endpoint_set_params should be
>>> subs->sync_endpoint.
>> Eh. You clearly spotted a bug here. The rally interesting thing is that
>> that it didn't bite us earlier, as it's in since 3.6.
> 
> Here's the diff.  I can't figure out how to submit a patch.
> 
> --- sound/usb/pcm.c.orig        2012-11-08 11:43:57.309732860 -0700
> +++ sound/usb/pcm.c     2012-11-08 11:41:06.512420658 -0700
> @@ -456,7 +456,7 @@ static int configure_endpoint(struct snd
>                 return ret;
>  
>         if (subs->sync_endpoint)
> -               ret = snd_usb_endpoint_set_params(subs->data_endpoint,
> +               ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
>                                                   subs->pcm_format,
>                                                   subs->channels,
>                                                   subs->period_bytes,

Thanks - I just sent out a patch for this.



Daniel

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

* Re: [Alsa-user] Ticks when playing to USB DAC at high sample rates
  2012-11-07 17:05                       ` Jeffrey Barish
@ 2012-11-22 19:40                         ` Daniel Mack
  2012-11-22 21:08                           ` Daniel Mack
  0 siblings, 1 reply; 14+ messages in thread
From: Daniel Mack @ 2012-11-22 19:40 UTC (permalink / raw)
  To: Jeffrey Barish; +Cc: alsa-user, alsa-devel

On 07.11.2012 18:05, Jeffrey Barish wrote:
> On Wed 07 November 2012 10:04:14 Daniel Mack wrote:
>> On 07.11.2012 10:01, Daniel Mack wrote:
>>> On 07.11.2012 00:54, Jeffrey Barish wrote:
>>>> I guess that snd_usb_pcm_prepare is called by the core usb system to
>>>> prepare the snd driver.  Anyway, snd_usb_pcm_prepare calls
>>>> configure_endpoint with a substream.  Then configure_endpoint calls
>>>> snd_usb_endpoint_set_params with the data endpoint that corresponds to
>>>> the substream.  snd_usb_endpoint_set_params calls data_ep_set_params
>>>> with the data ep and data_ep_set_params sets nurbs to 2 for the data
>>>> endpoint.
>>>>
>>>> snd_usb_endpoint_set_params has code to call sync_ep_set_params when the
>>>> endpoint is type sync.  sync_ep_set_params sets nurbs to 4 (why?). 
>>>> However, snd_usb_endpoint_set_params never invokes the call to
>>>> sync_ep_set_params because ep->type is always data.  Back up:
>>>> snd_usb_endpoint_set_params is called from configure_endpoint.  It is
>>>> called from an if block contingent on the substream's having a sync
>>>> endpoint.  It does.  However, the call to snd_usb_endpoint_set_params
>>>> passes subs->data_endpoint as the first argument, so
>>>> snd_usb_endpoint_set_params simply repeats the operations it performed
>>>> as a result of the previous invocation.  I presume that the first
>>>> argument to the second call to snd_usb_endpoint_set_params should be
>>>> subs->sync_endpoint.> 
>>> Eh. You clearly spotted a bug here. The rally interesting thing is that
>>> that it didn't bite us earlier, as it's in since 3.6.
>>>
>>>>  I
>>>>
>>>> made that change.  Now freqm does change.  However, I am getting tons of
>>>> ticks.  Now it sounds as if the payload size is always wrong.
>>>>
>>>> Oh, 44.1 kHz works.  48 kHz works.  88.2 and 96 don't work.
>>>
>>> That's a different issue. Would you like to prepare a patch for the
>>> issue above please?
> 
> I don't know how to prepare a patch, so I'm inclined to fix the remaining 
> problem before stopping to figure out the patch problem.
> 
> I didn't get your previous email.  I hope that it contained some suggestions 
> on what to look for to solve the remaining problem.  Please send it again.  
> The problem seems to be related to timing considering that the driver works 
> perfectly 5-10% of the time, but timing of what?  I don't know what to look 
> for.

So with the first problem sorted out, I guess the other one is related
to to inexactly reported data feedback from the device. Some explanation
about the current code.

The code in the lower half in snd_usb_handle_sync_urb(), endpoint.c does
some auto-detection of the feedback rate format. This is done in order
to cope with all the many devices use have all sorts of rate formats.
When called for the first time after a stream start, it shifts the
received value until it matches the nominal sampling frequency with an
accuracy of +50% or -25%. Once the shift value is determined, it is
saved for later reference. In case the values get badly of of bounds
over subsequent calls, the code falls back to the auto-detection mode again.

In other words: if the device reports a bogus value in the very first
feedback packet, but stays inside the limits of the thresholds that
would make it fall back to auto-detection, the shift value will always
be wrong for the duration of that stream, resulting in bogus data rates
produced by the driver.

This is where I would have a look. Add some printk()s in the "if
(unlikely(ep->freqshift == INT_MIN))" case and dump the values that are
detected, for both a working and non-working case.

Let me know if that brings you anywhere :)


Daniel

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

* Re: [Alsa-user] Ticks when playing to USB DAC at high sample rates
  2012-11-22 19:40                         ` [Alsa-user] " Daniel Mack
@ 2012-11-22 21:08                           ` Daniel Mack
  0 siblings, 0 replies; 14+ messages in thread
From: Daniel Mack @ 2012-11-22 21:08 UTC (permalink / raw)
  To: Jeffrey Barish; +Cc: alsa-user, alsa-devel

On 22.11.2012 20:40, Daniel Mack wrote:
> On 07.11.2012 18:05, Jeffrey Barish wrote:
>> On Wed 07 November 2012 10:04:14 Daniel Mack wrote:
>>> On 07.11.2012 10:01, Daniel Mack wrote:
>>>> On 07.11.2012 00:54, Jeffrey Barish wrote:
>>>>> I guess that snd_usb_pcm_prepare is called by the core usb system to
>>>>> prepare the snd driver.  Anyway, snd_usb_pcm_prepare calls
>>>>> configure_endpoint with a substream.  Then configure_endpoint calls
>>>>> snd_usb_endpoint_set_params with the data endpoint that corresponds to
>>>>> the substream.  snd_usb_endpoint_set_params calls data_ep_set_params
>>>>> with the data ep and data_ep_set_params sets nurbs to 2 for the data
>>>>> endpoint.
>>>>>
>>>>> snd_usb_endpoint_set_params has code to call sync_ep_set_params when the
>>>>> endpoint is type sync.  sync_ep_set_params sets nurbs to 4 (why?). 
>>>>> However, snd_usb_endpoint_set_params never invokes the call to
>>>>> sync_ep_set_params because ep->type is always data.  Back up:
>>>>> snd_usb_endpoint_set_params is called from configure_endpoint.  It is
>>>>> called from an if block contingent on the substream's having a sync
>>>>> endpoint.  It does.  However, the call to snd_usb_endpoint_set_params
>>>>> passes subs->data_endpoint as the first argument, so
>>>>> snd_usb_endpoint_set_params simply repeats the operations it performed
>>>>> as a result of the previous invocation.  I presume that the first
>>>>> argument to the second call to snd_usb_endpoint_set_params should be
>>>>> subs->sync_endpoint.> 
>>>> Eh. You clearly spotted a bug here. The rally interesting thing is that
>>>> that it didn't bite us earlier, as it's in since 3.6.
>>>>
>>>>>  I
>>>>>
>>>>> made that change.  Now freqm does change.  However, I am getting tons of
>>>>> ticks.  Now it sounds as if the payload size is always wrong.
>>>>>
>>>>> Oh, 44.1 kHz works.  48 kHz works.  88.2 and 96 don't work.
>>>>
>>>> That's a different issue. Would you like to prepare a patch for the
>>>> issue above please?
>>
>> I don't know how to prepare a patch, so I'm inclined to fix the remaining 
>> problem before stopping to figure out the patch problem.
>>
>> I didn't get your previous email.  I hope that it contained some suggestions 
>> on what to look for to solve the remaining problem.  Please send it again.  
>> The problem seems to be related to timing considering that the driver works 
>> perfectly 5-10% of the time, but timing of what?  I don't know what to look 
>> for.
> 
> So with the first problem sorted out, I guess the other one is related
> to to inexactly reported data feedback from the device. Some explanation
> about the current code.
> 
> The code in the lower half in snd_usb_handle_sync_urb(), endpoint.c does
> some auto-detection of the feedback rate format. This is done in order
> to cope with all the many devices use have all sorts of rate formats.
> When called for the first time after a stream start, it shifts the
> received value until it matches the nominal sampling frequency with an
> accuracy of +50% or -25%. Once the shift value is determined, it is
> saved for later reference. In case the values get badly of of bounds
> over subsequent calls, the code falls back to the auto-detection mode again.
> 
> In other words: if the device reports a bogus value in the very first
> feedback packet, but stays inside the limits of the thresholds that
> would make it fall back to auto-detection, the shift value will always
> be wrong for the duration of that stream, resulting in bogus data rates
> produced by the driver.
> 
> This is where I would have a look. Add some printk()s in the "if
> (unlikely(ep->freqshift == INT_MIN))" case and dump the values that are
> detected, for both a working and non-working case.

Btw - if that is the case, and the device stabilizes after a while, one
way to fix that problem is to simply ignore the first x packets that are
received. And there's already a quirks framework for that: initalize
ep->skip_packets from snd_usb_endpoint_start_quirk().


Daniel

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

end of thread, other threads:[~2012-11-22 21:08 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <3884466.olklcBH31l@quintet>
     [not found] ` <508AE8B9.4040405@gmail.com>
     [not found]   ` <10249117.axLqbotY1S@quintet>
     [not found]     ` <2168981.L00zyKDK9R@quintet>
2012-11-04 10:39       ` [Alsa-user] Ticks when playing to USB DAC at high sample rates Daniel Mack
2012-11-05  1:53         ` Jeffrey Barish
2012-11-05 15:03           ` [Alsa-user] " Daniel Mack
2012-11-05 22:29             ` Jeffrey Barish
2012-11-06  0:12               ` [Alsa-user] " Daniel Mack
2012-11-06 23:54                 ` Jeffrey Barish
2012-11-07  9:01                   ` [Alsa-user] " Daniel Mack
2012-11-07  9:04                     ` Daniel Mack
2012-11-07 17:05                       ` Jeffrey Barish
2012-11-22 19:40                         ` [Alsa-user] " Daniel Mack
2012-11-22 21:08                           ` Daniel Mack
2012-11-08 18:54                     ` Jeffrey Barish
2012-11-22 19:29                       ` [Alsa-user] " Daniel Mack
2012-11-05 14:20         ` Jeffrey Barish

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.