From b3e982fbaed59154fe18663f6134e1e674d38e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Muller?= Date: Tue, 19 Mar 2024 11:43:50 +0100 Subject: [PATCH] Update some documentation --- gradle/libs.versions.toml | 1 - pillarbox-core-business/build.gradle.kts | 1 - pillarbox-core-business/docs/README.md | 14 +++++---- .../core/business/SRGMediaItemBuilder.kt | 4 +-- .../core/business/TrackerDataProvider.kt | 30 ------------------- .../integrationlayer/ResourceSelector.kt | 2 +- .../service/MediaCompositionService.kt | 2 +- .../core/business/source/SRGAssetLoader.kt | 22 +++++++------- .../core/business/SRGAssetLoaderTest.kt | 28 ++++++++--------- .../CommandersActTrackerIntegrationTest.kt | 10 +++---- .../pillarbox/demo/shared/data/DemoItem.kt | 2 +- .../demo/shared/source/CustomAssetLoader.kt | 12 ++++---- pillarbox-player/build.gradle.kts | 1 - pillarbox-player/docs/MediaItemTracking.md | 17 ++++------- pillarbox-player/docs/README.md | 11 +++---- .../pillarbox/player/asset/UrlAssetLoader.kt | 2 +- .../source/PillarboxMediaSourceFactory.kt | 10 +++++-- .../player/tracker/CurrentMediaItemTracker.kt | 5 +--- .../player/tracker/MediaItemTrackerData.kt | 2 +- .../tracker/MediaItemTrackerDataTest.kt | 5 ++++ 20 files changed, 75 insertions(+), 106 deletions(-) delete mode 100644 pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/TrackerDataProvider.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d1b3d1b36..24a6abf38 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -73,7 +73,6 @@ kotlinx-kover-gradle = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", v kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx-serialization" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } -ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" } ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } ktor-http = { module = "io.ktor:ktor-http", version.ref = "ktor" } diff --git a/pillarbox-core-business/build.gradle.kts b/pillarbox-core-business/build.gradle.kts index 1ed2db21a..bd6eff51d 100644 --- a/pillarbox-core-business/build.gradle.kts +++ b/pillarbox-core-business/build.gradle.kts @@ -50,7 +50,6 @@ dependencies { testImplementation(libs.junit) testImplementation(libs.kotlin.test) testImplementation(libs.kotlinx.coroutines.test) - testImplementation(libs.ktor.client.mock) testImplementation(libs.mockk) testImplementation(libs.mockk.dsl) testRuntimeOnly(libs.robolectric) diff --git a/pillarbox-core-business/docs/README.md b/pillarbox-core-business/docs/README.md index eec0648aa..41e7f27d2 100644 --- a/pillarbox-core-business/docs/README.md +++ b/pillarbox-core-business/docs/README.md @@ -33,15 +33,17 @@ In order to play an urn content with PillarboxPlayer, you have to create it like ```kotlin val player = PillarboxPlayer( context = context, - mediaSourceFactory = SRGMediaSource.Factory(context), + mediaSourceFactory = PillarboxMediaSourceFactory(context).apply { + addAssetLoader(SRGAssetLoader(context)) + }, mediaItemTrackerProvider = DefaultMediaItemTrackerRepository() ) ``` ### Create MediaItem with URN -In order to tell PillarboxPlayer to load a specific MediaItem with SRGMediaSource.Factory. -The MediaItem have to be created by `SRGMediaItemBuilder`. +In order to tell `PillarboxPlayer` to load a specific `MediaItem` with `PillarboxMediaSourceFactory`, the `MediaItem` has to be created with +`SRGMediaItemBuilder` : ```kotlin val urnToPlay = "urn:rts:video:12345" @@ -78,12 +80,12 @@ All exceptions thrown by `MediaCompositionMediaItemSource` are caught by the pla ## Going further -SRGMediaSource factory can be created with a MediaCompositionService, this MediaCompositionService can be used to retrieve a MediaComposition. -You can create you own MediaCompositionService for loading the MediaComposition. +`PillarboxMediaSource` factory can be created with a `MediaCompositionService`, which can be used to retrieve a `MediaComposition`. You can create +you own `MediaCompositionService` to load the `MediaComposition` : ```kotlin class MediaCompositionMapDataSource : MediaCompositionService { - private val mediaCompositionMap = HashMap() + private val mediaCompositionMap = mutableMapOf() override suspend fun fetchMediaComposition(uri: Uri): Result { return mediaCompositionMap[uri]?.let { diff --git a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/SRGMediaItemBuilder.kt b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/SRGMediaItemBuilder.kt index 8d0695f3a..24a1f0520 100644 --- a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/SRGMediaItemBuilder.kt +++ b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/SRGMediaItemBuilder.kt @@ -14,7 +14,7 @@ import ch.srgssr.pillarbox.core.business.source.MimeTypeSrg import java.net.URL /** - * Create a [MediaItem] that can be parsed by SRGMediaSource + * Create a [MediaItem] that can be parsed by [PillarboxMediaSource][ch.srgssr.pillarbox.player.source.PillarboxMediaSource]. * * @param mediaItem Build a new [SRGMediaItemBuilder] from an existing [MediaItem]. */ @@ -44,7 +44,7 @@ class SRGMediaItemBuilder(mediaItem: MediaItem) { /** * Set media metadata * - * @param mediaMetadata The [MediaMetadata] to use set to [MediaItem]. + * @param mediaMetadata The [MediaMetadata] to set to [MediaItem]. * @return this for convenience */ fun setMediaMetadata(mediaMetadata: MediaMetadata): SRGMediaItemBuilder { diff --git a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/TrackerDataProvider.kt b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/TrackerDataProvider.kt deleted file mode 100644 index 4b18b1749..000000000 --- a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/TrackerDataProvider.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) SRG SSR. All rights reserved. - * License information is available from the LICENSE file. - */ -package ch.srgssr.pillarbox.core.business - -import ch.srgssr.pillarbox.core.business.integrationlayer.data.Chapter -import ch.srgssr.pillarbox.core.business.integrationlayer.data.MediaComposition -import ch.srgssr.pillarbox.core.business.integrationlayer.data.Resource -import ch.srgssr.pillarbox.player.tracker.MediaItemTrackerData - -/** - * Tracker data provider to add some data for custom tracker. - */ -fun interface TrackerDataProvider { - /** - * Update tracker data with given integration layer data. - * - * @param trackerData The [MediaItemTrackerData.Builder] to update. - * @param resource The selected [Resource]. - * @param chapter The selected [Chapter]. - * @param mediaComposition The loaded [MediaComposition]. - */ - fun update( - trackerData: MediaItemTrackerData.Builder, - resource: Resource, - chapter: Chapter, - mediaComposition: MediaComposition - ) -} diff --git a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/integrationlayer/ResourceSelector.kt b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/integrationlayer/ResourceSelector.kt index 70f3e8f7d..5a1c7f59f 100644 --- a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/integrationlayer/ResourceSelector.kt +++ b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/integrationlayer/ResourceSelector.kt @@ -23,7 +23,7 @@ internal class ResourceSelector { return try { chapter.listResource?.first { (it.type == Resource.Type.DASH || it.type == Resource.Type.HLS || it.type == Resource.Type.PROGRESSIVE) && - (it.drmList == null || it.drmList.find { drm -> drm.type == Drm.Type.WIDEVINE } != null) + (it.drmList == null || it.drmList.any { drm -> drm.type == Drm.Type.WIDEVINE }) } } catch (e: NoSuchElementException) { null diff --git a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/integrationlayer/service/MediaCompositionService.kt b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/integrationlayer/service/MediaCompositionService.kt index 30305ac95..99116f9a8 100644 --- a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/integrationlayer/service/MediaCompositionService.kt +++ b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/integrationlayer/service/MediaCompositionService.kt @@ -14,7 +14,7 @@ interface MediaCompositionService { /** * Fetch media composition * - * @param uri Uri to get MediaComposition. + * @param uri The uri of the [MediaComposition] to fetch. * @return Result */ suspend fun fetchMediaComposition(uri: Uri): Result diff --git a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/source/SRGAssetLoader.kt b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/source/SRGAssetLoader.kt index 91ebfe05c..9c0da5497 100644 --- a/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/source/SRGAssetLoader.kt +++ b/pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/source/SRGAssetLoader.kt @@ -59,11 +59,11 @@ class SRGAssetLoader( */ fun interface MediaMetadataProvider { /** - * Provide + * Feed the available information from the [resource], [chapter], and [mediaComposition] into the provided [mediaMetadataBuilder]. * - * @param mediaMetadataBuilder The [MediaMetadata.Builder] used to build MediaMetadata. + * @param mediaMetadataBuilder The [MediaMetadata.Builder] used to build the [MediaMetadata]. * @param resource The [Resource] the player will play. - * @param chapter The main [Chapter] from the mediaComposition + * @param chapter The main [Chapter] from the mediaComposition. * @param mediaComposition The [MediaComposition] loaded from [MediaCompositionService]. */ fun provide( @@ -83,7 +83,7 @@ class SRGAssetLoader( * * @param trackerDataBuilder The [MediaItemTrackerData.Builder] to add trackers data. * @param resource The [Resource] the player will play. - * @param chapter The main [Chapter] from the mediaComposition + * @param chapter The main [Chapter] from the mediaComposition. * @param mediaComposition The [MediaComposition] loaded from [MediaCompositionService]. */ fun provide( @@ -107,7 +107,9 @@ class SRGAssetLoader( var trackerDataProvider: TrackerDataProvider? = null override fun canLoadAsset(mediaItem: MediaItem): Boolean { - return mediaItem.localConfiguration?.mimeType == MimeTypeSrg || mediaItem.localConfiguration?.uri?.lastPathSegment.isValidMediaUrn() + val localConfiguration = mediaItem.localConfiguration ?: return false + + return localConfiguration.mimeType == MimeTypeSrg || localConfiguration.uri.lastPathSegment.isValidMediaUrn() } override suspend fun loadAsset(mediaItem: MediaItem): Asset { @@ -171,7 +173,7 @@ class SRGAssetLoader( } private fun fillDrmConfiguration(resource: Resource): MediaItem.DrmConfiguration? { - val drm = resource.drmList.orEmpty().find { it.type == Drm.Type.WIDEVINE } + val drm = resource.drmList?.find { it.type == Drm.Type.WIDEVINE } return drm?.let { MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID) .setLicenseUri(it.licenseUrl) @@ -180,7 +182,7 @@ class SRGAssetLoader( } /** - * ComScore (MediaPulse) don't want to track audio. Integration layer doesn't fill analytics labels for audio content, + * ComScore (MediaPulse) doesn't want to track audio. Integration layer doesn't fill analytics labels for audio content, * but only in [chapter] and [resource]. MediaComposition will still have analytics content. */ private fun getComScoreData( @@ -188,7 +190,7 @@ class SRGAssetLoader( chapter: Chapter, resource: Resource ): ComScoreTracker.Data? { - val comScoreData = HashMap().apply { + val comScoreData = mutableMapOf().apply { chapter.comScoreAnalyticsLabels?.let { mediaComposition.comScoreAnalyticsLabels?.let { mediaComposition -> putAll(mediaComposition) } putAll(it) @@ -203,7 +205,7 @@ class SRGAssetLoader( } /** - * ComScore (MediaPulse) don't want to track audio. Integration layer doesn't fill analytics labels for audio content, + * CommandersAct doesn't want to track audio. Integration layer doesn't fill analytics labels for audio content, * but only in [chapter] and [resource]. MediaComposition will still have analytics content. */ private fun getCommandersActData( @@ -211,7 +213,7 @@ class SRGAssetLoader( chapter: Chapter, resource: Resource ): CommandersActTracker.Data? { - val commandersActData = HashMap().apply { + val commandersActData = mutableMapOf().apply { mediaComposition.analyticsLabels?.let { mediaComposition -> putAll(mediaComposition) } chapter.analyticsLabels?.let { putAll(it) } resource.analyticsLabels?.let { putAll(it) } diff --git a/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/SRGAssetLoaderTest.kt b/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/SRGAssetLoaderTest.kt index 97444e474..01bd87e3b 100644 --- a/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/SRGAssetLoaderTest.kt +++ b/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/SRGAssetLoaderTest.kt @@ -31,42 +31,42 @@ import kotlin.test.Test class SRGAssetLoaderTest { private val mediaCompositionService = DummyMediaCompositionProvider() - private lateinit var mediaSourceFactory: SRGAssetLoader + private lateinit var assetLoader: SRGAssetLoader @BeforeTest fun init() { val context: Context = ApplicationProvider.getApplicationContext() - mediaSourceFactory = SRGAssetLoader(context, mediaCompositionService) + assetLoader = SRGAssetLoader(context, mediaCompositionService) } @Test(expected = IllegalStateException::class) fun testNoMediaId() = runTest { - mediaSourceFactory.loadAsset(MediaItem.Builder().build()) + assetLoader.loadAsset(MediaItem.Builder().build()) } @Test(expected = IllegalArgumentException::class) fun testInvalidMediaId() = runTest { - mediaSourceFactory.loadAsset(SRGMediaItemBuilder("urn:rts:show:radio:1234").build()) + assetLoader.loadAsset(SRGMediaItemBuilder("urn:rts:show:radio:1234").build()) } @Test(expected = ResourceNotFoundException::class) fun testNoResource() = runTest { - mediaSourceFactory.loadAsset(SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_NO_RESOURCES).build()) + assetLoader.loadAsset(SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_NO_RESOURCES).build()) } @Test(expected = ResourceNotFoundException::class) fun testNoCompatibleResource() = runTest { - mediaSourceFactory.loadAsset(SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_INCOMPATIBLE_RESOURCE).build()) + assetLoader.loadAsset(SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_INCOMPATIBLE_RESOURCE).build()) } @Test fun testCompatibleResource() = runTest { - mediaSourceFactory.loadAsset(SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_HLS_RESOURCE).build()) + assetLoader.loadAsset(SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_HLS_RESOURCE).build()) } @Test fun testMetadata() = runTest { - val asset = mediaSourceFactory.loadAsset(SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_METADATA).build()) + val asset = assetLoader.loadAsset(SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_METADATA).build()) val metadata = asset.mediaMetadata val expected = MediaMetadata.Builder() @@ -86,7 +86,7 @@ class SRGAssetLoaderTest { .setDescription("CustomDescription") .build() - val asset = mediaSourceFactory.loadAsset( + val asset = assetLoader.loadAsset( SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_METADATA) .setMediaMetadata(input) .build() @@ -104,7 +104,7 @@ class SRGAssetLoaderTest { val input = MediaMetadata.Builder() .setTitle("CustomTitle") .build() - val asset = mediaSourceFactory.loadAsset( + val asset = assetLoader.loadAsset( SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_METADATA).setMediaMetadata(input).build() ) val metadata = asset.mediaMetadata @@ -119,11 +119,11 @@ class SRGAssetLoaderTest { @Test fun testCustomMetadataProvider() = runTest { - mediaSourceFactory.mediaMetadataProvider = SRGAssetLoader.MediaMetadataProvider { mediaMetadataBuilder, _, _, _ -> + assetLoader.mediaMetadataProvider = SRGAssetLoader.MediaMetadataProvider { mediaMetadataBuilder, _, _, _ -> mediaMetadataBuilder.setTitle("My custom title") mediaMetadataBuilder.setSubtitle("My custom subtitle") } - val asset = mediaSourceFactory.loadAsset(SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_METADATA).build()) + val asset = assetLoader.loadAsset(SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_METADATA).build()) val expected = MediaMetadata.Builder() .setTitle("My custom title") .setSubtitle("My custom subtitle") @@ -133,14 +133,14 @@ class SRGAssetLoaderTest { @Test(expected = BlockReasonException::class) fun testBlockReason() = runTest { - mediaSourceFactory.loadAsset( + assetLoader.loadAsset( SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_BLOCK_REASON).build() ) } @Test(expected = BlockReasonException::class) fun testBlockedSegment() = runTest { - mediaSourceFactory.loadAsset( + assetLoader.loadAsset( SRGMediaItemBuilder(DummyMediaCompositionProvider.URN_SEGMENT_BLOCK_REASON).build() ) } diff --git a/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/tracker/commandersact/CommandersActTrackerIntegrationTest.kt b/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/tracker/commandersact/CommandersActTrackerIntegrationTest.kt index 651dda0c8..3e202521a 100644 --- a/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/tracker/commandersact/CommandersActTrackerIntegrationTest.kt +++ b/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/tracker/commandersact/CommandersActTrackerIntegrationTest.kt @@ -86,12 +86,12 @@ class CommandersActTrackerIntegrationTest { mockk(relaxed = true) } - val mediaCompositionWithFallbackDataSource = LocalMediaCompositionWithFallbackDataSource(context) + val mediaCompositionWithFallbackService = LocalMediaCompositionWithFallbackService(context) player = DefaultPillarbox( context = context, mediaItemTrackerRepository = mediaItemTrackerRepository, - mediaCompositionService = mediaCompositionWithFallbackDataSource, + mediaCompositionService = mediaCompositionWithFallbackService, clock = clock, ) } @@ -801,9 +801,9 @@ class CommandersActTrackerIntegrationTest { assertTrue(tcMediaEvents.all { it.sourceId == null }) } - private class LocalMediaCompositionWithFallbackDataSource( + private class LocalMediaCompositionWithFallbackService( context: Context, - private val fallbackDataSource: MediaCompositionService = HttpMediaCompositionService(), + private val fallbackService: MediaCompositionService = HttpMediaCompositionService(), ) : MediaCompositionService { private var mediaComposition: MediaComposition? = null @@ -820,7 +820,7 @@ class CommandersActTrackerIntegrationTest { requireNotNull(mediaComposition) } } else { - fallbackDataSource.fetchMediaComposition(uri) + fallbackService.fetchMediaComposition(uri) } } } diff --git a/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/data/DemoItem.kt b/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/data/DemoItem.kt index d5b38141d..2d19ef488 100644 --- a/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/data/DemoItem.kt +++ b/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/data/DemoItem.kt @@ -35,7 +35,7 @@ data class DemoItem( ) : Serializable { /** * Convert to a [MediaItem] - * When [uri] is a Urn MediaItem is created with [SRGMediaItemBuilder]. + * When [uri] is an URN, the [MediaItem] is created with [SRGMediaItemBuilder]. */ fun toMediaItem(ilHost: URL = IlHost.PROD): MediaItem { return if (uri.startsWith("urn:")) { diff --git a/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/source/CustomAssetLoader.kt b/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/source/CustomAssetLoader.kt index d9874f237..51f3be656 100644 --- a/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/source/CustomAssetLoader.kt +++ b/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/source/CustomAssetLoader.kt @@ -32,26 +32,26 @@ class CustomAssetLoader(context: Context) : AssetLoader(DefaultMediaSourceFactor mediaMetadata = MediaMetadata.Builder() .setTitle("${mediaItem.mediaMetadata.title}:NotSeekable") .build(), - mediaSource = NoneSeekableMediaSource(mediaSource) + mediaSource = NotSeekableMediaSource(mediaSource) ) } } /** - * A [MediaSource] that cannot be seekable. + * A [MediaSource] that cannot be seek. */ -private class NoneSeekableMediaSource(mediaSource: MediaSource) : +private class NotSeekableMediaSource(mediaSource: MediaSource) : WrappingMediaSource(mediaSource) { override fun onChildSourceInfoRefreshed(newTimeline: Timeline) { - super.onChildSourceInfoRefreshed(TimelineWithUpdatedMediaItem(NoneSeekableContent(newTimeline), mediaItem)) + super.onChildSourceInfoRefreshed(TimelineWithUpdatedMediaItem(NotSeekableContent(newTimeline), mediaItem)) } /** - * Let's say the business required that the [NoneSeekableMediaSource] cannot be seek at any time. + * Let's say the business required that the [NotSeekableMediaSource] cannot be seek at any time. * @param timeline The [Timeline] to forward. */ - private class NoneSeekableContent(timeline: Timeline) : ForwardingTimeline(timeline) { + private class NotSeekableContent(timeline: Timeline) : ForwardingTimeline(timeline) { override fun getWindow(windowIndex: Int, window: Window, defaultPositionProjectionUs: Long): Window { val internalWindow = timeline.getWindow(windowIndex, window, defaultPositionProjectionUs) internalWindow.isSeekable = false diff --git a/pillarbox-player/build.gradle.kts b/pillarbox-player/build.gradle.kts index 2cb3a7548..2de9f09c2 100644 --- a/pillarbox-player/build.gradle.kts +++ b/pillarbox-player/build.gradle.kts @@ -56,7 +56,6 @@ dependencies { testImplementation(libs.robolectric.shadows.framework) testImplementation(libs.turbine) - androidTestImplementation(libs.androidx.test.ext.junit) androidTestImplementation(libs.androidx.test.monitor) androidTestRuntimeOnly(libs.androidx.test.runner) androidTestImplementation(libs.junit) diff --git a/pillarbox-player/docs/MediaItemTracking.md b/pillarbox-player/docs/MediaItemTracking.md index 0741bd60f..d3ab76c5d 100644 --- a/pillarbox-player/docs/MediaItemTracking.md +++ b/pillarbox-player/docs/MediaItemTracking.md @@ -8,16 +8,16 @@ To enable media item tracking, you need 3 classes ## Getting started -`MediaItemTrackers` are stared and stopped when a `MediaItem` with `MediaItemTracker` changing is current state. -`PillarboxPlayer` taking care of starting, updating or stopping `MediaItemTrackers` when needed. +`MediaItemTracker`s are stared and stopped when a `MediaItem` with `MediaItemTracker` changing is current state. +`PillarboxPlayer` takes care of starting and stopping `MediaItemTracker`s when needed. ### Create a MediaItemTracker ```kotlin -data class MyTrackingData(val data:String) +data class MyTrackingData(val data: String) class DemoMediaItemTracker : MediaItemTracker { - override fun start(player: ExoPlayer,initialData: Any?) { + override fun start(player: ExoPlayer, initialData: Any?) { val data = initialData as MyTrackingData // .... } @@ -26,10 +26,6 @@ class DemoMediaItemTracker : MediaItemTracker { // .... } - override fun update(data: Any) { - // Do something with data - } - class Factory : MediaItemTracker.Factory() { override fun create(): DemoMediaItemTracker { return DemoMediaItemTracker() @@ -41,8 +37,7 @@ class DemoMediaItemTracker : MediaItemTracker { ### Append MediaItemTrackerData to MediaItem at creation Add `MediaItemTrackerData` to a `MediaItem` only when the uri is known. To add data for a `MediaItemTracker` you have to retrieve -a `MediaItemTrackerData` -from given `MediaItem` and put data in it. The data can be null if no data is required. +a `MediaItemTrackerData` from a given `MediaItem` and put data in it. The data can be `null` if no data is required. ```kotlin val trackerData = MediaItemTrackerData.Builder() @@ -73,7 +68,7 @@ val mediaItemTrackerProvider = MediaItemTrackerRepository().apply { } ``` -### Inject into the PillarboxPlayer +### Inject into the `PillarboxPlayer` ```kotlin val player = PillarboxPlayer(context = context, mediaItemTrackerProvider = mediaItemTrackerProvider) diff --git a/pillarbox-player/docs/README.md b/pillarbox-player/docs/README.md index 3759f2c1c..eca2c2dbd 100644 --- a/pillarbox-player/docs/README.md +++ b/pillarbox-player/docs/README.md @@ -25,16 +25,13 @@ More information can be found on the [top level README](../docs/README.md) ## Getting started -### Create a MediaItem - - - +### Create a `MediaItem` ```kotlin val mediaItem = MediaItem.fromUri(videoUri) ``` -### Create a PillarboxPlayer +### Create a `PillarboxPlayer` ```kotlin val player = PillarboxPlayer(context = context) @@ -46,8 +43,8 @@ player.play() ### Start playing a content -Create a `MediaItem` with all media information needed by 'PillarboxPlayer' as you would do with Exoplayer. -More information about MediaItem creation can be found [here](https://developer.android.com/media/media3/exoplayer/media-items) +Create a `MediaItem` with all media information needed by `PillarboxPlayer` as you would do with ExoPlayer. +More information about `MediaItem` creation can be found [here](https://developer.android.com/media/media3/exoplayer/media-items) ```kotlin val itemToPlay = MediaItem.fromUri("https://sample.com/sample.mp4") diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/asset/UrlAssetLoader.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/asset/UrlAssetLoader.kt index 835036fe3..a88974f02 100644 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/asset/UrlAssetLoader.kt +++ b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/asset/UrlAssetLoader.kt @@ -29,7 +29,7 @@ class UrlAssetLoader( */ fun interface TrackerDataProvider { /** - * Provide + * Provide Tracker Data to the [MediaItem]. * * @param mediaItem The input [MediaItem] of the [UrlAssetLoader.loadAsset]. * @param trackerDataBuilder The [MediaItemTrackerData.Builder] to add tracker data. diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/source/PillarboxMediaSourceFactory.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/source/PillarboxMediaSourceFactory.kt index d908a04b5..f34b46d83 100644 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/source/PillarboxMediaSourceFactory.kt +++ b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/source/PillarboxMediaSourceFactory.kt @@ -1,3 +1,7 @@ +/* + * Copyright (c) SRG SSR. All rights reserved. + * License information is available from the LICENSE file. + */ package ch.srgssr.pillarbox.player.source import android.content.Context @@ -10,8 +14,8 @@ import ch.srgssr.pillarbox.player.asset.AssetLoader import ch.srgssr.pillarbox.player.asset.UrlAssetLoader /** - * Pillarbox media source factory create a new [PillarboxMediaSource] from a MediaItem. - * It select the first [AssetLoader] to use by checking if [AssetLoader.canLoadAsset]. + * Pillarbox media source factory create a new [PillarboxMediaSource] from a [MediaItem]. + * It selects the first [AssetLoader] to use by checking if [AssetLoader.canLoadAsset]. * * @param context to create the [defaultAssetLoader]. */ @@ -25,7 +29,7 @@ class PillarboxMediaSourceFactory(context: Context) : MediaSource.Factory { * Minimal duration in milliseconds to consider a live with seek capabilities. */ var minLiveDvrDurationMs = LIVE_DVR_MIN_DURATION_MS - private val listAssetLoader = ArrayList() + private val listAssetLoader = mutableListOf() /** * Add asset loader diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/tracker/CurrentMediaItemTracker.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/tracker/CurrentMediaItemTracker.kt index 84d7ee6e2..03b3604bc 100644 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/tracker/CurrentMediaItemTracker.kt +++ b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/tracker/CurrentMediaItemTracker.kt @@ -69,10 +69,7 @@ internal class CurrentMediaItemTracker internal constructor( } return } - if (areEqual(mediaItem, currentMediaItem) && - mediaItem.canHaveTrackingSession() && - currentMediaItem?.getMediaItemTrackerDataOrNull() == null - ) { + if (mediaItem.canHaveTrackingSession() && currentMediaItem?.getMediaItemTrackerDataOrNull() == null) { startNewSession(mediaItem) // Update current media item with tracker data this.currentMediaItem = mediaItem diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/tracker/MediaItemTrackerData.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/tracker/MediaItemTrackerData.kt index fce7e5ea8..39c6c8746 100644 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/tracker/MediaItemTrackerData.kt +++ b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/tracker/MediaItemTrackerData.kt @@ -25,7 +25,7 @@ class MediaItemTrackerData private constructor(private val map: Map, An /** * Is not empty */ - val isNotEmpty: Boolean = map.isNotEmpty() + val isNotEmpty: Boolean = !isEmpty /** * Get data for a Tracker diff --git a/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/tracker/MediaItemTrackerDataTest.kt b/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/tracker/MediaItemTrackerDataTest.kt index d78335f56..1e1492469 100644 --- a/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/tracker/MediaItemTrackerDataTest.kt +++ b/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/tracker/MediaItemTrackerDataTest.kt @@ -7,6 +7,7 @@ package ch.srgssr.pillarbox.player.tracker import androidx.media3.exoplayer.ExoPlayer import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertNotEquals import kotlin.test.assertNull import kotlin.test.assertTrue @@ -19,6 +20,8 @@ class MediaItemTrackerDataTest { val mediaItemTracker2 = MediaItemTracker2() assertTrue(emptyMediaItemTrackerData.trackers.isEmpty()) + assertTrue(emptyMediaItemTrackerData.isEmpty) + assertFalse(emptyMediaItemTrackerData.isNotEmpty) assertNull(emptyMediaItemTrackerData.getData(mediaItemTracker1)) assertNull(emptyMediaItemTrackerData.getDataAs(mediaItemTracker1)) assertNull(emptyMediaItemTrackerData.getData(mediaItemTracker2)) @@ -30,6 +33,8 @@ class MediaItemTrackerDataTest { .build() assertEquals(setOf(mediaItemTracker1::class.java, mediaItemTracker2::class.java), mediaItemTrackerDataUpdated.trackers) + assertFalse(mediaItemTrackerDataUpdated.isEmpty) + assertTrue(mediaItemTrackerDataUpdated.isNotEmpty) assertEquals("Some value", mediaItemTrackerDataUpdated.getData(mediaItemTracker1)) assertEquals("Some value", mediaItemTrackerDataUpdated.getDataAs(mediaItemTracker1)) assertNull(mediaItemTrackerDataUpdated.getData(mediaItemTracker2))