diff --git a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/DefaultPillarbox.kt b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/DefaultPillarbox.kt index 263e4b02c..8794452f0 100644 --- a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/DefaultPillarbox.kt +++ b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/DefaultPillarbox.kt @@ -6,6 +6,7 @@ package ch.srgssr.pillarbox.core.business import android.content.Context import androidx.annotation.VisibleForTesting +import androidx.media3.common.Player import androidx.media3.common.util.Clock import androidx.media3.exoplayer.DefaultLoadControl import androidx.media3.exoplayer.LoadControl @@ -14,10 +15,12 @@ import ch.srgssr.pillarbox.core.business.integrationlayer.service.MediaCompositi import ch.srgssr.pillarbox.core.business.source.SRGAssetLoader import ch.srgssr.pillarbox.core.business.tracker.DefaultMediaItemTrackerRepository import ch.srgssr.pillarbox.player.PillarboxExoPlayer +import ch.srgssr.pillarbox.player.PillarboxExoPlayer.Companion.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION import ch.srgssr.pillarbox.player.PillarboxLoadControl import ch.srgssr.pillarbox.player.SeekIncrement import ch.srgssr.pillarbox.player.source.PillarboxMediaSourceFactory import ch.srgssr.pillarbox.player.tracker.MediaItemTrackerProvider +import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds /** @@ -31,6 +34,7 @@ object DefaultPillarbox { * * @param context The context. * @param seekIncrement The seek increment. + * @param maxSeekToPreviousPosition The [Player.getMaxSeekToPreviousPosition] value. * @param mediaItemTrackerRepository The provider of MediaItemTracker, by default [DefaultMediaItemTrackerRepository]. * @param mediaCompositionService The [MediaCompositionService] to use, by default [HttpMediaCompositionService]. * @param loadControl The load control, by default [PillarboxLoadControl]. @@ -39,6 +43,7 @@ object DefaultPillarbox { operator fun invoke( context: Context, seekIncrement: SeekIncrement = defaultSeekIncrement, + maxSeekToPreviousPosition: Duration = DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION, mediaItemTrackerRepository: MediaItemTrackerProvider = DefaultMediaItemTrackerRepository(), mediaCompositionService: MediaCompositionService = HttpMediaCompositionService(), loadControl: LoadControl = PillarboxLoadControl(), @@ -46,6 +51,7 @@ object DefaultPillarbox { return DefaultPillarbox( context = context, seekIncrement = seekIncrement, + maxSeekToPreviousPosition = maxSeekToPreviousPosition, mediaItemTrackerRepository = mediaItemTrackerRepository, mediaCompositionService = mediaCompositionService, loadControl = loadControl, @@ -58,6 +64,7 @@ object DefaultPillarbox { * * @param context The context. * @param seekIncrement The seek increment. + * @param maxSeekToPreviousPosition The [Player.getMaxSeekToPreviousPosition] value. * @param mediaItemTrackerRepository The provider of MediaItemTracker, by default [DefaultMediaItemTrackerRepository]. * @param loadControl The load control, by default [DefaultLoadControl]. * @param mediaCompositionService The [MediaCompositionService] to use, by default [HttpMediaCompositionService]. @@ -68,6 +75,7 @@ object DefaultPillarbox { operator fun invoke( context: Context, seekIncrement: SeekIncrement = defaultSeekIncrement, + maxSeekToPreviousPosition: Duration = DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION, mediaItemTrackerRepository: MediaItemTrackerProvider = DefaultMediaItemTrackerRepository(), loadControl: LoadControl = DefaultLoadControl(), mediaCompositionService: MediaCompositionService = HttpMediaCompositionService(), @@ -76,6 +84,7 @@ object DefaultPillarbox { return PillarboxExoPlayer( context = context, seekIncrement = seekIncrement, + maxSeekToPreviousPosition = maxSeekToPreviousPosition, mediaSourceFactory = PillarboxMediaSourceFactory(context).apply { addAssetLoader(SRGAssetLoader(context, mediaCompositionService)) }, diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/PillarboxExoPlayer.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/PillarboxExoPlayer.kt index 1aace7e3b..754bbda3d 100644 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/PillarboxExoPlayer.kt +++ b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/PillarboxExoPlayer.kt @@ -6,6 +6,7 @@ package ch.srgssr.pillarbox.player import android.content.Context import androidx.annotation.VisibleForTesting +import androidx.media3.common.C import androidx.media3.common.MediaItem import androidx.media3.common.PlaybackException import androidx.media3.common.PlaybackParameters @@ -33,6 +34,8 @@ import ch.srgssr.pillarbox.player.tracker.MediaItemTrackerProvider import ch.srgssr.pillarbox.player.tracker.MediaItemTrackerRepository import ch.srgssr.pillarbox.player.tracker.TimeRangeTracker import ch.srgssr.pillarbox.player.utils.PillarboxEventLogger +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds /** * Pillarbox player @@ -123,13 +126,15 @@ class PillarboxExoPlayer internal constructor( mediaSourceFactory: PillarboxMediaSourceFactory = PillarboxMediaSourceFactory(context), loadControl: LoadControl = PillarboxLoadControl(), mediaItemTrackerProvider: MediaItemTrackerProvider = MediaItemTrackerRepository(), - seekIncrement: SeekIncrement = SeekIncrement() + seekIncrement: SeekIncrement = SeekIncrement(), + maxSeekToPreviousPosition: Duration = DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION, ) : this( context = context, mediaSourceFactory = mediaSourceFactory, loadControl = loadControl, mediaItemTrackerProvider = mediaItemTrackerProvider, seekIncrement = seekIncrement, + maxSeekToPreviousPosition = maxSeekToPreviousPosition, clock = Clock.DEFAULT, ) @@ -140,6 +145,7 @@ class PillarboxExoPlayer internal constructor( loadControl: LoadControl = PillarboxLoadControl(), mediaItemTrackerProvider: MediaItemTrackerProvider = MediaItemTrackerRepository(), seekIncrement: SeekIncrement = SeekIncrement(), + maxSeekToPreviousPosition: Duration = DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION, clock: Clock, analyticsCollector: PillarboxAnalyticsCollector = PillarboxAnalyticsCollector(clock), ) : this( @@ -147,6 +153,7 @@ class PillarboxExoPlayer internal constructor( .setClock(clock) .setUsePlatformDiagnostics(false) .setSeekIncrements(seekIncrement) + .setMaxSeekToPreviousPositionMs(maxSeekToPreviousPosition.inWholeMilliseconds) .setRenderersFactory( DefaultRenderersFactory(context) .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF) @@ -405,6 +412,13 @@ class PillarboxExoPlayer internal constructor( } } } + + companion object { + /** + * A default maximum position for which a seek to previous will seek to the previous window. + */ + val DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION = C.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION_MS.milliseconds + } } /** @@ -426,7 +440,7 @@ fun Player.isPlaybackSpeedPossibleAtPosition(position: Long, speed: Float, windo internal fun Window.isPlaybackSpeedPossibleAtPosition(positionMs: Long, playbackSpeed: Float): Boolean { return when { - !isLive() || playbackSpeed == NormalSpeed -> true + !isLive || playbackSpeed == NormalSpeed -> true !isSeekable -> false isAtDefaultPosition(positionMs) && playbackSpeed > NormalSpeed -> false else -> true