3

The problem: I am unable to receive (RX) bluetooth SCO data packets although a SCO link is present.

  • Board: intel NUC (NUC6i7KYK) with integrated bluetooth adapter
  • Network Chipset: Intel Wireless 8260 (8086:24F3)
  • OS: Linux Kernel 4.8.8
  • Bluez-5.45
  • Homebrewed distro (every binary compiled from source at the farm... I like to know where the bits come from...)
  • Remote bluetooth devices: 3 different models of headsets/speakers have been tested: Jabra ROX Wireless v2.9.0, JBL Charge 2, Sennheiser URBANITE: behavior is the same.

This is about BR/EDR audio over SCO. It is not bluetooth Low Energy (LE) related.

Computer is used as Audio Gateway (i.e. HFAG bluetooth profile), headsets have Headset and HandsFree profile registered

Bluetooth connection of the headset works. I know that because A2DP works like a charm: i.e. "Audio Sink" profile on the headset device and "Audio Source" profile on the computer connect together:

bluetoothd[1884]: src/service.c:change_state() 0x216b9d0: device AA:BB:CC:DD:EE:FF profile a2dp-sink state changed: disconnected -> connected (0)
bluetoothd[1884]: src/service.c:btd_service_ref() 0x216b9d0: ref=3
bluetoothd[1884]: plugins/policy.c:service_cb() Added a2dp-sink reconnect 0
bluetoothd[1884]: profiles/audio/sink.c:sink_set_state() State changed /org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF: SINK_STATE_CONNECTING -> SINK_STATE_CONNECTED
bluetoothd[1884]: profiles/audio/transport.c:transport_update_playing() /org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF/fd0 State=TRANSPORT_STATE_IDLE Playing=0

The problem arises when I want to get a SCO link: i.e. having my computer playing the Handsfree Audio Gateway profile (HFAG) role, and linking to the headset's Headset/Handsfree profile (HSP/HFP).

I first used Pulseaudio 10-0 along with sox 14.4.2 audioplayer (compiled with pulseaudio support):

  • A2DP: works fine: audio goes through both ways (sox play and sox rec work).
  • SCO: setting pulseaudio's bluez card profile to headset_head_unit and adjusting default source/sink to bluez HFP/HSP: No audio goes through: sox and pulseaudio block as soon as I start playing/recording

SCO connection is there: I deduced that from the outputs of:

hcitool con:

Connections:
< eSCO AA:BB:CC:DD:EE:FF handle 257 state 1 lm MASTER
> ACL AA:BB:CC:DD:EE:FF handle 256 state 1 lm MASTER AUTH ENCRYPT 

cat /sys/kernel/debug/bluetooth/sco:

gg:hh:ii:jj:kk:ll aa:bb:cc:dd:ee:ff 1

btmon (or hcidump):

...
< HCI Command: Setup Synchronous.. (0x01|0x0028) plen 17  #578 [hci0] 12.108972
        ...
> HCI Event: Synchronous Connect Complete (0x2c) plen 17  #593 [hci0] 12.261784
        Status: Success (0x00)
        Handle: 257
        Address: AA:BB:CC:DD:EE:FF (OUI 1C-48-F9)
        Link type: eSCO (0x02)
        Transmission interval: 0x0c
        Retransmission window: 0x02
        RX packet length: 60
        TX packet length: 60
        Air mode: CVSD (0x02) 

Going through btmon output, I see that even though SCO packets are transmitted (TX), none are received (RX):

...
< SCO Data TX: Handle 257 flags 0x00 dlen 60              #811 [hci0] 82.683653
< SCO Data TX: Handle 257 flags 0x00 dlen 60              #812 [hci0] 83.683862
< SCO Data TX: Handle 257 flags 0x00 dlen 60              #813 [hci0] 84.684030
...

hciconfig hci0 -a shows the TX sco packet count incrementing but RX sco count desperately stays at 0:

# hciconfig -a
hci0:   Type: Primary  Bus: USB
BD Address: AA:BB:CC:DD:EE:FF  ACL MTU: 1021:4  SCO MTU: 60:8
UP RUNNING PSCAN 
RX bytes:21578 acl:271 sco:0 events:2728 errors:0
TX bytes:597283 acl:260 sco:358 commands:2446 errors:0

So I then tried without Pulseaudio, to try to narrow down to the problem. I used bluez's package scotest tool (in the package's tools/ directory):

Reading the Hands-Free profile specs: first a RFCOMM link has to be created and a 'Service Level Connexion' ('SLC': negociation between AG and HF/HS device for audio codec etc...) must be run. So I manually registered a HFAG profile on the computer using sdptool (sdptool HFAG add) and created a RFCOMM link manually using socat and a chat script so I could have total control on the SLC sequence (and control AT commands: +BRSF, +CIEV: indicators...)

  • At this point: The device connects, a RFCOMM link is created and is stable, and I can tweak the SLC sequence around

I now can come back to the initial problem: having a working SCO connection with SCO packets going both ways, using scotest:

bluez-5.45/tools/scotest -d -V 0x0060 <BD_ADDRESS_REMOTE>

I tried every command line options ('mode') of scotest: -d: dump, -s: send, -r: receive, -n: connect

Getting into scotest's code I could figure out the connect() call worked.

sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
bind(sk, (struct sockaddr *) &addr, sizeof(addr);
connect(sk, (struct sockaddr *) &addr, sizeof(addr);

These lines of code create an SCO connection (hcitool con, kernel debugfs, btmon, report the same as above).

But at this point: same symptoms: I can send packets (now I can choose how much and when I send, etc...), but none received.

EDIT: I tried on another computer: Intel XPS13 with a Qualcomm Ahteros Killer QCA6174 network card and the behavior is as expected on this chipset: as soon as an SCO connection is made scotest -n will connect and a whole bunch of these lines will flood btmon's output:

> SCO Data RX: Handle 9 flags 0x00 dlen 48                #819 [hci0] 16.686260
> SCO Data RX: Handle 9 flags 0x00 dlen 48                #820 [hci0] 16.696251
> SCO Data RX: Handle 9 flags 0x00 dlen 48                #821 [hci0] 16.696258
> SCO Data RX: Handle 9 flags 0x00 dlen 48                #822 [hci0] 16.696259
> SCO Data RX: Handle 9 flags 0x00 dlen 48                #823 [hci0] 16.706253
> SCO Data RX: Handle 9 flags 0x00 dlen 48                #824 [hci0] 16.706259
> SCO Data RX: Handle 9 flags 0x00 dlen 48                #825 [hci0] 16.706260
> SCO Data RX: Handle 9 flags 0x00 dlen 48                #826 [hci0] 16.706261
> SCO Data RX: Handle 9 flags 0x00 dlen 48                #827 [hci0] 16.716256
> SCO Data RX: Handle 9 flags 0x00 dlen 48                #828 [hci0] 16.716262

My hypothesis at this point is that it's an issue that has to do with SCO audio routing for the chipset, as mentioned here: https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Bluetooth/ EDIT

So I tried several things:

  • On the socket's file descriptor returned by connect() in scotest's code: replacing scotest's read() with recv() or recvmsg(), setting socket flag MSG_DONTWAIT: the call either waits infinitely (using read(), recv(), recvmsg()) or exits immediately (MSG_DONTWAIT flag on).
  • Fork()ing to read() and write() on the socket's file descriptor at the same time (duplexing).
  • Doing the connect() call at several time points during the SLC (beginning, after / indicators are modified, making pauses (using sleep() calls): Once the device is connected (RFCOMM launched), the leds on the headsets react to the existence of the SCO connection the same way they do with a phone (tipically: red when no connection, blue when SCO connection is on).
  • Figured out why the setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &opts, sizeof(opts)) call in scotest's dump_mode() returns an error "Invalid argument": because in the kernel the sk->sk_state is BT_CONNECTED since do_connect(). But that error does not affect the setting which is done earlier in do_connect if using the "-V 0x0060" command line parameter.
  • Modify the MTU size (hciconfig hci0 scomtu 60:8): It doesn't affect the related HCI command parameters (Setup Synchronous Connection ogf:0x01 | ocf:0x0028) at SCO connexion, but I use it to match with the packet size obtained from the Setup synchronous connexion response I see in btmon/hcidump (i.e. > HCI Event: Synchronous Connect Complete 0x2c: RX/TX packet length: 60)
  • Modify packet types, which I could only do by modifying the kernel: struct esco_param_cvsd[] in net/bluetooth/hci_conn.c. After kernel debugging I found out the commands "hciconfig 0 " or " hcitool cpt " can not affect the SCO connection setup hci command parameters. (I use a vanilla Kernel)
  • Use btsco (from this post), but I didn't give it a 'hard try': the docs do not mention kernel versions above 3 and the most recent tarball available are from 2006

From what I understand I tend to believe SCO Data packets should be incoming quite automatically. So I'm really wondering where I went wrong.

Vincent Achard
  • 221
  • 1
  • 10
  • post your code, ask question about specific error occurred when you try to use sco socket to send/receive packets. – EsmaeelE Jun 30 '17 at 14:07
  • I'm working on bluetooth socket programming with C too. If this post not solve your problem reach me at email, may i can help – EsmaeelE Jun 30 '17 at 14:10
  • Thanks EsmaeelE, I will eventually. Do you have any idea about what might block packets in my situtation? – Vincent Achard Jun 30 '17 at 15:13
  • Vincent if you not give any actual code i cant give any help... but i can implement a simple client-server app that do send from server side on PC_1 and listen to link( i.e. bluetooth channel) from PC_2 as client with sco socket (voice communication) . is it helpful for you? – EsmaeelE Jun 30 '17 at 16:30
  • EsmaeelE, the code I'm using is open source: it's all in bluez-5.45 package in tools/scotest.c. You can reproduce what I'm doing using: scotest -n -V 0x0060 . The only tweaking I did in scotest.c was using the send() call (from the send_mode() function) before a recv() or read() function, or merely modifying a setsockopt. No big remastering of the code. Creating an SCO connection between two computers is actually a very good idea! – Vincent Achard Jun 30 '17 at 17:10
  • Ok, great! I'll be out of office starting tomorrow for 3-5 days. I'll try to get some new ideas. I'll get back to you when I'm back. – Vincent Achard Jul 01 '17 at 10:16
  • I asked Intel: https://communities.intel.com/thread/116293 It seems they don't have the problem with Linux Ubuntu 16.04 Kernel: 4.4.0 / 4.8.0 / 4.10.0 / 4.12.3. I'm gonna have to try it... – Vincent Achard Jul 26 '17 at 15:44
  • I am also starts to work on scotest.c and try to send some message buffer for example, buf: "hello" over an sco socket that is successfully connected. Although its connects, send() return true buffer size length and recv() return received buffer size length but when i printf() received buffer its shows weired things (some negative numbers if i cast them each one to int). I tried this with write and read but not differ. – EsmaeelE Aug 16 '17 at 00:05
  • And what does btmon show when you send()/receive()? – Vincent Achard Aug 16 '17 at 07:25
  • https://github.com/esmaeelE/BT/blob/master/btmon.log – EsmaeelE Aug 16 '17 at 14:22
  • I think sco perform some changes on my buffer to make it suitable to send over BT socket because of sco is voice specific socket. I send a constant data and received different buffer each time. i test it over ten times – EsmaeelE Aug 16 '17 at 22:44
  • I test it with rfcomm and l2cap socket its work but when i try to apply this on sco socket not work. i send number over l2cap https://stackoverflow.com/questions/28020844/continuous-data-transfer-over-bluetooth/45703710#45703710 – EsmaeelE Aug 16 '17 at 22:49
  • Consider `scotest.c` I find out at the Rx side specially inside `recv_mode(int sk)`, the function `setsockopt()` not work properly, and possible this is point of error in our problem. `setsocket` returns negative value. check it on your machine. – EsmaeelE Aug 23 '17 at 21:35
  • Hi, sorry I'm out of office for personal reasons, will try as soon as I get back – Vincent Achard Aug 25 '17 at 05:50

0 Answers0