> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kontext.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Media3 player

> Hand a Media3 player (ExoPlayer, MediaController) to the SDK with so.kontext:video-media3.

The SDK follows your content player: where the viewer is in the episode, and whether the content plays. An overlay shows over playing content only and ends when the viewer pauses; a pause ad ends when the content plays again. With a [Media3](https://developer.android.com/media/media3) player, one call gives the SDK all of that.

## Add the adapter

```kotlin theme={null}
dependencies {
    implementation("so.kontext:video:0.1.0")
    implementation("so.kontext:video-media3:0.1.0")
}
```

It works with Media3 1.1 or later and uses your app's own Media3 version: adding it never changes the Media3 your app resolves.

## Track the player

```kotlin theme={null}
import so.kontext.video.media3.track

player.setMediaItem(episode.mediaItem)
player.prepare()
ads.track(player)          // after setMediaItem: the episode is now in the player
player.play()
```

* **Any Media3 `Player`:** an `ExoPlayer`, a `MediaController`, or your own `Player`.
* **The main looper:** the SDK reads the player on the main thread. A player built on another looper is not followed (an error in the log), and the content counts as not playing.
* **Held weakly:** the SDK never keeps your player alive. It lets go at `ads.destroy()` or the next `track`.

## One player across episodes

Most apps reuse one player and swap its media item. Track it from each episode's `VideoAds` once that episode is in the player:

```kotlin theme={null}
fun open(episode: Episode) {
    ads?.destroy()                                     // after a post-roll's onAdEnded, if one is on screen
    ads = VideoAds(episode.content)
    player.setMediaItem(episode.mediaItem)
    player.prepare()
    ads!!.track(player)
}
```

Tracked before `setMediaItem`, the new episode's overlay and pause ads throw `Invalidated(ContentChanged)` at `show`: the SDK took the previous item for this episode's. Track again after `setMediaItem` and they show.

## What the SDK reads

| The SDK needs | Read from Media3 |
| - | - |
| Where the content is | `contentPosition`: the content's position, also while the player plays an ad of its own |
| Whether it plays | `playWhenReady`, and ready or buffering, and no suppression (such as lost audio focus), and not in an ad of the player's own. Buffering counts as playing: the content is about to move on. |
| The speed | `playbackParameters.speed` |
| A seek | a position discontinuity caused by a seek |
| Another episode | a media item transition, including a repeat of the same item |

The adapter listens to the player's own callbacks, so an overlay ends the moment the viewer pauses.

## Ads inserted by the player

If your player also plays ads itself (an ads loader, server-inserted ads), the time in those ads is not content: an overlay is not shown over them, and the position the SDK reads stays the content's.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.