6f7f7ddd6c
The bar turned green after 2 s on a timer even when the microphone delivered nothing. It now turns green only on real audio: RMS above 0.0005, or three consecutive chunks that are not digital silence (the virtual mic emits one stray nonzero chunk right after start, and a Bluetooth headset's floor ramps in from a few LSB). Measured 1.2-1.4 s after the key, within 0.14 s of the first real samples. diagnostics/bluetooth/ records how startup went from ~1.6 s (or never) to ~1.1-1.4 s: a btusb driver bug, two PipeWire bluez5 bugs, a 500 ms WirePlumber switch timeout and an over-broad auto-connect rule. Those fixes are machine level and live outside this repo; the patches, tools and measurements are here. STARTUP-TIME.md is the summary and explains the ~0.9 s hardware floor. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xoc9DJCViR7dg9eKzzAcfQ
73 lines
3.1 KiB
Diff
73 lines
3.1 KiB
Diff
From: Alan Silva <alanfortlink@gmail.com>
|
|
Subject: [PATCH] Bluetooth: btusb: switch the isoc interface on every SCO enable notification
|
|
|
|
hci_conn_num(hdev, SCO_LINK) also counts (e)SCO links that are still being
|
|
set up, since hci_connect_sco() adds them to the connection hash before the
|
|
Synchronous Connection Complete event arrives. btusb_notify() only compares
|
|
that count with data->sco_num and stores whatever event it was called with
|
|
as the air mode. Two things go wrong when an unrelated connection event
|
|
arrives while an (e)SCO link is pending:
|
|
|
|
1. The unrelated event (e.g. HCI_NOTIFY_CONN_DEL from a failed ACL page to
|
|
another device) changes the count from 0 to 1, so btusb_work() runs
|
|
with air_mode = HCI_NOTIFY_CONN_DEL, computes new_alts = 0 and submits
|
|
isochronous URBs on the alternate setting 0 endpoints, whose
|
|
wMaxPacketSize is 0. usb_submit_urb() fails with -EMSGSIZE:
|
|
Bluetooth: hci0: urb 00000000d42f828b submission failed (90)
|
|
and BTUSB_ISOC_RUNNING is cleared again.
|
|
|
|
2. When HCI_NOTIFY_ENABLE_SCO_TRANSP finally arrives for that link, the
|
|
count already equals data->sco_num, so nothing is scheduled. The
|
|
interface stays on alternate setting 0, no isochronous URBs are
|
|
submitted, and the SCO link carries no audio in either direction for
|
|
its whole lifetime. The user sees a working headset with a dead
|
|
microphone.
|
|
|
|
Reproduced on an Intel AX210 (8087:0032) with a Sony WH-1000XM5 and
|
|
PipeWire 1.6.8: PipeWire re-tries ConnectProfile() on absent paired devices
|
|
when it starts, bluetoothd pages them, the page times out (status 0x04)
|
|
while dictation opens the headset microphone, and the mSBC link comes up
|
|
silent. Traced with kprobes on btusb_notify/btusb_work/btusb_submit_isoc_urb.
|
|
|
|
Program the alternate setting on every ENABLE_SCO_* notification, and on
|
|
other events only react when links went away.
|
|
---
|
|
--- a/drivers/bluetooth/btusb.c 2026-09-09 02:54:49.664029766 +0100
|
|
+++ b/drivers/bluetooth/btusb.c 2026-09-09 02:55:52.408391149 +0100
|
|
@@ -2289,13 +2289,33 @@
|
|
static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
|
|
{
|
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
|
+ int sco_num = hci_conn_num(hdev, SCO_LINK);
|
|
|
|
BT_DBG("%s evt %d", hdev->name, evt);
|
|
|
|
- if (hci_conn_num(hdev, SCO_LINK) != data->sco_num) {
|
|
- data->sco_num = hci_conn_num(hdev, SCO_LINK);
|
|
+ switch (evt) {
|
|
+ case HCI_NOTIFY_ENABLE_SCO_CVSD:
|
|
+ case HCI_NOTIFY_ENABLE_SCO_TRANSP:
|
|
+ /* A (e)SCO link just came up: program the isochronous
|
|
+ * alternate setting for its air mode, even if the link was
|
|
+ * already counted while it was still being set up.
|
|
+ */
|
|
+ data->sco_num = sco_num;
|
|
data->air_mode = evt;
|
|
schedule_work(&data->work);
|
|
+ break;
|
|
+ default:
|
|
+ /* hci_conn_num() also counts (e)SCO links that are still
|
|
+ * being set up, and only the ENABLE_SCO_* notifications
|
|
+ * carry an air mode. Any other event may only tear the
|
|
+ * isochronous interface down or adjust it for fewer links;
|
|
+ * a pending link is handled once it is enabled.
|
|
+ */
|
|
+ if (sco_num < data->sco_num) {
|
|
+ data->sco_num = sco_num;
|
|
+ schedule_work(&data->work);
|
|
+ }
|
|
+ break;
|
|
}
|
|
}
|
|
|