bluez / bluer

BlueR — Official BlueZ Bindings for Rust
https://crates.io/crates/bluer
Other
321 stars 45 forks source link

Is setting the L2CAP LE LL PDU possible? If so, how would this be done in BlueR? #111

Closed Jah-On closed 1 year ago

Jah-On commented 1 year ago

Hello!

I am working on a project trying to implement Google's ASHA on Linux. The problem that I seem to be running into is not being able to set the PDU data as needed. This may be due to an inadequate amount of knowledge I have about Bluetooth and BlueZ/R. I am new to it.

I have been using Stream as that's what I believe the processors are using but I've also tried SeqPacket. Here are my questions..

Thank you for taking the time to read this!

Vudentz commented 1 year ago

@Jah-On assuming BlueR uses L2CAP sockets then only the data itself needs to be transferred, all the L2CAP signalling will be handled automatically, including headers, segmentation, credits, etc.

Jah-On commented 1 year ago

@Vudentz Thank you for your reply. Here's an image that I am using as a reference...

image

As listed in the ASHA documentation above, it is crucial for the streaming to work that I modify the two bytes of the PDU. Is there a way I can modify the PDU bytes in BlueZ? Maybe in either the socket options or in the file descriptor?

Any insight would be much appreciated!

shermp commented 1 year ago

@Jah-On I'm no bluetooth expert (but I'm eagerly watching LASHA), but is Data Length Extensions (DLE) enabled?

shermp commented 1 year ago

Also, just throwing ideas out there, does MTU need to be specified?

Jah-On commented 1 year ago

Also, just throwing ideas out there, does MTU need to be specified?

No as this is set by the peripheral. At 20ms intervals (160 bytes), I am well under the L2CAP LE data frame MTU of 251 bytes.

Jah-On commented 1 year ago

@Jah-On I'm no bluetooth expert (but I'm eagerly watching LASHA), but is Data Length Extensions (DLE) enabled?

I haven't tried this yet, I don't think... can't remember lol. However, I don't think this gets at the underlying issue of needing to modify the PDU. I'll keep it in mind tho.

Edit: I think it's on by default anyways.

Vudentz commented 1 year ago

@Vudentz Thank you for your reply. Here's an image that I am using as a reference...

image

As listed in the ASHA documentation above, it is crucial for the streaming to work that I modify the two bytes of the PDU. Is there a way I can modify the PDU bytes in BlueZ? Maybe in either the socket options or in the file descriptor?

Where exactly are these 2 bytes that you want to change, L2CAP header? Not sure why it is even mentioned on the ASHA documentation about the layer bellow HCI, afaik even with the likes of Android you can't really do anything about that, as for L2CAP the headers are also subject to qualification so Id be really surprised if they don't comply with the standard.

The actual L2CAP PDU format is the following:

Screenshot from 2023-11-21 15-42-12

Even the SDU header is actually appended based on the length of the information payload, perhaps the idea is to avoid L2CAP segmentation, HCI fragmentation and LL segmentation altogether which means the MTU needs to be the smallest of the 3, in that case you can probably set the BT_MTU to 0 which when then make it automatically select whatever was set in the hci_conn->mtu:

https://github.com/bluez/bluetooth-next/commit/4b6e228e297b73451f3a4b12fb7d0b24d9d32e6f

shermp commented 1 year ago

Looking at the source code for ASHA in Flouride (the Android bluetooth stack), it seems it makes a call to BTM_SetBleDataLength(), which appears to be setting the link layer PDU size?

EDIT: Note that Fluoride just sets it to 167 bytes.

Jah-On commented 1 year ago

@Vudentz Thank you for your reply. Here's an image that I am using as a reference... image As listed in the ASHA documentation above, it is crucial for the streaming to work that I modify the two bytes of the PDU. Is there a way I can modify the PDU bytes in BlueZ? Maybe in either the socket options or in the file descriptor?

Where exactly are these 2 bytes that you want to change, L2CAP header? Not sure why it is even mentioned on the ASHA documentation about the layer bellow HCI, afaik even with the likes of Android you can't really do anything about that, as for L2CAP the headers are also subject to qualification so Id be really surprised if they don't comply with the standard.

The actual L2CAP PDU format is the following:

Screenshot from 2023-11-21 15-42-12

Even the SDU header is actually appended based on the length of the information payload, perhaps the idea is to avoid L2CAP segmentation, HCI fragmentation and LL segmentation altogether which means the MTU needs to be the smallest of the 3, in that case you can probably set the BT_MTU to 0 which when then make it automatically select whatever was set in the hci_conn->mtu:

bluez/bluetooth-next@4b6e228

Here is the Android source for the hearing aid streaming...hear_aid.cc

From what I can gather, they are generating their own packet and sending it via GAP but I may be wrong on that. If you could read their source code and say whether getting same result is possible with BlueZ/R, that would be much appreciated. You are much more informed in this area and I feel overwhelmed after trying to understand what I should be doing for two weeks.

It is entirely possible that this goes beyond the intended scope of BlueZ but I would rather hear that coming from you than falsely come to that conclusion myself. Thanks for taking the time to discuss this. ex

surban commented 1 year ago

BlueR exposes all available L2CAP socket options via Socket<_>. So far I am not aware of any socket option to explicitly set the PDU. This would first have to be implemented in the Linux kernel, before we can expose it in BlueR.

Jah-On commented 1 year ago

I took another look at the Android source code and I now think the sequence counter is actually in the data part of the packet. Thus, I shouldn't need to modify the generated packet components. However, I have tried this as well as two other developers for their MacOS implementation and the streaming isn't behaving as expected. When we send the packet data into BlueZ/R, is it expecting the data to arrive in a specific endian/orientation?

Edit: We've been able to verify that the G722 encoder is behaving as it should. The LASHA repo is linked here as an issue reference.

surban commented 1 year ago

I am not aware of any endian-requirements.

Could you verify that L2CAP sockets work for you between two Linux hosts using l2cat?

Jah-On commented 1 year ago

I am not aware of any endian-requirements.

Could you verify that L2CAP sockets work for you between two Linux hosts using l2cat?

No as the device(s) we are interfacing with are hearing aids or cochlear implant processors that only run embedded closed source firmware. Perhaps I could see if any open source RTOS projects have implemented ASHA but I doubt that will yield anything.

Edit: If you were asking whether I know an L2CAP socket is established and sends data... then yes, it is. I can verify this in WireShark and the processor crashes and resets after some amount of frames.

Jah-On commented 1 year ago

As it turns out, this is not needed. However, we do need a way to set the connection interval to 20ms. It looks like this is already implemented for BlueZ but is not a part of BlueR yet. Can this be added and should I rename this "issue" or close it and make a new one?

surban commented 1 year ago

Please create a new issue.