Skip to content

moonggae/KMedia

Repository files navigation

KMedia - KMP Music Player Library

Maven Central

Audio player library built with Kotlin Multiplatform (KMP). It provides a consistent API for music playback functionality across both Android and iOS.

Android Sample

iOS Sample

Key Features

  • Supports Kotlin Multiplatform (Android, iOS)
  • Consistent music playback experience with a unified API
  • Media caching support
  • Playlist management (add, remove, reorder)
  • Shuffle and repeat mode support
  • Playback state and position monitoring
  • Background playback support
  • Control Center (iOS) and Media Notification (Android) integration

Setup

Gradle Setup

For Kotlin Multiplatform, add the dependency below to your module's build.gradle.kts file:

sourceSets {
    commonMain.dependencies {
        implementation("io.github.moonggae:kmedia:$kmedia_version")
    }
}

Android Setup

Add the following permissions and service to your AndroidManifest.xml:

<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />

<!-- Service registration -->
<service android:name="io.github.moonggae.kmedia.session.PlaybackService"
    android:exported="false"
    android:foregroundServiceType="mediaPlayback">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService" />
    </intent-filter>
</service>

iOS Setup

Add the following to your Info.plist:

<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
    <string>io.github.moonggae.kmedia.assetDownloadSession</string>
</array>
<key>UIBackgroundModes</key>
<array>
    <string>audio</string>
    <string>processing</string>
</array>

Usage

Basic Usage

KMedia can be initialized in Composable using PlatformContext

@Composable
fun KMediaSample() {
    val platformContext = LocalPlatformContext.current
    val media = remember {
        KMedia.builder()
            .cache(enabled = true, sizeInMb = 1024)
            .build(platformContext)
    }
}

KMedia can be used as follows:

// Create a KMedia instance
val media = KMedia.Builder()
    .cache(enabled = true, sizeInMb = 1024)
    .build(context)

// Get music list
val musics = SampleMusicRepository().getSampleMusicList()

// Start playback
media.player.playMusics(musics, startIndex = 0)

// Play/Pause
media.player.play()
media.player.pause()

// Previous/Next track
media.player.previous()
media.player.next()

// Seek to position
media.player.seekTo(positionMs = 30000)

Monitoring Playback State

You can monitor the playback state through Flow:

val playbackState by media.playbackState.collectAsState()

// Check current playback status
when (playbackState.playingStatus) {
    PlayingStatus.PLAYING -> // Playing
    PlayingStatus.PAUSED -> // Paused
    PlayingStatus.BUFFERING -> // Buffering
    PlayingStatus.IDLE -> // Not ready
    PlayingStatus.ENDED -> // Playback completed
}

// Current position and duration
val position = playbackState.position
val duration = playbackState.duration

Repeat and Shuffle Modes

// Set repeat mode
media.player.setRepeatMode(RepeatMode.REPEAT_MODE_ONE) // Repeat one
media.player.setRepeatMode(RepeatMode.REPEAT_MODE_ALL) // Repeat all
media.player.setRepeatMode(RepeatMode.REPEAT_MODE_OFF) // No repeat

// Set shuffle mode
media.player.setShuffleMode(true) // Enable shuffle
media.player.setShuffleMode(false) // Disable shuffle

Cache Management

// Check cache usage
val cacheUsage by media.cache.usedSizeBytes.collectAsState(initial = 0L)

// Cache specific music
media.cache.preCacheMusic(url = "https://example.com/music.mp3", key = "music1")

// Check cache status
val isCached = media.cache.checkMusicCached("music1")

// Remove cache
media.cache.removeCachedMusic("music1")

// Clear all cache
media.cache.clearCache()

Additional Features

CacheStatusListener

An interface for monitoring cache status changes. You can implement this to track caching progress.

interface CacheStatusListener {
    fun onCacheStatusChanged(musicId: String, status: CacheStatus)

    enum class CacheStatus {
        NONE,               // Not cached
        PARTIALLY_CACHED,   // Partially cached
        FULLY_CACHED        // Fully cached
    }
}

Usage example:

val cacheStatusListener = object : CacheStatusListener {
    override fun onCacheStatusChanged(musicId: String, status: CacheStatus) {
        when (status) {
            CacheStatus.NONE -> println("$musicId: No cache")
            CacheStatus.PARTIALLY_CACHED -> println("$musicId: Caching in progress")
            CacheStatus.FULLY_CACHED -> println("$musicId: Caching completed")
        }
    }
}

// Register listener when initializing KMedia
val media = KMedia.Builder()
    .cache(enabled = true, sizeInMb = 1024, listener = cacheStatusListener)
    .build(context)

PlaybackAnalyticsListener

An interface for collecting playback analytics. You can track user playback patterns and statistics.

interface PlaybackAnalyticsListener {
    fun onPlaybackCompleted(
        musicId: String,
        totalPlayTimeMs: Long,
        duration: Long
    )
}

Usage example:

val analyticsListener = object : PlaybackAnalyticsListener {
    override fun onPlaybackCompleted(musicId: String, totalPlayTimeMs: Long, duration: Long) {
        // Process playback statistics
        val playPercentage = (totalPlayTimeMs.toFloat() / duration.toFloat()) * 100
        println("$musicId playback completed: $playPercentage% played ($totalPlayTimeMs ms / $duration ms)")
        
        // You can send analytics data to server here
    }
}

// Register listener when initializing KMedia
val media = KMedia.Builder()
    .analytics(analyticsListener)
    .build(context)

About

KMedia is a Kotlin Multiplatform(KMP) audio player library

Resources

License

Stars

Watchers

Forks

Packages

No packages published