mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-07-30 19:46:17 +00:00
TEMP: HlsVerify error-level probes for on-device verification
DO NOT MERGE — revert this commit before the branch goes anywhere.
PLAYBACK_DIAG_TAG logs at DEBUG and Amethyst.onCreate sets
`Log.minLevel = if (BuildConfig.DEBUG) DEBUG else ERROR`, so nothing on that
tag survives in the benchmark build. Three logcat captures during this work
had zero PlaybackDiag lines for exactly that reason, which left the routing
decision unverifiable — the fix was only ever confirmed indirectly, by the
crash no longer happening.
Adds one ERROR-level tag, HlsVerify, on the three paths unit tests cannot
reach:
- CustomMediaSourceFactory.createMediaSource — the routing decision, so
isHlsMediaItem's verdict and the chosen factory are visible. This is the
predicate with no test coverage, since android.net.Uri stubs to null
under unitTests.isReturnDefaultValues.
- LowLatencyStrippingParser.parse — whether the stripper actually engaged
and how many bytes it removed, so a silent stop-stripping regression is
visible rather than inferred.
- HlsLivenessRecorder.maybeRecord — the other consumer of the shared
predicate, unreachable without a Player.
The pure predicates underneath are already unit-tested and remain the durable
regression guard; this is only for confirming the wiring on a device.
Capture with `adb logcat -s HlsVerify:E`. Remove with `grep -rn HlsVerify` or
by reverting this commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018uE2Db4pzmhi5cFKKkyq2m
This commit is contained in:
co-authored by
Claude Opus 5
parent
cabe539e8e
commit
76b3323583
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.service.playback
|
||||
|
||||
/**
|
||||
* TEMPORARY — delete this file and its three call sites before merging.
|
||||
* `grep -rn HlsVerify` finds all of them; reverting the commit that added it does the same job.
|
||||
*
|
||||
* [PLAYBACK_DIAG_TAG] logs at DEBUG, and `Amethyst.onCreate` sets
|
||||
* `Log.minLevel = if (BuildConfig.DEBUG) DEBUG else ERROR` — so nothing on that tag survives in a
|
||||
* benchmark or release build. On-device verification of the HLS work therefore has to log at ERROR
|
||||
* to be visible at all.
|
||||
*
|
||||
* Deliberately placed only on the paths that unit tests *cannot* reach:
|
||||
* - `isHlsMediaItem` and the factory choice — needs `android.net.Uri`, which stubs to null under
|
||||
* `unitTests.isReturnDefaultValues`.
|
||||
* - `LowLatencyStrippingParser.parse` — needs a `Uri` for the same reason.
|
||||
* - `HlsLivenessRecorder.maybeRecord` — needs a `Player`.
|
||||
*
|
||||
* The pure predicates underneath (`stripLowLatencyTags`, `isHlsMedia`, `shouldBypassCache`,
|
||||
* `livenessVerdictToRecord`) already have unit tests, which are the durable regression guard. This
|
||||
* tag is only for confirming the wiring on a real device.
|
||||
*
|
||||
* Capture with: `adb logcat -s HlsVerify:E`
|
||||
*/
|
||||
const val HLS_VERIFY_TAG = "HlsVerify"
|
||||
+6
@@ -30,6 +30,7 @@ import androidx.media3.exoplayer.hls.HlsMediaSource
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy
|
||||
import com.vitorpamplona.amethyst.service.playback.HLS_VERIFY_TAG
|
||||
import com.vitorpamplona.amethyst.service.playback.PLAYBACK_DIAG_TAG
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.MediaItemCache
|
||||
import com.vitorpamplona.amethyst.service.playback.diskCache.HlsLivenessCache
|
||||
@@ -165,6 +166,11 @@ class CustomMediaSourceFactory(
|
||||
|
||||
// Logs the routing inputs directly rather than a re-derived label, so it can't drift from
|
||||
// shouldBypassCache.
|
||||
// TEMPORARY HlsVerify — see HlsVerifyLog.kt. Remove before merge.
|
||||
Log.e(HLS_VERIFY_TAG) {
|
||||
"ROUTE hls=$hls bypassCache=$bypassCache flaggedLive=$flaggedLive knownOnDemand=$knownOnDemand " +
|
||||
"mime=${mediaItem.localConfiguration?.mimeType} -> ${source::class.java.simpleName} id=$id"
|
||||
}
|
||||
Log.d(PLAYBACK_DIAG_TAG) {
|
||||
"SOURCE ${if (bypassCache) "BYPASS" else "CACHE"} flaggedLive=$flaggedLive hls=$hls knownOnDemand=$knownOnDemand " +
|
||||
"mime=${mediaItem.localConfiguration?.mimeType} -> ${source::class.java.simpleName} id=$id"
|
||||
|
||||
+3
@@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.service.playback.playerPool
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.Timeline
|
||||
import com.vitorpamplona.amethyst.service.playback.HLS_VERIFY_TAG
|
||||
import com.vitorpamplona.amethyst.service.playback.PLAYBACK_DIAG_TAG
|
||||
import com.vitorpamplona.amethyst.service.playback.diskCache.HlsLivenessCache
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
@@ -105,6 +106,8 @@ class HlsLivenessRecorder(
|
||||
// refresh of a live stream, and the verdict is stable once learned, so re-putting the same
|
||||
// value would take a ConcurrentHashMap bin lock on every callback for nothing.
|
||||
if (known != toRecord) {
|
||||
// TEMPORARY HlsVerify — see HlsVerifyLog.kt. Remove before merge.
|
||||
Log.e(HLS_VERIFY_TAG) { "LIVENESS ${if (toRecord) "LIVE" else "ON-DEMAND"} learned for $url" }
|
||||
Log.d(PLAYBACK_DIAG_TAG) { "LIVENESS ${if (toRecord) "LIVE" else "ON-DEMAND"} learned for $url" }
|
||||
HlsLivenessCache.record(url, toRecord)
|
||||
}
|
||||
|
||||
+15
-1
@@ -28,6 +28,8 @@ import androidx.media3.exoplayer.hls.playlist.HlsMultivariantPlaylist
|
||||
import androidx.media3.exoplayer.hls.playlist.HlsPlaylist
|
||||
import androidx.media3.exoplayer.hls.playlist.HlsPlaylistParserFactory
|
||||
import androidx.media3.exoplayer.upstream.ParsingLoadable
|
||||
import com.vitorpamplona.amethyst.service.playback.HLS_VERIFY_TAG
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
|
||||
@@ -104,7 +106,19 @@ internal class LowLatencyStrippingParser(
|
||||
override fun parse(
|
||||
uri: Uri,
|
||||
inputStream: InputStream,
|
||||
): HlsPlaylist = delegate.parse(uri, ByteArrayInputStream(stripLowLatencyTags(inputStream.readBytes())))
|
||||
): HlsPlaylist {
|
||||
val original = inputStream.readBytes()
|
||||
val stripped = stripLowLatencyTags(original)
|
||||
// TEMPORARY HlsVerify — see HlsVerifyLog.kt. Remove before merge.
|
||||
Log.e(HLS_VERIFY_TAG) {
|
||||
if (stripped === original) {
|
||||
"PARSE no LL tags (${original.size}B) $uri"
|
||||
} else {
|
||||
"PARSE STRIPPED ${original.size - stripped.size}B of ${original.size}B $uri"
|
||||
}
|
||||
}
|
||||
return delegate.parse(uri, ByteArrayInputStream(stripped))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user