#include "prx/libSceAudio3d/include/Audio3d.hpp" #include "SceTypes.hpp" #include #include #include #include #include #include #include static_assert(sizeof(Audio3dOpenParameters) == 0x28); static_assert(offsetof(Audio3dOpenParameters, num_beds) == 0x20); static void Require(bool value, const char* message) { if (value) return; std::fprintf(stderr, "%s\n", message); std::abort(); } static void CheckDefaults(const void* memory) { Audio3dOpenParameters parameters{}; std::memcpy(¶meters, memory, 0x20); Require(parameters.size_this == 0x20, "default parameter size must be 32 bytes"); Require(parameters.granularity == 256, "incorrect default granularity"); Require(parameters.rate == 0, "incorrect default rate"); Require(parameters.max_objects == 512, "incorrect default object limit"); Require(parameters.queue_depth == 2, "incorrect default queue depth"); Require(parameters.buffer_mode == 2, "incorrect default buffer mode"); Require(parameters.pad == 0, "reserved parameter bytes must be cleared"); } static void CheckInvalidDestination() { bool threw = false; try { sceAudio3dGetDefaultOpenParameters(nullptr); } catch (const std::invalid_argument&) { threw = true; } Require(threw, "null destination must throw invalid_argument"); } static void CheckShortBuffer() { struct GuardedParameters { std::array before; alignas(Audio3dOpenParameters) std::array parameters; std::array after; } guarded; static_assert(offsetof(GuardedParameters, after) == offsetof(GuardedParameters, parameters) + 0x20); std::memset(&guarded, 0xa5, sizeof(guarded)); for (std::uint64_t size : std::array{0, 0x10, 0x18, 0x20, 0x28, UINT64_MAX}) { guarded.parameters.fill(0xa5); std::memcpy(guarded.parameters.data(), &size, sizeof(size)); sceAudio3dGetDefaultOpenParameters(reinterpret_cast(guarded.parameters.data())); CheckDefaults(guarded.parameters.data()); for (unsigned char value : guarded.before) Require(value == 0xa5, "parameter underrun"); for (unsigned char value : guarded.after) Require(value == 0xa5, "parameter overrun"); } } static void CheckExtendedBuffer() { Audio3dOpenParameters parameters; std::memset(¶meters, 0xa5, sizeof(parameters)); for (unsigned char pattern : {0xa5, 0x5a}) { std::memset(¶meters, pattern, 0x20); sceAudio3dGetDefaultOpenParameters(¶meters); CheckDefaults(¶meters); const auto* bytes = reinterpret_cast(¶meters); for (std::size_t i = 0x20; i < sizeof(parameters); ++i) { Require(bytes[i] == 0xa5, "extended parameter bytes must remain unchanged"); } } } static void CheckErrorStrings() { constexpr const char* messages[]{ "port does not exist", "object does not exist", "invalid parameter", "out of memory", "out of resources", "not ready" }; for (std::uint32_t index = 0; index < std::size(messages); ++index) { errno = 7; const char* result = sceAudio3dStrError(std::bit_cast(0x80ea0002u + index)); Require(result && std::strcmp(result, messages[index]) == 0, "incorrect Audio3d error description"); Require(errno == 7, "error description lookup must preserve errno"); Require(std::strcmp(sceAudio3dStrError(0), "(unknown)") == 0 && std::strcmp(result, messages[index]) == 0, "error descriptions must remain valid after another lookup"); } for (const auto code : std::array{0, 1, 0xffffffffu, 0x80000000u, 0x7fffffffu, 0x80e9ffffu, 0x80ea0000u, 0x80ea0001u, 0x80ea0008u, 0x80ea0009u, 0x80eb0002u}) { errno = 7; const char* result = sceAudio3dStrError(std::bit_cast(code)); Require(result && std::strcmp(result, "(unknown)") == 0 && errno == 7, "unrecognized codes must return the native fallback without changing errno"); } } int main() { CheckErrorStrings(); CheckInvalidDestination(); CheckShortBuffer(); CheckExtendedBuffer(); Require(sceAudio3dTerminate() == static_cast(0x80EA0007), "terminate before initialize reports not ready"); Require(sceAudio3dInitialize(1) == static_cast(0x80EA0004), "positive reserved parameter rejected in sceAudio3dInitialize"); Require(sceAudio3dInitialize(42) == static_cast(0x80EA0004), "positive reserved parameter rejected in sceAudio3dInitialize"); Require(sceAudio3dInitialize(-1) == static_cast(0x80EA0004), "non-zero reserved parameter rejected in sceAudio3dInitialize"); }