🎬 KMPPlayer — Kotlin Multiplatform Media Player

KMPPlayer is a Kotlin Multiplatform media playback library that delivers a unified, reactive interface to control media playback across Android and iOS platforms. Internally, it leverages ExoPlayer on Android and AVPlayer on iOS, while exposing a clean Kotlin API usable from shared code and Jetpack Compose.
✨ Features
- 🧩 Unified playback interface (
KMPPlayerState
)
- 📁 Supports local files & remote media URLs
- 🎮 Built-in media controls: play, pause, stop, loop, seek
- 📡 Reactive
StateFlow
-based event stream (KMPPlayerEvent
)
- 🎚 Volume & playback speed control
- 📍 Position & duration tracking
- 🎨 Jetpack Compose support (
KMPPlayer
)
- ⚙️ Access native players: ExoPlayer (Android), AVPlayer (iOS)
- 🧼 Proper resource cleanup with
destroy()
📦 Installation
1. Add Maven Repository
Published to Maven Central:
repositories {
mavenCentral()
}
2. Add the Dependency
For Kotlin Multiplatform (shared code):
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.rufenkhokhar:KMP-Player:+")
}
}
}
Or for Android-only usage:
dependencies {
implementation("io.github.rufenkhokhar:KMP-Player:+")
}
⚡ Quick Start (Jetpack Compose)
val playerState = rememberKMPPlayerState()
KMPPlayer(
state = playerState,
showControls = true,
modifier = Modifier
.fillMaxSize()
.background(Color.Black)
)
LaunchedEffect(Unit) {
playerState.setFileUrl("https://www.sample-videos.com/video321/mp4/360/big_buck_bunny_360p_20mb.mp4")
playerState.setVolume(0.8f)
playerState.setPlaybackSpeed(1.25f)
playerState.setVideoLoop(true)
playerState.play()
playerState.observePlayerEvent().collect { event ->
when (event) {
is KMPPlayerEvent.Playing -> {
println("Playing: ${event.currentPosition} / ${event.duration}")
}
KMPPlayerEvent.Paused -> println("Paused")
KMPPlayerEvent.Stop -> println("Stopped")
KMPPlayerEvent.Buffering -> println("Buffering…")
KMPPlayerEvent.Ideal -> println("Idle")
KMPPlayerEvent.Ended -> println("Playback ended")
is KMPPlayerEvent.Error -> println("Error: ${event.message}")
}
}
}
🧩 API Reference
🔧 KMPPlayerState
@ExperimentalMultiplatform
interface KMPPlayerState {
fun play()
fun stop()
fun pause()
fun isPlaying(): Boolean
fun setLocalFile(absolutePath: String)
fun setFileUrl(url: String)
fun setVideoLoop(loop: Boolean)
fun observePlayerEvent(): StateFlow<KMPPlayerEvent>
fun getPlatformPlayer(): Any?
fun destroy()
fun setVolume(volume: Float)
fun getVolume(): Float
fun setPlaybackSpeed(speed: Float)
fun getCurrentPosition(): Long
fun getDuration(): Long
fun seekTo(position: Long)
}
📡 KMPPlayerEvent
sealed interface KMPPlayerEvent {
data class Playing(
val currentPosition: Long = 0L,
val duration: Long = 0L
) : KMPPlayerEvent
data object Paused : KMPPlayerEvent
data object Stop : KMPPlayerEvent
data object Buffering : KMPPlayerEvent
data object Ideal : KMPPlayerEvent
data object Ended : KMPPlayerEvent
data class Error(val message: String) : KMPPlayerEvent
}
💡 Tips
- Use
setVideoLoop(true)
for infinite looping
- Use
setVolume(0.0f–1.0f)
to control playback volume
- Use
setPlaybackSpeed(speed)
to adjust playback rate
- Use
getCurrentPosition()
+ getDuration()
for progress tracking
- Use
seekTo(ms)
to scrub or skip
- Always call
destroy()
to release player resources when not in use
- For advanced control, use
getPlatformPlayer()
and cast to native types
📄 License
MIT License
© 2025 Rufen Khokhar
🤝 Contributing
Pull requests and feature ideas are welcome!
Open an issue to start the discussion.
👤 Maintainer
Rufen Khokhar
📧 rufankhokhar@gmail.com
🔗 github.com/rufenkhokhar