diff --git a/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp b/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp index e061012669..450247b12b 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp @@ -15,6 +15,9 @@ #include "Common/ScopeGuard.h" #include "Common/Swap.h" #include "Core/Config/MainSettings.h" +#include "Core/Core.h" +#include "Core/IOS/USB/Emulated/WiiSpeak.h" +#include "Core/System.h" #ifdef _WIN32 #include @@ -22,7 +25,7 @@ namespace IOS::HLE::USB { -Microphone::Microphone() +Microphone::Microphone(const WiiSpeakState& sampler) : m_sampler(sampler) { #if defined(_WIN32) && defined(HAVE_CUBEB) m_work_queue.PushBlocking([this] { @@ -175,6 +178,15 @@ void Microphone::StreamStop() long Microphone::CubebDataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, void* /*output_buffer*/, long nframes) { + // Skip data when core isn't running + if (Core::GetState(Core::System::GetInstance()) != Core::State::Running) + return nframes; + + // Skip data when HLE Wii Speak is not connected + // TODO: Update cubeb and use cubeb_stream_set_input_mute + if (!Config::Get(Config::MAIN_WII_SPEAK_CONNECTED)) + return nframes; + auto* mic = static_cast(user_data); return mic->DataCallback(static_cast(input_buffer), nframes); } @@ -183,6 +195,10 @@ long Microphone::DataCallback(const s16* input_buffer, long nframes) { std::lock_guard lock(m_ring_lock); + // Skip data if sampling is off or mute is on + if (!m_sampler.sample_on || m_sampler.mute) + return nframes; + const s16* buff_in = static_cast(input_buffer); for (long i = 0; i < nframes; i++) { @@ -229,9 +245,9 @@ void Microphone::ReadIntoBuffer(u8* dst, u32 size) } } -bool Microphone::HasData() const +bool Microphone::HasData(u32 sample_count = BUFF_SIZE_SAMPLES) const { std::lock_guard lock(m_ring_lock); - return m_samples_avail > 0 && Config::Get(Config::MAIN_WII_SPEAK_CONNECTED); + return m_samples_avail >= sample_count; } } // namespace IOS::HLE::USB diff --git a/Source/Core/Core/IOS/USB/Emulated/Microphone.h b/Source/Core/Core/IOS/USB/Emulated/Microphone.h index 58264eafd1..227d9926b4 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Microphone.h +++ b/Source/Core/Core/IOS/USB/Emulated/Microphone.h @@ -19,13 +19,15 @@ struct cubeb_stream; namespace IOS::HLE::USB { +struct WiiSpeakState; + class Microphone final { public: - Microphone(); + Microphone(const WiiSpeakState& sampler); ~Microphone(); - bool HasData() const; + bool HasData(u32 sample_count) const; void ReadIntoBuffer(u8* dst, u32 size); private: @@ -53,6 +55,8 @@ private: mutable std::mutex m_ring_lock; + const WiiSpeakState& m_sampler; + #ifdef HAVE_CUBEB std::shared_ptr m_cubeb_ctx = nullptr; cubeb_stream* m_cubeb_stream = nullptr; diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp index 0e5ce62a2c..712292f240 100644 --- a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp @@ -43,7 +43,7 @@ bool WiiSpeak::Attach() DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x}] Opening device", m_vid, m_pid); if (!m_microphone) - m_microphone = std::make_unique(); + m_microphone = std::make_unique(m_sampler); m_device_attached = true; return true; } @@ -178,7 +178,7 @@ int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) { case ENDPOINT_AUDIO_IN: // Transfer: Wii Speak -> Wii - if (m_microphone && m_microphone->HasData()) + if (m_microphone && m_microphone->HasData(cmd->length / sizeof(s16))) m_microphone->ReadIntoBuffer(packets, cmd->length); break; case ENDPOINT_AUDIO_OUT: diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h index 6dc88e6456..3546d06851 100644 --- a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include @@ -12,6 +13,17 @@ namespace IOS::HLE::USB { +struct WiiSpeakState +{ + // Use atomic for members concurrently used by the data callback + std::atomic sample_on; + std::atomic mute; + int freq; + int gain; + bool ec_reset; + bool sp_on; +}; + class WiiSpeak final : public Device { public: @@ -34,17 +46,7 @@ public: int SubmitTransfer(std::unique_ptr message) override; private: - struct WSState - { - bool sample_on; - bool mute; - int freq; - int gain; - bool ec_reset; - bool sp_on; - }; - - WSState m_sampler{}; + WiiSpeakState m_sampler{}; enum Registers {