From 6e8b164a1ecd5d16ba98a7c5baa3ea7642be5e5d Mon Sep 17 00:00:00 2001 From: Alexander Lilleaas <16395330+Loffah@users.noreply.github.com> Date: Tue, 25 Aug 2026 17:10:27 +0200 Subject: [PATCH] linux: add setting to toggle media takeover The app unconditionally force-connects to the AirPods and sends a disconnect request to the phone whenever any MPRIS player reports Playing. With multipoint AirPods this steals audio from the phone even when the desktop playback was unintentional (a notification sound, or a player stuck buffering still reports Playing). Add a 'Take Over Audio When Media Plays' switch in settings, persisted as media/takeoverEnabled, defaulting to true to keep the current behavior. Co-Authored-By: Claude Fable 5 --- linux/Main.qml | 12 ++++++++++++ linux/main.cpp | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/linux/Main.qml b/linux/Main.qml index c7b235c33..5fface770 100644 --- a/linux/Main.qml +++ b/linux/Main.qml @@ -241,6 +241,18 @@ ApplicationWindow { onCheckedChanged: airPodsTrayApp.notificationsEnabled = checked } + Switch { + text: qsTr("Take Over Audio When Media Plays") + checked: airPodsTrayApp.mediaTakeoverEnabled + onCheckedChanged: airPodsTrayApp.mediaTakeoverEnabled = checked + + ToolTip { + visible: parent.hovered + text: qsTr("Automatically connect to the AirPods and take audio from\nother devices when media starts playing on this computer") + delay: 500 + } + } + Switch { visible: airPodsTrayApp.airpodsConnected text: qsTr("One Bud ANC Mode") diff --git a/linux/main.cpp b/linux/main.cpp index 7b1826b49..56d5f2f76 100644 --- a/linux/main.cpp +++ b/linux/main.cpp @@ -43,6 +43,7 @@ class AirPodsTrayApp : public QObject { Q_PROPERTY(AutoStartManager *autoStartManager READ autoStartManager CONSTANT) Q_PROPERTY(bool notificationsEnabled READ notificationsEnabled WRITE setNotificationsEnabled NOTIFY notificationsEnabledChanged) Q_PROPERTY(int retryAttempts READ retryAttempts WRITE setRetryAttempts NOTIFY retryAttemptsChanged) + Q_PROPERTY(bool mediaTakeoverEnabled READ mediaTakeoverEnabled WRITE setMediaTakeoverEnabled NOTIFY mediaTakeoverEnabledChanged) Q_PROPERTY(bool hideOnStart READ hideOnStart CONSTANT) Q_PROPERTY(DeviceInfo *deviceInfo READ deviceInfo CONSTANT) Q_PROPERTY(QString phoneMacStatus READ phoneMacStatus NOTIFY phoneMacStatusChanged) @@ -90,6 +91,7 @@ class AirPodsTrayApp : public QObject { CrossDevice.isEnabled = loadCrossDeviceEnabled(); setEarDetectionBehavior(loadEarDetectionSettings()); setRetryAttempts(loadRetryAttempts()); + m_mediaTakeoverEnabled = loadMediaTakeoverEnabled(); monitor->checkAlreadyConnectedDevices(); LOG_INFO("AirPodsTrayApp initialized"); @@ -133,6 +135,7 @@ class AirPodsTrayApp : public QObject { bool notificationsEnabled() const { return trayManager->notificationsEnabled(); } void setNotificationsEnabled(bool enabled) { trayManager->setNotificationsEnabled(enabled); } int retryAttempts() const { return m_retryAttempts; } + bool mediaTakeoverEnabled() const { return m_mediaTakeoverEnabled; } bool hideOnStart() const { return m_hideOnStart; } DeviceInfo *deviceInfo() const { return m_deviceInfo; } QString phoneMacStatus() const { return m_phoneMacStatus; } @@ -249,6 +252,17 @@ public slots: } } + void setMediaTakeoverEnabled(bool enabled) + { + if (m_mediaTakeoverEnabled != enabled) + { + LOG_DEBUG("Setting media takeover to: " << enabled); + m_mediaTakeoverEnabled = enabled; + emit mediaTakeoverEnabledChanged(enabled); + saveMediaTakeoverEnabled(enabled); + } + } + void initiateMagicPairing() { if (!socket || !socket->isOpen()) @@ -410,6 +424,9 @@ public slots: int loadRetryAttempts() const { return m_settings->value("bluetooth/retryAttempts", 3).toInt(); } void saveRetryAttempts(int attempts) { m_settings->setValue("bluetooth/retryAttempts", attempts); } + bool loadMediaTakeoverEnabled() const { return m_settings->value("media/takeoverEnabled", true).toBool(); } + void saveMediaTakeoverEnabled(bool enabled) { m_settings->setValue("media/takeoverEnabled", enabled); } + void onSystemGoingToSleep() { if (m_bleManager->isScanning()) @@ -887,6 +904,10 @@ private slots: public: void handleMediaStateChange(MediaController::MediaState state) { if (state == MediaController::MediaState::Playing) { + if (!m_mediaTakeoverEnabled) { + LOG_DEBUG("Media started playing, but media takeover is disabled"); + return; + } LOG_INFO("Media started playing, sending disconnect request to Android and taking over audio"); sendDisconnectRequestToAndroid(); connectToAirPods(true); @@ -966,6 +987,7 @@ private slots: void crossDeviceEnabledChanged(bool enabled); void notificationsEnabledChanged(bool enabled); void retryAttemptsChanged(int attempts); + void mediaTakeoverEnabledChanged(bool enabled); void oneBudANCModeChanged(bool enabled); void phoneMacStatusChanged(); void hearingAidEnabledChanged(bool enabled); @@ -981,6 +1003,7 @@ private slots: QSettings *m_settings; AutoStartManager *m_autoStartManager; int m_retryAttempts = 3; + bool m_mediaTakeoverEnabled = true; bool m_hideOnStart = false; DeviceInfo *m_deviceInfo; BleManager *m_bleManager;