> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stmlink.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 音频路由使用

# 音频路由使用说明（meetingSDK）

本文档基于 rtcSDK 中 `AudioRouterManager` 的相关实现整理；在 `meetingSDK` 中使用时，仅需将获取和释放入口适配为 `MeetingEngine`：

```kotlin theme={null}
var audioRouterManager = meetingEngine.getAudioRouterManager()

meetingEngine.releaseAudioRouterManager()
audioRouterManager = null
```

其中 `AudioRouterManager` 类型本身仍然来自 RTC 包：`cn.seastart.rtc.media.audioRouter.AudioRouterManager`。

***

## 1. 获取 `AudioRouterManager`

在 `meetingSDK` 中，应通过 `MeetingEngine` 获取：

```kotlin theme={null}
var audioRouterManager = meetingEngine.getAudioRouterManager()
```

对应释放方式：

```kotlin theme={null}
meetingEngine.releaseAudioRouterManager()
audioRouterManager = null
```

### 说明

* `getAudioRouterManager()` 返回的是可空类型，业务层请做好空判断。
* 从当前 `meetingSDK` 实现看，该方法会透传到底层 RTC 引擎。
* 推荐在**会议页面 / 通话页面**集中持有，不要在每次按钮点击时重复获取和初始化。

***

## 2. 推荐初始化顺序

结合 `meetingSDK` Demo，推荐在进入会议页后按以下顺序初始化：

1. 通过 `meetingEngine.getAudioRouterManager()` 获取管理类
2. 设置回调监听 `setAudioRouterCalllback(...)`
3. 设置音频模式 `setMode(...)`
4. 设置自动切换策略 `setAutoChangeAudioRouter(...)`
5. 调用 `init()` 启动路由监听

完整示例：

```kotlin theme={null}
// 以下示例省略 import

private var audioRouterManager: AudioRouterManager? = null

private fun initAudioRouterManager(meetingEngine: MeetingEngine) {
    audioRouterManager = meetingEngine.getAudioRouterManager()

    // 注意：API 名称为 setAudioRouterCalllback（Calllback 有 3 个 l）
    audioRouterManager?.setAudioRouterCalllback(object :
        AudioRouterManager.AudioRouterCallback {

        override fun exitOutputDeviceChange(
            audioOutputDevices: HashMap<AudioRouterManager.AudioOutputDeviceType?, AudioDeviceInfo?>
        ) {
            // 当前可用输出设备列表变化
            // 例如：插入有线耳机、连接蓝牙耳机、拔出耳机等
        }

        override fun activeOutputDeviceChange(
            audioOutputDevice: Pair<AudioRouterManager.AudioOutputDeviceType, AudioDeviceInfo?>
        ) {
            // 当前实际生效的输出设备变化
        }

        override fun onAudioBecomingNoisy() {
            // 耳机断开等场景下，系统可能切到外放
        }
    })

    // 当前 Demo 会议场景使用 MODE_IN_COMMUNICATION
    audioRouterManager?.setMode(AudioManager.MODE_IN_COMMUNICATION)

    // Demo 实际策略：扬声器优先于听筒；蓝牙优先于有线耳机
    audioRouterManager?.setAutoChangeAudioRouter(true, true, false)

    // 启动路由监听
    audioRouterManager?.init()
}
```

这与当前 Demo 中 `MeetingActivity.kt` 的实现保持一致：

```kotlin theme={null}
audioRouterManager = MeetingEngineHelper.getInstance().engine.getAudioRouterManager()
audioRouterManager?.setAudioRouterCalllback(/* callback */)
audioRouterManager?.setMode(AudioManager.MODE_IN_COMMUNICATION)
audioRouterManager?.setAutoChangeAudioRouter(true, true, false)
audioRouterManager?.init()
```

***

## 3. `setMode` 使用说明

会议 / 通话场景推荐：

```kotlin theme={null}
audioRouterManager?.setMode(AudioManager.MODE_IN_COMMUNICATION)
```

常见模式以 `AudioManager` 为准，例如：

* `AudioManager.MODE_NORMAL`
* `AudioManager.MODE_RINGTONE`
* `AudioManager.MODE_IN_CALL`
* `AudioManager.MODE_IN_COMMUNICATION`

### 说明

* 当前项目 `minSdk = 24`。
* 在当前接入中，建议业务层**主动设置 mode**，不要依赖默认值。
* 如果业务中存在会议、播放、语聊等不同音频场景，切换场景时建议重新调用一次 `setMode(...)`。

***

## 4. `setAutoChangeAudioRouter` 自动切换策略

### 4.1 简单用法

```kotlin theme={null}
audioRouterManager?.setAutoChangeAudioRouter(true)
```

### 4.2 完整用法

```kotlin theme={null}
audioRouterManager?.setAutoChangeAudioRouter(
    isAutoChange = true,
    isPrioritySpeaker = true,
    isPriorityWiredEarphone = false
)
```

参数含义：

* `isAutoChange`
  * `true`：内部自动切换路由
  * `false`：只监听设备变化，由业务层手动切换
* `isPrioritySpeaker`
  * `true`：扬声器优先级高于听筒
  * `false`：听筒优先级高于扬声器
* `isPriorityWiredEarphone`
  * `true`：有线耳机优先级高于蓝牙耳机
  * `false`：蓝牙耳机优先级高于有线耳机

### 4.3 当前 Demo 使用策略

`MeetingActivity.kt` 中使用的是：

```kotlin theme={null}
audioRouterManager?.setAutoChangeAudioRouter(true, true, false)
```

含义是：

* 开启自动切换
* 扬声器优先于听筒
* 蓝牙耳机优先于有线耳机

这比较适合会议扩音类场景。

***

## 5. 回调说明

### 5.1 当前可用输出设备变化

```kotlin theme={null}
override fun exitOutputDeviceChange(
    audioOutputDevices: HashMap<AudioRouterManager.AudioOutputDeviceType?, AudioDeviceInfo?>
) {
}
```

表示当前“可选设备列表”发生变化，例如：

* 连接 / 断开蓝牙耳机
* 插入 / 拔出有线耳机
* 系统输出设备能力发生变化

### 5.2 当前生效输出设备变化

```kotlin theme={null}
override fun activeOutputDeviceChange(
    audioOutputDevice: Pair<AudioRouterManager.AudioOutputDeviceType, AudioDeviceInfo?>
) {
}
```

表示当前真正生效的音频输出设备发生变化。

如果界面要展示“当前正在用扬声器 / 听筒 / 蓝牙耳机”，建议优先以这个回调为准。

### 5.3 路由变化可能产生噪音

```kotlin theme={null}
override fun onAudioBecomingNoisy() {
}
```

典型场景：

* 耳机拔出
* 蓝牙耳机断开
* 系统自动从耳机切换到外放

此时可做一些业务保护，比如：

* 降低音量
* 暂停播放
* 给用户提示

***

## 6. 获取当前可用设备和当前生效设备

### 6.1 获取当前可用输出设备

```kotlin theme={null}
val devices = audioRouterManager?.getExitAudioOutputDevices()
devices?.forEach { (type, info) ->
    val name = info?.productName?.toString() ?: type?.name.orEmpty()
}
```

### 6.2 获取当前活跃输出设备

```kotlin theme={null}
val activeDevice = audioRouterManager?.getActiveAudioOutputDevice()
val activeType = activeDevice?.first
val activeInfo = activeDevice?.second
```

### 6.3 蓝牙名称纠正（可选）

```kotlin theme={null}
AudioRouterManager.getValidBluetoothName(
    curName = activeInfo?.productName?.toString().orEmpty(),
    context = this
) { validName ->
    // validName 为纠正后的蓝牙名称
}
```

> 如果要获取更准确的蓝牙名称，请结合系统版本处理蓝牙权限；Android 12 及以上通常需要关注 `BLUETOOTH_CONNECT`。

***

## 7. 手动切换路由

业务层可在用户点击 UI 时主动切换：

```kotlin theme={null}
audioRouterManager?.switchAudioRouter(selectType)
```

其中 `selectType` 为 `AudioOutputDeviceType`，例如：

```kotlin theme={null}
audioRouterManager?.switchAudioRouter(AudioRouterManager.AudioOutputDeviceType.SPEAKER)
audioRouterManager?.switchAudioRouter(AudioRouterManager.AudioOutputDeviceType.EARPIECE)
audioRouterManager?.switchAudioRouter(AudioRouterManager.AudioOutputDeviceType.WIRED_EARPHONE)
audioRouterManager?.switchAudioRouter(AudioRouterManager.AudioOutputDeviceType.BLUETOOTH_HEADSET)
```

当前 Demo 中就是通过读取可用设备列表，然后弹窗供用户选择：

```kotlin theme={null}
val audioOutputDevices = audioRouterManager?.exitAudioOutputDevices
// 根据设备列表构造可选项
audioRouterManager?.switchAudioRouter(selectType)
```

### 特殊值：`UN_KNOW`

```kotlin theme={null}
audioRouterManager?.switchAudioRouter(AudioRouterManager.AudioOutputDeviceType.UN_KNOW)
```

这里不表示切换到“未知设备”，而是表示：

**按当前自动选路策略重新选择一个最合适的输出路由。**

适合以下场景：

* 恢复默认推荐路由
* 设备插拔后主动要求 SDK 重新选路

***

## 8. 释放资源

推荐在会议页面退出 / 销毁时调用：

```kotlin theme={null}
meetingEngine.releaseAudioRouterManager()
audioRouterManager = null
```

当前 Demo 的实际写法：

```kotlin theme={null}
private fun releaseAudioRouterManager() {
    MeetingEngineHelper.getInstance().engine.releaseAudioRouterManager()
    audioRouterManager = null
}

override fun onDestroy() {
    super.onDestroy()
    releaseAudioRouterManager()
}
```

***

## 9. 常用设备枚举

```kotlin theme={null}
AudioRouterManager.AudioOutputDeviceType.UN_KNOW
AudioRouterManager.AudioOutputDeviceType.SPEAKER
AudioRouterManager.AudioOutputDeviceType.EARPIECE
AudioRouterManager.AudioOutputDeviceType.WIRED_EARPHONE
AudioRouterManager.AudioOutputDeviceType.BLUETOOTH_HEADSET
```

含义如下：

* `UN_KNOW`：未知 / 触发自动重新选路
* `SPEAKER`：扬声器
* `EARPIECE`：听筒
* `WIRED_EARPHONE`：有线耳机
* `BLUETOOTH_HEADSET`：蓝牙耳机

***

## 10. 推荐实践

1. **通过 `MeetingEngine` 暴露的接口接入**，不要在业务层直接依赖底层 `rtcEngine`。
2. **进入会议页时初始化，退出会议页时释放**，避免在单个按钮点击中重复 `init()` / `release()`。
3. **每次切换业务音频场景都重新设置一次 `setMode(...)`**。
4. 展示“当前使用中的设备”时，以 `activeOutputDeviceChange(...)` 为准。
5. 展示“当前可选设备列表”时，以 `exitOutputDeviceChange(...)` 或 `getExitAudioOutputDevices()` 为准。
6. 蓝牙 / 有线耳机 / 扬声器 / 听筒切换建议在真机上完整验证。
7. 当前文档中的 `meetingEngine` 默认表示你已经持有的 `MeetingEngine` 实例。
