diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp index dfc3d6ea24..1dcbb6ceae 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -10,6 +10,8 @@ LOG_CHANNEL(cellAudio); +extern void lv2_sleep(u64 timeout, ppu_thread* ppu = nullptr); + vm::gvar g_audio_buffer; struct alignas(16) aligned_index_t @@ -1252,8 +1254,6 @@ error_code cellAudioPortOpen(vm::ptr audioParam, vm::ptrget(); - std::lock_guard lock(g_audio.mutex); - if (!g_audio.init) { return CELL_AUDIO_ERROR_NOT_INIT; @@ -1319,6 +1319,16 @@ error_code cellAudioPortOpen(vm::ptr audioParam, vm::ptrget(); - std::lock_guard lock(g_audio.mutex); - if (!g_audio.init) { return CELL_AUDIO_ERROR_NOT_INIT; @@ -1422,6 +1430,16 @@ error_code cellAudioPortStart(u32 portNum) return CELL_AUDIO_ERROR_PARAM; } + // Waiting for VSH + lv2_sleep(30); + + std::lock_guard lock(g_audio.mutex); + + if (!g_audio.init) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + switch (audio_port_state state = g_audio.ports[portNum].state.compare_and_swap(audio_port_state::opened, audio_port_state::started)) { case audio_port_state::closed: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; @@ -1650,10 +1668,69 @@ error_code cellAudioCreateNotifyEventQueueEx(ppu_thread& ppu, vm::ptr id, v return AudioCreateNotifyEventQueue(ppu, id, key, queue_type); } -error_code AudioSetNotifyEventQueue(u64 key, u32 iFlags) +error_code AudioSetNotifyEventQueue(ppu_thread& ppu, u64 key, u32 iFlags) { auto& g_audio = g_fxo->get(); + if (!g_audio.init) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + // Waiting for VSH + lv2_sleep(20, &ppu); + + // Dirty hack for sound: confirm the creation of _mxr000 event queue by _cellsurMixerMain thread + constexpr u64 c_mxr000 = 0x8000cafe0246030; + + if (key == c_mxr000 || key == 0) + { + bool has_sur_mixer_thread = false; + + for (usz count = 0; !lv2_event_queue::find(c_mxr000) && count < 100; count++) + { + if (has_sur_mixer_thread || idm::select>([&](u32 id, named_thread& test_ppu) + { + // Confirm thread existence + if (id == ppu.id) + { + return false; + } + + const auto ptr = test_ppu.ppu_tname.load(); + + if (!ptr) + { + return false; + } + + return *ptr == "_cellsurMixerMain"sv; + }).ret) + { + has_sur_mixer_thread = true; + } + else + { + break; + } + + if (ppu.is_stopped()) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellAudio.error("AudioSetNotifyEventQueue(): Waiting for _mxr000. x%d", count); + + lv2_sleep(50'000, &ppu); + } + + if (has_sur_mixer_thread && lv2_event_queue::find(c_mxr000)) + { + key = c_mxr000; + } + } + std::lock_guard lock(g_audio.mutex); if (!g_audio.init) @@ -1687,27 +1764,33 @@ error_code AudioSetNotifyEventQueue(u64 key, u32 iFlags) } // Set unique source associated with the key - g_audio.keys.push_back({ + g_audio.keys.push_back + ({ .start_period = g_audio.event_period, .flags = iFlags, .source = ((process_getpid() + u64{}) << 32) + lv2_event_port::id_base + (g_audio.key_count++ * lv2_event_port::id_step), .ack_timestamp = 0, .port = std::move(q) }); + g_audio.key_count %= lv2_event_port::id_count; return CELL_OK; } -error_code cellAudioSetNotifyEventQueue(u64 key) +error_code cellAudioSetNotifyEventQueue(ppu_thread& ppu, u64 key) { + ppu.state += cpu_flag::wait; + cellAudio.warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key); - return AudioSetNotifyEventQueue(key, 0); + return AudioSetNotifyEventQueue(ppu, key, 0); } -error_code cellAudioSetNotifyEventQueueEx(u64 key, u32 iFlags) +error_code cellAudioSetNotifyEventQueueEx(ppu_thread& ppu, u64 key, u32 iFlags) { + ppu.state += cpu_flag::wait; + cellAudio.todo("cellAudioSetNotifyEventQueueEx(key=0x%llx, iFlags=0x%x)", key, iFlags); if (iFlags & (~0u >> 5)) @@ -1715,7 +1798,7 @@ error_code cellAudioSetNotifyEventQueueEx(u64 key, u32 iFlags) return CELL_AUDIO_ERROR_PARAM; } - return AudioSetNotifyEventQueue(key, iFlags); + return AudioSetNotifyEventQueue(ppu, key, iFlags); } error_code AudioRemoveNotifyEventQueue(u64 key, u32 iFlags) diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index 61f9dbc95a..27766431d3 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -349,7 +349,7 @@ void disc_change_manager::insert_disc(u32 disc_type, std::string title_id) }); } -void lv2_sleep(u64 timeout, ppu_thread* ppu = nullptr) +extern void lv2_sleep(u64 timeout, ppu_thread* ppu = nullptr) { if (!ppu) { diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 1440a32883..e933549c65 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -591,32 +591,6 @@ error_code sys_ppu_thread_start(ppu_thread& ppu, u32 thread_id) { thread->cmd_notify++; thread->cmd_notify.notify_one(); - - // Dirty hack for sound: confirm the creation of _mxr000 event queue - if (*thread->ppu_tname.load() == "_cellsurMixerMain"sv) - { - ppu.check_state(); - lv2_obj::sleep(ppu); - - while (!idm::select([](u32, lv2_event_queue& eq) - { - //some games do not set event queue name, though key seems constant for them - return (eq.name == "_mxr000\0"_u64) || (eq.key == 0x8000cafe02460300); - })) - { - if (ppu.is_stopped()) - { - return {}; - } - - thread_ctrl::wait_for(50000); - } - - if (ppu.test_stopped()) - { - return 0; - } - } } return CELL_OK;