Skip to content

Conversation

@avinashmidathada
Copy link

@avinashmidathada avinashmidathada commented Dec 6, 2025

ℹ️ Description

When switching to a Bluetooth audio device, the SDK was changing the audio
route before the Bluetooth connection was established. This caused a race
condition where Android would reject Bluetooth routing and fall back to
Handset.

This fix introduces the BluetoothAudioRouter abstraction to encapsulate Bluetooth
connection management. The router defers route changes until the Bluetooth
connection is confirmed ready, with implementations selected via
BluetoothAudioRouterFactory based on API level. This design isolates the
complex asynchronous Bluetooth handling from DefaultDeviceController and
allows each platform path to be tested independently.

ScoBluetoothAudioRouter (API < 31):

  • Monitor ACTION_SCO_AUDIO_STATE_UPDATED broadcasts for connection state
  • Execute deferred setRoute() only when SCO reaches CONNECTED state
  • Handle SCO connection failures and timeouts (3 seconds)
  • Distinguish connection failure from device switching for multi-device support

CommunicationDeviceBluetoothAudioRouter (API 31+):

  • Use OnCommunicationDeviceChangedListener for connection confirmation
  • Retry on mismatch when setCommunicationDevice() succeeds but listener
    reports a different device (500ms delay, max 3 retries)
  • 5-second timeout for device switching per Android documentation

Additional changes:

  • Update MediaDevice to track device IDs for API 31+ routing
  • Add test coverage for both API paths

Issue #, if available

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update
    • README update
    • CHANGELOG update
    • guides update
  • This change requires a dependency update
    • Amazon Chime SDK Media
    • Other (update corresponding legal documents)

🧪 How Has This Been Tested?

Manually verified with a Pixel 8 device running Android

Unit test coverage

Added comprehensive unit tests

Additional Manual Test

  • Pause and resume remote video
  • Switch local camera
  • Rotate screen back and forth

📱 Screenshots, if available

provide screenshots/video record if there's a UI change in demo app

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@avinashmidathada avinashmidathada force-pushed the fix-bluetooth-audio-routing branch from 104d7b4 to 453db19 Compare December 9, 2025 02:27
@avinashmidathada avinashmidathada changed the base branch from master to development December 9, 2025 02:29
* @param state The new SCO audio state
* @param previousState The previous SCO audio state
*/
private fun onScoStateChanged(state: Int, previousState: Int) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard for me to gauge, but is there any way to break this logic out and if so, whether it could be an interface with two implementations? Understandable if not possible.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it kinda grew to a big chunk without me realizing as we're supporting two APIs. The callback logic makes it a bit tricky to cleanly extract this out but I can give it a shot and get back

dylonChime
dylonChime previously approved these changes Dec 11, 2025
@avinashmidathada avinashmidathada force-pushed the fix-bluetooth-audio-routing branch 2 times, most recently from 1d24b0f to 1332a57 Compare December 12, 2025 22:30
…eady

When switching to a Bluetooth audio device, the SDK was changing the audio
route before the Bluetooth connection was established. This caused a race
condition where Android would reject Bluetooth routing and fall back to
Handset.

This fix introduces the BluetoothAudioRouter abstraction to encapsulate Bluetooth
connection management. The router defers route changes until the Bluetooth
connection is confirmed ready, with implementations selected via
BluetoothAudioRouterFactory based on API level. This design isolates the
complex asynchronous Bluetooth handling from DefaultDeviceController and
allows each platform path to be tested independently.

ScoBluetoothAudioRouter (API < 31):
- Monitor ACTION_SCO_AUDIO_STATE_UPDATED broadcasts for connection state
- Execute deferred setRoute() only when SCO reaches CONNECTED state
- Handle SCO connection failures and timeouts (3 seconds)
- Distinguish connection failure from device switching for multi-device support

CommunicationDeviceBluetoothAudioRouter (API 31+):
- Use OnCommunicationDeviceChangedListener for connection confirmation
- Retry on mismatch when setCommunicationDevice() succeeds but listener
  reports a different device (500ms delay, max 3 retries)
- 5-second timeout for device switching per Android documentation

Additional changes:
- Update MediaDevice to track device IDs for API 31+ routing
- Add test coverage for both API paths
@avinashmidathada avinashmidathada force-pushed the fix-bluetooth-audio-routing branch from 1332a57 to 013f631 Compare December 12, 2025 23:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants