

# IVS 实时直播功能优化
<a name="real-time-streaming-optimization"></a>

为了确保您的用户在使用 IVS 实时流式传输时获得最佳的视频直播和观看体验，您可以使用我们目前提供的所有功能，通过多种方式对部分体验进行改进或优化。

## 简介
<a name="real-time-streaming-optimization-intro"></a>

在优化用户的体验质量时，务必考虑用户想要的观看体验，这种体验可能会根据其正在观看的内容和网络状况而变化。

在本指南中，我们重点关注流的*发布者*或流的*订阅用户*，并考虑这些用户所需的操作和体验。

使用 IVS SDK 可以配置流的最大比特率、帧速率和分辨率。当发布者出现网络拥塞时，SDK 会自动适应并通过降低比特率、帧速率和分辨率来降低视频质量。在 Android 和 iOS 上，遇到拥塞时可以选择降级偏好。无论您是启用使用联播进行分层编码还是保留默认配置，行为都是相同的。

## 自适应流式传输：通过联播分层编码
<a name="real-time-streaming-optimization-adaptive"></a>

此功能仅在下列客户端版本中受支持：
+ iOS 和 Android 1.18.0\$1
+ Web 1.12.0\$1

使用 IVS [实时广播 SDK](broadcast.md) 时，发布者可以对多层视频进行编码，而订阅用户会自动适应或根据其网络状况更改为最佳质量。我们将之称为*通过联播分层编码*。

Android 和 iOS 以及 Chrome 和 Edge 桌面浏览器（适用于 Windows 和 macOS）均支持通过联播分层编码。但其他浏览器不支持分层编码。

在下图中，主机发送了三种质量（高、中和低）的视频。IVS 根据可用带宽向每位观众发送最高质量的视频；每位观众可以获得最佳视频体验。如果观众 1 的网络连接从良好变为不良，IVS 会自动开始向观众 1 发送较低质量的视频，因而观众 1 可以继续以其所能获得的最佳质量观赏流。

![\[通过联播分层编码，以便根据观众的网络连接质量调整视频质量。\]](http://docs.aws.amazon.com/zh_cn/ivs/latest/RealTimeUserGuide/images/Layered_Encoding_1.png)


### 默认分层、质量和帧率
<a name="real-time-streaming-optimization-default-layers"></a>

为移动平台和 Web 用户提供默认质量和分层，如下所示：


| 移动平台（Android、iOS） | Web（Chrome） | 
| --- | --- | 
| 高级层（或自定义）： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html)  | 高级层（或自定义）： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html)  | 
| 中间层：无（不需要，因为移动平台上高级层和低级层的比特率之间的差异很小） | 中间层： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html)  | 
| 低级层： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html)  | 低级层： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html)  | 

### 图层分辨率
<a name="real-time-streaming-optimization-layer-resolution"></a>

中层和低层的分辨率会自动从高图层缩减，以保持相同的宽高比。

如果中层和低层的分辨率与上层过于接近，则将其排除在外。例如，如果配置的分辨率为 320x180，则 SDK 不会同时发送较低分辨率的图层。

下表显示不同配置分辨率生成的图层的分辨率。列出的值是横向的，但可以反向应用于纵向内容。


| 输入分辨率 | 输出图层分辨率：移动 | 输出层分辨率：Web | 
| --- | --- | --- | 
|  720p (1280x720)  |  高（1280x720） 低（320x180）  |  高（1280x720） 中（640x360） 低（320x180）  | 
|  540p (960x540)  |  高（960x540） 低（320x180）  |  高（960x540） 低（320x180）  | 
|  360p (640x360)  |  高（640x360） 低（360x180）  |  高（640x360） 低（360x180）  | 
|  270p (480x270)  |  高（480x270）  |  高（480x270）  | 
|  180p (320x180)  |  高（320x180）  |  高（320x180）  | 

对于上面未映射的自定义输入分辨率，您可以[使用以下工具](https://codepen.io/amazon-ivs/full/ZENQQvo)进行计算。

### 配置联播分层编码（发布者）
<a name="real-time-streaming-optimization-simulcast"></a>

要在联播中使用分层编码，您必须在客户端上[启用该功能](#real-time-streaming-optimization-adaptive)。如果已启用，您将看到发布者的上传带宽使用量增加，观众的视频冻结可能会减少。

**Android**

```
// Enable Simulcast
StageVideoConfiguration config = new StageVideoConfiguration();
config.simulcast.setEnabled(true);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

**iOS**

```
// Enable Simulcast
let config = IVSLocalStageStreamVideoConfiguration()
config.simulcast.enabled = true

let cameraStream = IVSLocalStageStream(device: camera, configuration: config)

// Other Stage implementation code
```

**Web**

```
// Enable Simulcast
let cameraStream = new LocalStageStream(cameraDevice, {
   simulcast: { enabled: true }
})

// Other Stage implementation code
```

有关配置各个层的详细信息，请参阅每个广播 SDK 指南中的“配置分层编码（发布者）”：[Android](android-publish-subscribe.md#android-layered-encoding-simulcast-configure-publisher)、[iOS](ios-publish-subscribe.md#ios-layered-encoding-simulcast-configure-publisher) 和 [Web](web-publish-subscribe.md#web-layered-encoding-simulcast-configure-publisher)。

### 配置联播分层编码（订阅用户）
<a name="real-time-streaming-optimization-simulcast-subscriber"></a>

要配置订阅用户接收的层，请参阅相应实时流媒体 SDK 指南中的“联播分层编码”部分：
+ [Android 广播 SDK](android-publish-subscribe.md#android-publish-subscribe-layered-encoding-simulcast)
+ [iOS 广播 SDK](ios-publish-subscribe.md#ios-publish-subscribe-layered-encoding-simulcast)
+ [Web 广播 SDK](web-publish-subscribe.md#web-publish-subscribe-layered-encoding-simulcast)

可以通过订阅用户配置来定义 `InitialLayerPreference`。这会决定最初交付的视频质量以及 `preferredLayerForStream`，后者又会决定在视频播放期间选择哪个层。如果层发生了变化、自适应发生了改变或选择了层，有一些事件和流方法可用于发出通知。

## 流式传输配置
<a name="real-time-streaming-configurations"></a>

本节介绍了可对视频和音频流进行的其他配置。

### 更改视频流比特率
<a name="real-time-streaming-changing-bitrate"></a>

要更改视频流的比特率，请使用以下配置示例。

**Android**

```
StageVideoConfiguration config = new StageVideoConfiguration();

// Update Max Bitrate to 1.5mbps
config.setMaxBitrate(1500000);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

**iOS**

```
let config = IVSLocalStageStreamVideoConfiguration();

// Update Max Bitrate to 1.5mbps
try! config.setMaxBitrate(1500000);

let cameraStream = IVSLocalStageStream(device: camera, configuration: config);

// Other Stage implementation code
```

**Web**

```
let cameraStream = new LocalStageStream(camera.getVideoTracks()[0], {
   // Update Max Bitrate to 1.5mbps or 1500kbps
   maxBitrate: 1500
})

// Other Stage implementation code
```

### 更改视频流帧率
<a name="real-time-streaming-changing-framerate"></a>

要更改视频流的帧率，请使用以下配置示例。

**Android**

```
StageVideoConfiguration config = new StageVideoConfiguration();

// Update target framerate to 10fps
config.targetFramerate(10);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

**iOS**

```
let config = IVSLocalStageStreamVideoConfiguration();

// Update target framerate to 10fps
try! config.targetFramerate(10);

let cameraStream = IVSLocalStageStream(device: camera, configuration: config);

// Other Stage implementation code
```

**Web**

```
// Note: On web it is also recommended to configure the framerate of your device from userMedia
const camera = await navigator.mediaDevices.getUserMedia({
   video: {
      frameRate: {
         ideal: 10,
         max: 10,
      },
   },
});

let cameraStream = new LocalStageStream(camera.getVideoTracks()[0], {
   // Update Max Framerate to 10fps
   maxFramerate: 10
})
// Other Stage implementation code
```

### 优化音频比特率和立体声支持
<a name="real-time-streaming-optimize-audio-stream"></a>

要更改音频流的比特率和立体声设置，请使用以下配置示例。

**Web**

```
// Note: Disable autoGainControl, echoCancellation, and noiseSuppression when enabling stereo.
const camera = await navigator.mediaDevices.getUserMedia({
   audio: {
      autoGainControl: false,
      echoCancellation: false,
      noiseSuppression: false
   },
});

let audioStream = new LocalStageStream(camera.getAudioTracks()[0], {
   // Optional: Update Max Audio Bitrate to 96Kbps. Default is 64Kbps
   maxAudioBitrateKbps: 96,

   // Signal stereo support. Note requires dual channel input source.
   stereo: true
})

// Other Stage implementation code
```

**Android**

```
StageAudioConfiguration config = new StageAudioConfiguration();

// Update Max Bitrate to 96Kbps. Default is 64Kbps.
config.setMaxBitrate(96000);

AudioLocalStageStream microphoneStream = new AudioLocalStageStream(microphone, config);

// Other Stage implementation code
```

**iOS**

```
let config = IVSLocalStageStreamConfiguration();

// Update Max Bitrate to 96Kbps. Default is 64Kbps.
try! config.audio.setMaxBitrate(96000);

let microphoneStream = IVSLocalStageStream(device: microphone, config: config);

// Other Stage implementation code
```

### 更改订阅用户抖动缓冲区最小延迟
<a name="real-time-streaming-jitter-buffer-min-delay"></a>

要更改正在订阅的参与者的抖动缓冲区最小延迟，可以使用自定义 `subscribeConfiguration`。抖动缓冲区决定在开始播放之前存储多少数据包。最小延迟表示应存储的最小数据量目标。当面临丢包/连接问题时，更改最小延迟可帮助提高播放弹性。

增加抖动缓冲区大小的代价是也会增加播放开始前的延迟。增加最小延迟可以提高弹性，但代价是影响视频播放时间。请注意，在播放期间增加最小延迟会产生类似的效果：播放将短暂停顿，等待抖动缓冲区填满。

如果需要更高的弹性，则建议最小延迟预设从 `MEDIUM` 开始，并在播放开始之前设置订阅配置。

请注意，最小延迟仅适用于仅订阅的参与者。如果参与者自行发布，则最小延迟不适用。这样做是为了确保多个发布者能够互相交流而不会产生额外的延迟。

以下示例使用的最小延迟预设为 `MEDIUM`。请参阅 SDK 参考文档以了解所有可能的值。

**Web**

```
const strategy = {  
   subscribeConfiguration: (participant) => {
      return {
         jitterBuffer: {
            minDelay: JitterBufferMinDelay.MEDIUM
         }  
      }

   // ... other strategy functions
}
```

**Android**

```
@Override
public SubscribeConfiguration subscribeConfigrationForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
    SubscribeConfiguration config = new SubscribeConfiguration();

    config.jitterBuffer.setMinDelay(JitterBufferConfiguration.JitterBufferDelay.MEDIUM());

    return config;
}
```

**iOS**

```
func stage(_ stage: IVSStage, subscribeConfigurationForParticipant participant: IVSParticipantInfo) -> IVSSubscribeConfiguration {
    let config = IVSSubscribeConfiguration()

    try! config.jitterBuffer.setMinDelay(.medium())

    return config
}
```

## 推荐优化
<a name="real-time-streaming-optimization-suggested"></a>


| 场景 | 建议 | 
| --- | --- | 
| 包含文字或移动缓慢内容的流，例如演示文稿或幻灯片  | 使用[通过联播分层编码](#real-time-streaming-optimization-adaptive)或[配置帧速率较低的流](#real-time-streaming-changing-framerate)。 | 
| 包含动作或大量移动的流 | 使用[通过联播分层编码](#real-time-streaming-optimization-adaptive)。 | 
| 包含对话或少量移动的流  | [通过联播分层编码](#real-time-streaming-optimization-adaptive)或选择纯音频（请参阅《实时流式广播 SDK 指南：[Web](web-publish-subscribe.md#web-publish-subscribe-concepts-strategy-participants)、[Android](android-publish-subscribe.md#android-publish-subscribe-concepts-strategy-participants) 和 [iOS](ios-publish-subscribe.md#ios-publish-subscribe-concepts-strategy-participants)》中的“订阅参与者”）。 | 
| 数据有限的用户流式传输  | 使用[通过联播分层编码](#real-time-streaming-optimization-adaptive)，或者，如果您想降低所有人的数据使用量，可以[配置较低的帧速率](#real-time-streaming-changing-framerate)并[手动降低比特率](#real-time-streaming-changing-bitrate)。 | 