Split SetRunning into Start and Stop

This commit is contained in:
Dr. Dystopia 2024-12-22 13:40:27 +01:00
parent 6c5aed38b3
commit 4de290dc6f
15 changed files with 198 additions and 151 deletions

View File

@ -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<std::mutex>{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<std::mutex>{cv_m}.unlock();

View File

@ -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; }

View File

@ -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.");

View File

@ -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();

View File

@ -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:

View File

@ -8,7 +8,12 @@ bool NullSound::Init()
return true;
}
bool NullSound::SetRunning(bool running)
bool NullSound::Start()
{
return true;
}
bool NullSound::Stop()
{
return true;
}

View File

@ -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; }

View File

@ -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;
}

View File

@ -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();

View File

@ -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)

View File

@ -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; }

View File

@ -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);

View File

@ -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; }
};

View File

@ -168,150 +168,150 @@ bool WASAPIStream::Init()
return true;
}
bool WASAPIStream::SetRunning(bool running)
bool WASAPIStream::Start()
{
if (running)
ComPtr<IMMDevice> device;
HRESULT result;
if (Config::Get(Config::MAIN_WASAPI_DEVICE) == "default")
{
ComPtr<IMMDevice> 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<IPropertyStore> 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<IAudioClient> audio_client;
// Get IAudioDevice
result = device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr,
reinterpret_cast<LPVOID*>(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<WAVEFORMATEX*>(&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<IPropertyStore> 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<IAudioClient> audio_client;
// Get IAudioDevice
result = device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr,
reinterpret_cast<LPVOID*>(audio_client.GetAddressOf()));
reinterpret_cast<LPVOID*>(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<REFERENCE_TIME>(
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<WAVEFORMATEX*>(&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<LPVOID*>(audio_client.ReleaseAndGetAddressOf()));
if (!HandleWinAPI("Failed to reactivate IAudioClient", result))
return false;
device_period =
static_cast<REFERENCE_TIME>(
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<WAVEFORMATEX*>(&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<IAudioRenderClient> 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<IAudioRenderClient> 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;
}

View File

@ -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<std::string> GetAvailableDevices();