q-p / SoundPusher

Virtual audio device, real-time encoder and SPDIF forwarder for macOS
MIT License
153 stars 15 forks source link

Random skipping due to overloads #24

Closed jebediah2 closed 2 years ago

jebediah2 commented 2 years ago

On Catalina I'm experiencing audio skips from SoundPusher, which I use through a Sound Blaster X4 sound card (usb-c). I've been running tests without using an aggregate device in the Audio MIDI Setup app in order to stream audio to SoundPusher only.

Here are the Console messages I see when the skipping happens:

coreaudiod Audio IO Overload inputs: '' outputs: 'AppleUSBAudioEngine:Creative Technology Ltd:Sound Blaster X1:6' cause: 'Unknown' prewarming: no recovering: no

SoundPusher HALC_ProxyIOContext::IOWorkLoop: skipping cycle due to overload

I'm also getting these messages but not necessarily when the skipping happens, so posting in case it's relevant: Audio MIDI Setup USBMuxHandleDictionary:1437 Adding event 0x6000012db660 to changelist.

coreaudiod  gPTPClockStatistics for 0x3d22fbe058770005
coreaudiod  Grandmaster Identity: 0x3d22fbe058770005
coreaudiod  Clock lock state: Locked
coreaudiod  Rate Ratio: 2199023255552/2199023255552 (1.000000000000)
coreaudiod  Anchors: 40193223614, 40193223614
coreaudiod  Sync Identity: 0x3d22fbe058770005.0

There's also a constant flood of the following whenever SoundPusher is active (numbers differ slightly): kernel + IOAudioEngineUserClient[<private>]::performWatchdogOutput(<private>, 31519) - (5c6,29e2)

I know the skipping gets worse if I also catch the stream with Loopback or an aggregate device to output the back speakers separately, and it will eventually stop altogether, but this is separate issue where the audio skips even when SoundPusher has only one output.

q-p commented 2 years ago

Hm. That sounds like a hardware or driver issue on the SPDIF output side. I'm not what I could be doing differently on the SoundPusher-side (which is in DigitalOutputContext::DeviceIOProcFunc() where the data is encoded).

Most other references to this issue seem to refer to problems on the USB-side (hackintoshes, using USB / TB-hubs in-between). Do you have have the USB card connected directly to the (non-Hackintosh?) Mac?

jebediah2 commented 2 years ago

It's a genuine Macbook Pro with a direct usb-c connection to the sound card, using a quality cable (tried others too), and trying different USB ports.

Is the constant flood of IOAudioEngineUserClient logs expected behavior?

q-p commented 2 years ago

Is the constant flood of IOAudioEngineUserClient logs expected behavior?

Unfortunately yes; Console.app is no longer mainly for actual warnings, but rather a logging hellhole of what is currently happening.

See for example https://opensource.apple.com/source/IOAudioFamily/IOAudioFamily-194.4.11/IOAudioEngineUserClient.cpp.auto.html where this logging unconditionally happens (and was added with mismatching tab vs spaces settings).

jebediah2 commented 2 years ago

Hm. That sounds like a hardware or driver issue on the SPDIF output side. I'm not what I could be doing differently on the SoundPusher-side (which is in DigitalOutputContext::DeviceIOProcFunc() where the data is encoded).

The thing is that the same hardware setup works perfectly well if I select the 'SPDIF Out (Encoded output)' as Audio Device in VLC instead of SoundPusher Audio (>SPDIF Out). So even though the issue might still be hardware-related, doesn't it look like SoundPusher has issues handling it?

q-p commented 2 years ago

It’s probably doing something differently…

You can try commenting out the IOCycle adjustment in https://github.com/q-p/SoundPusher/blob/7fba1a4a00a3786349ff7210b038e6ea6377e916/SoundPusher/DigitalOutputContext.cpp#L100 and see whether that makes a difference.

q-p commented 2 years ago

@jebediah2 Can you give https://www.maven.de/code/SoundPusher.app_nocycleusage.zip a try? This should be the last release version without the cycle-usage adjustment. It's probably not signed / notarized correctly, so you may have to circumvent that for testing.

jebediah2 commented 2 years ago

Thank you, I must say that I wouldn't have been able to compile it myself. I'll give it a try this afternoon.

jebediah2 commented 2 years ago

I gave a 4 hours run to this no-cycle-usage version and experienced no skipping/overload at all.

Strangely, when I tried to run the release version again, the sound was abnormally broken with tons of stutter, saturation and skipping, some of which was reported in the Console, but not all. I did not try to restart coreaudio. Shutting SoundPusher down and using the no-cycle-usage version again worked.

Later this week I'll give it a more real-world test by also sending the video signal to an external monitor and see if SoundPusher still holds, but I think we're already on the right track. Thanks a lot.

Just out of curiosity, how important is the IOCycle adjustment you turned off?

q-p commented 2 years ago

Just out of curiosity, how important is the IOCycle adjustment you turned off?

It tries to move the preparation (encoding) of the output to as late a point in time as needed, so the latency / delay of the sound is as small as possible.

I would like to try a different default for how much head-room I leave for this timing adjustment. The current default (4.0x times as much time as the minimum time needed for a "trial encoding") works fine for my system, but obviously seems to optimistic for your system.

q-p commented 2 years ago

Here's a different version with an adjusted default for the IOCycle SafetyFactor and a way to change it: https://www.maven.de/code/SoundPusher.app_safety8_variable.zip

The old default was 4.0, this new version doubles that to 8.0. Try this out to see whether it performs reliably. If not, you can either increase the value, or set it to 0 to disable adjusting the IOCycle like the previous test version.

You can change this value (you need to restart SoundPusher or the chain after changing it) in Terminal using defaults write de.maven.SoundPusher SafetyFactor -float 8.0.

jebediah2 commented 2 years ago

No issues whatsoever with this version, leaving the variable to its new default of 8.0. And this was with the external monitor plugged in, so the real conditions.

I did see 1 or 2 overloads in the Console but 99% certain it was when I changed the audio routing and/or plugged in some earphones in the Macbook's line out.

So happy the setup works flawlessly now :)

q-p commented 2 years ago

Ok. I'll try to prepare a new version (which will also include an update to the FFmpeg 5 APIs). Give that a shake and then close the issue(s) as appropriate.

q-p commented 2 years ago

Should be fixed with the new release.

jebediah2 commented 2 years ago

Awesome!