React Native安卓外呼录音问题:通话过程无法录制音频
安卓通话录音问题解决思路
问题现状
用React Native开发的安卓外呼录音APP,在Nokia C31(Android 12)上只能录到拨号前后的声音,通话过程完全无录音。尝试将音频源换成VOICE_CALL,但因需要CAPTURE_AUDIO_OUTPUT权限(该权限为系统专属,第三方APP无法获取),直接报错无法启动录音。
问题原因
- 当前使用的
VOICE_COMMUNICATION音频源,在Android 12系统下无法捕获通话双方的音频流,仅能录制设备麦克风的声音;进入通话状态后,系统会限制第三方APP访问通话音频通道。 VOICE_CALL是专门针对通话场景的音频源,但它依赖的CAPTURE_AUDIO_OUTPUT权限属于系统级权限,谷歌明确禁止第三方APP使用,因此直接调用会触发权限错误。
可行解决办法
办法1:通过MediaProjection捕获系统音频
Android 5.0及以上版本支持MediaProjection API,可捕获系统播放的音频,结合麦克风录制用户声音,最后合并两个音频流实现双向录音:
- 操作步骤:
- 在现有权限基础上,新增
MEDIA_CONTENT_CONTROL权限,同时引导用户手动开启屏幕录制权限(MediaProjection必须由用户主动授权)。 - 启动MediaProjection录制系统音频,同时开启麦克风录制用户声音,后期通过音频处理工具合并两个流。
- 在现有权限基础上,新增
- 注意事项:需要用户同意屏幕录制授权,部分设备存在兼容性差异,且需自行实现音频合并逻辑。
办法2:更换音频源+抢占音频焦点
尝试切换到VOICE_RECOGNITION或MIC音频源,配合音频焦点管理提升录音权限优先级:
- 先修改音频源配置:
const audioSet: AudioSet = { AudioEncoderAndroid: AudioEncoderAndroidType.DEFAULT, AudioSourceAndroid: AudioSourceAndroidType.VOICE_RECOGNITION, };
- 启动录音时抢占音频焦点(需安装
react-native-audio-manager库):
import { AudioManager } from 'react-native-audio-manager'; const startRecording = async () => { // 原有文件名、路径设置逻辑... try { await AudioManager.requestAudioFocus(); // 先抢占音频焦点 setIsRecording(true); const result = await audioRecorderPlayer.current.startRecorder( fileName, audioSet, true, ); console.log('start recording', result); } catch (error) { console.error('Error starting recording:', error); await AudioManager.abandonAudioFocus(); // 启动失败则释放焦点 } };
- 注意事项:这种方式仅能录制用户侧声音,对方声音需开启免提模式才能通过麦克风录入。
办法3:集成第三方通话SDK
直接使用自带录音功能的第三方通话SDK(如阿里云通话、容联云等),这类SDK已处理好系统权限和录音逻辑,集成后可直接实现双向录音,无需自行处理底层权限问题。
代码调整示例(办法2)
以下是调整后的录音相关代码参考:
import AudioRecorderPlayer, { AudioEncoderAndroidType, AudioSet, AudioSourceAndroidType, OutputFormatAndroidType, } from 'react-native-audio-recorder-player'; import dayjs from 'dayjs'; import RNFetchBlob from 'rn-fetch-blob'; import { AudioManager } from 'react-native-audio-manager'; const dirs = RNFetchBlob.fs.dirs; // 更换为AAC编码和MPEG_4格式,提升兼容性 const audioSet: AudioSet = { AudioEncoderAndroid: AudioEncoderAndroidType.AAC, AudioSourceAndroid: AudioSourceAndroidType.VOICE_RECOGNITION, OutputFormatAndroid: OutputFormatAndroidType.MPEG_4, }; export default function Dialer() { const audioRecorderPlayer = useRef(new AudioRecorderPlayer()); const startRecording = async () => { const formattedDate = dayjs().format('DD-MMM-YYYY_hh-mm-ss-A'); // 改用m4a格式,比mp3兼容性更好 const fileName = `${dirs.CacheDir}/call-record_${formattedDate}.m4a`; setAudioPath(fileName); try { // 先请求音频焦点 await AudioManager.requestAudioFocus(); setIsRecording(true); const result = await audioRecorderPlayer.current.startRecorder( fileName, audioSet, true, ); console.log('start recording', result); } catch (error) { console.error('Error starting recording:', error); // 启动失败释放焦点 await AudioManager.abandonAudioFocus(); } }; const handleCall = () => { if (!isRecording) { // 等待录音启动成功后再拨号 startRecording().then(() => { Linking.openURL(`tel:${number}`); }); } }; // 停止录音时释放音频焦点 const stopRecording = async () => { try { await audioRecorderPlayer.current.stopRecorder(); await AudioManager.abandonAudioFocus(); setIsRecording(false); } catch (error) { console.error('Error stopping recording:', error); } }; // ...其他业务代码 }
权限补充
需要在权限列表中新增MEDIA_CONTENT_CONTROL:
const permissions = [ PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, PermissionsAndroid.PERMISSIONS.CALL_PHONE, PermissionsAndroid.PERMISSIONS.MEDIA_CONTENT_CONTROL, ];
内容的提问来源于stack exchange,提问作者Hao.Le
相关产品推荐
相关产品推荐

