Skip to content

Commit 784b7a2

Browse files
authored
[Linux] Auto-restart WirePlumber when A2DP profile is unavailable (#213)
Fix: Auto-restart WirePlumber when A2DP profile is unavailable
1 parent d7a96c9 commit 784b7a2

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

linux/media/mediacontroller.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,69 @@ void MediaController::handleConversationalAwareness(const QByteArray &data) {
133133
}
134134
}
135135

136+
bool MediaController::isA2dpProfileAvailable() {
137+
if (m_deviceOutputName.isEmpty()) {
138+
return false;
139+
}
140+
141+
QProcess process;
142+
process.start("pactl", QStringList() << "list" << "cards");
143+
if (!process.waitForFinished(3000)) {
144+
LOG_ERROR("pactl command timed out while checking A2DP availability");
145+
return false;
146+
}
147+
148+
QString output = process.readAllStandardOutput();
149+
150+
// Check if the card section contains our device
151+
int cardStart = output.indexOf(m_deviceOutputName);
152+
if (cardStart == -1) {
153+
return false;
154+
}
155+
156+
// Look for a2dp-sink profile in the card's section
157+
int nextCard = output.indexOf("Name: ", cardStart + m_deviceOutputName.length());
158+
QString cardSection = (nextCard == -1) ? output.mid(cardStart) : output.mid(cardStart, nextCard - cardStart);
159+
160+
return cardSection.contains("a2dp-sink");
161+
}
162+
163+
bool MediaController::restartWirePlumber() {
164+
LOG_INFO("Restarting WirePlumber to rediscover A2DP profiles");
165+
int result = QProcess::execute("systemctl", QStringList() << "--user" << "restart" << "wireplumber");
166+
if (result == 0) {
167+
LOG_INFO("WirePlumber restarted successfully");
168+
// Wait a bit for WirePlumber to rediscover profiles
169+
QProcess::execute("sleep", QStringList() << "2");
170+
return true;
171+
} else {
172+
LOG_ERROR("Failed to restart WirePlumber");
173+
return false;
174+
}
175+
}
176+
136177
void MediaController::activateA2dpProfile() {
137178
if (connectedDeviceMacAddress.isEmpty() || m_deviceOutputName.isEmpty()) {
138179
LOG_WARN("Connected device MAC address or output name is empty, cannot activate A2DP profile");
139180
return;
140181
}
141182

183+
// Check if A2DP profile is available
184+
if (!isA2dpProfileAvailable()) {
185+
LOG_WARN("A2DP profile not available, attempting to restart WirePlumber");
186+
if (restartWirePlumber()) {
187+
// Update device output name after restart
188+
m_deviceOutputName = getAudioDeviceName();
189+
if (!isA2dpProfileAvailable()) {
190+
LOG_ERROR("A2DP profile still not available after WirePlumber restart");
191+
return;
192+
}
193+
} else {
194+
LOG_ERROR("Could not restart WirePlumber, A2DP profile unavailable");
195+
return;
196+
}
197+
}
198+
142199
LOG_INFO("Activating A2DP profile for AirPods");
143200
int result = QProcess::execute(
144201
"pactl", QStringList()

linux/media/mediacontroller.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class MediaController : public QObject
3737
void activateA2dpProfile();
3838
void removeAudioOutputDevice();
3939
void setConnectedDeviceMacAddress(const QString &macAddress);
40+
bool isA2dpProfileAvailable();
41+
bool restartWirePlumber();
4042

4143
void setEarDetectionBehavior(EarDetectionBehavior behavior);
4244
inline EarDetectionBehavior getEarDetectionBehavior() const { return earDetectionBehavior; }

0 commit comments

Comments
 (0)