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; } }
五、额外排查点
- 厂商权限限制:进入设备设置→应用管理→你的应用→权限,确认已开启「麦克风」「电话」权限,部分厂商需手动开启「通话录音」权限
- 测试环境:使用真实设备测试,模拟器的通话状态和音频源可能存在异常
- 文件大小检查:打印录音文件的大小,如果为0字节,说明MediaRecorder未正确启动;如果有大小但无声音,需检查音频源或编码器配置
内容的提问来源于stack exchange,提问作者Mariam Donbosco
相关产品推荐
相关产品推荐

