You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

无法通过MediaRecorder.AudioSource.MIC录制通话,调用start后停止的问题

解决MediaRecorder调用start()后立即停止的通话录制问题

我来帮你梳理下这个问题的常见原因和解决思路,这种调用recorder.start()就停止的情况在通话录音场景里挺普遍的,咱们一步步排查:

1. 权限问题(最常见)

Android对录音和通话相关权限的限制非常严格,尤其是高版本系统:

  • 首先确保清单文件里声明了必要权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 如果存储到外部目录 -->
  • Android 6.0+需要动态申请权限,而且RECORD_AUDIO是危险权限,必须在Activity里主动请求,Service里无法直接触发权限弹窗。建议在APP启动时就完成权限申请,否则录制时会直接失败。
  • 注意:Android 10及以上,系统会优先占用MIC资源用于通话,第三方APP很难通过MIC源录制通话内容,部分定制系统甚至会直接拦截这种请求。

2. MediaRecorder配置顺序与完整性

MediaRecorder的配置有严格的顺序要求,而且你提供的代码里只写到了setAudioEncoder,后面的关键步骤可能缺失:
正确的配置流程应该是:

private void startRecording() throws IOException {
    if (!isRecording) {
        this.isRecording = true;
        recorder = new MediaRecorder(); // 别忘了初始化实例!
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setAudioSamplingRate(8000);
        recorder.setAudioEncodingBitRate(12200);
        recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        // 必须设置输出文件路径(建议用应用私有目录,避免权限问题)
        File outputFile = new File(getExternalFilesDir(null), "call_recording.3gp");
        recorder.setOutputFile(outputFile.getAbsolutePath());
        recorder.prepare(); // 这一步绝对不能少!
        recorder.start();
    }
}

如果跳过prepare()直接调用start(),MediaRecorder会立即崩溃停止,这是很多新手容易踩的坑。

3. Service生命周期被系统回收

你的录制逻辑在Service里,而通话过程中系统可能会因为资源紧张杀掉后台Service,导致录制中断:

  • Android 8.0+要求后台Service必须升级为前台服务,否则启动后5秒内会被系统杀死。你需要在Service里启动前台通知:
private static final String CHANNEL_ID = "call_recording_channel";

@Override
public void onCreate() {
    super.onCreate();
    // 创建通知渠道(Android 8.0+必备)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "通话录制", NotificationManager.IMPORTANCE_LOW);
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);
    }
    // 启动前台服务
    Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("通话录制中")
            .setContentText("正在录制通话音频")
            .setSmallIcon(R.drawable.ic_recording)
            .build();
    startForeground(1, notification);
}

4. 音频焦点冲突

通话时系统会独占音频焦点,你的MediaRecorder请求MIC资源会被系统拒绝:
可以尝试通过AudioManager请求音频焦点,虽然不一定能成功,但值得一试:

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int focusResult = audioManager.requestAudioFocus(
        null,
        AudioManager.STREAM_VOICE_CALL,
        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
);
if (focusResult != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // 焦点获取失败,无法录制
    return;
}

另外,注意:MediaRecorder.AudioSource.VOICE_CALL这个源理论上可以录制通话双方的声音,但这个权限只有系统APP才能获取,普通第三方APP无法使用。

5. 状态管理问题

确保isRecording的状态逻辑正确,避免重复调用start()

  • stopRecording()里要正确释放资源并重置状态:
private void stopRecording() {
    if (isRecording && recorder != null) {
        isRecording = false;
        try {
            recorder.stop();
        } catch (RuntimeException e) {
            // 处理录制未正常启动的情况
            e.printStackTrace();
        }
        recorder.release();
        recorder = null;
    }
}
  • 在Service的onDestroy()方法里也要调用stopRecording(),防止资源泄漏。

内容的提问来源于stack exchange,提问作者M Talha

火山引擎 最新活动