React Native音频API真机播放后无法录音,仅模拟器正常
React Native音频API真机播放后无法录音,仅模拟器正常
我之前在iOS真机上碰到过一模一样的问题,这个-10851错误简直是噩梦!本质是iOS的音频会话冲突——播放音频后,音频资源没有被正确释放,或者录音前的音频会话配置和播放时的配置冲突,导致录音的AVAudioEngine无法初始化。模拟器因为音频栈的宽松性不会触发这个问题,但真机上卡得死死的。
先拆解错误原因
日志里的AURemoteIO.cpp:1091 failed: -10851和0 Hz是核心线索:
- -10851是iOS音频服务的「资源不可用」错误,通常是音频会话的类别、配置和要启动的音频单元(播放/录音)不匹配。
0 Hz说明系统没有正确获取到录音的采样率配置,和播放时的音频格式直接冲突了。
针对性解决方案(亲测有效)
1. 全局统一管理音频会话(最关键!)
iOS的AVAudioSession是全局单例,播放和录音必须切换正确的会话类别,不能各自为政。推荐用react-native-audio-session库来管理,不用自己写原生模块:
首先安装依赖:
npm install react-native-audio-session # 或 yarn add react-native-audio-session
然后封装两个会话配置函数,播放前调用播放配置,录音前调用录音配置:
import AudioSession from 'react-native-audio-session'; // 配置播放用的音频会话 export async function setupPlaybackSession() { try { // 先停用当前会话,彻底避免冲突 await AudioSession.setActive(false); // 设置播放类别,支持后台播放(按需调整) await AudioSession.setCategory(AudioSession.Category.Playback, { interruptionModeIOS: AudioSession.InterruptionModeIOS.DoNotMix, }); await AudioSession.setActive(true); } catch (err) { console.error("播放会话配置失败:", err); } } // 配置录音用的音频会话(适配16kHz单通道需求) export async function setupRecordingSession() { try { // 先停用播放会话 await AudioSession.setActive(false); // 用PlayAndRecord类别,支持边录边播(不需要的话可以用Record) await AudioSession.setCategory(AudioSession.Category.PlayAndRecord, { allowsBluetooth: false, // 按需调整 playThroughSpeaker: false, // 录音时关闭扬声器,用麦克风 interruptionModeIOS: AudioSession.InterruptionModeIOS.DoNotMix, // 强制指定16kHz采样率,解决日志里的0Hz问题 sampleRateIOS: 16000, numberOfChannelsIOS: 1, }); await AudioSession.setActive(true); } catch (err) { console.error("录音会话配置失败:", err); } }
2. 播放后强制释放所有资源
播放结束后,不能只调用stop(),必须销毁播放实例并重置会话:
// 假设你用react-native-sound播放音频 import Sound from 'react-native-sound'; let audioPlayer = null; async function playAudio(path) { await setupPlaybackSession(); audioPlayer = new Sound(path, '', (err) => { if (err) { console.error('加载音频失败:', err); return; } audioPlayer.play(() => { // 播放结束后立即清理 cleanupPlayer(); }); }); } async function cleanupPlayer() { if (audioPlayer) { audioPlayer.stop(); audioPlayer.release(); // 关键!释放底层AVAudioPlayer原生资源 audioPlayer = null; // 让GC回收实例 await AudioSession.setActive(false); // 停用播放会话 } }
3. 录音前严格校验会话状态
启动录音前,先调用setupRecordingSession(),并且确保会话激活成功后再初始化录音引擎:
// 假设用react-native-audio录制16kHz WAV import AudioRecorderPlayer from 'react-native-audio-recorder-player'; const audioRecorderPlayer = new AudioRecorderPlayer(); async function startRecording() { await setupRecordingSession(); // 明确指定录音格式为16kHz单通道WAV const recordingOptions = { ios: { audioQuality: 'low', sampleRate: 16000, numberOfChannels: 1, audioEncoding: 'wav', }, }; try { const path = await audioRecorderPlayer.startRecorder('', recordingOptions); console.log('开始录音:', path); } catch (err) { console.error('启动录音失败:', err); } }
4. 避免多音频引擎实例冲突
如果你同时用了播放和录音的独立引擎(比如AVAudioEngine),一定要确保播放引擎完全停止并销毁后再启动录音引擎:
// 播放引擎清理示例(原生或RN封装的引擎都适用) async function stopAndDestroyPlaybackEngine() { if (playbackEngine) { playbackEngine.stop(); playbackEngine = null; // 彻底销毁引擎实例 } }
最后检查两个细节
- Info.plist权限:确保添加了麦克风和音频使用权限,否则真机可能悄悄失败:
<key>NSMicrophoneUsageDescription</key> <string>需要访问麦克风进行录音</string> <key>NSMusicUsageDescription</key> <string>需要访问音频播放功能</string> - 会话激活重试:某些场景下会话激活可能失败,加个重试逻辑更稳妥:
async function activateSession() { try { await AudioSession.setActive(true); } catch (err) { // 重试一次,解决偶发的激活失败 setTimeout(async () => await AudioSession.setActive(true), 100); } }
这样调整后,真机上播放和录音的切换应该就正常了,不用再重启APP。我当时就是靠统一管理音频会话和严格释放资源解决的这个问题!




