From e6c3a8ff1d720dd97a513fa97aabbfd327ac8f15 Mon Sep 17 00:00:00 2001 From: cizra Date: Mon, 18 May 2026 08:06:47 +0000 Subject: [PATCH] Add MIDI playback (#6770) * Add MIDI playback * Implement PR suggestions --- gradle/libs.versions.toml | 1 + libraries/mediaviewer/impl/build.gradle.kts | 1 + .../impl/local/audio/MediaAudioView.kt | 2 +- .../impl/local/player/ExoPlayerFactory.kt | 15 +++++++++++++-- .../impl/local/video/MediaVideoView.kt | 2 +- settings.gradle.kts | 2 ++ 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 442d56c349..831cff5052 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -111,6 +111,7 @@ androidx_media3_ui = { module = "androidx.media3:media3-ui", version.ref = "medi androidx_media3_transformer = { module = "androidx.media3:media3-transformer", version.ref = "media3" } androidx_media3_effect = { module = "androidx.media3:media3-effect", version.ref = "media3" } androidx_media3_common = { module = "androidx.media3:media3-common", version.ref = "media3" } +androidx_media3_exoplayer_midi = { module = "androidx.media3:media3-exoplayer-midi", version.ref = "media3" } androidx_biometric = "androidx.biometric:biometric-ktx:1.4.0-alpha02" androidx_activity_activity = { module = "androidx.activity:activity", version.ref = "activity" } diff --git a/libraries/mediaviewer/impl/build.gradle.kts b/libraries/mediaviewer/impl/build.gradle.kts index cd1579d50d..f2dbf1aacf 100644 --- a/libraries/mediaviewer/impl/build.gradle.kts +++ b/libraries/mediaviewer/impl/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { implementation(libs.coroutines.core) implementation(libs.coil.compose) implementation(libs.androidx.media3.exoplayer) + implementation(libs.androidx.media3.exoplayer.midi) implementation(libs.androidx.media3.ui) implementation(libs.telephoto.zoomableimage) implementation(libs.vanniktech.blurhash) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/audio/MediaAudioView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/audio/MediaAudioView.kt index cb9d6ae9c8..3ac578196d 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/audio/MediaAudioView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/audio/MediaAudioView.kt @@ -88,7 +88,7 @@ fun MediaAudioView( modifier: Modifier = Modifier, isDisplayed: Boolean = true, ) { - val exoPlayer = rememberExoPlayer() + val exoPlayer = rememberExoPlayer(forAudioOnly = true) ExoPlayerMediaAudioView( isDisplayed = isDisplayed, localMediaViewState = localMediaViewState, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/ExoPlayerFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/ExoPlayerFactory.kt index d0043c657a..ccd628dbc5 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/ExoPlayerFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/ExoPlayerFactory.kt @@ -8,14 +8,18 @@ package io.element.android.libraries.mediaviewer.impl.local.player +import androidx.annotation.OptIn import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalInspectionMode +import androidx.media3.common.util.UnstableApi +import androidx.media3.exoplayer.DefaultRenderersFactory import androidx.media3.exoplayer.ExoPlayer +@OptIn(UnstableApi::class) @Composable -fun rememberExoPlayer(): ExoPlayer { +fun rememberExoPlayer(forAudioOnly: Boolean): ExoPlayer { return if (LocalInspectionMode.current) { remember { ExoPlayerForPreview() @@ -23,7 +27,14 @@ fun rememberExoPlayer(): ExoPlayer { } else { val context = LocalContext.current remember { - ExoPlayer.Builder(context).build() + if (forAudioOnly) { + // Required for media3-exoplayer-midi to decode MIDI samples produced by DefaultExtractorsFactory. + val renderersFactory = DefaultRenderersFactory(context) + .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON) + ExoPlayer.Builder(context, renderersFactory).build() + } else { + ExoPlayer.Builder(context).build() + } } } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt index 082dc0571c..9d5e290857 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt @@ -73,7 +73,7 @@ fun MediaVideoView( audioFocus: AudioFocus?, modifier: Modifier = Modifier, ) { - val exoPlayer = rememberExoPlayer() + val exoPlayer = rememberExoPlayer(forAudioOnly = false) ExoPlayerMediaVideoView( isDisplayed = isDisplayed, localMediaViewState = localMediaViewState, diff --git a/settings.gradle.kts b/settings.gradle.kts index 8c7b608465..db03a32f18 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,6 +21,8 @@ dependencyResolutionManagement { url = uri("https://www.jitpack.io") content { includeModule("com.github.matrix-org", "matrix-analytics-events") + // Required transitively by androidx.media3:media3-exoplayer-midi for MIDI playback. + includeModule("com.github.philburk", "jsyn") } } google()