[Android] AudioRecorder reopens a disconnected input stream with no limit: a re-route on every open (Samsung, concurrent capture) loops hundreds of times a minute and records nothing
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 48/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- android, cpp, react-native
- Área
- audio-video-rtc, mobile
Línea de trabajo
Start with packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp, following onErrorAfterClose to restartCapture() to understand the repeated reopen path. Review how recorder state and stop, pause, and resume are handled before deciding how bounded retries and capture-down reporting fit the API. Done means repeated disconnects no longer cause an unbounded reopen loop, and the recording session can still be controlled and finalized while retries wait.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Description
On Android, AudioRecorder reopens its input stream on every ErrorDisconnected with no delay or limit (AndroidAudioRecorder::onErrorAfterClose → restartCapture()). When the system moves the stream to a different input device right after every open, this becomes a tight open/disconnect loop: the recorder reopens hundreds of times a minute, writes no audio, and nothing reaches JS (no error, no event), so the app keeps showing an active recording that saves nothing.
We hit it on Samsung phones when the app runs a second capture client at the same time (an RTC SDK, Agora, capturing with MIC) and the recorder uses the default input preset (VOICE_RECOGNITION):
- The recorder's stream opens on
Built-In Mic. - ~20 ms later Samsung's audio policy re-routes the shared input to
Built-In 2 Mic(AUDIO_DEVICE_IN_2MIC, a Samsung vendor device), because a shared input is routed for the highest-priority active source andMICoutranksVOICE_RECOGNITION. - AAudio turns any device change on a running stream into a disconnect (
AudioStreamLegacy::onAudioDeviceUpdate— same rule in Android 13–16; the MMAP path disconnects on a device change too). restartCapture()reopens immediately into the same re-route. Repeat.
APM_AudioPolicyManager: getInputForAttr() … Source: AUDIO_SOURCE_VOICE_RECOGNITION … selectedDeviceId 19
AudioStreamLegacy: onAudioDeviceUpdate() request DISCONNECT in data callback, device 19 => 22
AudioRecord: processAudioBuffer(): EVENT_MORE_DATA requested 7680 bytes but callback returned -1 bytes
AAudio: AAudioStream_requestStop(s#1) called
… (repeats ~740×/min for the whole session)
Observed on a Galaxy S24 Ultra (Android 16) and a Galaxy S20 FE (Android 13). Pixels map both sources to the same mic, so they don't reproduce it.
Where this was reproduced vs. checked: we reproduced it on our fork, which is based on 0.13.6 and opens the input Shared / PerformanceMode::None. In 1.0.0 (ce354a54) and current main (96afff59) the same unbounded path is still there: onErrorAfterClose calls restartCapture() on every ErrorDisconnected, and restartCapture() has no delay or attempt limit. Those versions open Exclusive, but with another capture client active the input falls back to shared, and the disconnect rule applies on both paths, so we expect the same loop. We haven't run 1.0.0 on the Samsung devices yet.
Workaround: pass androidInputPreset: 'generic' (MIC) so both clients share one device. We confirmed this on the S20 FE: 0 disconnects over an 8.5-minute recording with the RTC SDK active.
Suggested fix: bound the reclaim. For example, treat a stream that dies within ~1 s of starting as a fast disconnect, reopen immediately for the first couple, then back off exponentially (we use 250 ms doubling to a 5 s cap) and reset once a reopened stream survives. Also tell JS that capture is down while backing off: an error, or a recorder event or state change, whichever fits the library's API. Keep the session's state (recording/paused, outputs) while it waits, so stop() during the wait still finalizes the file and pause()/resume() still apply. We have this working in our fork (gtest-covered policy, waits on oboe's error thread on a condition variable that stop()/start() cancel). We're happy to open a PR against main if you agree with the approach and tell us how you'd like the "capture down" state surfaced.
Steps to reproduce
- On a Samsung Android phone, start an in-app capture client with
MIC(e.g. join an Agora channel as broadcaster withAudioScenarioGameStreaming). - While it is capturing, start an
AudioRecorderwith file output and noandroidInputPreset(defaultVOICE_RECOGNITION). - Watch
adb logcat | grep -E "onAudioDeviceUpdate|AAudioStream_requestStop": aDISCONNECT … X => Yand a stop on every open, continuously. - Stop the recorder: the file holds well under a second of audio, captured only after the other client released the mic.
Snack or a link to a repository
No public repro yet. It needs a Samsung device and a second capture client in the same app; the code path is packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp (onErrorAfterClose → restartCapture). We can share a minimal repro app if that helps.
React Native Audio API version
Reproduced on a 0.13.6-based fork; unbounded restart confirmed by code in 1.0.0 and main (96afff59).
React Native version
0.88.1
Platforms
Android
JavaScript runtime
Hermes
Workflow
Expo Dev Client
Architecture
Fabric (New Architecture)
Build type
Debug and release
Device
Real device
Device model
Samsung Galaxy S24 Ultra (SM-S928U1, Android 16); Samsung Galaxy S20 FE 5G (SM-G781U1, Android 13)
- Lenguaje dominante
- C++
- Estrellas
- 856
- Forks
- 100
- Merge medio
- 2 d 1 h
- PR fusionados (30 d)
- 34
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de software-mansion/react-native-audio-api
-
Android: audio focus listener posts to a dead looper after JS reload, interruptions (calls) are missedPosiblemente ocupada @JaydeepAgravat la tomó hace 2 días. Abiertoandroid bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
software-mansion/react-native-audio-api#1358 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
android bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
software-mansion/react-native-audio-api#1273 · 5 comentarios ·
Los mantenedores suelen responder en 1 día
-
bug ios
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
software-mansion/react-native-audio-api#1238 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 57/100
software-mansion/react-native-audio-api#1418 ·
Los mantenedores suelen responder en 1 día
-
feature-request ios
Dificultad 5/5 Más de una semana Aptitud para principiantes 45/100
software-mansion/react-native-audio-api#1398 ·
Los mantenedores suelen responder en 1 día
Todos los issues de software-mansion/react-native-audio-api
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Niko1221/Strata#5560 · 2 comentarios ·
Los mantenedores suelen responder en 4 días
-
NVIDIA windows
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
-
[辞書] C/C++のプリプロセッサ指令名を英字のままにするAbierto要トリアージ 辞書
Dificultad 1/5 1-3 horas Aptitud para principiantes 86/100
yksr-melt/Meltype#1625 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
[yugabyted] xcluster set_up and add_to_replication fail for database names containing - . or (Abiertokind/bug priority/medium qa_automation
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
yugabyte/yugabyte-db#37324 ·
Los mantenedores suelen responder en 1 día