Automatic audio switching between devices in mobile app

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
Automatic audio switching between devices in mobile app
Medium
~3-5 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Automatic Audio Switching Between Devices

Connected AirPods — audio switches to them. Disconnected — returns to speaker. Connected Bluetooth headset during call — call doesn't interrupt. Sounds like basic OS functionality, but in production without explicit AVAudioSession event handling everything works unpredictably.

How iOS Manages Audio Routing

AVAudioSession — central object. By default iOS switches output device when route changes. Problem — app may not know about it, and current AVAudioPlayer or AVAudioEngine continues on "old" route until next playback operation.

For explicit control — AVAudioSession.routeChangeNotification:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(handleRouteChange(_:)),
    name: AVAudioSession.routeChangeNotification,
    object: nil
)

@objc func handleRouteChange(_ notification: Notification) {
    guard let info = notification.userInfo,
          let reasonValue = info[AVAudioSessionRouteChangeReasonKey] as? UInt,
          let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue)
    else { return }

    switch reason {
    case .newDeviceAvailable:
        // AirPods connected — switch to them
        resumePlaybackIfNeeded()
    case .oldDeviceUnavailable:
        // Headphones disconnected — pause or switch to speaker
        if let previousRoute = info[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
            let wasHeadphones = previousRoute.outputs.contains {
                $0.portType == .headphones || $0.portType == .bluetoothA2DP
            }
            if wasHeadphones { pausePlayback() }
        }
    case .categoryChange:
        reconfigureEngine()
    default: break
    }
}

oldDeviceUnavailable with pause — standard behavior users expect (Spotify, Apple Music). Without pause audio keeps playing in speaker after accidental headphone disconnection.

AirPods and Automatic Device Switching

AirPods Pro/Max support Automatic Switching — transition between iPhone, iPad, Mac. App can't control this switching but can react to consequences. When AirPods switch between devices app gets routeChangeNotification with reason override or categoryChange.

Subtlety: after route change AVAudioSession.currentRoute updates not instantly. On oldDeviceUnavailable still 50–100ms route shows old device. Need short Task.sleep(nanoseconds: 100_000_000) or check on next runloop cycle.

AVAudioEngine: Rebuilding Graph on Route Change

If app uses AVAudioEngine with effects (equalizer, reverb), route change can reset session. Sign — AVAudioEngine.isRunning returns false after routeChangeNotification.

Correct pattern: subscribe to AVAudioEngineConfigurationChange and reconnect graph:

NotificationCenter.default.addObserver(
    forName: .AVAudioEngineConfigurationChange,
    object: audioEngine, queue: .main
) { [weak self] _ in
    self?.rebuildAudioGraph()
    try? self?.audioEngine.start()
}

rebuildAudioGraph() — disconnect all nodes, change outputNode (now points to new device), reconnect. Without this step AVAudioPlayerNode continues playing but silent — quiet, no errors in logs.

Android: AudioManager and AudioDeviceCallback

On Android route management via AudioManager.AudioDeviceCallback:

val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager

audioManager.registerAudioDeviceCallback(object : AudioDeviceCallback() {
    override fun onAudioDevicesAdded(addedDevices: Array<AudioDeviceInfo>) {
        val bluetooth = addedDevices.firstOrNull {
            it.type == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP ||
            it.type == AudioDeviceInfo.TYPE_BLE_HEADSET
        }
        bluetooth?.let { switchToDevice(it) }
    }

    override fun onAudioDevicesRemoved(removedDevices: Array<AudioDeviceInfo>) {
        pauseIfHeadphonesRemoved(removedDevices)
    }
}, Handler(Looper.getMainLooper()))

AudioManager.setPreferredDevice() (API 28+) allows forcing device choice. Android 12+ added setCommunicationDevice() specifically for calls — don't confuse with regular playback.

Common Mistakes

  • Don't call AVAudioSession.setActive(true) after reconfig — get silent playback without error
  • Don't handle categoryChange on incoming call — phone call changes session category, after finish need restore it
  • Change route on background thread — AVAudioSession operations must be on main thread or explicitly synchronized

Timeline

Basic route change handling (iOS): 3–5 days. Full implementation with AVAudioEngine, Android support, all scenarios (calls, BT headsets, AirPods): 2–3 weeks. Cost calculated individually.