Skip to content

Commit 21b35c7

Browse files
StaehliJMGaetan89
andauthored
Refactor media loading (#475)
Co-authored-by: Gaëtan Muller <[email protected]>
1 parent cf1577a commit 21b35c7

File tree

70 files changed

+1640
-1723
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1640
-1723
lines changed

gradle/libs.versions.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ kotlinx-kover-gradle = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", v
7373
kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx-serialization" }
7474
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
7575
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
76-
ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" }
7776
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
7877
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
7978
ktor-http = { module = "io.ktor:ktor-http", version.ref = "ktor" }

pillarbox-core-business/build.gradle.kts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ dependencies {
5050
testImplementation(libs.junit)
5151
testImplementation(libs.kotlin.test)
5252
testImplementation(libs.kotlinx.coroutines.test)
53-
testImplementation(libs.ktor.client.mock)
5453
testImplementation(libs.mockk)
5554
testImplementation(libs.mockk.dsl)
5655
testRuntimeOnly(libs.robolectric)

pillarbox-core-business/docs/README.md

Lines changed: 18 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@
55

66
# Pillarbox Core Business module
77

8-
Provides SRG SSR media URN `MediaItemSource` to Pillarbox. It basically converts an integration layer `MediaComposition` to a
9-
playable `MediaItem`.
8+
Provides SRG SSR media URN `MediaSource` to Pillarbox. It basically converts an integration layer `MediaComposition` to a
9+
playable `MediaSource`.
1010

1111
Supported contents are :
1212

1313
- Video and Audio on demand
1414
- Live streams (with and without DVR)
1515
- Token protected
1616
- DRM protected
17-
18-
Unsupported contents are :
19-
20-
- 360° content
17+
- 360° content (Need to used the correct view)
2118

2219
## Integration
2320

@@ -34,27 +31,23 @@ More information can be found on the [top level README](../docs/README.md)
3431
In order to play an urn content with PillarboxPlayer, you have to create it like this :
3532

3633
```kotlin
37-
val player = PillarboxPlayer(
34+
val player = PillarboxPlayer(
3835
context = context,
39-
mediaItemSource = MediaCompositionMediaItemSource(DefaultMediaCompositionDataSource(baseUrl = IlHost.PROD)),
40-
/**
41-
* Can be skipped if you never play token-protected content.
42-
*/
43-
dataSourceFactory = AkamaiTokenDataSource.Factory(),
44-
/**
45-
* Required Default SRG MediaItem trackers
46-
*/
36+
mediaSourceFactory = PillarboxMediaSourceFactory(context).apply {
37+
addAssetLoader(SRGAssetLoader(context))
38+
},
4739
mediaItemTrackerProvider = DefaultMediaItemTrackerRepository()
4840
)
4941
```
5042

51-
`MediaCompositionDataSourceImpl` retrieves a `MediaComposition` from the integration layer web service.
52-
5343
### Create MediaItem with URN
5444

45+
In order to tell `PillarboxPlayer` to load a specific `MediaItem` with `PillarboxMediaSourceFactory`, the `MediaItem` has to be created with
46+
`SRGMediaItemBuilder` :
47+
5548
```kotlin
5649
val urnToPlay = "urn:rts:video:12345"
57-
val itemToPlay = MediaItem.Builder().setMediaId(urnToPlay).build()
50+
val itemToPlay = SRGMediaItemBuilder(urnToPlay).build()
5851

5952
player.setMediaItem(itemToPlay)
6053
```
@@ -85,58 +78,19 @@ All exceptions thrown by `MediaCompositionMediaItemSource` are caught by the pla
8578
})
8679
```
8780

88-
## Add custom trackers
89-
90-
`MediaItemTracker` can be added to the player. The data related to tracker have to be added during `MediaItem` creation inside
91-
`MediaCompositionMediaItemSource`. `TrackerDataProvider` allow to add data for specific tracker.
92-
93-
### Create custom MediaItemTracker
94-
95-
```kotlin
96-
class CustomTracker : MediaItemTracker {
97-
98-
data class Data(val mediaComposition: MediaComposition)
99-
100-
// implements here functions
101-
}
102-
```
103-
104-
### Create and add required custom tracker data
105-
106-
```kotlin
107-
val mediaItemSource = MediaCompositionMediaItemSource(
108-
mediaCompositionDataSource = mediaCompositionDataSource,
109-
trackerDataProvider = object : TrackerDataProvider {
110-
override fun update(trackerData: MediaItemTrackerData, resource: Resource, chapter: Chapter, mediaComposition: MediaComposition) {
111-
trackerData.putData(CustomTracker::class.java, CustomTracker.Data(mediaComposition))
112-
}
113-
})
114-
```
115-
116-
### Inject custom tracker to the player
117-
118-
```kotlin
119-
val player = PillarboxPlayer(context = context,
120-
mediaItemSource = mediaItemSource,
121-
mediaItemTrackerProvider = DefaultMediaItemTrackerRepository().apply {
122-
registerFactory(CustomTracker::class.java, CustomTracker.Factory())
123-
}
124-
)
125-
```
126-
12781
## Going further
12882

129-
As you see, the `MediaCompositionMediaItemSource` is created from an interface, so you can load custom MediaComposition easily into Pillarbox by
130-
implementing your own `MediaCompositionDataSource`.
83+
`PillarboxMediaSource` factory can be created with a `MediaCompositionService`, which can be used to retrieve a `MediaComposition`. You can create
84+
you own `MediaCompositionService` to load the `MediaComposition` :
13185

13286
```kotlin
133-
class MediaCompositionMapDataSource : MediaCompositionDataSource {
134-
private val mediaCompositionMap = HashMap<String, MediaComposition>()
87+
class MediaCompositionMapDataSource : MediaCompositionService {
88+
private val mediaCompositionMap = mutableMapOf<Uri, MediaComposition>()
13589

136-
override suspend fun getMediaCompositionByUrn(urn: String): Result<MediaComposition> {
137-
return mediaCompositionMap[urn]?.let {
90+
override suspend fun fetchMediaComposition(uri: Uri): Result<MediaComposition> {
91+
return mediaCompositionMap[uri]?.let {
13892
Result.success(it)
139-
} ?: Result.failure(IOException("$urn not found"))
93+
} ?: Result.failure(IOException("$uri not found"))
14094
}
14195
}
14296
```

pillarbox-core-business/src/main/java/ch/srgssr/pillarbox/core/business/DefaultPillarbox.kt

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ package ch.srgssr.pillarbox.core.business
77
import android.content.Context
88
import androidx.annotation.VisibleForTesting
99
import androidx.media3.common.util.Clock
10-
import androidx.media3.datasource.DataSource
1110
import androidx.media3.exoplayer.DefaultLoadControl
1211
import androidx.media3.exoplayer.LoadControl
13-
import ch.srgssr.pillarbox.core.business.akamai.AkamaiTokenDataSource
14-
import ch.srgssr.pillarbox.core.business.integrationlayer.service.DefaultMediaCompositionDataSource
12+
import ch.srgssr.pillarbox.core.business.integrationlayer.service.HttpMediaCompositionService
13+
import ch.srgssr.pillarbox.core.business.integrationlayer.service.MediaCompositionService
14+
import ch.srgssr.pillarbox.core.business.source.SRGAssetLoader
1515
import ch.srgssr.pillarbox.core.business.tracker.DefaultMediaItemTrackerRepository
1616
import ch.srgssr.pillarbox.player.PillarboxLoadControl
1717
import ch.srgssr.pillarbox.player.PillarboxPlayer
1818
import ch.srgssr.pillarbox.player.SeekIncrement
19-
import ch.srgssr.pillarbox.player.data.MediaItemSource
19+
import ch.srgssr.pillarbox.player.source.PillarboxMediaSourceFactory
2020
import ch.srgssr.pillarbox.player.tracker.MediaItemTrackerProvider
2121
import kotlin.time.Duration.Companion.seconds
2222

@@ -32,27 +32,22 @@ object DefaultPillarbox {
3232
* @param context The context.
3333
* @param seekIncrement The seek increment.
3434
* @param mediaItemTrackerRepository The provider of MediaItemTracker, by default [DefaultMediaItemTrackerRepository].
35-
* @param mediaItemSource The MediaItem source by default [MediaCompositionMediaItemSource].
36-
* @param dataSourceFactory The Http exoplayer data source factory, by default [AkamaiTokenDataSource.Factory].
37-
* @param loadControl The load control, by default [DefaultLoadControl].
35+
* @param mediaCompositionService The [MediaCompositionService] to use, by default [HttpMediaCompositionService].
36+
* @param loadControl The load control, by default [PillarboxLoadControl].
3837
* @return [PillarboxPlayer] suited for SRG.
3938
*/
4039
operator fun invoke(
4140
context: Context,
4241
seekIncrement: SeekIncrement = defaultSeekIncrement,
4342
mediaItemTrackerRepository: MediaItemTrackerProvider = DefaultMediaItemTrackerRepository(),
44-
mediaItemSource: MediaItemSource = MediaCompositionMediaItemSource(
45-
mediaCompositionDataSource = DefaultMediaCompositionDataSource(),
46-
),
47-
dataSourceFactory: DataSource.Factory = AkamaiTokenDataSource.Factory(),
43+
mediaCompositionService: MediaCompositionService = HttpMediaCompositionService(),
4844
loadControl: LoadControl = PillarboxLoadControl(),
4945
): PillarboxPlayer {
5046
return DefaultPillarbox(
5147
context = context,
5248
seekIncrement = seekIncrement,
5349
mediaItemTrackerRepository = mediaItemTrackerRepository,
54-
mediaItemSource = mediaItemSource,
55-
dataSourceFactory = dataSourceFactory,
50+
mediaCompositionService = mediaCompositionService,
5651
loadControl = loadControl,
5752
clock = Clock.DEFAULT,
5853
)
@@ -64,9 +59,8 @@ object DefaultPillarbox {
6459
* @param context The context.
6560
* @param seekIncrement The seek increment.
6661
* @param mediaItemTrackerRepository The provider of MediaItemTracker, by default [DefaultMediaItemTrackerRepository].
67-
* @param mediaItemSource The MediaItem source by default [MediaCompositionMediaItemSource].
68-
* @param dataSourceFactory The Http exoplayer data source factory, by default [AkamaiTokenDataSource.Factory].
6962
* @param loadControl The load control, by default [DefaultLoadControl].
63+
* @param mediaCompositionService The [MediaCompositionService] to use, by default [HttpMediaCompositionService].
7064
* @param clock The internal clock used by the player.
7165
* @return [PillarboxPlayer] suited for SRG.
7266
*/
@@ -75,18 +69,16 @@ object DefaultPillarbox {
7569
context: Context,
7670
seekIncrement: SeekIncrement = defaultSeekIncrement,
7771
mediaItemTrackerRepository: MediaItemTrackerProvider = DefaultMediaItemTrackerRepository(),
78-
mediaItemSource: MediaItemSource = MediaCompositionMediaItemSource(
79-
mediaCompositionDataSource = DefaultMediaCompositionDataSource(),
80-
),
81-
dataSourceFactory: DataSource.Factory = AkamaiTokenDataSource.Factory(),
82-
loadControl: LoadControl = PillarboxLoadControl(),
72+
loadControl: LoadControl = DefaultLoadControl(),
73+
mediaCompositionService: MediaCompositionService = HttpMediaCompositionService(),
8374
clock: Clock,
8475
): PillarboxPlayer {
8576
return PillarboxPlayer(
8677
context = context,
8778
seekIncrement = seekIncrement,
88-
dataSourceFactory = dataSourceFactory,
89-
mediaItemSource = mediaItemSource,
79+
mediaSourceFactory = PillarboxMediaSourceFactory(context).apply {
80+
addAssetLoader(SRGAssetLoader(context, mediaCompositionService))
81+
},
9082
mediaItemTrackerProvider = mediaItemTrackerRepository,
9183
loadControl = loadControl,
9284
clock = clock,

0 commit comments

Comments
 (0)