Skip to content

Latest commit

 

History

History
270 lines (205 loc) · 9.97 KB

File metadata and controls

270 lines (205 loc) · 9.97 KB

Module pillarbox-player

Provides PillarboxPlayer, an AndroidX Media3 Player implementation for media playback on Android.

Integration

To use this module, add the following dependency to your module's build.gradle/build.gradle.kts file:

implementation("ch.srgssr.pillarbox:pillarbox-player:<pillarbox_version>")

Getting started

Create the player

val player = PillarboxExoPlayer(context, Default)
// Make the player ready to play content
player.prepare()
// Will start playback when a MediaItem is ready to play
player.play() 

Playback monitoring

By default, PillarboxExoPlayer does not record any monitoring data. You can configure this behaviour when creating the player:

val player = PillarboxExoPlayer(context, Default) {
    // Disable monitoring recording (default behavior)
    disableMonitoring()

    // Output each monitoring event to Logcat
    monitoring(Logcat)

    // Send each monitoring event to a remote server
    monitoring(Remote) {
        config(endpointUrl = "https://example.com/monitoring")
    }
}

Create a MediaItem

val mediaUri = "https://example.com/media.mp4"
val mediaItem = MediaItem.fromUri(mediaUri)

player.setMediaItem(mediaItem)

More information about MediaItem creation can be found in the MediaItem documentation.

Display a Player

PillarboxPlayer can be used with the Views provided by AndroidX Media3 without any modifications.

To quickly get started, add the following to your module's build.gradle/build.gradle.kts file:

implementation("androidx.media3:media3-ui:<androidx_media3_version>")

Then link your player to a PlayerView:

@Override
fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)

    val player = PillarboxExoPlayer(context, Default)
    val playerView: PlayerView = findViewById(R.id.player_view)
    // A player can only be attached to one View!
    playerView.player = player
}

For more detailed information, you can check AndroidX Media3 UI.

Tip: for integration with Compose, you can use pillarbox-ui.

Release a Player

When the player is not needed anymore, you have to release it. This will free resources allocated by the player.

player.release()

Warning: the player can't be used anymore after that.

Custom AssetLoader

AssetLoader is used to load content that doesn't directly have a playable URL, for example, a resource id or a URI. Its responsibility is to provide a MediaSource that:

  • Is playable by the player;
  • Contains tracking data;
  • Provides optional media metadata.
class CustomAssetLoader(context: Context) : AssetLoader(DefaultMediaSourceFactory(context)) {
    override fun canLoadAsset(mediaItem: MediaItem): Boolean {
        return mediaItem.localConfigruation?.uri?.scheme == "custom"
    }

    override suspend fun loadAsset(mediaItem: MediaItem): Asset {
        val data = service.fetchData(mediaItem.localConfigruation!!.uri)
        val trackerData = MutableMediaItemTrackerData()
        trackerData[KEY] = FactoryData(CustomMediaItemTracker.Factory(), CustomTrackerData("CustomData"))

        val mediaMetadata = MediaMetadata.Builder()
            .setTitle(data.title)
            .setArtworkUri(data.imageUri)
            .setChapters(data.chapters)
            .setCredits(data.credits)
            .build()
        val mediaSource = mediaSourceFactory.createMediaSource(MediaItem.fromUri(data.url))

        return Asset(
            mediaSource = mediaSource,
            trackersData = trackerData.toMediaItemTrackerData(),
            mediaMetadata = mediaMetadata,
            blockedTimeRanges = emptyList(),
        )
    }
}

Now pass your CustomAssetLoader to your player, so it can understand and play your custom data:

val player = PillarboxExoPlayer(context, Default) {
    +CustomAssetLoader(context)
}
player.prepare()
player.setMediaItem(MediaItem.fromUri("custom://video:1234"))
player.play()

Chapters

Chapters represent the temporal segmentation of the playing media.

A Chapter can be created like that:

val chapter = Chapter(
    id = "1",
    start = 0L,
    end = 12_000L,
    mediaMetadata = MediaMetadata.Builder().setTitle("Chapter 1").build(),
)

PillarboxPlayer provides methods to observe and access chapters:

val player = PillarboxExoPlayer(context, Default)
player.addListener(object : Listener {
    override fun onChapterChanged(chapter: Chapter?) {
        if (chapter == null) {
            // Hide chapter information
        } else {
            // Display chapter information
        }
    }
})

val chapters = player.getCurrentChapters()
val currentChapter = player.getChapterAtPosition()
val chapterAtPosition = player.getChapterAtPosition(10_000L)

Chapters can be added to a MediaItem via its metadata:

val mediaMetadata = MediaMetadata.Builder()
    .setChapters(listOf(chapter))
    .build()
val mediaItem = MediaItem.Builder()
    .setMediaMetadata(mediaMetadata)
    .build()

Credits

Credits represent a point in the player timeline where opening credits or closing credits should be displayed.

A Credit can be created like that:

val openingCredits = Credit.Opening(start = 5_000L, end = 10_000L)
val closingCredits = Credit.Closing(start = 20_000L, end = 30_000L)

PillarboxPlayer provides methods to observe and access credits:

val player = PillarboxExoPlayer(context, Default)
player.addListener(object : Listener {
    override fun onCreditChanged(credit: Credit?) {
        when (credit) {
            is Credit.Opening -> Unit // Show "Skip intro" button
            is Credit.Closing -> Unit // Show "Skip credits" button
            else -> Unot // Hide button
        }
    }
})

val credits = player.getCurrentCredits()
val currentCredit = player.getCreditAtPosition()
val creditAtPosition = player.getCreditAtPosition(5_000L)

Chapters can be added to a MediaItem via its metadata:

val mediaMetadata = MediaMetadata.Builder()
    .setCredits(listOf(openingCredits, closingCredits))
    .build()
val mediaItem = MediaItem.Builder()
    .setMediaMetadata(mediaMetadata)
    .build()

Known issues

  • Playing DRM content on two instances of PillarboxPlayer is not supported on all devices.
    • Known affected devices: Samsung Galaxy A13, Huawei Nova 5i Pro, Huawei P40 Lite.
    • Related issue: androidx/media#1877.

Further reading

As PillarboxExoPlayer extends from ExoPlayer, all documentation related to ExoPlayer is also valid for Pillarbox. Here are some useful links to get more information about ExoPlayer:

You can check the following pages for a deeper understanding of Pillarbox concepts: