Skip to content
Advertisement

Why is Java Sound API frame position getting stuck?

I’m trying to create a sound recorder using Java Sound API on Kotlin Desktop. I want to automatically stop the recording after 3 seconds. The frame position does initially advance but then gets stuck.

class VoiceRecorder {

    private val format = AudioFormat(
        AudioFormat.Encoding.PCM_SIGNED,
        16000.0F,
        16,
        1,
        2,
        16000.0F,
        false
    )

    private val info = DataLine.Info(TargetDataLine::class.java, format)
    private val line = AudioSystem.getLine(info) as TargetDataLine

    init {
        if (!AudioSystem.isLineSupported(info)) {
            println("Line is not supported!!!")
        }else{
            println("Line is supported.")
        }
    }

    fun startRecording(){

        line.open()
        line.start()

        val recordingStream = AudioInputStream(line)
        val outputFile = File("src/main/resources/record.wav")
        val frameRate = format.frameRate

    runBlocking {
        while(line.framePosition/frameRate<3.0){
            val time = line.framePosition/frameRate
            delay(100)
            println("position: ${line.framePosition}, time: $time")
        }
    }


        AudioSystem.write(recordingStream, AudioFileFormat.Type.WAVE, outputFile)
        line.stop()
        line.close()
    }
}

This is output of the print statement:

position: 1619, time: 0.0
position: 3219, time: 0.1011875
position: 4835, time: 0.2011875
position: 6435, time: 0.3021875
position: 7999, time: 0.4021875
position: 7999, time: 0.4999375
position: 7999, time: 0.4999375
position: 7999, time: 0.4999375
goes on until you die...

What is causing this and is there a way to fix it?

Advertisement

Answer

The problem was that AudioSystem.write needs to run in a separate coroutine.

For example, add

private val cr = CoroutineScope(Dispatchers.IO)

then do

cr.launch { AudioSystem.write(recordingStream, AudioFileFormat.Type.WAVE, outputFile) }

runBlocking {
    while(line.framePosition/frameRate<3.0){
        val time = line.framePosition/frameRate
        delay(100)
        println("position: ${line.framePosition}, time: $time")
    }
}
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement