> ## 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 播放器

> 通过 so.kontext:video-media3 把 Media3 播放器（ExoPlayer、MediaController）交给 SDK。

SDK 会跟随你的内容播放器：观众在剧集中的位置，以及内容是否在播放。叠加广告只在内容播放时展示，观众暂停时结束；暂停广告在内容再次播放时结束。使用 [Media3](https://developer.android.com/media/media3) 播放器时，一次调用就能把这些都交给 SDK。

## 添加适配器

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

它支持 Media3 1.1 或更高版本，并使用你应用自己的 Media3 版本：添加它不会改变你的应用解析到的 Media3。

## 跟随播放器

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

player.setMediaItem(episode.mediaItem)
player.prepare()
ads.track(player)          // 在 setMediaItem 之后：此时剧集已在播放器中
player.play()
```

* **任何 Media3 `Player`：** `ExoPlayer`、`MediaController`，或你自己的 `Player`。
* **主 looper：** SDK 在主线程读取播放器。在其他 looper 上创建的播放器不会被跟随（日志中有错误），内容视为未在播放。
* **弱持有：** SDK 绝不会让你的播放器保持存活。它在 `ads.destroy()` 或下一次 `track` 时放开。

## 多集共用一个播放器

大多数应用复用一个播放器并替换它的媒体项。每一集进入播放器后，用该集的 `VideoAds` 跟随它：

```kotlin theme={null}
fun open(episode: Episode) {
    ads?.destroy()                                     // 如果片尾广告在屏幕上，在它的 onAdEnded 之后
    ads = VideoAds(episode.content)
    player.setMediaItem(episode.mediaItem)
    player.prepare()
    ads!!.track(player)
}
```

如果在 `setMediaItem` 之前跟随，新剧集的叠加广告和暂停广告会在 `show` 时抛出 `Invalidated(ContentChanged)`：SDK 把上一个媒体项当成了这一集的。在 `setMediaItem` 之后再次跟随即可正常展示。

## SDK 读取什么

| SDK 需要 | 从 Media3 读取 |
| - | - |
| 内容的位置 | `contentPosition`：内容的位置，播放器播放它自己的广告时也是如此 |
| 是否在播放 | `playWhenReady`，并且处于就绪或缓冲，没有被抑制（例如失去音频焦点），也不在播放器自己的广告中。缓冲算作播放：内容即将继续。 |
| 速度 | `playbackParameters.speed` |
| 拖动进度 | 由拖动引起的位置跳变 |
| 另一集 | 媒体项切换，包括同一媒体项的重复播放 |

适配器监听播放器自己的回调，因此观众一暂停叠加广告就会结束。

## 播放器插入的广告

如果你的播放器自己也播放广告（广告加载器、服务端插入的广告），这些广告中的时间不是内容：叠加广告不会展示在它们之上，SDK 读取的位置仍是内容的位置。


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