bluekitchen / btstack

Dual-mode Bluetooth stack, with small memory footprint.
http://bluekitchen-gmbh.com
Other
1.74k stars 614 forks source link

ESP32 slave role Multiple SCO connection problem #606

Open AbdelRahman3li opened 5 months ago

AbdelRahman3li commented 5 months ago

Describe the bug

I have an ESP32 board and want to make it a Bluetooth relay between a phone and a headphone the problem occurs with phones that force the ESP32 to be in a slave role the phone that doesn't require role change works correctly forces the ESP32 to make only one SCO connection with the phone and when I make a second SCO connection I got error code 0x0A which is from bluetooth.h corresponds to (ERROR_CODE_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED)

HINT: the ESP32 is in a slave role with the phone but master with the headphone but when it is a slave role with the phone I get an error code 0x0A with the headphone despite ESP32 being a master with the headphone.

To Reproduce

Steps to reproduce the behavior:

  1. I have combined the HFP AG and UNIT examples from the btstack examples.
  2. make an ACL connection to the headphone and the phone
  3. try to initiate a call an SCO connection is successfully created with the phone while with the headphone error code 0x0A

Expected behavior

The ESP32 should route audio back and forth between the phone and headphone without any problem as it do when it is a master role

HCI Packet Logs Unfortunately, I didn't take packet logs as the problem relies only on the ESP32 role.

Environment: (please complete the following information):

Additional context To Avoid opening another Issue I also face a problem with connection to various headphones such as DL19 and Sound Core life Q30 if you can look at this problem also it will be good but I want to fix the problem of multiple SCO connection as this is the main problem.

mringwal commented 5 months ago

Hi there. Relay for SCO in a master/slave combination doesn't work in general with any Bluetooth Controller. I think I was told work reasonably well with a CYW20706, but I haven't tried myself. For a relay/man-in-the-middle, I'd recommend to use 2 ESP32s instead.

AbdelRahman3li commented 5 months ago

Thanks mringwal for your fast reply.

Unfortunately, the requirement is to use only one ESP32 but it works well if the ESP32 is in the master role I tried to disable the link policy and force the ESP32 always to be master and prevent the role switch but some phones force the role switch I managed to write a code to automatically disconnects if the ESP32 is not a master and reconnect until it is master with the phone it works well with android phones but with iPhone 15 it connects for maybe 20 to 30 seconds.

For CYW20706, do you mean it can work with slave role with the phone and master role with the headphone unlike the ESP32?

mringwal commented 5 months ago

Hi @AbdelRahman3li

Just trying to sum up our experience. Some phones, especially iPhone don't want to switch to slave role.

If the requirement is to forward SCO traffic using a single ESP32, you can either try to raise an issue on the ESP-IDF github and ask Espressif if that's possible, or change your requirements. My worry here is that even if it works (i.e. it connects and the connection is stable), there's still a chance for higher SCO packet loss due to scheduling issues, which would results in glitches.

Yes, I think one customer reported using 20706 successfully for SCO forwarding.

We've only tried forwarding A2DP with the ESP32 which worked reasonably well, but SCO is way more sensible to scheduling issues.

AbdelRahman3li commented 5 months ago

@mringwal Thank you for your clarifications, regarding the second Issue of the ESP32 is unable to connect to modern headphones like Sound Core life Q30 despite I am able to connect with them with my phone but with ESP32 using the HFP_AG example I get an error code 0x04 as if the headphone is not exist.

mringwal commented 5 months ago

If you get error code 0x04 - Page Timeout - the BD ADDR is usually wrong, or the device is not in page scan mode (which means no device could connect at this time). Do you see the device if you make it discoverable and run e.g. the gap_inquiry example?

AbdelRahman3li commented 5 months ago

@mringwal I got the BD address of the Sound Core life Q30 with a Bluetooth scanner app after connecting to it with my phone and Yes when I use the gap_inquiry example it sometimes detects the headphone with the same BD ADDR I got with the Bluetooth scanner app and when it tries to connect to it I get error code 0x04 I tried many examples HSP_AG and a2dp_source all struggles to connect to this despite they connect smoothly with my old microphone and speaker toy.

mringwal commented 5 months ago

Sound like a hardware problem. Could you try with a different ESP32 or you can try with an USB Bluetooth dongle and port/libusb on macOS or Linux. There are a minimal configuration options to set-up a connection, but I haven't played with them as Classic connections work in general if the device is around and the BD ADDR is correct.

AbdelRahman3li commented 5 months ago

You tested with HFP_AG example on modern headphones before? I also thought it might be a problem with my ESP32 board but I have a friend also tried an iPhone headset with ESP32 and also faced the same problem he bought another headset and it worked so I don't know what is the problem I also tried the esp-idf examples and also the same problem I bought another headset DL19 and it also gets the error code 0x04 but both connects with my phone easily I think it is a hardware problem or it needs some configurations to be added in the code but I captured the HCI logs and it is the same whether the headphones is on or off as if the ESP32 is not seeing the headphone at all despite it can sometimes query the BD ADDR of it with the gap_inquiry example.

AbdelRahman3li commented 5 months ago

@mringwal this is the HCI logs when I attempt to connect to the DL19 headset with the HFP_AG example

[02:21:33.097] LOG -- hfp_ag_demo.c.198: USER:'a'
Establish HFP service level connection to 76:09:E4:A5:64:A1...
[02:21:33.100] LOG -- hfp.c.665: Create HFP context 0x3ffdeabc: role 1, addr 76:09:E4:A5:64:A1
[02:21:33.102] LOG -- l2cap.c.2544: create channel addr 76:09:E4:A5:64:A1 psm 0x1 mtu 1691 -> local mtu 1691, sec level 0
[02:21:33.109] LOG -- l2cap.c.2509: create channel 0x3ffdedd0, local_cid 0x0045
[02:21:33.119] LOG -- hci.c.7694: Create_connection to 76:09:E4:A5:64:A1
[02:21:33.128] LOG -- hci.c.326: create_connection_for_addr 76:09:E4:A5:64:A1, type fd
[02:21:33.129] LOG -- hci.c.7713: conn state 0
[02:21:33.138] CMD => 05 04 0D A1 64 A5 E4 09 76 18 CC 00 00 00 00 01 
[02:21:33.142] EVT <= 0F 04 00 05 05 04 
[02:21:48.504] EVT <= 03 0B 04 FF FF A1 64 A5 E4 09 76 01 00 
[02:21:48.506] LOG -- hci.c.3818: Connection_complete (status=4) 76:09:E4:A5:64:A1
[02:21:48.507] LOG -- hci.c.2632: Outgoing connection to 76:09:E4:A5:64:A1 failed
[02:21:48.512] LOG -- l2cap.c.1141: L2CAP_EVENT_CHANNEL_OPENED status 0x4 addr 76:09:E4:A5:64:A1 handle 0xffff psm 0x1 local_cid 0x45 remote_cid 0x0 local_mtu 1691, remote_mtu 672, flush_timeout 0
[02:21:48.523] LOG -- l2cap.c.1158: ERTM mode 0, fcs enabled 0
[02:21:48.533] LOG -- sdp_client.c.507: SDP Client Connection failed, status 0x04.
Connection failed, status 0x04
[02:21:48.543] LOG -- hfp.c.815: rfcomm service not found, status 0x04
[02:21:48.544] LOG -- l2cap.c.2515: free channel 0x3ffdedd0, local_cid 0x0045
[02:21:48.553] LOG -- l2cap.c.1419: l2cap_stop_rtx for local cid 0x45
[02:21:48.563] LOG -- l2cap.c.363: Stop Retransmission timer
[02:21:48.564] LOG -- l2cap.c.349: Stop Monitor timer

and this is when I used gap_inquiry example it rarely discover the device once every 20 attempts

Start scanning...
[02:47:43.883] CMD => 01 04 05 33 8B 9E 05 00 
[02:47:43.887] EVT <= 0F 04 00 05 01 04 
[02:47:50.288] EVT <= 01 01 00 
Inquiry scan complete.
Start scanning...
[02:47:51.672] CMD => 01 04 05 33 8B 9E 05 00 
[02:47:51.675] EVT <= 0F 04 00 05 01 04 
[02:47:58.077] EVT <= 01 01 00 
Inquiry scan complete.
Start scanning...
[02:48:14.748] CMD => 01 04 05 33 8B 9E 05 00 
[02:48:14.751] EVT <= 0F 04 00 05 01 04 
[02:48:21.140] EVT <= 01 01 00 
Inquiry scan complete.
Start scanning...
[02:48:23.120] CMD => 01 04 05 33 8B 9E 05 00 
[02:48:23.124] EVT <= 0F 04 00 05 01 04 
[02:48:29.526] EVT <= 01 01 00 
Inquiry scan complete.
Start scanning...
[02:48:30.785] CMD => 01 04 05 33 8B 9E 05 00 
[02:48:30.789] EVT <= 0F 04 00 05 01 04 
[02:48:37.191] EVT <= 01 01 00 
Inquiry scan complete.
Start scanning...
[02:48:40.339] CMD => 01 04 05 33 8B 9E 05 00 
[02:48:40.343] EVT <= 0F 04 00 05 01 04 
[02:48:40.855] EVT <= 02 0F 01 A1 64 A5 E4 09 76 01 00 00 04 04 24 79 57 
Device found: 76:09:E4:A5:64:A1 with COD: 0x240404, 
[02:48:47.745] EVT <= 01 01 00 
Inquiry scan complete.
mringwal commented 5 months ago

If you get error 0x04 page timeout, the ESP32 did not get a response to it's paging requests, which would be identical to the device not being around. There's a 'page scan repetition' mode parameter, which is set to 0 by default (hci.c:7253). Please try the other values: 1 and 2 if it makes a difference,

Other than that, please try an Broadcom/Cypress/Infineon USB Bluetooth dongle with one of our desktop ports, e.g. with the Laird BT-851 for comparison with the headset.

Do you have a links to the headsets that you cannot connect to? A few customers connect to all kinds of headsets, although they mostly use A2DP instead of HFP, but they also need to connect first.

AbdelRahman3li commented 5 months ago

@mringwal Thanks for your reply, The link to a headset that I cannot connect SoundCore life Q30 but I can connect to it easily with my android phones I thought of maybe I need to make the headset in a state to accept the paging request before sending a page request I will try to buy a Bluetooth dongle to see how it can connect to the headset and I also tried A2DP source example and the same problem happens.