Skip to content

Repository files navigation

蓝牙麦克风 · BluetoothMic

在录音时强制使用蓝牙耳机的麦克风(如 AirPods),而不是手机自带麦克风。 已在 华为 Pura 70(HarmonyOS 4.2) 实测可用。


中文说明

简介

安卓/鸿蒙系统在普通录音时,即使连接了蓝牙耳机,通常仍然使用手机内置麦克风——只有在"通话"场景(微信语音、系统电话等)才会启用蓝牙耳机的麦克风(走 HFP/SCO 通道)。

本 App 让你在普通录音时也能把收音设备切到蓝牙耳机麦克风,并可在手机麦 / 蓝牙耳机麦之间自由切换、录音对比。

背景与核心难点

要从蓝牙耳机麦克风录音,必须打开蓝牙的 SCO(Synchronous Connection-Oriented) 音频通道。难点在于:

  • 传统做法 AudioManager.startBluetoothSco() 在新系统上已废弃,且在部分厂商 ROM 上行为不一致;
  • 华为设备存在"通话录音白名单":当录音源为 MediaRecorder.AudioSource.VOICE_COMMUNICATION(通话源)时,系统会拦截非白名单 App 从 SCO 麦克风取音,日志表现为:
    [isBtScoRecordAllowed]allowed = false
    [setBlueToothScoState]cur app is not in whitelist
    
    此时即使框架层 getRoutedDevice() 显示已路由到蓝牙,实际采到的仍是手机麦(HAL 层做了替换)。

本项目最初尝试过"注册成自管理 VoIP 通话服务(ConnectionService)"的路线:它确实能把音频路由到蓝牙,但恰恰会触发上述白名单,导致回落到手机麦。该路线已废弃。

解决方案(实测有效)

关键发现:华为的白名单只针对 VOICE_COMMUNICATION 这个"通话录音"源。换一个录音源即可绕开:

  1. AudioManager.setCommunicationDevice(蓝牙SCO设备)(Android 12 / API 31+)——由系统托管 SCO 链路;
  2. AudioRecord 使用 MediaRecorder.AudioSource.VOICE_RECOGNITION 录音(而非 VOICE_COMMUNICATION);
  3. 对旧系统(API < 31)回退到 startBluetoothSco()。

这样全程不触发白名单,SCO 麦克风正常采音。无需 root、无需系统权限、无需 ConnectionService。

验证方法:搓/敲击 AirPods 耳机杆时,录音里出现接近削顶(0 dB)的巨大声响——只有耳机麦贴着耳机杆才可能这么响,据此确认真正用的是耳机麦。

功能

  • 🎙️ 手动选择收音设备:自动(优先蓝牙)/ 蓝牙耳机 / 手机麦克风 / 有线 / USB,方便 A/B 对比;
  • ✅ 实时显示真实收音设备:界面上的设备名直接取自 AudioRecord.getRoutedDevice(),并通过 OnRoutingChangedListener 实时更新,作为可信的 double-check;
  • 🎚️ 自适应采样率:按所选设备能力自动选最高采样率(蓝牙 SCO 封顶 16 kHz,手机麦/有线/USB 可达 44.1~48 kHz);
  • 📄 录音列表:查看历史录音,支持播放 / 分享 / 删除;
  • 💾 录音保存为 WAV(16-bit PCM),位于 App 私有目录。

兼容性

  • 目标/测试机型:华为 Pura 70,HarmonyOS 4.2(Android 12 基座,API 31+)
  • minSdk 24,targetSdk 33
  • 蓝牙耳机麦走 HFP/SCO,为窄带语音,采样率与音质有物理上限;高采样率主要在使用手机麦时才有意义。

构建

# 需要 JDK 17(或 Android Studio 自带 JBR 21),Android SDK(platform 33、build-tools 34.0.0)
./gradlew :app:assembleDebug
# 产物:app/build/outputs/apk/debug/app-debug.apk

或直接用 Android Studio 打开工程点 Run。

工程使用 AGP 8.2.2 / Kotlin 1.9.22 / Gradle 8.5。

使用

  1. 连接蓝牙耳机,打开 App,授予录音 / 蓝牙 / 通知权限;
  2. 在底部"收音设备"下拉框选择要用的麦克风(默认自动优先蓝牙);
  3. 点中间按钮开始录音,界面会显示"实际收音:xxx"确认真实设备;
  4. 再次点击停止,录音保存为 WAV;
  5. 点右上角"录音列表"可播放 / 分享 / 删除。

录音文件位置

Android/data/io.github.asterlight0626.bluetoothmic/files/
  bt_YYYYMMDD_HHMMSS.wav    # 蓝牙耳机麦
  mic_YYYYMMDD_HHMMSS.wav   # 手机/其它麦

项目结构

app/src/main/java/io/github/asterlight0626/bluetoothmic/
  MainActivity.kt        # 主界面:设备选择、权限、开始/停止、显示真实收音设备
  RecordingService.kt    # 前台服务:SCO 路由 + AudioRecord 录音 + 自适应采样率 + WAV
  RecordingsActivity.kt  # 录音列表:播放 / 分享(FileProvider) / 删除

已知限制

  • 蓝牙 SCO 为窄带语音,音质受协议限制(≈16 kHz),无法达到高保真;
  • 华为白名单机制随 ROM 版本可能变化,本方案在 HarmonyOS 4.2 实测有效,其它版本/厂商未逐一验证。

English

Overview

On Android/HarmonyOS, normal audio recording uses the phone's built-in microphone even when a Bluetooth headset is connected — the headset mic (over HFP/SCO) is only used in "call" scenarios (VoIP apps, phone calls).

This app forces recording to use the Bluetooth headset microphone (e.g. AirPods) during ordinary recording, and lets you freely switch between the phone mic and the Bluetooth mic for A/B comparison.

The core challenge

Recording from a Bluetooth mic requires opening the Bluetooth SCO (Synchronous Connection-Oriented) audio channel. The difficulties:

  • The legacy AudioManager.startBluetoothSco() is deprecated and behaves inconsistently across OEM ROMs.
  • Huawei devices enforce a "call-recording whitelist": when the audio source is MediaRecorder.AudioSource.VOICE_COMMUNICATION, the system blocks non-whitelisted apps from capturing the SCO mic:
    [isBtScoRecordAllowed]allowed = false
    [setBlueToothScoState]cur app is not in whitelist
    
    Even though getRoutedDevice() reports Bluetooth, the samples silently fall back to the phone mic (substituted at the HAL layer).

An earlier approach — registering a self-managed VoIP call via ConnectionService — did route audio to Bluetooth, but it triggered exactly this whitelist and fell back to the phone mic. That route was abandoned.

The working solution

Key finding: Huawei's whitelist only targets the VOICE_COMMUNICATION source. Using a different source bypasses it:

  1. AudioManager.setCommunicationDevice(bluetoothScoDevice) (Android 12 / API 31+) — lets the system manage the SCO link;
  2. Record with AudioRecord using MediaRecorder.AudioSource.VOICE_RECOGNITION (not VOICE_COMMUNICATION);
  3. Fall back to startBluetoothSco() on API < 31.

No root, no system privileges, no ConnectionService required.

Verification: rubbing/tapping the AirPods stem produced near-clipping (0 dB) peaks in the recording — only a mic physically on the earbud could pick that up, confirming the Bluetooth mic is truly in use.

Features

  • 🎙️ Manual input-device selection: Auto (prefer Bluetooth) / Bluetooth / phone mic / wired / USB — for easy A/B comparison.
  • ✅ Live, trustworthy device readout: the on-screen device name comes straight from AudioRecord.getRoutedDevice() and updates via OnRoutingChangedListener, as a reliable double-check.
  • 🎚️ Adaptive sample rate: picks the highest rate the chosen device supports (Bluetooth SCO capped at 16 kHz; phone/wired/USB up to 44.1–48 kHz).
  • 📄 Recordings list: play / share / delete saved files.
  • 💾 Saved as WAV (16-bit PCM) in the app's private storage.

Compatibility

  • Target/tested device: Huawei Pura 70, HarmonyOS 4.2 (Android 12 base, API 31+)
  • minSdk 24, targetSdk 33
  • The Bluetooth mic uses HFP/SCO (narrowband voice); sample rate and quality are physically limited. High sample rates matter mainly for the phone mic.

Build

# Requires JDK 17 (or Android Studio's bundled JBR), Android SDK
# (platform 33, build-tools 34.0.0)
./gradlew :app:assembleDebug
# Output: app/build/outputs/apk/debug/app-debug.apk

Or open the project in Android Studio and press Run.

Built with AGP 8.2.2 / Kotlin 1.9.22 / Gradle 8.5.

Usage

  1. Connect a Bluetooth headset, open the app, grant Microphone / Bluetooth / Notification permissions.
  2. Pick the mic in the "Input device" spinner (defaults to auto-prefer-Bluetooth).
  3. Tap the center button to record; the UI shows "Actual input: xxx".
  4. Tap again to stop; the recording is saved as WAV.
  5. Open "Recordings" (top-right) to play / share / delete.

Project structure

app/src/main/java/io/github/asterlight0626/bluetoothmic/
  MainActivity.kt        # UI: device selection, permissions, start/stop, live device readout
  RecordingService.kt    # Foreground service: SCO routing + AudioRecord + adaptive rate + WAV
  RecordingsActivity.kt  # Recordings list: play / share (FileProvider) / delete

Known limitations

  • Bluetooth SCO is narrowband voice (~16 kHz); it cannot reach hi-fi quality.
  • Huawei's whitelist behavior may change across ROM versions; this approach is verified on HarmonyOS 4.2 and not exhaustively tested on other versions/OEMs.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages