bluez-alsa icon indicating copy to clipboard operation
bluez-alsa copied to clipboard

Improve SCO socket transfer size selection

Open borine opened this issue 2 years ago • 11 comments

It now seems that the linux btusb module developers will not modify btusb to report the HCI link MTU in the SCO socket options instead of reporting the HCI SCO buffer size. So this PR implements a work-around that obtains the correct write() size by waiting until the first incoming BT message has been read - this is similar to the strategy used by pulseaudio and pipewire.

If accepted, I think issue #400 can be closed since the code should work for all USB interface AlternateSetting values. I've tested with QCA and Broadcom adapters (both use USB Alt1) and a RPi zero W (Broadcom UART) Unfortunately I do not have an Alt3 adapter; hopefully some other volunteer can test that, since Alt3 mSBC support is really the whole point of this PR !

borine avatar Mar 07 '22 16:03 borine

I tried this with a RTL8761b, which works with Alt3 + 72 byte MTU. No luck. Initially impressions is it's not detecting the incoming eSCO data.

bluealsa[170724]: /usr/bin/bluealsa: D: codec-msbc.c:82: Initializing mSBC codec
bluealsa[170724]: /usr/bin/bluealsa: D: sco.c:573: IO loop: START: sco_msbc_dec_thread: HFP Audio Gateway (mSBC)
bluealsa[170724]: /usr/bin/bluealsa: D: ba-transport.c:1402: PCM resumed: 14
bluealsa[170724]: /usr/bin/bluealsa: D: sco.c:580: SCO decoder read timeout
bluealsa[170724]: /usr/bin/bluealsa: D: sco.c:591: USB adjusted SCO MTU: 30: 24
bluealsa[170724]: /usr/bin/bluealsa: D: sco.c:224: Setting SCO write MTU 24

There is incoming data. The timing of various points, in milliseconds, HCI xfers are USB, while rest are Bluetooth:

-57: HCI Setup Sync Connection (transparent audio, 7.81 kb/sec, only 3-EV3 and larger packets??)
-47: LMP eSCO Link Request (7.5 ms interval, 60 byte packets bidirectional, 2-EV3 packets bidirectional)
-44: LMP Accepted eSCO Link Request
-41: HCI Sync Connection Complete (7.5 ms interval, 60 byte packets)
-33: USB Set Interface Alt 0 (yes, alt 0)
-30: eSCO POLL/NULL packet pair (first eSCO traffic, repeats every 7.5 ms)
-23: eSCO POLL/NULL packet pair
-15: eSCO POLL/NULL packet pair
 -8: eSCO POLL/NULL packet pair
 -1: USB Set Interface Alt 3
  0: eSCO POLL/2-EV3 packet pair (no data out, 60 bytes in), repeats every 7.5 ms
  0: HCI SCO Data out (0 bytes), repeats every 1ms USB frame (not shown)
  2: HCI SCO Data in (0 bytes), repeats every 1ms USB frame (not shown)
  8: eSCO POLL/2-EV3 packet pair
 15: eSCO POLL/2-EV3 packet pair
 16: HCI SCO Data in (25 bytes), start of 1st HCI data packet, HCI packet size 72 bytes
 17: HCI SCO Data in (25 bytes), continue packet from 16
 18: HCI SCO Data in (25 bytes), finish packet from 16, repeat this 3 packet burst

Few interesting things.

  • Basic concept, send data in same size packet that it arrives in, would work. Data arrives in 72 byte HCI packets and should be sent the same way.
  • Accepted packet types bitmask in HCI Setup Sync Connection only sets 3-EV3, 2-EV5, 3-EV5 to true, yet actual connection is using 2-EV3 packets.
  • Initially interface is set to alt 0, then switched to alt 3 after 32 ms.
  • No Bluetooth data is initially sent on eSCO link (internal audio buffer in headphones filling?) but just 1 ms after alt 3 is selected on USB, incoming data arrives on BT eSCO. Is this just a coincidence? Selecting Alt 3 didn't generate any BT traffic I can see, so I don't know how the headphones would know it happened.
  • It takes ~59 ms from when the HCI connection complete status is returned from the RT8761 until the first 72 byte payload HCI SCO data packet is finished.
  • Three 60 byte data packets arrive on BT before the 1st USB HCI data packet starts.

xyzzy42 avatar Apr 04 '22 20:04 xyzzy42

I increased the eSCO timeout from 30 ms to 90 ms. This fixed it and a MTU of 72 is detected.

There is still a glitch at the beginning of the stream.

xyzzy42 avatar Apr 05 '22 00:04 xyzzy42

I've increased the SCO timeout to 100ms to make debugging easier. I need to read through the BT protocol layer interactions to understand the traces for Alt-3. That will take some time as I am busy with other priorities at present.

borine avatar Apr 06 '22 08:04 borine

I've obtained a ASUS USB_BT500 adapter (usbid 0b05:190e) which has a realtek chip:

hciconfig -a
hci0:	Type: Primary  Bus: USB
	BD Address: 04:42:1A:55:44:96  ACL MTU: 1021:5  SCO MTU: 255:11
	UP RUNNING PSCAN 
	RX bytes:1488 acl:0 sco:0 events:157 errors:0
	TX bytes:26835 acl:0 sco:0 commands:157 errors:0
	Features: 0xff 0xff 0xff 0xfe 0xdb 0xfd 0x7b 0x87
	Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 
	Link policy: RSWITCH HOLD SNIFF PARK 
	Link mode: SLAVE ACCEPT 
	Name: 'lenovo #2'
	Class: 0x48010c
	Service Classes: Capturing, Telephony
	Device Class: Computer, Laptop
	HCI Version: 5.1 (0xa)  Revision: 0xd9a
	LMP Version: 5.1 (0xa)  Subversion: 0x2883
	Manufacturer: Realtek Semiconductor Corporation (93)

The linux btusb driver selects Alt3 for this adapter, and this PR correctly sets the SCO socket MTU to 72 bytes for mSBC, and I get good results - no "glitches" at playback startup. However, there is some strangeness with firmware versions. I'm using Ubuntu 20.04 LTS with kernel 5.13.0-37-generic and the linux-firmware package does not include firmware for this adapter. The firmware files required bt the driver are /lib/firmware/rtl_bt/rtl8761b_fw.bin and rtl8761b_config.bin. However, these names belong to the UART variants; USB names should be rtl8761bu_*. I initially tried the firmware files from https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/rtl_bt (both the 'b' and 'bu' versions, renaming 'bu' to 'b') but they give an error in dmesg: Bluetooth: hci0: RTL: extension section signature mismatch. So then I downloaded the versions from the ASUS support site, and surprisingly both the 'bu' and 'b' variants work well (renaming 'bu' to 'b' so that the driver loads it).

So at present I am assuming that this PR is correct (-ish) , and possibly the problems reported are firmware related. I'll update my system next month and try again with a more recent kernel.

borine avatar Apr 14 '22 19:04 borine

update on the firmware naming issue: this is a bug in the linux btrtl driver and was fixed in commit https://github.com/torvalds/linux/commit/9fd2e2949b43dea869f7fce0f8f51df44f635d59 which appears in linux 5.14. So for linux 5.13 and earlier, I guess we need to use the vendor's rtl8761bu_fw but rename it to rtl8761b_fw.bin [EDIT} I messed up when installing the firmware from git.kernel.org. Now that I've done it correctly, those files also give good results. So it is not necessary to use the vendor's firmware if you have a recent version of the linux-firmware package.

For the record. I've now tested 3 different Realtek firmware versions, each with 2 different adapters. The adapters are: ASUS USB-BT500 usbid: 0b05:190e MPOW BH519A usbid: 0bda:2550

The chip in both adapters is the Realtek RTL8761BU The firmware versions here are as reported by dmesg on driver load linux-firmware: 0x09a98a6b (https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git) ASUS: 0x0999646b (https://dlcdnets.asus.com/pub/ASUS/wireless/USB-BT500/20200909_LINUX_BT_DRIVER_KERNEL_5.7_COEX_v0202.zip) MPOW: 0x099a2885 (https://mpow.s3-us-west-1.amazonaws.com/mpow_BH519A_driver+for+Linux.7z)

borine avatar Apr 15 '22 07:04 borine

To answer some of the comment points above:

Accepted packet types bitmask in HCI Setup Sync Connection only sets 3-EV3, 2-EV5, 3-EV5 to true, yet actual connection is using 2-EV3 packets.

The bitmask actually states which packet types will not be accepted.

Initially interface is set to alt 0, then switched to alt 3 after 32 ms.

btusb sends the HCI Setup Synchronous Connection request, then obtains a handle on the USB isochronous endpoint and sets its config to Alt0. I guess this is to gain exclusive access while not consuming any USB bandwidth. When/if a Synchronous Connection Complete response is received, btusb then changes the USB isochronous endpoint config to Alt3.

No Bluetooth data is initially sent on eSCO link (internal audio buffer in headphones filling?) but just 1 ms after alt 3 is selected on USB, incoming data arrives on BT eSCO. Is this just a coincidence? Selecting Alt 3 didn't generate any BT traffic I can see, so I don't know how the headphones would know it happened.

Once the remote has sent Synchronous Connection Complete it begins sending eSCO packets. I'm not sure about the exact timing, but it has nothing to do with the local HCI switch to Alt3. I guess on the local side, once the switch to Alt3 has happened, 1ms represents the first "slot" on the isochronous endpoint.

It takes ~59 ms from when the HCI connection complete status is returned from the RT8761 until the first 72 byte payload HCI SCO data packet is finished.

This seems to be quite variable. My USB-BT500 has this interval varying from 31ms to 40ms in the testing I have done. I think it best to leave the timeout at 100ms permanently. In a correctly functioning system the timeout will never be needed anyway.

borine avatar Apr 15 '22 14:04 borine

Codecov Report

Patch coverage is 62.61% of modified lines.

:exclamation: Current head 7247350 differs from pull request most recent head b2fc3e7. Consider uploading reports for the commit b2fc3e7 to get more accurate results

Files Changed Coverage
src/hci.c 0.00%
src/ba-transport.c 50.00%
src/io.c 50.00%
src/sco.c 65.02%

:loudspeaker: Thoughts on this report? Let us know!.

codecov[bot] avatar Nov 10 '22 14:11 codecov[bot]

@borine I see that you are working on this and some CI check are failing. After my recent changes to master (added mutexes here and there), test-alsa-pcm might fail on various occasions. I will try to fix that in the nearest future by fixing all warnings reported by TSAN. However, right now, I don't know how to run TSAN properly with bluez-alsa because of pthread cancellation - TSAN and cancellation do not go along very well :/

Also, really sorry for not taking care of this PR for such a long time... I'd like to test that properly, but for that I need a day or two of free time. I've checked this PR with my RPi and laptop and indeed it seems to work properly. However, I do remember that with some setup (I do not remember which), there was no incoming data from SCO socket if remote device was not sending any data. But maybe my memory is flaky....

arkq avatar Nov 10 '22 14:11 arkq

No worries about taking time with this; to be honest I'm not very confident of it myself yet. I recently upgraded my RPi systems and now I'm getting lots of issues with networking and bluetooth, so its quite hard for me to test properly at present.

borine avatar Nov 10 '22 15:11 borine

With the recent changes to BlueALSA HFP support, and the latest realtek firmware from the linux-firmware , I'm now getting very good results with this branch. If anyone is watching this PR, please can they test and give feedback. Results from all adapter types and brands (not just USB and not just Realtek) would be very much appreciated.

borine avatar Apr 07 '23 10:04 borine

I'm re-working this to simplify it and take advantage of changes made in release 4.1.0. Hopefully a complete re-write will be available soon.

borine avatar Jun 10 '23 10:06 borine