mirror of
https://github.com/FluxaMedia/fluxa.git
synced 2026-08-06 16:59:44 +00:00
fix: reset Android torrent telemetry sessions
This commit is contained in:
parent
211dc44b37
commit
e539cfc024
2 changed files with 53 additions and 8 deletions
|
|
@ -7,6 +7,7 @@ import android.app.Activity
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.media3.common.Player
|
||||
|
|
@ -31,6 +32,12 @@ import com.fluxa.app.shared.feature.player.TorrentStreamStatus
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.UUID
|
||||
|
||||
private data class PlaybackTelemetrySession(
|
||||
val id: String?,
|
||||
val startedAtMs: Long
|
||||
)
|
||||
|
||||
@Composable
|
||||
internal fun ExoPlayerListenerEffect(
|
||||
|
|
@ -58,11 +65,22 @@ internal fun ExoPlayerListenerEffect(
|
|||
val latestAutoFallbackOnStreamError by rememberUpdatedState(autoFallbackOnStreamError)
|
||||
val latestCurrentStreamIndex by rememberUpdatedState(currentStreamIndex)
|
||||
val latestCurrentStreamsSize by rememberUpdatedState(currentStreamsSize)
|
||||
val telemetrySession = remember(currentUrl) {
|
||||
PlaybackTelemetrySession(
|
||||
id = currentUrl.takeIf { it.isTorrentPlaybackUrl() }?.let { UUID.randomUUID().toString() },
|
||||
startedAtMs = android.os.SystemClock.elapsedRealtime()
|
||||
)
|
||||
}
|
||||
val latestTelemetrySession by rememberUpdatedState(telemetrySession)
|
||||
|
||||
LaunchedEffect(telemetrySession) {
|
||||
telemetrySession.id?.let(torrentManager::beginPlaybackTelemetry)
|
||||
}
|
||||
|
||||
DisposableEffect(exoPlayer, useMpvBackend) {
|
||||
val playbackStartedAt = android.os.SystemClock.elapsedRealtime()
|
||||
var firstFrameReported = false
|
||||
var stallStartedAt: Long? = null
|
||||
var listenerSessionId: String? = null
|
||||
val listener = object : Player.Listener {
|
||||
override fun onMetadata(metadata: androidx.media3.common.Metadata) {
|
||||
if (useMpvBackend) return
|
||||
|
|
@ -87,14 +105,20 @@ internal fun ExoPlayerListenerEffect(
|
|||
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
if (useMpvBackend) return
|
||||
if (currentUrl.isTorrentPlaybackUrl() && exoPlayer.currentPosition > 0L) {
|
||||
val telemetry = latestTelemetrySession
|
||||
if (listenerSessionId != telemetry.id) {
|
||||
listenerSessionId = telemetry.id
|
||||
firstFrameReported = false
|
||||
stallStartedAt = null
|
||||
}
|
||||
if (telemetry.id != null && exoPlayer.currentPosition > 0L) {
|
||||
val now = android.os.SystemClock.elapsedRealtime()
|
||||
if (playbackState == Player.STATE_BUFFERING && stallStartedAt == null) {
|
||||
stallStartedAt = now
|
||||
torrentManager.recordPlaybackTelemetry("stallStarted")
|
||||
torrentManager.recordPlaybackTelemetry("stallStarted", sessionId = telemetry.id)
|
||||
} else if (playbackState != Player.STATE_BUFFERING) {
|
||||
stallStartedAt?.let { startedAt ->
|
||||
torrentManager.recordPlaybackTelemetry("stallEnded", now - startedAt)
|
||||
torrentManager.recordPlaybackTelemetry("stallEnded", now - startedAt, telemetry.id)
|
||||
stallStartedAt = null
|
||||
}
|
||||
}
|
||||
|
|
@ -132,11 +156,18 @@ internal fun ExoPlayerListenerEffect(
|
|||
|
||||
override fun onRenderedFirstFrame() {
|
||||
if (useMpvBackend) return
|
||||
if (!firstFrameReported && currentUrl.isTorrentPlaybackUrl()) {
|
||||
val telemetry = latestTelemetrySession
|
||||
if (listenerSessionId != telemetry.id) {
|
||||
listenerSessionId = telemetry.id
|
||||
firstFrameReported = false
|
||||
stallStartedAt = null
|
||||
}
|
||||
if (!firstFrameReported && telemetry.id != null) {
|
||||
firstFrameReported = true
|
||||
torrentManager.recordPlaybackTelemetry(
|
||||
"firstFrame",
|
||||
android.os.SystemClock.elapsedRealtime() - playbackStartedAt
|
||||
android.os.SystemClock.elapsedRealtime() - telemetry.startedAtMs,
|
||||
telemetry.id
|
||||
)
|
||||
}
|
||||
latestUpdateEngine.value { copy(render = render.copy(isVideoRendered = true), playerError = null) }
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ class TorrentStreamManager private constructor() {
|
|||
@Volatile private var appContext: Context? = null
|
||||
@Volatile private var engine: TorrentServerEngine? = null
|
||||
@Volatile private var activeTorrentLink: String? = null
|
||||
@Volatile private var activeTelemetrySessionId: String? = null
|
||||
|
||||
private val _status = MutableStateFlow(TorrentStreamStatus())
|
||||
val status: StateFlow<TorrentStreamStatus> = _status.asStateFlow()
|
||||
|
|
@ -177,18 +178,31 @@ class TorrentStreamManager private constructor() {
|
|||
}
|
||||
}
|
||||
activeTorrentLink = null
|
||||
activeTelemetrySessionId = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports player-side milestones to the local streaming engine. This is
|
||||
* best-effort telemetry: a failed report must never affect playback.
|
||||
*/
|
||||
fun recordPlaybackTelemetry(event: String, elapsedMs: Long? = null) {
|
||||
fun beginPlaybackTelemetry(sessionId: String) {
|
||||
if (sessionId.isBlank() || activeTorrentLink == null) return
|
||||
activeTelemetrySessionId = sessionId
|
||||
recordPlaybackTelemetry("sessionStarted", sessionId = sessionId)
|
||||
}
|
||||
|
||||
fun recordPlaybackTelemetry(event: String, elapsedMs: Long? = null, sessionId: String) {
|
||||
val link = activeTorrentLink ?: return
|
||||
if (activeTelemetrySessionId != sessionId) return
|
||||
scope.launch {
|
||||
runCatching {
|
||||
val payload = gson.toJson(
|
||||
mapOf("link" to link, "event" to event, "elapsedMs" to elapsedMs)
|
||||
mapOf(
|
||||
"link" to link,
|
||||
"sessionId" to sessionId,
|
||||
"event" to event,
|
||||
"elapsedMs" to elapsedMs
|
||||
)
|
||||
)
|
||||
val request = Request.Builder()
|
||||
.url("${Constants.LocalServer.TORRENT_SERVER_BASE_URL}/telemetry")
|
||||
|
|
|
|||
Loading…
Reference in a new issue