Yamaha YAS-207's Bluetooth protocol: basic recon


As explained in the Introductory post, I’m reversing the control interfaces of the Yamaha YAS-207 soundbar.

In this installment I’m doing a basic recon of the Bluetooth part.

And as before with the infrared protocol, my plans were thwarted by reality. If you don’t care about the journey, maybe skip to the next post when it’s available. Or maybe just to the Closing words section.


Figure out the bluetooth protocol used in YAS-207 soundbar’s remote app, the “Home Theater Controller”. Because I want to drive the soundbar from a raspi.

Sniff me some Bluetooth LE… or not

Having an Adafruit’s Bluefruit LE Sniffer1 I thought this part might be easy.

Bluefruit LE Sniffer Pic originally by Adafruit (CC-NC-SA 2.0 licensed), resized+cropped by me.

Only to find out that no, YAS-207 doesn’t support BLE. It speaks Bluetooth classic.

I guess reading the Specs page a little bit more carefully would help me avoid this blunder.

Because on the manufacturer’s website it not-so-clearly says:

It is my fault for interpreting it as BLE and/or Classic.

Moving on, we’ll have to do this some other way.

Now, since sniffing Bluetooth Classic is hard2, this situation got a lot more interesting.

Basic recon

OK, so that was a fail. Let’s at least see what protocols the device speaks:

# hcitool scan
Scanning ...
        C8:84:xx:xx:xx:xx       YAS-207  Yamaha

# hcitool info C8:84:xx:xx:xx:xx
Requesting information ...
        BD Address:  C8:84:xx:xx:xx:xx
        Device Name: YAS-207  Yamaha
        LMP Version: 4.2 (0x8) LMP Subversion: 0x30e7
        Manufacturer: Cambridge Silicon Radio (10)
        Features page 0: 0xff 0xff 0x8f 0xfe 0xdb 0xff 0x5b 0x87
                <3-slot packets> <5-slot packets> <encryption> <slot offset>
                <timing accuracy> <role switch> <hold mode> <sniff mode>
                <park state> <RSSI> <channel quality> <SCO link> <HV2 packets>
                <HV3 packets> <u-law log> <A-law log> <CVSD> <paging scheme>
                <power control> <transparent SCO> <broadcast encrypt>
                <EDR ACL 2 Mbps> <EDR ACL 3 Mbps> <enhanced iscan>
                <interlaced iscan> <interlaced pscan> <inquiry with RSSI>
                <extended SCO> <EV4 packets> <EV5 packets> <AFH cap. slave>
                <AFH class. slave> <LE support> <3-slot EDR ACL>
                <5-slot EDR ACL> <sniff subrating> <pause encryption>
                <AFH cap. master> <AFH class. master> <EDR eSCO 2 Mbps>
                <EDR eSCO 3 Mbps> <3-slot EDR eSCO> <extended inquiry>
                <LE and BR/EDR> <simple pairing> <encapsulated PDU>
                <non-flush flag> <LSTO> <inquiry TX power> <EPC>
                <extended features>
        Features page 1: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
        Features page 2: 0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00

So that doesn’t tell me much (not exactly Bluetooth expert, me).

Let’s pair with it and then begin interrogation:

# bluetoothctl pair C8:84:xx:xx:xx:xx
Attempting to pair with C8:84:xx:xx:xx:xx
[CHG] Device C8:84:xx:xx:xx:xx Connected: yes
[CHG] Device C8:84:xx:xx:xx:xx UUIDs: 00000000-deca-fade-deca-deafdecacaff
[CHG] Device C8:84:xx:xx:xx:xx UUIDs: 00001000-d102-11e1-9b23-00025b00a5a5
[CHG] Device C8:84:xx:xx:xx:xx UUIDs: 00001101-0000-1000-8000-00805f9b34fb
[CHG] Device C8:84:xx:xx:xx:xx UUIDs: 0000110b-0000-1000-8000-00805f9b34fb
[CHG] Device C8:84:xx:xx:xx:xx UUIDs: 00001200-0000-1000-8000-00805f9b34fb
[CHG] Device C8:84:xx:xx:xx:xx ServicesResolved: yes
[CHG] Device C8:84:xx:xx:xx:xx Paired: yes
Pairing successful

# bluetoothctl info C8:84:xx:xx:xx:xx
Device C8:84:xx:xx:xx:xx (public)
        Name: YAS-207  Yamaha
        Alias: YAS-207  Yamaha
        Class: 0x00240428
        Icon: audio-card
        Paired: yes
        Trusted: yes
        Blocked: no
        Connected: no
        LegacyPairing: no
        UUID: Vendor specific           (00000000-deca-fade-deca-deafdecacaff)
        UUID: Vendor specific           (00001000-d102-11e1-9b23-00025b00a5a5)
        UUID: Serial Port               (00001101-0000-1000-8000-00805f9b34fb)
        UUID: Audio Sink                (0000110b-0000-1000-8000-00805f9b34fb)
        UUID: PnP Information           (00001200-0000-1000-8000-00805f9b34fb)

Now we’re getting somewhere. They weren’t kidding about the serial port (1101 is SPP_UUID) and Audio Sink (110b is A2DP_SINK_UUID).

But there are multiple other services:

Let’s dig further:

# sdptool records C8:84:xx:xx:xx:xx
Service RecHandle: 0x10000
Service Class ID List:
  "Audio Sink" (0x110b)
Protocol Descriptor List:
  "L2CAP" (0x0100)
    PSM: 25
  "AVDTP" (0x0019)
    uint16: 0x0103
Profile Descriptor List:
  "Advanced Audio" (0x110d)
    Version: 0x0103

Service RecHandle: 0x10001
Service Class ID List:
  "PnP Information" (0x1200)

Service Name: SUBWOOFER
Service Description: Wireless Subwoofer
Service Provider: CSR
Service RecHandle: 0x10002
Service Class ID List:
  UUID 128: 00001000-d102-11e1-9b23-00025b00a5a5
Protocol Descriptor List:
  "L2CAP" (0x0100)
    PSM: 32769
Language Base Attr List:
  code_ISO639: 0x656e
  encoding:    0x6a
  base_offset: 0x100

Service Name: Wireless iAP
Service RecHandle: 0x10004
Service Class ID List:
  UUID 128: 00000000-deca-fade-deca-deafdecacaff
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 14
Language Base Attr List:
  code_ISO639: 0x656e
  encoding:    0x6a
  base_offset: 0x100

Service Name: SPP Dev
Service RecHandle: 0x10006
Service Class ID List:
  "Serial Port" (0x1101)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 1
Language Base Attr List:
  code_ISO639: 0x656e
  encoding:    0x6a
  base_offset: 0x100
Profile Descriptor List:
  "Serial Port" (0x1101)
    Version: 0x0102

OK, so the 00001000-d102-11e1-9b23-00025b00a5a5 is a service to support the wireless subwoofer. Makes sense.

There’s bunch more info to be had using sdptool records --tree C8:84:xx:xx:xx:xx but the output is rather long, and mostly boring, so I’ll skip it.

In any case, given the protocols exported, I’m betting that the remote control is done using the serial port.

But to get at it, I’ll have to get the communication dump elsewhere.

Second try: Let’s sniff it using Android

Fortunately, YAS-207 comes not only with an iOS app, but also with an Android app. And even though I’m nearly an Android virgin4

Little searching around the ’Net will score you an *.apk (application archive) of the “Home Theater Controller” in a jiffy. Wow. Such an (apk)pure experience.

Not having any Android hardware, I went on a hunt for an emulator… and ended up with something better. The nice people at android-x86.org did all the heavy lifting of getting Android to run on x865.

Thus one download of android-x86_64-7.1-r5.iso later, my VirtualBox was humming happily with fresh Android 7.1.26, connected to the VirtWifi wifi :-).

In order to sniff Bluetooth, you become a developer7, and in the “Developer options” enable:

and optionally disable “Verify apps over USB”.

And now the fun starts.

On my desktop, it pretty much went thusly:

$ adb connect
$ adb install the_home_controller.apk

Then I had the HT Controller app talk to the YAS-207. Successfully, I might add.

But now the question is – where do I get the promised log of all Bluetooth communication, the btsnoop_hci.log?

Turns out, on newer(?) androids the location is mentioned in /etc/bluetooth/bt_stack.conf. Therefore:

$ adb shell  grep BtSnoopFileName /etc/bluetooth/bt_stack.conf 

and then:

$ adb shell su -c "'cat /data/misc/bluetooth/logs/btsnoop_hci.log'" > btsnoop_hci.log
$ file btsnoop_hci.log
btsnoop_hci.log: BTSnoop version 1, HCI UART (H4)

So, yay! We can sniff. And wireshark reads that file natively (wireshark btsnoop_hci.log):


Closing words

In this somewhat lengthy piece8 I’ve done basic recon of the Bluetooth properties of the Yamaha YAS-207 soundbar, as well as some prep work for sniffing the traffic.

Findings so far:

  1. YAS-207 speaks Bluetooth Classic, not Bluetooth LE.
  2. The protocol is probably through Serial-over-Bluetooth (SPP), on channel 1.9
  3. I can dump (sniff) the communication log from Android in BTSnoop version 1, HCI UART (H4) format.

But I dislike the manualness of this process:

  1. I would like streaming solution, not one-off done by downloading a file.
  2. I need to find a way to parse the HCI log somehow.

More on that in next installment(s), watch the yas 207 tag.

  1. An nRF51822-based stick that costs about $25. The sniffer version has promiscuous firmware that streams to Wireshark, see Adafruit’s guide for intro, install instructions, etc.

  2. I don’t have the hardware; donations of “Ubertooth One” are welcome. :-)

  3. Surprisingly (as you’ll find out below), this is another Serial-over-BT protocol, but we don’t care about it. From what I was able to gather, the communication is guarded by a crypto chip – to separate the deep-pocketed royalty from the plebs.

  4. Never owned an Android phone. Also aside from brief stint with Android Wear never used it much.

  5. I bet you did not expect that punchline.

  6. There are guides how to run it in VirtualBox, but essentially: boot it with BT dongle attached in the Live CD VESA mode (from the “Advanced options” menu).

  7. Click the Build number bunch of times in SettingsAbout tablet.

  8. I blame the debug outputs. It for sure can’t be my blundering around due to sheer lack of qualification.

  9. Forgot to mention – had a brief looksie at the BT specs and the A2DP sink isn’t capable of remote control; there’s a different protocol for that. So either it’s the SPP, or Yamaha went the Microsoft way and extended existing protocol with a proprietary addon. Hope it’s the former.