Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions core/libs/prx/libSceAudioOut/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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/AudioOutShutdown.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioOut2Context.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioOut2PadMix.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioOut2Port.cpp
Expand Down Expand Up @@ -135,4 +136,17 @@ if(BUILD_TESTING)
set_tests_properties(audio_out2_timing PROPERTIES RUN_SERIAL TRUE ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAudioOut>")
endif()
add_test_executable(audio_out_shutdown_tests tests/AudioOutShutdown.cpp)
target_include_directories(audio_out_shutdown_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(audio_out_shutdown_tests PRIVATE libSceAudioOut libkernel libc)
configure_windows_unwind(audio_out_shutdown_tests)
add_test(NAME audio_out2_shutdown COMMAND audio_out_shutdown_tests --audio-out2)
add_test(NAME audio_out2_waiting_push_shutdown COMMAND audio_out_shutdown_tests --audio-out2-waiting-push)
add_test(NAME audio_out2_advance_shutdown COMMAND audio_out_shutdown_tests --audio-out2-advance)
add_test(NAME audio_out_shutdown COMMAND audio_out_shutdown_tests --audio-out)
set_tests_properties(audio_out2_shutdown audio_out2_waiting_push_shutdown audio_out2_advance_shutdown audio_out_shutdown PROPERTIES TIMEOUT 10)
if(WIN32)
set_tests_properties(audio_out2_shutdown audio_out2_waiting_push_shutdown audio_out2_advance_shutdown audio_out_shutdown PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAudioOut>")
endif()
endif()
12 changes: 10 additions & 2 deletions core/libs/prx/libSceAudioOut/src/AudioOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
#include "SDL.h"
#include "SceTypes.hpp"
#include "prx/libc/include/PreciseWait.hpp"
#include "prx/libc/include/Shutdown.hpp"
#include "prx/libkernel/Time/include/Time.hpp"
#include "prx/libSceAudioOut/include/AudioOutSdl.hpp"
#include "AudioOutShutdown.hpp"

static constexpr int PORT_TYPE_MAIN = 0;
static constexpr int PORT_TYPE_BGM = 1;
Expand Down Expand Up @@ -383,7 +385,8 @@ int APS5_VABI sceAudioOutClose(int handle) {
return 0;
}

int APS5_VABI sceAudioOutOutput(int handle, const void* ptr) {
int APS5_VABI sceAudioOutOutput(int handle, const void* ptr) try {
const AudioOutCall call;
std::lock_guard<std::mutex> outputLock(g_outputMutex);
std::unique_lock<std::mutex> lock(g_mutex);
Port* port = getPort(handle);
Expand All @@ -398,13 +401,16 @@ int APS5_VABI sceAudioOutOutput(int handle, const void* ptr) {
}
if (ptr != nullptr) port->lastDataOutputTime = sceKernelGetProcessTime();
return static_cast<int>(port->samplesNum);
} catch (const ProcessShutdown&) {
LibcAwaitExit_nid_postfix();
}

int APS5_VABI sceAudioOutOutputs(AudioOutOutputParam* param, std::uint32_t num) {
int APS5_VABI sceAudioOutOutputs(AudioOutOutputParam* param, std::uint32_t num) try {
if (param == nullptr || num == 0) {
return -2144993276;
}

const AudioOutCall call;
std::lock_guard<std::mutex> outputLock(g_outputMutex);
std::unique_lock<std::mutex> lock(g_mutex);

Expand All @@ -430,6 +436,8 @@ int APS5_VABI sceAudioOutOutputs(AudioOutOutputParam* param, std::uint32_t num)
}

return static_cast<int>(first.samplesNum);
} catch (const ProcessShutdown&) {
LibcAwaitExit_nid_postfix();
}

int APS5_VABI sceAudioOutSetVolume(int handle, std::uint32_t flag, int* vol) {
Expand Down
19 changes: 15 additions & 4 deletions core/libs/prx/libSceAudioOut/src/AudioOut2Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libc/include/PreciseWait.hpp"
#include "prx/libc/include/Shutdown.hpp"
#include "AudioOut2Internal.hpp"
#include "AudioOutShutdown.hpp"
#include "prx/libSceAudioOut/include/AudioOutSdl.hpp"
#include "prx/libScePad/include/PadState.hpp"

Expand Down Expand Up @@ -256,7 +258,8 @@ static void TraceSummary(AudioOut2Context& context, Clock::time_point now) {

extern "C" {

int APS5_VABI sceAudioOut2ContextAdvance(AudioOut2ContextHandle ctx) {
int APS5_VABI sceAudioOut2ContextAdvance(AudioOut2ContextHandle ctx) try {
const AudioOutCall call;
auto* context = FromHandle(ctx);
if (!context) return SCE_AUDIO_OUT2_ERROR_INVALID_HANDLE;
std::lock_guard lock(context->lock);
Expand All @@ -278,6 +281,8 @@ int APS5_VABI sceAudioOut2ContextAdvance(AudioOut2ContextHandle ctx) {
context->summaryAdvances++;
if (context->advances <= CALL_TRACE_FULL) AUDIOOUT2_TRACE("t=%.3f Advance ctx %p (pushes so far %llu)\n", AudioOut2TraceSeconds(), static_cast<void*>(context), static_cast<unsigned long long>(context->pushes));
return 0;
} catch (const ProcessShutdown&) {
LibcAwaitExit_nid_postfix();
}

int APS5_VABI sceAudioOut2ContextCreate(const AudioOut2ContextParam* params, void* buffer, size_t buffer_size, AudioOut2ContextHandle* ctx) {
Expand All @@ -295,7 +300,8 @@ int APS5_VABI sceAudioOut2ContextCreate(const AudioOut2ContextParam* params, voi
return 0;
}

int APS5_VABI sceAudioOut2ContextDestroy(AudioOut2ContextHandle ctx) {
int APS5_VABI sceAudioOut2ContextDestroy(AudioOut2ContextHandle ctx) try {
const AudioOutCall call;
auto* context = FromHandle(ctx);
if (!context) return SCE_AUDIO_OUT2_ERROR_INVALID_HANDLE;
AUDIOOUT2_TRACE("t=%.3f ContextDestroy ctx %p after %llu pushes\n", AudioOut2TraceSeconds(), static_cast<void*>(context), static_cast<unsigned long long>(context->pushes));
Expand All @@ -309,6 +315,8 @@ int APS5_VABI sceAudioOut2ContextDestroy(AudioOut2ContextHandle ctx) {
AudioOut2ReleasePorts(*context);
delete context;
return 0;
} catch (const ProcessShutdown&) {
LibcAwaitExit_nid_postfix();
}

int APS5_VABI sceAudioOut2ContextGetQueueLevel(AudioOut2ContextHandle ctx, uint32_t* queue_level, uint32_t* available_queue) {
Expand All @@ -324,7 +332,8 @@ int APS5_VABI sceAudioOut2ContextGetQueueLevel(AudioOut2ContextHandle ctx, uint3
return 0;
}

int APS5_VABI sceAudioOut2ContextPush(AudioOut2ContextHandle ctx, uint32_t blocking) {
int APS5_VABI sceAudioOut2ContextPush(AudioOut2ContextHandle ctx, uint32_t blocking) try {
const AudioOutCall call;
auto* context = FromHandle(ctx);
if (!context) return SCE_AUDIO_OUT2_ERROR_INVALID_HANDLE;
std::unique_lock lock(context->lock);
Expand All @@ -344,7 +353,7 @@ int APS5_VABI sceAudioOut2ContextPush(AudioOut2ContextHandle ctx, uint32_t block
}
if (context->advancedMode && context->advancedGrains.empty()) {
if (!blocking) throw std::runtime_error("AudioOut2: a non-blocking push without a rendered grain is not implemented");
context->grainReady.wait(lock, [&] { return !context->advancedGrains.empty(); });
if (!context->grainReady.wait(lock, LibcShutdownToken_nid_postfix(), [&] { return !context->advancedGrains.empty(); })) throw ProcessShutdown{};
now = Clock::now();
Drain(*context, now);
}
Expand Down Expand Up @@ -390,6 +399,8 @@ int APS5_VABI sceAudioOut2ContextPush(AudioOut2ContextHandle ctx, uint32_t block
}
TraceSummary(*context, now);
return 0;
} catch (const ProcessShutdown&) {
LibcAwaitExit_nid_postfix();
}

int APS5_VABI sceAudioOut2ContextQueryMemory(const AudioOut2ContextParam* params, size_t* memory_size) {
Expand Down
3 changes: 2 additions & 1 deletion core/libs/prx/libSceAudioOut/src/AudioOut2Internal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <cstdio>
#include <deque>
#include <mutex>
#include <stop_token>
#include <utility>
#include <vector>

Expand Down Expand Up @@ -91,7 +92,7 @@ struct AudioOut2Context {
std::deque<float> output;
bool priming = true;
bool advancedMode = false;
std::condition_variable grainReady;
std::condition_variable_any grainReady;
std::deque<AudioOut2Grain> advancedGrains;
std::deque<AudioOut2Grain> pendingGrains;
std::deque<std::chrono::steady_clock::time_point> pendingSince;
Expand Down
22 changes: 18 additions & 4 deletions core/libs/prx/libSceAudioOut/src/AudioOut2Port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#include <vector>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libc/include/Shutdown.hpp"
#include "AudioOut2Internal.hpp"
#include "AudioOut2PadMix.hpp"
#include "AudioOutShutdown.hpp"

static constexpr std::uint16_t OUTPUT_MAIN = 1;
static constexpr std::int16_t VOLUME_MAX = 127;
Expand Down Expand Up @@ -178,7 +180,8 @@ static void TraceAttribute(AudioOut2PortHandle handle, const AudioOut2Port& port

extern "C" {

int APS5_VABI sceAudioOut2PortCreate(AudioOut2ContextHandle ctx, const AudioOut2PortParam* params, AudioOut2PortHandle* port) {
int APS5_VABI sceAudioOut2PortCreate(AudioOut2ContextHandle ctx, const AudioOut2PortParam* params, AudioOut2PortHandle* port) try {
const AudioOutCall call;
if (!ctx) return SCE_AUDIO_OUT2_ERROR_INVALID_HANDLE;
if (!params || !port) return SCE_AUDIO_OUT2_ERROR_INVALID_ARGUMENT;
const auto channels = (params->data_format >> FORMAT_CHANNELS_SHIFT) & FORMAT_CHANNELS_MASK;
Expand Down Expand Up @@ -219,18 +222,24 @@ int APS5_VABI sceAudioOut2PortCreate(AudioOut2ContextHandle ctx, const AudioOut2
AudioOut2TraceSeconds(), static_cast<unsigned long long>(ctx), static_cast<unsigned long long>(*port), params->port_type, params->data_format,
entry.channels, params->sampling_freq, params->flags, static_cast<unsigned long long>(params->user_handle));
return 0;
} catch (const ProcessShutdown&) {
LibcAwaitExit_nid_postfix();
}

int APS5_VABI sceAudioOut2PortDestroy(AudioOut2PortHandle port) {
int APS5_VABI sceAudioOut2PortDestroy(AudioOut2PortHandle port) try {
const AudioOutCall call;
std::lock_guard lock(g_portsLock);
auto* entry = FromHandle(port);
if (!entry) return SCE_AUDIO_OUT2_ERROR_INVALID_HANDLE;
AUDIOOUT2_TRACE("t=%.3f PortDestroy port %llu (data sets %llu)\n", AudioOut2TraceSeconds(), static_cast<unsigned long long>(port), static_cast<unsigned long long>(entry->dataSets));
*entry = AudioOut2Port{};
return 0;
} catch (const ProcessShutdown&) {
LibcAwaitExit_nid_postfix();
}

int APS5_VABI sceAudioOut2PortGetState(AudioOut2PortHandle port, AudioOut2PortState* state) {
int APS5_VABI sceAudioOut2PortGetState(AudioOut2PortHandle port, AudioOut2PortState* state) try {
const AudioOutCall call;
std::lock_guard lock(g_portsLock);
const auto* entry = FromHandle(port);
if (!entry) return SCE_AUDIO_OUT2_ERROR_INVALID_HANDLE;
Expand All @@ -240,9 +249,12 @@ int APS5_VABI sceAudioOut2PortGetState(AudioOut2PortHandle port, AudioOut2PortSt
state->num_channels = static_cast<std::uint8_t>(entry->channels);
state->volume = VOLUME_MAX;
return 0;
} catch (const ProcessShutdown&) {
LibcAwaitExit_nid_postfix();
}

int APS5_VABI sceAudioOut2PortSetAttributes(AudioOut2PortHandle port, const AudioOut2Attribute* attributes, uint32_t num) {
int APS5_VABI sceAudioOut2PortSetAttributes(AudioOut2PortHandle port, const AudioOut2Attribute* attributes, uint32_t num) try {
const AudioOutCall call;
std::lock_guard lock(g_portsLock);
auto* entry = FromHandle(port);
if (!entry) return SCE_AUDIO_OUT2_ERROR_INVALID_HANDLE;
Expand All @@ -268,6 +280,8 @@ int APS5_VABI sceAudioOut2PortSetAttributes(AudioOut2PortHandle port, const Audi
if (traces < ATTRIBUTE_TRACE_FULL || traces % ATTRIBUTE_TRACE_EVERY == 0) TraceAttribute(port, *entry, attribute, verdict);
}
return 0;
} catch (const ProcessShutdown&) {
LibcAwaitExit_nid_postfix();
}

}
34 changes: 34 additions & 0 deletions core/libs/prx/libSceAudioOut/src/AudioOutShutdown.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <atomic>
#include <cstdint>
#include "prx/libc/include/Shutdown.hpp"
#include "AudioOutShutdown.hpp"

namespace {

std::atomic<std::uint32_t> inside{0};
std::atomic<bool> stopping{false};

void Leave() {
if (inside.fetch_sub(1) == 1) inside.notify_all();
}

void Stop() {
stopping.store(true);
for (auto count = inside.load(); count != 0; count = inside.load()) inside.wait(count);
}

}

AudioOutCall::AudioOutCall() {
static const bool registered = (LibcRegisterShutdown_nid_postfix(Stop), true);
static_cast<void>(registered);
inside.fetch_add(1);
if (stopping.load() || LibcShutdownToken_nid_postfix().stop_requested()) {
Leave();
throw ProcessShutdown{};
}
}

AudioOutCall::~AudioOutCall() {
Leave();
}
12 changes: 12 additions & 0 deletions core/libs/prx/libSceAudioOut/src/AudioOutShutdown.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef CORE_LIBS_PRX_LIBSCEAUDIOOUT_SRC_AUDIOOUTSHUTDOWN_HPP
#define CORE_LIBS_PRX_LIBSCEAUDIOOUT_SRC_AUDIOOUTSHUTDOWN_HPP

class AudioOutCall final {
public:
AudioOutCall();
~AudioOutCall();
AudioOutCall(const AudioOutCall&) = delete;
AudioOutCall& operator=(const AudioOutCall&) = delete;
};

#endif
Loading
Loading