I'm building an Android app that connects to two BLE peripherals simultaneously (two separate BluetoothGatt connections, both created via device.connectGatt(this, false, callback, BluetoothDevice.TRANSPORT_LE)). Each peripheral streams sensor data at a fixed sample rate, and I need both connections to sustain roughly the same packet throughput.
When only ONE peripheral is connected, it reliably reaches the expected packet rate (~42 packets/sec, matching the theoretical rate for the given packet size and sample rate).
When BOTH peripherals are connected simultaneously, calling requestConnectionPriority(CONNECTION_PRIORITY_HIGH) on both connections (right after onMtuChanged fires) results in only one connection reaching high speed, while the other is throttled down to ~2–7 packets/sec — even though both calls return true.
requestConnectionPriority() calls return true (not a permission or API-misuse issue).| Device | SoC | Bluetooth version | Behavior | |---|---|---|---| | Device A | Qualcomm Snapdragon 6 Gen 1 | BT 5.1 | Both connections sustain ~42 pkt/s simultaneously | | Device B | (similar mid-range chipset, comparable results) | BT 5.1-class | Both connections sustain full speed simultaneously | | Device C | MediaTek Dimensity 6300 | BT 5.2/5.3 | Only one connection reaches full speed; the other is capped at ~2–7 pkt/s regardless of priority requests |
Interestingly, the device with the older Bluetooth version handles concurrent high-priority connections fine, while the device with the newer version does not — suggesting this is about controller/firmware scheduling capability rather than the BT spec version.
1. Single request per connection (in onMtuChanged):
override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) { super.onMtuChanged(gatt, mtu, status) val result = gatt?.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH) Log.i("BLE", "requestConnectionPriority(HIGH) result=$result") }
Result on the problematic device: one connection stays permanently capped at low throughput for the rest of the session, even though the call succeeded.
2. Periodic rotation — every few seconds, alternate which connection gets CONNECTION_PRIORITY_HIGH while explicitly demoting the other to CONNECTION_PRIORITY_BALANCED:
// runs every ~4s via Handler.postDelayed if (rotateToA) { gattA.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH) gattB.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED) } else { gattB.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH) gattA.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED) }
This does work — both connections now alternate between high and low throughput instead of one being permanently starved — but neither connection sustains full speed continuously; average throughput per connection ends up around 25–35 pkt/s with noticeable oscillation, rather than both connections holding steady at ~42 pkt/s.
Is there a known way (public API, undocumented flag, or best practice) to get two concurrent BLE GATT connections to both maintain a short connection interval simultaneously on chipsets that otherwise seem to only fully honor one high-priority connection at a time? Or is this fundamentally a controller/firmware scheduling limitation with no app-level workaround beyond periodic priority rotation?
I'm aware requestConnectionPriority() is documented as best-effort, so I'm not expecting a guarantee — but I'd like to know if there's a more effective technique than what I've tried, or confirmation that this is a known hardware limitation on certain mid-range chipsets.