We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 3656 - SDL 2.0.5 won't play sound at 96KHz on macOS
Summary: SDL 2.0.5 won't play sound at 96KHz on macOS
Status: RESOLVED FIXED
Alias: None
Product: SDL
Classification: Unclassified
Component: audio (show other bugs)
Version: 2.0.5
Hardware: x86_64 macOS 10.12
: P2 normal
Assignee: Ryan C. Gordon
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-05-20 08:38 UTC by Lior Halphon
Modified: 2017-05-24 05:33 UTC (History)
0 users

See Also:


Attachments
sample.wav at 96k (2.00 MB, audio/wav)
2017-05-23 17:42 UTC, Ryan C. Gordon
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Lior Halphon 2017-05-20 08:38:25 UTC
I upgraded my SDL1.2 project to SDL2, and sound stopped working on macOS. Sound is configured to 96KHz. SDL_OpenAudio returns 0 and returns the correct obtained struct, and my audio callback is being called, but no sound is produced.

Lowering the frequency to 44.1KHz makes the sound play. Downgrading to SDL 2.0.4 allows playback in 96KHz again.
Comment 1 Ryan C. Gordon 2017-05-23 17:42:58 UTC
Created attachment 2745 [details]
sample.wav at 96k


This is working here for me with the test/loopwave.c program in SDL's source distribution ( https://hg.libsdl.org/SDL/file/7860594a8ad7/test/loopwave.c ) and a 96KHz wave file (attached) on macOS 10.12.5.

--ryan.
Comment 2 Ryan C. Gordon 2017-05-23 17:43:46 UTC
Is there some code you can post that reproduces this bug?
Comment 3 Lior Halphon 2017-05-23 18:09:15 UTC
The following code reproduces the problem. It should play white noise for 10 seconds, but only plays for a split second. Changing freq to 96000 or samples to 2048 solves it.

#include <stdlib.h>
#include <SDL2/SDL.h>

static void audio_callback(void *gb, Uint8 *stream, int len)
{
    while (len--) {
        *(stream++) = rand();
    }
}
    
int main(int argc, char **argv)
{
    SDL_AudioSpec want_aspec, have_aspec;

    SDL_Init( SDL_INIT_EVERYTHING );
    
    /* Configure Audio */
    memset(&want_aspec, 0, sizeof(want_aspec));
    want_aspec.freq = 96000;
    want_aspec.format = AUDIO_S16SYS;
    want_aspec.channels = 2;
    want_aspec.samples = 512;
    want_aspec.callback = audio_callback;
    want_aspec.userdata = NULL;
    SDL_OpenAudio(&want_aspec, &have_aspec);
    
    /* Start Audio */
    SDL_PauseAudio(0);

    SDL_Delay(10000);
    return 0;
}
Comment 4 Lior Halphon 2017-05-23 18:10:07 UTC
(In reply to Lior Halphon from comment #3)
> Changing freq to 96000

to 44100*
Comment 5 Sam Lantinga 2017-05-23 18:32:04 UTC
This is a quirk in Mac OS X CoreAudio. If you don't fill audio buffers fast enough they'll stop being used in the audio pipeline. The only answer I've found is to make sure you have 15-20 ms in your audio buffers. Changing your buffer size or reducing your audio rate is the correct workaround.
Comment 6 Sam Lantinga 2017-05-23 18:32:20 UTC
This is true on iOS as well.
Comment 7 Ryan C. Gordon 2017-05-23 18:40:57 UTC
(In reply to Sam Lantinga from comment #6)
> This is true on iOS as well.

Hmm, we might be able to mitigate this now that we have SDL_AudioStream, which can buffer the difference if the app wants too small of a buffer per-callback...

(But it's still possible the issue is me misusing CoreAudio and it only manifests when the buffers are small.)

--ryan.
Comment 8 Lior Halphon 2017-05-23 18:46:33 UTC
How did it work in SDL 2.0.4 and 1.2 then? What was changed to make this an issue?
Comment 9 Ryan C. Gordon 2017-05-23 18:59:28 UTC
(In reply to Lior Halphon from comment #8)
> How did it work in SDL 2.0.4 and 1.2 then? What was changed to make this an
> issue?

We moved from Apple's AudioUnits API to AudioQueues.

--ryan.
Comment 10 Ryan C. Gordon 2017-05-24 04:24:10 UTC
This should be fixed by https://hg.libsdl.org/SDL/rev/ad26a063ffff ... poking at Apple's API suggests that what CoreAudio wants is at least X milliseconds of audio available when it's time to feed the audio hardware, and it doesn't care if you queued one gigantic buffer to get there or a dozen tiny ones.

I imagine it's possible that a USB or bluetooth device wants way more buffered at a time than the on-board PCM chip, and there's probably an API to query for that minimum limit, but aiming for being able to buffer two blocks of 50 milliseconds seems to work okay (20ms was too small).

This approach also lets us have the app's callback fire with the originally-desired sample size but also not use a full SDL_AudioStream to buffer the difference.

--ryan.
Comment 11 Ryan C. Gordon 2017-05-24 05:33:43 UTC
(In reply to Ryan C. Gordon from comment #10)
> I imagine it's possible that a USB or bluetooth device wants way more
> buffered at a time than the on-board PCM chip, and there's probably an API
> to query for that minimum limit, but aiming for being able to buffer two
> blocks of 50 milliseconds seems to work okay (20ms was too small).

Turns out 50 only needs to be 10 when you use the correct variable with the equation (samples, not size). https://hg.libsdl.org/SDL/rev/0b4a3c824d38

--ryan.