maxrave-dev / maxrave-dev/SimpMusic
Playback stops after a brief network hiccup (error 2000 is not retryable)
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 11.4k
- Forks
- 599
- Avg merge
- 3d 18h
- Merged PRs (30d)
- 7
Description
On 2.0.0 (versionCode 57), Galaxy S23 (SM-S911B), Android 16, stock release build.
A short network interruption during a song stops playback permanently. It does not resume when the connection comes back. Pressing play recovers it instantly, so nothing is actually broken except that the retry is never attempted.
Repro
- Start a playlist.
- While a song is still buffering (early in the track works best), turn on airplane mode for about 10 seconds.
- Turn it off, the connection returns within seconds.
- Playback stops as soon as the already-buffered audio runs out, and stays stopped.
- Press play: it resumes from exactly where it stopped.
I did not even do this deliberately. My phone roamed between two Wi-Fi access points on the same SSID at home:
08:38:59 ConnectivityService: registerNetworkAgent NetworkAgentInfo{network{398} (WIFI CONNECTING)
08:39:04 ConnectivityService: [397 WIFI] disconnected
08:39:04 ConnectivityService: registerNetworkAgent NetworkAgentInfo{network{399}
DNS was unavailable for a few seconds, and the player asked for more stream data inside that window:
08:39:02 Stream: Error: Unable to resolve host "music.youtube.com": No address associated with hostname
08:39:02 Stream: Failed to resolve stream URL for TRACK_A
08:39:02 ExoPlayerImplInternal: Playback error / qt3: Source error
08:39:02 Caused by: java.io.IOException: Failed to resolve stream URL for TRACK_A
08:39:02 CrossfadeExoPlayerAdapter: Playback error: Source error
08:39:02 Player Error: Source error, code: 2000, code name: ERROR_CODE_IO_UNSPECIFIED
08:39:02 CrossfadeExoPlayerAdapter: pause() called (state: PLAYING, playWhenReady: true)
08:39:02 CrossfadeExoPlayerAdapter: State: PLAYING -> ERROR (playWhenReady=true)
08:39:02 CrossfadeExoPlayerAdapter: Pause: Called in invalid state: ERROR
It then sat at ERROR(7), position=48753, buffered position=48753 for 35 minutes with zero retry attempts, while the network was fine the whole time (music.youtube.com resolving in 21 ms).
Cause
In CrossfadeExoPlayerAdapter.onPlayerError:
val isRetryableSourceError =
error.errorCode == PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED || // 3001
error.errorCode == PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS || // 2004
error.errorCode == PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND // 2005
The observed code is 2000, which is not in the set, so the retry branch is never entered and the adapter parks in ERROR. ERROR_CODE_IO_NETWORK_CONNECTION_FAILED (2001) is not there either, even though the comment directly above this expression documents it as handled.
The retry logic already works, it is just never reached
A single play command recovered it immediately:
09:20:05 state=ERROR(7), position=48753, buffered position=48753
09:20:06 (media play key)
09:20:07 CrossfadeExoPlayerAdapter: State: ERROR -> PLAYING (playWhenReady=true)
09:20:12 state=PLAYING(3), position=51325, buffered position=155021
A fresh URL was resolved and playback resumed from the failure point, which is exactly what the existing retry path does, including its position snapshot.
Suggested fix
Add 2000 and 2001 to isRetryableSourceError, or retry the whole IO class, reusing the maxRetryCount and cachedPosition resume that already sits directly below.
Why this is worse than it looks
Any loss of connectivity triggers this, and SimpMusic manufactures its own. #2233 gets the app's network revoked while it keeps playing, and this morning that revocation produced three failed precaches in six minutes (08:30, 08:32, 08:35), one per track transition. It was provably app-targeted rather than a connectivity problem: all 52 DNS failures in that window belonged to SimpMusic and none to any other process on the phone. Those three then stopped playback one after another about 50 minutes later (#2239), each needing its own manual play. The mid-song failure above was separate, caused by the genuine 5-second Wi-Fi roam. Together that is the mechanism behind reports of "it stops every song and I keep having to press play".
Related: #2233, #2239, #2428
Track ID replaced with a placeholder. Wi-Fi lines trimmed to remove SSID, BSSID, MAC and IP.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at CrossfadeExoPlayerAdapter.onPlayerError and inspect the isRetryableSourceError check against the documented network error codes. Verify the existing retry path, including maxRetryCount and cachedPosition, is reached for transient I/O failures. Done means a brief connectivity loss retries playback and resumes from the failure point instead of remaining in ERROR.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100