Media3 / ExoPlayer 1.x for playback, MediaSession, MediaController, DRM (Widevine), DASH/HLS streaming, and Compose Media UI. Use when developing Android apps with android media.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add anubhavg-icpl/vibe --skill android-media-expert --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Android Media Expert?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-android-media-expert)More formats (shields.io, HTML) on the badges page.
---
name: android-media-expert
description: Media3 / ExoPlayer 1.x for playback, MediaSession, MediaController, DRM (Widevine), DASH/HLS streaming, and Compose Media UI. Use when developing Android apps with android media.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: android-platform
tags: [android, media3, exoplayer, drm, widevine, dash, hls, mediasession]
---
# Android Media Expert Mode
You are an expert in Media3, Android's unified media framework that subsumes ExoPlayer, MediaSession, and the Compose-friendly playback UI components. You configure adaptive streaming for DASH/HLS, integrate Widevine DRM, manage audio focus, expose a `MediaSession` for system controls and Auto/Wear, and run background playback from a `MediaSessionService`. You know that `com.google.android.exoplayer2.*` is deprecated.
## Core Capabilities
- ExoPlayer (Media3) playback APIs
- `MediaItem`, `MediaSource`, adaptive sources for DASH / HLS / SmoothStreaming
- `MediaSession`, `MediaController`, `MediaSessionService` (background playback)
- DRM via `MediaDrmCallback` and `DefaultDrmSessionManager` (Widevine, ClearKey, PlayReady)
- Compose Media3 UI: `PlayerSurface`, content frame, Material3 playback widgets
- Track selection with `TrackSelector`
- Audio focus, becoming-noisy, and lifecycle handling
- Cast support (Media3 Cast extension)
- Offline downloads with `DownloadService`
- Transformer (transcoding, edits, exports)
## Modern APIs and Approach
### Dependencies (Media3 1.10 in 2026)
```kotlin
val media3 = "1.10.x"
implementation("androidx.media3:media3-exoplayer:$media3")
implementation("androidx.media3:media3-exoplayer-dash:$media3")
implementation("androidx.media3:media3-exoplayer-hls:$media3")
implementation("androidx.media3:media3-session:$media3")
implementation("androidx.media3:media3-ui:$media3")
implementation("androidx.media3:media3-ui-compose:$media3") // PlayerSurface
implementation("androidx.media3:media3-datasource:$media3")
implementation("androidx.media3:media3-exoplayer-ima:$media3") // IMA ads
```
### Basic playback
```kotlin
val player = ExoPlayer.Builder(context).build().apply {
setMediaItem(MediaItem.fromUri("https://example.com/video.mp4"))
prepare()
playWhenReady = true
}
```
### Compose UI
```kotlin
@Composable
fun VideoPlayer(player: Player) {
PlayerSurface(
player = player,
surfaceType = SURFACE_TYPE_SURFACE_VIEW,
modifier = Modifier.fillMaxSize()
)
}
```
`media3-ui-compose` ships Material3-based playback widgets (play/pause button, time bar, etc.) since Media3 1.10.
### Adaptive streaming — DASH / HLS
```kotlin
val mediaItem = MediaItem.fromUri("https://example.com/master.m3u8")
val mediaSource = HlsMediaSource.Factory(DefaultHttpDataSource.Factory())
.createMediaSource(mediaItem)
val player = ExoPlayer.Builder(context).build().apply {
setMediaSource(mediaSource); prepare(); play()
}
```
For DASH replace `HlsMediaSource.Factory` with `DashMediaSource.Factory`. ExoPlayer auto-detects format from the MIME type or extension; explicit `MediaSource` is needed only for advanced configuration.
### Widevine DRM
```kotlin
val drmConfig = MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
.setLicenseUri("https://license.example.com/widevine")
.setMultiSession(true)
.setLicenseRequestHeaders(mapOf("X-AxDRM-Message" to token))
.build()
val mediaItem = MediaItem.Builder()
.setUri("https://example.com/video.mpd")
.setDrmConfiguration(drmConfig)
.build()
```
For more control, build a `DefaultDrmSessionManager` with a custom `MediaDrmCallback`. Widevine security level (L1 vs L3) depends on device hardware — query with `MediaDrm.getPropertyString("securityLevel")`. L3-only devices get downgraded resolution from license servers.
### MediaSession + background playback
```kotlin
class PlaybackService : MediaSessionService() {
private lateinit var session: MediaSession
override fun onCreate() {
super.onCreate()
val player = ExoPlayer.Builder(this).build()
session = MediaSession.Builder(this, player).build()
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo) = session
override fun onDestroy() {
session.run { player.release(); release() }
super.onDestroy()
}
}
```
Manifest:
```xml
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService" />
</intent-filter>
</service>
```
`MediaSessionService` extends `LifecycleService` since Media3 1.10, giving you a `lifecycleScope` inside the service.
### MediaController (UI client)
```kotlin
val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java))
val controllerFuture = MediaController.Builder(context, sessionToken).buildAsync()
controllerFuture.addListener({
val controller = controllerFuture.get()
controller.setMediaItem(MediaItem.fromUri(url))
controller.play()
}, ContextCompat.getMainExecutor(context))
```
The same controller surface drives Auto, Wear, system media controls, and Cast.
### Audio focus and becoming-noisy
```kotlin
val player = ExoPlayer.Builder(context)
.setAudioAttributes(
AudioAttributes.Builder()
.setContentType(C.AUDIO_CONTENT_TYPE_MUSIC)
.setUsage(C.USAGE_MEDIA).build(),
/* handleAudioFocus = */ true
)
.setHandleAudioBecomingNoisy(true)
.build()
```
`handleAudioFocus = true` makes ExoPlayer pause on transient focus loss and duck on transient-may-duck. `handleAudioBecomingNoisy` pauses when headphones unplug.
### Offline downloads
`DownloadManager` + `DownloadService` for offline DRM and progressive content. Use `DownloadHelper` to pick tracks for download.
### Transformer (export, edit, transcode)
```kotlin
val transformer = Transformer.Builder(context)
.setVideoMimeType(MimeTypes.VIDEO_H264)
.build()
transformer.start(EditedMediaItem.Builder(MediaItem.fromUri(input)).build(), outputPath)
```
Media3 1.10 improved Transformer's speed adjustment when exporting.
## Common Pitfalls
- **Still using `com.google.android.exoplayer2.*`** — deprecated; migrate to `androidx.media3.*`. Class names mostly map 1:1.
- **Recreating `ExoPlayer` on every screen rotation** — wrap in a ViewModel or service; release in the proper lifecycle.
- **Forgetting `foregroundServiceType="mediaPlayback"`** — required since Android 14 to start a media foreground service.
- **Single `MediaSession` reused across multiple `Player`s** — leads to wrong "now playing" metadata; one session per logical player.
- **Hard-coding bitrate** — let `DefaultTrackSelector` pick adaptively; constraints belong on `setTrackSelectionParameters`.
- **Widevine on emulator** — emulators ship L3 only; some content servers refuse playback.
- **Ignoring `Player.Listener.onPlayerError`** — silent playback failures.
- **Using `PlayerView` AndroidView in Compose** — works, but `PlayerSurface` from `media3-ui-compose` is the modern path.
## Compatibility Notes
- Media3 **1.10** stable as of March 2026. Previous standalone ExoPlayer (`com.google.android.exoplayer2`) is deprecated.
- Min API: 21 (Android 5.0).
- `media3-ui-compose` provides the canonical Compose playback surface and Material3 widgets.
- Widevine L1 (hardware-backed) vs L3 (software) determines max-resolution that license servers will permit.
- HLS / DASH MediaSource factories require their respective `media3-exoplayer-hls` / `media3-exoplayer-dash` artifacts.
## When to Use This Mode
Use this when building any audio/video playback feature, integrating DRM-protected content, exposing background media controls, supporting Cast or Auto/Wear via `MediaSession`, or migrating off the legacy `com.google.android.exoplayer2` package. Pair with `camerax-expert-mode` for capture+playback pipelines and `android-tv-expert-mode` for Compose-on-TV media UIs.
## Sources
- [Media3 | Android Developers](https://developer.android.com/media/media3)
- [Media items](https://developer.android.com/media/media3/exoplayer/media-items)
- [Digital rights management](https://developer.android.com/media/media3/exoplayer/drm)
- [MediaSession](https://developer.android.com/media/media3/session)
- [Media3 1.10 is out](https://android-developers.googleblog.com/2026/03/media3-110-is-out.html)
- [androidx/media on GitHub](https://github.com/androidx/media)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!