AVAudioSession's "availableInputs" not update in time

// Here addObserver for routeChangeNotification
    func testAudioRoute() {
        // My app is an VoIP app, so I need to set "playAndRecord" and "allowBluetooth"
        try? AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: [.duckOthers, .allowBluetooth, .allowBluetoothA2DP])
        
        NotificationCenter.default.addObserver(self, selector: #selector(currentRouteChanged(noti:)), name: AVAudioSession.routeChangeNotification, object: nil)
    }


// Print the "availableInputs" once got a notification
 @objc func currentRouteChanged(noti: Notification) {
        let availableInputs = AVAudioSession.sharedInstance().availableInputs?.compactMap({ $0.portType }) ?? []
        let currentRouteInputs = AVAudioSession.sharedInstance().currentRoute.inputs.compactMap({ $0.portType })
        let currentRouteOutputs = AVAudioSession.sharedInstance().currentRoute.outputs.compactMap({ $0.portType })
        print("willtest: \navailableInputs=\(availableInputs), \ncurrentRouteInputs=\(currentRouteInputs), \ncurrentRouteOutputs=\(currentRouteOutputs)")
        
        /*
         When BT (Airpods pro 2) CONNECTTED: it will print like below when notification comes, this is correct.
         ----------------------------------------------------------
         willtest:
         availableInputs=[__C.AVAudioSessionPort(_rawValue: MicrophoneBuiltIn), __C.AVAudioSessionPort(_rawValue: BluetoothHFP)],
         currentRouteInputs=[],
         currentRouteOutputs=[__C.AVAudioSessionPort(_rawValue: BluetoothA2DPOutput)]
         ----------------------------------------------------------         
         
         When BT (Airpods pro 2) DISCONNECTTED: it will print like below when notification comes, this is wrong.
         ----------------------------------------------------------         
         availableInputs=[__C.AVAudioSessionPort(_rawValue: MicrophoneBuiltIn), __C.AVAudioSessionPort(_rawValue: BluetoothHFP)],   
         currentRouteInputs=[],
         currentRouteOutputs=[__C.AVAudioSessionPort(_rawValue: Speaker)]
         */
    }

So my question here is: Why does the "availableInputs" still contain the "C.AVAudioSessionPort(_rawValue: BluetoothHFP)" item even though I have already disconnected the BT device? (Put AirPods in the case.)

BTW, if I tap the "Manual" button once I disconnected the BT, it also prints the "wrong" value for "availableInputs", and it will become normal after about 3~4 seconds.

Hello @WillWei, thank you for your post. Please refer to the Responding to audio route changes article. It shows how to infer the RouteChangeReason from the notification, as well as to use newDeviceAvailable and oldDeviceUnavailable to detect when devices are connected or disconnected.

Thanks. @Engineer , I will check your info. But for now, my requirement is to create a button that can indicate the audio route state, eg:

  1. If no BT is connected, just a built-in and the speaker, Show a button with 2 states: normal(for build-in) and selected(Speaker).

  2. If has BT connected, tap the button will show the system "AVRoutePickerView" for user to choose a route.

but now, I can't get the correct state when "user choose speaker when BT connected", at this time, when user tap the button, I need to show the "AVRoutePickerView", but the current route is speaker, I don't know if the BT is connected.

Hope you can understand my requirements. thanks.

Hello @WillWei. One idea would be to call availableInputs at initialization time and check if any of the ports has the portType you are looking for. You can then set the button state accordingly. Also at initialization time, you would subscribe to the routeChangeNotification. Every time a route change is triggered, you might need to update the button state.

Note that more than one Bluetooth device might be connected to the system. You can use the port's uid property, for example, to disambiguate.

yes, I'm doing so.

but in the case I post above:

When BT (Airpods pro 2) DISCONNECTTED: it will print like below when the route change notification comes, this is wrong. should not contains the "BluetoothHFP" at this time.

So @Engineer you can have demo based on my code.


availableInputs=[__C.AVAudioSessionPort(_rawValue: MicrophoneBuiltIn), __C.AVAudioSessionPort(_rawValue: BluetoothHFP)],

currentRouteInputs=[],

currentRouteOutputs=[__C.AVAudioSessionPort(_rawValue: Speaker)]

AVAudioSession's "availableInputs" not update in time
 
 
Q