Model radio worker I/O faults and partial native capture effects
This commit is contained in:
1 parent
128af68a89
commit
5d74bcd865
2 files changed
+65
-17
No files matched your search
@@ -1,6 +1,7 @@
|
||||
package android.media
|
||||
|
||||
import android.os.Handler
|
||||
import java.util.concurrent.LinkedBlockingDeque
|
||||
|
||||
interface AudioRouting {
|
||||
fun interface OnRoutingChangedListener { fun onRoutingChanged(router: AudioRouting) }
|
||||
@@ -22,8 +23,8 @@ class AudioTrack(val id: Int) : AudioRouting {
|
||||
failures = nextFailures
|
||||
created.add(this)
|
||||
}
|
||||
var playbackHeadPosition = 0
|
||||
private set
|
||||
private var head = 0
|
||||
val playbackHeadPosition: Int get() { access("head"); return head }
|
||||
fun play() { access("play") }
|
||||
var interruptOnStop = false
|
||||
fun stop() { access("stop"); if (interruptOnStop) Thread.currentThread().interrupt() }
|
||||
@@ -36,12 +37,21 @@ class AudioTrack(val id: Int) : AudioRouting {
|
||||
check("release after" !in failures) { "track release failed after effect" }
|
||||
}
|
||||
fun write(samples: ShortArray, offset: Int, count: Int): Int {
|
||||
onWrite()
|
||||
access("write")
|
||||
check(offset >= 0 && offset + count <= samples.size)
|
||||
playbackHeadPosition += count / 2
|
||||
return count
|
||||
val result = forcedWriteResult ?: minOf(count, maxWriteSamples)
|
||||
val write = Write(offset, count, result, samples.copyOfRange(offset, offset + count))
|
||||
if (!writes.offerLast(write)) { writes.pollFirst(); writes.offerLast(write) }
|
||||
if (result > 0) head += result / 2
|
||||
return result
|
||||
}
|
||||
var failures = emptySet<String>()
|
||||
data class Write(val offset: Int, val count: Int, val result: Int, val pcm: ShortArray)
|
||||
val writes = LinkedBlockingDeque<Write>(64)
|
||||
@Volatile var onWrite: () -> Unit = {}
|
||||
@Volatile var maxWriteSamples = Int.MAX_VALUE
|
||||
@Volatile var forcedWriteResult: Int? = null
|
||||
@Volatile var failures = emptySet<String>()
|
||||
var acceptPreference = true
|
||||
var autoRoute = true
|
||||
var emitOnPreference = false
|
||||
|
||||
+50
-12
@@ -2,6 +2,7 @@ package com.utun.chat.data
|
||||
|
||||
import java.util.Collections
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -40,7 +41,12 @@ object NativeLib {
|
||||
@Volatile private var radioGroup = 0L
|
||||
@Volatile private var radioMode = 0
|
||||
@Volatile private var radioTx = false
|
||||
var radioFailures = emptySet<String>()
|
||||
@Volatile var radioFailures = emptySet<String>()
|
||||
@Volatile var radioCaptureAlive = false
|
||||
@Volatile var radioPullResult = 0
|
||||
val radioPullResults = ConcurrentLinkedQueue<Int>()
|
||||
@Volatile var onRadioFeed: (Long) -> Unit = {}
|
||||
val radioFeeds: MutableList<Long> = Collections.synchronizedList(mutableListOf())
|
||||
fun radioSetActive(group: Long, active: Boolean) { radioCommands.add(RadioCommand("active=$active", group)) }
|
||||
fun radioConfigure(request: Long, settings: RadioAutoSettings): Boolean { radioRequest = request; return settings.valid() }
|
||||
fun radioAudioStart(group: Long, channels: Int): Boolean {
|
||||
@@ -50,19 +56,51 @@ object NativeLib {
|
||||
fun radioAudioStop() {
|
||||
radioCommands.add(RadioCommand("audio stop", radioGroup))
|
||||
check("stop" !in radioFailures) { "native audio stop failed" }
|
||||
radioTx = false; radioCaptureAlive = false
|
||||
}
|
||||
fun radioAudioPull(group: Long, out: ShortArray, playedFrames: Long): Int {
|
||||
check("pull" !in radioFailures) { "native pull failed" }
|
||||
val result = radioPullResults.poll() ?: radioPullResult
|
||||
if (result in 1..out.size) out.fill(7, 0, result)
|
||||
return result
|
||||
}
|
||||
fun radioAudioFeed(group: Long, samples: ShortArray): Boolean {
|
||||
onRadioFeed(group)
|
||||
radioFeeds.add(group)
|
||||
check("feed" !in radioFailures) { "native feed failed" }
|
||||
return "feed reject" !in radioFailures && group == radioGroup && radioCaptureAlive && samples.isNotEmpty()
|
||||
}
|
||||
fun radioCaptureStart(group: Long, channels: Int, mode: Int): Boolean {
|
||||
radioCommands.add(RadioCommand("capture start", group))
|
||||
if ("capture reject" in radioFailures) return false
|
||||
radioMode = if ("detector off" in radioFailures) 0 else mode
|
||||
radioCaptureAlive = true
|
||||
check("capture start" !in radioFailures) { "native capture start failed after effect" }
|
||||
return true
|
||||
}
|
||||
fun radioCaptureStop() {
|
||||
radioCommands.add(RadioCommand("capture stop", radioGroup))
|
||||
check("capture stop" !in radioFailures) { "native capture stop failed" }
|
||||
radioTx = false; radioCaptureAlive = false
|
||||
}
|
||||
fun radioCaptureDiscontinuity(group: Long) {
|
||||
radioCommands.add(RadioCommand("boundary", group))
|
||||
check("boundary" !in radioFailures) { "native boundary failed" }
|
||||
}
|
||||
fun radioAutoMode(): Int {
|
||||
check("mode" !in radioFailures) { "native mode query failed" }
|
||||
return if ("bad mode" in radioFailures) 99 else radioMode
|
||||
}
|
||||
fun radioTransmitting() = radioTx
|
||||
fun radioTalkBegin(group: Long) {
|
||||
radioCommands.add(RadioCommand("begin", group)); radioTx = true
|
||||
check("begin" !in radioFailures) { "native begin failed after effect" }
|
||||
}
|
||||
fun radioTalkEnd(group: Long) {
|
||||
radioCommands.add(RadioCommand("end", group))
|
||||
check("end" !in radioFailures) { "native end failed" }
|
||||
radioTx = false
|
||||
}
|
||||
fun radioAudioPull(group: Long, out: ShortArray, playedFrames: Long): Int = 0
|
||||
fun radioAudioFeed(group: Long, samples: ShortArray): Boolean = group == radioGroup
|
||||
fun radioCaptureStart(group: Long, channels: Int, mode: Int): Boolean {
|
||||
radioMode = mode; radioCommands.add(RadioCommand("capture start", group)); return true
|
||||
}
|
||||
fun radioCaptureStop() { radioTx = false; radioCommands.add(RadioCommand("capture stop", radioGroup)) }
|
||||
fun radioCaptureDiscontinuity(group: Long) { radioCommands.add(RadioCommand("boundary", group)) }
|
||||
fun radioAutoMode() = radioMode
|
||||
fun radioTransmitting() = radioTx
|
||||
fun radioTalkBegin(group: Long) { radioTx = true; radioCommands.add(RadioCommand("begin", group)) }
|
||||
fun radioTalkEnd(group: Long) { radioTx = false; radioCommands.add(RadioCommand("end", group)) }
|
||||
data class LocalInvite(val peer: Long, val request: Long, val link: String)
|
||||
val localInvites = mutableListOf<LocalInvite>()
|
||||
var sendLocal: (LocalInvite) -> Boolean = { true }
|
||||
|
||||
Reference in new issue
Block a user