This PR refactors the iOS player sync hooks to rely on the native instead AVPlayer time observation hooks instead of using timers.
The theory is in low memory situations, iOS is stopping the current tick timer in the background, leading to issues where the player does not have the most accurate currentTime.
Changes
Persisting a syncing sessions are now done via addPeriodicTimeObserver() firing every 0.5 wall-clock seconds
The database currentTime is updated on every invocation
The server receives the latest session and media progress every 10 wall-clock seconds and when the player is paused or stopped
timeListening is now calculated based on updateAt times between sync vs. running an incremental counter each second
This ensures it's reliable regardless of the interval the value is updated
Sleep timers are now done via addBoundaryTimeObserver scheduled for the time to stop sleep
This refactor takes into account playbackSpeed, changes in playbackSpeed, seeks, and locks on a specific chapter time when required, to ensure the scheduled sleep time is always accurate
Syncing the current progress from the server is still done via a timer, but has been refactored into the Audio Player, and is now aware of pauses using the Now Playing widget or a remote
When resuming audio with allowed seek back, the last played time is based off the database session, allowing persistence across app restarts
Fixes an existing Realm memory leak that was made worse by this change
Adds lots of error handling logic as part of tracking down this memory leak
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
## 📋 Pull Request Information
**Original PR:** https://github.com/advplyr/audiobookshelf-app/pull/330
**Author:** [@ronaldheft](https://github.com/ronaldheft)
**Created:** 8/23/2022
**Status:** ✅ Merged
**Merged:** 8/27/2022
**Merged by:** [@advplyr](https://github.com/advplyr)
**Base:** `master` ← **Head:** `bug-ios-background-currenttime`
---
### 📝 Commits (10+)
- [`27d2ed2`](https://github.com/advplyr/audiobookshelf-app/commit/27d2ed230446219b370c7ff523bf18992ee3730e) Convert PlayerHandler to shared instance
- [`8952cbf`](https://github.com/advplyr/audiobookshelf-app/commit/8952cbfd20eec6cccdc2c76c1b274464bd2aff7b) Start of refactor
- [`d57fe44`](https://github.com/advplyr/audiobookshelf-app/commit/d57fe44bcc8b73ee50cb9d855c9164c80213c503) Sleep timer using native time observer
- [`ccecba7`](https://github.com/advplyr/audiobookshelf-app/commit/ccecba7a19d34161223a6e9060bfb3f30789cbd3) If adjusting sleep time from chapter, convert to regular sleep timer
- [`d084958`](https://github.com/advplyr/audiobookshelf-app/commit/d084958f2db13d7abc2510fdea1bfa6b072f9098) Scale time reporting by the rate
- [`fe042f3`](https://github.com/advplyr/audiobookshelf-app/commit/fe042f3f83a6e67566d61b89c4192d5aa13990a5) Fix NaN causing bad data
- [`2448b46`](https://github.com/advplyr/audiobookshelf-app/commit/2448b461f09344da1d6e116effaf4a8e79f69293) Re-implement the paused timer
- [`cdd2f40`](https://github.com/advplyr/audiobookshelf-app/commit/cdd2f40ef9646ec794b015c10c21337d5a33dab0) Merge branch 'master' into bug-ios-background-currenttime
- [`06f87d2`](https://github.com/advplyr/audiobookshelf-app/commit/06f87d24a707720b5c8796b7f1ccf64de792c1bd) Fix merge conflict
- [`94e261d`](https://github.com/advplyr/audiobookshelf-app/commit/94e261d7bfe47c181eee6dcff5966b176bde793e) Fix bad data being encoded
### 📊 Changes
**18 files changed** (+697 additions, -369 deletions)
<details>
<summary>View changed files</summary>
📝 `ios/App/App/AppDelegate.swift` (+9 -1)
📝 `ios/App/App/plugins/AbsAudioPlayer.swift` (+30 -28)
📝 `ios/App/App/plugins/AbsDatabase.swift` (+34 -28)
📝 `ios/App/App/plugins/AbsDownloader.swift` (+5 -5)
📝 `ios/App/App/plugins/AbsFileSystem.swift` (+20 -15)
📝 `ios/App/Shared/models/PlaybackSession.swift` (+1 -0)
📝 `ios/App/Shared/models/download/DownloadItem.swift` (+2 -2)
📝 `ios/App/Shared/models/local/LocalLibraryItem.swift` (+2 -2)
📝 `ios/App/Shared/models/local/LocalMediaProgress.swift` (+29 -20)
📝 `ios/App/Shared/models/server/AudioTrack.swift` (+1 -1)
📝 `ios/App/Shared/player/AudioPlayer.swift` (+220 -18)
📝 `ios/App/Shared/player/PlayerHandler.swift` (+90 -155)
📝 `ios/App/Shared/player/PlayerProgress.swift` (+109 -22)
📝 `ios/App/Shared/util/ApiClient.swift` (+6 -1)
📝 `ios/App/Shared/util/DaoExtensions.swift` (+8 -8)
📝 `ios/App/Shared/util/Database.swift` (+111 -52)
📝 `ios/App/Shared/util/NowPlayingInfo.swift` (+11 -6)
📝 `ios/App/Shared/util/Store.swift` (+9 -5)
</details>
### 📄 Description
This PR refactors the iOS player sync hooks to rely on the native instead `AVPlayer` time observation hooks instead of using timers.
The theory is in low memory situations, iOS is stopping the current tick timer in the background, leading to issues where the player does not have the most accurate `currentTime`.
## Changes
* Persisting a syncing sessions are now done via `addPeriodicTimeObserver()` firing every 0.5 wall-clock seconds
* The database `currentTime` is updated on every invocation
* The server receives the latest session and media progress every 10 wall-clock seconds and when the player is paused or stopped
* `timeListening` is now calculated based on `updateAt` times between sync vs. running an incremental counter each second
* This ensures it's reliable regardless of the interval the value is updated
* Sleep timers are now done via `addBoundaryTimeObserver` scheduled for the time to stop sleep
* This refactor takes into account playbackSpeed, changes in playbackSpeed, seeks, and locks on a specific chapter time when required, to ensure the scheduled sleep time is always accurate
* Syncing the current progress from the server is still done via a timer, but has been refactored into the Audio Player, and is now aware of pauses using the Now Playing widget or a remote
* When resuming audio with allowed seek back, the last played time is based off the database session, allowing persistence across app restarts
* Fixes an existing Realm memory leak that was made worse by this change
* Adds lots of error handling logic as part of tracking down this memory leak
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/advplyr/audiobookshelf-app/pull/330
Author: @ronaldheft
Created: 8/23/2022
Status: ✅ Merged
Merged: 8/27/2022
Merged by: @advplyr
Base:
master← Head:bug-ios-background-currenttime📝 Commits (10+)
27d2ed2Convert PlayerHandler to shared instance8952cbfStart of refactord57fe44Sleep timer using native time observerccecba7If adjusting sleep time from chapter, convert to regular sleep timerd084958Scale time reporting by the ratefe042f3Fix NaN causing bad data2448b46Re-implement the paused timercdd2f40Merge branch 'master' into bug-ios-background-currenttime06f87d2Fix merge conflict94e261dFix bad data being encoded📊 Changes
18 files changed (+697 additions, -369 deletions)
View changed files
📝
ios/App/App/AppDelegate.swift(+9 -1)📝
ios/App/App/plugins/AbsAudioPlayer.swift(+30 -28)📝
ios/App/App/plugins/AbsDatabase.swift(+34 -28)📝
ios/App/App/plugins/AbsDownloader.swift(+5 -5)📝
ios/App/App/plugins/AbsFileSystem.swift(+20 -15)📝
ios/App/Shared/models/PlaybackSession.swift(+1 -0)📝
ios/App/Shared/models/download/DownloadItem.swift(+2 -2)📝
ios/App/Shared/models/local/LocalLibraryItem.swift(+2 -2)📝
ios/App/Shared/models/local/LocalMediaProgress.swift(+29 -20)📝
ios/App/Shared/models/server/AudioTrack.swift(+1 -1)📝
ios/App/Shared/player/AudioPlayer.swift(+220 -18)📝
ios/App/Shared/player/PlayerHandler.swift(+90 -155)📝
ios/App/Shared/player/PlayerProgress.swift(+109 -22)📝
ios/App/Shared/util/ApiClient.swift(+6 -1)📝
ios/App/Shared/util/DaoExtensions.swift(+8 -8)📝
ios/App/Shared/util/Database.swift(+111 -52)📝
ios/App/Shared/util/NowPlayingInfo.swift(+11 -6)📝
ios/App/Shared/util/Store.swift(+9 -5)📄 Description
This PR refactors the iOS player sync hooks to rely on the native instead
AVPlayertime observation hooks instead of using timers.The theory is in low memory situations, iOS is stopping the current tick timer in the background, leading to issues where the player does not have the most accurate
currentTime.Changes
addPeriodicTimeObserver()firing every 0.5 wall-clock secondscurrentTimeis updated on every invocationtimeListeningis now calculated based onupdateAttimes between sync vs. running an incremental counter each secondaddBoundaryTimeObserverscheduled for the time to stop sleep🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.