| Summary: | [Feature Request] Add SDL_GetAudioDeviceSpec | ||
|---|---|---|---|
| Product: | SDL | Reporter: | Ethan Lee <flibitijibibo> |
| Component: | audio | Assignee: | Ryan C. Gordon <icculus> |
| Status: | ASSIGNED --- | QA Contact: | Sam Lantinga <slouken> |
| Severity: | enhancement | ||
| Priority: | P2 | CC: | aeikum |
| Version: | HG 2.0 | ||
| Hardware: | All | ||
| OS: | All | ||
| Attachments: | GetAudioDeviceSpec stub | ||
|
Description
Ethan Lee
2018-05-29 21:40:59 UTC
This is something we've been running into too, I'm going to think on this for a bit and come up with a solution. --ryan. This just went from "FAudio kind of needs this" to "how on Earth is any Windows application shipping without this" real quick... WASAPI, as it turns out, does not work at all whatsoever if we do not have a way to detect the samples value that it asks for via IAudioClient_GetBufferSize. If your period size is too small it introduces skipping (or worse if the rest of the unused buffer is uninitialized), if your period size is too big it will cause a buffer overflow (!!!). The REALLY serious problem with WASAPI is that we don't get this value until after the IAudioClient is made, which for WinRT appears to be asynchronous and only happens after RunAudio has started. It would probably take a lot of work to do this with ALLOW_SAMPLES_CHANGE (though I do still think that's important to have), but this could be a way to avoid having to depend on that. For now FAudio has a hack since we're locked at 48KHz anyhow, but this is still extremely dangerous and may potentially be both a health/safety concern and a security issue when we're wrong: https://github.com/FNA-XNA/FAudio/commit/59e88cb097a258ea2d8f5a0d8d74a3a87ede11b4 Throwing some basic notes in here for later: ALSA: - snd_pcm_hw_params_get_channels - snd_pcm_hw_params_get_rate Pulse: pa_sample_spec, requires connecting to server first? CoreAudio: AudioDeviceGetProperty - kAudioDevicePropertyStreamConfiguration (AudioBufferList) - kAudioDevicePropertyNominalSampleRate WASAPI: IAudioClient_GetMixFormat, requires initializing the client first DirectSound: - IDirectSound_GetSpeakerConfig, channel mask -> channel count - IDirectSound_GetCaps, dwMaxSecondarySampleRate? Created attachment 3956 [details]
GetAudioDeviceSpec stub
Wow, almost exactly a year... anyway:
I've had this stub laying around but I never got into the details of the implementation. It's basically a ripoff of GetAudioDeviceName, including the part where spec is stored in the device item list. This makes the function convenient to implement, but adds the issue of detecting the spec at device add time, so we'd have to modify AddAudioDevice and DetectDevices (including the default fallback) and pray that the query on each device doesn't add to init time.
The alternative is that we add a new function to AudioDriverImpl, but it looks like no other function of this type does this, so the only thing that would change in GetAudioDeviceSpec is passing the opaque handle to the implementation instead of doing that memcpy, if that makes any sense.
Any opinions? Depending on the preference I can probably throw together a prototype for WASAPI and Pulse, dunno about the others.
Been occasionally reading audio APIs and how others get device info... I'm starting to wonder if we should just make the API honest and treat it more like OpenAudioDevice? It's kind of amazing how absolutely nobody lets you get basic device info without making a whole sound server connection first. One of the main reasons we don't just do OpenAudioDevice with 0s for all the spec info is because SDL specifically gets itself in the way between the application and the backend: https://hg.libsdl.org/SDL/file/e42055c6d8b5/src/audio/SDL_audio.c#l1152 For XAudio2/FAudio (and other middlewares like FMOD) the API is actually the same on paper; to get the system default you just pass 0 for channels/samplerate (and sometimes buffer size). This _should_ be the same for SDL, but instead we get hardcoded values. I can see two possible ways of dealing with this: 1. Fix OpenAudioDevice to _actually_ send 0 to the backends, and allow the backend to provide the real device mix format. This would totally solve it for FAudio and friends and I'd have no problem opening/closing just for format queries, but I don't know how many programs out there depend on those hardcoded defaults. If the system doesn't match SDL's numbers it could get ugly. 2. Add the new SDL_GetAudioDeviceSpec func, but give it the same API as OpenAudioDevice (rather than something like GetAudioDeviceName) and document it as being effectively the same as opening and closing a device manually. This would allow us to do #1 without having to worry about prepare_audiospec compatibility, but it's a whole new function and code path on the inside and people on the outside may be surprised by how slow the function may end up being (particularly on platforms like WinRT), unlike Open/Close where you know exactly what you've gotten yourself into. Obviously this can wait until after 2.0.12, but I'd like to start thinking about this for 2.0.14 so I can finally get rid of the environment variable hack in FAudio and FMOD_SDL. |