From 0d6e8e227a7c71223ad5d154538a1e1213a661d3 Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Wed, 14 Aug 2024 21:30:44 +0300 Subject: [PATCH] Fixed some sound and threading issues. Details: * Switched SDL audio mutex to RW lock. This fixes games that continiously call SetVolume in a different thread (like Ghostbusters) * Added contition to buffer audio packets independent of video packets. This fixes choppy audio across many games. * Increased the number of audio frame buffers from 2 to 4. Just in case. * Migrated to std::jthread and std::mutex from pthreads. * Fixed a race condition with joins on avplayer close that caused a crash. --- src/audio_core/sdl_audio.cpp | 8 +- src/audio_core/sdl_audio.h | 4 +- src/core/libraries/audio/audioout.cpp | 4 +- src/core/libraries/avplayer/avplayer.cpp | 67 +---- src/core/libraries/avplayer/avplayer.h | 1 + .../libraries/avplayer/avplayer_common.cpp | 59 ---- src/core/libraries/avplayer/avplayer_common.h | 90 +------ .../avplayer/avplayer_file_streamer.cpp | 6 +- src/core/libraries/avplayer/avplayer_impl.cpp | 43 +-- src/core/libraries/avplayer/avplayer_impl.h | 34 +-- .../libraries/avplayer/avplayer_source.cpp | 254 ++++++++---------- src/core/libraries/avplayer/avplayer_source.h | 25 +- .../libraries/avplayer/avplayer_state.cpp | 74 ++--- src/core/libraries/avplayer/avplayer_state.h | 21 +- src/core/libraries/kernel/thread_management.h | 16 +- src/core/libraries/kernel/time_management.h | 1 - src/core/libraries/save_data/savedata.cpp | 5 +- 17 files changed, 231 insertions(+), 481 deletions(-) diff --git a/src/audio_core/sdl_audio.cpp b/src/audio_core/sdl_audio.cpp index aac67d8c..9c8c5991 100644 --- a/src/audio_core/sdl_audio.cpp +++ b/src/audio_core/sdl_audio.cpp @@ -13,7 +13,7 @@ namespace Audio { int SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq, Libraries::AudioOut::OrbisAudioOutParamFormat format) { using Libraries::AudioOut::OrbisAudioOutParamFormat; - std::scoped_lock lock{m_mutex}; + std::unique_lock lock{m_mutex}; for (int id = 0; id < portsOut.size(); id++) { auto& port = portsOut[id]; if (!port.isOpen) { @@ -88,7 +88,7 @@ int SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq, } s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) { - std::scoped_lock lock{m_mutex}; + std::shared_lock lock{m_mutex}; auto& port = portsOut[handle - 1]; if (!port.isOpen) { return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; @@ -109,7 +109,7 @@ s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) { bool SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) { using Libraries::AudioOut::OrbisAudioOutParamFormat; - std::scoped_lock lock{m_mutex}; + std::shared_lock lock{m_mutex}; auto& port = portsOut[handle - 1]; if (!port.isOpen) { return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; @@ -147,7 +147,7 @@ bool SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) { } bool SDLAudio::AudioOutGetStatus(s32 handle, int* type, int* channels_num) { - std::scoped_lock lock{m_mutex}; + std::shared_lock lock{m_mutex}; auto& port = portsOut[handle - 1]; *type = port.type; *channels_num = port.channels_num; diff --git a/src/audio_core/sdl_audio.h b/src/audio_core/sdl_audio.h index d20c4455..7844bd61 100644 --- a/src/audio_core/sdl_audio.h +++ b/src/audio_core/sdl_audio.h @@ -3,7 +3,7 @@ #pragma once -#include +#include #include #include "core/libraries/audio/audioout.h" @@ -32,7 +32,7 @@ private: int volume[8] = {}; SDL_AudioStream* stream = nullptr; }; - std::mutex m_mutex; + std::shared_mutex m_mutex; std::array portsOut; // main up to 8 ports , BGM 1 port , voice up to 4 ports , // personal up to 4 ports , padspk up to 5 ports , aux 1 port }; diff --git a/src/core/libraries/audio/audioout.cpp b/src/core/libraries/audio/audioout.cpp index 08929383..cb676afc 100644 --- a/src/core/libraries/audio/audioout.cpp +++ b/src/core/libraries/audio/audioout.cpp @@ -234,7 +234,7 @@ int PS4_SYSV_ABI sceAudioOutGetSystemState() { } int PS4_SYSV_ABI sceAudioOutInit() { - LOG_INFO(Lib_AudioOut, "called"); + LOG_TRACE(Lib_AudioOut, "called"); if (audio != nullptr) { return ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT; } @@ -323,12 +323,10 @@ int PS4_SYSV_ABI sceAudioOutOpenEx() { } s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) { - LOG_TRACE(Lib_AudioOut, "called"); return audio->AudioOutOutput(handle, ptr); } int PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num) { - LOG_TRACE(Lib_AudioOut, "called"); for (u32 i = 0; i < num; i++) { if (auto err = audio->AudioOutOutput(param[i].handle, param[i].ptr); err != 0) return err; diff --git a/src/core/libraries/avplayer/avplayer.cpp b/src/core/libraries/avplayer/avplayer.cpp index e8e99bca..8fccc659 100644 --- a/src/core/libraries/avplayer/avplayer.cpp +++ b/src/core/libraries/avplayer/avplayer.cpp @@ -11,8 +11,6 @@ #include // std::max, std::min -#include // va_list - namespace Libraries::AvPlayer { using namespace Kernel; @@ -140,17 +138,7 @@ SceAvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(SceAvPlayerInitData* data) { return nullptr; } - ThreadPriorities priorities{}; - const u32 base_priority = data->base_priority != 0 ? data->base_priority : 700; - priorities.video_decoder_priority = GetPriority(base_priority, 5); - priorities.audio_decoder_priority = GetPriority(base_priority, 6); - priorities.demuxer_priority = GetPriority(base_priority, 9); - priorities.controller_priority = GetPriority(base_priority, 2); - // priorities.http_streaming_priority = GetPriority(base_priority, 10); - // priorities.file_streaming_priority = GetPriority(priorities.http_streaming_priority, 15); - // priorities.maxPriority = priorities.http_streaming_priority; - - return new AvPlayer(*data, priorities); + return new AvPlayer(*data); } s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data, @@ -176,56 +164,7 @@ s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data, data.num_output_video_framebuffers = p_data->num_output_video_framebuffers; data.auto_start = p_data->auto_start; - ThreadPriorities priorities{}; - s32 base_priority = 0; - const auto res = scePthreadGetprio(scePthreadSelf(), &base_priority); - if (res != 0 || base_priority == 0) { - base_priority = 700; - } - - if (p_data->video_decoder_priority != 0) { - priorities.video_decoder_priority = p_data->video_decoder_priority; - } else { - priorities.video_decoder_priority = GetPriority(base_priority, 5); - } - priorities.video_decoder_affinity = p_data->video_decoder_affinity; - - if (p_data->audio_decoder_priority != 0) { - priorities.audio_decoder_priority = p_data->audio_decoder_priority; - } else { - priorities.audio_decoder_priority = GetPriority(base_priority, 6); - } - priorities.audio_decoder_affinity = p_data->audio_decoder_affinity; - - if (p_data->controller_priority != 0) { - priorities.controller_priority = p_data->controller_priority; - } else { - priorities.controller_priority = GetPriority(base_priority, 2); - } - priorities.controller_affinity = p_data->controller_affinity; - - if (p_data->demuxer_priority != 0) { - priorities.demuxer_priority = p_data->demuxer_priority; - } else { - priorities.demuxer_priority = GetPriority(base_priority, 9); - } - priorities.demuxer_affinity = p_data->demuxer_affinity; - - // if (p_data->http_streaming_priority != 0) { - // priorities.http_streaming_priority = p_data->http_streaming_priority; - // } else { - // priorities.http_streaming_priority = GetPriority(base_priority, 10); - // } - // priorities.http_streaming_affinity = p_data->http_streaming_affinity; - - // if (p_data->file_streaming_priority != 0) { - // priorities.file_streaming_priority = p_data->file_streaming_priority; - // } else { - // priorities.file_streaming_priority = GetPriority(base_priority, 15); - // } - // priorities.http_streaming_affinity = p_data->http_streaming_affinity; - - *p_player = new AvPlayer(data, priorities); + *p_player = new AvPlayer(data); return ORBIS_OK; } @@ -320,7 +259,7 @@ s32 PS4_SYSV_ABI sceAvPlayerStart(SceAvPlayerHandle handle) { } s32 PS4_SYSV_ABI sceAvPlayerStop(SceAvPlayerHandle handle) { - LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); + LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } diff --git a/src/core/libraries/avplayer/avplayer.h b/src/core/libraries/avplayer/avplayer.h index e88419c1..360f06b6 100644 --- a/src/core/libraries/avplayer/avplayer.h +++ b/src/core/libraries/avplayer/avplayer.h @@ -5,6 +5,7 @@ #include "common/types.h" +#include // va_list #include // size_t namespace Core::Loader { diff --git a/src/core/libraries/avplayer/avplayer_common.cpp b/src/core/libraries/avplayer/avplayer_common.cpp index 3536c030..306603e2 100644 --- a/src/core/libraries/avplayer/avplayer_common.cpp +++ b/src/core/libraries/avplayer/avplayer_common.cpp @@ -12,65 +12,6 @@ namespace Libraries::AvPlayer { using namespace Kernel; -Kernel::ScePthreadMutex CreateMutex(int type, const char* name) { - ScePthreadMutexattr attr{}; - ScePthreadMutex mutex{}; - if (scePthreadMutexattrInit(&attr) == 0) { - if (scePthreadMutexattrSettype(&attr, type) == 0) { - if (scePthreadMutexInit(&mutex, &attr, name) != 0) { - if (mutex != nullptr) { - scePthreadMutexDestroy(&mutex); - } - return nullptr; - } - } - } - if (attr != nullptr) { - scePthreadMutexattrDestroy(&attr); - } - return mutex; -} - -ScePthread CreateThread(Kernel::PthreadEntryFunc func, const ThreadParameters& params) { - ScePthreadAttr attr; - if (scePthreadAttrInit(&attr) != 0) { - return nullptr; - } - if (scePthreadAttrSetinheritsched(&attr, 0) != 0) { - scePthreadAttrDestroy(&attr); - return nullptr; - } - - SceKernelSchedParam param{.sched_priority = static_cast(params.priority)}; - if (scePthreadAttrSetschedparam(&attr, ¶m) != 0) { - scePthreadAttrDestroy(&attr); - return nullptr; - } - if (scePthreadAttrSetstacksize(&attr, std::min(params.stack_size, 0x4000u)) != 0) { - scePthreadAttrDestroy(&attr); - return nullptr; - } - if (scePthreadAttrSetdetachstate(&attr, 0) != 0) { - scePthreadAttrDestroy(&attr); - return nullptr; - } - if (params.affinity > 0) { - if (scePthreadAttrSetaffinity(&attr, params.affinity) != 0) { - scePthreadAttrDestroy(&attr); - return nullptr; - } - } - - ScePthread thread{}; - if (scePthreadCreate(&thread, &attr, func, params.p_user_data, params.thread_name) != 0) { - scePthreadAttrDestroy(&attr); - return nullptr; - } - - scePthreadAttrDestroy(&attr); - return thread; -} - static bool ichar_equals(char a, char b) { return std::tolower(static_cast(a)) == std::tolower(static_cast(b)); diff --git a/src/core/libraries/avplayer/avplayer_common.h b/src/core/libraries/avplayer/avplayer_common.h index 5faf2388..a53696ec 100644 --- a/src/core/libraries/avplayer/avplayer_common.h +++ b/src/core/libraries/avplayer/avplayer_common.h @@ -31,9 +31,6 @@ enum class AvState { C0x0B, Buffering, Starting, - C0x0E, - C0x0F, - C0x10, Error, }; @@ -45,23 +42,6 @@ enum class AvEventType { Error = 255, }; -struct ThreadPriorities { - u32 audio_decoder_priority; - u32 audio_decoder_affinity; - u32 video_decoder_priority; - u32 video_decoder_affinity; - u32 demuxer_priority; - u32 demuxer_affinity; - u32 controller_priority; - u32 controller_affinity; - // u32 http_streaming_priority; - // u32 http_streaming_affinity; - // u32 file_streaming_priority; - // u32 file_streaming_affinity; - // u32 maxPriority; - // u32 maxAffinity; -}; - union AvPlayerEventData { u32 num_frames; // 20 AvState state; // AvEventType::ChangeFlowState @@ -74,68 +54,9 @@ struct AvPlayerEvent { AvPlayerEventData payload; }; -Kernel::ScePthreadMutex CreateMutex(int type, const char* name); - -class PthreadMutex { -public: - using ScePthreadMutex = Kernel::ScePthreadMutex; - - PthreadMutex() = default; - - PthreadMutex(const PthreadMutex&) = delete; - PthreadMutex& operator=(const PthreadMutex&) = delete; - - PthreadMutex(PthreadMutex&& r) : m_mutex(r.m_mutex) { - r.m_mutex = nullptr; - } - PthreadMutex& operator=(PthreadMutex&& r) { - std::swap(m_mutex, r.m_mutex); - return *this; - } - - PthreadMutex(int type, const char* name) : m_mutex(CreateMutex(type, name)) {} - ~PthreadMutex() { - if (m_mutex != nullptr) { - Kernel::scePthreadMutexDestroy(&m_mutex); - } - } - - operator ScePthreadMutex() { - return m_mutex; - } - - int Lock() { - return Kernel::scePthreadMutexLock(&m_mutex); - } - - int Unlock() { - return Kernel::scePthreadMutexUnlock(&m_mutex); - } - - // implement BasicLockable to use std::lock_guard - // NOLINTNEXTLINE(readability-identifier-naming) - void lock() { - ASSERT_MSG(Lock() >= 0, "Could not lock the mutex"); - } - - // NOLINTNEXTLINE(readability-identifier-naming) - void unlock() { - ASSERT_MSG(Unlock() >= 0, "Could not unlock the mutex"); - } - - operator bool() { - return m_mutex != nullptr; - } - -private: - ScePthreadMutex m_mutex{}; -}; - template class AvPlayerQueue { public: - AvPlayerQueue() : m_mutex(PTHREAD_MUTEX_ERRORCHECK, "SceAvPlayer0StlHandler") {} - size_t Size() { return m_queue.size(); } @@ -161,19 +82,10 @@ public: } private: - PthreadMutex m_mutex{}; + std::mutex m_mutex{}; std::queue m_queue{}; }; -struct ThreadParameters { - void* p_user_data; - const char* thread_name; - u32 stack_size; - u32 priority; - u32 affinity; -}; - -Kernel::ScePthread CreateThread(Kernel::PthreadEntryFunc func, const ThreadParameters& params); SceAvPlayerSourceType GetSourceType(std::string_view path); } // namespace Libraries::AvPlayer diff --git a/src/core/libraries/avplayer/avplayer_file_streamer.cpp b/src/core/libraries/avplayer/avplayer_file_streamer.cpp index 43055fd5..4b1ddb6e 100644 --- a/src/core/libraries/avplayer/avplayer_file_streamer.cpp +++ b/src/core/libraries/avplayer/avplayer_file_streamer.cpp @@ -69,14 +69,14 @@ s64 AvPlayerFileStreamer::Seek(void* opaque, s64 offset, int whence) { if (whence == SEEK_CUR) { self->m_position = - std::min(u64(std::max(0ll, s64(self->m_position) + offset)), self->m_file_size); + std::min(u64(std::max(0i64, s64(self->m_position) + offset)), self->m_file_size); return self->m_position; } else if (whence == SEEK_SET) { - self->m_position = std::min(u64(std::max(0ll, offset)), self->m_file_size); + self->m_position = std::min(u64(std::max(0i64, offset)), self->m_file_size); return self->m_position; } else if (whence == SEEK_END) { self->m_position = - std::min(u64(std::max(0ll, s64(self->m_file_size) + offset)), self->m_file_size); + std::min(u64(std::max(0i64, s64(self->m_file_size) + offset)), self->m_file_size); return self->m_position; } diff --git a/src/core/libraries/avplayer/avplayer_impl.cpp b/src/core/libraries/avplayer/avplayer_impl.cpp index f08356bd..1114254f 100644 --- a/src/core/libraries/avplayer/avplayer_impl.cpp +++ b/src/core/libraries/avplayer/avplayer_impl.cpp @@ -77,29 +77,30 @@ u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) { return size(ptr); } -AvPlayer::AvPlayer(const SceAvPlayerInitData& data, const ThreadPriorities& priorities) - : m_file_io_mutex(PTHREAD_MUTEX_ERRORCHECK, "AvPlayer_FileIO"), m_init_data(data), - m_init_data_original(data) { - - m_init_data.memory_replacement.object_ptr = this; - m_init_data.memory_replacement.allocate = &AvPlayer::Allocate; - m_init_data.memory_replacement.deallocate = &AvPlayer::Deallocate; - m_init_data.memory_replacement.allocate_texture = &AvPlayer::AllocateTexture; - m_init_data.memory_replacement.deallocate_texture = &AvPlayer::DeallocateTexture; +SceAvPlayerInitData AvPlayer::StubInitData(const SceAvPlayerInitData& data) { + SceAvPlayerInitData result = data; + result.memory_replacement.object_ptr = this; + result.memory_replacement.allocate = &AvPlayer::Allocate; + result.memory_replacement.deallocate = &AvPlayer::Deallocate; + result.memory_replacement.allocate_texture = &AvPlayer::AllocateTexture; + result.memory_replacement.deallocate_texture = &AvPlayer::DeallocateTexture; if (data.file_replacement.open == nullptr || data.file_replacement.close == nullptr || data.file_replacement.readOffset == nullptr || data.file_replacement.size == nullptr) { - m_init_data.file_replacement = {}; + result.file_replacement = {}; } else { - m_init_data.file_replacement.object_ptr = this; - m_init_data.file_replacement.open = &AvPlayer::OpenFile; - m_init_data.file_replacement.close = &AvPlayer::CloseFile; - m_init_data.file_replacement.readOffset = &AvPlayer::ReadOffsetFile; - m_init_data.file_replacement.size = &AvPlayer::SizeFile; + result.file_replacement.object_ptr = this; + result.file_replacement.open = &AvPlayer::OpenFile; + result.file_replacement.close = &AvPlayer::CloseFile; + result.file_replacement.readOffset = &AvPlayer::ReadOffsetFile; + result.file_replacement.size = &AvPlayer::SizeFile; } - - m_state = std::make_unique(m_init_data, priorities); + return result; } +AvPlayer::AvPlayer(const SceAvPlayerInitData& data) + : m_init_data(StubInitData(data)), m_init_data_original(data), + m_state(std::make_unique(m_init_data)) {} + s32 AvPlayer::PostInit(const SceAvPlayerPostInitData& data) { m_post_init_data = data; return ORBIS_OK; @@ -109,11 +110,9 @@ s32 AvPlayer::AddSource(std::string_view path) { if (path.empty()) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - if (AVPLAYER_IS_ERROR(m_state->AddSource(path, GetSourceType(path)))) { return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; } - return ORBIS_OK; } @@ -121,7 +120,11 @@ s32 AvPlayer::GetStreamCount() { if (m_state == nullptr) { return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; } - return m_state->GetStreamCount(); + const auto res = m_state->GetStreamCount(); + if (AVPLAYER_IS_ERROR(res)) { + return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; + } + return res; } s32 AvPlayer::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) { diff --git a/src/core/libraries/avplayer/avplayer_impl.h b/src/core/libraries/avplayer/avplayer_impl.h index 98f959e6..df4acfee 100644 --- a/src/core/libraries/avplayer/avplayer_impl.h +++ b/src/core/libraries/avplayer/avplayer_impl.h @@ -9,6 +9,8 @@ #include "core/libraries/kernel/thread_management.h" +#include + extern "C" { #include #include @@ -21,19 +23,7 @@ namespace Libraries::AvPlayer { class AvPlayer { public: - // Memory Replacement - static void* PS4_SYSV_ABI Allocate(void* handle, u32 alignment, u32 size); - static void PS4_SYSV_ABI Deallocate(void* handle, void* memory); - static void* PS4_SYSV_ABI AllocateTexture(void* handle, u32 alignment, u32 size); - static void PS4_SYSV_ABI DeallocateTexture(void* handle, void* memory); - - // File Replacement - static int PS4_SYSV_ABI OpenFile(void* handle, const char* filename); - static int PS4_SYSV_ABI CloseFile(void* handle); - static int PS4_SYSV_ABI ReadOffsetFile(void* handle, u8* buffer, u64 position, u32 length); - static u64 PS4_SYSV_ABI SizeFile(void* handle); - - AvPlayer(const SceAvPlayerInitData& data, const ThreadPriorities& priorities); + AvPlayer(const SceAvPlayerInitData& data); s32 PostInit(const SceAvPlayerPostInitData& data); s32 AddSource(std::string_view filename); @@ -51,13 +41,27 @@ public: private: using ScePthreadMutex = Kernel::ScePthreadMutex; - std::unique_ptr m_state{}; + // Memory Replacement + static void* PS4_SYSV_ABI Allocate(void* handle, u32 alignment, u32 size); + static void PS4_SYSV_ABI Deallocate(void* handle, void* memory); + static void* PS4_SYSV_ABI AllocateTexture(void* handle, u32 alignment, u32 size); + static void PS4_SYSV_ABI DeallocateTexture(void* handle, void* memory); + + // File Replacement + static int PS4_SYSV_ABI OpenFile(void* handle, const char* filename); + static int PS4_SYSV_ABI CloseFile(void* handle); + static int PS4_SYSV_ABI ReadOffsetFile(void* handle, u8* buffer, u64 position, u32 length); + static u64 PS4_SYSV_ABI SizeFile(void* handle); + + SceAvPlayerInitData StubInitData(const SceAvPlayerInitData& data); + SceAvPlayerInitData m_init_data{}; SceAvPlayerInitData m_init_data_original{}; SceAvPlayerPostInitData m_post_init_data{}; - PthreadMutex m_file_io_mutex{}; + std::mutex m_file_io_mutex{}; std::atomic_bool m_has_source{}; + std::unique_ptr m_state{}; }; } // namespace Libraries::AvPlayer diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index c3d3dc55..e235b2c2 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -24,9 +24,9 @@ namespace Libraries::AvPlayer { using namespace Kernel; AvPlayerSource::AvPlayerSource(AvPlayerStateCallback& state, std::string_view path, - const SceAvPlayerInitData& init_data, ThreadPriorities& priorities, + const SceAvPlayerInitData& init_data, SceAvPlayerSourceType source_type) - : m_state(state), m_priorities(priorities), m_memory_replacement(init_data.memory_replacement), + : m_state(state), m_memory_replacement(init_data.memory_replacement), m_num_output_video_framebuffers(init_data.num_output_video_framebuffers) { AVFormatContext* context = avformat_alloc_context(); if (init_data.file_replacement.open != nullptr) { @@ -113,7 +113,7 @@ s32 AvPlayerSource::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) info.details.video.height = p_stream->codecpar->height; if (p_lang_node != nullptr) { std::memcpy(info.details.video.language_code, p_lang_node->value, - std::min(strlen(p_lang_node->value), 3ull)); + std::min(strlen(p_lang_node->value), size_t(3))); } break; case SCE_AVPLAYER_AUDIO: @@ -123,7 +123,7 @@ s32 AvPlayerSource::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) info.details.audio.size = 0; // sceAvPlayerGetStreamInfo() is expected to set this to 0 if (p_lang_node != nullptr) { std::memcpy(info.details.audio.language_code, p_lang_node->value, - std::min(strlen(p_lang_node->value), 3ull)); + std::min(strlen(p_lang_node->value), size_t(3))); } break; case SCE_AVPLAYER_TIMEDTEXT: @@ -132,7 +132,7 @@ s32 AvPlayerSource::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) info.details.subs.text_size = 12; if (p_lang_node != nullptr) { std::memcpy(info.details.subs.language_code, p_lang_node->value, - std::min(strlen(p_lang_node->value), 3ull)); + std::min(strlen(p_lang_node->value), size_t(3))); } break; default: @@ -189,7 +189,7 @@ bool AvPlayerSource::EnableStream(u32 stream_index) { const auto num_channels = m_audio_codec_context->ch_layout.nb_channels; const auto align = num_channels * sizeof(u16); const auto size = num_channels * sizeof(u16) * 1024; - for (u64 index = 0; index < 2; ++index) { + for (u64 index = 0; index < 4; ++index) { m_audio_buffers.Push(FrameBuffer(m_memory_replacement, 0x100, size)); } LOG_INFO(Lib_AvPlayer, "Audio stream {} enabled", stream_index); @@ -212,78 +212,41 @@ std::optional AvPlayerSource::HasFrames(u32 num_frames) { } s32 AvPlayerSource::Start() { + std::unique_lock lock(m_state_mutex); + if (m_audio_codec_context == nullptr && m_video_codec_context == nullptr) { LOG_ERROR(Lib_AvPlayer, "Could not start playback. NULL context."); return -1; } - { - ThreadParameters demuxer_params{ - .p_user_data = this, - .thread_name = "AvPlayer_Demuxer", - .stack_size = 0x4000, - .priority = m_priorities.demuxer_priority, - .affinity = m_priorities.demuxer_affinity, - }; - m_demuxer_thread = CreateThread(&DemuxerThread, demuxer_params); - if (m_demuxer_thread == nullptr) { - LOG_ERROR(Lib_AvPlayer, "Could not create DEMUXER thread."); - return -1; - } - } - if (m_video_codec_context != nullptr) { - ThreadParameters video_decoder_params{ - .p_user_data = this, - .thread_name = "AvPlayer_VideoDecoder", - .stack_size = 0x4000, - .priority = m_priorities.video_decoder_priority, - .affinity = m_priorities.video_decoder_affinity, - }; - m_video_decoder_thread = CreateThread(&VideoDecoderThread, video_decoder_params); - if (m_video_decoder_thread == nullptr) { - LOG_ERROR(Lib_AvPlayer, "Could not create VIDEO DECODER thread."); - return -1; - } - } - if (m_audio_codec_context != nullptr) { - ThreadParameters audio_decoder_params{ - .p_user_data = this, - .thread_name = "AvPlayer_AudioDecoder", - .stack_size = 0x4000, - .priority = m_priorities.audio_decoder_priority, - .affinity = m_priorities.audio_decoder_affinity, - }; - m_audio_decoder_thread = CreateThread(&AudioDecoderThread, audio_decoder_params); - if (m_audio_decoder_thread == nullptr) { - LOG_ERROR(Lib_AvPlayer, "Could not create AUDIO DECODER thread."); - return -1; - } - } + m_demuxer_thread = std::jthread([this](std::stop_token stop) { this->DemuxerThread(stop); }); + m_video_decoder_thread = + std::jthread([this](std::stop_token stop) { this->VideoDecoderThread(stop); }); + m_audio_decoder_thread = + std::jthread([this](std::stop_token stop) { this->AudioDecoderThread(stop); }); m_start_time = std::chrono::high_resolution_clock::now(); return 0; } bool AvPlayerSource::Stop() { - if (m_is_stop) { + std::unique_lock lock(m_state_mutex); + + if (!HasRunningThreads()) { LOG_WARNING(Lib_AvPlayer, "Could not stop playback: already stopped."); return false; } - m_is_stop = true; - - void* res = nullptr; - if (m_video_decoder_thread != nullptr) { - scePthreadJoin(m_video_decoder_thread, &res); + m_video_decoder_thread.request_stop(); + m_audio_decoder_thread.request_stop(); + m_demuxer_thread.request_stop(); + if (m_demuxer_thread.joinable()) { + m_demuxer_thread.join(); } - if (m_audio_decoder_thread != nullptr) { - scePthreadJoin(m_audio_decoder_thread, &res); + if (m_video_decoder_thread.joinable()) { + m_video_decoder_thread.join(); } - if (m_demuxer_thread != nullptr) { - scePthreadJoin(m_demuxer_thread, &res); + if (m_audio_decoder_thread.joinable()) { + m_audio_decoder_thread.join(); } - m_audio_packets.Clear(); - m_video_packets.Clear(); - m_audio_frames.Clear(); - m_video_frames.Clear(); if (m_current_audio_frame.has_value()) { m_audio_buffers.Push(std::move(m_current_audio_frame.value())); m_current_audio_frame.reset(); @@ -292,10 +255,19 @@ bool AvPlayerSource::Stop() { m_video_buffers.Push(std::move(m_current_video_frame.value())); m_current_video_frame.reset(); } + + m_audio_packets.Clear(); + m_video_packets.Clear(); + m_audio_frames.Clear(); + m_video_frames.Clear(); return true; } bool AvPlayerSource::GetVideoData(SceAvPlayerFrameInfo& video_info) { + if (!IsActive()) { + return false; + } + SceAvPlayerFrameInfoEx info{}; if (!GetVideoData(info)) { return false; @@ -315,8 +287,13 @@ static void CopyNV12Data(u8* dst, const AVFrame& src) { } bool AvPlayerSource::GetVideoData(SceAvPlayerFrameInfoEx& video_info) { + if (!IsActive()) { + return false; + } + + using namespace std::chrono; while (m_video_frames.Size() == 0 && !m_is_eof) { - sceKernelUsleep(5000); + std::this_thread::sleep_for(milliseconds(5)); } auto frame = m_video_frames.Pop(); @@ -326,11 +303,10 @@ bool AvPlayerSource::GetVideoData(SceAvPlayerFrameInfoEx& video_info) { } { - using namespace std::chrono; auto elapsed_time = duration_cast(high_resolution_clock::now() - m_start_time).count(); while (elapsed_time < frame->info.timestamp) { - sceKernelUsleep((frame->info.timestamp - elapsed_time) * 1000); + std::this_thread::sleep_for(milliseconds(frame->info.timestamp - elapsed_time)); elapsed_time = duration_cast(high_resolution_clock::now() - m_start_time).count(); } @@ -346,8 +322,13 @@ bool AvPlayerSource::GetVideoData(SceAvPlayerFrameInfoEx& video_info) { } bool AvPlayerSource::GetAudioData(SceAvPlayerFrameInfo& audio_info) { + if (!IsActive()) { + return false; + } + + using namespace std::chrono; while (m_audio_frames.Size() == 0 && !m_is_eof) { - sceKernelUsleep(5000); + std::this_thread::sleep_for(milliseconds(5)); } auto frame = m_audio_frames.Pop(); @@ -357,11 +338,10 @@ bool AvPlayerSource::GetAudioData(SceAvPlayerFrameInfo& audio_info) { } { - using namespace std::chrono; auto elapsed_time = duration_cast(high_resolution_clock::now() - m_start_time).count(); while (elapsed_time < frame->info.timestamp) { - sceKernelUsleep((frame->info.timestamp - elapsed_time) * 1000); + std::this_thread::sleep_for(milliseconds(frame->info.timestamp - elapsed_time)); elapsed_time = duration_cast(high_resolution_clock::now() - m_start_time).count(); } @@ -387,8 +367,8 @@ u64 AvPlayerSource::CurrentTime() { } bool AvPlayerSource::IsActive() { - return !m_is_stop && (!m_is_eof || m_audio_packets.Size() != 0 || m_video_packets.Size() != 0 || - m_video_frames.Size() != 0 || m_audio_frames.Size() != 0); + return !m_is_eof || m_audio_packets.Size() != 0 || m_video_packets.Size() != 0 || + m_video_frames.Size() != 0 || m_audio_frames.Size() != 0; } void AvPlayerSource::ReleaseAVPacket(AVPacket* packet) { @@ -427,52 +407,51 @@ void AvPlayerSource::ReleaseAVFormatContext(AVFormatContext* context) { } } -void* AvPlayerSource::DemuxerThread(void* opaque) { - const auto self = reinterpret_cast(opaque); - if (!self->m_audio_stream_index.has_value() && !self->m_video_stream_index.has_value()) { +void AvPlayerSource::DemuxerThread(std::stop_token stop) { + using namespace std::chrono; + if (!m_audio_stream_index.has_value() && !m_video_stream_index.has_value()) { LOG_WARNING(Lib_AvPlayer, "Could not start DEMUXER thread. No streams enabled."); - return nullptr; + return; } LOG_INFO(Lib_AvPlayer, "Demuxer Thread started"); - while (!self->m_is_stop) { - if (self->m_video_packets.Size() > 60) { - sceKernelUsleep(5000); + while (!stop.stop_requested()) { + if (m_video_packets.Size() > 30 && m_audio_packets.Size() > 8) { + std::this_thread::sleep_for(milliseconds(5)); continue; } AVPacketPtr up_packet(av_packet_alloc(), &ReleaseAVPacket); - const auto res = av_read_frame(self->m_avformat_context.get(), up_packet.get()); + const auto res = av_read_frame(m_avformat_context.get(), up_packet.get()); if (res < 0) { if (res == AVERROR_EOF) { LOG_INFO(Lib_AvPlayer, "EOF reached in demuxer"); break; } else { LOG_ERROR(Lib_AvPlayer, "Could not read AV frame: error = {}", res); - self->m_state.OnError(); - scePthreadExit(0); + m_state.OnError(); + return; } break; } - if (up_packet->stream_index == self->m_video_stream_index) { - self->m_video_packets.Push(std::move(up_packet)); - } else if (up_packet->stream_index == self->m_audio_stream_index) { - self->m_audio_packets.Push(std::move(up_packet)); + if (up_packet->stream_index == m_video_stream_index) { + m_video_packets.Push(std::move(up_packet)); + } else if (up_packet->stream_index == m_audio_stream_index) { + m_audio_packets.Push(std::move(up_packet)); } } - self->m_is_eof = true; + m_is_eof = true; void* res; - if (self->m_video_decoder_thread) { - scePthreadJoin(self->m_video_decoder_thread, &res); + if (m_video_decoder_thread.joinable()) { + m_video_decoder_thread.join(); } - if (self->m_audio_decoder_thread) { - scePthreadJoin(self->m_audio_decoder_thread, &res); + if (m_audio_decoder_thread.joinable()) { + m_audio_decoder_thread.join(); } - self->m_state.OnEOF(); + m_state.OnEOF(); LOG_INFO(Lib_AvPlayer, "Demuxer Thread exited normaly"); - scePthreadExit(0); } AvPlayerSource::AVFramePtr AvPlayerSource::ConvertVideoFrame(const AVFrame& frame) { @@ -537,67 +516,63 @@ Frame AvPlayerSource::PrepareVideoFrame(FrameBuffer buffer, const AVFrame& frame }; } -void* AvPlayerSource::VideoDecoderThread(void* opaque) { +void AvPlayerSource::VideoDecoderThread(std::stop_token stop) { + using namespace std::chrono; LOG_INFO(Lib_AvPlayer, "Video Decoder Thread started"); - const auto self = reinterpret_cast(opaque); - - while ((!self->m_is_eof || self->m_video_packets.Size() != 0) && !self->m_is_stop) { - if (self->m_video_packets.Size() == 0) { - sceKernelUsleep(5000); + while ((!m_is_eof || m_video_packets.Size() != 0) && !stop.stop_requested()) { + if (m_video_packets.Size() == 0) { + std::this_thread::sleep_for(milliseconds(5)); continue; } - const auto packet = self->m_video_packets.Pop(); + const auto packet = m_video_packets.Pop(); if (!packet.has_value()) { continue; } - auto res = avcodec_send_packet(self->m_video_codec_context.get(), packet->get()); + auto res = avcodec_send_packet(m_video_codec_context.get(), packet->get()); if (res < 0 && res != AVERROR(EAGAIN)) { - self->m_state.OnError(); + m_state.OnError(); LOG_ERROR(Lib_AvPlayer, "Could not send packet to the video codec. Error = {}", av_err2str(res)); - scePthreadExit(nullptr); + return; } while (res >= 0) { - if (self->m_video_buffers.Size() == 0 && !self->m_is_stop) { - sceKernelUsleep(5000); + if (m_video_buffers.Size() == 0 && !stop.stop_requested()) { + std::this_thread::sleep_for(milliseconds(5)); continue; } auto up_frame = AVFramePtr(av_frame_alloc(), &ReleaseAVFrame); - res = avcodec_receive_frame(self->m_video_codec_context.get(), up_frame.get()); + res = avcodec_receive_frame(m_video_codec_context.get(), up_frame.get()); if (res < 0) { if (res == AVERROR_EOF) { LOG_INFO(Lib_AvPlayer, "EOF reached in video decoder"); - scePthreadExit(nullptr); + return; } else if (res != AVERROR(EAGAIN)) { LOG_ERROR(Lib_AvPlayer, "Could not receive frame from the video codec. Error = {}", av_err2str(res)); - self->m_state.OnError(); - scePthreadExit(nullptr); + m_state.OnError(); + return; } } else { - auto buffer = self->m_video_buffers.Pop(); + auto buffer = m_video_buffers.Pop(); if (!buffer.has_value()) { // Video buffers queue was cleared. This means that player was stopped. break; } if (up_frame->format != AV_PIX_FMT_NV12) { - const auto nv12_frame = self->ConvertVideoFrame(*up_frame); - self->m_video_frames.Push( - self->PrepareVideoFrame(std::move(buffer.value()), *nv12_frame)); + const auto nv12_frame = ConvertVideoFrame(*up_frame); + m_video_frames.Push(PrepareVideoFrame(std::move(buffer.value()), *nv12_frame)); } else { - self->m_video_frames.Push( - self->PrepareVideoFrame(std::move(buffer.value()), *up_frame)); + m_video_frames.Push(PrepareVideoFrame(std::move(buffer.value()), *up_frame)); } LOG_TRACE(Lib_AvPlayer, "Produced Video Frame. Num Frames: {}", - self->m_video_frames.Size()); + m_video_frames.Size()); } } } LOG_INFO(Lib_AvPlayer, "Video Decoder Thread exited normaly"); - scePthreadExit(nullptr); } AvPlayerSource::AVFramePtr AvPlayerSource::ConvertAudioFrame(const AVFrame& frame) { @@ -659,66 +634,67 @@ Frame AvPlayerSource::PrepareAudioFrame(FrameBuffer buffer, const AVFrame& frame }; } -void* AvPlayerSource::AudioDecoderThread(void* opaque) { +void AvPlayerSource::AudioDecoderThread(std::stop_token stop) { + using namespace std::chrono; LOG_INFO(Lib_AvPlayer, "Audio Decoder Thread started"); - const auto self = reinterpret_cast(opaque); - - while ((!self->m_is_eof || self->m_audio_packets.Size() != 0) && !self->m_is_stop) { - if (self->m_audio_packets.Size() == 0) { - sceKernelUsleep(5000); + while ((!m_is_eof || m_audio_packets.Size() != 0) && !stop.stop_requested()) { + if (m_audio_packets.Size() == 0) { + std::this_thread::sleep_for(milliseconds(5)); continue; } - const auto packet = self->m_audio_packets.Pop(); + const auto packet = m_audio_packets.Pop(); if (!packet.has_value()) { continue; } - auto res = avcodec_send_packet(self->m_audio_codec_context.get(), packet->get()); + auto res = avcodec_send_packet(m_audio_codec_context.get(), packet->get()); if (res < 0 && res != AVERROR(EAGAIN)) { - self->m_state.OnError(); + m_state.OnError(); LOG_ERROR(Lib_AvPlayer, "Could not send packet to the audio codec. Error = {}", av_err2str(res)); - scePthreadExit(nullptr); + return; } while (res >= 0) { - if (self->m_audio_buffers.Size() == 0 && !self->m_is_stop) { - sceKernelUsleep(5000); + if (m_audio_buffers.Size() == 0 && !stop.stop_requested()) { + std::this_thread::sleep_for(milliseconds(5)); continue; } auto up_frame = AVFramePtr(av_frame_alloc(), &ReleaseAVFrame); - res = avcodec_receive_frame(self->m_audio_codec_context.get(), up_frame.get()); + res = avcodec_receive_frame(m_audio_codec_context.get(), up_frame.get()); if (res < 0) { if (res == AVERROR_EOF) { LOG_INFO(Lib_AvPlayer, "EOF reached in audio decoder"); - scePthreadExit(nullptr); + return; } else if (res != AVERROR(EAGAIN)) { - self->m_state.OnError(); + m_state.OnError(); LOG_ERROR(Lib_AvPlayer, "Could not receive frame from the audio codec. Error = {}", av_err2str(res)); - scePthreadExit(nullptr); + return; } } else { - auto buffer = self->m_audio_buffers.Pop(); + auto buffer = m_audio_buffers.Pop(); if (!buffer.has_value()) { // Audio buffers queue was cleared. This means that player was stopped. break; } if (up_frame->format != AV_SAMPLE_FMT_S16) { - const auto pcm16_frame = self->ConvertAudioFrame(*up_frame); - self->m_audio_frames.Push( - self->PrepareAudioFrame(std::move(buffer.value()), *pcm16_frame)); + const auto pcm16_frame = ConvertAudioFrame(*up_frame); + m_audio_frames.Push(PrepareAudioFrame(std::move(buffer.value()), *pcm16_frame)); } else { - self->m_audio_frames.Push( - self->PrepareAudioFrame(std::move(buffer.value()), *up_frame)); + m_audio_frames.Push(PrepareAudioFrame(std::move(buffer.value()), *up_frame)); } LOG_TRACE(Lib_AvPlayer, "Produced Audio Frame. Num Frames: {}", - self->m_audio_frames.Size()); + m_audio_frames.Size()); } } } LOG_INFO(Lib_AvPlayer, "Audio Decoder Thread exited normaly"); - scePthreadExit(nullptr); +} + +bool AvPlayerSource::HasRunningThreads() const { + return m_demuxer_thread.joinable() || m_video_decoder_thread.joinable() || + m_audio_decoder_thread.joinable(); } } // namespace Libraries::AvPlayer diff --git a/src/core/libraries/avplayer/avplayer_source.h b/src/core/libraries/avplayer/avplayer_source.h index 67ad44d8..c2f9ac02 100644 --- a/src/core/libraries/avplayer/avplayer_source.h +++ b/src/core/libraries/avplayer/avplayer_source.h @@ -12,8 +12,11 @@ #include #include +#include #include +#include #include +#include struct AVCodecContext; struct AVFormatContext; @@ -88,8 +91,7 @@ struct Frame { class AvPlayerSource { public: AvPlayerSource(AvPlayerStateCallback& state, std::string_view path, - const SceAvPlayerInitData& init_data, ThreadPriorities& priorities, - SceAvPlayerSourceType source_type); + const SceAvPlayerInitData& init_data, SceAvPlayerSourceType source_type); ~AvPlayerSource(); bool FindStreamInfo(); @@ -109,10 +111,6 @@ public: private: using ScePthread = Kernel::ScePthread; - static void* PS4_SYSV_ABI DemuxerThread(void* opaque); - static void* PS4_SYSV_ABI VideoDecoderThread(void* opaque); - static void* PS4_SYSV_ABI AudioDecoderThread(void* opaque); - static void ReleaseAVPacket(AVPacket* packet); static void ReleaseAVFrame(AVFrame* frame); static void ReleaseAVCodecContext(AVCodecContext* context); @@ -127,6 +125,12 @@ private: using SWSContextPtr = std::unique_ptr; using AVFormatContextPtr = std::unique_ptr; + void DemuxerThread(std::stop_token stop); + void VideoDecoderThread(std::stop_token stop); + void AudioDecoderThread(std::stop_token stop); + + bool HasRunningThreads() const; + AVFramePtr ConvertAudioFrame(const AVFrame& frame); AVFramePtr ConvertVideoFrame(const AVFrame& frame); @@ -135,13 +139,11 @@ private: AvPlayerStateCallback& m_state; - ThreadPriorities m_priorities{}; SceAvPlayerMemAllocator m_memory_replacement{}; u64 m_num_output_video_framebuffers{}; std::atomic_bool m_is_looping = false; std::atomic_bool m_is_eof = false; - std::atomic_bool m_is_stop = false; std::unique_ptr m_up_data_streamer; @@ -160,9 +162,10 @@ private: std::optional m_video_stream_index{}; std::optional m_audio_stream_index{}; - ScePthread m_demuxer_thread{}; - ScePthread m_video_decoder_thread{}; - ScePthread m_audio_decoder_thread{}; + std::mutex m_state_mutex; + std::jthread m_demuxer_thread{}; + std::jthread m_video_decoder_thread{}; + std::jthread m_audio_decoder_thread{}; AVFormatContextPtr m_avformat_context{nullptr, &ReleaseAVFormatContext}; AVCodecContextPtr m_video_codec_context{nullptr, &ReleaseAVCodecContext}; diff --git a/src/core/libraries/avplayer/avplayer_state.cpp b/src/core/libraries/avplayer/avplayer_state.cpp index e7aa4571..061d1da6 100644 --- a/src/core/libraries/avplayer/avplayer_state.cpp +++ b/src/core/libraries/avplayer/avplayer_state.cpp @@ -89,12 +89,8 @@ void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, s32 event_i } // Called inside GAME thread -AvPlayerState::AvPlayerState(const SceAvPlayerInitData& init_data, - const ThreadPriorities& priorities) - : m_init_data(init_data), m_event_replacement(init_data.event_replacement), - m_thread_priorities(priorities), - m_event_handler_mutex(PTHREAD_MUTEX_ERRORCHECK, "AvPlayer_EventHandler"), - m_state_machine_mutex(PTHREAD_MUTEX_ERRORCHECK, "AvPlayer_StateMachine") { +AvPlayerState::AvPlayerState(const SceAvPlayerInitData& init_data) + : m_init_data(init_data), m_event_replacement(init_data.event_replacement) { if (m_event_replacement.event_callback == nullptr || init_data.auto_start) { m_auto_start = true; m_init_data.event_replacement.event_callback = &AvPlayerState::AutoPlayEventCallback; @@ -111,10 +107,9 @@ AvPlayerState::~AvPlayerState() { if (m_up_source && m_current_state == AvState::Play) { m_up_source->Stop(); } - m_quit = true; - if (m_controller_thread != nullptr) { - void* res = nullptr; - scePthreadJoin(m_controller_thread, &res); + if (m_controller_thread.joinable()) { + m_controller_thread.request_stop(); + m_controller_thread.join(); } m_event_queue.Clear(); } @@ -131,8 +126,7 @@ s32 AvPlayerState::AddSource(std::string_view path, SceAvPlayerSourceType source return -1; } - m_up_source = std::make_unique(*this, path, m_init_data, m_thread_priorities, - source_type); + m_up_source = std::make_unique(*this, path, m_init_data, source_type); AddSourceEvent(); return 0; } @@ -166,17 +160,17 @@ s32 AvPlayerState::Start() { return 0; } -void* AvPlayerState::AvControllerThread(void* p_user_data) { - AvPlayerState* self = reinterpret_cast(p_user_data); - while (!self->m_quit) { - if (self->m_event_queue.Size() != 0) { - self->ProcessEvent(); +void AvPlayerState::AvControllerThread(std::stop_token stop) { + using std::chrono::milliseconds; + + while (!stop.stop_requested()) { + if (m_event_queue.Size() != 0) { + ProcessEvent(); continue; } - sceKernelUsleep(5000); - self->UpdateBufferingState(); + std::this_thread::sleep_for(milliseconds(5)); + UpdateBufferingState(); } - scePthreadExit(0); } // Called inside GAME thread @@ -198,22 +192,9 @@ void AvPlayerState::WarningEvent(s32 id) { } // Called inside GAME thread -int AvPlayerState::StartControllerThread() { - m_quit.store(0); - - ThreadParameters params{ - .p_user_data = this, - .thread_name = "AvPlayer_Controller", - .stack_size = 0x4000, - .priority = m_thread_priority, - .affinity = m_thread_affinity, - }; - m_controller_thread = CreateThread(&AvControllerThread, params); - if (m_controller_thread == nullptr) { - LOG_ERROR(Lib_AvPlayer, "Could not create CONTROLLER thread."); - return -1; - } - return 0; +void AvPlayerState::StartControllerThread() { + m_controller_thread = + std::jthread([this](std::stop_token stop) { this->AvControllerThread(stop); }); } // Called inside GAME thread @@ -262,7 +243,7 @@ bool AvPlayerState::IsActive() { return false; } return m_current_state != AvState::Stop && m_current_state != AvState::Error && - m_up_source->IsActive(); + m_current_state != AvState::EndOfFile && m_up_source->IsActive(); } u64 AvPlayerState::CurrentTime() { @@ -284,7 +265,9 @@ void AvPlayerState::OnError() { OnPlaybackStateChanged(AvState::Error); } -void AvPlayerState::OnEOF() {} +void AvPlayerState::OnEOF() { + SetState(AvState::EndOfFile); +} // Called inside CONTROLLER thread void AvPlayerState::OnPlaybackStateChanged(AvState state) { @@ -347,16 +330,16 @@ void AvPlayerState::EmitEvent(SceAvPlayerEvents event_id, void* event_data) { } // Called inside CONTROLLER thread -int AvPlayerState::ProcessEvent() { +void AvPlayerState::ProcessEvent() { if (m_current_state == AvState::Jump) { - return -2; + return; } std::lock_guard guard(m_event_handler_mutex); auto event = m_event_queue.Pop(); if (!event.has_value()) { - return -1; + return; } switch (event->event) { case AvEventType::WarningId: { @@ -385,16 +368,14 @@ int AvPlayerState::ProcessEvent() { default: break; } - - return 0; } // Called inside CONTROLLER thread -int AvPlayerState::UpdateBufferingState() { +void AvPlayerState::UpdateBufferingState() { if (m_current_state == AvState::Buffering) { const auto has_frames = OnBufferingCheckEvent(10); if (!has_frames.has_value()) { - return -1; + return; } if (has_frames.value()) { const auto state = @@ -405,14 +386,13 @@ int AvPlayerState::UpdateBufferingState() { } else if (m_current_state == AvState::Play) { const auto has_frames = OnBufferingCheckEvent(0); if (!has_frames.has_value()) { - return -1; + return; } if (!has_frames.value()) { SetState(AvState::Buffering); OnPlaybackStateChanged(AvState::Buffering); } } - return 0; } bool AvPlayerState::IsStateTransitionValid(AvState state) { diff --git a/src/core/libraries/avplayer/avplayer_state.h b/src/core/libraries/avplayer/avplayer_state.h index cfddab09..8aacc575 100644 --- a/src/core/libraries/avplayer/avplayer_state.h +++ b/src/core/libraries/avplayer/avplayer_state.h @@ -10,6 +10,9 @@ #include "core/libraries/kernel/thread_management.h" #include +#include +#include +#include namespace Libraries::AvPlayer { @@ -18,7 +21,7 @@ class AvDecoder; class AvPlayerState : public AvPlayerStateCallback { public: - AvPlayerState(const SceAvPlayerInitData& init_data, const ThreadPriorities& priorities); + AvPlayerState(const SceAvPlayerInitData& init_data); ~AvPlayerState(); s32 AddSource(std::string_view filename, SceAvPlayerSourceType source_type); @@ -51,34 +54,32 @@ private: void EmitEvent(SceAvPlayerEvents event_id, void* event_data = nullptr); bool SetState(AvState state); - static void* PS4_SYSV_ABI AvControllerThread(void* p_user_data); + void AvControllerThread(std::stop_token stop); void AddSourceEvent(); void WarningEvent(s32 id); - int StartControllerThread(); - int ProcessEvent(); - int UpdateBufferingState(); + void StartControllerThread(); + void ProcessEvent(); + void UpdateBufferingState(); bool IsStateTransitionValid(AvState state); std::unique_ptr m_up_source; SceAvPlayerInitData m_init_data{}; SceAvPlayerEventReplacement m_event_replacement{}; - ThreadPriorities m_thread_priorities{}; bool m_auto_start{}; u8 m_default_language[4]{}; - std::atomic_bool m_quit; std::atomic m_current_state; std::atomic m_previous_state; u32 m_thread_priority; u32 m_thread_affinity; std::atomic_uint32_t m_some_event_result{}; - PthreadMutex m_state_machine_mutex{}; - PthreadMutex m_event_handler_mutex{}; - ScePthread m_controller_thread{}; + std::mutex m_state_machine_mutex{}; + std::mutex m_event_handler_mutex{}; + std::jthread m_controller_thread{}; AvPlayerQueue m_event_queue{}; }; diff --git a/src/core/libraries/kernel/thread_management.h b/src/core/libraries/kernel/thread_management.h index bd555ccc..c5935275 100644 --- a/src/core/libraries/kernel/thread_management.h +++ b/src/core/libraries/kernel/thread_management.h @@ -158,24 +158,19 @@ void init_pthreads(); void pthreadInitSelfMainThread(); int PS4_SYSV_ABI scePthreadAttrInit(ScePthreadAttr* attr); -int PS4_SYSV_ABI scePthreadAttrDestroy(ScePthreadAttr* attr); int PS4_SYSV_ABI scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachstate); int PS4_SYSV_ABI scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inheritSched); int PS4_SYSV_ABI scePthreadAttrSetschedparam(ScePthreadAttr* attr, const SceKernelSchedParam* param); int PS4_SYSV_ABI scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy); +ScePthread PS4_SYSV_ABI scePthreadSelf(); int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr, const /*SceKernelCpumask*/ u64 mask); -int PS4_SYSV_ABI scePthreadAttrSetstacksize(ScePthreadAttr* attr, size_t stack_size); - -ScePthread PS4_SYSV_ABI scePthreadSelf(); int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpumask*/ u64 mask); int PS4_SYSV_ABI scePthreadGetaffinity(ScePthread thread, /*SceKernelCpumask*/ u64* mask); int PS4_SYSV_ABI scePthreadCreate(ScePthread* thread, const ScePthreadAttr* attr, PthreadEntryFunc start_routine, void* arg, const char* name); -[[noreturn]] void PS4_SYSV_ABI scePthreadExit(void* value_ptr); -int PS4_SYSV_ABI scePthreadJoin(ScePthread thread, void** res); -int PS4_SYSV_ABI scePthreadGetprio(ScePthread thread, int* prio); + int PS4_SYSV_ABI scePthreadSetprio(ScePthread thread, int prio); /*** @@ -183,14 +178,11 @@ int PS4_SYSV_ABI scePthreadSetprio(ScePthread thread, int prio); */ int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr, const char* name); -int PS4_SYSV_ABI scePthreadMutexDestroy(ScePthreadMutex* mutex); -int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex); -int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex); - -int PS4_SYSV_ABI scePthreadMutexattrDestroy(ScePthreadMutexattr* attr); int PS4_SYSV_ABI scePthreadMutexattrInit(ScePthreadMutexattr* attr); int PS4_SYSV_ABI scePthreadMutexattrSettype(ScePthreadMutexattr* attr, int type); int PS4_SYSV_ABI scePthreadMutexattrSetprotocol(ScePthreadMutexattr* attr, int protocol); +int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex); +int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex); /**** * Cond calls */ diff --git a/src/core/libraries/kernel/time_management.h b/src/core/libraries/kernel/time_management.h index 8934171d..a28f8c13 100644 --- a/src/core/libraries/kernel/time_management.h +++ b/src/core/libraries/kernel/time_management.h @@ -50,7 +50,6 @@ u64 PS4_SYSV_ABI sceKernelGetProcessTime(); u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounter(); u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounterFrequency(); u64 PS4_SYSV_ABI sceKernelReadTsc(); -int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds); void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym); diff --git a/src/core/libraries/save_data/savedata.cpp b/src/core/libraries/save_data/savedata.cpp index 64237994..98ff4fdd 100644 --- a/src/core/libraries/save_data/savedata.cpp +++ b/src/core/libraries/save_data/savedata.cpp @@ -792,10 +792,11 @@ int PS4_SYSV_ABI sceSaveDataTransferringMount() { } s32 PS4_SYSV_ABI sceSaveDataUmount(const OrbisSaveDataMountPoint* mountPoint) { - LOG_INFO(Lib_SaveData, "mountPoint = {}", std::string(mountPoint->data)); - if (std::string(mountPoint->data).empty()) { + if (mountPoint->data == nullptr) { + LOG_WARNING(Lib_SaveData, "mountPoint = nullptr"); return ORBIS_SAVE_DATA_ERROR_NOT_MOUNTED; } + LOG_INFO(Lib_SaveData, "mountPoint = {}", mountPoint->data); const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / std::to_string(1) / game_serial / mountPoint->data; auto* mnt = Common::Singleton::Instance();