From e3ce9ae8288dd526134b20baa279b81ecb1fb7cb Mon Sep 17 00:00:00 2001 From: John Lorentzson Date: Sun, 6 Apr 2025 23:44:17 +0200 Subject: [PATCH] Park the main thread while getting audio frames from the game The main justification for this is that normal behaviour from a backend is to have the main thread be interrupted by the audio system and to then stay within the audio system while getting audio frames. Parking the main thread simulates this by ensuring nothing else happens in the game's logical flow at the same time. --- src/Backends/Audio/SoftwareMixer/Solaris.cpp | 35 ++++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Backends/Audio/SoftwareMixer/Solaris.cpp b/src/Backends/Audio/SoftwareMixer/Solaris.cpp index 32df74e9..cfc7487a 100644 --- a/src/Backends/Audio/SoftwareMixer/Solaris.cpp +++ b/src/Backends/Audio/SoftwareMixer/Solaris.cpp @@ -2,8 +2,10 @@ // See LICENCE.txt for details. #include "Backend.h" +#include "../../Misc.h" -#include +#include +#include #include #include #include @@ -15,8 +17,10 @@ #include #include -int sndfp; -void (*parent_callback)(long *stream, size_t frames_total); +static pthread_t mainThread; +static int sndfp; +static void (*parent_callback)(long *stream, size_t frames_total); +static bool audioDone = false; static void* soundcheckthread(void*) { unsigned long for_as_long_as_it_seems_we_should = 0; @@ -38,17 +42,35 @@ static void* soundcheckthread(void*) { long mix[0x400 * 2]; memset(mix, 0, 0x400 * 2); + + // park the main thread since the game probably expects it to not be + // doing anything else while we're requesting audio frames. + audioDone = false; + pthread_kill(mainThread, SIGUSR1); + parent_callback(mix, 0x400 * 2); + // unpark the main thread now that we're not using game state anymore + audioDone = true; + write(sndfp, mix, 0x400 * 2); for_as_long_as_it_seems_we_should = (0x400 / 48000) * 1000000; } } +static void threadPark(int signo) { + while(audioDone == false); +} + unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total)) { sndfp = open("/dev/audio", 0, O_WRONLY); + if(sndfp == -1) { + Backend_PrintError("Failed to open audio device.\n"); + return 0; + } + audio_prinfo_t audioInfo; ioctl(sndfp, AUDIO_GETINFO, &audioInfo); audioInfo.sample_rate = 48000; @@ -58,6 +80,13 @@ unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t fr audioInfo.port = AUDIO_SPEAKER; ioctl(sndfp, AUDIO_SETINFO, &audioInfo); + if(signal(SIGUSR1, threadPark) == SIG_ERR) { + Backend_PrintError("Failed to register thread park signal handler for audio system.\n"); + return 0; + } + + mainThread = pthread_self(); + pthread_t thread; pthread_attr_t thread_attr; pthread_attr_init(&thread_attr);