Connecting to a BLE Peripheral on linux - bluez

417 views
Skip to first unread message

mario...@gmail.com

unread,
Mar 12, 2019, 9:01:33 AM3/12/19
to android-midi
Hi

I have written a BLE peripheral app running on linux using bluez - dbus (in python)


it advertises a MIDI Service with a MIDI Characteristics.

If I use apps like GATT Browser and BluetoothLeGatt I can browse my device and read / write values.

When I try to use MIDI+BTLE on the other hand, what happens is

Scan is successful, but the device disappears after 2-3 seconds and no Read/Write operations are ever sent to my device.

Does anybody know exactly what the Android BLE Midi code checks in determining if a device is a valid MIDI?

I have created a service and a characteristic like

class MIDICharacteristic(egs.Characteristic):
    def __init__(self, bus, index, service):
        flags = ['notify', 'read', 'write', 'write-without-response']
        super().__init__(bus, index, MIDI_CHARACTERISTIC_UUID, flags, service)

class MIDIService(egs.Service):
    def __init__(self, bus, index):
        super().__init__(bus, index, MIDI_SERVICE_UUID, True)
        self.add_characteristic(MIDICharacteristic(bus, 0, self))

with

MIDI_SERVICE_UUID = '03b80e5a-ede8-4b33-a751-6ce34ec4c700'
MIDI_CHARACTERISTIC_UUID = '7772e5db-3868-4112-a1a9-f2669d106bf3'

The steps seems so easy that I am not sure what should be changed.
The hardware works, because the other apps can interoperate, but I think I am not advertising a MIDI service 100% correct and so the Android code tries something and then drops it as invalid.

Does anybody have some hint?

mario...@gmail.com

unread,
Mar 12, 2019, 10:32:55 AM3/12/19
to android-midi
This behaviour might be related to something I reported here as well.

Even on a real piano, the device can disappear after a few seconds, but if one tries 3 or 4 times, then the connection is more stable.
Is it possible to access some logging to understand why the android kernel decided to drop the connection?

Andrea

Phil Burk

unread,
Mar 12, 2019, 10:36:59 AM3/12/19
to android-midi
Hello Mario,

What Android devices and versions are you testing?

Links to the source code for the MIDI+BTLE app are here:
Is that the one you are using?

After the scan do you press the button and does it connect?
Or does it disappear from the scan before you can connect?

On your device, can you see the Android trying to negotiate a connection?

Are you encrypting packets?

Do you have the BLE-MIDI spec from the MMA on midi.org?

Here are some old notes on getting a snoop log from Android and opening it in WireShark:
  1. In Settings / Developer Options / Enable Bluetooth HCI Snoop Log
  2. Find out where Snoop log is written:
  3.    adb shell grep Snoop /etc/bluetooth/bt_stack.conf
  4. Look for something like:      BtSnoopFileName=/data/misc/bluetooth/logs/btsnoop_hci.log
  5. Reboot and connect the Bluetooth Device using the MIDI+BTLE app.
  6. Enter:  adb root
  7. Enter something like:
  8.    adb pull /data/misc/bluetooth/logs/btsnoop_hci.log ~/my_snoop_file.log
  9. Open ~/my_snoop_file.log in WireShark
from "frameworks/base/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java"

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                BluetoothGattService service = gatt.getService(MIDI_SERVICE);
                if (service != null) {
                    Log.d(TAG, "found MIDI_SERVICE");
                    BluetoothGattCharacteristic characteristic
                            = service.getCharacteristic(MIDI_CHARACTERISTIC);
                    if (characteristic != null) {
                        Log.d(TAG, "found MIDI_CHARACTERISTIC");
                        mCharacteristic = characteristic;

                        // Request a lower Connection Interval for better latency.
                        boolean result = gatt.requestConnectionPriority(
                                BluetoothGatt.CONNECTION_PRIORITY_HIGH);
                        Log.d(TAG, "requestConnectionPriority(CONNECTION_PRIORITY_HIGH):"
                            + result);

                        // Specification says to read the characteristic first and then
                        // switch to receiving notifications
                        mBluetoothGatt.readCharacteristic(characteristic);
                    }
                }
            } else {
                Log.e(TAG, "onServicesDiscovered received: " + status);
                close();
            }
        }

Phil Burk

--
You received this message because you are subscribed to the Google Groups "android-midi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-midi...@googlegroups.com.
To post to this group, send email to androi...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/android-midi/90d87f67-9910-42ad-a209-d59716da3755%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

mario...@gmail.com

unread,
Mar 12, 2019, 10:48:33 AM3/12/19
to android-midi
Galaxy Samsung S2, Android 7, API 24, kernel 3.10.9

I am using both the App from the appstore and th eone I compiled myself, and another one I am writing based on the same code.
All behaves the same.

While scanning the device is always there.
When I press on it, it goes back in the main activity (where it tries to create a MidiDevice), then it stays there for a few seconds (during which I can select it in a MidiPortSelector if I am quick enough in a different app),
then it disappears.

I will try to get some logs.

and it is really simple, compatible with what you have copied above.

But, I do not ever see this happening: if I use the 2 apps mentioned above I can see on my PC the Read requests, but this one never appears.

mario...@gmail.com

unread,
Mar 12, 2019, 11:04:10 AM3/12/19
to android-midi
I got the log, but it does not let me attach it here.

mario...@gmail.com

unread,
Mar 12, 2019, 11:10:23 AM3/12/19
to android-midi
This line is towards the end and it might be (or not) the problem

Event Code: Connect Complete (0x03)
Parameter Total Length: 11
Status: Connection Rejected due to Unacceptable BD_ADDR (0x0f)
Connection Handle: 0x000b
BD_ADDR: Cyber-Bl_da:71:0b (00:1a:7d:da:71:0b)
Link Type: ACL connection (Data Channels) (0x01)
Encryption Mode: Encryption Disabled (0x00)

Googled it, but did not understand much

mario...@gmail.com

unread,
Mar 12, 2019, 11:34:07 AM3/12/19
to android-midi
Tried on a Android 8,

kernel 3.18.91,

same behaviour

mario...@gmail.com

unread,
Mar 12, 2019, 12:24:29 PM3/12/19
to android-midi
I've changed the PC mac address to something else and now the connections stays up about 8 seconds.
Then it goes

in Android studio I can see the lines below in logcat

Where PIETR B9:... is the correct pepripheral.

How do I get the log of the piece of code you have copied it above? I do not think we are there yet, it must stop sooner.

Here the bluetooth log file


2019-03-12 16:12:56.662 3453-3548/? D/BtGatt.GattService: onConnected() - clientIf=7, connId=0, address=B9:1A:75:DD:34:XX
2019-03-12 16:12:56.663 3453-3548/? W/bt_btif: btif_dm_upstreams_cback  ev: UNKNOWN DM EVENT
2019-03-12 16:12:56.663 11829-11843/? D/BluetoothGatt: onClientConnectionState() - status=133 clientIf=7 device=B9:1A:75:DD:34:XX
2019-03-12 16:12:56.669 11829-11843/? I/BluetoothMidiDevice: Disconnected from GATT server.
2019-03-12 16:12:56.669 11829-20107/? D/BluetoothMidiDevice: BluetoothMidiDevice thread exit
2019-03-12 16:12:56.672 11829-11843/? D/BluetoothGatt: close()
2019-03-12 16:12:56.674 11829-11843/? D/BluetoothGatt: unregisterApp() - mClientIf=7
2019-03-12 16:12:56.676 3453-4701/? D/BtGatt.GattService: unregisterClient() - clientIf=7
2019-03-12 16:12:56.680 20031-20031/? I/MidiTools: #9, PIETER[0],  was removed
2019-03-12 16:12:56.685 3453-3538/? D/BluetoothAdapterService: getAdapterService() - returning com.android.bluetooth.btservice.AdapterService@be95ce3
2019-03-12 16:12:56.692 3465-3664/? D/BluetoothEventManager: onReceive :: getAction = android.bluetooth.device.action.NAME_CHANGED
2019-03-12 16:12:56.692 3203-7616/? V/WindowManager: Relayout Window{d384a60d0 u0 com.mobileer.example.midibtlepairing/com.mobileer.example.midibtlepairing.MainActivity}: viewVisibility=0 req=1536x2048 WM.LayoutParams{(0,0)(fillxfill) sim=#20 ty=1 fl=#81810100 wanim=0x103038a vsysui=0x600 needsMenuKey=2 naviIconColor=0}
2019-03-12 16:12:56.693 3453-3548/? D/BluetoothUtils: getBtEnabledContainers(): btContainers = []
2019-03-12 16:12:56.698 3465-3664/? D/BluetoothEventManager: onReceive :: getAction = android.bluetooth.device.action.CLASS_CHANGED
2019-03-12 16:12:56.698 3453-3548/? D/BluetoothUtils: getBtEnabledContainers(): btContainers = []
2019-03-12 16:12:56.698 3453-3548/? E/BluetoothRemoteDevices: devicePropertyChangedCallback: bdDevice: B9:1A:75:DD:34:XX, value is empty for type: 241

mario...@gmail.com

unread,
Mar 12, 2019, 2:48:34 PM3/12/19
to android-midi
So some more debugging.
This is when it connects to a CA78

2019-03-12 18:32:30.493 28710-28710/? I/MidiBtlePairing: Bluetooth device name = CA78, address = F5:EA:4F:2E:BD:74
2019-03-12 18:32:30.496 11829-11896/? D/BluetoothGatt: connect() - device: F5:EA:4F:2E:BD:XX, auto: false
2019-03-12 18:32:30.496 11829-11896/? D/BluetoothAdapter: isSecureModeEnabled
2019-03-12 18:32:30.497 11829-11896/? D/BluetoothGatt: registerApp()
2019-03-12 18:32:30.497 11829-11896/? D/BluetoothGatt: registerApp() - UUID=40c1d97e-f768-45a5-a9cc-6bfdaa3e0de1
2019-03-12 18:32:30.599 11829-11843/? D/BluetoothGatt: onClientRegistered() - status=0 clientIf=6
2019-03-12 18:32:31.276 3465-3664/? D/BluetoothEventManager: onReceive :: getAction = android.bluetooth.device.action.NAME_CHANGED
2019-03-12 18:32:31.276 3453-3548/? D/BluetoothUtils: getBtEnabledContainers(): btContainers = []
2019-03-12 18:32:31.311 3453-3548/? E/BluetoothRemoteDevices: aclStateChangeCallback: State:Connected to Device:F5:EA:4F:2E:BD:XX, linktype is 2
2019-03-12 18:32:31.315 3453-3548/? D/BluetoothUtils: getBtEnabledContainers(): btContainers = []
2019-03-12 18:32:31.318 6171-6171/? I/oneconnect[1.7.27-25_04][CORE]: BluetoothHelper.handleActionConnectionStateChanged -  [action]android.bluetooth.device.action.ACL_CONNECTED [connState]0[address] - ($)
2019-03-12 18:32:31.326 11829-11899/? D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=F5:EA:4F:2E:BD:XX
2019-03-12 18:32:31.333 6171-6349/? D/BluetoothA2dp: getState(F5:EA:4F:2E:BD:XX)
2019-03-12 18:32:31.340 11829-11899/? I/BluetoothMidiDevice: Connected to GATT server.
2019-03-12 18:32:31.341 11829-11899/? D/BluetoothGatt: discoverServices() - device: F5:EA:4F:2E:BD:XX
2019-03-12 18:32:31.344 11829-11899/? I/BluetoothMidiDevice: Attempting to start service discovery:true
2019-03-12 18:32:31.350 6171-6349/? D/BluetoothHeadset: getConnectionState() in if statement
2019-03-12 18:32:31.368 3453-4261/? E/BluetoothRemoteDevices: getGearIsConnected false
2019-03-12 18:32:31.393 6171-6349/? I/oneconnect[1.7.27-25_04][CORE]: BluetoothHelper.getManufacturerData -  - ($)
2019-03-12 18:32:31.418 6171-6349/? I/oneconnect[1.7.27-25_04][CORE]: BluetoothHelper.addDevice - ADD: [Name]CA78[DeviceType]UNKNOWN[Discover]_BT[Services]None[Connected]false[Alias]null[Class]7936[BatteryLevel]-1[Battery]-1[Bonded]false[ConnectedA2dpSink]false[ConnectedA2dpSinkByOtherModule]false[SecType]Unknown[A2dpSink]false[HasAppLinkerPkg]0[PluginTypes]null
2019-03-12 18:32:31.917 11829-11896/? D/BluetoothGatt: onClientConnParamsChanged() - Device=F5:EA:4F:2E:BD:XX interval=6 status=0
2019-03-12 18:32:32.280 11829-11844/? D/BluetoothGatt: onSearchComplete() = Device=F5:EA:4F:2E:BD:XX Status=0
2019-03-12 18:32:32.281 11829-11844/? D/BluetoothMidiDevice: found MIDI_SERVICE
2019-03-12 18:32:32.281 11829-11844/? D/BluetoothMidiDevice: found MIDI_CHARACTERISTIC
2019-03-12 18:32:32.320 11829-11843/? W/BluetoothGatt: onCharacteristicRead() - Device=F5:EA:4F:2E:BD:XX handle=27 Status=0
2019-03-12 18:32:32.321 11829-11843/? D/BluetoothMidiDevice: onCharacteristicRead 0
2019-03-12 18:32:32.321 11829-11843/? D/BluetoothGatt: setCharacteristicNotification() - uuid: 7772e5db-3868-4112-a1a9-f2669d106bf3 enable: true
2019-03-12 18:32:32.329 11829-11843/? D/BluetoothMidiDevice: writeDescriptor returned true
2019-03-12 18:32:32.383 11829-11899/? D/BluetoothGatt: onClientConnParamsChanged() - Device=F5:EA:4F:2E:BD:XX interval=39 status=0

This is when it tries to connect to my bluez app

2019-03-12 18:35:41.905 28710-28710/? I/MidiBtlePairing: Bluetooth device name = Andrea MIDI, address = B9:1A:75:DD:34:02
2019-03-12 18:35:41.907 11829-11899/? D/BluetoothGatt: connect() - device: B9:1A:75:DD:34:XX, auto: false
2019-03-12 18:35:41.907 11829-11899/? D/BluetoothAdapter: isSecureModeEnabled
2019-03-12 18:35:41.908 11829-11899/? D/BluetoothGatt: registerApp()
2019-03-12 18:35:41.908 11829-11899/? D/BluetoothGatt: registerApp() - UUID=5b5e0db8-4ba4-401e-b5f3-aceb9e974e22
2019-03-12 18:35:42.009 11829-11896/? D/BluetoothGatt: onClientRegistered() - status=0 clientIf=6
2019-03-12 18:35:48.424 11829-11843/? D/BluetoothGatt: onClientConnectionState() - status=133 clientIf=6 device=B9:1A:75:DD:34:XX
2019-03-12 18:35:48.431 11829-11843/? I/BluetoothMidiDevice: Disconnected from GATT server.
2019-03-12 18:35:48.431 11829-593/? D/BluetoothMidiDevice: BluetoothMidiDevice thread exit
2019-03-12 18:35:48.434 11829-11843/? D/BluetoothGatt: close()
2019-03-12 18:35:48.436 11829-11843/? D/BluetoothGatt: unregisterApp() - mClientIf=6

You see they start very similarly, but then the good one does something including 

2019-03-12 18:32:31.418 6171-6349/? I/oneconnect[1.7.27-25_04][CORE]: BluetoothHelper.addDevice - ADD: [Name]CA78[DeviceType]UNKNOWN[Discover]_BT[Services]None[Connected]false[Alias]null[Class]7936[BatteryLevel]-1[Battery]-1[Bonded]false[ConnectedA2dpSink]false[ConnectedA2dpSinkByOtherModule]false[SecType]Unknown[A2dpSink]false[HasAppLinkerPkg]0[PluginTypes]null
2019-03-12 18:32:31.917 11829-11896/? D/BluetoothGatt: onClientConnParamsChanged() - Device=F5:EA:4F:2E:BD:XX interval=6 status=0
2019-03-12 18:32:32.280 11829-11844/? D/BluetoothGatt: onSearchComplete() = Device=F5:EA:4F:2E:BD:XX Status=0
2019-03-12 18:32:32.281 11829-11844/? D/BluetoothMidiDevice: found MIDI_SERVICE
2019-03-12 18:32:32.281 11829-11844/? D/BluetoothMidiDevice: found MIDI_CHARACTERISTIC
2019-03-12 18:32:32.320 11829-11843/? W/BluetoothGatt: onCharacteristicRead() - Device=F5:EA:4F:2E:BD:XX handle=27 Status=0

which is really the key.

Does it ring any bell?
Is it because it does not provide ManufactureData and so on?

Phil Burk

unread,
Mar 13, 2019, 1:56:51 PM3/13/19
to android-midi
I asked a Bluetooth expert to look at this. He said that Samsung uses a different Bluetooth stack. So this may be specific to Samsung.

Can you try connecting to a non-Samsung device?

mario...@gmail.com

unread,
Mar 13, 2019, 5:14:45 PM3/13/19
to android-midi
I have already tried a Moto G4, but I have not captured the logs.

One thing I wanted to understand is: who creates a BluetoothMidiDevice?

I am going to copy that code and call it directly, so to debug that side of the story, but I think the issue is before.


and nowhere there is anything calling the constructor of a BluetoothMidiDevice?
How is this supposed to work?

What connects  MidiManager.openBluetoothDevice to a BluetoothMidiDevice?

mario...@gmail.com

unread,
Mar 13, 2019, 5:55:46 PM3/13/19
to android-midi
I have tried a different app, this time written using the C interface to bluez


and the behaviour is exactly the same: it can be browsed using GATT browser apps, but in the MIDI+BTLE app it never gets to the point of reading the MIDI characteristic.
It stop somewhere before.

This happens with a Samsung and Motorola Moto G4 both running Android 7.



On Wednesday, March 13, 2019 at 5:56:51 PM UTC, Phil Burk wrote:

mario...@gmail.com

unread,
Mar 17, 2019, 4:05:53 AM3/17/19
to android-midi
I have made some progress and I need to amend some of my early conclusions.

I can reproduce the issue with a manual call to

BluetoothDevice.connectGatt().

The first time my callabck is called I get

2019-03-12 18:35:48.424 11829-11843/? D/BluetoothGatt: onClientConnectionState() - status=133 clientIf=6 device=B9:1A:75:DD:34:XX

which ends the connection.

It seems it is a subtle issue with no easy solution


I would like to see the source code of the apps able to browse my peripheral, but it is not available.

mario...@gmail.com

unread,
Mar 17, 2019, 7:45:54 AM3/17/19
to android-midi
After further debugging, following the advice to specify the transport to TRANSPORT_LE
in the constructor of BluetoothMidiDevice to the Gatt call

BluetoothDevice.connectGatt( argument n 4)

makes it possible to connect to the peripheral (not always but 50% of the times). So that the code can proceed to querying the characteristics.


Quick read at this as well


it recommends to set the transport explicitly.

Now, all my tests are not done in the correct MIDI Framework, but just trying to connect to the device in some test code.
I would like to try to pass TRANSPORT_LE to the connectGatt call made in the MIDI Framework.
Is it possible? Maybe with some reflection-magic? Code-injection?

Does anybody know something more about this?

Thank you

Phil Burk

unread,
Mar 18, 2019, 1:39:49 PM3/18/19
to android-midi
Hello Mario,

It sound like you are making progress.

> Now, all my tests are not done in the correct MIDI Framework, but just trying to connect to the device in some test code.

So it seems the issue is not specific to MIDI and is actually a very deep technical Bluetooth issue.  While I am sure that the people on this MIDI list want to help, we probably do not have the expertise you need.

I recommend opening an Android bug/question related to Bluetooth and summarize your findings. Send me the bug number and I will make sure someone in the Bluetooth team takes a look.

Or send a note to the android-ndk list.

Thanks,
Phil Burk

mario...@gmail.com

unread,
Mar 18, 2019, 5:33:07 PM3/18/19
to android-midi
On the other hand, the parameters passed to the bluetooth stack are specific to BluetoothMidiDevice, so if one wanted to try a different combination would have to change the MIDI Bluetooth code, rather than the Bluetooth code itself.

What you could help with, is to explain how one can change the code in BluetoothMidiDevice and try it to see if it works.
Do I need a rooted device to do it? If it is a change required on the Android OS itself, I will probably not live long enough to see it delivered...

I will see what I can do...
Reply all
Reply to author
Forward
0 new messages