- Star icons now use distinct tint colors (primary vs faded) for clear state - Station switching no longer races — old playback job is cancelled before new - Skip-ahead drops ~1s of buffered audio per tap via atomic counter - Custom SocketFactory with SO_RCVBUF=16KB and TCP_NODELAY for minimal TCP buffering - Catch-up drain: discards pre-buffered frames until network reads block (live edge) - AudioTrack PERFORMANCE_MODE_LOW_LATENCY for smallest hardware buffer Made-with: Cursor
38 lines
816 B
Kotlin
38 lines
816 B
Kotlin
package xyz.cottongin.radio247.audio
|
|
|
|
class RingBuffer(
|
|
private val capacityFrames: Int,
|
|
private val onFrame: (ByteArray) -> Unit
|
|
) {
|
|
private val buffer = ArrayDeque<ByteArray>()
|
|
|
|
fun write(frame: ByteArray) {
|
|
if (capacityFrames == 0) {
|
|
onFrame(frame)
|
|
return
|
|
}
|
|
if (buffer.size >= capacityFrames) {
|
|
onFrame(buffer.removeFirst())
|
|
}
|
|
buffer.addLast(frame)
|
|
}
|
|
|
|
fun flush() {
|
|
while (buffer.isNotEmpty()) {
|
|
onFrame(buffer.removeFirst())
|
|
}
|
|
}
|
|
|
|
fun clear() {
|
|
buffer.clear()
|
|
}
|
|
|
|
fun drop(maxCount: Int): Int {
|
|
val toDrop = minOf(maxCount, buffer.size)
|
|
repeat(toDrop) { buffer.removeFirst() }
|
|
return toDrop
|
|
}
|
|
|
|
val size: Int get() = buffer.size
|
|
}
|