USB Audio - Strange Behavior of Explicit Feedback calculator

Sub forums for various specialist XMOS applications. e.g. USB audio, motor control and robotics.
User avatar
Caleb
Experienced Member
Posts: 82
Joined: Thu Apr 04, 2013 10:14 pm

USB Audio - Strange Behavior of Explicit Feedback calculator

Post by Caleb »

I've encountered some strange problems with OSX and USB audio that do not occur with PC/Thesycon. I wonder if anyone has some similar experience or has a clue what's up.

Our company's products allow a user to monitor various audio inputs including an XMOS-based USB audio interface. When monitoring another input, it is required that the audio mclk to the XMOS be turned-off. It would require a great deal of reorganization of the reference software project in order for it to tolerate arbitrary removal of mclk. One simple solution is to use a hardware MUX (controlled by a supervisor micro) to select an alternate oscillator when the proper audio mclk is not available. Since we're using a 24MHz oscillator to run the XMOS, we have have also used this oscillator as the alternate source for mclk.

The problem I encounter with Apple macintosh computers: if I switch the mclk from the proper audio mclk (24.576 or 22.5792MHz depending on FS) to 24MHz and then later switch back to the proper audio mclk, sometimes the audio data is corrupted. It will stutter on and off at various rates and sometimes it just goes silent. This behavior is always fixed when I stop and start the audio player on the computer.

The audio mclk is used in two places in the reference software project: It clocks the IIS interface and it is used to calculate data for the explicit feedback endpoint.

Consider the impact of suddenly changing the frequency of mclk: the frequency of the IIS interface changes and the calculated feedback changes. If you were to listen to the output of a DAC connected to the IIS interface then you would hear the music slow-down or speed-up. The computer should simply continue to send audio data at the rate specified by the feedback endpoint. There may be some momentary overrun or underrun but the decouple thread seems to handle this gracefully. My experience is that PC/Thesycon works well with this change in mclk frequency. Apple does not.

One theory I had was the Apple computer simply does not tolerate a sudden significant change in FS or else the sample rate derived from a 24MHz mclk is too far from the proper FS. My first attempt to solve the problem was to substitute a constant nominal feedback value while the mclk is changed to 24MHz. The supervisor micro-controller provides this cue such that the substitute feedback begins before the mclk changes and continues well after the proper mclk frequency resumes. It is necessary for the feedback calculation to run for 128 USB frames in order to accumulate correct data. This did not solve the problem.

Through various experiments I came across a strange solution. In usb_buffer.xc, case inuint_byref(c_sof, tmp): calculates explicit feedback based on reading the counter of a port that is clocked by mclk.
asm (" getts %0, res[%1]" : "=r" ( tmp ) : "r" ( p_off_mclk ) );

If, while the mclk is 24MHz, I simply don't read the port counter, the problem does not occur. Of course I must still send the correct substitute (nominal) feedback data until correct calculated feedback resumes.

I can't explain why reading the port counter could cause a problem – what would be different if only the frequency of mclk changes? I measured time between execution of case inuint_byref(c_sof, tmp):. Sometimes when the mclk frequency changes it appears that servicing a SOF is dropped.
Perhaps something goes wrong with the port when the mux switches and a runt pulse appears. Could this somehow temporarily stall execution in this thread? I'd thought that clock inputs are sampled by the system clock and so the port should be immune to anomalous clock pulses.

Does anyone have any thoughts on this? thanks


User avatar
Ross
XCore Expert
Posts: 768
Joined: Thu Dec 10, 2009 9:20 pm

Post by Ross »

In the apple usb audio driver there is a filter than tracks the feedback. It is quite sensitive and doesn't tolerate errors in the feedback very well.
Caleb wrote:
If, while the mclk is 24MHz, I simply don't read the port counter, the problem does not occur. Of course I must still send the correct substitute (nominal) feedback data until correct calculated feedback resumes.
yes you would be better off sending the "expected" feedback value (so 6 samples exactly for 48KHz) than some count based on a bad clock. However, in general you should avoid the situation where the device is running at a different frequency than the host has set it to.
User avatar
Caleb
Experienced Member
Posts: 82
Joined: Thu Apr 04, 2013 10:14 pm

Post by Caleb »

Yes, I'd guessed this to be the case. I've also demonstrated that it is sensitive to small changes in FS when using implicit feedback. To do that requires input channels and removing the feedback endpoint descriptor.
Ross wrote:In the apple usb audio driver there is a filter than tracks the feedback. It is quite sensitive and doesn't tolerate errors in the feedback very well.
User avatar
Caleb
Experienced Member
Posts: 82
Joined: Thu Apr 04, 2013 10:14 pm

Post by Caleb »

Right - I'm just using a lookup table to chose the correct nominal or "expected" feedback for the current FS: 5.5125 for 44.1lkHz, 6 for 48kHz, etc. ( FS / 8kHz ). And for sanity check I also added some test code that checks the feedback as it is sent and records an error if the value is outside a tight range.

This all works as I intended - BUT only as if I bypass reading the port time stamp while switching to the 24MHz oscillator.

I'd like to learn and understand why reading that port time stamp causes a problem.

I found that when the problem occurs, it is coincident with missing or delayed execution of the SOF handler (case inuint_byref(c_sof, tmp): in usb_buffer.xc). It seems likely that servicing the c_sof is getting blocked for a while. And, it seems that the cause is reading the port time stamp:
asm (" getts %0, res[%1]" : "=r" ( tmp ) : "r" ( p_off_mclk ) );

Is this possible?

I'm looking at the Instruction Details for getts in "The XMOS XS1 Architecture" document (page 109). It lists conditions that raise an exception: Resource illegally shared between threads...
I wonder if this could be a problem. The port named p_off_mclk is not shared between threads but it does share its clock source with the IIS output ports in the audio.xc thread.

I'm not clear what happens when an exception is raised.
Ross wrote:
Caleb wrote:
If, while the mclk is 24MHz, I simply don't read the port counter, the problem does not occur. Of course I must still send the correct substitute (nominal) feedback data until correct calculated feedback resumes.
yes you would be better off sending the "expected" feedback value (so 6 samples exactly for 48KHz) than some count based on a bad clock. However, in general you should avoid the situation where the device is running at a different frequency than the host has set it to.
bearcat
Respected Member
Posts: 282
Joined: Fri Mar 19, 2010 4:49 am

Post by bearcat »

OSX actually uses the feedback. Ok, thanks for the info Ross. Do you know if IOS is similiar, like the iPhone and iPad? Just tested my design this week with an iPhone (using the CCK), and it worked fine. But that was minimal testing. So now I know more testing will be needed with OSX, at least.
User avatar
Ross
XCore Expert
Posts: 768
Joined: Thu Dec 10, 2009 9:20 pm

Post by Ross »

I'm lead to believe that the driver in the Apple devices is very similar to the one in OSX.
User avatar
Caleb
Experienced Member
Posts: 82
Joined: Thu Apr 04, 2013 10:14 pm

Post by Caleb »

If your device only has output channels then the feedback endpoint is required; it's the only way the host gets feedback. If you have input channels and a feedback endpoint (the way the reference project is written) then the host can use either. The Thesycon driver will not exercise the feedback endpoint if there are input channels. OSX will. It seems that the OSX driver observes the FB endpoint but can't seem to always resolve the rate of input samples with the (delayed) fluctuations of the FB endpoint.

I found that, with input channels, OSX driver is much better behaved once I removed the explicit feedback endpoint.

A much simpler way to calculate how many samples to send per frame (for implicit feedback) is to just count how man samples have been delivered to handle_audio_request() between every SOF. That's how many samples to send for the next frame. Then you can throw-away all that explicit feedback calculation every SOF.

There's a useful apple tech note about OSX and USB audio and feedback:
https://developer.apple.com/library/mac ... index.html

Table 4 is interesting - and prompted me towards removing the FB endpoint and improved performance.
bearcat wrote:OSX actually uses the feedback. Ok, thanks for the info Ross. Do you know if IOS is similiar, like the iPhone and iPad? Just tested my design this week with an iPhone (using the CCK), and it worked fine. But that was minimal testing. So now I know more testing will be needed with OSX, at least.
User avatar
Ross
XCore Expert
Posts: 768
Joined: Thu Dec 10, 2009 9:20 pm

Post by Ross »

Previous versions of OSX only had support for "explicit feedback" this is why we have left it in for the moment.

Its worth noting that if things are going wrong with explicit feedback enabled then you are probably doing something nasty to the host...
bearcat
Respected Member
Posts: 282
Joined: Fri Mar 19, 2010 4:49 am

Post by bearcat »

My experience is that the Theyscon driver simply outputs the same number of samples as input, and works well. The match is exact, and doesn't even use the feedback. So I agree it appears if there is an input channel, things are easier. Without an input channel, the driver has no choice but to handle feedback.

My recent experince with IOS, is you do need to handle feedback, unlike the Theyscon driver. That said, it appears the feedback is relatively easy. I achieved a +-2 sample match with little effort.
User avatar
Caleb
Experienced Member
Posts: 82
Joined: Thu Apr 04, 2013 10:14 pm

Post by Caleb »

Ross wrote: Its worth noting that if things are going wrong with explicit feedback enabled then you are probably doing something nasty to the host...
Nasty? perhaps. One example: some of our products will slave to an external word clock. If a valid word clock source is selected then it will become the source (rather than "internal" clock). If then the sampling frequency changes slightly, OSX may freak-out. Operating without the explicit feedback endpoint significantly decreases OSX susceptibility. I guess that this is because it may notice the change from the input channels sooner than from the feedback that is probably reported many frames later.
bearcat wrote: My recent experince with IOS, is you do need to handle feedback, unlike the Theyscon driver. That said, it appears the feedback is relatively easy. I achieved a +-2 sample match with little effort.
If you're not able to operate without the explicit feedback (with OSX) then you may have an error in your descriptors (perhaps 4.9.1 or 4.10.1.1). It works and is Apple's recommended method.