From 14a5ad2ebcb72bbf157a968c4519095e7cbb11e0 Mon Sep 17 00:00:00 2001 From: Roman Pudashkin Date: Mon, 6 Jul 2026 14:06:49 +0300 Subject: [PATCH 1/3] Fix playback after sleep --- .../main/internal/audiodrivercontroller.cpp | 24 +++++++++++++++++-- .../main/internal/audiodrivercontroller.h | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/framework/audio/main/internal/audiodrivercontroller.cpp b/src/framework/audio/main/internal/audiodrivercontroller.cpp index 1c6991e8cd518..169a5c8263107 100644 --- a/src/framework/audio/main/internal/audiodrivercontroller.cpp +++ b/src/framework/audio/main/internal/audiodrivercontroller.cpp @@ -177,6 +177,10 @@ void AudioDriverController::setNewDriver(IAudioDriverPtr newDriver) }); m_audioDriver->activeSpecChanged().onReceive(this, [this](const IAudioDriver::Spec& spec) { + if (spec.isValid()) { + m_lastValidSpec = spec; + } + m_activeSpecChanged.send(spec); async::Async::call(this, [this, spec]() { @@ -364,8 +368,24 @@ void AudioDriverController::handleOutputDeviceChange() return; } + // Some drivers reset their internal spec to a blank state after a failed open attempt, so fall + // back to the last spec that was actually confirmed to work IAudioDriver::Spec spec = m_audioDriver->activeSpec(); - LOGI() << "Checking output device: " << spec.deviceId; + if (!spec.isValid()) { + if (m_lastValidSpec.isValid()) { + spec = m_lastValidSpec; + } else { + spec.deviceId = DEFAULT_DEVICE_ID; + spec.output = configuration()->defaultOutputSpec(); + spec.callback = m_callback; + } + } + + LOGI() << "Reopening output device: " << spec.deviceId + << ", sampleRate: " << spec.output.sampleRate + << ", channels: " << spec.output.audioChannelCount + << ", samplesPerChannel: " << spec.output.samplesPerChannel; + m_audioDriver->close(); bool ok = m_audioDriver->open(spec, nullptr); if (!ok) { @@ -375,7 +395,7 @@ void AudioDriverController::handleOutputDeviceChange() ok = m_audioDriver->open(spec, nullptr); if (!ok) { LOGE() << "Failed to reopen default device on " << m_audioDriver->name() << ", switching to default audio driver"; - switchToDefaultAudioDriver(); + ok = switchToDefaultAudioDriver(); } } diff --git a/src/framework/audio/main/internal/audiodrivercontroller.h b/src/framework/audio/main/internal/audiodrivercontroller.h index 57bf46f3dd087..f8b986d279800 100644 --- a/src/framework/audio/main/internal/audiodrivercontroller.h +++ b/src/framework/audio/main/internal/audiodrivercontroller.h @@ -80,6 +80,7 @@ class AudioDriverController : public IAudioDriverController, public Contextable, IAudioDriver::Callback m_callback; IAudioDriverPtr m_audioDriver; + IAudioDriver::Spec m_lastValidSpec; async::Notification m_currentAudioApiChanged; async::Notification m_availableOutputDevicesChanged; async::Channel m_activeSpecChanged; From a8dd20f2a08df8637ddd51830af56c1a4458a520 Mon Sep 17 00:00:00 2001 From: Roman Pudashkin Date: Mon, 6 Jul 2026 14:20:30 +0300 Subject: [PATCH 2/3] Set default audio API to CoreAudio on macOS --- src/framework/audio/main/internal/audioconfiguration.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/framework/audio/main/internal/audioconfiguration.cpp b/src/framework/audio/main/internal/audioconfiguration.cpp index 2f234bcb4b5f6..babb868d12522 100644 --- a/src/framework/audio/main/internal/audioconfiguration.cpp +++ b/src/framework/audio/main/internal/audioconfiguration.cpp @@ -63,6 +63,8 @@ void AudioConfiguration::init() settings()->setDefaultValue(AUDIO_API_KEY, Val("WASAPI")); #elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) settings()->setDefaultValue(AUDIO_API_KEY, Val("ALSA")); +#elif defined(Q_OS_MACOS) + settings()->setDefaultValue(AUDIO_API_KEY, Val("CoreAudio")); #endif settings()->valueChanged(AUDIO_API_KEY).onReceive(nullptr, [this](const Val&) { m_currentAudioApiChanged.notify(); From 75cd157ab2940b3ddfcd83ec37f60c4d17f1f575 Mon Sep 17 00:00:00 2001 From: Roman Pudashkin Date: Mon, 6 Jul 2026 14:34:23 +0300 Subject: [PATCH 3/3] Improve logs --- src/framework/audio/common/audiotypes.h | 8 ++++++++ src/framework/audio/iaudiodriver.h | 8 ++++++++ .../audio/main/internal/audiodrivercontroller.cpp | 15 +++++---------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/framework/audio/common/audiotypes.h b/src/framework/audio/common/audiotypes.h index a1569e0827c28..1ba7d7724bbfc 100644 --- a/src/framework/audio/common/audiotypes.h +++ b/src/framework/audio/common/audiotypes.h @@ -578,3 +578,11 @@ struct TransportEvent { }; using TransportEvents = std::vector; } + +inline muse::logger::Stream& operator<<(muse::logger::Stream& s, const muse::audio::OutputSpec& spec) +{ + s << "sampleRate: " << spec.sampleRate + << ", channels: " << spec.audioChannelCount + << ", samplesPerChannel: " << spec.samplesPerChannel; + return s; +} diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index 8076a9de077e6..12f3ae98815e6 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -28,6 +28,7 @@ #include #include "global/async/notification.h" +#include "global/logstream.h" #include "audio/common/audiotypes.h" @@ -67,3 +68,10 @@ class IAudioDriver }; using IAudioDriverPtr = std::shared_ptr; } + +inline muse::logger::Stream& operator<<(muse::logger::Stream& s, const muse::audio::IAudioDriver::Spec& spec) +{ + s << "deviceId: " << spec.deviceId + << ", " << spec.output; + return s; +} diff --git a/src/framework/audio/main/internal/audiodrivercontroller.cpp b/src/framework/audio/main/internal/audiodrivercontroller.cpp index 169a5c8263107..1f677c65b3869 100644 --- a/src/framework/audio/main/internal/audiodrivercontroller.cpp +++ b/src/framework/audio/main/internal/audiodrivercontroller.cpp @@ -263,7 +263,7 @@ 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; + LOGI() << "Trying to open audio driver: " << m_audioDriver->name() << ", " << spec; bool ok = m_audioDriver->open(spec, activeSpec); if (!ok) { // reset to default device @@ -278,8 +278,7 @@ bool AudioDriverController::open(const IAudioDriver::Spec& spec, IAudioDriver::S } if (ok) { - LOGI() << "Opened audio driver: " << m_audioDriver->name() - << ", device: " << m_audioDriver->activeSpec().deviceId; + LOGI() << "Opened audio driver: " << m_audioDriver->name() << ", " << m_audioDriver->activeSpec(); } else { LOGE() << "Failed to open any audio driver, last tried: " << m_audioDriver->name(); } @@ -336,15 +335,14 @@ bool AudioDriverController::selectOutputDevice(const AudioDeviceID& deviceId) } const IAudioDriver::Spec oldSpec = m_audioDriver->activeSpec(); - LOGI() << "Trying to change output device" - << " from: " << oldSpec.deviceId - << ", to: " << deviceId; IAudioDriver::Spec spec; spec.deviceId = deviceId; spec.callback = oldSpec.callback; spec.output = configuration()->desiredOutputSpec(); + LOGI() << "Trying to change output device from " << oldSpec << " to " << spec; + m_audioDriver->close(); bool ok = m_audioDriver->open(spec, nullptr); if (!ok) { @@ -381,10 +379,7 @@ void AudioDriverController::handleOutputDeviceChange() } } - LOGI() << "Reopening output device: " << spec.deviceId - << ", sampleRate: " << spec.output.sampleRate - << ", channels: " << spec.output.audioChannelCount - << ", samplesPerChannel: " << spec.output.samplesPerChannel; + LOGI() << "Reopening output device, " << spec; m_audioDriver->close(); bool ok = m_audioDriver->open(spec, nullptr);