Skip to content

Mobile: fix playback speed resetting to 1.0x on episode start and interruption resume - #974

Open
mrmichaeladavis wants to merge 2 commits into
madeofpendletonwool:mainfrom
mrmichaeladavis:fix/mobile-audio-playback-review
Open

Mobile: fix playback speed resetting to 1.0x on episode start and interruption resume#974
mrmichaeladavis wants to merge 2 commits into
madeofpendletonwool:mainfrom
mrmichaeladavis:fix/mobile-audio-playback-review

Conversation

@mrmichaeladavis

@mrmichaeladavis mrmichaeladavis commented Aug 29, 2026

Copy link
Copy Markdown

Fixes #882
Fixes #963
Fixes #973

Root cause

Two separate bugs caused the playback speed to reset to 1.0x.

On iOS, AVPlayer.play() resets rate to 1.0 on every call. This happens
on episode start, on lock-screen resume, and after an interruption. Each
call erased the user's chosen speed. The fix tracks the desired rate and
sets it again after every play() call.

On both platforms, getPlayEpisodeDetails reads the server's
playback_speed field but ignored playback_speed_customized. The
backend sends this second field to show whether the value is a real
per-podcast override or the unchanged account default. The app set the
local speed first, when playback started. Then it applied the server
value too, on every episode start, on both platforms. The server value
overwrote the local value each time.

Also in this PR

On iOS, playback now resumes automatically when the system reports an
interruption with shouldResume set. An example is a Siri or
notification readout. Previously, if the screen was off, the episode
stayed paused with no way to resume it. A real phone call does not set
shouldResume, so calls are not affected.

Testing

I tested this manually on iOS and Android.

  • The speed stays set across episode starts.
  • Playback resumes after a short interruption, such as a Siri or
    notification readout, and keeps the correct speed.
  • A speed set only in the app, with no server-side override, is not
    overwritten.
  • A podcast with an explicit per-podcast override, set through the web
    UI, still uses the server value. This is the intended behavior.

Michael A. Davis added 2 commits August 28, 2026 21:46
…ayback speed on play

- Auto-resume playback when AVAudioSession reports an interruption ended
  with shouldResume (e.g. a Siri or notification readout), instead of
  leaving the episode paused with no way to resume it if the screen is
  off. Real phone calls don't set shouldResume, so they're unaffected.
- AVPlayer.play() always resets rate to 1.0, discarding a user-selected
  playback speed on episode start, lock-screen play, and interruption
  resume. Track the desired rate and reassert it after every play() call.

Fixes the iOS side of madeofpendletonwool#882.
…l speed

Root cause of both madeofpendletonwool#882 (iOS) and madeofpendletonwool#963 (Android): getPlayEpisodeDetails
parsed the server's playback_speed field but dropped
playback_speed_customized, which the Rust backend sends to distinguish a
real per-podcast override from it echoing back the account-wide default
(Users.playbackspeed). The mobile speed selector only writes to local
SharedPreferences and never syncs to that server column, so for anyone
who hasn't set it via the web UI it sits at 1.0.

playPinepodsEpisode() then unconditionally called setPlaybackSpeed with
that value right after starting playback, stomping whatever speed
playEpisode() had just applied locally, on every episode start, on both
platforms. That's why tapping the in-app speed +/- buttons after
playback started seemed to fix it: it's the only path with no follow-up
override.

Add playbackSpeedCustomized to PlayEpisodeDetails and only apply the
server's speed when it's an actual customization, in both the main
playback path and the local-download background enrichment path.

This doesn't replace the AVPlayer.play()-resets-rate fix already applied
for iOS. That's a separate, contributing bug.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant