Skip to content

android: don't let conversation awareness overshoot the original volume - #855

Open
SAGIRIxr wants to merge 1 commit into
librepods-org:android/rewritefrom
SAGIRIxr:fix/ca-volume-overshoot
Open

SAGIRIxr wants to merge 1 commit into
librepods-org:android/rewritefrom
SAGIRIxr:fix/ca-volume-overshoot

Conversation

@SAGIRIxr

Copy link
Copy Markdown
Contributor

The bug

With conversation awareness on, the volume does duck while you talk. But once you stop it comes back higher than it was, and each conversation pushes it a bit further. Captured on a Xiaomi 14 Pro (HyperOS's volume scale is 0..150, so 43 % = 64 and 20 % = 30), starting from 44:

conversation awareness state: 1
Starting speaking, initial volume: 44
Smooth volume transition from 44 to 64        <- "ducking" raises it
conversation awareness state: 7
Smooth volume transition from 45 to 44
conversation awareness state: 1
Starting speaking, initial volume: 46          <- re-recorded mid-ramp
Smooth volume transition from 46 to 64
conversation awareness state: 7
Smooth volume transition from 47 to 46
conversation awareness state: 1
Starting speaking, initial volume: 48
...                                              57, 59, 61, 62 ...
Starting speaking, initial volume: 64
conversation awareness state: 2
Smooth volume transition from 64 to 30
conversation awareness state: 7
Smooth volume transition from 63 to 64        <- "restores" to 64

Three things compound:

  1. The ducked levels are absolute (conversationAwarenessVolume = 43 %, conversationAwarenessReducedVolume = 20 % of max) and are never compared with the current volume. Below 43 %, level 1 and level 3 raise the volume. The previous startSpeaking(), still in MediaController but commented out, had an initialVolume > max * percent guard for this.
  2. Ramps are never cancelled. Each smoothVolumeTransition posts its own 50 ms stepper, so a ramp heading up to the ducked level keeps running underneath the restore and can be the last one to write.
  3. The AirPods flap between 1 and 7 for about the first second after you start talking. stopSpeaking() clears initialVolume, so the next 1 records whatever the still-running ramp has reached. The "original" volume ratchets up 44 → 46 → 48 → … → 64, and that's what gets restored.

The fix

  • MediaController.duckVolume(percent): like setVolume, but capped at the volume recorded when speaking started, so ducking can only lower.
  • smoothVolumeTransition stamps each ramp with a generation number, and a ramp that has been superseded stops instead of finishing.
  • Level 2 also calls startSpeaking(). Both 1 and 2 mean "started speaking", and startSpeaking() only records when nothing is recorded yet, so a sequence that opens on 2 still gets restored.

setVolume is left unchanged for any other caller.

Testing

On the same device, starting at 40/150, I talked in four separate bursts with music playing. The build I tested also carried #852 (strings only, it doesn't touch this code path). This branch is the same commit cherry-picked onto the current android/rewrite. Every burst recorded 40 as the starting volume, ducked 40 → 30, and came back to 40:

Starting speaking, initial volume: 40
Smooth volume transition from 40 to 40        <- level 1 no longer raises
Smooth volume transition from 40 to 30        <- level 2
Smooth volume transition from 30 to 40        <- level 3, capped at 40
Smooth volume transition from 31 to 40        <- restore
... next burst:
Starting speaking, initial volume: 40

The ducked levels are a fixed share of the maximum volume, so with a quiet starting volume level 1/3 actually raised it. On top of that, volume ramps were never cancelled: the AirPods step from 3 to 6 quickly, so the ramp towards the ducked level could still be running after the restore to the original volume had finished, and it won, leaving the volume above where it started.

Ducking now never goes above the volume recorded when speaking started, every ramp supersedes the previous one, and level 2 also records the starting volume since it means 'started speaking' too.
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.

1 participant