Bluetooth Multiple connections, stuck in "connecting" state

Hi,

There is a random issue I am facing where if I'm trying to connect to a device, it goes to connecting state but even after waiting quite a while, the state doesn't become connected, neither does connection fails.

The issue is more observable when connecting to multiple devices, for eg if i'm connecting to 8 devices, sometimes 1 gets stuck in connecting state. In an even rarer case, all devices start getting stuck in connecting state. Killing the app and opening seems to resolve the issue but a few days later the issue resurfaces.

This is what I'm doing regarding CBBluetoothManager:

  1. Define two dispatch queues
fileprivate let bluetoothQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".CBCentralManager")

fileprivate let nonBluetoothQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".CBCentralManager.2")
  1. Define centralManager
private lazy var defaultCentralManager = CBCentralManager(delegate: self,
                               queue: bluetoothQueue,
                               options: [
                                CBCentralManagerOptionShowPowerAlertKey: true,
                                CBCentralManagerOptionRestoreIdentifierKey: "MyCBCentralManager"
  ])
  1. Start and stop scan
func start() {
    isScanningRequested = true
    bluetoothQueue.async {
      self.centralManagerDidUpdateState(self.defaultCentralManager)
    }
  }
   
  func stop() {
    isScanningRequested = false
    restartScanJob?.cancel()
    bluetoothQueue.async {
      self.centralManagerDidUpdateState(self.defaultCentralManager)
    }
  }

   func centralManagerDidUpdateState(_ central: CBCentralManager) {
    nonBluetoothQueue.async { [self] in
      switch central.state {
      case .poweredOn:
        if(isScanningRequested){
          Logger.log(priority: .INFO, message: "starting scan")
          restartScanJob?.cancel()
          restartScanJob = DispatchWorkItem(block: {
            self.start()
          })
          bluetoothQueue.asyncAfter(deadline: .now() + .seconds(120), execute: restartScanJob!)
          //Restarting after 2 mins as it is observed that scan slows down after sometime
          central.scanForPeripherals(withServices: getServiceCBUUIDs(), options:[CBCentralManagerScanOptionAllowDuplicatesKey: true] )
        }
        else{
          Logger.log(priority: .INFO, message: "stopping scan")
          central.stopScan()
        }
        break
      default:
        break
      }
    }
  }
  1. All delegate functions run in nonBluetoothQueue so as to return the function immediately. Following is one example
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    nonBluetoothQueue.async { [self] in
      guard let extendedPeripheral : ExtendedPeripheral = getExtendedPeriperal(from: peripheral) else {
        Logger.log(priority: .ERROR, message: "Connected to unknown \(peripheral.identifier.uuidString) disconnecting")
        defaultCentralManager.cancelPeripheralConnection(peripheral)
        return
      }
      Logger.log(priority: .DEBUG, message: "Connected to \(peripheral.identifier.uuidString)")
      extendedPeripheral.connected = true
      delegate.didConnect(extendedPeripheral)
      peripheral.discoverServices(nil);
    }
  }

PS. ExtendedPeripheral is a wrapper class to store the CBPeripheral object

  1. I also have a safety check to not call connect repeatedly. This was done because I used to observe the connection getting delayed if calling connect when it's already connecting
private func connect(to extendedPeripheral : ExtendedPeripheral) {
    if (extendedPeripheral.cbPeripheral.state == .connected || extendedPeripheral.cbPeripheral.state == .connecting) {
      Logger.log(priority: .WARN, message: "Will not connect. Current state is \(extendedPeripheral.cbPeripheral.state)")
      return
    }
    Logger.log(priority: .INFO, message: "Connecting to " + extendedPeripheral.identifier.uuidString)
    defaultCentralManager.connect(extendedPeripheral.cbPeripheral)
  }
Bluetooth Multiple connections, stuck in "connecting" state
 
 
Q