Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/alsa wait #1770

Merged
merged 4 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class SoundAudioStream(
}
} catch (e: CancellationException) {
// Do nothing
nas.stop()
params.onCancel?.invoke()
} finally {
nas.wait()
Expand Down
32 changes: 27 additions & 5 deletions korau/src/commonMain/kotlin/korlibs/audio/sound/backends/ALSA.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class ALSAPlatformAudioOutput(
coroutineContext: CoroutineContext,
frequency: Int,
) : PlatformAudioOutput(coroutineContext, frequency) {
override var availableSamples: Int = 0
val channels = 2
private val lock = Lock()
val sdeque = AudioSamplesDeque(channels)
Expand All @@ -45,15 +46,19 @@ class ALSAPlatformAudioOutput(
}

override suspend fun add(samples: AudioSamples, offset: Int, size: Int) {
if (!ASound2.initialized) return super.add(samples, offset, size)
if (size == 0) return
if (!ASound2.initialized) return super.add(samples, offset, samples.totalSamples)
//if (!running) start()

if (!running) delay(10.milliseconds)

while (running && lock { sdeque.availableRead > 4 * 1024 }) {
delay(10.milliseconds)
}
lock { sdeque.write(samples, offset, size) }
lock {
availableSamples += samples.totalSamples
sdeque.write(samples, offset, samples.totalSamples)
}
}

override fun start() {
Expand All @@ -70,6 +75,9 @@ class ALSAPlatformAudioOutput(
}
//println("START!")
sdeque.clear()
lock {
availableSamples = 0
}

if (!ASound2.initialized) return

Expand Down Expand Up @@ -127,16 +135,26 @@ class ALSAPlatformAudioOutput(
buff[n * channels + ch] = (samples[ch, n] * rscale).toInt().toShort()
}
}
if (!running) break
val result = ASound2.snd_pcm_writei(pcm, buff, frames)
//println("result=$result")
if (result == -ASound2.EPIPE) {
ASound2.snd_pcm_prepare(pcm)
} else {
while (running && ASound2.snd_pcm_delay(pcm) > frames) {
blockingSleep(10.milliseconds)
}
}
lock {
availableSamples -= samples.totalSamples
}
}
} finally {
//println("COMPLETED: $pcm")
thread = null
// stop()
lock {
availableSamples = 0
}
}
}.also {
it.isDaemon = true
Expand All @@ -148,9 +166,11 @@ class ALSAPlatformAudioOutput(
running = false

if (pcm != 0L) {
ASound2.snd_pcm_drain(pcm)
ASound2.snd_pcm_drop(pcm)
ASound2.snd_pcm_close(pcm)
//println("ASound2.snd_pcm_close: ${pcm}")
lock {
availableSamples = 0
}
pcm = 0L
}
}
Expand Down Expand Up @@ -181,6 +201,8 @@ interface ASound2 {
fun snd_pcm_writei(pcm: Long, buffer: ShortArray, size: Int): Int = ERROR
fun snd_pcm_prepare(pcm: Long): Int = ERROR
fun snd_pcm_drain(pcm: Long): Int = ERROR
fun snd_pcm_drop(pcm: Long): Int = ERROR
fun snd_pcm_delay(pcm: Long): Int = ERROR
fun snd_pcm_close(pcm: Long): Int = ERROR

companion object : ASound2 by ASoundImpl {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,20 @@ actual object ASoundImpl : ASound2 {
return tempOut.getInt(0L)
}

override fun snd_pcm_delay(pcm: Long): Int {
val tempDelay = Memory(4).also { it.clear() }
A2.snd_pcm_delay(pcm.toCPointer(), tempDelay)
return tempDelay.getInt(0L)
}

override fun snd_pcm_writei(pcm: Long, buffer: ShortArray, size: Int): Int {
val mem = Memory((buffer.size * 2).toLong()).also { it.clear() }
for (n in 0 until buffer.size) mem.setShort((n * 2).toLong(), buffer[n])
return A2.snd_pcm_writei(pcm.toCPointer(), mem, size)
}

override fun snd_pcm_prepare(pcm: Long): Int = A2.snd_pcm_prepare(pcm.toCPointer())
override fun snd_pcm_drop(pcm: Long): Int = A2.snd_pcm_drop(pcm.toCPointer())
override fun snd_pcm_drain(pcm: Long): Int = A2.snd_pcm_drain(pcm.toCPointer())
override fun snd_pcm_close(pcm: Long): Int = A2.snd_pcm_close(pcm.toCPointer())
}
Expand All @@ -76,6 +83,8 @@ object A2 {
@JvmStatic external fun snd_pcm_writei(pcm: Pointer?, buffer: Pointer?, size: Int): Int
@JvmStatic external fun snd_pcm_prepare(pcm: Pointer?): Int
@JvmStatic external fun snd_pcm_drain(pcm: Pointer?): Int
@JvmStatic external fun snd_pcm_drop(pcm: Pointer?): Int
@JvmStatic external fun snd_pcm_delay(pcm: Pointer?, delay: Pointer?): Int
@JvmStatic external fun snd_pcm_close(pcm: Pointer?): Int

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,21 @@ actual object ASoundImpl : ASound2 {
}
}

override fun snd_pcm_delay(params: Long): Int {
memScoped {
val out = alloc<IntVar>()
A2.snd_pcm_delay(params.toCPointer(), out.ptr)
return out.value.toInt()
}
}

override fun snd_pcm_writei(pcm: Long, buffer: ShortArray, size: Int): Int = buffer.usePinned {
A2.snd_pcm_writei(pcm.toCPointer(), it.startAddressOf, size)
}

override fun snd_pcm_prepare(pcm: Long): Int = A2.snd_pcm_prepare(pcm.toCPointer())
override fun snd_pcm_drain(pcm: Long): Int = A2.snd_pcm_drain(pcm.toCPointer())
override fun snd_pcm_drop(pcm: Long): Int = A2.snd_pcm_drop(pcm.toCPointer())
override fun snd_pcm_close(pcm: Long): Int = A2.snd_pcm_close(pcm.toCPointer())
}

Expand All @@ -67,6 +76,8 @@ internal object A2 : DynamicLibrary("libasound.so.2") {
val snd_pcm_writei by func<(pcm: COpaquePointer?, buffer: COpaquePointer?, size: Int) -> Int>()
val snd_pcm_prepare by func<(pcm: COpaquePointer?) -> Int>()
val snd_pcm_drain by func<(pcm: COpaquePointer?) -> Int>()
val snd_pcm_drop by func<(pcm: COpaquePointer?) -> Int>()
val snd_pcm_delay by func<(pcm: COpaquePointer?, delay: COpaquePointer?) -> Int>()
val snd_pcm_close by func<(pcm: COpaquePointer?) -> Int>()

}