From 3acba87728033b44904d33b7965a7a619589bb7e Mon Sep 17 00:00:00 2001 From: Antoine Jaury Date: Sat, 5 Sep 2026 14:21:29 +0200 Subject: [PATCH] chore: add jaad dependency to fix `.m4a` playback on Desktop --- CHANGELOG.md | 7 ++++++- core/audioplayer/build.gradle.kts | 4 ++++ .../bzh/ajaury/chombev/player/data/JvmAudioPlayer.kt | 4 ++++ gradle/libs.versions.toml | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a507449..8c807a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Desktop: audio playback failed with *Failed to play audio* on every record, + because the JDK cannot decode the `.m4a` (AAC) recordings on its own. + ## [1.0.0-alpha02] - 2026-08-04 ### Added @@ -64,7 +69,7 @@ First public release of **Chom Bev e Brezhoneg**. - Targets Android, iOS, Desktop (JVM) and Web (JS + Wasm), all sharing the same Compose Multiplatform UI. Only Android has been deeply tested for this version. - Audio playback backed by ExoPlayer (Android), AVFoundation (iOS), the browser - audio APIs (Web). + audio APIs (Web) and `javax.sound.sampled` (Desktop). - Light and dark themes; interface localised in French and Breton. - Modular architecture: `core`, `data` and `feature` modules glued by a thin `shared` module, with Koin dependency injection validated at build time. diff --git a/core/audioplayer/build.gradle.kts b/core/audioplayer/build.gradle.kts index c19c823..44d0c5e 100644 --- a/core/audioplayer/build.gradle.kts +++ b/core/audioplayer/build.gradle.kts @@ -13,6 +13,10 @@ kotlin { implementation(libs.media3.exoplayer) implementation(libs.media3.common) } + jvmMain.dependencies { + // Desktop audio: AAC/MP4 SPI so javax.sound.sampled can decode .m4a + implementation(libs.jaad) + } // webMain is the js + wasmJs intermediate source set from the default hierarchy template. webMain.dependencies { // Browser audio (HTMLAudioElement, document) for js + wasmJs diff --git a/core/audioplayer/src/jvmMain/kotlin/bzh/ajaury/chombev/player/data/JvmAudioPlayer.kt b/core/audioplayer/src/jvmMain/kotlin/bzh/ajaury/chombev/player/data/JvmAudioPlayer.kt index be644c4..f1af5d4 100644 --- a/core/audioplayer/src/jvmMain/kotlin/bzh/ajaury/chombev/player/data/JvmAudioPlayer.kt +++ b/core/audioplayer/src/jvmMain/kotlin/bzh/ajaury/chombev/player/data/JvmAudioPlayer.kt @@ -17,6 +17,10 @@ import kotlin.time.Duration.Companion.microseconds /** * Desktop [AudioPlayer] backed by [javax.sound.sampled]. + * + * The JDK decodes neither AAC nor its MP4 container, so the `.m4a` recordings are decoded to PCM by + * the jaad AAC provider on the classpath, which [AudioSystem] discovers automatically. Loading then + * works the same as for any natively supported format. */ internal class JvmAudioPlayer : AudioPlayer { private var clip: Clip? = null diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b624049..f70ac34 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,6 +10,7 @@ composeIconsExtended = "1.7.3" composeMultiplatform = "1.11.1" datastore = "1.2.1" # https://developer.android.com/jetpack/androidx/releases/datastore googleServices = "4.5.0" +jaad = "0.9.4" kermit = "2.1.0" koin = "4.2.2" kotlin = "2.4.10" @@ -43,6 +44,7 @@ compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.re compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "composeMultiplatform" } compose-uiTooling = { module = "org.jetbrains.compose.ui:ui-tooling", version.ref = "composeMultiplatform" } compose-uiToolingPreview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "composeMultiplatform" } +jaad = { module = "com.tianscar.javasound:jaad", version.ref = "jaad" } koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin" } koin-compose = { module = "io.insert-koin:koin-compose" } koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel" }