Skip to content

Commit f2ae650

Browse files
committed
audio: Binding an SDL_AudioStream will set missing formats.
It _must_ have the format set for the opposite side from the device (so playback needs the src format set, and recording needs the dst format set), since the stream gets mangled by the device thread if not. So if it has never been set (stream created with NULL audiospec), just set it to match the device. If the stream is just meant to buffer and not convert, this is desired behavior, even if it didn't also fix a bug. Binding the audio stream will always set the device side's format, as usual; this does not need to be set by the caller at all. Fixes #13363.
1 parent 3c04c88 commit f2ae650

File tree

2 files changed

+17
-5
lines changed

2 files changed

+17
-5
lines changed

include/SDL3/SDL_audio.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID devid);
942942
* Binding a stream to a device will set its output format for playback
943943
* devices, and its input format for recording devices, so they match the
944944
* device's settings. The caller is welcome to change the other end of the
945-
* stream's format at any time with SDL_SetAudioStreamFormat().
945+
* stream's format at any time with SDL_SetAudioStreamFormat(). If the other
946+
* end of the stream's format has never been set (the audio stream was created
947+
* with a NULL audio spec), this function will set it to match the device
948+
* end's format.
946949
*
947950
* \param devid an audio device to bind a stream to.
948951
* \param streams an array of audio streams to bind.

src/audio/SDL_audio.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,8 @@ bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
11651165
// We should have updated this elsewhere if the format changed!
11661166
SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &device->spec, NULL, NULL));
11671167

1168+
SDL_assert(stream->src_spec.format != SDL_AUDIO_UNKNOWN);
1169+
11681170
int br = 0;
11691171

11701172
if (!SDL_GetAtomicInt(&logdev->paused)) {
@@ -1224,6 +1226,8 @@ bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
12241226
// We should have updated this elsewhere if the format changed!
12251227
SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &outspec, NULL, NULL));
12261228

1229+
SDL_assert(stream->src_spec.format != SDL_AUDIO_UNKNOWN);
1230+
12271231
/* this will hold a lock on `stream` while getting. We don't explicitly lock the streams
12281232
for iterating here because the binding linked list can only change while the device lock is held.
12291233
(we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
@@ -1363,6 +1367,7 @@ bool SDL_RecordingAudioThreadIterate(SDL_AudioDevice *device)
13631367
SDL_assert(stream->src_spec.format == ((logdev->postmix || (logdev->gain != 1.0f)) ? SDL_AUDIO_F32 : device->spec.format));
13641368
SDL_assert(stream->src_spec.channels == device->spec.channels);
13651369
SDL_assert(stream->src_spec.freq == device->spec.freq);
1370+
SDL_assert(stream->dst_spec.format != SDL_AUDIO_UNKNOWN);
13661371

13671372
void *final_buf = output_buffer;
13681373

@@ -2024,10 +2029,6 @@ bool SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream * const *stre
20242029
} else if (logdev->simplified) {
20252030
result = SDL_SetError("Cannot change stream bindings on device opened with SDL_OpenAudioDeviceStream");
20262031
} else {
2027-
2028-
// !!! FIXME: We'll set the device's side's format below, but maybe we should refuse to bind a stream if the app's side doesn't have a format set yet.
2029-
// !!! FIXME: Actually, why do we allow there to be an invalid format, again?
2030-
20312032
// make sure start of list is sane.
20322033
SDL_assert(!logdev->bound_streams || (logdev->bound_streams->prev_binding == NULL));
20332034

@@ -2062,9 +2063,17 @@ bool SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream * const *stre
20622063

20632064
if (result) {
20642065
// Now that everything is verified, chain everything together.
2066+
const bool recording = device->recording;
20652067
for (int i = 0; i < num_streams; i++) {
20662068
SDL_AudioStream *stream = streams[i];
20672069
if (stream) { // shouldn't be NULL, but just in case...
2070+
// if the stream never had its non-device-end format set, just set it to the device end's format.
2071+
if (recording && (stream->dst_spec.format == SDL_AUDIO_UNKNOWN)) {
2072+
SDL_copyp(&stream->dst_spec, &device->spec);
2073+
} else if (!recording && (stream->src_spec.format == SDL_AUDIO_UNKNOWN)) {
2074+
SDL_copyp(&stream->src_spec, &device->spec);
2075+
}
2076+
20682077
stream->bound_device = logdev;
20692078
stream->prev_binding = NULL;
20702079
stream->next_binding = logdev->bound_streams;

0 commit comments

Comments
 (0)