You need to enable JavaScript to run this app. React Native实现通话录音:Headless Task录制的通话文件无声音求助
优惠活动
大模型
产品
解决方案
定价
更多

React Native实现通话录音:Headless Task录制的通话文件无声音求助

通话录音无声音的核心原因
  • 首先,react-native-audio-recorder-player 空参调用startRecorder()时,默认使用的录音源是普通麦克风(AudioSource.MIC),该源仅能采集设备周围的环境声,通话过程中系统会将音频通路切换到专用通话链路,普通应用通过MIC源根本拿不到通话的双向音频,自然生成的文件是无声的。
  • 其次,现有原生层配置存在权限拦截问题:给电话状态接收器加了android.permission.BIND_DEVICE_ADMIN权限,该权限仅对设备管理员类应用开放,普通应用注册的接收器带这个属性时,系统发送的PHONE_STATE广播会直接被权限校验拦截,很多时候录音触发流程根本没有真正跑通。
  • 第三,现有代码存在生命周期逻辑漏洞:RecReceiver里的incomingCall是成员变量,安卓系统每次发送广播都会新建BroadcastReceiver实例,该变量永远是初始的false值,无法正确跟踪来电状态,容易导致录音启动/停止时机错位。
  • 第四,现有HeadlessTask的超时设置太短,原代码中任务超时时间为5000ms,远短于正常通话时长,任务会在通话过程中被系统回收,导致录音中断。
具体修复步骤

1. 调整JS层录音启动参数

替换原有空参启动录音的逻辑,在启动时显式指定适配通话场景的录音配置,核心是修正录音源:

// 定义通话录音的配置项
const getCallRecordConfig = () => {
  const timeStamp = Date.now();
  return {
    // 指定可写的录音文件路径,避免外部存储权限兼容问题
    path: `${AudioUtils.DocumentDirectoryPath}/call_${timeStamp}.m4a`,
    // 关键:替换默认的MIC录音源
    // 6 对应安卓原生AudioSource.VOICE_CALL,适配Android 9及以下版本
    // 7 对应安卓原生AudioSource.VOICE_COMMUNICATION,适配高版本系统
    audioSource: 7,
    sampleRate: 44100,
    bitRate: 128000,
    format: 'mpeg4',
    encoder: 'aac'
  }
}

// 在HeadlessTask的Rec函数中替换原有启动逻辑
const Rec = async (data) => {
  try {
    if (data.state === 'extra_state_offhook') {
      // 先清理可能残留的录音监听,避免重复绑定
      audioRecorderPlayer.removeRecordBackListener();
      // 传入正确配置启动录音
      const startResult = await audioRecorderPlayer.startRecorder(getCallRecordConfig());
      console.log('录音启动状态:', startResult);
      audioRecorderPlayer.addRecordBackListener((e) => {
        // 如果一直收不到非0的位置值,说明录音源被系统拦截
        console.log('录音中,当前位置:', e.current_position);
      })
    } else if (data.state === 'extra_state_idle') {
      // 通话结束停止录音
      const stopResult = await audioRecorderPlayer.stopRecorder();
      audioRecorderPlayer.removeRecordBackListener();
      console.log('录音文件路径:', stopResult);
    }
  } catch (err) {
    console.log('录音流程错误:', err)
  }
}

注意:如果高版本Android设备上配置VOICE_CALL源后录音仍无声,可以切换为VOICE_COMMUNICATION源测试,该源是安卓专门为通话类应用开放的录音源,多数国产ROM不会拦截普通应用的调用。

2. 修正Android层配置错误

  • 打开AndroidManifest.xml,找到注册的RecReceiver标签,删掉android:permission="android.permission.BIND_DEVICE_ADMIN"属性,这个权限会导致系统广播无法正常传递到接收器。
  • 清理重复的权限声明:Manifest里CALL_PHONE、PROCESS_OUTGOING_CALLS、STORAGE等权限重复写了多次,删掉重复条目避免编译警告。
  • 修正RecReceiver.java的状态逻辑:不要把来电状态存在接收器的成员变量里,因为每次广播都会新建Receiver实例,成员变量的值不会跨广播保留,所有状态判断直接基于每次Intent携带的参数处理即可,不需要维护全局的incomingCall变量。
  • 适配安卓8.0及以上的后台服务限制:普通应用在后台无法直接通过startService启动普通后台服务,需要把RecService改成前台服务,用startForegroundService启动服务,同时在Service内弹出一个常驻通知,满足安卓后台服务的启动要求,否则系统会直接拦截服务启动,导致HeadlessTask根本跑不起来。

3. 调整HeadlessTask生命周期配置

修改RecService.java中创建HeadlessJsTaskConfig的逻辑,把原来的5000ms超时时间调整为3600000ms(1小时),避免任务因为超时被系统回收,导致录音中断。同时在Service启动后手动持有足够时长的唤醒锁,避免通话过程中系统进入休眠模式打断录音通路。

常见问题排查要点
  • 录音启动后如果回调的current_position一直是0,说明录音源被系统拦截,没有实际采集到音频,这时候需要检查系统权限里的录音权限是否已授予应用,是否被厂商的应用后台管理策略限制了录音能力。
  • 部分定制ROM会强制拦截所有第三方应用的通话录音能力,这种情况没有办法通过代码绕过,需要引导用户在系统设置里给应用开启“通话录音”的特殊权限。

内容的提问来源于stack exchange,提问作者SIDDHANT JOHARI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.23 18:06:07