Skip to content

feat(android): add preferConnectedAudioDevice flag to route audio to …#401

Merged
gdelataillade merged 3 commits into
gdelataillade:mainfrom
lw-manoj:fix/issue-400-prefer-connected-audio-device
May 30, 2026
Merged

feat(android): add preferConnectedAudioDevice flag to route audio to …#401
gdelataillade merged 3 commits into
gdelataillade:mainfrom
lw-manoj:fix/issue-400-prefer-connected-audio-device

Conversation

@lw-manoj

Copy link
Copy Markdown
Contributor

…earphones or Bluetooth

STREAM_ALARM / USAGE_ALARM (introduced in 5.4.0) forces audio to the built-in speaker by Android design, bypassing connected earphones and Bluetooth devices. This is correct for wake-up alarms but is a regression for developers who need external device routing.

Adds preferConnectedAudioDevice (default false) to AlarmSettings. When true, both AudioService and VolumeService switch to STREAM_MUSIC + USAGE_MEDIA, routing to a connected earphone or Bluetooth device if present and falling back to the speaker if not. The trade-off is that the media volume slider controls the volume instead of the alarm slider.

Also fixes androidStopAlarmOnTermination being absent from AlarmSettings copyWith() and props — two callers relying on equality or copyWith for this field would have seen silent incorrect behaviur.

Threads the flag through the full stack: AlarmSettingsWire pigeon definition → Dart AlarmSettings model → regenerated platform bindings → Android AlarmSettings.kt (with = false default for safe deserialization of persisted alarms) → AlarmService.kt → AudioService.kt and VolumeService.kt.

Fixes #400.

Tested on: Pixel 9a, Android 16

lw-manoj and others added 2 commits May 28, 2026 20:49
…earphones or Bluetooth

STREAM_ALARM / USAGE_ALARM (introduced in 5.4.0) forces audio to the
built-in speaker by Android design, bypassing connected earphones and
Bluetooth devices. This is correct for wake-up alarms but is a regression
for developers who need external device routing.

Adds preferConnectedAudioDevice (default false) to AlarmSettings. When
true, both AudioService and VolumeService switch to STREAM_MUSIC +
USAGE_MEDIA, routing to a connected earphone or Bluetooth device if
present and falling back to the speaker if not. The trade-off is that
the media volume slider controls the volume instead of the alarm slider.

Also fixes androidStopAlarmOnTermination being absent from AlarmSettings
copyWith() and props — two callers relying on equality or copyWith for
this field would have seen silent incorrect behaviour.

Threads the flag through the full stack: AlarmSettingsWire pigeon
definition → Dart AlarmSettings model → regenerated platform bindings
→ Android AlarmSettings.kt (with = false default for safe deserialization
of persisted alarms) → AlarmService.kt → AudioService.kt and VolumeService.kt.

Fixes gdelataillade#400.

Tested on: Pixel 9a, Android 16
@gdelataillade

Copy link
Copy Markdown
Owner

Thanks @lw-manoj, the fix looks great — clean threading through every layer, backward compat is solid, and nice catch on the stale alarm_settings.g.dart (it was silently dropping androidStopAlarmOnTermination from persisted alarms).

Two small things before I merge:

1. Audio focus stream consistency

VolumeService.requestAudioFocus() still hardcodes USAGE_ALARM / STREAM_ALARM even when preferConnectedAudioDevice is true. The MediaPlayer playback uses USAGE_MEDIA but the focus request stays alarm-typed, which is inconsistent and may affect how other apps duck/yield. Could you thread the flag into requestAudioFocus() as well (and through the AlarmService call site)?

2. README docs

Could you add a row for preferConnectedAudioDevice to the AlarmSettings table in README.md (around line 89, next to androidStopAlarmOnTermination)? Something like:

| preferConnectedAudioDevice | `bool` | If true, routes alarm audio to a connected earphone or Bluetooth device when present, falling back to the speaker. Uses the media volume slider instead of the alarm slider. Android-only. Disabled by default. |

Once those are in I'll merge. Thanks again for the fast turnaround!

@lw-manoj

Copy link
Copy Markdown
Contributor Author

Thanks @gdelataillade for reviewing and catching the missing update. I will fix it later tonight and update the PR.

…e flag

requestAudioFocus() hardcoded USAGE_ALARM / STREAM_ALARM regardless of
preferConnectedAudioDevice, causing an inconsistency where MediaPlayer
used USAGE_MEDIA for playback but audio focus was still requested as
alarm-typed. This affects how other apps duck or yield to the alarm.

When preferConnectedAudioDevice is true, requestAudioFocus() now uses
USAGE_MEDIA (API 26+) and STREAM_MUSIC (pre-26), consistent with the
AudioAttributes already set on MediaPlayer.

Also adds preferConnectedAudioDevice to the AlarmSettings table in README.
@lw-manoj

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review @gdelataillade. Both points addressed:

  1. Audio focus consistency: requestAudioFocus() now branches on preferConnectedAudioDevice the same way AudioService does: USAGE_MEDIA (API 26+) and STREAM_MUSIC (pre-26) when true, USAGE_ALARM / STREAM_ALARM when false. Audio focus and playback are now consistent.

  2. README: Added preferConnectedAudioDevice row to the AlarmSettings table, with wording adjusted to "Has no effect on iOS" rather than "Android-only" to be more precise and consistent with the existing doc style.

@gdelataillade
gdelataillade merged commit b8c1701 into gdelataillade:main May 30, 2026
2 checks passed
@gdelataillade

Copy link
Copy Markdown
Owner

Thank you! Added to version 5.4.1 !

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.

Alarm sound ONLY plays through the speaker, bypassing earphones (5.4.0)

2 participants