
关于
构建、维护和扩展 EarLLM One Android 项目——一个通过语音管道将蓝牙耳机连接到 LLM 的 Kotlin/Compose 应用
name: earllm-build description: "构建、维护和扩展 EarLLM One Android 项目 — 一个通过语音管道将蓝牙耳机连接到 LLM 的 Kotlin/Compose 应用。" risk: safe source: community date_added: '2026-03-06' author: renat tags:
- android
- kotlin
- bluetooth
- llm
- voice tools:
- claude-code
- antigravity
- cursor
- gemini-cli
- codex-cli
EarLLM One — 构建与维护
概述
构建、维护和扩展 EarLLM One Android 项目 — 一个通过语音管道将蓝牙耳机连接到 LLM 的 Kotlin/Compose 应用。
何时使用此技能
- 当用户提到 "earllm" 或相关主题时
- 当用户提到 "earbudllm" 或相关主题时
- 当用户提到 "earbud app" 或相关主题时
- 当用户提到 "voice pipeline kotlin" 或相关主题时
- 当用户提到 "bluetooth audio android" 或相关主题时
- 当用户提到 "sco microphone" 或相关主题时
不要在以下情况使用此技能
- 任务与 earllm 构建无关时
- 更简单、更具体的工具可以处理请求时
- 用户需要不涉及领域专业知识的通用帮助时
工作原理
EarLLM One 是一个多模块 Android 应用(Kotlin + Jetpack Compose),它从蓝牙耳机捕获语音,进行转录,发送到 LLM,然后将响应语音播放回来。
项目位置
C:\\Users\\renat\\earbudllm
模块依赖图
app ──→ voice ──→ audio ──→ core-logging
│ │
├──→ bluetooth ──→ core-logging
└──→ llm ──→ core-logging
模块与关键文件
| 模块 | 用途 | 关键文件 |
|--------|---------|-----------|
| core-logging | 结构化日志、性能追踪 | EarLogger.kt, PerformanceTracker.kt |
| bluetooth | 蓝牙发现、配对、A2DP/HFP 配置文件 | BluetoothController.kt, BluetoothState.kt, BluetoothPermissions.kt |
| audio | 音频路由(SCO/BLE)、捕获、耳机按钮 | AudioRouteController.kt, VoiceCaptureController.kt, HeadsetButtonController.kt |
| voice | STT(SpeechRecognizer + Vosk 存根)、TTS、管道 | SpeechToTextController.kt, TextToSpeechController.kt, VoicePipeline.kt |
| llm | LLM 接口、存根、OpenAI 兼容客户端 | LlmClient.kt, StubLlmClient.kt, RealLlmClient.kt, SecureTokenStore.kt |
| app | UI、ViewModel、Service、设置、所有界面 | MainViewModel.kt, EarLlmForegroundService.kt, 6 个 Compose 界面 |
构建配置
- SDK: minSdk 26, targetSdk 34, compileSdk 34
- 构建工具: AGP 8.2.2, Kotlin 1.9.22, Gradle 8.5
- Compose BOM: 2024.02.00
- 关键依赖: OkHttp, AndroidX Security (EncryptedSharedPreferences), DataStore, Media
目标硬件
| 设备 | 型号 | 关键详情 | |--------|-------|-------------| | 手机 | Samsung Galaxy S24 Ultra | Android 14, One UI 6.1, Snapdragon 8 Gen 3 | | 耳机 | Xiaomi Redmi Buds 6 Pro | BT 5.3, A2DP/HFP/AVRCP, ANC, LDAC |
关键技术事实
以下是来自官方文档和设备测试的已验证事实。在做决策时将其视为基本事实:
-
蓝牙 SCO 在大多数设备上限制为 8kHz 单声道输入。部分设备支持 16kHz mSBC。BLE Audio(Android 12+,
TYPE_BLE_HEADSET = 26)支持高达 32kHz 立体声。可用时始终优先使用 BLE Audio。 -
startBluetoothSco()自 Android 12(API 31)起已弃用。 请改用AudioManager.setCommunicationDevice(AudioDeviceInfo)和clearCommunicationDevice()。项目已在AudioRouteController.kt中实现了两种路径。 -
Samsung One UI 7/8 存在已知的 HFP 损坏 bug,A2DP 播放会损坏 SCO 链路。应用通过静音检测和自动回退到手机内置麦克风来处理此问题。
-
Redmi Buds 6 Pro 的点击控制必须在小米耳机伴侣应用中设置为"默认"(播放/暂停)。如果设置为 ANC 或自定义功能,事件将由耳机内部处理,永远不会到达 Android。
-
Android 14+ 需要
FOREGROUND_SERVICE_MICROPHONE权限和服务声明中的foregroundServiceType="microphone"。RECORD_AUDIO必须在startForeground()之前获得授权。 -
VOICE_COMMUNICATION音频源启用 AEC(声学回声消除),这对于防止 TTS 音频输出反馈到 STT 麦克风输入至关重要。在不了解回声影响的情况下切勿更改此源。 -
切勿在通过 SCO 录音的同时播放 TTS(A2DP)。 正确的顺序是:停止播放 → 切换到 HFP → 录音 → 切换到 A2DP → 播放响应。
数据流
Headset button tap
→ MediaSession (HeadsetButtonController)
→ TapAction.RECORD_TOGGLE
→ VoicePipeline.toggleRecording()
→ VoiceCaptureController captures PCM (16kHz mono)
→ stopRecording() returns ByteArray
→ SpeechToTextController.transcribe(pcmData)
→ LlmClient.chat(messages)
→ TextToSpeechController.speak(response)
→ Audio output via A2DP to earbuds