Merge pull request #4789 from PrintOrb/fix/audioout-shared-sdl-init
fix(audioout): serialize SDL audio initialization for Dark Forces
This commit is contained in:
commit
6d032559c3
|
|
@ -1,5 +1,6 @@
|
|||
add_library(libSceAudioOut SHARED EXCLUDE_FROM_ALL
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioOut.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioOutSdl.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioOut2Context.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioOut2PadMix.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioOut2Port.cpp
|
||||
|
|
@ -17,6 +18,17 @@ target_link_libraries(libSceAudioOut PRIVATE libc libkernel SDL2-static)
|
|||
configure_windows_unwind(libSceAudioOut)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(audio_out_initialization_tests tests/AudioOutInitialization.cpp src/AudioOutSdl.cpp)
|
||||
target_include_directories(audio_out_initialization_tests PRIVATE ${LIBS_INCLUDE_DIR} ${ANYPS5_SDL2_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out_initialization_tests PRIVATE libc)
|
||||
configure_windows_unwind(audio_out_initialization_tests)
|
||||
add_test(NAME audio_out_initialization COMMAND audio_out_initialization_tests)
|
||||
set_tests_properties(audio_out_initialization PROPERTIES TIMEOUT 10)
|
||||
if(WIN32)
|
||||
set_tests_properties(audio_out_initialization PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
|
||||
add_test_executable(audio_out2_pad_mix_tests tests/AudioOut2PadMix.cpp src/AudioOut2PadMix.cpp)
|
||||
target_include_directories(audio_out2_pad_mix_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out2_pad_mix_tests PRIVATE libc)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef CORE_LIBS_PRX_LIBSCEAUDIOOUT_INCLUDE_AUDIOOUTSDL_HPP
|
||||
#define CORE_LIBS_PRX_LIBSCEAUDIOOUT_INCLUDE_AUDIOOUTSDL_HPP
|
||||
|
||||
int InitializeSdlAudio_nid_no_patch();
|
||||
|
||||
#endif
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/PreciseWait.hpp"
|
||||
#include "prx/libkernel/Time/include/Time.hpp"
|
||||
#include "prx/libSceAudioOut/include/AudioOutSdl.hpp"
|
||||
|
||||
static constexpr int PORT_TYPE_MAIN = 0;
|
||||
static constexpr int PORT_TYPE_BGM = 1;
|
||||
|
|
@ -108,7 +109,7 @@ static bool ensureSdlAudio() {
|
|||
if (g_sdlInitialized) {
|
||||
return true;
|
||||
}
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
||||
if (InitializeSdlAudio_nid_no_patch() < 0) {
|
||||
return false;
|
||||
}
|
||||
g_sdlInitialized = true;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "prx/libc/include/General.hpp"
|
||||
#include "prx/libc/include/PreciseWait.hpp"
|
||||
#include "AudioOut2Internal.hpp"
|
||||
#include "prx/libSceAudioOut/include/AudioOutSdl.hpp"
|
||||
|
||||
// An AudioOut2 context is the hardware output queue: every push appends a grain (num_grains samples)
|
||||
// to a queue of queue_depth grains that plays in real time. Titles pace their mixer on that queue, so
|
||||
|
|
@ -106,7 +107,7 @@ static std::uint32_t QueueLevel(AudioOut2Context& context, Clock::time_point now
|
|||
static void DeviceCallback(void* userdata, Uint8* stream, int length);
|
||||
|
||||
static void OpenDevice(AudioOut2Context& context) {
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
||||
if (InitializeSdlAudio_nid_no_patch() < 0) {
|
||||
AUDIOOUT2_TRACE("SDL audio init failed: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
|
@ -134,7 +135,7 @@ static void CloseDevice(SDL_AudioDeviceID device) {
|
|||
}
|
||||
|
||||
static void OpenPadDevice(AudioOut2Context& context) {
|
||||
if (SDL_WasInit(SDL_INIT_AUDIO) == 0 && SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) return;
|
||||
if (SDL_WasInit(SDL_INIT_AUDIO) == 0 && InitializeSdlAudio_nid_no_patch() < 0) return;
|
||||
const int count = SDL_GetNumAudioDevices(0);
|
||||
for (int index = 0; index < count; index++) {
|
||||
const char* listed = SDL_GetAudioDeviceName(index, 0);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
#include "prx/libSceAudioOut/include/AudioOutSdl.hpp"
|
||||
|
||||
#include "SDL.h"
|
||||
#include <mutex>
|
||||
|
||||
int InitializeSdlAudio_nid_no_patch() {
|
||||
static std::mutex initializationMutex;
|
||||
std::lock_guard lock(initializationMutex);
|
||||
return SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
#define SDL_MAIN_HANDLED
|
||||
#include "prx/libSceAudioOut/include/AudioOutSdl.hpp"
|
||||
#include "SDL.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
namespace {
|
||||
std::mutex stateMutex;
|
||||
std::condition_variable stateChanged;
|
||||
int calls = 0;
|
||||
int active = 0;
|
||||
int peak = 0;
|
||||
bool secondEntered = false;
|
||||
bool secondReady = false;
|
||||
bool validFlags = true;
|
||||
}
|
||||
|
||||
extern "C" int SDLCALL SDL_InitSubSystem(Uint32 flags) {
|
||||
std::unique_lock lock(stateMutex);
|
||||
validFlags = validFlags && flags == SDL_INIT_AUDIO;
|
||||
const int call = ++calls;
|
||||
++active;
|
||||
if (active > peak) peak = active;
|
||||
stateChanged.notify_all();
|
||||
if (call == 1) {
|
||||
stateChanged.wait(lock, [] { return secondReady; });
|
||||
stateChanged.wait_for(lock, std::chrono::milliseconds(500), [] { return secondEntered; });
|
||||
} else {
|
||||
secondEntered = true;
|
||||
stateChanged.notify_all();
|
||||
}
|
||||
--active;
|
||||
return call == 1 ? -1 : 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int firstResult = 99;
|
||||
int secondResult = 99;
|
||||
std::thread first([&] { firstResult = InitializeSdlAudio_nid_no_patch(); });
|
||||
{
|
||||
std::unique_lock lock(stateMutex);
|
||||
stateChanged.wait(lock, [] { return calls == 1; });
|
||||
}
|
||||
std::thread second([&] {
|
||||
{
|
||||
std::lock_guard lock(stateMutex);
|
||||
secondReady = true;
|
||||
stateChanged.notify_all();
|
||||
}
|
||||
secondResult = InitializeSdlAudio_nid_no_patch();
|
||||
});
|
||||
first.join();
|
||||
second.join();
|
||||
if (peak != 1 || calls != 2 || active != 0 || !validFlags || firstResult != -1 || secondResult != 0) {
|
||||
std::fprintf(stderr, "audio initialization overlap or return-value mismatch: peak=%d calls=%d results=%d,%d\n", peak, calls, firstResult, secondResult);
|
||||
return 1;
|
||||
}
|
||||
std::puts("Serialized audio initialization: PASS");
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue