diff --git a/core/libs/prx/libSceTextToSpeech2/CMakeLists.txt b/core/libs/prx/libSceTextToSpeech2/CMakeLists.txt new file mode 100644 index 000000000..cb54c1384 --- /dev/null +++ b/core/libs/prx/libSceTextToSpeech2/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(libSceTextToSpeech2 SHARED EXCLUDE_FROM_ALL Export.cpp) +target_include_directories(libSceTextToSpeech2 PRIVATE ${LIBS_INCLUDE_DIR}) +configure_windows_unwind(libSceTextToSpeech2) + +if(BUILD_TESTING) + add_test_executable(guest_text_to_speech2_tests ${LIBS_INCLUDE_DIR}/tests/GuestTextToSpeech2.cpp) + target_include_directories(guest_text_to_speech2_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_text_to_speech2_tests PRIVATE libSceTextToSpeech2 libc) + configure_windows_unwind(guest_text_to_speech2_tests) + add_test(NAME guest_text_to_speech2 COMMAND guest_text_to_speech2_tests) + if(WIN32) + set_tests_properties(guest_text_to_speech2 PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() +endif() diff --git a/core/libs/prx/libSceTextToSpeech2/Export.cpp b/core/libs/prx/libSceTextToSpeech2/Export.cpp index 2b94ca2f8..8e344ce25 100644 --- a/core/libs/prx/libSceTextToSpeech2/Export.cpp +++ b/core/libs/prx/libSceTextToSpeech2/Export.cpp @@ -3,6 +3,12 @@ #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +namespace { + +constexpr std::int32_t SCE_KERNEL_ERROR_EOPNOTSUPP = static_cast(0x8002002D); + +} + extern "C" { int APS5_VABI sceTextToSpeech2GetSystemStatus() { @@ -10,4 +16,39 @@ int APS5_VABI sceTextToSpeech2GetSystemStatus() { return 0; } +std::int32_t APS5_VABI sceTextToSpeech2Initialize(const void* param) { + (void)param; + return SCE_KERNEL_ERROR_EOPNOTSUPP; +} + +int APS5_VABI sceTextToSpeech2Cancel() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceTextToSpeech2Close() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceTextToSpeech2GetSpeechStatus() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceTextToSpeech2Open() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceTextToSpeech2Speak() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceTextToSpeech2Terminate() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + } diff --git a/core/libs/tests/GuestTextToSpeech2.cpp b/core/libs/tests/GuestTextToSpeech2.cpp new file mode 100644 index 000000000..f3ee2c80e --- /dev/null +++ b/core/libs/tests/GuestTextToSpeech2.cpp @@ -0,0 +1,31 @@ +#include "prx/libc/include/general/VabiMacros.hpp" + +#include +#include +#include +#include + +extern "C" { +std::int32_t APS5_VABI sceTextToSpeech2Initialize(const void* param); +int APS5_VABI sceTextToSpeech2Open(); +} + +int main() { + const std::uint32_t param[12]{0x2000000, 0x26c}; + if (sceTextToSpeech2Initialize(param) != static_cast(0x8002002D)) { + std::puts("TextToSpeech2: initialization did not report the unsupported operation"); + std::abort(); + } + bool threw = false; + try { + sceTextToSpeech2Open(); + } catch (const std::runtime_error&) { + threw = true; + } + if (!threw) { + std::puts("TextToSpeech2: open after failed initialization did not throw"); + std::abort(); + } + std::puts("TextToSpeech2 tests passed"); + return 0; +} diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index 484eda8ec..0efd38423 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -26,6 +26,7 @@ Throughout the project, every function at every stage either **does exactly what - [sceVideoOutOpen](../../core/libs/prx/libSceVideoOut/src/Output.cpp) validates the priority and CPU affinity that the open param requests for the VideoOut service thread but does not apply them: the port's present and vblank threads are host threads, and guest priorities and affinities do not reach host scheduling - Without `VK_KHR_fragment_shader_barycentric` the shader recompiler [does not load the barycentric VGPRs](../../core/shader/recompiler/Translation/src/InstructionTranslator.cpp): [`v_interp_p1_f32` is dropped and `v_interp_p2_f32` reads the attribute Vulkan interpolated](../../core/shader/recompiler/Translation/src/AttributeInstructions.cpp), so pixel shaders that use the barycentrics for anything other than `v_interp` get wrong values. - [libSceAudio3d](../../core/libs/prx/libSceAudio3d/Export.cpp) - the port produces no sound: objects can be reserved but the library has no bed exports or `sceAudio3dObjectSetAttributes` to give them audio, so `sceAudio3dPortPush` only paces the queue at `granularity` samples per frame at 48 kHz. `sceAudio3dPortSetAttribute` accepts the late reverb level and the downmix spread attributes and ignores them +- [libSceTextToSpeech2](../../core/libs/prx/libSceTextToSpeech2/Export.cpp) has no speech engine: `sceTextToSpeech2Initialize` fails and the other exports throw. PPSA01317 skips its narration set-up when initialization fails - [libSceAvPlayer](../../core/libs/prx/libSceAvPlayer/Export.cpp): `sceAvPlayerSetLogCallback` accepts a callback that is never called, as the player produces no log messages, and `sceAvPlayerSetAvailableBandwidth` has no effect, as it governs HLS sources, which `sceAvPlayerAddSource` does not implement. - [libSceHttp2](../../core/libs/prx/libSceHttp2/Export.cpp) - no request reaches the network, so `sceHttp2SetMinSslVersion` has no TLS connection to restrict and returns success for any `id`, like `sceHttp2SslEnableOption` (prosper returns the invalid-id error for an unknown one) - [libSceNpTrophy2](../../core/libs/prx/libSceNpTrophy2/src/GameInfo.cpp): `sceNpTrophy2RegisterUnlockCallback` accepts a callback that is never called, as no trophy is ever unlocked, and `sceNpTrophy2UnregisterUnlockCallback` only returns success. @@ -48,6 +49,7 @@ Throughout the project, every function at every stage either **does exactly what - [scePadOpenExt](../../core/libs/prx/libScePad/Export.cpp) (libScePad) - only special ports (type 2) are handled, and they return `DEVICE_NOT_CONNECTED` (0x80920007) because the host has no special controller; whether the console opens a handle and reports the device as disconnected later is unknown. PPSA01317 passes a 16-byte param that names the device by vendor and product id (`b7 0e 04 0e ...` for 0x0eb7:0x0e04) and skips the user on any negative result. Other port types throw - PPSA23566 imports declared without parameters, signatures unknown: [sceAudioOut2UserGetSupportedAttributes](../../core/libs/prx/libSceAudioOut/src/AudioOut2System.cpp), [sceConvertKeycodeGetCharacterFromKeyboardData](../../core/libs/prx/libSceConvertKeycode/Export.cpp), [sceHttpSetCookieRecvCallback, sceHttpSetRedirectCallback, sceHttpsGetSslError, sceHttpsSetSslVersion](../../core/libs/prx/libSceHttp/Export.cpp), [sce::Json::MemAllocator::notifyError, sce::Json::Value::clear](../../core/libs/prx/libSceJson2/Export.cpp), [sceNetResolverAbort](../../core/libs/prx/libSceNet/Export.cpp), [sceNpCommerceDialogOpen2](../../core/libs/prx/libSceNpCommerce/Export.cpp), [sceNpEntitlementAccessGetPftFlag](../../core/libs/prx/libSceNpEntitlementAccess/Export.cpp), [sceProprietaryVoiceChatHelper{Initialize,Terminate,SetVoiceChatState,GetVoiceChatUsageState}](../../core/libs/prx/libSceProprietaryVoiceChatHelperPrx/Export.cpp), [sceVoice{GetResourceInfo,ResetPort,EnableChat,DisableChat}](../../core/libs/prx/libSceVoice/Export.cpp). Names from the shadPS4 aerolib NID list - [sceAvPlayerAddSource](../../core/libs/prx/libSceAvPlayer/src/Source.cpp) (libSceAvPlayer) - requests up to 4 additional decode-ahead video framebuffers from the memory replacement beyond `num_output_video_framebuffers` when memory is available; the console's internal buffering behaviour is unknown +- [sceTextToSpeech2Initialize](../../core/libs/prx/libSceTextToSpeech2/Export.cpp) (libSceTextToSpeech2) - the console's error for an unavailable speech engine is unknown; it returns the kernel's `EOPNOTSUPP` (0x8002002D). PPSA01317 passes a param that starts with 0x2000000 and only tests the result for non-zero; the other exports it imports are declared without parameters - [sceAgcDcbClearState](../../core/libs/prx/libSceAgc/DcbFlow/src/Control.cpp) (libSceAgc) - the (buffer, command) signature follows [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/Agc/SceAgc.cs) and [OpenAGC](https://github.com/OpenAGC/OpenAGC/blob/main/src/game_compat.c), and the 2-dword CLEAR_STATE (0x12) packet is OpenAGC's; OpenAGC masks the command to 4 bits, here a command above 0xf throws, as the driver rejects that payload - [sceVideoOutRegisterBuffers2](../../core/libs/prx/libSceVideoOut/src/Buffer.cpp) (libSceVideoOut) - buffer option 8 (STRICT_COLORIMETRY) is presented as option 0, with the stored values unchanged; what the console changes for it is unknown. Only options 0 and 8 are accepted - [sceAgcGetRegisterDefaultsInternal](../../core/libs/prx/libSceAgc/Misc/src/RegisterDefaults.cpp) (libSceAgc) - returns the version 0 internal table, as `sceAgcGetRegisterDefaults` returns the version 0 public one; [OpenAGC](https://github.com/OpenAGC/OpenAGC/blob/main/src/game_compat.c) returns the table of the version passed to `sceAgcInit` instead, and null before it