From 7d4bf4fc3c2a14cb8307034f4fd1865fe251d148 Mon Sep 17 00:00:00 2001 From: Roman Pudashkin Date: Mon, 25 May 2026 11:25:30 +0300 Subject: [PATCH 1/3] Fix #33224: fix auto switch to System default --- src/framework/audio/common/audiotypes.h | 1 - .../audio/main/iaudioconfiguration.h | 1 + .../main/internal/audioconfiguration.cpp | 17 ++++++++++++--- .../audio/main/internal/audioconfiguration.h | 1 + .../main/internal/audiodrivercontroller.cpp | 21 +++++++------------ .../main/internal/audiodrivercontroller.h | 2 -- .../stubs/audio/audioconfigurationstub.cpp | 5 +++++ .../stubs/audio/audioconfigurationstub.h | 1 + 8 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/framework/audio/common/audiotypes.h b/src/framework/audio/common/audiotypes.h index 651061c81c327..ba7f1018376ba 100644 --- a/src/framework/audio/common/audiotypes.h +++ b/src/framework/audio/common/audiotypes.h @@ -80,7 +80,6 @@ static constexpr samples_t MINIMUM_BUFFER_SIZE = 128; #endif static constexpr samples_t MAXIMUM_BUFFER_SIZE = 4096; -static constexpr samples_t DEFAULT_BUFFER_SIZE = 1024; struct OutputSpec { sample_rate_t sampleRate = 0; diff --git a/src/framework/audio/main/iaudioconfiguration.h b/src/framework/audio/main/iaudioconfiguration.h index 3a25886917f1e..1dd2bf767c4be 100644 --- a/src/framework/audio/main/iaudioconfiguration.h +++ b/src/framework/audio/main/iaudioconfiguration.h @@ -58,6 +58,7 @@ class IAudioConfiguration : MODULE_GLOBAL_INTERFACE virtual void setSampleRate(unsigned int sampleRate) = 0; virtual async::Notification sampleRateChanged() const = 0; + virtual OutputSpec defaultOutputSpec() const = 0; virtual OutputSpec desiredOutputSpec() const = 0; // synthesizers diff --git a/src/framework/audio/main/internal/audioconfiguration.cpp b/src/framework/audio/main/internal/audioconfiguration.cpp index 419fbdd009429..17d982c2cd8c4 100644 --- a/src/framework/audio/main/internal/audioconfiguration.cpp +++ b/src/framework/audio/main/internal/audioconfiguration.cpp @@ -36,7 +36,9 @@ using namespace muse; using namespace muse::audio; using namespace muse::audio::synth; -static const audioch_t AUDIO_CHANNELS = 2; +static constexpr audioch_t AUDIO_CHANNELS = 2; +static constexpr samples_t DEFAULT_BUFFER_SIZE = 1024; +static constexpr sample_rate_t DEFAULT_SAMPLE_RATE = 44100; //TODO: add other setting: audio device etc static const Settings::Key AUDIO_API_KEY("audio", "io/audioApi"); @@ -51,7 +53,7 @@ static const Settings::Key USER_SOUNDFONTS_PATHS("midi", "application/paths/mySo void AudioConfiguration::init() { - settings()->setDefaultValue(AUDIO_BUFFER_SIZE_KEY, Val(1024)); + settings()->setDefaultValue(AUDIO_BUFFER_SIZE_KEY, Val(static_cast(DEFAULT_BUFFER_SIZE))); settings()->valueChanged(AUDIO_BUFFER_SIZE_KEY).onReceive(nullptr, [this](const Val&) { m_driverBufferSizeChanged.notify(); }); @@ -70,7 +72,7 @@ void AudioConfiguration::init() m_audioOutputDeviceIdChanged.notify(); }); - settings()->setDefaultValue(AUDIO_SAMPLE_RATE_KEY, Val(44100)); + settings()->setDefaultValue(AUDIO_SAMPLE_RATE_KEY, Val(static_cast(DEFAULT_SAMPLE_RATE))); settings()->setCanBeManuallyEdited(AUDIO_SAMPLE_RATE_KEY, false, Val(44100), Val(192000)); settings()->valueChanged(AUDIO_SAMPLE_RATE_KEY).onReceive(nullptr, [this](const Val&) { m_driverSampleRateChanged.notify(); @@ -176,6 +178,15 @@ async::Notification AudioConfiguration::sampleRateChanged() const return m_driverSampleRateChanged; } +OutputSpec AudioConfiguration::defaultOutputSpec() const +{ + OutputSpec spec; + spec.sampleRate = DEFAULT_SAMPLE_RATE; + spec.samplesPerChannel = DEFAULT_BUFFER_SIZE; + spec.audioChannelCount = AUDIO_CHANNELS; + return spec; +} + OutputSpec AudioConfiguration::desiredOutputSpec() const { OutputSpec spec; diff --git a/src/framework/audio/main/internal/audioconfiguration.h b/src/framework/audio/main/internal/audioconfiguration.h index 5d08107d05364..4629c0e6df8f6 100644 --- a/src/framework/audio/main/internal/audioconfiguration.h +++ b/src/framework/audio/main/internal/audioconfiguration.h @@ -63,6 +63,7 @@ class AudioConfiguration : public IAudioConfiguration, public Contextable void setSampleRate(unsigned int sampleRate) override; async::Notification sampleRateChanged() const override; + OutputSpec defaultOutputSpec() const override; OutputSpec desiredOutputSpec() const override; io::paths_t soundFontDirectories() const override; diff --git a/src/framework/audio/main/internal/audiodrivercontroller.cpp b/src/framework/audio/main/internal/audiodrivercontroller.cpp index a5b052728ce71..1a32da774c5ce 100644 --- a/src/framework/audio/main/internal/audiodrivercontroller.cpp +++ b/src/framework/audio/main/internal/audiodrivercontroller.cpp @@ -190,16 +190,6 @@ void AudioDriverController::setNewDriver(IAudioDriverPtr newDriver) } } -IAudioDriver::Spec AudioDriverController::defaultSpec() const -{ - IAudioDriver::Spec spec; - spec.deviceId = m_audioDriver ? m_audioDriver->defaultDevice() : AudioDeviceID(); - spec.output.audioChannelCount = 2; - spec.output.sampleRate = 44100; - spec.output.samplesPerChannel = DEFAULT_BUFFER_SIZE; - return spec; -} - std::string AudioDriverController::currentAudioApi() const { return configuration()->currentAudioApi(); @@ -221,10 +211,11 @@ void AudioDriverController::changeCurrentAudioApi(const std::string& name) LOGI() << "Used audio driver: " << m_audioDriver->name(); // reset to default - IAudioDriver::Spec spec = defaultSpec(); + IAudioDriver::Spec spec; + spec.output = configuration()->defaultOutputSpec(); spec.callback = m_callback; - if (!spec.deviceId.empty()) { + if (m_audioDriver && !m_audioDriver->defaultDevice().empty()) { spec.deviceId = DEFAULT_DEVICE_ID; m_audioDriver->open(spec, nullptr); } else { @@ -278,7 +269,9 @@ bool AudioDriverController::open(const IAudioDriver::Spec& spec, IAudioDriver::S defaultDriver->init(); setNewDriver(defaultDriver); // reset to default - IAudioDriver::Spec defSpec = defaultSpec(); + IAudioDriver::Spec defSpec; + defSpec.deviceId = DEFAULT_DEVICE_ID; + defSpec.output = configuration()->defaultOutputSpec(); defSpec.callback = spec.callback; ok = m_audioDriver->open(defSpec, activeSpec); if (ok) { @@ -377,7 +370,7 @@ void AudioDriverController::checkOutputDevice() bool ok = m_audioDriver->open(spec, nullptr); if (!ok) { // reset to default device - spec.deviceId = m_audioDriver->defaultDevice(); + spec.deviceId = DEFAULT_DEVICE_ID; m_audioDriver->open(spec, nullptr); } } diff --git a/src/framework/audio/main/internal/audiodrivercontroller.h b/src/framework/audio/main/internal/audiodrivercontroller.h index d770801c10e56..cdf9639eddf48 100644 --- a/src/framework/audio/main/internal/audiodrivercontroller.h +++ b/src/framework/audio/main/internal/audiodrivercontroller.h @@ -74,8 +74,6 @@ class AudioDriverController : public IAudioDriverController, public Contextable, IAudioDriverPtr createDriver(const std::string& name) const; void setNewDriver(IAudioDriverPtr newDriver); - IAudioDriver::Spec defaultSpec() const; - void checkOutputDevice(); void updateOutputSpec(); diff --git a/src/framework/stubs/audio/audioconfigurationstub.cpp b/src/framework/stubs/audio/audioconfigurationstub.cpp index 72d5605d0effd..6e97e4a6fc443 100644 --- a/src/framework/stubs/audio/audioconfigurationstub.cpp +++ b/src/framework/stubs/audio/audioconfigurationstub.cpp @@ -95,6 +95,11 @@ async::Notification AudioConfigurationStub::sampleRateChanged() const return async::Notification(); } +OutputSpec AudioConfigurationStub::defaultOutputSpec() const +{ + return OutputSpec(); +} + OutputSpec AudioConfigurationStub::desiredOutputSpec() const { return OutputSpec(); diff --git a/src/framework/stubs/audio/audioconfigurationstub.h b/src/framework/stubs/audio/audioconfigurationstub.h index 92a38978e882d..a5494408e5abc 100644 --- a/src/framework/stubs/audio/audioconfigurationstub.h +++ b/src/framework/stubs/audio/audioconfigurationstub.h @@ -48,6 +48,7 @@ class AudioConfigurationStub : public IAudioConfiguration void setSampleRate(unsigned int sampleRate) override; async::Notification sampleRateChanged() const override; + OutputSpec defaultOutputSpec() const override; OutputSpec desiredOutputSpec() const override; // synthesizers From eba029c137ad029db46144cd31cc81d07ef41bca Mon Sep 17 00:00:00 2001 From: Roman Pudashkin Date: Mon, 25 May 2026 11:50:14 +0300 Subject: [PATCH 2/3] AudioDriverController: improve logs --- .../main/internal/audiodrivercontroller.cpp | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/framework/audio/main/internal/audiodrivercontroller.cpp b/src/framework/audio/main/internal/audiodrivercontroller.cpp index 1a32da774c5ce..e1a34a787a242 100644 --- a/src/framework/audio/main/internal/audiodrivercontroller.cpp +++ b/src/framework/audio/main/internal/audiodrivercontroller.cpp @@ -217,7 +217,10 @@ void AudioDriverController::changeCurrentAudioApi(const std::string& name) if (m_audioDriver && !m_audioDriver->defaultDevice().empty()) { spec.deviceId = DEFAULT_DEVICE_ID; - m_audioDriver->open(spec, nullptr); + bool ok = m_audioDriver->open(spec, nullptr); + if (!ok) { + LOGE() << "Failed to open audio driver: " << name; + } } else { LOGW() << "No devices for " << name; } @@ -254,17 +257,20 @@ bool AudioDriverController::open(const IAudioDriver::Spec& spec, IAudioDriver::S driver->init(); setNewDriver(driver); + LOGI() << "Trying to open audio driver: " << m_audioDriver->name() << ", device: " << spec.deviceId; bool ok = m_audioDriver->open(spec, activeSpec); if (!ok) { // reset to default device IAudioDriver::Spec defaultDeviceSpec = spec; defaultDeviceSpec.deviceId = m_audioDriver->defaultDevice(); + LOGW() << "Failed to open device: " << spec.deviceId << ", falling back to default: " << defaultDeviceSpec.deviceId; ok = m_audioDriver->open(defaultDeviceSpec, activeSpec); } if (!ok) { const std::string defaultAudioApi = configuration()->defaultAudioApi(); if (defaultAudioApi != currentAudioApi) { + LOGW() << "Failed to open driver: " << m_audioDriver->name() << ", falling back to default: " << defaultAudioApi; IAudioDriverPtr defaultDriver = createDriver(defaultAudioApi); defaultDriver->init(); setNewDriver(defaultDriver); @@ -280,9 +286,12 @@ bool AudioDriverController::open(const IAudioDriver::Spec& spec, IAudioDriver::S } } - LOGI() << "Used audio driver: " << m_audioDriver->name() - << ", opened: " << (ok ? "success" : "failed") - << ", device: " << m_audioDriver->activeSpec().deviceId; + if (ok) { + LOGI() << "Opened audio driver: " << m_audioDriver->name() + << ", device: " << m_audioDriver->activeSpec().deviceId; + } else { + LOGE() << "Failed to open any audio driver, last tried: " << m_audioDriver->name(); + } return ok; } @@ -348,8 +357,11 @@ bool AudioDriverController::selectOutputDevice(const AudioDeviceID& deviceId) m_audioDriver->close(); bool ok = m_audioDriver->open(spec, nullptr); if (!ok) { - LOGE() << "failed select device, return to old: " << oldSpec.deviceId; - m_audioDriver->open(oldSpec, nullptr); + LOGE() << "Failed to select device: " << deviceId << ", returning to: " << oldSpec.deviceId; + bool restored = m_audioDriver->open(oldSpec, nullptr); + if (!restored) { + LOGE() << "Failed to restore previous device: " << oldSpec.deviceId; + } } return ok; } @@ -366,12 +378,17 @@ void AudioDriverController::checkOutputDevice() } IAudioDriver::Spec spec = m_audioDriver->activeSpec(); + LOGI() << "Checking output device: " << spec.deviceId; m_audioDriver->close(); bool ok = m_audioDriver->open(spec, nullptr); if (!ok) { // reset to default device + LOGW() << "Failed to reopen device: " << spec.deviceId << ", falling back to default"; spec.deviceId = DEFAULT_DEVICE_ID; - m_audioDriver->open(spec, nullptr); + ok = m_audioDriver->open(spec, nullptr); + if (!ok) { + LOGE() << "Failed to reopen default device"; + } } } @@ -413,6 +430,8 @@ void AudioDriverController::changeBufferSize(samples_t samples) updateOutputSpec(); configuration()->setDriverBufferSize(samples); m_outputDeviceBufferSizeChanged.notify(); + } else { + LOGE() << "Failed to change buffer size to: " << samples; } } @@ -449,6 +468,8 @@ void AudioDriverController::changeSampleRate(sample_rate_t sampleRate) updateOutputSpec(); configuration()->setSampleRate(sampleRate); m_outputDeviceSampleRateChanged.notify(); + } else { + LOGE() << "Failed to change sample rate to: " << sampleRate; } } From 77b65509d1c609d876e33dae45ad65007e9b16cf Mon Sep 17 00:00:00 2001 From: Roman Pudashkin Date: Mon, 25 May 2026 13:14:43 +0300 Subject: [PATCH 3/3] ASIO: fix device disconnect handling * ASIO reset() now fires availableOutputDevicesChanged instead of self-handling close/reopen, matching the WASAPI behavior * AudioDriverController::checkOutputDevice() falls back to the default audio driver (WASAPI) if reopen fails --- .../platform/win/asio/asioaudiodriver.cpp | 4 +- .../main/internal/audiodrivercontroller.cpp | 54 +++++++++++++------ .../main/internal/audiodrivercontroller.h | 1 + 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/framework/audio/driver/platform/win/asio/asioaudiodriver.cpp b/src/framework/audio/driver/platform/win/asio/asioaudiodriver.cpp index 664e2238d44c1..b184fa6014451 100644 --- a/src/framework/audio/driver/platform/win/asio/asioaudiodriver.cpp +++ b/src/framework/audio/driver/platform/win/asio/asioaudiodriver.cpp @@ -592,9 +592,7 @@ void AsioAudioDriver::reset() return; } - Spec spec = s_adata.activeSpec; - close(); - open(spec, nullptr); + m_availableOutputDevicesChanged.notify(); } bool AsioAudioDriver::isOpened() const diff --git a/src/framework/audio/main/internal/audiodrivercontroller.cpp b/src/framework/audio/main/internal/audiodrivercontroller.cpp index e1a34a787a242..55edcde5476bd 100644 --- a/src/framework/audio/main/internal/audiodrivercontroller.cpp +++ b/src/framework/audio/main/internal/audiodrivercontroller.cpp @@ -268,22 +268,7 @@ bool AudioDriverController::open(const IAudioDriver::Spec& spec, IAudioDriver::S } if (!ok) { - const std::string defaultAudioApi = configuration()->defaultAudioApi(); - if (defaultAudioApi != currentAudioApi) { - LOGW() << "Failed to open driver: " << m_audioDriver->name() << ", falling back to default: " << defaultAudioApi; - IAudioDriverPtr defaultDriver = createDriver(defaultAudioApi); - defaultDriver->init(); - setNewDriver(defaultDriver); - // reset to default - IAudioDriver::Spec defSpec; - defSpec.deviceId = DEFAULT_DEVICE_ID; - defSpec.output = configuration()->defaultOutputSpec(); - defSpec.callback = spec.callback; - ok = m_audioDriver->open(defSpec, activeSpec); - if (ok) { - configuration()->setCurrentAudioApi(defaultAudioApi); - } - } + ok = switchToDefaultAudioDriver(activeSpec); } if (ok) { @@ -387,11 +372,46 @@ void AudioDriverController::checkOutputDevice() spec.deviceId = DEFAULT_DEVICE_ID; ok = m_audioDriver->open(spec, nullptr); if (!ok) { - LOGE() << "Failed to reopen default device"; + LOGE() << "Failed to reopen default device on " << m_audioDriver->name() << ", switching to default audio driver"; + switchToDefaultAudioDriver(); } } } +bool AudioDriverController::switchToDefaultAudioDriver(IAudioDriver::Spec* activeSpec) +{ + const std::string defaultAudioApi = configuration()->defaultAudioApi(); + const std::string currentAudioApi = configuration()->currentAudioApi(); + + if (defaultAudioApi == currentAudioApi) { + LOGE() << "Already on the default audio driver: " << defaultAudioApi << ", cannot fall back further"; + return false; + } + + LOGW() << "Switching from " << currentAudioApi << " to default audio driver: " << defaultAudioApi; + + IAudioDriverPtr defaultDriver = createDriver(defaultAudioApi); + defaultDriver->init(); + setNewDriver(defaultDriver); + + IAudioDriver::Spec defSpec; + defSpec.deviceId = DEFAULT_DEVICE_ID; + defSpec.output = configuration()->defaultOutputSpec(); + defSpec.callback = m_callback; + + bool ok = m_audioDriver->open(defSpec, activeSpec); + if (ok) { + configuration()->setCurrentAudioApi(defaultAudioApi); + m_currentAudioApiChanged.notify(); + m_availableOutputDevicesChanged.notify(); + LOGI() << "Successfully switched to default audio driver: " << defaultAudioApi; + } else { + LOGE() << "Failed to open default audio driver: " << defaultAudioApi; + } + + return ok; +} + void AudioDriverController::updateOutputSpec() { if (!m_audioDriver->isOpened()) { diff --git a/src/framework/audio/main/internal/audiodrivercontroller.h b/src/framework/audio/main/internal/audiodrivercontroller.h index cdf9639eddf48..09033a84561e9 100644 --- a/src/framework/audio/main/internal/audiodrivercontroller.h +++ b/src/framework/audio/main/internal/audiodrivercontroller.h @@ -75,6 +75,7 @@ class AudioDriverController : public IAudioDriverController, public Contextable, void setNewDriver(IAudioDriverPtr newDriver); void checkOutputDevice(); + bool switchToDefaultAudioDriver(IAudioDriver::Spec* activeSpec = nullptr); void updateOutputSpec(); IAudioDriver::Callback m_callback;