197 lines
3.7 KiB
Markdown
197 lines
3.7 KiB
Markdown
# 04_播放控制与音频焦点流程
|
|
|
|
## 页面按钮控制流程
|
|
|
|
```text
|
|
1. 用户点击蓝牙音乐页面按钮
|
|
↓
|
|
2. BluetoothMusicActivity.onClick()
|
|
↓
|
|
3. 根据按钮 ID 判断动作
|
|
↓
|
|
4. 调用 BtMusicViewModel
|
|
↓
|
|
5. BtMusicViewModel 调用 BtMusicControlManager
|
|
↓
|
|
6. BtMusicControlManager 调用 BtMusicManager
|
|
↓
|
|
7. BtMusicManager 调用 BluetoothAvrcpClient
|
|
↓
|
|
8. BluetoothAvrcpClient 调用 MediaController.TransportControls
|
|
↓
|
|
9. 手机音乐 App 响应
|
|
```
|
|
|
|
## 页面按钮映射
|
|
|
|
| 控件 ID | 方法 | 最终 AVRCP 控制 |
|
|
|---|---|---|
|
|
| `iv_bt_music_pre` | `preBtMusic()` | `skipToPrevious()` |
|
|
| `iv_bt_music_state` | `playBtMusic()` / `pauseBtMusic()` | `play()` / `pause()` |
|
|
| `iv_bt_music_next` | `nextBtMusic()` | `skipToNext()` |
|
|
|
|
## 播放命令详细链路
|
|
|
|
```text
|
|
BluetoothMusicActivity.onClick()
|
|
↓
|
|
mViewModel.playBtMusic()
|
|
↓
|
|
BtMusicViewModel.playBtMusic()
|
|
↓
|
|
BtMusicControlManager.playBtMusic()
|
|
↓
|
|
BtMusicManager.requestFocus()
|
|
↓
|
|
BtMusicAudioManager.requestAudioFocus()
|
|
↓
|
|
BtMusicManager.playBtMusic()
|
|
↓
|
|
BluetoothAvrcpClient.play()
|
|
↓
|
|
TransportControls.play()
|
|
```
|
|
|
|
## 暂停命令详细链路
|
|
|
|
```text
|
|
BluetoothMusicActivity.onClick()
|
|
↓
|
|
mViewModel.pauseBtMusic()
|
|
↓
|
|
BtMusicViewModel.pauseBtMusic()
|
|
↓
|
|
BtMusicControlManager.pauseBtMusic()
|
|
↓
|
|
BtMusicManager.pauseBtMusic()
|
|
↓
|
|
BluetoothAvrcpClient.pause()
|
|
↓
|
|
TransportControls.pause()
|
|
```
|
|
|
|
## 切歌命令详细链路
|
|
|
|
```text
|
|
上一曲:
|
|
BluetoothMusicActivity
|
|
↓
|
|
BtMusicViewModel.preBtMusic()
|
|
↓
|
|
BtMusicControlManager.preBtMusic()
|
|
↓
|
|
BtMusicManager.preBtMusic()
|
|
↓
|
|
BluetoothAvrcpClient.previous()
|
|
↓
|
|
TransportControls.skipToPrevious()
|
|
|
|
下一曲:
|
|
BluetoothMusicActivity
|
|
↓
|
|
BtMusicViewModel.nextBtMusic()
|
|
↓
|
|
BtMusicControlManager.nextBtMusic()
|
|
↓
|
|
BtMusicManager.nextBtMusic()
|
|
↓
|
|
BluetoothAvrcpClient.next()
|
|
↓
|
|
TransportControls.skipToNext()
|
|
```
|
|
|
|
## 音频焦点是什么
|
|
|
|
```text
|
|
音频焦点 = 当前谁有资格出声
|
|
|
|
车机里可能同时有:
|
|
蓝牙音乐
|
|
收音机
|
|
USB 音乐
|
|
视频
|
|
导航播报
|
|
蓝牙电话
|
|
|
|
所以蓝牙音乐播放前必须申请焦点。
|
|
```
|
|
|
|
## 焦点申请流程
|
|
|
|
```text
|
|
1. 用户点击播放
|
|
↓
|
|
2. BtMusicManager.requestFocus()
|
|
↓
|
|
3. BtMusicAudioManager.requestAudioFocus()
|
|
↓
|
|
4. AudioManager.requestAudioFocus()
|
|
↓
|
|
5. 如果返回 AUDIOFOCUS_REQUEST_GRANTED
|
|
↓
|
|
6. setA2dpUnMute()
|
|
↓
|
|
7. isFocus = true
|
|
↓
|
|
8. setMediaButtonEvent()
|
|
↓
|
|
9. 允许执行 AVRCP play()
|
|
```
|
|
|
|
## 焦点变化处理
|
|
|
|
| 焦点变化 | 处理 |
|
|
|---|---|
|
|
| `AUDIOFOCUS_GAIN` | 恢复 A2DP 出声,必要时恢复播放,通知语音当前是蓝牙音乐。 |
|
|
| `AUDIOFOCUS_LOSS` | 释放焦点,暂停蓝牙音乐,清空 Launcher 蓝牙音乐信息。 |
|
|
| `AUDIOFOCUS_LOSS_TRANSIENT` | 临时失焦,A2DP 静音,暂停蓝牙音乐。 |
|
|
| `AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK` | 降低蓝牙音乐音量。 |
|
|
|
|
## 失焦流程
|
|
|
|
```text
|
|
1. 其他音源抢焦点
|
|
↓
|
|
2. BtMusicAudioManager.mAudioFocusListener.onAudioFocusChange()
|
|
↓
|
|
3. 收到 AUDIOFOCUS_LOSS 或 AUDIOFOCUS_LOSS_TRANSIENT
|
|
↓
|
|
4. 记录当前是否正在播放
|
|
↓
|
|
5. setA2dpMute()
|
|
↓
|
|
6. BtMusicManager.pauseBtMusic()
|
|
↓
|
|
7. 手机音乐暂停
|
|
```
|
|
|
|
## 恢复焦点流程
|
|
|
|
```text
|
|
1. 蓝牙音乐重新获得焦点
|
|
↓
|
|
2. 收到 AUDIOFOCUS_GAIN
|
|
↓
|
|
3. isFocus = true
|
|
↓
|
|
4. setA2dpUnMute()
|
|
↓
|
|
5. 如果 isPlayingLossFocus == true
|
|
↓
|
|
6. BtMusicManager.playBtMusic()
|
|
↓
|
|
7. 手机音乐恢复播放
|
|
```
|
|
|
|
## 注意点
|
|
|
|
`BluetoothA2dpSinkClient` 中这两个方法底层调用目前被注释:
|
|
|
|
```text
|
|
setFluorideAudioTrackGain()
|
|
setFluorideStreaming()
|
|
```
|
|
|
|
所以焦点切换时,A2DP 静音/恢复是否真正生效,需要真机验证。
|
|
|