mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
libSceCesCs goes to 17 of 17: three-byte EUC-JP JIS X 0212 (0x8F) characters convert through a table read from the Unicode consortium's JIS0212.TXT, both directions, so sceCesEucJpToUcs2, the MbcsStrTo* and *Get*Len forms and the context conversions accept them, and a character with cells in both JIS X 0208 and JIS X 0212 still encodes to the two-byte form. sceCesRefersUcsProfileCp1250 returns a profile with the Windows-1250 table of Microsoft's bestfit1250.txt, accepted by the SBC and context conversions. The AudioOut HDMI bitstream Sys family follows the Ex ports: SysOpen opens a port only for mode 5, the TrueHD MAT route EVO-PLAYER-PS5 reads from the firmware 12.70 mode tables, paced at 192 kHz with no host device; SysConfigureOutput accepts the observed HDMI MAT switch; SysClose closes a Sys port. sceAudioOut2MasteringGetState fills the states by states id with the descriptors KytyPS5 declares, SetParam answers a null parameter with the mastering invalid-API-parameter error, Set3DLatency follows KytyPS5's output validation (0x80268001 above 2, any user), SetSystemDebugState records the debug state id, and GetSpeakerArrayCoefficients returns the front pair KytyPS5 and prosper both return. sceAudioInOpen accepts param 0x10 as float mono like KytyPS5; HqOpen answers a longer grain or a lower rate with the invalid-size and invalid-frequency errors; AsyncOpen also accepts the 384-sample grain SharpProspero documents. sceGameUpdateGetAddcontLatestVersion answers a null entitlement label with 0x80412803, as prosper does.
170 lines
8.0 KiB
C++
170 lines
8.0 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <random>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
extern "C" {
|
|
int APS5_VABI sceAudioInInit();
|
|
int APS5_VABI sceAudioInOpen(int, std::uint32_t, std::uint32_t, std::uint32_t, std::uint32_t, std::uint32_t);
|
|
int APS5_VABI sceAudioInHqOpen(int, std::uint32_t, std::uint32_t, std::uint32_t, std::uint32_t, std::uint32_t);
|
|
int APS5_VABI sceAudioInAsyncOpen(int, std::uint32_t, std::uint32_t, std::uint32_t, std::uint32_t, std::uint32_t);
|
|
int32_t APS5_VABI sceAudioInIsPadEmbeddedMic(int32_t);
|
|
int APS5_VABI sceAudioInInput(int, void*);
|
|
int APS5_VABI sceAudioInGetSilentState(int);
|
|
int APS5_VABI sceAudioInClose(int);
|
|
}
|
|
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
template <typename TCall>
|
|
static bool ReportsNotImplemented(const char* name, TCall call) {
|
|
try {
|
|
call();
|
|
} catch (const std::runtime_error& error) {
|
|
return std::string(error.what()) == std::string(name) + " not implemented";
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void SetEnvironment(const char* name, const std::string& value) {
|
|
#ifdef _WIN32
|
|
_putenv_s(name, value.c_str());
|
|
#else
|
|
setenv(name, value.c_str(), 1);
|
|
#endif
|
|
}
|
|
|
|
namespace {
|
|
|
|
constexpr int user = 0x10000000;
|
|
|
|
void TestValidation() {
|
|
constexpr int invalidSize = static_cast<int>(0x80260102);
|
|
constexpr int invalidFreq = static_cast<int>(0x80260103);
|
|
constexpr int invalidType = static_cast<int>(0x80260104);
|
|
constexpr int invalidParam = static_cast<int>(0x80260106);
|
|
Require(sceAudioInOpen(user, 2, 0, 256, 48000, 2) == invalidType);
|
|
Require(sceAudioInOpen(user, 0, 1, 256, 48000, 2) == invalidParam);
|
|
Require(sceAudioInOpen(user, 0, 0, 512, 48000, 2) == invalidSize);
|
|
Require(sceAudioInOpen(user, 0, 0, 256, 44100, 2) == invalidFreq);
|
|
Require(sceAudioInOpen(user, 0, 0, 256, 48000, 3) == invalidParam);
|
|
Require(sceAudioInOpen(user, 0, 0, 256, 48000, 0) == invalidParam);
|
|
Require(sceAudioInHqOpen(user, 2, 0, 128, 48000, 2) == invalidType);
|
|
Require(sceAudioInHqOpen(user, 0, 1, 128, 48000, 2) == invalidParam);
|
|
Require(sceAudioInHqOpen(user, 0, 0, 512, 48000, 2) == invalidSize);
|
|
Require(sceAudioInHqOpen(user, 0, 0, 128, 44100, 2) == invalidFreq);
|
|
Require(sceAudioInHqOpen(user, 0, 0, 128, 48000, 3) == invalidParam);
|
|
Require(sceAudioInAsyncOpen(user, 2, 0, 128, 48000, 2) == invalidType);
|
|
Require(sceAudioInAsyncOpen(user, 0, 1, 128, 48000, 2) == invalidParam);
|
|
Require(sceAudioInAsyncOpen(user, 0, 0, 385, 48000, 2) == invalidSize);
|
|
Require(sceAudioInAsyncOpen(user, 0, 0, 200, 48000, 2) == invalidSize);
|
|
Require(sceAudioInAsyncOpen(user, 0, 0, 256, 44100, 2) == invalidFreq);
|
|
Require(sceAudioInAsyncOpen(user, 0, 0, 256, 48000, 0) == invalidParam);
|
|
Require(sceAudioInHqOpen(user, 0, 0, 256, 48000, 2) == invalidSize);
|
|
Require(sceAudioInHqOpen(user, 0, 0, 128, 16000, 2) == invalidFreq);
|
|
int port = sceAudioInAsyncOpen(user, 0, 0, 384, 48000, 2);
|
|
Require(port > 0 && sceAudioInClose(port) == 0);
|
|
port = sceAudioInOpen(user, 0, 0, 256, 48000, 0x10);
|
|
Require(port > 0 && sceAudioInClose(port) == 0);
|
|
port = sceAudioInHqOpen(user, 0, 0, 128, 48000, 0x10);
|
|
Require(port > 0 && sceAudioInClose(port) == 0);
|
|
port = sceAudioInAsyncOpen(user, 0, 0, 384, 48000, 0x10);
|
|
Require(port > 0 && sceAudioInClose(port) == 0);
|
|
Require(ReportsNotImplemented("sceAudioInIsPadEmbeddedMic", [] { sceAudioInIsPadEmbeddedMic(1); }));
|
|
}
|
|
|
|
void TestCapture() {
|
|
const auto path = std::filesystem::temp_directory_path() / ("anyps5_audio_in_capture-" + std::to_string(std::random_device{}()) + ".raw");
|
|
std::vector<std::int16_t> recorded(256 * 2 * 4);
|
|
for (std::size_t i = 0; i < recorded.size(); ++i) recorded[i] = static_cast<std::int16_t>(i * 7 - 3000);
|
|
std::ofstream(path, std::ios::binary).write(reinterpret_cast<const char*>(recorded.data()), static_cast<std::streamsize>(recorded.size() * 2));
|
|
SetEnvironment("SDL_AUDIODRIVER", "disk");
|
|
SetEnvironment("SDL_DISKAUDIOFILEIN", path.string());
|
|
|
|
TestValidation();
|
|
const int handle = sceAudioInOpen(user, 0, 0, 256, 48000, 2);
|
|
Require(handle > 0 && sceAudioInGetSilentState(handle) == 0);
|
|
std::vector<std::int16_t> block(256 * 2 + 1, 0x5555);
|
|
std::vector<std::int16_t> captured;
|
|
for (int i = 0; i < 4; ++i) {
|
|
Require(sceAudioInInput(handle, block.data()) == 256);
|
|
captured.insert(captured.end(), block.begin(), block.end() - 1);
|
|
Require(block.back() == 0x5555);
|
|
}
|
|
Require(captured == recorded);
|
|
Require(sceAudioInInput(handle, block.data()) == 256);
|
|
for (std::size_t i = 0; i < 256 * 2; ++i) Require(block[i] == 0);
|
|
Require(sceAudioInClose(handle) == 0);
|
|
const int async = sceAudioInAsyncOpen(user, 0, 0, 256, 48000, 2);
|
|
Require(async == handle && sceAudioInGetSilentState(async) == 0);
|
|
Require(sceAudioInInput(async, block.data()) == 256);
|
|
Require(std::equal(block.begin(), block.end() - 1, recorded.begin()) && block.back() == 0x5555);
|
|
Require(sceAudioInClose(async) == 0);
|
|
std::filesystem::remove(path);
|
|
}
|
|
|
|
void TestNoDevice() {
|
|
constexpr int invalidHandle = static_cast<int>(0x80260101);
|
|
constexpr int portFull = static_cast<int>(0x80260107);
|
|
SetEnvironment("SDL_AUDIODRIVER", "none");
|
|
|
|
TestValidation();
|
|
const int handle = sceAudioInOpen(user, 0, 0, 256, 16000, 0x12);
|
|
Require(handle > 0 && sceAudioInGetSilentState(handle) == 1);
|
|
Require(sceAudioInGetSilentState(handle + 1) == invalidHandle);
|
|
Require(sceAudioInInput(handle + 1, nullptr) == invalidHandle);
|
|
std::vector<std::uint8_t> buffer(256 * 8 + 1, 0xCC);
|
|
const auto start = std::chrono::steady_clock::now();
|
|
for (int block = 0; block < 5; ++block) Require(sceAudioInInput(handle, buffer.data()) == 256);
|
|
const auto elapsed = std::chrono::steady_clock::now() - start;
|
|
Require(elapsed >= std::chrono::milliseconds(4 * 16) && elapsed < std::chrono::milliseconds(1000));
|
|
for (std::size_t i = 0; i < 256 * 8; ++i) Require(buffer[i] == 0);
|
|
Require(buffer[256 * 8] == 0xCC);
|
|
Require(sceAudioInInput(handle, nullptr) == 0);
|
|
const int hq = sceAudioInHqOpen(user, 0, 0, 128, 48000, 2);
|
|
const int async = sceAudioInAsyncOpen(user, 1, 0, 256, 16000, 0x11);
|
|
Require(hq > 0 && async > 0 && hq != handle && async != handle && hq != async);
|
|
Require(sceAudioInGetSilentState(hq) == 1 && sceAudioInGetSilentState(async) == 1);
|
|
std::fill(buffer.begin(), buffer.end(), 0xCC);
|
|
Require(sceAudioInInput(hq, buffer.data()) == 128);
|
|
for (std::size_t i = 0; i < 128 * 4; ++i) Require(buffer[i] == 0);
|
|
Require(buffer[128 * 4] == 0xCC);
|
|
std::fill(buffer.begin(), buffer.end(), 0xCC);
|
|
Require(sceAudioInInput(async, buffer.data()) == 256);
|
|
for (std::size_t i = 0; i < 256 * 4; ++i) Require(buffer[i] == 0);
|
|
Require(buffer[256 * 4] == 0xCC);
|
|
Require(sceAudioInInput(async, nullptr) == 0);
|
|
for (int port = 3; port < 8; ++port) Require(sceAudioInOpen(user, 1, 0, 128, 48000, 1) > 0);
|
|
Require(sceAudioInOpen(user, 1, 0, 128, 48000, 1) == portFull);
|
|
Require(sceAudioInHqOpen(user, 1, 0, 128, 48000, 1) == portFull);
|
|
Require(sceAudioInAsyncOpen(user, 1, 0, 128, 48000, 1) == portFull);
|
|
Require(sceAudioInClose(hq) == 0);
|
|
Require(sceAudioInClose(hq) == invalidHandle);
|
|
Require(sceAudioInGetSilentState(hq) == invalidHandle);
|
|
Require(sceAudioInAsyncOpen(user, 0, 0, 128, 48000, 2) == hq);
|
|
Require(sceAudioInClose(async) == 0);
|
|
Require(sceAudioInInput(async, buffer.data()) == invalidHandle);
|
|
Require(sceAudioInHqOpen(user, 1, 0, 128, 48000, 0x12) == async);
|
|
Require(sceAudioInClose(handle) == 0);
|
|
Require(sceAudioInClose(handle) == invalidHandle);
|
|
Require(sceAudioInInput(handle, buffer.data()) == invalidHandle);
|
|
Require(sceAudioInOpen(user, 1, 0, 128, 48000, 0x11) == handle);
|
|
}
|
|
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
Require(argc == 2);
|
|
Require(sceAudioInInit() == 0);
|
|
if (std::strcmp(argv[1], "capture") == 0) TestCapture();
|
|
else TestNoDevice();
|
|
}
|