Repository navigation
fix(presence): read the Discord card's play state from playback intent, not the raw render flag - #314
Merged
Merged
Conversation
…t, not the raw render flag MusicPlayerState.isPlaying is ExoPlayer's raw flag, and ExoPlayer reports it false on every stall - the first buffer of a fresh track, a mid-track network hiccup, the re-prepare behind a quality upgrade - while playWhenReady stays true. The player publishes exactly that as isBuffering, which is playWhenReady-gated. The presence publisher pushed a card on every signature change and the signature carried the raw flag, so every stall on a streaming connection told Discord "Paused", flip-flopping back on resume. On a hi-res stream that is most of the listen. The card's play state is now isPlaying || isBuffering - the user's intent at the state boundary (isBuffering only ever rides with playWhenReady, and both flags are cleared together by pause(), a fatal error and cast teardown). Both buildActivity (timestamps + play/pause asset) and signature read it, so a stall shares the playing signature: a resume repushes nothing, and neither can a stall become a frame on its own. A genuine pause still reads Paused with no timestamps, and its signature still differs so the pause repushes. Also logs one line per frame actually handed to Discord, so a card that never appears is diagnosable as no pushes at all, refused pushes (the existing WARN), or Discord dropping them. Tests: buffering-while-intending-playback reads Playing with the countdown bar up, a stall shares the playing signature, and a real pause reads Paused and repushes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The Discord card told everyone you were Paused while music was playing.
Root cause
MusicPlayerState.isPlayingis ExoPlayer's raw flag, and ExoPlayer reports it false on every stall — the first buffer of a fresh track, a mid-track network hiccup, the re-prepare behind a quality upgrade — whileplayWhenReadystays true. The player publishes exactly that asisBuffering(which isplayWhenReady-gated). The presence publisher pushed a card on every signature change, and the signature carried the raw flag — so every stall on a streaming connection published "Paused" to Discord, flip-flopping back on resume. On a hi-res stream, stalls are most of the listen.Fix
The card's play state is now
isPlaying || isBuffering— the user's intent at the state boundary (isBufferingonly ever rides withplayWhenReady, and both flags are cleared together bypause(), a fatal error, and cast teardown):buildActivity— timestamps stay up and the asset says play/"Playing" through a stall, so the countdown bar never reads as a frozen paused card mid-buffer.signature— a stall shares the playing signature, so a resume repushes nothing (nothing visible changed) and a stall cannot become a frame on its own.Also logs one line per frame actually handed to Discord, so a card that never appears is diagnosable as no pushes at all, refused pushes (existing WARN), or Discord dropping them (rate limit / app side).
Tests
bufferingWhileTheUserWantsPlaybackStillReadsAsPlaying— stall card reads Playing, bar up.aStallSharesThePlayingSignatureSoItCannotChurnOrBeSwallowedaRealPauseStillReadsAsPausedAndRepushesRun:
./gradlew :app:testDebugUnitTest --tests "com.lastwave.app.presence.DiscordPresenceTest"Not yet run — if the "sometimes isn't even detecting" symptom persists after this, logcat with
-s DiscordPresence DiscordIpcTransportwhile reproducing will show whether frames stop flowing or Discord refuses them.