requestMtu method
Request to change MTU (Android Only)
- returns new MTU
predelay
adds delay to avoid race conditions on some devices. see comments below.
Implementation
Future<int> requestMtu(int desiredMtu,
{double predelay = 0.35, int timeout = 15}) async {
// check android
// if (Platform.isAndroid == false) {
// throw FlutterBluePlusException(ErrorPlatform.fbp, "requestMtu",
// FbpErrorCode.androidOnly.index, "android-only");
// }
// check connected
if (isDisconnected) {
throw FlutterBluePlusException(ErrorPlatform.fbp, "requestMtu",
FbpErrorCode.deviceIsDisconnected.index, "device is not connected");
}
// Only allow a single ble operation to be underway at a time
_Mutex mtx = _MutexFactory.getMutexForKey("global");
await mtx.take();
// predelay
if (predelay > 0) {
// hack: By adding delay before we call `requestMtu`, we can avoid
// a race condition that can cause `discoverServices` to timeout or fail.
//
// Note: This hack is only needed for devices that automatically send an
// MTU update right after connection. If your device does not do that,
// you can set this delay to zero. Other people may need to increase it!
//
// The race condition goes like this:
// 1. you call `requestMtu` right after connection
// 2. some devices automatically send a new MTU right after connection, without being asked
// 3. your call to `requestMtu` confuses the results from step 1 and step 2, and returns to early
// 4. the user then calls `discoverServices`, thinking that `requestMtu` has finished
// 5. in reality, `requestMtu` is still happening, and the call to `discoverServices` will fail/timeout
//
// Adding delay before we call `requestMtu` helps ensure
// that the automatic mtu update has already happened.
await Future.delayed(Duration(milliseconds: (predelay * 1000).toInt()));
}
var mtu = 0;
try {
var request = BmMtuChangeRequest(
remoteId: remoteId,
mtu: desiredMtu,
);
var responseStream = FlutterBluePlus._methodStream.stream
.where((m) => m.method == "OnMtuChanged")
.map((m) => m.arguments)
.map((args) => BmMtuChangedResponse.fromMap(args))
.where((p) => p.remoteId == remoteId)
.map((p) => p.mtu);
// Start listening now, before invokeMethod, to ensure we don't miss the response
Future<int> futureResponse = responseStream.first;
// invoke
await FlutterBluePlus._invokeMethod('requestMtu', request.toMap());
// wait for response
mtu = await futureResponse
.fbpEnsureAdapterIsOn("requestMtu")
.fbpEnsureDeviceIsConnected(this, "requestMtu")
.fbpTimeout(timeout, "requestMtu");
} finally {
mtx.give();
}
return mtu;
}