MediaRecorder启动失败错误码-2147483648,通话录音问题求助
这个错误我之前帮不少Android开发者排查过,核心原因大多和系统权限限制以及Android版本对通话录音API的严格管控有关,咱们一步步拆解问题,再给出可行的解决方案:
为什么会出现start failed : -2147483648?
这个错误码对应的是MediaRecorder的非法操作异常,根源在于你使用的MediaRecorder.AudioSource.VOICE_CALL音频源:
- 从Android 10(API 29)开始,Google直接封锁了普通应用调用
VOICE_CALL的权限,只有系统级应用才能使用这个接口; - 就算是Android 10以下的版本,很多国内厂商也早就通过定制系统限制了这个接口的调用,防止隐私泄露。
这就是你调用recorder.start()时直接失败的核心原因。
为什么用VOICE_COMMUNICATION录不到来电者声音?
VOICE_COMMUNICATION是为语音通话场景优化的音频源,但它的设计逻辑是只采集当前设备麦克风的输入,不会捕获对方通过通话链路传输过来的音频,所以自然录不到来电者的声音。
可行的解决方案
1. 适配Android 10+的官方规则
从Android 10开始,普通应用想要录制通话,只能通过MediaProjection API实现——这个API原本是用于屏幕录制,但同时会捕获系统的所有音频(包括通话)。不过这种方式需要用户手动授权"录制屏幕和音频",体验上需要引导用户操作:
- 先申请
RECORD_AUDIO、WRITE_EXTERNAL_STORAGE(Android 13+还要POST_NOTIFICATIONS)权限; - 启动
MediaProjectionManager获取用户授权; - 通过
MediaProjection创建VirtualDisplay,同时录制系统音频。
2. 低版本设备的折中方案(Android 9及以下)
如果你的应用目标用户主要是低版本设备,可以尝试:
- 切换音频源为
MediaRecorder.AudioSource.MIC; - 引导用户开启通话免提,让麦克风直接采集通话声音;
- 这种方式体验一般,但至少能实现录音功能,缺点是依赖免提,音质受环境影响。
3. 检查并完善权限配置
不管用哪种方案,都必须确保权限配置正确:
在AndroidManifest.xml中声明必要权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Android 10+ 访问媒体文件需要 --> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- Android 12+ 通知权限 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
而且这些都是危险权限,必须在运行时动态申请,不能只靠Manifest声明。
优化你的代码示例
针对你的代码,我调整了权限检查、音频源适配和文件创建逻辑,避免一些潜在问题:
import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; import android.media.MediaRecorder; import android.os.Build; import android.os.Environment; import android.widget.Toast; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; public class CallRecorder { private MediaRecorder recorder; private boolean recordstarted = false; private Context context; public CallRecorder(Context context) { this.context = context; } public void SesKayitBaslat(String number) { Toast.makeText(context, "ANSWERED", Toast.LENGTH_LONG).show(); String timeStamp = new SimpleDateFormat("dd-MM-yyyy hh-mm-ss", Locale.getDefault()).format(new Date()); File sampleDir = new File(Environment.getExternalStorageDirectory(), "/ASesKaydi"); if (!sampleDir.exists()) { sampleDir.mkdirs(); } String fileName = "Record_" + timeStamp + ".amr"; File audioFile = new File(sampleDir, fileName); // 先检查权限,没有权限就申请 if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1001); Toast.makeText(context, "请授予录音和存储权限", Toast.LENGTH_SHORT).show(); return; } recorder = new MediaRecorder(); // 根据系统版本选择合适的音频源 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { recorder.setAudioSource(MediaRecorder.AudioSource.MIC); } else { recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION); } recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(audioFile.getAbsolutePath()); try { recorder.prepare(); if (!recordstarted) { recorder.start(); recordstarted = true; Toast.makeText(context, "录音已开始", Toast.LENGTH_SHORT).show(); } } catch (IllegalStateException e) { Toast.makeText(context, "录音启动失败:状态异常", Toast.LENGTH_SHORT).show(); e.printStackTrace(); } catch (IOException e) { Toast.makeText(context, "录音启动失败:IO异常", Toast.LENGTH_SHORT).show(); e.printStackTrace(); } } // 记得添加停止录音的方法 public void SesKayitDurdur() { if (recordstarted && recorder != null) { try { recorder.stop(); recorder.release(); recordstarted = false; Toast.makeText(context, "录音已停止", Toast.LENGTH_SHORT).show(); } catch (IllegalStateException e) { e.printStackTrace(); } } } }
最后提醒
Android平台对通话录音的限制越来越严格,主要是为了保护用户隐私。如果你的应用依赖通话录音功能,最好的方式是引导用户使用手机系统自带的通话录音功能;如果必须自己实现,MediaProjection是目前高版本系统唯一合法的路径,但需要用户主动授权。
内容的提问来源于stack exchange,提问作者Zibian Domichi

