Web Bluetooth MTU samplers

Browser-side test pages and matching ESP32-C3 firmware that exercise the Web Bluetooth ATT MTU exchange path in Chromium. Used to observe behavior of issues 40265040, 40686244 and 40163619 across platforms.

Tracked issues

#40163619 Fixed Feature
WebBluetooth: not implemented "Exchange MTU" step
Chromium performs the ATT Exchange MTU procedure (since Chrome 98 via kWebBluetoothRequestLargerMtu). Demos consistently see effective MTU 517.
#40163619
#40265040 Assigned Feature
Support getMTU() in Web Bluetooth
Adds a BluetoothRemoteGATTCharacteristic.getMTU() method.
#40265040
#40686244 Assigned Bug
20 byte MTU for web-bluetooth on Windows Chrome
Historically, writeValueWithoutResponse() rejected payloads > 20 bytes on Windows. Current behavior on Windows: 1 to 512 byte writes succeed on both APIs.
#40686244

Required Chrome flags

Launch Chrome with the flag below so getMTU() and the new BLE GATT session handling are available:

--enable-features=NewBLEGattSessionHandling,WebBluetooth

The flag is only required for the new MTU API; the write-size and image-streaming demos otherwise work on stable Chrome too.

Firmware

ESP32C3_All_BLE_Tester

Flash ESP32C3_All_BLE_Tester to a single ESP32-C3 board. It advertises as dino tester and serves both demos from the same characteristic:

Service:        0000ffe0-0000-1000-8000-00805f9b34fb
Characteristic: 0000ffe1-0000-1000-8000-00805f9b34fb
Device name:    dino tester

Demos

1. Progressive JPEG streamer demonstrates #40163619 + #40265040

Pulls a progressive JPEG over BLE notifications and progressively decodes it in the browser.

Connects to the dino tester peripheral, calls getMTU(), then pulls the embedded progressive JPEG chunk-by-chunk using a get <seq> pull-mode protocol. The browser reassembles the JPEG and paints successive scans (blurry to sharp) as bytes arrive. Notification payload is capped at 244 bytes to work around the Chromium notification cap on macOS/CoreBluetooth (see notes below).

2. getMTU() conformance tests #40265040

Focused pass/fail conformance suite for the new BluetoothRemoteGATTCharacteristic.getMTU() API.

Runs eight checks against the new API: it exists, returns a Promise, resolves to an integer in the spec range, matches the device-reported peerMTU, is idempotent, handles concurrent calls, and the reported MTU actually drives the maximum write size. Point reviewers at this page on each platform to verify the API end-to-end.

3. Write-size probe demonstrates #40686244

Sweeps payload sizes through both write APIs and verifies received length on the peripheral.

Connects to the same dino tester peripheral, then writes a deterministic payload at sizes 1, 19, 20, 21, 22, 32, 64, 100, 182, 200, 244, 247, 300, 400, 512 through both writeValueWithResponse() and writeValueWithoutResponse(). The firmware echoes the actual received length so the page can flag silent truncation. On Windows with effective MTU 517, both APIs accept payloads up to 512 bytes.

Hardware

Tested with an ESP32-C3 SuperMini development board (ESP32-C3FN4). Any ESP32-C3 with the Espressif Arduino core and the NimBLE-Arduino library should work.

Serial monitor baud: 115200. Recommended Arduino IDE settings:

Board:           ESP32C3 Dev Module
USB CDC On Boot: Enabled
Flash Size:      4MB
CPU Frequency:   160MHz
Upload Speed:    921600

Chrome for Android builds

Pre-built Chrome for Android APKs from CL 7879985 ("Web Bluetooth: Expose ATT MTU via getMTU()"), on top of Chromium main. Install with adb install -r <file>.apk on a device with the prior Chrome uninstalled. Launch flag still required at runtime:

adb shell 'echo --enable-features=NewBLEGattSessionHandling,WebBluetooth > /data/local/tmp/chrome-command-line'
arm64-v8a (most physical devices)
466 MB
Download APK
sha256
5496607eb14bf0c59211850a30c2fe3569fb810e65e170156790ba9b744b5bf4
x86 (Android emulator / x86 devices)
462 MB
Download APK
sha256
ae88532f422d1c451de3c66cb87438feaccdef9609e0655fef9114ab7614c535

SHA256SUMS