shithub: m8c

Download patch

ref: b0c49e6a0004579941b8b1a23d687187cec40f99
parent: 45b1ba0b09ae146cb4b117785ed38c979a26141c
author: laamaa <jonne.kokkonen@gmail.com>
date: Mon Aug 25 06:59:56 EDT 2025

add prefill logic to SDL audio callback to help with audio glitching

--- a/src/backends/audio_sdl.c
+++ b/src/backends/audio_sdl.c
@@ -10,12 +10,14 @@
 static unsigned int audio_initialized = 0;
 static SDL_AudioSpec audio_spec_in = {SDL_AUDIO_S16LE, 2, 44100};
 
-static void SDLCALL audio_cb_out(void *userdata, SDL_AudioStream *stream, int length, int unused) {
+static void SDLCALL audio_cb_out(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount) {
   // suppress compiler warnings
   (void)userdata;
-  (void)length;
-  (void)unused;
 
+  if (additional_amount <= 0) {
+    return;
+  }
+
   const int bytes_available = SDL_GetAudioStreamAvailable(audio_stream_in);
   if (bytes_available == -1) {
     SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
@@ -24,27 +26,51 @@
     audio_close();
     return;
   }
-  if (bytes_available == 0) {
-    return;
-  }
 
-  Uint8 *src_audio_data = SDL_malloc(bytes_available);
-  if (!src_audio_data) { // check allocation
-    SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Failed to allocate audio buffer");
-    audio_close();
-    return;
+  // Decide how much to feed this time.
+  int to_write_goal = additional_amount;
+  if (total_amount > 0) {
+    const int prefill_cap = additional_amount * 2;
+    if (to_write_goal < total_amount) {
+      to_write_goal = SDL_min(total_amount, prefill_cap);
+    }
   }
 
-  const int bytes_read = SDL_GetAudioStreamData(audio_stream_in, src_audio_data, bytes_available);
-  if (bytes_read == bytes_available) {
-    SDL_PutAudioStreamData(stream, src_audio_data, bytes_read);
-  } else {
-    SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
-                 "Error getting available audio stream bytes: %s, destroying audio",
-                 SDL_GetError());
-    audio_close();
+  int to_write = to_write_goal;
+  Uint8 temp[4096];
+
+  while (to_write > 0) {
+    int still_avail = SDL_GetAudioStreamAvailable(audio_stream_in);
+    if (still_avail <= 0) {
+      break; // nothing more to pull now
+    }
+
+    int chunk = still_avail;
+    if (chunk > (int)sizeof(temp)) chunk = (int)sizeof(temp);
+    if (chunk > to_write) chunk = to_write;
+
+    const int got = SDL_GetAudioStreamData(audio_stream_in, temp, chunk);
+    if (got == -1) {
+      SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
+                   "Error reading audio stream data: %s, destroying audio",
+                   SDL_GetError());
+      audio_close();
+      return;
+    }
+    if (got == 0) {
+      break; // no data currently available
+    }
+
+    if (!SDL_PutAudioStreamData(stream, temp, got)) {
+      SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
+                   "Error putting audio stream data: %s, destroying audio",
+                   SDL_GetError());
+      audio_close();
+      return;
+    }
+
+    to_write -= got;
   }
-  SDL_free(src_audio_data);
 }
 
 void audio_toggle(const char *output_device_name, unsigned int audio_buffer_size) {
@@ -134,9 +160,9 @@
   audio_stream_out = SDL_OpenAudioDeviceStream(output_device_id, NULL, audio_cb_out, NULL);
 
   SDL_AudioSpec audio_spec_out;
-  int audio_buffer_size_real = 0;
+  int audio_out_buffer_size_real, audio_in_buffer_size_real = 0;
 
-  SDL_GetAudioDeviceFormat(output_device_id, &audio_spec_out, &audio_buffer_size_real);
+  SDL_GetAudioDeviceFormat(output_device_id, &audio_spec_out, &audio_out_buffer_size_real);
 
   if (!audio_stream_out) {
     SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Error opening audio output device: %s", SDL_GetError());
@@ -143,8 +169,8 @@
     return 0;
   }
   SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO,
-              "Opening audio output: rate %dhz, buffer size: %d sample frames", audio_spec_out.freq,
-              audio_buffer_size_real);
+              "Opening audio output: rate %dhz, buffer size: %d frames", audio_spec_out.freq,
+              audio_out_buffer_size_real);
 
   audio_stream_in = SDL_OpenAudioDeviceStream(m8_device_id, &audio_spec_in, NULL, NULL);
   if (!audio_stream_in) {
@@ -152,10 +178,13 @@
     SDL_DestroyAudioStream(audio_stream_out);
     return 0;
   }
-  SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO, "Audiospec In: format %d, channels %d, rate %d",
-               audio_spec_in.format, audio_spec_in.channels, audio_spec_in.freq);
 
   SDL_SetAudioStreamFormat(audio_stream_in, &audio_spec_in, &audio_spec_out);
+  SDL_GetAudioDeviceFormat(m8_device_id, &audio_spec_in, &audio_in_buffer_size_real);
+  SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO, "Audiospec In: format %d, channels %d, rate %d, buffer size %d frames",
+               audio_spec_in.format, audio_spec_in.channels, audio_spec_in.freq, audio_in_buffer_size_real);
+
+
 
   SDL_ResumeAudioStreamDevice(audio_stream_out);
   SDL_ResumeAudioStreamDevice(audio_stream_in);
--