All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openbase.jul.audio.AudioPlayer.kt Maven / Gradle / Ivy

The newest version!
package org.openbase.jul.audio

import org.openbase.jul.exception.CouldNotPerformException
import org.openbase.jul.exception.printer.ExceptionPrinter
import org.openbase.jul.exception.printer.LogLevel
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.ByteArrayInputStream
import java.io.File
import java.io.IOException
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock
import javax.sound.sampled.*
import kotlin.concurrent.withLock

/**
 *
 * @author [Divine Threepwood](mailto:[email protected])
 */
class AudioPlayer @JvmOverloads constructor(soundChannels: Int = 10) {
    private val executorService: ExecutorService = Executors.newFixedThreadPool(soundChannels)

    @JvmOverloads
    fun playAudio(source: AudioSource, wait: Boolean = false): Boolean {
        try {
            if (wait) {
                play(source)
                return true
            }
            executorService.execute {
                try {
                    play(source)
                } catch (ex: IOException) {
                    ExceptionPrinter.printHistory(
                        CouldNotPerformException("Could not play clip!", ex),
                        logger,
                        LogLevel.WARN
                    )
                } catch (ex: UnsupportedAudioFileException) {
                    ExceptionPrinter.printHistory(
                        CouldNotPerformException("Could not play clip!", ex),
                        logger,
                        LogLevel.WARN
                    )
                } catch (ex: LineUnavailableException) {
                    ExceptionPrinter.printHistory(
                        CouldNotPerformException("Could not play clip!", ex),
                        logger,
                        LogLevel.WARN
                    )
                }
            }
        } catch (ex: IOException) {
            ExceptionPrinter.printHistory(CouldNotPerformException("Could not play clip!", ex), logger, LogLevel.WARN)
            return false
        } catch (ex: UnsupportedAudioFileException) {
            ExceptionPrinter.printHistory(CouldNotPerformException("Could not play clip!", ex), logger, LogLevel.WARN)
            return false
        } catch (ex: LineUnavailableException) {
            ExceptionPrinter.printHistory(CouldNotPerformException("Could not play clip!", ex), logger, LogLevel.WARN)
            return false
        }
        return true
    }

    companion object {
        const val BUFSIZE: Int = 512
        private val logger: Logger = LoggerFactory.getLogger(AudioPlayer::class.java)

        val lock = ReentrantLock()
        val condition: Condition = lock.newCondition()

        @Throws(
            IOException::class,
            UnsupportedAudioFileException::class,
            LineUnavailableException::class,
            InterruptedException::class
        )
        private fun play(source: AudioSource) = when (source) {
            is AudioData -> play(source)
            is AudioFileHolder -> play(source.file)
            else -> {
                logger.warn("Unknown audio source! Skip clip ...")
            }
        }

        @Throws(
            IOException::class,
            UnsupportedAudioFileException::class,
            LineUnavailableException::class,
            InterruptedException::class
        )
        private fun play(audioData: AudioData) = AudioInputStream(
            ByteArrayInputStream(audioData.data),
            audioData.format,
            audioData.dataLength
        ).also { play(it) }

        @Throws(
            IOException::class,
            UnsupportedAudioFileException::class,
            LineUnavailableException::class,
            InterruptedException::class
        )
        private fun play(clipFile: File?) = play(AudioSystem.getAudioInputStream(clipFile))

        @Throws(
            IOException::class,
            UnsupportedAudioFileException::class,
            LineUnavailableException::class,
            InterruptedException::class
        )
        private fun play(audioInputStream: AudioInputStream) {
            class AudioListener : LineListener {
                private var done = false

                override fun update(event: LineEvent) {
                    lock.withLock {
                        val eventType = event.type
                        if (eventType === LineEvent.Type.STOP || eventType === LineEvent.Type.CLOSE) {
                            done = true
                            condition.signalAll()
                        }
                    }
                }

                @Throws(InterruptedException::class)
                fun waitUntilDone() = lock.withLock {
                    while (!done) {
                        condition.await()
                    }
                }
            }

            AudioListener().also { listener ->
                audioInputStream.use {
                    val clip = AudioSystem.getClip()
                    clip.addLineListener(listener)
                    clip.open(audioInputStream)
                    clip.use {
                        clip.start()
                        listener.waitUntilDone()
                    }
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy