Verify failed radio restore and trace resource join completion

This commit is contained in:
evgeny committed 2026-10-29 13:34:23 +01:00
1 parent b6ec030128
commit 2fd8a35230
2 files changed
+30 -7

No files matched your search

@@ -285,13 +285,13 @@ class RadioAudioEngine {
check(trackMin > 0) { "AudioTrack minimum buffer invalid group=$group value=$trackMin" }
val trackBuf = (trackMin * 2).coerceAtLeast(FRAME_SAMPLES * PLAY_CHANNELS * 4)
val track = AudioTrack(
AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH).build(),
AudioFormat.Builder().setSampleRate(SAMPLE_RATE)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO).build(),
trackBuf, AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE)
AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH).build(),
AudioFormat.Builder().setSampleRate(SAMPLE_RATE)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO).build(),
trackBuf, AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE)
audioTrack = track
@@ -525,10 +525,12 @@ class RadioAudioEngine {
/** Дождаться своего worker до остановки DSP; interruption не разрешает освободить используемые им ресурсы. */
private fun joinWorker(worker: Thread?, kind: String): Boolean {
var interrupted = Thread.interrupted()
if (worker != null) LogManager.addLog("DEBUG", "RadioAudio", "joining $kind worker=${worker.name} group=$audioGroup")
while (worker?.isAlive == true) try { worker.join() } catch (e: InterruptedException) {
interrupted = true
LogManager.addLog("WARN", "RadioAudio", "$kind join interrupted group=$audioGroup; finishing cleanup")
}
if (worker != null) LogManager.addLog("DEBUG", "RadioAudio", "$kind worker joined group=$audioGroup")
return interrupted
}
@@ -305,4 +305,25 @@ class RadioAudioLifecycleTest {
assertTrue(engine.isActive()); assertFalse(track.released); assertEquals(1, AudioTrack.created.size)
diagnostic("zero group ID")
}
@Test fun failedRestoreAfterCallDisablesNativeGroupMembershipBeforeClearingThePublishedGroup() {
context.configProvider.failRadioSettings = true
engine.restoreAfterCall(7); drain(); main.dispatchAll(); drain()
val activation = synchronized(NativeLib.radioCommands) { NativeLib.radioCommands.filter { it.kind.startsWith("active=") } }
assertEquals(listOf("active=true", "active=false"), activation.map { it.kind })
assertFalse(engine.isActive()); assertNull(engine.activeGroup.value)
}
@Test fun reentrantStartFromFailedReadinessCannotBeClearedByTheOldCallback() {
context.configProvider.failRadioSettings = true
val results = mutableListOf<Pair<Long, Boolean>>()
engine.start(7) { ready ->
results.add(7L to ready)
context.configProvider.failRadioSettings = false
engine.start(8) { results.add(8L to it) }
}
drain(); main.dispatchAll(); drain(); main.dispatchAll()
assertEquals(listOf(7L to false, 8L to true), results)
assertEquals(8L, engine.activeGroup.value); assertTrue(engine.isActive())
}
}