Compose Multiplatform Media Player

January 21, 2026 Β· View on GitHub

Maven Central Kotlin Compose Multiplatform License

badge-android badge-ios badge-desktop badge-wasmJs

Compose Multiplatform Media Player is a powerful media player library designed for Compose Multiplatform projects. It enables seamless video player, reels viewing, audio playing, YouTube video integration, video preview thumbnails and HLS m3u8 support on iOS, Android, wasmJs and Desktop platforms. The library offers extensive customization options for various controls, making it flexible for different types of media applications.

Blog-banner-02 5

πŸŽ‰ What's New in Version 1.0.53

Customization Option Added

  • showControlsOverride: Overrides the internal control visibility state.

✨ Features

Cross-Platform Compatibility: Works seamlessly on iOS, Android, wasmJs and Desktop platforms within Compose Multiplatform projects.

Video Player: Effortlessly play videos in your app with high performance and reliability.

HLS m3u8 Playback: Seamlessly stream live and on-demand content with HLS (.m3u8), featuring quality, caption, and audio track selection for a customizable viewing experience.

YouTube Player: Integrate YouTube videos directly into your app, with full control over playback and video state management.

Reel Viewing: Enjoy reel viewing with support for horizontal and vertical scrolling.

Audio Player: Enjoy high-quality audio playback with customizable controls.

Video Preview: Display animated video previews for a more engaging experience.

Customizable Controls: Enable/disable pause/resume functionality and adjust the appearance and visibility of the seek bar, along with various control icons and colors.

Resume Video Playback: Automatically resume video playback from the last position.

Picture-in-Picture: Seamless PiP support on mobile, allowing video playback to continue in a floating window while users multitask.

media-player-animation-updated2

media-player-animation-updated2

πŸ“¦ Installation

Add the following dependency to your build.gradle.kts file:

commonMain.dependencies {
    implementation("network.chaintech:compose-multiplatform-media-player:1.0.53")
}

πŸ’‘ Note: For desktop video player, ensure VLC Player is installed, and for desktop YouTube support, Java must be installed on your system.

🌐 Setup for wasmJs (WebAssembly)

⚠️ Experimental Notice

The WebAssembly (wasmJs) target in JetBrains Compose Multiplatform is still in experimental status. While this library provides preliminary support using Shaka Player for media playback, stability, performance, and feature parity may vary between browsers.

Use this feature for testing, prototyping, or early adoption β€” not production-critical scenarios yet.

To enable wasmJs support with Shaka Player, you need to include the supporting files shipped with this library.

All required files are available here:

Add Scripts in index.html

Make sure to add these scripts before your Compose WASM app (composeApp.js).

⚠️ The order matters: Shaka β†’ Global β†’ Helpers β†’ Compose app.

<!-- Shaka Player -->
<script src="shaka-player.compiled.js"></script>
<script src="shaka-global.js"></script>

<!-- WASM Helpers -->
<script src="shaka-wasm-helpers.js"></script>

<!-- Your Compose WASM app -->
<script src="composeApp.js"></script>

πŸ“¦ Setup for Picture-in-Picture (PiP)

πŸ€– Android

Before using PiP mode in your media player, you need to enable it in your app’s AndroidManifest.xml.

Add the following flags inside your (usually MainActivity):

<activity
    android:name=".MainActivity"
    android:supportsPictureInPicture="true"
    android:resizeableActivity="true"
    android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboardHidden"/>

πŸ“± iOS

In Xcode, enable Background Modes capability.

Check βœ… Audio, AirPlay, and Picture in Picture.

πŸ“¦ Setup for Resuming Video Playback in Android

If you want to enable the feature to resume video playback from the last saved position, you need to initialize PlaybackPreference in your Android app. Add the following setup in your AppActivity:

class AppActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        PlaybackPreference.initialize(this)
    }
}

This ensures that playback positions are properly saved and retrieved when needed. Without this initialization, the resume feature will not work on Android. πŸš€

πŸ“‹ Setup Guide for Fullscreen Support in Desktop

To enable fullscreen and window placement control from the library, you need to provide your app's WindowState using CompositionLocalProvider.

For example:

fun main() = application {
    val windowState = rememberWindowState(width = 900.dp, height = 700.dp)
    CompositionLocalProvider(LocalWindowState provides windowState) {
        Window(
            title = "MediaPlayer",
            state = windowState,
            onCloseRequest = ::exitApplication,
        ) {
            MainView()
        }
    }
}

🎬 Usage

MediaPlayerHost Class

Constructor Parameters

  • mediaUrl (String): The URL of the media to be played.
  • autoPlay (Boolean): Sets the initial playback state. Defaults to true (play on load).
  • isMuted (Boolean): Indicates whether the video is muted initially. Defaults to false.
  • initialSpeed (PlayerSpeed): Sets the initial playback speed. Defaults to PlayerSpeed.X1.
  • initialVideoFitMode (ScreenResize): Specifies the video resizing mode. Defaults to ScreenResize.FILL.
  • isLooping (Boolean): Enables or disables looping. Defaults to true.
  • startTimeInSeconds (Float?): Optionally specifies the start time (in seconds) for the video. Defaults to null.
  • isFullScreen (Boolean): Enables or disables full screen. Defaults to false.
  • headers (Map<String, String>?): Optional HTTP headers to be sent with the media request. Defaults to null.
  • drmConfig (DrmConfig?): Optional DRM configuration for protected content. Defaults to null. Supports ClearKey Encryption DRM for playing encrypted media.

Available Controls

  • loadUrl(mediaUrl: String, headers: Map<String, String>? = null, drmConfig: DrmConfig? = null): Updates the media URL to load a new media. Optionally, you can pass HTTP headers and DRM configuration
  • play(): Resumes media playback.
  • pause(): Pauses media playback.
  • togglePlayPause(): Toggles between play and pause states.
  • mute(): Mutes the video.
  • unmute(): Unmutes the video.
  • toggleMuteUnmute(): Toggles between muted and unmuted states.
  • setSpeed(speed: PlayerSpeed): Adjusts the playback speed.
  • seekTo(seconds: Float?): Seeks to a specific time in the media.
  • setVideoFitMode(mode: ScreenResize): Updates the video resizing mode.
  • setLooping(isLooping: Boolean): Enables or disables looping.
  • toggleLoop(): Toggles loop state.
  • setVolume(level: Float): Adjusts the volume. Value must be between 0.0 and 1.0.
  • setFullScreen(isFullScreen: Boolean): Enables or disables full screen.
  • toggleFullScreen(): Toggles full screen enable/disable states.

Internal Updates and Events

The MediaPlayerHost class manages internal state changes and triggers events via the onEvent callback. These events allow developers to monitor and respond to changes in the media player state:

EventDescription
PauseChange(isPaused: Boolean)Triggered when the playback state changes (play or pause).
MuteChange(isMuted: Boolean)Triggered when the mute state changes (mute or unmute).
BufferChange(isBuffering: Boolean)Triggered when the buffering state changes (e.g., when buffering starts/stops).
TotalTimeChange(totalTime: Float)Triggered when the total duration of the video updates.
CurrentTimeChange(currentTime: Float)Triggered when the current playback position updates.
FullScreenChange(isFullScreen: Boolean)Triggered when the full screen state changes.
MediaEndTriggered when the media playback completes.
PIPChange(isPip: Boolean)Triggered when the PIP Mode changes.

Error Handling

The MediaPlayerHost class provides an onError callback to handle various errors that may occur during media playback.

Error TypeDescription
VlcNotFoundTriggered when the VLC library is not found, preventing playback in Desktop.
InitializationError(details: String)Occurs if the media player fails to initialize properly.
PlaybackError(details: String)Triggered when an error occurs during media playback
ResourceError(details: String)Occurs when the media resource is unavailable or cannot be loaded.

Example Usage

val videoPlayerHost = MediaPlayerHost(
    mediaUrl = "https://example.com/video.mp4",
    autoPlay = true,
    isMuted = false,
    initialSpeed = PlayerSpeed.X1,
    initialVideoFitMode = ScreenResize.FIT,
    isLooping = false,
    startTimeInSeconds = 10f,
    isFullScreen = true
)

// Play the video
videoPlayerHost.play()

// Pause the video
videoPlayerHost.pause()

// Toggle mute
videoPlayerHost.toggleMuteUnmute()

// Seek to 30 seconds
videoPlayerHost.seekTo(30f)

// Change playback speed to 1.5x
videoPlayerHost.setSpeed(PlayerSpeed.X1_5)

// Enable looping
videoPlayerHost.setLooping(true)

// Enable Full screen
videoPlayerHost.setFullScreen(true)

videoPlayerHost.onEvent = { event ->
    when (event) {
        is MediaPlayerEvent.MuteChange -> { println("Mute status changed: ${event.isMuted}") }
        is MediaPlayerEvent.PauseChange -> { println("Pause status changed: ${event.isPaused}") }
        is MediaPlayerEvent.BufferChange -> { println("Buffering status: ${event.isBuffering}") }
        is MediaPlayerEvent.CurrentTimeChange -> { println("Current playback time: ${event.currentTime}s") }
        is MediaPlayerEvent.TotalTimeChange -> { println("Video duration updated: ${event.totalTime}s") }
        is MediaPlayerEvent.FullScreenChange -> { println("FullScreen status changed: ${event.isFullScreen}") }
        MediaPlayerEvent.MediaEnd -> { println("Video playback ended") }
    }
}

videoPlayerHost.onError = { error ->
    when(error) {
        is MediaPlayerError.VlcNotFound -> { println("Error: VLC library not found. Please ensure VLC is installed.") }
        is MediaPlayerError.InitializationError -> { println("Initialization Error: ${error.details}") }
        is MediaPlayerError.PlaybackError -> { println("Playback Error: ${error.details}") }
        is MediaPlayerError.ResourceError -> { println("Resource Error: ${error.details}") }
    }
}

πŸ“Ή Video Player

To play videos in your app, use the VideoPlayerComposable:

val playerHost = remember { MediaPlayerHost(mediaUrl = url) }

VideoPlayerComposable(
    modifier = Modifier.fillMaxSize(),
    playerHost = playerHost
)

πŸ’‘ Note: The VideoPlayerComposable supports both online and local video playback. You can provide a URL for a remote video or a local file path.

πŸ“Ή Video Preview

To display video preview thumbnails, use the VideoPreviewComposable:

VideoPreviewComposable(
    url = videoUrl,
    frameCount = 5,
    contentScale = ContentScale.Crop
)

⚠️ Note:

  • VideoPreviewComposable Desktop support has been removed in this package.
  • The VideoPreviewComposable does not support local asset video in Android.

▢️ YouTube Player

⚠️ Experimental Notice

The YouTube player integration in YouTubePlayerComposable uses a custom HTML wrapper with YouTube's IFrame API.
Due to frequent backend or policy changes from YouTube, playback behavior may vary across platforms.
This feature is provided as experimental and may require adjustments or updates if YouTube changes its embedding restrictions.

We recommend testing on all target platforms before production use.

To play youtube videos in your app, use the YouTubePlayerComposable:

val playerHost = remember { MediaPlayerHost(mediaUrl = youtubeVideoId) }

YouTubePlayerComposable(
    modifier = Modifier.fillMaxSize(),
    playerHost = playerHost
)

πŸ’‘ Note: The YouTubePlayerComposable supports both YouTube video URLs and video IDs. It automatically extracts the video ID if a full URL is provided, ensuring seamless playback.

πŸŽ₯ Reel Viewing

For reel viewing, utilize the ReelsPlayerComposable:

ReelsPlayerComposable(
    modifier = Modifier.fillMaxSize(),
    urls = videoUrlArray
)

🎧 Audio Player

To play audio in your app, use AudioPlayerComposable for a built-in UI experience or AudioPlayer for a fully customizable, independent player. 🎡

val playerHost = remember { MediaPlayerHost(mediaUrl = url) }
AudioPlayerComposable(
    modifier = Modifier,
    audios = audioFilesArray,
    playerHost = playerHost,
)

//Independent player
AudioPlayer(
    playerHost = playerHost
)

πŸ’‘ Note: The AudioPlayerComposable supports both online and local audio playback. You can provide a URL for a remote audio file or a local file path.

πŸ“ Retrieve Media Duration

To retrieve the duration of a media file, use the RetrieveMediaDuration function:

RetrieveMediaDuration(
    url = videoUrl,
    onDurationRetrieved = { duration ->
        // Handle the retrieved duration (in seconds)
    }
)

This function asynchronously fetches the total duration of the media file from the provided URL and returns it via the onDurationRetrieved callback.

⚠️ Note: RetrieveMediaDuration Desktop support has been removed in this package.

βš™οΈ Customization

You can customize various aspects of the media player:

  • modifier: Modifies the layout and appearance of the video player and reel player.
  • playerHost: The VideoPlayerHost class manages internal state changes of video player.
  • urls: An array of URLs for the reel player, allowing playback of multiple reels.
  • playerConfig: You can configure various aspects of the video player appearance using the VideoPlayerConfig data class.
PropertyDescription
showControlsHide/Show video player inbuilt controls.
isPauseResumeEnabledEnable or disable the pause/resume functionality.
isSeekBarVisibleToggle the visibility of the seek bar.
isDurationVisibleControl the display of the playback time duration.
seekBarThumbColorSets the color of the seek bar thumb.
seekBarActiveTrackColorSets the color of the played portion of the track.
seekBarInactiveTrackColorSets the color of the unplayed portion of the track.
seekBarThumbRadiusAdjusts the size of the seek bar thumb.
seekBarTrackHeightAdjusts the height of the seek bar track.
durationTextColorCustomize the color of the duration text displayed alongside the seek bar.
durationTextStyleCustomize the text style of the duration text, including font size and weight.
seekBarBottomPaddingConfigure the bottom padding for the seek bar control, ensuring proper alignment within the UI layout.
seekBarBottomPaddingInFullScreenConfigure the bottom padding for the seek bar control at the time of fullscreen.
playIconResource & pauseIconResourceCustomize the play and pause button icons.
pauseResumeIconSizeCustomize the size of the pause/resume icons.
reelVerticalScrollingManage vertical and horizontal scrolling in reel viewing.
isAutoHideControlEnabled & controlHideIntervalSecondsEnable the automatic hiding of controls after a specified time interval (in seconds).
isFastForwardBackwardEnabledEnable or disable fast forward and backward controls.
fastForwardBackwardIconSizeCustomize the size of the fast forward/backward icons.
fastForwardIconResource & fastBackwardIconResourceCustomize the icons for fast forward and fast backward controls.
fastForwardBackwardIntervalSecondsSet the interval (in seconds) for fast forward and backward actions.
isMuteControlEnabledEnable or disable mute control functionality.
unMuteIconResource & muteIconResourceCustomize the icons for unmute and mute controls.
topControlSizeCustomize the size of the top control buttons.
isSpeedControlEnabledEnable or disable speed control functionality.
speedIconResourceCustomize the icon for speed control.
isFullScreenEnabledEnable or disable full-screen functionality.
controlTopPaddingConfigure the top padding for controls, ensuring proper alignment within the UI layout.
isScreenLockEnabledEnable or disable screen lock functionality.
iconsTintColorCustomize the tint color of the control icons.
isScreenResizeEnabledEnable or disable screen resize (Fit/Fill) functionality.
loadingIndicatorColorCustomize the color of the loading indicator.
loaderViewCustom loader for showing loading state.
isLiveStreamA boolean property that indicates whether the currently playing video is a live stream.
controlClickAnimationDurationDuration (in milliseconds) of the click animation applied to a button or control when the user interacts with it
backdropAlphaControls the transparency of the backdrop beneath the media controls.
autoPlayNextReelAutomatically plays the next reel when the current one ends.
enableResumePlaybackResume from last saved position.
isZoomEnabledEnables or disables zoom functionality. Defaults to true.
isGestureVolumeControlEnabledAllows to control volume level by using vertical drag gesture on right side of player
showVideoQualityOptionsLets users select from available video resolutions.
showAudioTracksOptionsLets users switch between available audio tracks.
showSubTitlesOptionsLets users choose from available subtitles.
watermarkConfigAllows adding a dynamic watermark that moves within video bounds with customizable content and timing.
chaptersShows chapter points on the SeekBar with titles.
enableFullEdgeToEdgeUses immersive full-screen mode that extends content into system and cutout areas
enableBackButtonShows a back button at the top-left corner when true
backIconResourceCustom icon for the back button (DrawableResource)
backActionCallbackCallback triggered when back button is tapped
enablePIPControlEnable a Picture-in-Picture (PiP) for the player
enableLongPressFastForwardEnables long-press gesture to temporarily increase playback speed.
longPressPlaybackSpeedThe playback speed value applied while long-press fast-forward is active.
showControlsOverrideOverrides the internal control visibility state.
  • audioPlayerConfig: You can configure various aspects of the audio player appearance and behavior using the AudioPlayerConfig data class.
PropertyDescription
showControlToggle to show or hide the AudioPlayer UI for a customizable playback experience.
isControlsVisibleToggle the visibility of the player controls.
backgroundColorCustomize the background color of the audio player.
coverBackgroundCustomize the background color of the cover image.
seekBarThumbColorSets the color of the seek bar thumb.
seekBarActiveTrackColorSets the color of the played portion of the track.
seekBarInactiveTrackColorSets the color of the unplayed portion of the track.
seekBarThumbRadiusAdjusts the size of the seek bar thumb.
seekBarTrackHeightAdjusts the height of the seek bar track.
fontColorCustomize the color of the text used in the player.
durationTextStyleCustomize the text style of the duration text, including font size and weight.
titleTextStyleCustomize the text style of the title text, including font size and weight.
controlsBottomPaddingConfigure the bottom padding for the controls, ensuring proper alignment within the UI layout.
playIconResource & pauseIconResourceCustomize the play and pause button icons.
pauseResumeIconSizeCustomize the size of the pause/resume icons.
previousNextIconSizeCustomize the size of the previous and next track icons.
previousIconResource & nextIconResourceCustomize the icons for the previous and next track controls.
iconsTintColorCustomize the tint color of the control icons.
loadingIndicatorColorCustomize the color of the loading indicator.
shuffleOnIconResource & shuffleOffIconResourceCustomize the icons for the shuffle control when enabled and disabled.
advanceControlIconSizeCustomize the size of the advance control icons (e.g., fast forward/backward).
repeatOnIconResource & repeatOffIconResourceCustomize the icons for the repeat control when enabled and disabled.
controlClickAnimationDurationDuration (in milliseconds) of the click animation applied to a button or control when the user interacts with it
val playerHost = remember { MediaPlayerHost(mediaUrl = videoUrl) }

VideoPlayerComposable(modifier = Modifier.fillMaxSize(),
                playerHost = playerHost,
                playerConfig = VideoPlayerConfig(
                    isPauseResumeEnabled = true,
                    isSeekBarVisible = true,
                    isDurationVisible = true,
                    seekBarThumbColor = Color.Red,
                    seekBarActiveTrackColor = Color.Red,
                    seekBarInactiveTrackColor = Color.White,
                    durationTextColor = Color.White,
                    seekBarBottomPadding = 10.dp,
                    pauseResumeIconSize = 40.dp,
                    isAutoHideControlEnabled = true,
                    controlHideIntervalSeconds = 5,
                    isFastForwardBackwardEnabled = true,
                    playIconResource = ComposeResourceDrawable(Res.drawable.icn_play),
                    pauseIconResource = ComposeResourceDrawable(Res.drawable.icn_pause),
                )
            )
VideoPreviewComposable(
    url = videoUrl,
    loadingIndicatorColor = Color.White,
    frameCount = 5
)
val playerHost = remember { MediaPlayerHost(mediaUrl = "QFxN2oDKk0E") }

YouTubePlayerComposable(modifier = Modifier.fillMaxSize(),
                playerHost = playerHost,
                playerConfig = VideoPlayerConfig(
                    isPauseResumeEnabled = true,
                    isSeekBarVisible = true,
                    isDurationVisible = true,
                    seekBarThumbColor = Color.Red,
                    seekBarActiveTrackColor = Color.Red,
                    seekBarInactiveTrackColor = Color.White,
                    durationTextColor = Color.White,
                    seekBarBottomPadding = 10.dp,
                    pauseResumeIconSize = 40.dp,
                    isAutoHideControlEnabled = true,
                    controlHideIntervalSeconds = 5,
                    isFastForwardBackwardEnabled = true,
                    playIconResource = ComposeResourceDrawable(Res.drawable.icn_play),
                    pauseIconResource = ComposeResourceDrawable(Res.drawable.icn_pause),
                )
            )
ReelsPlayerComposable(modifier = Modifier.fillMaxSize(),
        urls = videoUrlArray,
        playerConfig = VideoPlayerConfig(
            isPauseResumeEnabled = true,
            isSeekBarVisible = false,
            isDurationVisible = false,
            isMuteControlEnabled = false,
            isSpeedControlEnabled = false,
            isFullScreenEnabled = false,
            isScreenLockEnabled = false,
            reelVerticalScrolling = true
        ),
        currentItemIndex = { /* Current Reel Index */ }
    )
val audioFilesArray = listOf(
        AudioFile(
            audioUrl = "https://codeskulptor-demos.commondatastorage.googleapis.com/GalaxyInvaders/theme_01.mp3",
            audioTitle = "Galaxy Invaders",
            thumbnailUrl = "https://c.saavncdn.com/866/On-My-Way-English-2019-20190308195918-500x500.jpg"
        ),
        AudioFile(
            audioUrl = "https://codeskulptor-demos.commondatastorage.googleapis.com/pang/paza-moduless.mp3",
            audioTitle = "Paza Moduless"
        )
    )

val playerHost = remember { MediaPlayerHost(mediaUrl = audioFilesArray.first().audioUrl) }

AudioPlayerComposable(
        modifier = Modifier,
        audios = audioFilesArray,
        playerHost = playerHost,
        audioPlayerConfig = AudioPlayerConfig(
            isControlsVisible = true,
            fontColor = Color.White,
            iconsTintColor = Color.White
        ),
        currentItemIndex = { /* Current Audio File Index */ }
    )

πŸ“€ Format Support

FormatAndroidiOSDesktopWasmJS
MP4βœ…βœ…βœ…βœ…
MOVβœ…βœ…βœ…πŸŸ‘
3GPβœ…βœ…βœ…βœ…
AVIβœ…βŒβœ…βŒ
MKVβœ…βŒβœ…βŒ
WEBMβœ…βŒβœ…πŸŸ‘
MTSβœ…βŒβœ…βŒ
m3u8βœ…βœ…βœ…βœ…
MP3βœ…βœ…βœ…βœ…
FLACβœ…βœ…βœ…πŸŸ‘
WAVβœ…βœ…βœ…πŸŸ‘
AACβœ…βŒβœ…βœ…
AIFβŒβœ…βœ…βŒ
ALACβœ…βŒβœ…βŒ
OGGβœ…βŒβœ…πŸŸ‘
YouTubeβœ…βœ…βœ…βœ…

⚠️ Note:

  • '🟑' : Support depends entirely on the browser.

πŸ“– Detailed Explanation

For an in-depth guide and detailed explanation, check out our comprehensive Medium Blog Post.

Medium
LinkedIn

πŸ›€οΈ Roadmap

We're committed to continuously improving and expanding the capabilities of our media player library. Here's a glimpse into our future plans:

🌟 Upcoming Features

  • Video Caching for iOS & Desktop
  • Clear key encryption for iOS & Desktop
  • Control Center (iOS) and Media Notification (Android) integration

πŸ› οΈ Troubleshooting

If you encounter the following error during the build:

Could not find org.jogamp.gluegen:gluegen-rt:2.5.0

This issue occurs because the required dependency is not available in the default Maven repository. To resolve this, add Jogamp's Maven to your project's repositories:

repositories {
    maven("https://jogamp.org/deployment/maven")
}

This should resolve the missing dependencies and allow the build to proceed successfully.

πŸ“šοΈ Libraries Used in Demo

The demo project utilizes the following libraries:

SDP & SSP for Compose Multiplatform – Scalable size units for responsive UI

Connectivity Monitor – Seamless Network Monitoring for Compose Multiplatform

Voyager Navigation – Simple and scalable navigation for Compose Multiplatform

  • voyager-navigator – cafe.adriel.voyager:voyager-navigator
  • voyager-transitions – cafe.adriel.voyager:voyager-transitions
  • voyager-tab – cafe.adriel.voyager:voyager-tab-navigator

Image Loader – Efficient image loading and caching

  • image-loader – io.github.qdsfdhvh:image-loader

πŸ“š Additional Resources & Guides

Contributing & Feedback

We appreciate any feedback, bug reports, or feature suggestions to improve ComposeMultiplatformMediaPlayer

  • Report Issues: If you encounter any issues or bugs, please open an issue in the GitHub Issues section.
  • Feature Requests: Have an idea for a new feature? Let us know by creating a feature request issue.
  • General Feedback: We welcome any suggestions or feedback to enhance the library. Feel free to start a discussion or share your thoughts.
  • Contributions: If you’d like to contribute, feel free to submit a pull request. We’re happy to review and collaborate on improvements!

Your support and contributions help make ComposeMultiplatformMediaPlayer better for everyone! πŸš€

πŸ“„ License

Copyright 2023 Mobile Innovation Network

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

🌟 If you find this library useful, consider starring ⭐ the repository to show your support!