You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 10双向通话录音无音频问题求助(附实现代码)

Android 10通话录音文件无内容问题排查与解决

针对你在Android 10设备上使用MediaRecorder实现通话录音时文件为空的问题,结合系统限制和代码逻辑,整理以下排查修复方案:

一、先明确Android 10的核心限制

Android 10开始,系统严格限制第三方应用访问通话音频:

  • 第三方应用无法使用MediaRecorder.AudioSource.VOICE_CALL(该音频源仅对系统应用开放)
  • 部分厂商(小米、华为等)还会额外限制第三方应用的录音权限,需手动在系统设置中开启

二、权限配置检查

1. 清单文件权限声明

确保AndroidManifest.xml中添加必要权限:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- Android 10+ 写入应用私有目录无需该权限,仅兼容低版本时保留 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />

2. 动态申请危险权限

RECORD_AUDIO和READ_PHONE_STATE属于危险权限,需在代码中动态申请:

private void requestPermissions() {
    String[] permissions = {Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_PHONE_STATE};
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED
            || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, permissions, 100);
    }
}

三、MediaRecorder配置修正

1. 音频源调整

替换无法访问的VOICE_CALL,改用第三方应用可使用的音频源:

// Android 10+ 推荐使用该音频源,适配语音通话场景
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
// 备选:仅录制麦克风输入(只能录到自己的声音)
// mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

2. 文件存储路径优化

Android 10+推荐使用应用私有目录存储录音文件,避免权限问题:

// 获取应用私有外部存储目录
File storageDir = getExternalFilesDir(Environment.DIRECTORY_MUSIC);
audioFile = new File(storageDir, "call_recording_" + System.currentTimeMillis() + ".mp4");
mediaRecorder.setOutputFile(audioFile.getAbsolutePath());

四、录音时机与服务逻辑修复

1. 通话状态监听逻辑

确保在通话真正接通后才启动录音,避免振铃阶段无效启动:

@Override
public void onReceive(Context context, Intent intent) {
    String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
    switch (state) {
        case TelephonyManager.EXTRA_STATE_OFFHOOK:
            // 通话接通,启动前台服务开始录音
            Intent serviceIntent = new Intent(context, MyService.class);
            serviceIntent.setAction("START_RECORD");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                context.startForegroundService(serviceIntent);
            } else {
                context.startService(serviceIntent);
            }
            break;
        case TelephonyManager.EXTRA_STATE_IDLE:
            // 通话结束,停止录音
            Intent stopIntent = new Intent(context, MyService.class);
            stopIntent.setAction("STOP_RECORD");
            context.startService(stopIntent);
            break;
    }
}

2. 前台服务录音流程

确保录音启动、停止的完整流程,避免异常导致文件损坏:

public class MyService extends Service {
    private MediaRecorder mediaRecorder;
    private File audioFile;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if ("START_RECORD".equals(intent.getAction())) {
            startForegroundNotification();
            initRecorder();
            try {
                mediaRecorder.prepare();
                mediaRecorder.start();
            } catch (IOException e) {
                e.printStackTrace();
                stopSelf();
            }
        } else if ("STOP_RECORD".equals(intent.getAction())) {
            stopRecorder();
            stopForeground(true);
            stopSelf();
        }
        return START_STICKY;
    }

    private void initRecorder() {
        mediaRecorder = new MediaRecorder();
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mediaRecorder.setAudioSamplingRate(44100);
        mediaRecorder.setAudioEncodingBitRate(128000);
        
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_MUSIC);
        audioFile = new File(storageDir, "call_recording_" + System.currentTimeMillis() + ".mp4");
        mediaRecorder.setOutputFile(audioFile.getAbsolutePath());
    }

    private void stopRecorder() {
        if (mediaRecorder != null) {
            try {
                mediaRecorder.stop();
            } catch (IllegalStateException e) {
                // 处理录音未启动就停止的异常
                e.printStackTrace();
            } finally {
                mediaRecorder.release();
                mediaRecorder = null;
            }
        }
    }

    private void startForegroundNotification() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("call_recording", "通话录音", NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
        Notification notification = new NotificationCompat.Builder(this, "call_recording")
                .setContentTitle("通话录音中")
                .setContentText("正在录制通话内容")
                .setSmallIcon(R.drawable.ic_recording)
                .build();
        startForeground(1001, notification);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

五、额外排查点

  1. 厂商权限限制:进入设备设置→应用管理→你的应用→权限,确认已开启「麦克风」「电话」权限,部分厂商需手动开启「通话录音」权限
  2. 测试环境:使用真实设备测试,模拟器的通话状态和音频源可能存在异常
  3. 文件大小检查:打印录音文件的大小,如果为0字节,说明MediaRecorder未正确启动;如果有大小但无声音,需检查音频源或编码器配置

内容的提问来源于stack exchange,提问作者Mariam Donbosco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 17:45:47