Verify explicit native cancellation failure and document independent audio ownership

This commit is contained in:
evgeny committed 2026-10-29 13:35:19 +01:00
1 parent a9099a5ea7
commit 41ea2afaaa
2 files changed
+5 -2

No files matched your search

@@ -16,12 +16,14 @@ import java.util.concurrent.atomic.AtomicReference
/**
* Запись голосового сообщения/тест микрофона и отдельный плеер native Opus-файла.
* Запись и тест делят один native recorder: успешный voiceStart даёт владение до stop/cancel.
* Lifecycle сериализован монитором менеджера; stopRecording/cancelRecording вызываются также из IO worker.
* Capture lifecycle сериализован монитором менеджера; playback controls/callbacks имеют отдельный короткий lock.
* Захват — PCM16 48 кГц mono, чтение без блокировки; stop сначала останавливает reader, ждёт join и освобождает Android.
* Ошибка захвата/очистки запрещает публикацию частичной записи: stopRecording вернёт -1 и отменит native recorder.
* После отказа worker владелец вызывает stop/cancel; неосвобождённый Android device сохраняется для повтора cleanup.
* Плеер владеет своим decoder/AudioTrack в worker; прогресс/завершение — быстрые callbacks этого потока.
* Pause/stop меняют поколение и прерывают worker, старое поколение больше не уведомляет UI.
* Process registry и cleanup worker сохраняют владельцев до release ACK также после ViewModel.onCleared.
* Stop core/запуск звонка ждут всех владельцев; file decoder освобождается независимо от отказа AudioTrack.
*/
class AudioRecorderManager {
companion object {
@@ -191,7 +191,7 @@ class AudioRecorderManagerTest {
@Test fun nativeCancelFailureRetainsTheCaptureUntilARealAcknowledgement() {
plan(); assertTrue(manager.startRecording("7")); NativeLib.failCancel = true
assertEquals(-1, manager.stopRecording()); assertTrue(NativeLib.active)
manager.cancelRecording(); assertTrue(NativeLib.active)
val closed = manager.requestClose(); assertFalse(closed.isDone)
assertThrows(IllegalStateException::class.java) { AudioRecorderManager.requireReleasedForCore() }
NativeLib.failCancel = false; closed.get(2, TimeUnit.SECONDS)
@@ -239,6 +239,7 @@ class AudioRecorderManagerTest {
val closed = manager.requestClose()
try {
assertFalse(closed.isDone); assertFalse(manager.startRecording("8"))
manager.pausePlayback(); manager.stopPlayback(); manager.cancelRecording(); manager.stopMicTest()
assertThrows(IllegalStateException::class.java) { AudioRecorderManager.requireReleasedForCore() }
} finally { leave.countDown() }
closed.get(2, TimeUnit.SECONDS); assertTrue(device.released); assertFalse(NativeLib.active)