You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The stream onTimebasedPlayerStateChanged emits different results depending on OS, when playing a publication in WebPubAudioOnly format:
When calling e.g. next() or previous():
Android: the state TimebasedState.loading is emitted.
iOS: the state TimebasedState.paused is emitted.
When audio files are switched (e.g. from 0001.mp3 to 0002.mp3):
Android: no new state (TimebasedState) is emitted.
iOS: the state TimebasedState.paused is emitted.
Expected Result
iOS behaves as Android and emits TimebasedState.loading or nothing.
If possible, do not emit TimebasedState.paused in these scenarios. We should be able to know that if TimebasedState.paused is set, it's an action from the user or OS.
Sorry for our MIA, lots of sickness going around the office these past weeks. The onTimebasedPlayerStateChanged didn't really reach a stage where it was tested very well across platforms. We will follow up on this as soon as possible.
If possible, do not emit TimebasedState.paused in these scenarios. We should be able to know that if TimebasedState.paused is set, it's an action from the user or OS.
The Android version works as we would expected already, in that the paused state only triggers when an actual pause of the book happens by the user, i.e. the user decided that the book should not continue playing anymore (by e.g. calling .pause() or pressing pause in control center).
But the iOS version also triggers the paused state when it's swithcing mp3 files or jumps to another location (rewind/fast forward), which is not the user wanting to pause the book. It is this distinction of the paused state that would be good to keep (and hopefully make it happen in FlutterAudioNavigator.swift).
Yep that does seem to be the culprit. They should probably have disabled state-change emits while they pause there.
For now when listening to the onTimebasedPlayerStateChanged, you should probably just use a debounceTime(50), so that minor erratic changes are skipped. This could solve the UI state representation, since the temporary pause state would be skipped when seeking.
Activity
ddfreiling commentedon Dec 9, 2025
Sorry for our MIA, lots of sickness going around the office these past weeks. The
onTimebasedPlayerStateChangeddidn't really reach a stage where it was tested very well across platforms. We will follow up on this as soon as possible.ddfreiling commentedon Dec 11, 2025
I would wish so, but right now it seems to be an artifact of how AVAudioPlayer behaves and is used in the swift-toolkit. See https://github.com/readium/swift-toolkit/blob/develop/Sources/Navigator/Audiobook/AudioNavigator.swift
Maybe we should make a PR towards it, or alternatively map the state differently on our
FlutterAudioNavigator.swiftI will continue investigating the Android side.
AndreasLymalmMTM commentedon Dec 11, 2025
The Android version works as we would expected already, in that the
pausedstate only triggers when an actual pause of the book happens by the user, i.e. the user decided that the book should not continue playing anymore (by e.g. calling.pause()or pressing pause in control center).But the iOS version also triggers the
pausedstate when it's swithcing mp3 files or jumps to another location (rewind/fast forward), which is not the user wanting to pause the book. It is this distinction of thepausedstate that would be good to keep (and hopefully make it happen inFlutterAudioNavigator.swift).ddfreiling commentedon Dec 11, 2025
You can see the mapping in swift-toolkit here:
https://github.com/readium/swift-toolkit/blob/develop/Sources/Navigator/Audiobook/AudioNavigator.swift#L516-L529
This is the same enum that we forward in flutter_readium, do you have a suggestion on how to map or ignore this status change?
AndreasLymalmMTM commentedon Dec 11, 2025
I assume swift-toolkit forward
pausedfor control center pausing too? Because in that case we can't distinguish the actions based on the state alone.AndreasLymalmMTM commentedon Dec 11, 2025
The
gofunction seems to be the culprit, by pausing everytime it moves location (be jumping or switching file): https://github.com/readium/swift-toolkit/blob/develop/Sources/Navigator/Audiobook/AudioNavigator.swift#L413-L452ddfreiling commentedon Jan 23, 2026
Yep that does seem to be the culprit. They should probably have disabled state-change emits while they pause there.
For now when listening to the
onTimebasedPlayerStateChanged, you should probably just use adebounceTime(50), so that minor erratic changes are skipped. This could solve the UI state representation, since the temporary pause state would be skipped when seeking.AndreasLymalmMTM commentedon Jan 26, 2026
Yes, that's how we decided to do it for now, and it works well enough.
AndreasLymalmMTM commentedon Oct 15, 2026
Android and/or iOS now behaves differently than was originally described, and the value that we wanted from it is now satified with #194.