Browse Source

audio: Fixed assertions when capture devices have wrong audio formats.

Fixes #8376.
Ryan C. Gordon 1 year ago
parent
commit
044046bc50
2 changed files with 31 additions and 15 deletions
  1. 29 15
      src/audio/SDL_audio.c
  2. 2 0
      src/audio/SDL_sysaudio.h

+ 29 - 15
src/audio/SDL_audio.c

@@ -189,23 +189,25 @@ static SDL_bool AudioDeviceCanUseSimpleCopy(SDL_AudioDevice *device)
 // should hold device->lock before calling.
 static void UpdateAudioStreamFormatsPhysical(SDL_AudioDevice *device)
 {
-    const SDL_bool iscapture = device->iscapture;
-    const SDL_bool simple_copy = AudioDeviceCanUseSimpleCopy(device);
-    SDL_AudioSpec spec;
+    if (!device->iscapture) {  // for capture devices, we only want to move to float32 for postmix, which we'll handle elsewhere.
+        const SDL_bool simple_copy = AudioDeviceCanUseSimpleCopy(device);
+        SDL_AudioSpec spec;
 
-    device->simple_copy = simple_copy;
-    SDL_copyp(&spec, &device->spec);
-    if (!simple_copy) {
-        spec.format = SDL_AUDIO_F32;  // mixing and postbuf operates in float32 format.
-    }
+        device->simple_copy = simple_copy;
+        SDL_copyp(&spec, &device->spec);
 
-    for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev != NULL; logdev = logdev->next) {
-        for (SDL_AudioStream *stream = logdev->bound_streams; stream != NULL; stream = stream->next_binding) {
-            // set the proper end of the stream to the device's format.
-            // SDL_SetAudioStreamFormat does a ton of validation just to memcpy an audiospec.
-            SDL_LockMutex(stream->lock);
-            SDL_copyp(iscapture ? &stream->src_spec : &stream->dst_spec, &spec);
-            SDL_UnlockMutex(stream->lock);
+        if (!simple_copy) {
+            spec.format = SDL_AUDIO_F32;  // mixing and postbuf operates in float32 format.
+        }
+
+        for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev != NULL; logdev = logdev->next) {
+            for (SDL_AudioStream *stream = logdev->bound_streams; stream != NULL; stream = stream->next_binding) {
+                // set the proper end of the stream to the device's format.
+                // SDL_SetAudioStreamFormat does a ton of validation just to memcpy an audiospec.
+                SDL_LockMutex(stream->lock);
+                SDL_copyp(&stream->dst_spec, &spec);
+                SDL_UnlockMutex(stream->lock);
+            }
         }
     }
 }
@@ -1567,6 +1569,16 @@ int SDL_SetAudioPostmixCallback(SDL_AudioDeviceID devid, SDL_AudioPostmixCallbac
         if (retval == 0) {
             logdev->postmix = callback;
             logdev->postmix_userdata = userdata;
+
+            if (device->iscapture) {
+                for (SDL_AudioStream *stream = logdev->bound_streams; stream != NULL; stream = stream->next_binding) {
+                    // set the proper end of the stream to the device's format.
+                    // SDL_SetAudioStreamFormat does a ton of validation just to memcpy an audiospec.
+                    SDL_LockMutex(stream->lock);
+                    stream->src_spec.format = callback ? SDL_AUDIO_F32 : device->spec.format;
+                    SDL_UnlockMutex(stream->lock);
+                }
+            }
         }
 
         UpdateAudioStreamFormatsPhysical(device);
@@ -1639,6 +1651,8 @@ int SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream **streams, int
             }
             logdev->bound_streams = stream;
 
+            stream->src_spec.format = logdev->postmix ? SDL_AUDIO_F32 : device->spec.format;
+
             SDL_UnlockMutex(stream->lock);
         }
     }

+ 2 - 0
src/audio/SDL_sysaudio.h

@@ -156,6 +156,8 @@ typedef struct SDL_AudioDriver
     SDL_AudioStream *existing_streams;  // a list of all existing SDL_AudioStreams.
     SDL_AudioDeviceID default_output_device_id;
     SDL_AudioDeviceID default_capture_device_id;
+
+    // !!! FIXME: most (all?) of these don't have to be atomic.
     SDL_AtomicInt output_device_count;
     SDL_AtomicInt capture_device_count;
     SDL_AtomicInt last_device_instance_id;  // increments on each device add to provide unique instance IDs