Verify explicit native cancellation failure and document independent audio ownership
This commit is contained in:
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 {
|
||||
|
||||
+2
-1
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user