new: implement desktop audio player with Ogg Vorbis support using VorbisSPI
This commit is contained in:
@@ -43,6 +43,10 @@ kotlin {
|
||||
implementation(libs.media3.exoplayer)
|
||||
implementation(libs.media3.common)
|
||||
}
|
||||
jvmMain.dependencies {
|
||||
// Desktop audio: Ogg Vorbis SPI so javax.sound.sampled can decode .ogg
|
||||
implementation(libs.vorbisspi)
|
||||
}
|
||||
commonMain.dependencies {
|
||||
// DI
|
||||
implementation(project.dependencies.platform(libs.koin.bom))
|
||||
|
||||
@@ -1,23 +1,61 @@
|
||||
package fr.ajaury.gwenedeg.player
|
||||
|
||||
import java.io.BufferedInputStream
|
||||
import java.net.URI
|
||||
import javax.sound.sampled.AudioFormat
|
||||
import javax.sound.sampled.AudioSystem
|
||||
import javax.sound.sampled.Clip
|
||||
|
||||
/**
|
||||
* Desktop [AudioPlayer] backed by [javax.sound.sampled].
|
||||
*
|
||||
* The Ogg Vorbis recordings are decoded to PCM by the VorbisSPI providers on the classpath, which
|
||||
* the JDK [AudioSystem] discovers automatically, so loading works the same as any natively
|
||||
* supported format.
|
||||
*/
|
||||
class JvmAudioPlayer : AudioPlayer {
|
||||
private var clip: Clip? = null
|
||||
|
||||
override fun load(uri: String) {
|
||||
release()
|
||||
|
||||
val encodedInput = BufferedInputStream(URI(uri).toURL().openStream())
|
||||
.let { AudioSystem.getAudioInputStream(it) }
|
||||
val baseFormat = encodedInput.format
|
||||
val pcmFormat = AudioFormat(
|
||||
AudioFormat.Encoding.PCM_SIGNED,
|
||||
baseFormat.sampleRate,
|
||||
16,
|
||||
baseFormat.channels,
|
||||
baseFormat.channels * 2,
|
||||
baseFormat.sampleRate,
|
||||
false,
|
||||
)
|
||||
|
||||
val decodedInput = AudioSystem.getAudioInputStream(pcmFormat, encodedInput)
|
||||
clip = AudioSystem.getClip().apply { open(decodedInput) }
|
||||
}
|
||||
|
||||
override fun play() {
|
||||
TODO("Not yet implemented")
|
||||
clip?.start()
|
||||
}
|
||||
|
||||
override fun pause() {
|
||||
TODO("Not yet implemented")
|
||||
clip?.stop()
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
TODO("Not yet implemented")
|
||||
clip?.apply {
|
||||
stop()
|
||||
framePosition = 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun release() {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun load(uri: String) {
|
||||
TODO("Not yet implemented")
|
||||
clip?.apply {
|
||||
stop()
|
||||
close()
|
||||
}
|
||||
clip = null
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package fr.ajaury.gwenedeg.player
|
||||
|
||||
/**
|
||||
* Desktop has no system audio focus model to honour, so activation is a no-op.
|
||||
*/
|
||||
class JvmAudioSessionManager : AudioSessionManager {
|
||||
override fun activate() {
|
||||
}
|
||||
|
||||
override fun deactivate() {
|
||||
}
|
||||
}
|
||||
+9
-2
@@ -1,6 +1,13 @@
|
||||
package fr.ajaury.gwenedeg.player.di
|
||||
|
||||
import fr.ajaury.gwenedeg.player.AudioPlayer
|
||||
import fr.ajaury.gwenedeg.player.AudioSessionManager
|
||||
import fr.ajaury.gwenedeg.player.JvmAudioPlayer
|
||||
import fr.ajaury.gwenedeg.player.JvmAudioSessionManager
|
||||
import org.koin.core.module.Module
|
||||
import org.koin.dsl.module
|
||||
|
||||
actual val audioPlayerModule: Module
|
||||
get() = TODO("Not yet implemented")
|
||||
actual val audioPlayerModule: Module = module {
|
||||
single<AudioPlayer> { JvmAudioPlayer() }
|
||||
single<AudioSessionManager> { JvmAudioSessionManager() }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user