package com.doublesymmetry.trackplayer import androidx.media3.common.MediaItem import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.drm.DrmSessionManagerProvider import androidx.media3.exoplayer.source.MediaSource import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy /** * A [MediaSource.Factory] that routes each item to one of two delegates based on * whether it is a live stream: live items go to [uncachedFactory], everything * else to [cachedFactory]. * * Live HLS/streaming segments are write-once-read-once — the player consumes * each one at the live edge and never seeks back to it. Caching them only churns * the bounded LRU cache, evicting genuinely reusable VOD content and wasting * disk writes. Routing live items around the cache mirrors iOS, where the proxy * streams non-VOD segments through without persisting them. * * Liveness is read from the `isLive` flag carried in the item's * [MediaItem.mediaMetadata] extras (set in `TrackPlayerMediaItem.asMediaItem`). * The actual playlist liveness isn't known until the manifest is fetched — * which happens inside ExoPlayer, after the media source is created — so the * user-supplied flag is the only signal available at routing time. */ @UnstableApi class LivenessRoutingMediaSourceFactory( private val cachedFactory: MediaSource.Factory, private val uncachedFactory: MediaSource.Factory ) : MediaSource.Factory { override fun createMediaSource(mediaItem: MediaItem): MediaSource { val isLive = mediaItem.mediaMetadata.extras?.getBoolean("isLive", false) == true val factory = if (isLive) uncachedFactory else cachedFactory return factory.createMediaSource(mediaItem) } override fun getSupportedTypes(): IntArray = cachedFactory.supportedTypes override fun setDrmSessionManagerProvider( drmSessionManagerProvider: DrmSessionManagerProvider ): MediaSource.Factory { cachedFactory.setDrmSessionManagerProvider(drmSessionManagerProvider) uncachedFactory.setDrmSessionManagerProvider(drmSessionManagerProvider) return this } override fun setLoadErrorHandlingPolicy( loadErrorHandlingPolicy: LoadErrorHandlingPolicy ): MediaSource.Factory { cachedFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) uncachedFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) return this } }