diff --git a/Source/Core/AudioCommon/AlsaSoundStream.cpp b/Source/Core/AudioCommon/AlsaSoundStream.cpp index b9e817331c..467558dae5 100644 --- a/Source/Core/AudioCommon/AlsaSoundStream.cpp +++ b/Source/Core/AudioCommon/AlsaSoundStream.cpp @@ -77,9 +77,21 @@ void AlsaSound::SoundLoop() m_thread_status.store(ALSAThreadStatus::STOPPED); } -bool AlsaSound::SetRunning(bool running) +bool AlsaSound::Start() { - m_thread_status.store(running ? ALSAThreadStatus::RUNNING : ALSAThreadStatus::PAUSED); + m_thread_status.store(ALSAThreadStatus::RUNNING); + + // Immediately lock and unlock mutex to prevent cv race. + std::unique_lock{cv_m}.unlock(); + + // Notify thread that status has changed + cv.notify_one(); + return true; +} + +bool AlsaSound::Stop() +{ + m_thread_status.store(ALSAThreadStatus::PAUSED); // Immediately lock and unlock mutex to prevent cv race. std::unique_lock{cv_m}.unlock(); diff --git a/Source/Core/AudioCommon/AlsaSoundStream.h b/Source/Core/AudioCommon/AlsaSoundStream.h index d3e34386a7..99103c8966 100644 --- a/Source/Core/AudioCommon/AlsaSoundStream.h +++ b/Source/Core/AudioCommon/AlsaSoundStream.h @@ -23,7 +23,8 @@ public: ~AlsaSound() override; bool Init() override; - bool SetRunning(bool running) override; + bool Start() override; + bool Stop() override; static bool IsValid() { return true; } diff --git a/Source/Core/AudioCommon/AudioCommon.cpp b/Source/Core/AudioCommon/AudioCommon.cpp index 51b4347dee..32dbe0b456 100644 --- a/Source/Core/AudioCommon/AudioCommon.cpp +++ b/Source/Core/AudioCommon/AudioCommon.cpp @@ -182,7 +182,7 @@ void StartSoundStream(Core::System& system) system.StartSoundStream(); - if (sound_stream->SetRunning(true)) + if (sound_stream->Start()) return; ERROR_LOG_FMT(AUDIO, "Error starting stream."); @@ -200,7 +200,7 @@ void StopSoundStream(Core::System& system) system.StopSoundStream(); - if (sound_stream->SetRunning(false)) + if (sound_stream->Stop()) return; ERROR_LOG_FMT(AUDIO, "Error stopping stream."); diff --git a/Source/Core/AudioCommon/CubebStream.cpp b/Source/Core/AudioCommon/CubebStream.cpp index 92ab886580..33b8655a31 100644 --- a/Source/Core/AudioCommon/CubebStream.cpp +++ b/Source/Core/AudioCommon/CubebStream.cpp @@ -105,8 +105,9 @@ bool CubebStream::Init() return return_value; } -bool CubebStream::SetRunning(bool running) +bool CubebStream::Start() { + bool running = true; bool return_value = false; #ifdef _WIN32 @@ -116,10 +117,28 @@ bool CubebStream::SetRunning(bool running) m_work_queue.EmplaceItem([this, running, &return_value, &sync_event] { Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); #endif - if (running) - return_value = cubeb_stream_start(m_stream) == CUBEB_OK; - else - return_value = cubeb_stream_stop(m_stream) == CUBEB_OK; + return_value = cubeb_stream_start(m_stream) == CUBEB_OK; +#ifdef _WIN32 + }); + sync_event.Wait(); +#endif + + return return_value; +} + +bool CubebStream::Stop() +{ + bool running = false; + bool return_value = false; + +#ifdef _WIN32 + if (!m_coinit_success) + return false; + Common::Event sync_event; + m_work_queue.EmplaceItem([this, running, &return_value, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); +#endif + return_value = cubeb_stream_stop(m_stream) == CUBEB_OK; #ifdef _WIN32 }); sync_event.Wait(); diff --git a/Source/Core/AudioCommon/CubebStream.h b/Source/Core/AudioCommon/CubebStream.h index 4b0c0e5eae..155efbe4a2 100644 --- a/Source/Core/AudioCommon/CubebStream.h +++ b/Source/Core/AudioCommon/CubebStream.h @@ -23,7 +23,8 @@ public: CubebStream& operator=(CubebStream&& other) = delete; ~CubebStream() override; bool Init() override; - bool SetRunning(bool running) override; + bool Start() override; + bool Stop() override; void SetVolume(int) override; private: diff --git a/Source/Core/AudioCommon/NullSoundStream.cpp b/Source/Core/AudioCommon/NullSoundStream.cpp index 3c7a0ebb98..f140df07ec 100644 --- a/Source/Core/AudioCommon/NullSoundStream.cpp +++ b/Source/Core/AudioCommon/NullSoundStream.cpp @@ -8,7 +8,12 @@ bool NullSound::Init() return true; } -bool NullSound::SetRunning(bool running) +bool NullSound::Start() +{ + return true; +} + +bool NullSound::Stop() { return true; } diff --git a/Source/Core/AudioCommon/NullSoundStream.h b/Source/Core/AudioCommon/NullSoundStream.h index f186787900..a9d1e5cb53 100644 --- a/Source/Core/AudioCommon/NullSoundStream.h +++ b/Source/Core/AudioCommon/NullSoundStream.h @@ -9,7 +9,8 @@ class NullSound final : public SoundStream { public: bool Init() override; - bool SetRunning(bool running) override; + bool Start() override; + bool Stop() override; void SetVolume(int volume) override; static bool IsValid() { return true; } diff --git a/Source/Core/AudioCommon/OpenALStream.cpp b/Source/Core/AudioCommon/OpenALStream.cpp index cdd44501ca..9cde5f1b46 100644 --- a/Source/Core/AudioCommon/OpenALStream.cpp +++ b/Source/Core/AudioCommon/OpenALStream.cpp @@ -153,16 +153,15 @@ void OpenALStream::SetVolume(int volume) palSourcef(m_source, AL_GAIN, m_volume); } -bool OpenALStream::SetRunning(bool running) +bool OpenALStream::Start() { - if (running) - { - palSourcePlay(m_source); - } - else - { - palSourceStop(m_source); - } + palSourcePlay(m_source); + return true; +} + +bool OpenALStream::Stop() +{ + palSourceStop(m_source); return true; } diff --git a/Source/Core/AudioCommon/OpenALStream.h b/Source/Core/AudioCommon/OpenALStream.h index 812f0a9019..0f808c9fca 100644 --- a/Source/Core/AudioCommon/OpenALStream.h +++ b/Source/Core/AudioCommon/OpenALStream.h @@ -57,7 +57,8 @@ public: ~OpenALStream() override; bool Init() override; void SetVolume(int volume) override; - bool SetRunning(bool running) override; + bool Start() override; + bool Stop() override; static bool IsValid(); diff --git a/Source/Core/AudioCommon/OpenSLESStream.cpp b/Source/Core/AudioCommon/OpenSLESStream.cpp index a3f6308187..1ad239681c 100644 --- a/Source/Core/AudioCommon/OpenSLESStream.cpp +++ b/Source/Core/AudioCommon/OpenSLESStream.cpp @@ -137,10 +137,14 @@ OpenSLESStream::~OpenSLESStream() } } -bool OpenSLESStream::SetRunning(bool running) +bool OpenSLESStream::Start() { - SLuint32 new_state = running ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED; - return (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, new_state) == SL_RESULT_SUCCESS; + return (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING) == SL_RESULT_SUCCESS; +} + +bool OpenSLESStream::Stop() +{ + return (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED) == SL_RESULT_SUCCESS; } void OpenSLESStream::SetVolume(int volume) diff --git a/Source/Core/AudioCommon/OpenSLESStream.h b/Source/Core/AudioCommon/OpenSLESStream.h index f22aaf9a0f..1c11accf2a 100644 --- a/Source/Core/AudioCommon/OpenSLESStream.h +++ b/Source/Core/AudioCommon/OpenSLESStream.h @@ -14,7 +14,8 @@ class OpenSLESStream final : public SoundStream public: ~OpenSLESStream() override; bool Init() override; - bool SetRunning(bool running) override; + bool Start() override; + bool Stop() override; void SetVolume(int volume) override; static bool IsValid() { return true; } diff --git a/Source/Core/AudioCommon/PulseAudioStream.h b/Source/Core/AudioCommon/PulseAudioStream.h index acbf0dadcb..a9cdb819ec 100644 --- a/Source/Core/AudioCommon/PulseAudioStream.h +++ b/Source/Core/AudioCommon/PulseAudioStream.h @@ -20,7 +20,8 @@ public: ~PulseAudio() override; bool Init() override; - bool SetRunning(bool running) override { return true; } + bool Start() override { return true; } + bool Stop() override { return true; } static bool IsValid() { return true; } void StateCallback(pa_context* c); void WriteCallback(pa_stream* s, size_t length); diff --git a/Source/Core/AudioCommon/SoundStream.h b/Source/Core/AudioCommon/SoundStream.h index 9e1be0d33f..b1e124f344 100644 --- a/Source/Core/AudioCommon/SoundStream.h +++ b/Source/Core/AudioCommon/SoundStream.h @@ -21,5 +21,6 @@ public: virtual bool Init() { return false; } virtual void SetVolume(int) {} // Returns true if successful. - virtual bool SetRunning(bool running) { return false; } + virtual bool Start() { return false; } + virtual bool Stop() { return false; } }; diff --git a/Source/Core/AudioCommon/WASAPIStream.cpp b/Source/Core/AudioCommon/WASAPIStream.cpp index dddc1f6ebb..e4784d8cec 100644 --- a/Source/Core/AudioCommon/WASAPIStream.cpp +++ b/Source/Core/AudioCommon/WASAPIStream.cpp @@ -168,150 +168,150 @@ bool WASAPIStream::Init() return true; } -bool WASAPIStream::SetRunning(bool running) +bool WASAPIStream::Start() { - if (running) + ComPtr device; + + HRESULT result; + + if (Config::Get(Config::MAIN_WASAPI_DEVICE) == "default") { - ComPtr device; + result = m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, device.GetAddressOf()); + } + else + { + result = S_OK; + device = GetDeviceByName(Config::Get(Config::MAIN_WASAPI_DEVICE)); - HRESULT result; - - if (Config::Get(Config::MAIN_WASAPI_DEVICE) == "default") + if (!device) { + ERROR_LOG_FMT(AUDIO, "Can't find device '{}', falling back to default", + Config::Get(Config::MAIN_WASAPI_DEVICE)); result = m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, device.GetAddressOf()); } - else - { - result = S_OK; - device = GetDeviceByName(Config::Get(Config::MAIN_WASAPI_DEVICE)); + } - if (!device) - { - ERROR_LOG_FMT(AUDIO, "Can't find device '{}', falling back to default", - Config::Get(Config::MAIN_WASAPI_DEVICE)); - result = m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, device.GetAddressOf()); - } - } + if (!HandleWinAPI("Failed to obtain default endpoint", result)) + return false; - if (!HandleWinAPI("Failed to obtain default endpoint", result)) + // Show a friendly name in the log + ComPtr device_properties; + + result = device->OpenPropertyStore(STGM_READ, device_properties.GetAddressOf()); + + if (!HandleWinAPI("Failed to initialize IPropertyStore", result)) + return false; + + wil::unique_prop_variant device_name; + device_properties->GetValue(PKEY_Device_FriendlyName, device_name.addressof()); + + INFO_LOG_FMT(AUDIO, "Using audio endpoint '{}'", TStrToUTF8(device_name.pwszVal)); + + ComPtr audio_client; + + // Get IAudioDevice + result = device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr, + reinterpret_cast(audio_client.GetAddressOf())); + + if (!HandleWinAPI("Failed to activate IAudioClient", result)) + return false; + + REFERENCE_TIME device_period = 0; + + result = audio_client->GetDevicePeriod(nullptr, &device_period); + + device_period += Config::Get(Config::MAIN_AUDIO_LATENCY) * (10000 / m_format.Format.nChannels); + INFO_LOG_FMT(AUDIO, "Audio period set to {}", device_period); + + if (!HandleWinAPI("Failed to obtain device period", result)) + return false; + + result = audio_client->Initialize( + AUDCLNT_SHAREMODE_EXCLUSIVE, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, device_period, + device_period, reinterpret_cast(&m_format), nullptr); + + if (result == AUDCLNT_E_UNSUPPORTED_FORMAT) + { + OSD::AddMessage("Your current audio device doesn't support 16-bit 48000 hz PCM audio. WASAPI " + "exclusive mode won't work.", + 6000U); + return false; + } + + if (result == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) + { + result = audio_client->GetBufferSize(&m_frames_in_buffer); + + if (!HandleWinAPI("Failed to get aligned buffer size", result)) return false; - // Show a friendly name in the log - ComPtr device_properties; - - result = device->OpenPropertyStore(STGM_READ, device_properties.GetAddressOf()); - - if (!HandleWinAPI("Failed to initialize IPropertyStore", result)) - return false; - - wil::unique_prop_variant device_name; - device_properties->GetValue(PKEY_Device_FriendlyName, device_name.addressof()); - - INFO_LOG_FMT(AUDIO, "Using audio endpoint '{}'", TStrToUTF8(device_name.pwszVal)); - - ComPtr audio_client; - // Get IAudioDevice result = device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr, - reinterpret_cast(audio_client.GetAddressOf())); + reinterpret_cast(audio_client.ReleaseAndGetAddressOf())); - if (!HandleWinAPI("Failed to activate IAudioClient", result)) + if (!HandleWinAPI("Failed to reactivate IAudioClient", result)) return false; - REFERENCE_TIME device_period = 0; - - result = audio_client->GetDevicePeriod(nullptr, &device_period); - - device_period += Config::Get(Config::MAIN_AUDIO_LATENCY) * (10000 / m_format.Format.nChannels); - INFO_LOG_FMT(AUDIO, "Audio period set to {}", device_period); - - if (!HandleWinAPI("Failed to obtain device period", result)) - return false; + device_period = + static_cast( + 10000.0 * 1000 * m_frames_in_buffer / m_format.Format.nSamplesPerSec + 0.5) + + Config::Get(Config::MAIN_AUDIO_LATENCY) * 10000; result = audio_client->Initialize( AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, device_period, device_period, reinterpret_cast(&m_format), nullptr); - - if (result == AUDCLNT_E_UNSUPPORTED_FORMAT) - { - OSD::AddMessage("Your current audio device doesn't support 16-bit 48000 hz PCM audio. WASAPI " - "exclusive mode won't work.", - 6000U); - return false; - } - - if (result == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) - { - result = audio_client->GetBufferSize(&m_frames_in_buffer); - - if (!HandleWinAPI("Failed to get aligned buffer size", result)) - return false; - - // Get IAudioDevice - result = device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr, - reinterpret_cast(audio_client.ReleaseAndGetAddressOf())); - - if (!HandleWinAPI("Failed to reactivate IAudioClient", result)) - return false; - - device_period = - static_cast( - 10000.0 * 1000 * m_frames_in_buffer / m_format.Format.nSamplesPerSec + 0.5) + - Config::Get(Config::MAIN_AUDIO_LATENCY) * 10000; - - result = audio_client->Initialize( - AUDCLNT_SHAREMODE_EXCLUSIVE, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, device_period, - device_period, reinterpret_cast(&m_format), nullptr); - } - - if (!HandleWinAPI("Failed to initialize IAudioClient", result)) - return false; - - result = audio_client->GetBufferSize(&m_frames_in_buffer); - - if (!HandleWinAPI("Failed to get buffer size from IAudioClient", result)) - return false; - - ComPtr audio_renderer; - - result = audio_client->GetService(IID_PPV_ARGS(audio_renderer.GetAddressOf())); - - if (!HandleWinAPI("Failed to get IAudioRenderClient from IAudioClient", result)) - return false; - - wil::unique_event_nothrow need_data_event; - need_data_event.create(); - - audio_client->SetEventHandle(need_data_event.get()); - - result = audio_client->Start(); - - if (!HandleWinAPI("Failed to get IAudioRenderClient from IAudioClient", result)) - return false; - - INFO_LOG_FMT(AUDIO, "WASAPI: Successfully initialized!"); - - // "Commit" audio client and audio renderer now - m_audio_client = std::move(audio_client); - m_audio_renderer = std::move(audio_renderer); - m_need_data_event = std::move(need_data_event); - - m_running.store(true, std::memory_order_relaxed); - m_thread = std::thread(&WASAPIStream::SoundLoop, this); } - else - { - m_running.store(false, std::memory_order_relaxed); - if (m_thread.joinable()) - m_thread.join(); + if (!HandleWinAPI("Failed to initialize IAudioClient", result)) + return false; - m_need_data_event.reset(); - m_audio_renderer.Reset(); - m_audio_client.Reset(); - } + result = audio_client->GetBufferSize(&m_frames_in_buffer); + + if (!HandleWinAPI("Failed to get buffer size from IAudioClient", result)) + return false; + + ComPtr audio_renderer; + + result = audio_client->GetService(IID_PPV_ARGS(audio_renderer.GetAddressOf())); + + if (!HandleWinAPI("Failed to get IAudioRenderClient from IAudioClient", result)) + return false; + + wil::unique_event_nothrow need_data_event; + need_data_event.create(); + + audio_client->SetEventHandle(need_data_event.get()); + + result = audio_client->Start(); + + if (!HandleWinAPI("Failed to get IAudioRenderClient from IAudioClient", result)) + return false; + + INFO_LOG_FMT(AUDIO, "WASAPI: Successfully initialized!"); + + // "Commit" audio client and audio renderer now + m_audio_client = std::move(audio_client); + m_audio_renderer = std::move(audio_renderer); + m_need_data_event = std::move(need_data_event); + + m_running.store(true, std::memory_order_relaxed); + m_thread = std::thread(&WASAPIStream::SoundLoop, this); + + return true; +} + +bool WASAPIStream::Stop() +{ + m_running.store(false, std::memory_order_relaxed); + + if (m_thread.joinable()) + m_thread.join(); + + m_need_data_event.reset(); + m_audio_renderer.Reset(); + m_audio_client.Reset(); return true; } diff --git a/Source/Core/AudioCommon/WASAPIStream.h b/Source/Core/AudioCommon/WASAPIStream.h index 6f3218cc4b..b752669dde 100644 --- a/Source/Core/AudioCommon/WASAPIStream.h +++ b/Source/Core/AudioCommon/WASAPIStream.h @@ -34,7 +34,8 @@ public: explicit WASAPIStream(); ~WASAPIStream(); bool Init() override; - bool SetRunning(bool running) override; + bool Start() override; + bool Stop() override; static bool IsValid(); static std::vector GetAvailableDevices();