Add bounded Android microphone subscriptions with independent ownership
This commit is contained in:
1 parent
d4eb1da233
commit
4a49c830d1
3 files changed
+224
No files matched your search
@@ -0,0 +1,69 @@
|
||||
package com.utun.chat.data
|
||||
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
import java.util.concurrent.LinkedBlockingQueue
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class MicrophoneCaptureTest {
|
||||
private class Device : MicrophoneCapture.Device {
|
||||
override val channels = 2
|
||||
override val inputId = 7
|
||||
val input = LinkedBlockingQueue<MicrophoneCapture.Frame>()
|
||||
val reads = AtomicInteger()
|
||||
var closes = 0
|
||||
override fun read(): MicrophoneCapture.Frame = input.take().also { reads.incrementAndGet() }
|
||||
override fun stop() { input.offer(MicrophoneCapture.Frame(shortArrayOf(), 0, 0)) }
|
||||
override fun close() { closes++ }
|
||||
}
|
||||
private fun frame(subscription: MicrophoneCapture.Subscription): MicrophoneCapture.Frame {
|
||||
repeat(50) { (subscription.poll() as? MicrophoneCapture.Frame)?.let { return it } }
|
||||
error("Capture frame timeout")
|
||||
}
|
||||
|
||||
@Test fun consumersShareCaptureFormatAndTimeButOwnTheirSamples() {
|
||||
val device = Device(); val capture = MicrophoneCapture(device, {})
|
||||
val stream = capture.subscribe("stream"); val radio = capture.subscribe("radio")
|
||||
try {
|
||||
device.input.add(MicrophoneCapture.Frame(shortArrayOf(10, 20), 987654321, 960))
|
||||
val first = frame(stream); val second = frame(radio)
|
||||
assertEquals(2, radio.channels); assertEquals(first.timeNs, second.timeNs); assertEquals(first.sequence, second.sequence)
|
||||
first.pcm[0] = 99
|
||||
assertArrayEquals(shortArrayOf(10, 20), second.pcm)
|
||||
stream.close()
|
||||
device.input.add(MicrophoneCapture.Frame(shortArrayOf(30, 40), 987674321, 1920))
|
||||
assertArrayEquals(shortArrayOf(30, 40), frame(radio).pcm); assertEquals(0, device.closes)
|
||||
} finally { stream.close(); radio.close() }
|
||||
assertEquals(1, device.closes); assertTrue(capture.closed)
|
||||
}
|
||||
|
||||
@Test fun stoppingRadioKeepsStreamAndPttIsOrderedWithPcm() {
|
||||
val device = Device(); val capture = MicrophoneCapture(device, {})
|
||||
val stream = capture.subscribe("stream"); val radio = capture.subscribe("radio")
|
||||
try {
|
||||
assertTrue(radio.ptt(true))
|
||||
device.input.add(MicrophoneCapture.Frame(shortArrayOf(1, 2), 1000, 0))
|
||||
assertEquals(MicrophoneCapture.Ptt(true), radio.poll())
|
||||
assertArrayEquals(shortArrayOf(1, 2), frame(radio).pcm)
|
||||
assertTrue(radio.ptt(false)); assertEquals(MicrophoneCapture.Ptt(false), radio.poll())
|
||||
radio.close(); assertEquals(0, device.closes)
|
||||
assertArrayEquals(shortArrayOf(1, 2), frame(stream).pcm)
|
||||
} finally { radio.close(); stream.close() }
|
||||
assertEquals(1, device.closes)
|
||||
}
|
||||
|
||||
@Test fun slowConsumerHasBoundedQueueAndReservedControlCapacity() {
|
||||
val device = Device(); val logs = LinkedBlockingQueue<String>(); val capture = MicrophoneCapture(device, { logs.add(it) })
|
||||
val stream = capture.subscribe("stream"); val radio = capture.subscribe("radio")
|
||||
try {
|
||||
repeat(40) {
|
||||
device.input.add(MicrophoneCapture.Frame(shortArrayOf(1, 2), it * 20000000L, it * 960L))
|
||||
frame(stream) // Трансляция успевает, рация намеренно не читает.
|
||||
}
|
||||
assertTrue(logs.any { it.contains("consumer=radio dropped=") })
|
||||
assertTrue(radio.ptt(true)); assertTrue(radio.ptt(false))
|
||||
repeat(24) { assertTrue(radio.poll() is MicrophoneCapture.Frame) }
|
||||
assertEquals(MicrophoneCapture.Ptt(true), radio.poll()); assertEquals(MicrophoneCapture.Ptt(false), radio.poll())
|
||||
} finally { radio.close(); stream.close() }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user