

# IVS 广播 SDK：移动音频模式 \$1 实时直播功能
<a name="broadcast-mobile-audio-modes"></a>

音频质量是任何真实团队媒体体验的重要组成部分，而且没有适合所有使用案例的“一刀切”音频配置。为了确保您的用户在收听 IVS 直播时获得最佳体验，我们的移动 SDK 提供了多种预设音频配置，并可根据需要提供更强大的自定义设置。

## 简介
<a name="broadcast-mobile-audio-modes-introduction"></a>

IVS 移动广播 SDK 提供了一个 `StageAudioManager` 类。该类旨在成为控制两种平台上的底层音频模式的单一接触点。在 Android 上，它控制 [AudioManager](https://developer.android.com/reference/android/media/AudioManager)，包括音频模式、音频源、内容类型、使用情况和通信设备。在 iOS 上，它控制应用程序 [AVAudioSession](https://developer.apple.com/documentation/avfaudio/avaudiosession)，以及 [voiceProcessing](https://developer.apple.com/documentation/avfaudio/avaudioionode/3152101-voiceprocessingenabled?language=objc) 是否已启用。

**重要提示**：在 IVS 实时广播 SDK 处于活动状态时，请勿与 `AVAudioSession` 或 `AudioManager` 直接交互。那样可能会导致音频丢失，或者在错误的设备上录制或播放音频。

在创建第一个 `DeviceDiscovery` 或 `Stage` 对象之前，必须配置 `StageAudioManager` 类。

------
#### [ Android (Kotlin) ]

```
StageAudioManager.getInstance(context).setPreset(StageAudioManager.UseCasePreset.VIDEO_CHAT) // The default value

val deviceDiscovery = DeviceDiscovery(context)
val stage = Stage(context, token, this)

// Other Stage implementation code
```

------
#### [ iOS (Swift) ]

```
IVSStageAudioManager.sharedInstance().setPreset(.videoChat) // The default value

let deviceDiscovery = IVSDeviceDiscovery()
let stage = try? IVSStage(token: token, strategy: self)

// Other Stage implementation code
```

------

如果在初始化 `DeviceDiscovery` 或 `Stage` 实例之前未在 `StageAudioManager` 上设置任何内容，则会自动应用 `VideoChat` 预设。

## 音频模式预设
<a name="broadcast-mobile-audio-modes-presets"></a>

实时广播 SDK 提供了三种预设，各自针对常见使用案例量身定制，如下文所述。对于每种预设，我们涵盖了五个关键类别，用于将预设相互区分开来。

**音量摇杆**类别是指通过设备上的物理音量摇杆使用或更改的音量类型（媒体音量或通话音量）。请注意，在切换音频模式时，这会影响音量。例如，假设在使用视频聊天预设时将设备音量设置为最大值。切换到“仅订阅”预设会导致与操作系统不同的音量，这可能会导致设备上的音量发生显著变化。

### 视频聊天
<a name="audio-modes-presets-video-chat"></a>

这是默认预设，专为本地设备与其他参与者进行实时对话的应用场景设计。

**iOS 上的已知问题**：使用此预设而不连接麦克风会导致音频通过耳机而不是设备扬声器播放。此预设只能与麦克风组合使用。


| 类别 | Android | iOS | 
| --- | --- | --- | 
| 回声消除 | 已启用 | 已启用 | 
| 音量摇杆 | 通话音量 | 通话音量 | 
| 麦克风选择 | 视操作系统进行限制。USB 麦克风可能不可用。 | 视操作系统进行限制。USB 和蓝牙麦克风可能不可用。 同时处理输入和输出的蓝牙耳机应可正常工作；例如 AirPods。 | 
| 音频输出 | 任何输出设备都应正常工作。 | 视操作系统进行限制。有线耳机可能不可用。 | 
| 音频质量 | 中/低。听起来像是打电话，不像播放媒体。 | 中/低。听起来像是打电话，不像播放媒体。 | 

### 仅订阅
<a name="audio-modes-presets-subscribe-only"></a>

此预设适合用于您计划订阅其他发布参与者但不打算自己发布的情况。它专注于音频质量并支持所有可用的输出设备。


| 类别 | Android | iOS | 
| --- | --- | --- | 
| 回声消除 | 已禁用 | 已禁用 | 
| 音量摇杆 | 媒体音量 | 媒体音量 | 
| 麦克风选择 | 不适用，此预设不适合用于发布。 | 不适用，此预设不适合用于发布。 | 
| 音频输出 | 任何输出设备都应正常工作。 | 任何输出设备都应正常工作。 | 
| 音频质量 | 高。任何媒体类型都应清晰，包括音乐。 | 高。任何媒体类型都应清晰，包括音乐。 | 

### Studio
<a name="audio-modes-presets-studio"></a>

此预设专为高质量订阅设计，同时保持发布能力。它需要录制和播放硬件来消除回声。此处的使用案例是使用 USB 麦克风和有线耳机。该 SDK 将保持最高质量的音频，同时依赖这些设备的物理隔离，以免产生回声。


| 类别 | Android | iOS | 
| --- | --- | --- | 
| 回声消除 | 平台回声消除已禁用，但如果 `StageAudioConfiguration.enableEchoCancellation` 为 true，则仍可能会发生软件回声消除。 | 已禁用 | 
| 音量摇杆 | 大多数情况下的媒体音量。连接蓝牙麦克风时的通话音量。 | 媒体音量 | 
| 麦克风选择 | 任何麦克风都应正常工作。 | 任何麦克风都应正常工作。 | 
| 音频输出 | 任何输出设备都应正常工作。 | 任何输出设备都应正常工作。 | 
| 音频质量 | 高。双方都应能够发送音乐，另一方也能清晰地听见。 连接蓝牙耳机后，由于启用了蓝牙 SCO 模式，音频质量将会下降。 | 高。双方都应能够发送音乐，另一方也能清晰地听见。 连接蓝牙耳机后，由于启用了蓝牙 SCO 模式，音频质量可能会下降，这取决于耳机。 | 

## 高级使用案例
<a name="broadcast-mobile-audio-modes-advanced-use-cases"></a>

除了预设之外，iOS 和 Android 实时流式广播 SDK 都允许配置底层平台的音频模式：
+ 在 Android 上，设置 [AudioSource](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource)、[Usage](https://developer.android.com/reference/android/media/AudioAttributes#USAGE_ALARM) 和 [ContentType](https://developer.android.com/reference/android/media/AudioAttributes#CONTENT_TYPE_MOVIE)。
+ 在 iOS 上，使用 [AVAudioSession.Category](https://developer.apple.com/documentation/avfaudio/avaudiosession/category)、[AVAudioSession.CategoryOptions](https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions)、[AVAudioSession.Mode](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode)，以及在发布时切换是否启用[语音处理](https://developer.apple.com/documentation/avfaudio/avaudioionode/3152101-voiceprocessingenabled?language=objc)的功能。

注意：使用这些音频 SDK 方法时，可能会错误地配置底层音频会话。例如，在 iOS 上将 `.allowBluetooth` 选项与 `.playback` 类别结合使用会产生无效的音频配置，并且 SDK 无法录制或播放音频。这些方法仅在应用程序具有经过验证的特定音频会话要求时使用。

------
#### [ Android (Kotlin) ]

```
// This would act similar to the Subscribe Only preset, but it uses a different ContentType.
StageAudioManager.getInstance(context)
    .setConfiguration(StageAudioManager.Source.GENERIC,
                      StageAudioManager.ContentType.MOVIE,
                      StageAudioManager.Usage.MEDIA);

val stage = Stage(context, token, this)

// Other Stage implementation code
```

------
#### [ iOS (Swift) ]

```
// This would act similar to the Subscribe Only preset, but it uses a different mode and options.
IVSStageAudioManager.sharedInstance()
    .setCategory(.playback,
                 options: [.duckOthers, .mixWithOthers],
                 mode: .default)

let stage = try? IVSStage(token: token, strategy: self)

// Other Stage implementation code
```

------

### iOS 回声消除
<a name="advanced-use-cases-ios_echo_cancellation"></a>

iOS 上的回声消除也可以通过 `IVSStageAudioManager` 使用其 `echoCancellationEnabled` 方法独立控制。此方法控制是否在 SDK 使用的底层 `AVAudioEngine` 的输入和输出节点上启用[语音处理](https://developer.apple.com/documentation/avfaudio/avaudioionode/3152101-voiceprocessingenabled?language=objc)。了解手动更改此属性的影响非常重要：
+ 只有当 SDK 的麦克风处于活动状态时，`AVAudioEngine` 属性才会生效；这是因为 iOS 要求同时在输入和输出节点上启用语音处理，因此这一点很有必要。通常，这会通过使用 `IVSDeviceDiscovery` 返回的麦克风创建要发布的 `IVSLocalStageStream` 来完成。或者，也可以通过将 `IVSAudioDeviceStatsCallback` 附加到麦克风本身来启用麦克风，而无需将其用于发布。如果在使用基于音频源的自定义麦克风而不是 IVS SDK 的麦克风时需要回声消除，则这种替代方法非常有用。
+ 启用 `AVAudioEngine` 属性需要 `.videoChat` 或 `.voiceChat` 模式。请求不同的模式会导致 iOS 的底层音频框架与 SDK 发生冲突，从而导致音频丢失。
+ 启用 `AVAudioEngine` 会自动启用 `.allowBluetooth ` 选项。

行为可能因设备和 iOS 版本不同而有所不同。

### iOS 自定义音频源
<a name="advanced-use-cases-ios_custom_audio_sources"></a>

通过使用 `IVSDeviceDiscovery.createAudioSource`，可以将自定义音频源与 SDK 配合使用。连接到暂存区时，即使未使用 SDK 的麦克风，IVS 实时流式广播 SDK 仍会管理用于音频播放的内部 `AVAudioEngine` 实例。因此，提供给 `IVSStageAudioManager` 的值必须与自定义音频源提供的音频兼容。

如果用于发布的自定义音频源是通过麦克风录制但由主机应用程序管理，则除非激活 SDK 管理的麦克风，否则上述回声消除 SDK 将无法运行。要绕过该要求，请参阅 [iOS 回声消除](#advanced-use-cases-ios_echo_cancellation)。

### 在 Android 系统上使用蓝牙发布
<a name="advanced-use-cases-bluetooth-android"></a>

满足以下条件时，SDK 将自动恢复为 Android 上的 `VIDEO_CHAT` 预设：
+ 分配的配置不使用 `VOICE_COMMUNICATION` 使用值。
+ 蓝牙麦克风已连接到设备。
+ 本地参与者正在向舞台发布内容。

这是 Android 操作系统在如何使用蓝牙耳机录制音频方面的限制。

## 与其他 SDK 集成
<a name="broadcast-mobile-audio-modes-integrating-other-sdks"></a>

由于 iOS 和 Android 对每个应用都仅支持一种活动音频模式，因此如果您的应用使用多个需要控制音频模式的 SDK，则经常会遇到冲突。当您遇到这些冲突时，可以尝试一些常见的解决策略，如下所述。

### 匹配音频模式值
<a name="integrating-other-sdks-match-values"></a>

使用 IVS SDK 的高级音频配置选项或其他 SDK 的功能，使这两种 SDK 在底层值上保持一致。

### Agora
<a name="integrating-other-sdks-agora"></a>

#### iOS
<a name="integrating-other-sdks-agora-ios"></a>

在 iOS 上，让 Agora SDK 将 `AVAudioSession` 保持活动状态可防止在 IVS 实时流式广播 SDK 使用它时它被停用。

```
myRtcEngine.SetParameters("{\"che.audio.keep.audiosession\":true}");
```

#### Android
<a name="integrating-other-sdks-agora-android"></a>

使用 IVS 实时流式广播 SDK 时，避免对 `RtcEngine` 调用 `setEnableSpeakerphone`，而应调用 `enableLocalAudio(false)`。当 IVS SDK 未发布时，您可以再次调用 `enableLocalAudio(true)`。