mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-15 00:42:54 +01:00
Media3 marks a progressive stream live when the data source reports no length and the extractor no duration, and a live item makes the media session publish PLAYBACK_POSITION_UNKNOWN, so the notification progress never advances even though the item carries the library duration. The app only declares a stream length for a transcode of a track that has one in a length-estimable format (`declaredStreamLength`), so a chunked response stays live for an Opus/Ogg/Vorbis transcode (a length estimate breaks the end-seek they rely on), for a transcode of a track whose library duration is missing, and for a direct play the server does not give a Content-Length. The now playing screen shows progress in all of those because it falls back to the metadata duration; the notification had nothing to advance. Wrap the ExoPlayer in a ForwardingPlayer that reports an item with a declared duration as finite. The session then publishes the real position and the metadata duration, so the notification shows progress for every unknown-length stream, not just Opus. The stream is still not seekable; only the reported liveness changes.
31 lines
1.3 KiB
Kotlin
31 lines
1.3 KiB
Kotlin
package com.subtracks.playback
|
|
|
|
import androidx.annotation.OptIn
|
|
import androidx.media3.common.ForwardingPlayer
|
|
import androidx.media3.common.Player
|
|
import androidx.media3.common.util.UnstableApi
|
|
|
|
/**
|
|
* Reports a track whose duration is known from its metadata as finite rather than live.
|
|
*
|
|
* Media3 marks a progressive stream live when the data source reports no length and the extractor
|
|
* no duration. The app declares a length only for a transcode of a track that has one in a
|
|
* length-estimable format, so a chunked response stays live for an Opus/Ogg/Vorbis transcode, for
|
|
* a transcode of a track whose library duration is missing, and for a direct play the server does
|
|
* not give a Content-Length. A live item makes the media session publish no playback position, so
|
|
* the notification loses its progress even though the item carries a real duration. The stream is
|
|
* still not seekable; this only restores the position the session reports.
|
|
*/
|
|
@OptIn(UnstableApi::class)
|
|
internal class KnownDurationPlayer(
|
|
player: Player,
|
|
) : ForwardingPlayer(player) {
|
|
override fun isCurrentMediaItemLive(): Boolean = if (declaredDurationMs() != null) false else super.isCurrentMediaItemLive()
|
|
|
|
private fun declaredDurationMs(): Long? =
|
|
currentMediaItem
|
|
?.mediaMetadata
|
|
?.durationMs
|
|
?.takeIf { it > 0 }
|
|
}
|