
Cross-platform media player library enables running sample apps on Android and iOS, and supports publishing to MavenLocal and MavenCentral with detailed setup instructions.
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.
KMPPlayerState)StateFlow-based event stream (KMPPlayerEvent)KMPPlayer)destroy()
Published to Maven Central:
repositories {
mavenCentral()
}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:+")
}val playerState = rememberKMPPlayerState()
KMPPlayer(
state = playerState,
showControls = true,
modifier = Modifier
.fillMaxSize()
.background(Color.Black)
)
LaunchedEffect(Unit) {
// Load media
playerState.setFileUrl("https://www.sample-videos.com/video321/mp4/360/big_buck_bunny_360p_20mb.mp4")
// Configure playback
playerState.setVolume(0.8f) // 80% volume
playerState.setPlaybackSpeed(1.25f) // 1.25x speed
playerState.setVideoLoop(true) // enable looping
// Start playback
playerState.play()
// Observe playback events
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}")
}
}
}@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)
}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
}setVideoLoop(true) for infinite loopingsetVolume(0.0f–1.0f) to control playback volumesetPlaybackSpeed(speed) to adjust playback rategetCurrentPosition() + getDuration() for progress trackingseekTo(ms) to scrub or skipdestroy() to release player resources when not in usegetPlatformPlayer() and cast to native typesMIT License
© 2025 Rufen Khokhar
Pull requests and feature ideas are welcome!
Open an issue to start the discussion.
Rufen Khokhar
📧 rufankhokhar@gmail.com
🔗 github.com/rufenkhokhar
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.
KMPPlayerState)StateFlow-based event stream (KMPPlayerEvent)KMPPlayer)destroy()
Published to Maven Central:
repositories {
mavenCentral()
}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:+")
}val playerState = rememberKMPPlayerState()
KMPPlayer(
state = playerState,
showControls = true,
modifier = Modifier
.fillMaxSize()
.background(Color.Black)
)
LaunchedEffect(Unit) {
// Load media
playerState.setFileUrl("https://www.sample-videos.com/video321/mp4/360/big_buck_bunny_360p_20mb.mp4")
// Configure playback
playerState.setVolume(0.8f) // 80% volume
playerState.setPlaybackSpeed(1.25f) // 1.25x speed
playerState.setVideoLoop(true) // enable looping
// Start playback
playerState.play()
// Observe playback events
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}")
}
}
}@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)
}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
}setVideoLoop(true) for infinite loopingsetVolume(0.0f–1.0f) to control playback volumesetPlaybackSpeed(speed) to adjust playback rategetCurrentPosition() + getDuration() for progress trackingseekTo(ms) to scrub or skipdestroy() to release player resources when not in usegetPlatformPlayer() and cast to native typesMIT License
© 2025 Rufen Khokhar
Pull requests and feature ideas are welcome!
Open an issue to start the discussion.
Rufen Khokhar
📧 rufankhokhar@gmail.com
🔗 github.com/rufenkhokhar