Android Oreo系统蓝牙耳机录音异常问题求助
看起来你碰到了Android版本升级后蓝牙SCO录音的兼容性坑——Android 8.0(API 26)开始,系统对音频路由和录音源的管理做了大幅调整,之前KitKat到Nougat的适配逻辑在新系统上就失效了。我来给你拆解下问题和对应的解决方案:
1. 替换录音源为VOICE_COMMUNICATION
你之前用的MediaRecorder.AudioSource.MIC是通用麦克风源,在Oreo之后,蓝牙SCO连接建立后系统不会自动把这个源路由到蓝牙设备。换成VOICE_COMMUNICATION就不一样了,这个源是专门为语音通话/通信场景设计的,系统会自动优先将录音输入切换到蓝牙SCO设备。
修改后的AudioRecord配置代码:
final int RECORDER_SAMPLERATE = 8000; final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO; final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT; int bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING); // 替换为专门的通信录音源 recorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, bufferSize);
2. 明确设置音频模式,强制路由到蓝牙SCO
在SCO连接成功后,除了调用setBluetoothScoOn(true),还需要把音频模式设置为MODE_IN_COMMUNICATION,这个模式会告诉系统当前是语音通信场景,必须优先使用蓝牙SCO设备的音频输入输出。
调整你的广播接收器逻辑:
if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state) { am.setMode(AudioManager.MODE_IN_COMMUNICATION); // 新增这行,强制通信模式 am.setBluetoothScoOn(true); unregisterReceiver(this); startRecord(); }
另外,建议在调用startBluetoothSco()之前就先设置好音频模式,避免路由冲突:
am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); am.setMode(AudioManager.MODE_IN_COMMUNICATION); // 提前设置模式 registerReceiver(...); am.startBluetoothSco();
3. 适配Android Oreo的前台服务和权限要求
Android 8.0开始,前台服务必须显示通知,而且录音权限属于危险权限需要动态申请,蓝牙相关权限也得确保到位:
- 动态申请录音权限:在启动录音前检查并申请
RECORD_AUDIO权限
private static final int REQUEST_RECORD_PERMISSION = 101; // 权限检查逻辑 if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_RECORD_PERMISSION); }
- 前台服务通知:Android 8.0+要求前台服务必须绑定通知,否则会被系统杀死,在
startRecord()里添加这段代码:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 创建通知渠道 NotificationChannel channel = new NotificationChannel("BT_RECORD_CHANNEL", "蓝牙录音服务", NotificationManager.IMPORTANCE_LOW); NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); // 创建前台通知 Notification notification = new NotificationCompat.Builder(this, "BT_RECORD_CHANNEL") .setContentTitle("蓝牙录音中") .setSmallIcon(R.drawable.ic_notification) // 替换成你自己的图标 .build(); startForeground(1, notification); }
4. Pixel设备的特殊适配:延迟启动录音
Pixel系列设备对音频路由的管控更严格,SCO连接成功的广播回调可能比系统实际完成路由切换要早,这时候启动录音会失败。可以加个1秒左右的延迟,等系统完成路由切换后再启动录音:
if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state) { am.setMode(AudioManager.MODE_IN_COMMUNICATION); am.setBluetoothScoOn(true); unregisterReceiver(this); // 延迟1秒启动录音,给系统足够时间完成路由切换 new Handler(Looper.getMainLooper()).postDelayed(() -> { startRecord(); }, 1000); }
另外,确认你的蓝牙耳机支持SCO协议(大部分通话耳机都支持,音乐耳机可能需要手动切换到通话模式)。
按上面的步骤调整后,应该就能解决华为荣耀8录音源错误和Pixel 2无法录音的问题了。
内容的提问来源于stack exchange,提问作者Sujith

