mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
@@ -32,5 +32,6 @@ public:
|
||||
virtual int BufferSize() const = 0;
|
||||
virtual int PeriodFrames() const = 0;
|
||||
virtual void DescribeOutputFormat(char *buffer, size_t bufferSize) const { buffer[0] = '-'; buffer[1] = '\0'; }
|
||||
virtual std::string GetCurrentDeviceName() const { return ""; }
|
||||
virtual void FrameUpdate(bool allowAutoChange) {}
|
||||
};
|
||||
|
||||
+1
-1
@@ -886,7 +886,7 @@ static const ConfigSetting soundSettings[] = {
|
||||
ConfigSetting("GamePreviewVolume", SETTING(g_Config, iGamePreviewVolume), &DefaultGamePreviewVolume, CfgFlag::DEFAULT),
|
||||
|
||||
ConfigSetting("AudioDevice", SETTING(g_Config, sAudioDevice), "", CfgFlag::DEFAULT),
|
||||
ConfigSetting("AutoAudioDevice", SETTING(g_Config, bAutoAudioDevice), true, CfgFlag::DEFAULT),
|
||||
ConfigSetting("AutoAudioDevice", SETTING(g_Config, bAutoSwitchAudioDevice), true, CfgFlag::DEFAULT),
|
||||
ConfigSetting("AudioMixWithOthers", SETTING(g_Config, bAudioMixWithOthers), true, CfgFlag::DEFAULT),
|
||||
ConfigSetting("AudioRespectSilentMode", SETTING(g_Config, bAudioRespectSilentMode), false, CfgFlag::DEFAULT),
|
||||
ConfigSetting("UseOldAtrac", SETTING(g_Config, bUseOldAtrac), false, CfgFlag::DEFAULT),
|
||||
|
||||
+1
-1
@@ -410,7 +410,7 @@ public:
|
||||
|
||||
bool bExtraAudioBuffering; // For bluetooth
|
||||
std::string sAudioDevice;
|
||||
bool bAutoAudioDevice;
|
||||
bool bAutoSwitchAudioDevice;
|
||||
bool bUseOldAtrac;
|
||||
|
||||
// iOS only for now
|
||||
|
||||
+1
-1
@@ -1290,7 +1290,7 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
|
||||
break;
|
||||
}
|
||||
// Don't start auto switching for a couple of seconds, because some devices init on start.
|
||||
bool doAutoSwitch = g_Config.bAutoAudioDevice;
|
||||
bool doAutoSwitch = g_Config.bAutoSwitchAudioDevice;
|
||||
if ((time_now_d() - g_audioStartTime) < 3.0) {
|
||||
INFO_LOG(Log::Audio, "Ignoring new audio device: %s (current: %s)", name, g_Config.sAudioDevice.c_str());
|
||||
doAutoSwitch = false;
|
||||
|
||||
@@ -796,7 +796,7 @@ void GameSettingsScreen::CreateAudioSettings(UI::ViewGroup *audioSettings) {
|
||||
WARN_LOG(Log::Audio, "InitOutputDevice failed");
|
||||
}
|
||||
});
|
||||
CheckBox *autoAudio = audioSettings->Add(new CheckBox(&g_Config.bAutoAudioDevice, a->T("Use new audio devices automatically")));
|
||||
CheckBox *autoAudio = audioSettings->Add(new CheckBox(&g_Config.bAutoSwitchAudioDevice, a->T("Use new audio devices automatically")));
|
||||
autoAudio->SetEnabledFunc([]()->bool {
|
||||
return g_Config.sAudioDevice.empty();
|
||||
});
|
||||
@@ -808,7 +808,7 @@ void GameSettingsScreen::CreateAudioSettings(UI::ViewGroup *audioSettings) {
|
||||
audioSettings->Add(new ItemHeader(a->T("Audio backend")));
|
||||
|
||||
if (sdlAudio) {
|
||||
audioSettings->Add(new CheckBox(&g_Config.bAutoAudioDevice, a->T("Use new audio devices automatically")));
|
||||
audioSettings->Add(new CheckBox(&g_Config.bAutoSwitchAudioDevice, a->T("Use new audio devices automatically")));
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
|
||||
+1
-1
@@ -1017,7 +1017,7 @@ void NativeFrame(GraphicsContext *graphicsContext) {
|
||||
g_iconCache.FrameUpdate();
|
||||
|
||||
if (g_audioBackend) {
|
||||
g_audioBackend->FrameUpdate(g_Config.bAutoAudioDevice);
|
||||
g_audioBackend->FrameUpdate(g_Config.bAutoSwitchAudioDevice);
|
||||
}
|
||||
|
||||
// NOTE: We must begin the frame before update, so we can do texture size queries and stuff in Measure etc.
|
||||
|
||||
@@ -152,7 +152,7 @@ bool WASAPIContext::InitOutputDevice(std::string_view uniqueId, LatencyMode late
|
||||
GetDeviceDesc(device.Get(), &desc);
|
||||
INFO_LOG(Log::Audio, "Activating audio device: %s", desc.name.c_str());
|
||||
|
||||
deviceId_ = uniqueId;
|
||||
curDeviceId_ = uniqueId;
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
// Try IAudioClient3 first if not in "safe" mode. It's probably safe anyway, but still, let's use the legacy client as a safe fallback option.
|
||||
@@ -242,6 +242,7 @@ bool WASAPIContext::InitOutputDevice(std::string_view uniqueId, LatencyMode late
|
||||
}
|
||||
} else {
|
||||
// All good, nothing to convert.
|
||||
_dbg_assert_(format_);
|
||||
}
|
||||
} else {
|
||||
// Some other format.
|
||||
@@ -291,13 +292,13 @@ bool WASAPIContext::InitOutputDevice(std::string_view uniqueId, LatencyMode late
|
||||
}
|
||||
|
||||
void WASAPIContext::Start() {
|
||||
_dbg_assert_(!audioThread_.joinable());
|
||||
running_ = true;
|
||||
audioThread_ = std::thread([this]() { AudioLoop(); });
|
||||
}
|
||||
|
||||
void WASAPIContext::Stop() {
|
||||
running_ = false;
|
||||
if (audioClient_) audioClient_->Stop();
|
||||
if (audioEvent_) SetEvent(audioEvent_);
|
||||
if (audioThread_.joinable()) audioThread_.join();
|
||||
|
||||
@@ -311,14 +312,37 @@ void WASAPIContext::Stop() {
|
||||
CoTaskMemFree(format_);
|
||||
format_ = nullptr;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(deviceLock_);
|
||||
curDeviceId_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void WASAPIContext::FrameUpdate(bool allowAutoChange) {
|
||||
if (deviceId_.empty() && defaultDeviceChanged_ && allowAutoChange) {
|
||||
defaultDeviceChanged_ = false;
|
||||
Stop();
|
||||
Start();
|
||||
std::string deviceIdToInit;
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(deviceLock_);
|
||||
if (!defaultDeviceChanged_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (allowAutoChange) {
|
||||
// Check if there actually was a change, we ignore false positives.
|
||||
{
|
||||
if (newDeviceId_ == curDeviceId_) {
|
||||
// False positive, ignore.
|
||||
defaultDeviceChanged_ = false;
|
||||
return;
|
||||
}
|
||||
deviceIdToInit = newDeviceId_;
|
||||
newDeviceId_.clear();
|
||||
}
|
||||
defaultDeviceChanged_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool reverted;
|
||||
InitOutputDevice(deviceIdToInit, latencyMode_, &reverted);
|
||||
}
|
||||
|
||||
void WASAPIContext::AudioLoop() {
|
||||
@@ -343,6 +367,11 @@ void WASAPIContext::AudioLoop() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!format_) {
|
||||
ERROR_LOG(Log::Audio, "Can't start audio - no format");
|
||||
return;
|
||||
}
|
||||
|
||||
const AudioFormat format = Classify(format_);
|
||||
const int nChannels = format_->nChannels;
|
||||
|
||||
@@ -445,3 +474,38 @@ void WASAPIContext::DescribeOutputFormat(char *buffer, size_t bufferSize) const
|
||||
}
|
||||
snprintf(buffer, bufferSize, "%d Hz %s %d-bit, %d ch%s", sampleRateHz, fmt, sampleBits, numChannels, audioClient3_ ? " (ac3)" : " (ac)");
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WASAPIContext::DeviceNotificationClient::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR device) {
|
||||
if (flow != eRender) {
|
||||
INFO_LOG(Log::Audio, "Default WASAPI audio recording device changed! Currently ignoring.");
|
||||
return S_OK;
|
||||
}
|
||||
INFO_LOG(Log::Audio, "Default device changed to %s! role=%d", ConvertWStringToUTF8(device).c_str(), role);
|
||||
if (role == eConsole) {
|
||||
// PostMessage(hwnd, WM_APP + 1, 0, 0);
|
||||
std::lock_guard<std::mutex> guard(engine_->deviceLock_);
|
||||
engine_->defaultDeviceChanged_ = true;
|
||||
engine_->newDeviceId_ = ConvertWStringToUTF8(device);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WASAPIContext::DeviceNotificationClient::OnDeviceAdded(LPCWSTR device) {
|
||||
INFO_LOG(Log::Audio, "Audio device added! device=%s", ConvertWStringToUTF8(device).c_str());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WASAPIContext::DeviceNotificationClient::OnDeviceRemoved(LPCWSTR device) {
|
||||
INFO_LOG(Log::Audio, "Audio device removed! device=%s", ConvertWStringToUTF8(device).c_str());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WASAPIContext::DeviceNotificationClient::OnDeviceStateChanged(LPCWSTR device, DWORD state) {
|
||||
INFO_LOG(Log::Audio, "Audio device state changed! device=%s state=%08x", ConvertWStringToUTF8(device).c_str(), state);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WASAPIContext::DeviceNotificationClient::OnPropertyValueChanged(LPCWSTR device, const PROPERTYKEY key) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
+16
-14
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Audio/AudioBackend.h"
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmdeviceapi.h>
|
||||
@@ -47,24 +48,22 @@ public:
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR) override {
|
||||
if (flow == eRender && role == eConsole) {
|
||||
// PostMessage(hwnd, WM_APP + 1, 0, 0);
|
||||
engine_->defaultDeviceChanged_ = true;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR) override { return S_OK; }
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR) override { return S_OK; }
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR, DWORD) override { return S_OK; }
|
||||
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) override { return S_OK; }
|
||||
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR device) override;
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR device) override;
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR device) override;
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR device, DWORD state) override;
|
||||
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR device, const PROPERTYKEY key) override;
|
||||
private:
|
||||
WASAPIContext *engine_;
|
||||
};
|
||||
|
||||
void DescribeOutputFormat(char *buffer, size_t bufferSize) const override;
|
||||
|
||||
std::string GetCurrentDeviceName() const override {
|
||||
std::lock_guard<std::mutex> guard(deviceLock_);
|
||||
return curDeviceId_;
|
||||
}
|
||||
|
||||
private:
|
||||
void Start();
|
||||
void Stop();
|
||||
@@ -95,8 +94,11 @@ private:
|
||||
RenderCallback callback_{};
|
||||
void *userdata_ = nullptr;
|
||||
LatencyMode latencyMode_ = LatencyMode::Aggressive;
|
||||
std::string deviceId_;
|
||||
std::atomic<bool> defaultDeviceChanged_{};
|
||||
|
||||
mutable std::mutex deviceLock_;
|
||||
std::string curDeviceId_;
|
||||
std::string newDeviceId_;
|
||||
bool defaultDeviceChanged_ = false;
|
||||
|
||||
std::unique_ptr<float[]> tempBuf_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user