Wire viewer-count presence heartbeat/leave into the player - #126
Wire viewer-count presence heartbeat/leave into the player#126dhinesh-kumar-m wants to merge 1 commit into
Conversation
Kept entirely internal to the player rather than exposed as new public API an app has to call: TPStreamsPlayer starts the heartbeat loop on onIsPlayingChanged(true) and stops it (sending a best-effort leave) on onIsPlayingChanged(false) and release() — the same signal NetworkDiagnosticsManager and ResumePlaybackManager already key off. PresenceHeartbeatManager mirrors the web presence-client's and iOS SDK's loop (jittered first beat, server-driven cadence via next_heartbeat_in, Retry-After handling) so all three behave identically to the server. JSON request/response bodies use org.json.JSONObject rather than Gson, matching how TPStreamsApiService/TestPressApiService already parse everything else in this codebase. Resends the same persisted device id (PresenceViewerIdStore, SharedPreferences-backed) on every heartbeat/leave call, matching the device-binding requirement flagged by senior review. On a 401 it calls back through TPStreamsPlayer.Listener.onPresenceTokenExpired(videoId, callback) rather than retrying the same token — mirrors onAccessTokenExpired's exact shape, but with a default no-op body (this interface already uses that pattern for onNetworkDiagnosticsStarted): presence is still rollout-gated to a handful of organizations, and a required override would break every existing integrator for a feature almost none of them have enabled. The presence token itself travels through the same asset-info fetch that already returns playback URLs, nested under live_stream.presence in the API response, gated behind a new viewer_id query param BaseApiService.assetInfoUrl now accepts — without it the server mints a fresh anonymous id per request and the token could never pass device binding at all. TPStreamsApiService only: TestPressApiService accepts and ignores the parameter, since that provider has no presence support to bind a device to. Scheduling and the OkHttpClient are both injected (PresenceScheduler, OkHttpClient — reusing AssetRepository's existing client-construction style rather than TPStreamsPlayer's own companion client, to avoid coupling an unrelated shared resource to this feature) so PresenceHeartbeatManager can be unit tested against a real MockWebServer, added here as a new test dependency (this module had none before). NOTE: this work was initially built in testpress/android-player-sdk, which turned out to be an archived, deprecated repo — a different package name (com.tpstream.player, singular) from this one (com.tpstreams.player, plural). Nothing was pushed there; this is the correct, from-scratch implementation against the actual active SDK.
|
Claude finished @dhinesh-kumar-m's task in 2m 10s —— View job Reviewing PR #126 — Wire viewer-count presence heartbeat/leave into the playerTodo list:
SummaryReviewed the full diff ( Overall this is a clean, well-isolated addition. It's kept internal to the SDK ( Risks found:
Both are non-blocking for a rollout gated to 3 orgs with an opt-in, default-no-op listener, but worth addressing before wider rollout since they affect data accuracy (point 2) and integration safety (point 1). No issues found with: SharedPreferences-backed Regression assessment: No changes to core playback, DRM, offline download, or track-selection paths. The blast radius is limited to a new opt-in listener method and additive fields on Final VerdictNo blocking correctness or lifecycle issues. The two points above are worth addressing (especially the threading contract on |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Summary
/presence/v1/heartbeat,/presence/v1/leave).PresenceHeartbeatManager— starts/stops with playback (onIsPlayingChanged,release()), jittered first heartbeat, server-driven cadence vianext_heartbeat_in,Retry-Afterhandling on 429, capped backoff on repeated 401s, best-effort fire-and-forget leave call.PresenceViewerIdStore— SharedPreferences-backed persistent viewer/device ID, generated once and reused across sessions (same ID resent on every heartbeat for device-binding checks server-side).PresenceScheduler— Handler-based timer abstraction, injectable for tests.TPStreamsPlayer.Listener.onPresenceTokenExpired(videoId, callback)— new optional, default no-op listener method (matches the existingonNetworkDiagnosticsStarted()pattern) fired on a 401, so integrators can fetch a fresh token and resolve the callback. Presence is still rollout-gated to 3 orgs, so this is opt-in and won't affect existing integrators who don't implement it.AssetInfo/API layer:viewer_idis appended to the asset-info request when available, and the response'slive_stream.presence.{token,base_url}is parsed into a newPresenceConfigand passed to the player.Test plan
PresenceViewerIdStoreTest,PresenceHeartbeatManagerTest(MockWebServer-based, using aRecordingPresenceSchedulerfor deterministic timer control)ApiServiceTestwith viewer_id URL construction and presence-parsing casesRelated: testpress/iOSPlayerSDK#170, testpress/streams#2507, testpress/flutter-player-sdk#56, testpress/react-native-tpstreams#57, testpress/player.js#42