# SDK 升级后的 API 设置 (/zh-CN/realtime-media/rtc/reference/after-migrate)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="android" />
声网支持将 RTC SDK 从 2.x、3.x、4.0.0 Preview 或 4.0.0 Beta 版本升级到 4.x 版本，升级步骤以及版本间的变更介绍见[迁移指南](/zh-CN/realtime-media/rtc/reference/migration-guide)。

本文介绍在 SDK 升级后需要修改 API 以及相关实现代码的场景，以帮助你顺利完成迁移。

:::info[信息]
如无特别说明，本文 API 名称均以 C++ 为例，平台均以 Windows 为例。
:::

## 升级前版本为 2.x 或 3.x [#升级前版本为-2x-或-3x]

如果你已经在 v2.x 或 v3.x 中用到了本节介绍的功能和场景，可参考对应示例更新 App 代码。

### 单频道 [#单频道]

本节提供单频道中常用功能的示例代码。

#### 初始化引擎 [#初始化引擎]

**v2.x & v3.x**

- Android: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Basic/JoinChannelVideo)

**v4.x**

- Android: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Basic/JoinChannelVideo)

#### 默认发布麦克风和摄像头采集的音视频流 [#默认发布麦克风和摄像头采集的音视频流]

**v2.x & v3.x**

```cpp
// 通过 muteLocalAudioStream 和 muteLocalVideoStream 控制是否发流
// true 为暂停发布音频流，false 为继续发布音频流
m_rtcEngine->muteLocalAudioStream(false);
// true 为暂停发布视频流，false 为继续发布视频流
m_rtcEngine->muteLocalVideoStream(false);
```

**v4.x**

```cpp
// m_rtcEngine 可以定义为 IRtcEngine* 或者 IRtcEngineEx*
// IRtcEngineEx 继承自 IRtcEngine，拥有更丰富的 API 以及多频道的能力
// 建议通过 ChannelMediaOptions 精细化控制音视频流的发布
// 注意：v4.x 默认可通过 ChannelMediaOptions 精细化控制音视频的发布及订阅
ChannelMediaOptions options;
options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
// true 为订阅音频流，false 为不订阅音频流
options.autoSubscribeAudio = true;
// true 为订阅视频流，false 为不订阅视频流
options.autoSubscribeVideo = true;
// true 为发布麦克风采集的音频流，false 为不发布
options.publishMicrophoneTrack = true;
// true 为发布摄像头采集的视频流，false 为不发布
options.publishCameraTrack = true;
// ex 频道则需使用 updateChannelMediaOptionsEx 替代
m_rtcEngine->updateChannelMediaOptions(options);
```

#### 将视频源从摄像头切换为共享的屏幕 [#将视频源从摄像头切换为共享的屏幕]

**v2.x & v3.x**

```cpp
SIZE size; size.cx = 100;
size.cy = 100;
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index);
ScreenCaptureParameters capParam;
// 根据实际需求，调用 startScreenCaptureByDisplayId、startScreenCaptureByWindowId 或 startScreenCaptureByScreenRect 来共享屏幕
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

**v4.x**

```cpp
SIZE size;
size.cx = 100;
size.cy = 100;
agora::rtc::Rectangle regionRect = { 0, 0, 0, 0 };
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index); ScreenCaptureParameters capParam;
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
ChannelMediaOptions options;
options.publishCameraTrack = false;
// 发布屏幕共享流
options.publishScreenTrack = true;
m_rtcEngine->updateChannelMediaOptions(options);
......
// 停止发布屏幕共享流
options.publishScreenTrack = false;
m_rtcEngine->updateChannelMediaOptions(options)
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

#### 发布 mp4 视频 [#发布-mp4-视频]

**v2.x & v3.x**
需要独立进程并通过 MediaPlayer Kit 实现，详见[媒体播放器组件（3.x）](/zh-CN/realtime-media/rtc/build/audio/media-player)。

**v4.x**
初始化 MediaPlayer。

详见[媒体播放器](/zh-CN/realtime-media/rtc/build/audio/media-player)。

1. 发布麦克风和摄像头采集的流

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    // 默认发布麦克风采集的音频流
    options.publishMicrophoneTrack = true;
    // 默认发布摄像头采集的视频流
    options.publishCameraTrack = true;
    // 加入频道
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 切换为发布媒体播放器的音视频流

    ```cpp
    IMediaPlayer* m_mediaPlayer = m_rtcEngine->createMediaPlayer().get();
    ChannelMediaOptions options;
    // 停止发布麦克风采集的音频流
    options.publishMicrophoneTrack = false;
    // 停止发布摄像头采集的视频流
    options.publishCameraTrack = false;
    // 指定发布的媒体播放器的 playerId
    options.publishMediaPlayerId = m_mediaPlayer->getMediaPlayerId();
    // 切换为媒体播放器的音频流
    options.publishMediaPlayerAudioTrack = true;
    // 切换为媒体播放器的视频流
    options.publishMediaPlayerVideoTrack = true;
    m_rtcEngine->updateChannelMediaOptions(options);
    ```

### 多频道 [#多频道]

本节提供多频道中常用功能的示例代码。

#### 加入多频道 [#加入多频道]

**v2.x & v3.x**
单进程只能发布一路流。加入多频道后，同一时间只能在一个频道发布一路流，其他频道只能订阅流不能发布流。如果需要发布多路流，则需要开多个进程。详见：

- Android：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/JoinMultipleChannel.java)
- iOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/iOS/APIExample/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift)
- Windows：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/MultiChannel)
- macOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/macOS/APIExample/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift)

**v4.x**
支持在单进程中加入多频道，并且同一时间可以在多个频道中发布音视频流。详见：

- Android：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/JoinMultipleChannel.java)
- iOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/JoinMultiChannel)
- Windows：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/MultiChannel)
- macOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/JoinMultiChannel)

#### 默认在两个频道发布流 [#默认在两个频道发布流]
例如：

- 在 `channel1` 发布麦克风和摄像头采集的流。
- 在 `channel2` 发布屏幕共享流。

**v2.x & v3.x**
不支持单进程同时在两个频道发布音视频流，所以需要通过多进程分别创建引擎。

1. 进程 1 发布摄像头流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->enableVideo();
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    ```

2. 进程 2 发布屏幕共享流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
    ```

**v4.x**
支持单进程直接在多个频道内发布音视频流。

1. 发布摄像头流。

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    options.publishCameraTrack = true;
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 发布屏幕共享流。

    ```cpp
    // 指定待分享的屏幕
    agora::rtc::Rectangle rc;
    ScreenCaptureParameters scp;
    scp.frameRate = 15;
    scp.bitrate = 0;
    HWND hWnd = ::GetDesktopWindow();
    RECT destop_rc;
    ::GetWindowRect(hWnd, &destop_rc);
    scp.dimensions.width = destop_rc.right - destop_rc.left;
    scp.dimensions.height = destop_rc.bottom - destop_rc.top;
    m_rtcEngine->startScreenCaptureByScreenRect(rc, rc, scp);
    // 加入多频道
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    // 如果是加入同一频道，则不必重复订阅音频流
    options.autoSubscribeAudio = false;
    // 如果是加入同一频道，则不必重复订阅视频流
    options.autoSubscribeVideo = false;
    // ex 频道不发布摄像头流
    options.publishCameraTrack = false;
    // ex 频道不发布麦克风流
    options.publishMicrophoneTrack = false;
    // ex 频道发布屏幕共享流
    options.publishScreenTrack = true;
    agora::rtc::RtcConnection connection;
    connection.channelId = szChannelId;
    // 自定义 uid
    connection.localUid = screenId;
    m_rtcEngine->joinChannelEx(APP_TOKEN, connection, options, &eventHandlerScreen);
    ```

### 屏幕共享 [#屏幕共享]

本节提供屏幕共享的示例代码。

#### 集成方式 [#集成方式]
**v2.x & v3.x**
直接调用屏幕共享方法，无需集成屏幕共享插件。

**v4.x**
需在调用屏幕共享方法之前集成如下屏幕共享插件：

- Android: `AgoraScreenShareExtension.aar` 和 `libagora_screen_capture_extension.so`
- iOS/macOS: `AgoraReplayKitExtension.xcframework`
- Windows: `libagora_screen_capture_extension.dll`

#### 实现方法 [#实现方法]

**v2.x & v3.x**

- Android：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiProcess.java)
- iOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)
- Windows：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)
- macOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/ScreenShare)

**v4.x**

- Android：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchCameraScreenShare.java)
- iOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/Agora-ScreenShare-Extension)
- Windows：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp)
- macOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/ScreenShare)

### 自定义采集 [#自定义采集]

如果你在 v2.x 或 v3.x 使用了自采集功能，例如通过视频自采集使用第三方美颜，声网推荐你在 v4.x 使用功能完善且更易用的 SDK 采集。

:::info[信息]
v4.x 完善了 SDK 的视频模块并在 Android 上支持了 Texture 格式。一般情况下，声网推荐用户在升级后使用 SDK 采集。在特殊场景下，例如用户需要统一对接不同厂商的 SDK，则可沿用原有自采集方案。v4.x 的 SDK 采集相对于自采集有如下优势：

    - 易用性高：用户不需要处理视频采集、机型适配、采集 Profile 策略，最大程度降低 App 代码复杂度并减少因采集导致的问题。此外，SDK 采集可以更好地避免音画不同步的问题。
    - 问题调查成本低：SDK 支持上传采集分辨率、帧率、美颜耗时等数据，声网后台会进行数据分析，从而快速、清晰地定位丢帧等问题原因。
    - 维护成本低：SDK 采集有研发团队持续迭代优化，QA 测试也比较完善。自采集插件主要是重要问题修复，缺乏持续迭代。
    - 问题修复速度快：采集策略可以配置下发，部分机型问题可以快速修复。
    - 其他须知：MediaIO 相关的 API 在 v4.x 中已删除，需要改用 Push 模式。
:::

**v2.x & v3.x**

- Android：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/customaudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [PushExternalVideo（Push 方式）](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/PushExternalVideo.java)
    - [SwitchExternalVideo（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchExternalVideo.java)
- iOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及示例项目：
    - [CustomAudioSource](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomAudioSource)
    - [ExternalAudio](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Common/ExternalAudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoSourcePush（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourceMediaIO（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomVideoSourceMediaIO)
- Windows：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/CustomAudioCapture)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoCapture（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/CustomVideoCapture)
    - [MediaIOCustomVideoCaptrue（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/MediaIOCustomVideoCaptrue)
- macOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及示例项目：
    - [CustomAudioSource](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomAudioSource)
    - [ExternalAudio](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Common/ExternalAudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoSourcePush（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourceMediaIO（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/CustomVideoSourceMediaIO)

**v4.x**

- Android：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/customaudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [PushExternalVideoYUV（Push 方式）](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/PushExternalVideoYUV.java)
    - [MultiVideoSourceTracks（Video Track 方式）](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiVideoSourceTracks.java)
- iOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioSource)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例代码：
    - [CustomVideoSourcePush（Push方式）](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourcePushMulti（Video Track 方式）](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomVideoSourcePushMulti)
- Windows：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/CustomAudioCapture)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/CustomVideoCapture)
- macOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/CustomAudioSource)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/CustomVideoSourcePush)

在设置视频采集的过程中，你可能会有如下疑问：

Q: `stopPreview`、`enableLocalVideo`、`muteLocalVideoStream` 有什么区别？

A: 三个 API 区别如下：

- `stopPreview` 用于停止本地预览，不会停止本地视频采集或发布本地视频流。
- `enableLocalVideo(false)` 用于停止本地视频采集。例如，App 切后台需要停止视频采集的情况。
- `muteLocalVideoStream(true)` 用于停止发布本地视频流。例如，App 希望保持占用摄像头但停止发布视频流的情况。

Q: 推荐在什么时机注册原始数据回调？

A: 用户在主播角色下调用 `joinChannel` 时会自动启动摄像头，所以建议用户在初始化引擎后直接调用 `registerVideoFrameObserver`。

## 升级前版本为 v4.0.0 Preview 或 v4.0.0 Beta [#升级前版本为-v400-preview-或-v400-beta]

#### 中断性变化 [#中断性变化]

- 删除了 `AUDIO_SCENARIO_TYPE` 中的 `AUDIO_SCENARIO_HIGH_DEFINITION`，改用功能一致的 `AUDIO_SCENARIO_GAME_STREAMING`。
- 修改了 `option` 命名，明确了对于 microphone track 的控制定义。将 `ChannelMediaOptions` 中的 `publishAudioTrack` 变更为 `publishMicrophoneTrack`。
- 为了丰富多路流功能的多样性，在视频流相关的回调事件中增加了视频源类型参数。例如：`onFirstLocalVideoFrame`、`onFirstLocalVideoFramePublished`、`onVideoSizeChanged`、`onVideoPublishStateChanged`、`onLocalVideoStats`、`onLocalVideoStateChanged`。
- 旁路推流  API 优化：
  - 为降低旁路推流集成难度，该版本优化了推流 API 设计，并改善了推流客户端和服务端内部对网络问题的处理机制。你可以通过如下方法体验优化后的旁路推流功能：
    - `startRtmpStreamWithoutTranscoding`: 开始非转码推流。与旧推流方法 `addPublishStreamUrl(false)` 作用相同。
    - `startRtmpStreamWithTranscoding`: 开始 CDN 直播推流并设置转码属性。与依次调用旧推流方法 `setLiveTranscoding`、`addPublishStreamUrl(true)` 的作用相同。
    - `updateRtmpTranscoding`: 更新转码属性。与非首次调用旧推流方法 `setLiveTranscoding` 的作用相同。
    - `stopRtmpStream`: 结束 CDN 直播推流。与旧推流方法 `removePublishStreamUrl` 作用相同。
    - （仅 Android 平台）`onRtmpStreamingStateChanged` 回调中的所有参数类型改为 Int 类型。
  - 该版本废弃 `addPublishStreamUrl`、`setLiveTranscoding`、`removePublishStreamUrl` 这三个旧推流方法，声网推荐你使用新的推流方法，并参考[旁路推流](/zh-CN/realtime-media/media-push)更新你的业务代码逻辑。
- 删除 `startAudioMixing` 中的 `replace`（Bool 类型）参数。`startAudioMixing` 默认发送麦克风音频和媒体播放器音频的混音，如果需要停止发送麦克风音频，你可以根据是否要继续录音，调用以下方法：
  - 需要录音：调用 `updateChannelMediaOptions` 将 `publishMicrophoneTrack` 设置为 `false`，此时麦克风仍然打开。
  - 不需要录音：调用 `enableLocalAudio` 关闭麦克风。
- （仅 Android 平台）`onRemoteAudioStateChanged` 回调中的所有参数类型改为 Int 类型。

#### 行为变更 & 新增 API [#行为变更--新增-api]

- `IAudioFrameObserver` 新增回调 `getObservedAudioFramePosition`、`getRecordAudioParams`、`getPlaybackAudioParams`、`getMixedAudioParams`。
- 屏幕共享采用插件方式，详见[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)。
- `enableVirtualBackground` 方法新增 `SegmentationProperty` 和 `segProperty` 参数。

## 参考信息 [#参考信息]

下表展示一些常用 API 在不同版本的区别：

<Tabs defaultValue="stream-controls" groupId="rtc-upgrade-reference-android">
<TabsList>
  <TabsTrigger value="stream-controls">音视频流控制</TabsTrigger>
  <TabsTrigger value="role-preview">角色与预览</TabsTrigger>
  <TabsTrigger value="local-capture">本地采集</TabsTrigger>
</TabsList>

<TabsContent value="stream-controls">

| 常用 API | muteLocalAudioStream | muteLocalVideoStream |
| --- | --- | --- |
| v2.x & v3.x | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalAudioStream` 的设置。 | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalVideoStream` 设置。 |
| v4.0.0 Preview 或 v4.0.0 Beta | 功能等同于更新发布流控制 `ChannelMediaOptions.publishAudioTrack`。如果频道内主播调用该方法并将参数设置为 `false` 则会打开麦克风。 | 等同于更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalAudioStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishMicrophoneTrack` 为 `true`， `muteLocalAudioStream` 为  `true`，则仍然不发送音频。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalVideoStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishCameraTrack` 为 `true`，`muteLocalVideoStream` 为 `true`，  仍然不发送视频。

</TabsContent>

<TabsContent value="role-preview">

| 常用 API | setClientRole | startPreview |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x（不支持多路上行流，不能同时在多频道中设置为主播）。 | 同 v4.x。 |
| v4.0.0 Preview 或 v4.0.0 Beta | `setClientRole` 会受到 `muteLocalAudioStream` 和 `muteLocalVideoStream` 的影响。例如，如果先调用 `muteLocalAudioStream(true)` 和 `muteLocalVideoStream(true)`， 再调用 `setClientRole` 为主播，主播仍然不能发流。 | 需要主动调用 `startPreview`/`stopPreview`，以开启/关闭本地视图。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1) | 加入频道时，主播角色发布摄像头采集的视频流时，会自动开启本地视图。如果 App 主动调用 `startPreview`，则离开频道时也需要主动调用 `stopPreview` 以关闭本地视图。 |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details**

- `setClientRole` 优先级高于  `enableLocalAudio`/`enableLocalVideo`。
- 如果在加入频道前调用该方法，SDK  会先记录该状态。
- 如果进频道后切换用户角色为主播，会根据 `enableLocalAudio`/`enableLocalVideo` 的状态，打开媒体采集并自动发布。
- 如果切换用户角色为观众，则会关闭采集并停止发布。
- 在多频道场景中，用户可以在每个频道都切换为主播角色，从而进行发流。在频道中，通过  `updateChannelMediaOptionsEx` 控制流发布。

</TabsContent>

<TabsContent value="local-capture">

| 常用 API | enableLocalAudio | enableLocalVideo |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x | 同 v4.x |
| v4.0.0 Preview 或 v4.0.0 Beta | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2) |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭麦克风。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制  `ChannelMediaOptions.publishAudioTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭摄像头。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details**

- 如果在频道外调用，不会打开/关闭麦克风，且加入频道后会自动打开/关闭麦克风。
- 如果在频道内调用，会打开/关闭麦克风。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details**

- 如果在频道外调用，不会打开/关闭摄像头，且加入频道后会自动打开/关闭摄像头。
- 如果在频道内调用，会打开/关闭摄像头。

</TabsContent>
</Tabs>
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="ios" />
声网支持将 RTC SDK 从 2.x、3.x、4.0.0 Preview 或 4.0.0 Beta 版本升级到 4.x 版本，升级步骤以及版本间的变更介绍见[迁移指南](/zh-CN/realtime-media/rtc/reference/migration-guide)。

本文介绍在 SDK 升级后需要修改 API 以及相关实现代码的场景，以帮助你顺利完成迁移。

:::info[信息]
如无特别说明，本文 API 名称均以 C++ 为例，平台均以 Windows 为例。
:::

## 升级前版本为 2.x 或 3.x [#升级前版本为-2x-或-3x-1]

如果你已经在 v2.x 或 v3.x 中用到了本节介绍的功能和场景，可参考对应示例更新 App 代码。

### 单频道 [#单频道-1]

本节提供单频道中常用功能的示例代码。

#### 初始化引擎 [#初始化引擎-1]

**v2.x & v3.x**

- Android: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Basic/JoinChannelVideo)

**v4.x**

- Android: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Basic/JoinChannelVideo)

#### 默认发布麦克风和摄像头采集的音视频流 [#默认发布麦克风和摄像头采集的音视频流-1]

**v2.x & v3.x**

```cpp
// 通过 muteLocalAudioStream 和 muteLocalVideoStream 控制是否发流
// true 为暂停发布音频流，false 为继续发布音频流
m_rtcEngine->muteLocalAudioStream(false);
// true 为暂停发布视频流，false 为继续发布视频流
m_rtcEngine->muteLocalVideoStream(false);
```

**v4.x**

```cpp
// m_rtcEngine 可以定义为 IRtcEngine* 或者 IRtcEngineEx*
// IRtcEngineEx 继承自 IRtcEngine，拥有更丰富的 API 以及多频道的能力
// 建议通过 ChannelMediaOptions 精细化控制音视频流的发布
// 注意：v4.x 默认可通过 ChannelMediaOptions 精细化控制音视频的发布及订阅
ChannelMediaOptions options;
options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
// true 为订阅音频流，false 为不订阅音频流
options.autoSubscribeAudio = true;
// true 为订阅视频流，false 为不订阅视频流
options.autoSubscribeVideo = true;
// true 为发布麦克风采集的音频流，false 为不发布
options.publishMicrophoneTrack = true;
// true 为发布摄像头采集的视频流，false 为不发布
options.publishCameraTrack = true;
// ex 频道则需使用 updateChannelMediaOptionsEx 替代
m_rtcEngine->updateChannelMediaOptions(options);
```

#### 将视频源从摄像头切换为共享的屏幕 [#将视频源从摄像头切换为共享的屏幕-1]

**v2.x & v3.x**

```cpp
SIZE size; size.cx = 100;
size.cy = 100;
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index);
ScreenCaptureParameters capParam;
// 根据实际需求，调用 startScreenCaptureByDisplayId、startScreenCaptureByWindowId 或 startScreenCaptureByScreenRect 来共享屏幕
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

**v4.x**

```cpp
SIZE size;
size.cx = 100;
size.cy = 100;
agora::rtc::Rectangle regionRect = { 0, 0, 0, 0 };
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index); ScreenCaptureParameters capParam;
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
ChannelMediaOptions options;
options.publishCameraTrack = false;
// 发布屏幕共享流
options.publishScreenTrack = true;
m_rtcEngine->updateChannelMediaOptions(options);
......
// 停止发布屏幕共享流
options.publishScreenTrack = false;
m_rtcEngine->updateChannelMediaOptions(options)
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

#### 发布 mp4 视频 [#发布-mp4-视频-1]

**v2.x & v3.x**
需要独立进程并通过 MediaPlayer Kit 实现，详见[媒体播放器组件（3.x）](/zh-CN/realtime-media/rtc/build/audio/media-player)。

**v4.x**
初始化 MediaPlayer。

详见[媒体播放器](/zh-CN/realtime-media/rtc/build/audio/media-player)。

1. 发布麦克风和摄像头采集的流

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    // 默认发布麦克风采集的音频流
    options.publishMicrophoneTrack = true;
    // 默认发布摄像头采集的视频流
    options.publishCameraTrack = true;
    // 加入频道
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 切换为发布媒体播放器的音视频流

    ```cpp
    IMediaPlayer* m_mediaPlayer = m_rtcEngine->createMediaPlayer().get();
    ChannelMediaOptions options;
    // 停止发布麦克风采集的音频流
    options.publishMicrophoneTrack = false;
    // 停止发布摄像头采集的视频流
    options.publishCameraTrack = false;
    // 指定发布的媒体播放器的 playerId
    options.publishMediaPlayerId = m_mediaPlayer->getMediaPlayerId();
    // 切换为媒体播放器的音频流
    options.publishMediaPlayerAudioTrack = true;
    // 切换为媒体播放器的视频流
    options.publishMediaPlayerVideoTrack = true;
    m_rtcEngine->updateChannelMediaOptions(options);
    ```

### 多频道 [#多频道-1]

本节提供多频道中常用功能的示例代码。

#### 加入多频道 [#加入多频道-1]

**v2.x & v3.x**
单进程只能发布一路流。加入多频道后，同一时间只能在一个频道发布一路流，其他频道只能订阅流不能发布流。如果需要发布多路流，则需要开多个进程。详见：

- Android：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/JoinMultipleChannel.java)
- iOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/iOS/APIExample/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift)
- Windows：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/MultiChannel)
- macOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/macOS/APIExample/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift)

**v4.x**
支持在单进程中加入多频道，并且同一时间可以在多个频道中发布音视频流。详见：

- Android：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/JoinMultipleChannel.java)
- iOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/JoinMultiChannel)
- Windows：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/MultiChannel)
- macOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/JoinMultiChannel)

#### 默认在两个频道发布流 [#默认在两个频道发布流-1]
例如：

- 在 `channel1` 发布麦克风和摄像头采集的流。
- 在 `channel2` 发布屏幕共享流。

**v2.x & v3.x**
不支持单进程同时在两个频道发布音视频流，所以需要通过多进程分别创建引擎。

1. 进程 1 发布摄像头流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->enableVideo();
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    ```

2. 进程 2 发布屏幕共享流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
    ```

**v4.x**
支持单进程直接在多个频道内发布音视频流。

1. 发布摄像头流。

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    options.publishCameraTrack = true;
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 发布屏幕共享流。

    ```cpp
    // 指定待分享的屏幕
    agora::rtc::Rectangle rc;
    ScreenCaptureParameters scp;
    scp.frameRate = 15;
    scp.bitrate = 0;
    HWND hWnd = ::GetDesktopWindow();
    RECT destop_rc;
    ::GetWindowRect(hWnd, &destop_rc);
    scp.dimensions.width = destop_rc.right - destop_rc.left;
    scp.dimensions.height = destop_rc.bottom - destop_rc.top;
    m_rtcEngine->startScreenCaptureByScreenRect(rc, rc, scp);
    // 加入多频道
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    // 如果是加入同一频道，则不必重复订阅音频流
    options.autoSubscribeAudio = false;
    // 如果是加入同一频道，则不必重复订阅视频流
    options.autoSubscribeVideo = false;
    // ex 频道不发布摄像头流
    options.publishCameraTrack = false;
    // ex 频道不发布麦克风流
    options.publishMicrophoneTrack = false;
    // ex 频道发布屏幕共享流
    options.publishScreenTrack = true;
    agora::rtc::RtcConnection connection;
    connection.channelId = szChannelId;
    // 自定义 uid
    connection.localUid = screenId;
    m_rtcEngine->joinChannelEx(APP_TOKEN, connection, options, &eventHandlerScreen);
    ```

### 屏幕共享 [#屏幕共享-1]

本节提供屏幕共享的示例代码。

#### 集成方式 [#集成方式-1]
**v2.x & v3.x**
直接调用屏幕共享方法，无需集成屏幕共享插件。

**v4.x**
需在调用屏幕共享方法之前集成如下屏幕共享插件：

- Android: `AgoraScreenShareExtension.aar` 和 `libagora_screen_capture_extension.so`
- iOS/macOS: `AgoraReplayKitExtension.xcframework`
- Windows: `libagora_screen_capture_extension.dll`

#### 实现方法 [#实现方法-1]

**v2.x & v3.x**

- Android：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiProcess.java)
- iOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)
- Windows：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)
- macOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/ScreenShare)

**v4.x**

- Android：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchCameraScreenShare.java)
- iOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/Agora-ScreenShare-Extension)
- Windows：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp)
- macOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/ScreenShare)

### 自定义采集 [#自定义采集-1]

如果你在 v2.x 或 v3.x 使用了自采集功能，例如通过视频自采集使用第三方美颜，声网推荐你在 v4.x 使用功能完善且更易用的 SDK 采集。

:::info[信息]
v4.x 完善了 SDK 的视频模块并在 Android 上支持了 Texture 格式。一般情况下，声网推荐用户在升级后使用 SDK 采集。在特殊场景下，例如用户需要统一对接不同厂商的 SDK，则可沿用原有自采集方案。v4.x 的 SDK 采集相对于自采集有如下优势：

    - 易用性高：用户不需要处理视频采集、机型适配、采集 Profile 策略，最大程度降低 App 代码复杂度并减少因采集导致的问题。此外，SDK 采集可以更好地避免音画不同步的问题。
    - 问题调查成本低：SDK 支持上传采集分辨率、帧率、美颜耗时等数据，声网后台会进行数据分析，从而快速、清晰地定位丢帧等问题原因。
    - 维护成本低：SDK 采集有研发团队持续迭代优化，QA 测试也比较完善。自采集插件主要是重要问题修复，缺乏持续迭代。
    - 问题修复速度快：采集策略可以配置下发，部分机型问题可以快速修复。
    - 其他须知：MediaIO 相关的 API 在 v4.x 中已删除，需要改用 Push 模式。
:::

**v2.x & v3.x**

- Android：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/customaudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [PushExternalVideo（Push 方式）](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/PushExternalVideo.java)
    - [SwitchExternalVideo（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchExternalVideo.java)
- iOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及示例项目：
    - [CustomAudioSource](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomAudioSource)
    - [ExternalAudio](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Common/ExternalAudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoSourcePush（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourceMediaIO（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomVideoSourceMediaIO)
- Windows：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/CustomAudioCapture)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoCapture（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/CustomVideoCapture)
    - [MediaIOCustomVideoCaptrue（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/MediaIOCustomVideoCaptrue)
- macOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及示例项目：
    - [CustomAudioSource](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomAudioSource)
    - [ExternalAudio](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Common/ExternalAudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoSourcePush（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourceMediaIO（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/CustomVideoSourceMediaIO)

**v4.x**

- Android：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/customaudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [PushExternalVideoYUV（Push 方式）](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/PushExternalVideoYUV.java)
    - [MultiVideoSourceTracks（Video Track 方式）](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiVideoSourceTracks.java)
- iOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioSource)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例代码：
    - [CustomVideoSourcePush（Push方式）](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourcePushMulti（Video Track 方式）](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomVideoSourcePushMulti)
- Windows：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/CustomAudioCapture)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/CustomVideoCapture)
- macOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/CustomAudioSource)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/CustomVideoSourcePush)

在设置视频采集的过程中，你可能会有如下疑问：

Q: `stopPreview`、`enableLocalVideo`、`muteLocalVideoStream` 有什么区别？

A: 三个 API 区别如下：

- `stopPreview` 用于停止本地预览，不会停止本地视频采集或发布本地视频流。
- `enableLocalVideo(false)` 用于停止本地视频采集。例如，App 切后台需要停止视频采集的情况。
- `muteLocalVideoStream(true)` 用于停止发布本地视频流。例如，App 希望保持占用摄像头但停止发布视频流的情况。

Q: 推荐在什么时机注册原始数据回调？

A: 用户在主播角色下调用 `joinChannel` 时会自动启动摄像头，所以建议用户在初始化引擎后直接调用 `registerVideoFrameObserver`。

## 升级前版本为 v4.0.0 Preview 或 v4.0.0 Beta [#升级前版本为-v400-preview-或-v400-beta-1]

#### 中断性变化 [#中断性变化-1]

- 删除了 `AUDIO_SCENARIO_TYPE` 中的 `AUDIO_SCENARIO_HIGH_DEFINITION`，改用功能一致的 `AUDIO_SCENARIO_GAME_STREAMING`。
- 修改了 `option` 命名，明确了对于 microphone track 的控制定义。将 `ChannelMediaOptions` 中的 `publishAudioTrack` 变更为 `publishMicrophoneTrack`。
- 为了丰富多路流功能的多样性，在视频流相关的回调事件中增加了视频源类型参数。例如：`onFirstLocalVideoFrame`、`onFirstLocalVideoFramePublished`、`onVideoSizeChanged`、`onVideoPublishStateChanged`、`onLocalVideoStats`、`onLocalVideoStateChanged`。
- 旁路推流  API 优化：
  - 为降低旁路推流集成难度，该版本优化了推流 API 设计，并改善了推流客户端和服务端内部对网络问题的处理机制。你可以通过如下方法体验优化后的旁路推流功能：
    - `startRtmpStreamWithoutTranscoding`: 开始非转码推流。与旧推流方法 `addPublishStreamUrl(false)` 作用相同。
    - `startRtmpStreamWithTranscoding`: 开始 CDN 直播推流并设置转码属性。与依次调用旧推流方法 `setLiveTranscoding`、`addPublishStreamUrl(true)` 的作用相同。
    - `updateRtmpTranscoding`: 更新转码属性。与非首次调用旧推流方法 `setLiveTranscoding` 的作用相同。
    - `stopRtmpStream`: 结束 CDN 直播推流。与旧推流方法 `removePublishStreamUrl` 作用相同。
    - （仅 Android 平台）`onRtmpStreamingStateChanged` 回调中的所有参数类型改为 Int 类型。
  - 该版本废弃 `addPublishStreamUrl`、`setLiveTranscoding`、`removePublishStreamUrl` 这三个旧推流方法，声网推荐你使用新的推流方法，并参考[旁路推流](/zh-CN/realtime-media/media-push)更新你的业务代码逻辑。
- 删除 `startAudioMixing` 中的 `replace`（Bool 类型）参数。`startAudioMixing` 默认发送麦克风音频和媒体播放器音频的混音，如果需要停止发送麦克风音频，你可以根据是否要继续录音，调用以下方法：
  - 需要录音：调用 `updateChannelMediaOptions` 将 `publishMicrophoneTrack` 设置为 `false`，此时麦克风仍然打开。
  - 不需要录音：调用 `enableLocalAudio` 关闭麦克风。
- （仅 Android 平台）`onRemoteAudioStateChanged` 回调中的所有参数类型改为 Int 类型。

#### 行为变更 & 新增 API [#行为变更--新增-api-1]

- `IAudioFrameObserver` 新增回调 `getObservedAudioFramePosition`、`getRecordAudioParams`、`getPlaybackAudioParams`、`getMixedAudioParams`。
- 屏幕共享采用插件方式，详见[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)。
- `enableVirtualBackground` 方法新增 `SegmentationProperty` 和 `segProperty` 参数。

## 参考信息 [#参考信息-1]

下表展示一些常用 API 在不同版本的区别：

<Tabs defaultValue="stream-controls" groupId="rtc-upgrade-reference-ios">
<TabsList>
  <TabsTrigger value="stream-controls">音视频流控制</TabsTrigger>
  <TabsTrigger value="role-preview">角色与预览</TabsTrigger>
  <TabsTrigger value="local-capture">本地采集</TabsTrigger>
</TabsList>

<TabsContent value="stream-controls">

| 常用 API | muteLocalAudioStream | muteLocalVideoStream |
| --- | --- | --- |
| v2.x & v3.x | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalAudioStream` 的设置。 | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalVideoStream` 设置。 |
| v4.0.0 Preview 或 v4.0.0 Beta | 功能等同于更新发布流控制 `ChannelMediaOptions.publishAudioTrack`。如果频道内主播调用该方法并将参数设置为 `false` 则会打开麦克风。 | 等同于更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-1) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-1) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalAudioStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishMicrophoneTrack` 为 `true`， `muteLocalAudioStream` 为  `true`，则仍然不发送音频。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalVideoStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishCameraTrack` 为 `true`，`muteLocalVideoStream` 为 `true`，  仍然不发送视频。

</TabsContent>

<TabsContent value="role-preview">

| 常用 API | setClientRole | startPreview |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x（不支持多路上行流，不能同时在多频道中设置为主播）。 | 同 v4.x。 |
| v4.0.0 Preview 或 v4.0.0 Beta | `setClientRole` 会受到 `muteLocalAudioStream` 和 `muteLocalVideoStream` 的影响。例如，如果先调用 `muteLocalAudioStream(true)` 和 `muteLocalVideoStream(true)`， 再调用 `setClientRole` 为主播，主播仍然不能发流。 | 需要主动调用 `startPreview`/`stopPreview`，以开启/关闭本地视图。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-1) | 加入频道时，主播角色发布摄像头采集的视频流时，会自动开启本地视图。如果 App 主动调用 `startPreview`，则离开频道时也需要主动调用 `stopPreview` 以关闭本地视图。 |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details**

- `setClientRole` 优先级高于  `enableLocalAudio`/`enableLocalVideo`。
- 如果在加入频道前调用该方法，SDK  会先记录该状态。
- 如果进频道后切换用户角色为主播，会根据 `enableLocalAudio`/`enableLocalVideo` 的状态，打开媒体采集并自动发布。
- 如果切换用户角色为观众，则会关闭采集并停止发布。
- 在多频道场景中，用户可以在每个频道都切换为主播角色，从而进行发流。在频道中，通过  `updateChannelMediaOptionsEx` 控制流发布。

</TabsContent>

<TabsContent value="local-capture">

| 常用 API | enableLocalAudio | enableLocalVideo |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x | 同 v4.x |
| v4.0.0 Preview 或 v4.0.0 Beta | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-1) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-1) |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-1) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-1) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭麦克风。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制  `ChannelMediaOptions.publishAudioTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭摄像头。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details**

- 如果在频道外调用，不会打开/关闭麦克风，且加入频道后会自动打开/关闭麦克风。
- 如果在频道内调用，会打开/关闭麦克风。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-1"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details**

- 如果在频道外调用，不会打开/关闭摄像头，且加入频道后会自动打开/关闭摄像头。
- 如果在频道内调用，会打开/关闭摄像头。

</TabsContent>
</Tabs>
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="macos" />
声网支持将 RTC SDK 从 2.x、3.x、4.0.0 Preview 或 4.0.0 Beta 版本升级到 4.x 版本，升级步骤以及版本间的变更介绍见[迁移指南](/zh-CN/realtime-media/rtc/reference/migration-guide)。

本文介绍在 SDK 升级后需要修改 API 以及相关实现代码的场景，以帮助你顺利完成迁移。

:::info[信息]
如无特别说明，本文 API 名称均以 C++ 为例，平台均以 Windows 为例。
:::

## 升级前版本为 2.x 或 3.x [#升级前版本为-2x-或-3x-2]

如果你已经在 v2.x 或 v3.x 中用到了本节介绍的功能和场景，可参考对应示例更新 App 代码。

### 单频道 [#单频道-2]

本节提供单频道中常用功能的示例代码。

#### 初始化引擎 [#初始化引擎-2]

**v2.x & v3.x**

- Android: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Basic/JoinChannelVideo)

**v4.x**

- Android: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Basic/JoinChannelVideo)

#### 默认发布麦克风和摄像头采集的音视频流 [#默认发布麦克风和摄像头采集的音视频流-2]

**v2.x & v3.x**

```cpp
// 通过 muteLocalAudioStream 和 muteLocalVideoStream 控制是否发流
// true 为暂停发布音频流，false 为继续发布音频流
m_rtcEngine->muteLocalAudioStream(false);
// true 为暂停发布视频流，false 为继续发布视频流
m_rtcEngine->muteLocalVideoStream(false);
```

**v4.x**

```cpp
// m_rtcEngine 可以定义为 IRtcEngine* 或者 IRtcEngineEx*
// IRtcEngineEx 继承自 IRtcEngine，拥有更丰富的 API 以及多频道的能力
// 建议通过 ChannelMediaOptions 精细化控制音视频流的发布
// 注意：v4.x 默认可通过 ChannelMediaOptions 精细化控制音视频的发布及订阅
ChannelMediaOptions options;
options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
// true 为订阅音频流，false 为不订阅音频流
options.autoSubscribeAudio = true;
// true 为订阅视频流，false 为不订阅视频流
options.autoSubscribeVideo = true;
// true 为发布麦克风采集的音频流，false 为不发布
options.publishMicrophoneTrack = true;
// true 为发布摄像头采集的视频流，false 为不发布
options.publishCameraTrack = true;
// ex 频道则需使用 updateChannelMediaOptionsEx 替代
m_rtcEngine->updateChannelMediaOptions(options);
```

#### 将视频源从摄像头切换为共享的屏幕 [#将视频源从摄像头切换为共享的屏幕-2]

**v2.x & v3.x**

```cpp
SIZE size; size.cx = 100;
size.cy = 100;
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index);
ScreenCaptureParameters capParam;
// 根据实际需求，调用 startScreenCaptureByDisplayId、startScreenCaptureByWindowId 或 startScreenCaptureByScreenRect 来共享屏幕
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

**v4.x**

```cpp
SIZE size;
size.cx = 100;
size.cy = 100;
agora::rtc::Rectangle regionRect = { 0, 0, 0, 0 };
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index); ScreenCaptureParameters capParam;
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
ChannelMediaOptions options;
options.publishCameraTrack = false;
// 发布屏幕共享流
options.publishScreenTrack = true;
m_rtcEngine->updateChannelMediaOptions(options);
......
// 停止发布屏幕共享流
options.publishScreenTrack = false;
m_rtcEngine->updateChannelMediaOptions(options)
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

#### 发布 mp4 视频 [#发布-mp4-视频-2]

**v2.x & v3.x**
需要独立进程并通过 MediaPlayer Kit 实现，详见[媒体播放器组件（3.x）](/zh-CN/realtime-media/rtc/build/audio/media-player)。

**v4.x**
初始化 MediaPlayer。

详见[媒体播放器](/zh-CN/realtime-media/rtc/build/audio/media-player)。

1. 发布麦克风和摄像头采集的流

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    // 默认发布麦克风采集的音频流
    options.publishMicrophoneTrack = true;
    // 默认发布摄像头采集的视频流
    options.publishCameraTrack = true;
    // 加入频道
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 切换为发布媒体播放器的音视频流

    ```cpp
    IMediaPlayer* m_mediaPlayer = m_rtcEngine->createMediaPlayer().get();
    ChannelMediaOptions options;
    // 停止发布麦克风采集的音频流
    options.publishMicrophoneTrack = false;
    // 停止发布摄像头采集的视频流
    options.publishCameraTrack = false;
    // 指定发布的媒体播放器的 playerId
    options.publishMediaPlayerId = m_mediaPlayer->getMediaPlayerId();
    // 切换为媒体播放器的音频流
    options.publishMediaPlayerAudioTrack = true;
    // 切换为媒体播放器的视频流
    options.publishMediaPlayerVideoTrack = true;
    m_rtcEngine->updateChannelMediaOptions(options);
    ```

### 多频道 [#多频道-2]

本节提供多频道中常用功能的示例代码。

#### 加入多频道 [#加入多频道-2]

**v2.x & v3.x**
单进程只能发布一路流。加入多频道后，同一时间只能在一个频道发布一路流，其他频道只能订阅流不能发布流。如果需要发布多路流，则需要开多个进程。详见：

- Android：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/JoinMultipleChannel.java)
- iOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/iOS/APIExample/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift)
- Windows：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/MultiChannel)
- macOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/macOS/APIExample/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift)

**v4.x**
支持在单进程中加入多频道，并且同一时间可以在多个频道中发布音视频流。详见：

- Android：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/JoinMultipleChannel.java)
- iOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/JoinMultiChannel)
- Windows：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/MultiChannel)
- macOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/JoinMultiChannel)

#### 默认在两个频道发布流 [#默认在两个频道发布流-2]
例如：

- 在 `channel1` 发布麦克风和摄像头采集的流。
- 在 `channel2` 发布屏幕共享流。

**v2.x & v3.x**
不支持单进程同时在两个频道发布音视频流，所以需要通过多进程分别创建引擎。

1. 进程 1 发布摄像头流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->enableVideo();
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    ```

2. 进程 2 发布屏幕共享流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
    ```

**v4.x**
支持单进程直接在多个频道内发布音视频流。

1. 发布摄像头流。

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    options.publishCameraTrack = true;
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 发布屏幕共享流。

    ```cpp
    // 指定待分享的屏幕
    agora::rtc::Rectangle rc;
    ScreenCaptureParameters scp;
    scp.frameRate = 15;
    scp.bitrate = 0;
    HWND hWnd = ::GetDesktopWindow();
    RECT destop_rc;
    ::GetWindowRect(hWnd, &destop_rc);
    scp.dimensions.width = destop_rc.right - destop_rc.left;
    scp.dimensions.height = destop_rc.bottom - destop_rc.top;
    m_rtcEngine->startScreenCaptureByScreenRect(rc, rc, scp);
    // 加入多频道
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    // 如果是加入同一频道，则不必重复订阅音频流
    options.autoSubscribeAudio = false;
    // 如果是加入同一频道，则不必重复订阅视频流
    options.autoSubscribeVideo = false;
    // ex 频道不发布摄像头流
    options.publishCameraTrack = false;
    // ex 频道不发布麦克风流
    options.publishMicrophoneTrack = false;
    // ex 频道发布屏幕共享流
    options.publishScreenTrack = true;
    agora::rtc::RtcConnection connection;
    connection.channelId = szChannelId;
    // 自定义 uid
    connection.localUid = screenId;
    m_rtcEngine->joinChannelEx(APP_TOKEN, connection, options, &eventHandlerScreen);
    ```

### 屏幕共享 [#屏幕共享-2]

本节提供屏幕共享的示例代码。

#### 集成方式 [#集成方式-2]
**v2.x & v3.x**
直接调用屏幕共享方法，无需集成屏幕共享插件。

**v4.x**
需在调用屏幕共享方法之前集成如下屏幕共享插件：

- Android: `AgoraScreenShareExtension.aar` 和 `libagora_screen_capture_extension.so`
- iOS/macOS: `AgoraReplayKitExtension.xcframework`
- Windows: `libagora_screen_capture_extension.dll`

#### 实现方法 [#实现方法-2]

**v2.x & v3.x**

- Android：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiProcess.java)
- iOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)
- Windows：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)
- macOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/ScreenShare)

**v4.x**

- Android：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchCameraScreenShare.java)
- iOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/Agora-ScreenShare-Extension)
- Windows：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp)
- macOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/ScreenShare)

### 自定义采集 [#自定义采集-2]

如果你在 v2.x 或 v3.x 使用了自采集功能，例如通过视频自采集使用第三方美颜，声网推荐你在 v4.x 使用功能完善且更易用的 SDK 采集。

:::info[信息]
v4.x 完善了 SDK 的视频模块并在 Android 上支持了 Texture 格式。一般情况下，声网推荐用户在升级后使用 SDK 采集。在特殊场景下，例如用户需要统一对接不同厂商的 SDK，则可沿用原有自采集方案。v4.x 的 SDK 采集相对于自采集有如下优势：

    - 易用性高：用户不需要处理视频采集、机型适配、采集 Profile 策略，最大程度降低 App 代码复杂度并减少因采集导致的问题。此外，SDK 采集可以更好地避免音画不同步的问题。
    - 问题调查成本低：SDK 支持上传采集分辨率、帧率、美颜耗时等数据，声网后台会进行数据分析，从而快速、清晰地定位丢帧等问题原因。
    - 维护成本低：SDK 采集有研发团队持续迭代优化，QA 测试也比较完善。自采集插件主要是重要问题修复，缺乏持续迭代。
    - 问题修复速度快：采集策略可以配置下发，部分机型问题可以快速修复。
    - 其他须知：MediaIO 相关的 API 在 v4.x 中已删除，需要改用 Push 模式。
:::

**v2.x & v3.x**

- Android：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/customaudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [PushExternalVideo（Push 方式）](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/PushExternalVideo.java)
    - [SwitchExternalVideo（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchExternalVideo.java)
- iOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及示例项目：
    - [CustomAudioSource](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomAudioSource)
    - [ExternalAudio](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Common/ExternalAudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoSourcePush（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourceMediaIO（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomVideoSourceMediaIO)
- Windows：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/CustomAudioCapture)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoCapture（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/CustomVideoCapture)
    - [MediaIOCustomVideoCaptrue（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/MediaIOCustomVideoCaptrue)
- macOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及示例项目：
    - [CustomAudioSource](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomAudioSource)
    - [ExternalAudio](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Common/ExternalAudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoSourcePush（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourceMediaIO（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/CustomVideoSourceMediaIO)

**v4.x**

- Android：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/customaudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [PushExternalVideoYUV（Push 方式）](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/PushExternalVideoYUV.java)
    - [MultiVideoSourceTracks（Video Track 方式）](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiVideoSourceTracks.java)
- iOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioSource)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例代码：
    - [CustomVideoSourcePush（Push方式）](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourcePushMulti（Video Track 方式）](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomVideoSourcePushMulti)
- Windows：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/CustomAudioCapture)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/CustomVideoCapture)
- macOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/CustomAudioSource)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/CustomVideoSourcePush)

在设置视频采集的过程中，你可能会有如下疑问：

Q: `stopPreview`、`enableLocalVideo`、`muteLocalVideoStream` 有什么区别？

A: 三个 API 区别如下：

- `stopPreview` 用于停止本地预览，不会停止本地视频采集或发布本地视频流。
- `enableLocalVideo(false)` 用于停止本地视频采集。例如，App 切后台需要停止视频采集的情况。
- `muteLocalVideoStream(true)` 用于停止发布本地视频流。例如，App 希望保持占用摄像头但停止发布视频流的情况。

Q: 推荐在什么时机注册原始数据回调？

A: 用户在主播角色下调用 `joinChannel` 时会自动启动摄像头，所以建议用户在初始化引擎后直接调用 `registerVideoFrameObserver`。

## 升级前版本为 v4.0.0 Preview 或 v4.0.0 Beta [#升级前版本为-v400-preview-或-v400-beta-2]

#### 中断性变化 [#中断性变化-2]

- 删除了 `AUDIO_SCENARIO_TYPE` 中的 `AUDIO_SCENARIO_HIGH_DEFINITION`，改用功能一致的 `AUDIO_SCENARIO_GAME_STREAMING`。
- 修改了 `option` 命名，明确了对于 microphone track 的控制定义。将 `ChannelMediaOptions` 中的 `publishAudioTrack` 变更为 `publishMicrophoneTrack`。
- 为了丰富多路流功能的多样性，在视频流相关的回调事件中增加了视频源类型参数。例如：`onFirstLocalVideoFrame`、`onFirstLocalVideoFramePublished`、`onVideoSizeChanged`、`onVideoPublishStateChanged`、`onLocalVideoStats`、`onLocalVideoStateChanged`。
- 旁路推流  API 优化：
  - 为降低旁路推流集成难度，该版本优化了推流 API 设计，并改善了推流客户端和服务端内部对网络问题的处理机制。你可以通过如下方法体验优化后的旁路推流功能：
    - `startRtmpStreamWithoutTranscoding`: 开始非转码推流。与旧推流方法 `addPublishStreamUrl(false)` 作用相同。
    - `startRtmpStreamWithTranscoding`: 开始 CDN 直播推流并设置转码属性。与依次调用旧推流方法 `setLiveTranscoding`、`addPublishStreamUrl(true)` 的作用相同。
    - `updateRtmpTranscoding`: 更新转码属性。与非首次调用旧推流方法 `setLiveTranscoding` 的作用相同。
    - `stopRtmpStream`: 结束 CDN 直播推流。与旧推流方法 `removePublishStreamUrl` 作用相同。
    - （仅 Android 平台）`onRtmpStreamingStateChanged` 回调中的所有参数类型改为 Int 类型。
  - 该版本废弃 `addPublishStreamUrl`、`setLiveTranscoding`、`removePublishStreamUrl` 这三个旧推流方法，声网推荐你使用新的推流方法，并参考[旁路推流](/zh-CN/realtime-media/media-push)更新你的业务代码逻辑。
- 删除 `startAudioMixing` 中的 `replace`（Bool 类型）参数。`startAudioMixing` 默认发送麦克风音频和媒体播放器音频的混音，如果需要停止发送麦克风音频，你可以根据是否要继续录音，调用以下方法：
  - 需要录音：调用 `updateChannelMediaOptions` 将 `publishMicrophoneTrack` 设置为 `false`，此时麦克风仍然打开。
  - 不需要录音：调用 `enableLocalAudio` 关闭麦克风。
- （仅 Android 平台）`onRemoteAudioStateChanged` 回调中的所有参数类型改为 Int 类型。

#### 行为变更 & 新增 API [#行为变更--新增-api-2]

- `IAudioFrameObserver` 新增回调 `getObservedAudioFramePosition`、`getRecordAudioParams`、`getPlaybackAudioParams`、`getMixedAudioParams`。
- 屏幕共享采用插件方式，详见[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)。
- `enableVirtualBackground` 方法新增 `SegmentationProperty` 和 `segProperty` 参数。

## 参考信息 [#参考信息-2]

下表展示一些常用 API 在不同版本的区别：

<Tabs defaultValue="stream-controls" groupId="rtc-upgrade-reference-macos">
<TabsList>
  <TabsTrigger value="stream-controls">音视频流控制</TabsTrigger>
  <TabsTrigger value="role-preview">角色与预览</TabsTrigger>
  <TabsTrigger value="local-capture">本地采集</TabsTrigger>
</TabsList>

<TabsContent value="stream-controls">

| 常用 API | muteLocalAudioStream | muteLocalVideoStream |
| --- | --- | --- |
| v2.x & v3.x | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalAudioStream` 的设置。 | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalVideoStream` 设置。 |
| v4.0.0 Preview 或 v4.0.0 Beta | 功能等同于更新发布流控制 `ChannelMediaOptions.publishAudioTrack`。如果频道内主播调用该方法并将参数设置为 `false` 则会打开麦克风。 | 等同于更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-2) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-2) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-2"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalAudioStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishMicrophoneTrack` 为 `true`， `muteLocalAudioStream` 为  `true`，则仍然不发送音频。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-2"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalVideoStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishCameraTrack` 为 `true`，`muteLocalVideoStream` 为 `true`，  仍然不发送视频。

</TabsContent>

<TabsContent value="role-preview">

| 常用 API | setClientRole | startPreview |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x（不支持多路上行流，不能同时在多频道中设置为主播）。 | 同 v4.x。 |
| v4.0.0 Preview 或 v4.0.0 Beta | `setClientRole` 会受到 `muteLocalAudioStream` 和 `muteLocalVideoStream` 的影响。例如，如果先调用 `muteLocalAudioStream(true)` 和 `muteLocalVideoStream(true)`， 再调用 `setClientRole` 为主播，主播仍然不能发流。 | 需要主动调用 `startPreview`/`stopPreview`，以开启/关闭本地视图。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-2) | 加入频道时，主播角色发布摄像头采集的视频流时，会自动开启本地视图。如果 App 主动调用 `startPreview`，则离开频道时也需要主动调用 `stopPreview` 以关闭本地视图。 |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-2"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details**

- `setClientRole` 优先级高于  `enableLocalAudio`/`enableLocalVideo`。
- 如果在加入频道前调用该方法，SDK  会先记录该状态。
- 如果进频道后切换用户角色为主播，会根据 `enableLocalAudio`/`enableLocalVideo` 的状态，打开媒体采集并自动发布。
- 如果切换用户角色为观众，则会关闭采集并停止发布。
- 在多频道场景中，用户可以在每个频道都切换为主播角色，从而进行发流。在频道中，通过  `updateChannelMediaOptionsEx` 控制流发布。

</TabsContent>

<TabsContent value="local-capture">

| 常用 API | enableLocalAudio | enableLocalVideo |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x | 同 v4.x |
| v4.0.0 Preview 或 v4.0.0 Beta | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-2) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-2) |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-2) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-2) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-2"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭麦克风。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制  `ChannelMediaOptions.publishAudioTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-2"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭摄像头。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-2"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details**

- 如果在频道外调用，不会打开/关闭麦克风，且加入频道后会自动打开/关闭麦克风。
- 如果在频道内调用，会打开/关闭麦克风。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-2"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details**

- 如果在频道外调用，不会打开/关闭摄像头，且加入频道后会自动打开/关闭摄像头。
- 如果在频道内调用，会打开/关闭摄像头。

</TabsContent>
</Tabs>
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="windows" />
声网支持将 RTC SDK 从 2.x、3.x、4.0.0 Preview 或 4.0.0 Beta 版本升级到 4.x 版本，升级步骤以及版本间的变更介绍见[迁移指南](/zh-CN/realtime-media/rtc/reference/migration-guide)。

本文介绍在 SDK 升级后需要修改 API 以及相关实现代码的场景，以帮助你顺利完成迁移。

:::info[信息]
如无特别说明，本文 API 名称均以 C++ 为例，平台均以 Windows 为例。
:::

## 升级前版本为 2.x 或 3.x [#升级前版本为-2x-或-3x-3]

如果你已经在 v2.x 或 v3.x 中用到了本节介绍的功能和场景，可参考对应示例更新 App 代码。

### 单频道 [#单频道-3]

本节提供单频道中常用功能的示例代码。

#### 初始化引擎 [#初始化引擎-3]

**v2.x & v3.x**

- Android: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Basic/JoinChannelVideo)

**v4.x**

- Android: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Basic/JoinChannelVideo)

#### 默认发布麦克风和摄像头采集的音视频流 [#默认发布麦克风和摄像头采集的音视频流-3]

**v2.x & v3.x**

```cpp
// 通过 muteLocalAudioStream 和 muteLocalVideoStream 控制是否发流
// true 为暂停发布音频流，false 为继续发布音频流
m_rtcEngine->muteLocalAudioStream(false);
// true 为暂停发布视频流，false 为继续发布视频流
m_rtcEngine->muteLocalVideoStream(false);
```

**v4.x**

```cpp
// m_rtcEngine 可以定义为 IRtcEngine* 或者 IRtcEngineEx*
// IRtcEngineEx 继承自 IRtcEngine，拥有更丰富的 API 以及多频道的能力
// 建议通过 ChannelMediaOptions 精细化控制音视频流的发布
// 注意：v4.x 默认可通过 ChannelMediaOptions 精细化控制音视频的发布及订阅
ChannelMediaOptions options;
options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
// true 为订阅音频流，false 为不订阅音频流
options.autoSubscribeAudio = true;
// true 为订阅视频流，false 为不订阅视频流
options.autoSubscribeVideo = true;
// true 为发布麦克风采集的音频流，false 为不发布
options.publishMicrophoneTrack = true;
// true 为发布摄像头采集的视频流，false 为不发布
options.publishCameraTrack = true;
// ex 频道则需使用 updateChannelMediaOptionsEx 替代
m_rtcEngine->updateChannelMediaOptions(options);
```

#### 将视频源从摄像头切换为共享的屏幕 [#将视频源从摄像头切换为共享的屏幕-3]

**v2.x & v3.x**

```cpp
SIZE size; size.cx = 100;
size.cy = 100;
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index);
ScreenCaptureParameters capParam;
// 根据实际需求，调用 startScreenCaptureByDisplayId、startScreenCaptureByWindowId 或 startScreenCaptureByScreenRect 来共享屏幕
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

**v4.x**

```cpp
SIZE size;
size.cx = 100;
size.cy = 100;
agora::rtc::Rectangle regionRect = { 0, 0, 0, 0 };
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index); ScreenCaptureParameters capParam;
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
ChannelMediaOptions options;
options.publishCameraTrack = false;
// 发布屏幕共享流
options.publishScreenTrack = true;
m_rtcEngine->updateChannelMediaOptions(options);
......
// 停止发布屏幕共享流
options.publishScreenTrack = false;
m_rtcEngine->updateChannelMediaOptions(options)
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

#### 发布 mp4 视频 [#发布-mp4-视频-3]

**v2.x & v3.x**
需要独立进程并通过 MediaPlayer Kit 实现，详见[媒体播放器组件（3.x）](/zh-CN/realtime-media/rtc/build/audio/media-player)。

**v4.x**
初始化 MediaPlayer。

详见[媒体播放器](/zh-CN/realtime-media/rtc/build/audio/media-player)。

1. 发布麦克风和摄像头采集的流

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    // 默认发布麦克风采集的音频流
    options.publishMicrophoneTrack = true;
    // 默认发布摄像头采集的视频流
    options.publishCameraTrack = true;
    // 加入频道
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 切换为发布媒体播放器的音视频流

    ```cpp
    IMediaPlayer* m_mediaPlayer = m_rtcEngine->createMediaPlayer().get();
    ChannelMediaOptions options;
    // 停止发布麦克风采集的音频流
    options.publishMicrophoneTrack = false;
    // 停止发布摄像头采集的视频流
    options.publishCameraTrack = false;
    // 指定发布的媒体播放器的 playerId
    options.publishMediaPlayerId = m_mediaPlayer->getMediaPlayerId();
    // 切换为媒体播放器的音频流
    options.publishMediaPlayerAudioTrack = true;
    // 切换为媒体播放器的视频流
    options.publishMediaPlayerVideoTrack = true;
    m_rtcEngine->updateChannelMediaOptions(options);
    ```

### 多频道 [#多频道-3]

本节提供多频道中常用功能的示例代码。

#### 加入多频道 [#加入多频道-3]

**v2.x & v3.x**
单进程只能发布一路流。加入多频道后，同一时间只能在一个频道发布一路流，其他频道只能订阅流不能发布流。如果需要发布多路流，则需要开多个进程。详见：

- Android：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/JoinMultipleChannel.java)
- iOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/iOS/APIExample/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift)
- Windows：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/MultiChannel)
- macOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/legacy/macOS/APIExample/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift)

**v4.x**
支持在单进程中加入多频道，并且同一时间可以在多个频道中发布音视频流。详见：

- Android：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/JoinMultipleChannel.java)
- iOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/JoinMultiChannel)
- Windows：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/MultiChannel)
- macOS：[加入多频道介绍](/zh-CN/realtime-media/rtc/build/advanced-channel/multiple-channel)及[示例代码](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/JoinMultiChannel)

#### 默认在两个频道发布流 [#默认在两个频道发布流-3]
例如：

- 在 `channel1` 发布麦克风和摄像头采集的流。
- 在 `channel2` 发布屏幕共享流。

**v2.x & v3.x**
不支持单进程同时在两个频道发布音视频流，所以需要通过多进程分别创建引擎。

1. 进程 1 发布摄像头流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->enableVideo();
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    ```

2. 进程 2 发布屏幕共享流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
    ```

**v4.x**
支持单进程直接在多个频道内发布音视频流。

1. 发布摄像头流。

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    options.publishCameraTrack = true;
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 发布屏幕共享流。

    ```cpp
    // 指定待分享的屏幕
    agora::rtc::Rectangle rc;
    ScreenCaptureParameters scp;
    scp.frameRate = 15;
    scp.bitrate = 0;
    HWND hWnd = ::GetDesktopWindow();
    RECT destop_rc;
    ::GetWindowRect(hWnd, &destop_rc);
    scp.dimensions.width = destop_rc.right - destop_rc.left;
    scp.dimensions.height = destop_rc.bottom - destop_rc.top;
    m_rtcEngine->startScreenCaptureByScreenRect(rc, rc, scp);
    // 加入多频道
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    // 如果是加入同一频道，则不必重复订阅音频流
    options.autoSubscribeAudio = false;
    // 如果是加入同一频道，则不必重复订阅视频流
    options.autoSubscribeVideo = false;
    // ex 频道不发布摄像头流
    options.publishCameraTrack = false;
    // ex 频道不发布麦克风流
    options.publishMicrophoneTrack = false;
    // ex 频道发布屏幕共享流
    options.publishScreenTrack = true;
    agora::rtc::RtcConnection connection;
    connection.channelId = szChannelId;
    // 自定义 uid
    connection.localUid = screenId;
    m_rtcEngine->joinChannelEx(APP_TOKEN, connection, options, &eventHandlerScreen);
    ```

### 屏幕共享 [#屏幕共享-3]

本节提供屏幕共享的示例代码。

#### 集成方式 [#集成方式-3]
**v2.x & v3.x**
直接调用屏幕共享方法，无需集成屏幕共享插件。

**v4.x**
需在调用屏幕共享方法之前集成如下屏幕共享插件：

- Android: `AgoraScreenShareExtension.aar` 和 `libagora_screen_capture_extension.so`
- iOS/macOS: `AgoraReplayKitExtension.xcframework`
- Windows: `libagora_screen_capture_extension.dll`

#### 实现方法 [#实现方法-3]

**v2.x & v3.x**

- Android：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiProcess.java)
- iOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)
- Windows：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)
- macOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/ScreenShare)

**v4.x**

- Android：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchCameraScreenShare.java)
- iOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/Agora-ScreenShare-Extension)
- Windows：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp)
- macOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/ScreenShare)

### 自定义采集 [#自定义采集-3]

如果你在 v2.x 或 v3.x 使用了自采集功能，例如通过视频自采集使用第三方美颜，声网推荐你在 v4.x 使用功能完善且更易用的 SDK 采集。

:::info[信息]
v4.x 完善了 SDK 的视频模块并在 Android 上支持了 Texture 格式。一般情况下，声网推荐用户在升级后使用 SDK 采集。在特殊场景下，例如用户需要统一对接不同厂商的 SDK，则可沿用原有自采集方案。v4.x 的 SDK 采集相对于自采集有如下优势：

    - 易用性高：用户不需要处理视频采集、机型适配、采集 Profile 策略，最大程度降低 App 代码复杂度并减少因采集导致的问题。此外，SDK 采集可以更好地避免音画不同步的问题。
    - 问题调查成本低：SDK 支持上传采集分辨率、帧率、美颜耗时等数据，声网后台会进行数据分析，从而快速、清晰地定位丢帧等问题原因。
    - 维护成本低：SDK 采集有研发团队持续迭代优化，QA 测试也比较完善。自采集插件主要是重要问题修复，缺乏持续迭代。
    - 问题修复速度快：采集策略可以配置下发，部分机型问题可以快速修复。
    - 其他须知：MediaIO 相关的 API 在 v4.x 中已删除，需要改用 Push 模式。
:::

**v2.x & v3.x**

- Android：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/customaudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [PushExternalVideo（Push 方式）](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/PushExternalVideo.java)
    - [SwitchExternalVideo（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchExternalVideo.java)
- iOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及示例项目：
    - [CustomAudioSource](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomAudioSource)
    - [ExternalAudio](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Common/ExternalAudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoSourcePush（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourceMediaIO（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomVideoSourceMediaIO)
- Windows：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/CustomAudioCapture)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoCapture（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/CustomVideoCapture)
    - [MediaIOCustomVideoCaptrue（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/windows/APIExample/APIExample/Advanced/MediaIOCustomVideoCaptrue)
- macOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及示例项目：
    - [CustomAudioSource](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Advanced/CustomAudioSource)
    - [ExternalAudio](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Common/ExternalAudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [CustomVideoSourcePush（Push 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourceMediaIO（MediaIO 方式）](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/CustomVideoSourceMediaIO)

**v4.x**

- Android：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/customaudio)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例项目：
    - [PushExternalVideoYUV（Push 方式）](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/PushExternalVideoYUV.java)
    - [MultiVideoSourceTracks（Video Track 方式）](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiVideoSourceTracks.java)
- iOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioSource)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及示例代码：
    - [CustomVideoSourcePush（Push方式）](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomVideoSourcePush)
    - [CustomVideoSourcePushMulti（Video Track 方式）](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomVideoSourcePushMulti)
- Windows：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/CustomAudioCapture)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/CustomVideoCapture)
- macOS：
  - [自定义音频采集](/zh-CN/realtime-media/rtc/build/audio/custom-audio-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/CustomAudioSource)
  - [自定义视频采集](/zh-CN/realtime-media/rtc/build/video/custom-video-source)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/CustomVideoSourcePush)

在设置视频采集的过程中，你可能会有如下疑问：

Q: `stopPreview`、`enableLocalVideo`、`muteLocalVideoStream` 有什么区别？

A: 三个 API 区别如下：

- `stopPreview` 用于停止本地预览，不会停止本地视频采集或发布本地视频流。
- `enableLocalVideo(false)` 用于停止本地视频采集。例如，App 切后台需要停止视频采集的情况。
- `muteLocalVideoStream(true)` 用于停止发布本地视频流。例如，App 希望保持占用摄像头但停止发布视频流的情况。

Q: 推荐在什么时机注册原始数据回调？

A: 用户在主播角色下调用 `joinChannel` 时会自动启动摄像头，所以建议用户在初始化引擎后直接调用 `registerVideoFrameObserver`。

## 升级前版本为 v4.0.0 Preview 或 v4.0.0 Beta [#升级前版本为-v400-preview-或-v400-beta-3]

#### 中断性变化 [#中断性变化-3]

- 删除了 `AUDIO_SCENARIO_TYPE` 中的 `AUDIO_SCENARIO_HIGH_DEFINITION`，改用功能一致的 `AUDIO_SCENARIO_GAME_STREAMING`。
- 修改了 `option` 命名，明确了对于 microphone track 的控制定义。将 `ChannelMediaOptions` 中的 `publishAudioTrack` 变更为 `publishMicrophoneTrack`。
- 为了丰富多路流功能的多样性，在视频流相关的回调事件中增加了视频源类型参数。例如：`onFirstLocalVideoFrame`、`onFirstLocalVideoFramePublished`、`onVideoSizeChanged`、`onVideoPublishStateChanged`、`onLocalVideoStats`、`onLocalVideoStateChanged`。
- 旁路推流  API 优化：
  - 为降低旁路推流集成难度，该版本优化了推流 API 设计，并改善了推流客户端和服务端内部对网络问题的处理机制。你可以通过如下方法体验优化后的旁路推流功能：
    - `startRtmpStreamWithoutTranscoding`: 开始非转码推流。与旧推流方法 `addPublishStreamUrl(false)` 作用相同。
    - `startRtmpStreamWithTranscoding`: 开始 CDN 直播推流并设置转码属性。与依次调用旧推流方法 `setLiveTranscoding`、`addPublishStreamUrl(true)` 的作用相同。
    - `updateRtmpTranscoding`: 更新转码属性。与非首次调用旧推流方法 `setLiveTranscoding` 的作用相同。
    - `stopRtmpStream`: 结束 CDN 直播推流。与旧推流方法 `removePublishStreamUrl` 作用相同。
    - （仅 Android 平台）`onRtmpStreamingStateChanged` 回调中的所有参数类型改为 Int 类型。
  - 该版本废弃 `addPublishStreamUrl`、`setLiveTranscoding`、`removePublishStreamUrl` 这三个旧推流方法，声网推荐你使用新的推流方法，并参考[旁路推流](/zh-CN/realtime-media/media-push)更新你的业务代码逻辑。
- 删除 `startAudioMixing` 中的 `replace`（Bool 类型）参数。`startAudioMixing` 默认发送麦克风音频和媒体播放器音频的混音，如果需要停止发送麦克风音频，你可以根据是否要继续录音，调用以下方法：
  - 需要录音：调用 `updateChannelMediaOptions` 将 `publishMicrophoneTrack` 设置为 `false`，此时麦克风仍然打开。
  - 不需要录音：调用 `enableLocalAudio` 关闭麦克风。
- （仅 Android 平台）`onRemoteAudioStateChanged` 回调中的所有参数类型改为 Int 类型。

#### 行为变更 & 新增 API [#行为变更--新增-api-3]

- `IAudioFrameObserver` 新增回调 `getObservedAudioFramePosition`、`getRecordAudioParams`、`getPlaybackAudioParams`、`getMixedAudioParams`。
- 屏幕共享采用插件方式，详见[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)。
- `enableVirtualBackground` 方法新增 `SegmentationProperty` 和 `segProperty` 参数。

## 参考信息 [#参考信息-3]

下表展示一些常用 API 在不同版本的区别：

<Tabs defaultValue="stream-controls" groupId="rtc-upgrade-reference-windows">
<TabsList>
  <TabsTrigger value="stream-controls">音视频流控制</TabsTrigger>
  <TabsTrigger value="role-preview">角色与预览</TabsTrigger>
  <TabsTrigger value="local-capture">本地采集</TabsTrigger>
</TabsList>

<TabsContent value="stream-controls">

| 常用 API | muteLocalAudioStream | muteLocalVideoStream |
| --- | --- | --- |
| v2.x & v3.x | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalAudioStream` 的设置。 | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalVideoStream` 设置。 |
| v4.0.0 Preview 或 v4.0.0 Beta | 功能等同于更新发布流控制 `ChannelMediaOptions.publishAudioTrack`。如果频道内主播调用该方法并将参数设置为 `false` 则会打开麦克风。 | 等同于更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-3) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-3) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-3"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalAudioStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishMicrophoneTrack` 为 `true`， `muteLocalAudioStream` 为  `true`，则仍然不发送音频。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-3"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalVideoStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishCameraTrack` 为 `true`，`muteLocalVideoStream` 为 `true`，  仍然不发送视频。

</TabsContent>

<TabsContent value="role-preview">

| 常用 API | setClientRole | startPreview |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x（不支持多路上行流，不能同时在多频道中设置为主播）。 | 同 v4.x。 |
| v4.0.0 Preview 或 v4.0.0 Beta | `setClientRole` 会受到 `muteLocalAudioStream` 和 `muteLocalVideoStream` 的影响。例如，如果先调用 `muteLocalAudioStream(true)` 和 `muteLocalVideoStream(true)`， 再调用 `setClientRole` 为主播，主播仍然不能发流。 | 需要主动调用 `startPreview`/`stopPreview`，以开启/关闭本地视图。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-3) | 加入频道时，主播角色发布摄像头采集的视频流时，会自动开启本地视图。如果 App 主动调用 `startPreview`，则离开频道时也需要主动调用 `stopPreview` 以关闭本地视图。 |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-3"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details**

- `setClientRole` 优先级高于  `enableLocalAudio`/`enableLocalVideo`。
- 如果在加入频道前调用该方法，SDK  会先记录该状态。
- 如果进频道后切换用户角色为主播，会根据 `enableLocalAudio`/`enableLocalVideo` 的状态，打开媒体采集并自动发布。
- 如果切换用户角色为观众，则会关闭采集并停止发布。
- 在多频道场景中，用户可以在每个频道都切换为主播角色，从而进行发流。在频道中，通过  `updateChannelMediaOptionsEx` 控制流发布。

</TabsContent>

<TabsContent value="local-capture">

| 常用 API | enableLocalAudio | enableLocalVideo |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x | 同 v4.x |
| v4.0.0 Preview 或 v4.0.0 Beta | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-3) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-3) |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-3) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-3) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-3"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭麦克风。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制  `ChannelMediaOptions.publishAudioTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-3"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭摄像头。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-3"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details**

- 如果在频道外调用，不会打开/关闭麦克风，且加入频道后会自动打开/关闭麦克风。
- 如果在频道内调用，会打开/关闭麦克风。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-3"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details**

- 如果在频道外调用，不会打开/关闭摄像头，且加入频道后会自动打开/关闭摄像头。
- 如果在频道内调用，会打开/关闭摄像头。

</TabsContent>
</Tabs>
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="electron" />
声网支持将 RTC SDK 从 2.x、3.x、4.0.0 Preview 或 4.0.0 Beta 版本升级到 4.x 版本，升级步骤以及版本间的变更介绍见[迁移指南](/zh-CN/realtime-media/rtc/reference/migration-guide)。

本文介绍在 SDK 升级后需要修改 API 以及相关实现代码的场景，以帮助你顺利完成迁移。

:::info[信息]
如无特别说明，本文 API 名称均以 C++ 为例，平台均以 Windows 为例。
:::

## 升级前版本为 2.x 或 3.x [#升级前版本为-2x-或-3x-4]

如果你已经在 v2.x 或 v3.x 中用到了本节介绍的功能和场景，可参考对应示例更新 App 代码。

### 单频道 [#单频道-4]

本节提供单频道中常用功能的示例代码。

#### 初始化引擎 [#初始化引擎-4]

**v2.x & v3.x**

- Android: [实现互动直播](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/start_live_android?platform=Android#在客户端实现互动直播)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现互动直播](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/start_live_ios?platform=iOS#基本流程)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现互动直播](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/start_live_windows?platform=Windows#实现音视频直播)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现互动直播](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/start_live_mac?platform=macOS#基本流程)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Basic/JoinChannelVideo)

**v4.x**

- Android: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Basic/JoinChannelVideo)

#### 默认发布麦克风和摄像头采集的音视频流 [#默认发布麦克风和摄像头采集的音视频流-4]

**v2.x & v3.x**

```cpp
// 通过 muteLocalAudioStream 和 muteLocalVideoStream 控制是否发流
// true 为暂停发布音频流，false 为继续发布音频流
m_rtcEngine->muteLocalAudioStream(false);
// true 为暂停发布视频流，false 为继续发布视频流
m_rtcEngine->muteLocalVideoStream(false);
```

**v4.x**

```cpp
// m_rtcEngine 可以定义为 IRtcEngine* 或者 IRtcEngineEx*
// IRtcEngineEx 继承自 IRtcEngine，拥有更丰富的 API 以及多频道的能力
// 建议通过 ChannelMediaOptions 精细化控制音视频流的发布
// 注意：v4.x 默认可通过 ChannelMediaOptions 精细化控制音视频的发布及订阅
ChannelMediaOptions options;
options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
// true 为订阅音频流，false 为不订阅音频流
options.autoSubscribeAudio = true;
// true 为订阅视频流，false 为不订阅视频流
options.autoSubscribeVideo = true;
// true 为发布麦克风采集的音频流，false 为不发布
options.publishMicrophoneTrack = true;
// true 为发布摄像头采集的视频流，false 为不发布
options.publishCameraTrack = true;
// ex 频道则需使用 updateChannelMediaOptionsEx 替代
m_rtcEngine->updateChannelMediaOptions(options);
```

#### 将视频源从摄像头切换为共享的屏幕 [#将视频源从摄像头切换为共享的屏幕-4]

**v2.x & v3.x**

```cpp
SIZE size; size.cx = 100;
size.cy = 100;
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index);
ScreenCaptureParameters capParam;
// 根据实际需求，调用 startScreenCaptureByDisplayId、startScreenCaptureByWindowId 或 startScreenCaptureByScreenRect 来共享屏幕
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

**v4.x**

```cpp
SIZE size;
size.cx = 100;
size.cy = 100;
agora::rtc::Rectangle regionRect = { 0, 0, 0, 0 };
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index); ScreenCaptureParameters capParam;
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
ChannelMediaOptions options;
options.publishCameraTrack = false;
// 发布屏幕共享流
options.publishScreenTrack = true;
m_rtcEngine->updateChannelMediaOptions(options);
......
// 停止发布屏幕共享流
options.publishScreenTrack = false;
m_rtcEngine->updateChannelMediaOptions(options)
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

#### 发布 mp4 视频 [#发布-mp4-视频-4]

**v2.x & v3.x**
需要独立进程并通过 MediaPlayer Kit 实现，详见[媒体播放器组件（3.x）](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/mediaplayer_win?platform=Windows)。

**v4.x**
初始化 MediaPlayer。

1. 发布麦克风和摄像头采集的流

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    // 默认发布麦克风采集的音频流
    options.publishMicrophoneTrack = true;
    // 默认发布摄像头采集的视频流
    options.publishCameraTrack = true;
    // 加入频道
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 切换为发布媒体播放器的音视频流

    ```cpp
    IMediaPlayer* m_mediaPlayer = m_rtcEngine->createMediaPlayer().get();
    ChannelMediaOptions options;
    // 停止发布麦克风采集的音频流
    options.publishMicrophoneTrack = false;
    // 停止发布摄像头采集的视频流
    options.publishCameraTrack = false;
    // 指定发布的媒体播放器的 playerId
    options.publishMediaPlayerId = m_mediaPlayer->getMediaPlayerId();
    // 切换为媒体播放器的音频流
    options.publishMediaPlayerAudioTrack = true;
    // 切换为媒体播放器的视频流
    options.publishMediaPlayerVideoTrack = true;
    m_rtcEngine->updateChannelMediaOptions(options);
    ```

### 多频道 [#多频道-4]

本节提供多频道中常用功能的示例代码。

#### 默认在两个频道发布流 [#默认在两个频道发布流-4]
例如：

- 在 `channel1` 发布麦克风和摄像头采集的流。
- 在 `channel2` 发布屏幕共享流。

**v2.x & v3.x**
不支持单进程同时在两个频道发布音视频流，所以需要通过多进程分别创建引擎。

1. 进程 1 发布摄像头流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->enableVideo();
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    ```

2. 进程 2 发布屏幕共享流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
    ```

**v4.x**
支持单进程直接在多个频道内发布音视频流。

1. 发布摄像头流。

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    options.publishCameraTrack = true;
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 发布屏幕共享流。

    ```cpp
    // 指定待分享的屏幕
    agora::rtc::Rectangle rc;
    ScreenCaptureParameters scp;
    scp.frameRate = 15;
    scp.bitrate = 0;
    HWND hWnd = ::GetDesktopWindow();
    RECT destop_rc;
    ::GetWindowRect(hWnd, &destop_rc);
    scp.dimensions.width = destop_rc.right - destop_rc.left;
    scp.dimensions.height = destop_rc.bottom - destop_rc.top;
    m_rtcEngine->startScreenCaptureByScreenRect(rc, rc, scp);
    // 加入多频道
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    // 如果是加入同一频道，则不必重复订阅音频流
    options.autoSubscribeAudio = false;
    // 如果是加入同一频道，则不必重复订阅视频流
    options.autoSubscribeVideo = false;
    // ex 频道不发布摄像头流
    options.publishCameraTrack = false;
    // ex 频道不发布麦克风流
    options.publishMicrophoneTrack = false;
    // ex 频道发布屏幕共享流
    options.publishScreenTrack = true;
    agora::rtc::RtcConnection connection;
    connection.channelId = szChannelId;
    // 自定义 uid
    connection.localUid = screenId;
    m_rtcEngine->joinChannelEx(APP_TOKEN, connection, options, &eventHandlerScreen);
    ```

### 屏幕共享 [#屏幕共享-4]

本节提供屏幕共享的示例代码。

#### 集成方式 [#集成方式-4]
**v2.x & v3.x**
直接调用屏幕共享方法，无需集成屏幕共享插件。

**v4.x**
需在调用屏幕共享方法之前集成如下屏幕共享插件：

- Android: `AgoraScreenShareExtension.aar` 和 `libagora_screen_capture_extension.so`
- iOS/macOS: `AgoraReplayKitExtension.xcframework`
- Windows: `libagora_screen_capture_extension.dll`

#### 实现方法 [#实现方法-4]

**v2.x & v3.x**

- Android：[屏幕共享介绍](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/screensharing_android?platform=Android)及[示例代码](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/screensharing_android?platform=Android#示例代码-1)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiProcess.java)
- iOS：[屏幕共享介绍](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/screensharing_ios?platform=iOS)及[示例代码](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/screensharing_ios?platform=iOS#实现方法)
- Windows：[屏幕共享介绍](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/screensharing_windows?platform=Windows)及[实现方法](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/screensharing_windows?platform=Windows#实现方法)
- macOS：[屏幕共享介绍](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/screensharing_mac?platform=macOS)及[实现方法](https://docportal.shengwang.cn/cn/live-streaming-premium-legacy/screensharing_mac?platform=macOS#实现方法)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/ScreenShare)

**v4.x**

- Android：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchCameraScreenShare.java)
- iOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/Agora-ScreenShare-Extension)
- Windows：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp)
- macOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/ScreenShare)

### 自定义采集 [#自定义采集-4]

如果你在 v2.x 或 v3.x 使用了自采集功能，例如通过视频自采集使用第三方美颜，声网推荐你在 v4.x 使用功能完善且更易用的 SDK 采集。

:::info[信息]
v4.x 完善了 SDK 的视频模块并在 Android 上支持了 Texture 格式。一般情况下，声网推荐用户在升级后使用 SDK 采集。在特殊场景下，例如用户需要统一对接不同厂商的 SDK，则可沿用原有自采集方案。v4.x 的 SDK 采集相对于自采集有如下优势：

    - 易用性高：用户不需要处理视频采集、机型适配、采集 Profile 策略，最大程度降低 App 代码复杂度并减少因采集导致的问题。此外，SDK 采集可以更好地避免音画不同步的问题。
    - 问题调查成本低：SDK 支持上传采集分辨率、帧率、美颜耗时等数据，声网后台会进行数据分析，从而快速、清晰地定位丢帧等问题原因。
    - 维护成本低：SDK 采集有研发团队持续迭代优化，QA 测试也比较完善。自采集插件主要是重要问题修复，缺乏持续迭代。
    - 问题修复速度快：采集策略可以配置下发，部分机型问题可以快速修复。
    - 其他须知：MediaIO 相关的 API 在 v4.x 中已删除，需要改用 Push 模式。
:::

在设置视频采集的过程中，你可能会有如下疑问：

Q: `stopPreview`、`enableLocalVideo`、`muteLocalVideoStream` 有什么区别？

A: 三个 API 区别如下：

- `stopPreview` 用于停止本地预览，不会停止本地视频采集或发布本地视频流。
- `enableLocalVideo(false)` 用于停止本地视频采集。例如，App 切后台需要停止视频采集的情况。
- `muteLocalVideoStream(true)` 用于停止发布本地视频流。例如，App 希望保持占用摄像头但停止发布视频流的情况。

Q: 推荐在什么时机注册原始数据回调？

A: 用户在主播角色下调用 `joinChannel` 时会自动启动摄像头，所以建议用户在初始化引擎后直接调用 `registerVideoFrameObserver`。

## 升级前版本为 v4.0.0 Preview 或 v4.0.0 Beta [#升级前版本为-v400-preview-或-v400-beta-4]

#### 中断性变化 [#中断性变化-4]

- 删除了 `AUDIO_SCENARIO_TYPE` 中的 `AUDIO_SCENARIO_HIGH_DEFINITION`，改用功能一致的 `AUDIO_SCENARIO_GAME_STREAMING`。
- 修改了 `option` 命名，明确了对于 microphone track 的控制定义。将 `ChannelMediaOptions` 中的 `publishAudioTrack` 变更为 `publishMicrophoneTrack`。
- 为了丰富多路流功能的多样性，在视频流相关的回调事件中增加了视频源类型参数。例如：`onFirstLocalVideoFrame`、`onFirstLocalVideoFramePublished`、`onVideoSizeChanged`、`onVideoPublishStateChanged`、`onLocalVideoStats`、`onLocalVideoStateChanged`。
- 旁路推流  API 优化：
  - 为降低旁路推流集成难度，该版本优化了推流 API 设计，并改善了推流客户端和服务端内部对网络问题的处理机制。你可以通过如下方法体验优化后的旁路推流功能：
    - `startRtmpStreamWithoutTranscoding`: 开始非转码推流。与旧推流方法 `addPublishStreamUrl(false)` 作用相同。
    - `startRtmpStreamWithTranscoding`: 开始 CDN 直播推流并设置转码属性。与依次调用旧推流方法 `setLiveTranscoding`、`addPublishStreamUrl(true)` 的作用相同。
    - `updateRtmpTranscoding`: 更新转码属性。与非首次调用旧推流方法 `setLiveTranscoding` 的作用相同。
    - `stopRtmpStream`: 结束 CDN 直播推流。与旧推流方法 `removePublishStreamUrl` 作用相同。
    - （仅 Android 平台）`onRtmpStreamingStateChanged` 回调中的所有参数类型改为 Int 类型。
  - 该版本废弃 `addPublishStreamUrl`、`setLiveTranscoding`、`removePublishStreamUrl` 这三个旧推流方法，声网推荐你使用新的推流方法，并参考[旁路推流](/zh-CN/realtime-media/media-push)更新你的业务代码逻辑。
- 删除 `startAudioMixing` 中的 `replace`（Bool 类型）参数。`startAudioMixing` 默认发送麦克风音频和媒体播放器音频的混音，如果需要停止发送麦克风音频，你可以根据是否要继续录音，调用以下方法：
  - 需要录音：调用 `updateChannelMediaOptions` 将 `publishMicrophoneTrack` 设置为 `false`，此时麦克风仍然打开。
  - 不需要录音：调用 `enableLocalAudio` 关闭麦克风。
- （仅 Android 平台）`onRemoteAudioStateChanged` 回调中的所有参数类型改为 Int 类型。

#### 行为变更 & 新增 API [#行为变更--新增-api-4]

- `IAudioFrameObserver` 新增回调 `getObservedAudioFramePosition`、`getRecordAudioParams`、`getPlaybackAudioParams`、`getMixedAudioParams`。
- 屏幕共享采用插件方式，详见[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)。
- `enableVirtualBackground` 方法新增 `SegmentationProperty` 和 `segProperty` 参数。

## 参考信息 [#参考信息-4]

下表展示一些常用 API 在不同版本的区别：

<Tabs defaultValue="stream-controls" groupId="rtc-upgrade-reference-electron">
<TabsList>
  <TabsTrigger value="stream-controls">音视频流控制</TabsTrigger>
  <TabsTrigger value="role-preview">角色与预览</TabsTrigger>
  <TabsTrigger value="local-capture">本地采集</TabsTrigger>
</TabsList>

<TabsContent value="stream-controls">

| 常用 API | muteLocalAudioStream | muteLocalVideoStream |
| --- | --- | --- |
| v2.x & v3.x | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalAudioStream` 的设置。 | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalVideoStream` 设置。 |
| v4.0.0 Preview 或 v4.0.0 Beta | 功能等同于更新发布流控制 `ChannelMediaOptions.publishAudioTrack`。如果频道内主播调用该方法并将参数设置为 `false` 则会打开麦克风。 | 等同于更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-4) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-4) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-4"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalAudioStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishMicrophoneTrack` 为 `true`， `muteLocalAudioStream` 为  `true`，则仍然不发送音频。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-4"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalVideoStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishCameraTrack` 为 `true`，`muteLocalVideoStream` 为 `true`，  仍然不发送视频。

</TabsContent>

<TabsContent value="role-preview">

| 常用 API | setClientRole | startPreview |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x（不支持多路上行流，不能同时在多频道中设置为主播）。 | 同 v4.x。 |
| v4.0.0 Preview 或 v4.0.0 Beta | `setClientRole` 会受到 `muteLocalAudioStream` 和 `muteLocalVideoStream` 的影响。例如，如果先调用 `muteLocalAudioStream(true)` 和 `muteLocalVideoStream(true)`， 再调用 `setClientRole` 为主播，主播仍然不能发流。 | 需要主动调用 `startPreview`/`stopPreview`，以开启/关闭本地视图。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-4) | 加入频道时，主播角色发布摄像头采集的视频流时，会自动开启本地视图。如果 App 主动调用 `startPreview`，则离开频道时也需要主动调用 `stopPreview` 以关闭本地视图。 |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-4"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details**

- `setClientRole` 优先级高于  `enableLocalAudio`/`enableLocalVideo`。
- 如果在加入频道前调用该方法，SDK  会先记录该状态。
- 如果进频道后切换用户角色为主播，会根据 `enableLocalAudio`/`enableLocalVideo` 的状态，打开媒体采集并自动发布。
- 如果切换用户角色为观众，则会关闭采集并停止发布。
- 在多频道场景中，用户可以在每个频道都切换为主播角色，从而进行发流。在频道中，通过  `updateChannelMediaOptionsEx` 控制流发布。

</TabsContent>

<TabsContent value="local-capture">

| 常用 API | enableLocalAudio | enableLocalVideo |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x | 同 v4.x |
| v4.0.0 Preview 或 v4.0.0 Beta | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-4) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-4) |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-4) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-4) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-4"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭麦克风。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制  `ChannelMediaOptions.publishAudioTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-4"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭摄像头。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-4"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details**

- 如果在频道外调用，不会打开/关闭麦克风，且加入频道后会自动打开/关闭麦克风。
- 如果在频道内调用，会打开/关闭麦克风。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-4"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details**

- 如果在频道外调用，不会打开/关闭摄像头，且加入频道后会自动打开/关闭摄像头。
- 如果在频道内调用，会打开/关闭摄像头。

</TabsContent>
</Tabs>
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="unity" />
声网支持将 RTC SDK 从 2.x、3.x、4.0.0 Preview 或 4.0.0 Beta 版本升级到 4.x 版本，升级步骤以及版本间的变更介绍见[迁移指南](/zh-CN/realtime-media/rtc/reference/migration-guide)。

本文介绍在 SDK 升级后需要修改 API 以及相关实现代码的场景，以帮助你顺利完成迁移。

:::info[信息]
如无特别说明，本文 API 名称均以 C++ 为例，平台均以 Windows 为例。
:::

## 升级前版本为 2.x 或 3.x [#升级前版本为-2x-或-3x-5]

如果你已经在 v2.x 或 v3.x 中用到了本节介绍的功能和场景，可参考对应示例更新 App 代码。

### 单频道 [#单频道-5]

本节提供单频道中常用功能的示例代码。

#### 初始化引擎 [#初始化引擎-5]

**v2.x & v3.x**

- Android: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Basic/JoinChannelVideo)

**v4.x**

- Android: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Basic/JoinChannelVideo)

#### 默认发布麦克风和摄像头采集的音视频流 [#默认发布麦克风和摄像头采集的音视频流-5]

**v2.x & v3.x**

```cpp
// 通过 muteLocalAudioStream 和 muteLocalVideoStream 控制是否发流
// true 为暂停发布音频流，false 为继续发布音频流
m_rtcEngine->muteLocalAudioStream(false);
// true 为暂停发布视频流，false 为继续发布视频流
m_rtcEngine->muteLocalVideoStream(false);
```

**v4.x**

```cpp
// m_rtcEngine 可以定义为 IRtcEngine* 或者 IRtcEngineEx*
// IRtcEngineEx 继承自 IRtcEngine，拥有更丰富的 API 以及多频道的能力
// 建议通过 ChannelMediaOptions 精细化控制音视频流的发布
// 注意：v4.x 默认可通过 ChannelMediaOptions 精细化控制音视频的发布及订阅
ChannelMediaOptions options;
options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
// true 为订阅音频流，false 为不订阅音频流
options.autoSubscribeAudio = true;
// true 为订阅视频流，false 为不订阅视频流
options.autoSubscribeVideo = true;
// true 为发布麦克风采集的音频流，false 为不发布
options.publishMicrophoneTrack = true;
// true 为发布摄像头采集的视频流，false 为不发布
options.publishCameraTrack = true;
// ex 频道则需使用 updateChannelMediaOptionsEx 替代
m_rtcEngine->updateChannelMediaOptions(options);
```

#### 将视频源从摄像头切换为共享的屏幕 [#将视频源从摄像头切换为共享的屏幕-5]

**v2.x & v3.x**

```cpp
SIZE size; size.cx = 100;
size.cy = 100;
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index);
ScreenCaptureParameters capParam;
// 根据实际需求，调用 startScreenCaptureByDisplayId、startScreenCaptureByWindowId 或 startScreenCaptureByScreenRect 来共享屏幕
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

**v4.x**

```cpp
SIZE size;
size.cx = 100;
size.cy = 100;
agora::rtc::Rectangle regionRect = { 0, 0, 0, 0 };
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index); ScreenCaptureParameters capParam;
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
ChannelMediaOptions options;
options.publishCameraTrack = false;
// 发布屏幕共享流
options.publishScreenTrack = true;
m_rtcEngine->updateChannelMediaOptions(options);
......
// 停止发布屏幕共享流
options.publishScreenTrack = false;
m_rtcEngine->updateChannelMediaOptions(options)
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

#### 发布 mp4 视频 [#发布-mp4-视频-5]

**v2.x & v3.x**
需要独立进程并通过 MediaPlayer Kit 实现，详见[媒体播放器组件（3.x）](/zh-CN/realtime-media/rtc/build/audio/media-player)。

**v4.x**
初始化 MediaPlayer。

1. 发布麦克风和摄像头采集的流

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    // 默认发布麦克风采集的音频流
    options.publishMicrophoneTrack = true;
    // 默认发布摄像头采集的视频流
    options.publishCameraTrack = true;
    // 加入频道
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 切换为发布媒体播放器的音视频流

    ```cpp
    IMediaPlayer* m_mediaPlayer = m_rtcEngine->createMediaPlayer().get();
    ChannelMediaOptions options;
    // 停止发布麦克风采集的音频流
    options.publishMicrophoneTrack = false;
    // 停止发布摄像头采集的视频流
    options.publishCameraTrack = false;
    // 指定发布的媒体播放器的 playerId
    options.publishMediaPlayerId = m_mediaPlayer->getMediaPlayerId();
    // 切换为媒体播放器的音频流
    options.publishMediaPlayerAudioTrack = true;
    // 切换为媒体播放器的视频流
    options.publishMediaPlayerVideoTrack = true;
    m_rtcEngine->updateChannelMediaOptions(options);
    ```

### 多频道 [#多频道-5]

本节提供多频道中常用功能的示例代码。

#### 默认在两个频道发布流 [#默认在两个频道发布流-5]
例如：

- 在 `channel1` 发布麦克风和摄像头采集的流。
- 在 `channel2` 发布屏幕共享流。

**v2.x & v3.x**
不支持单进程同时在两个频道发布音视频流，所以需要通过多进程分别创建引擎。

1. 进程 1 发布摄像头流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->enableVideo();
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    ```

2. 进程 2 发布屏幕共享流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
    ```

**v4.x**
支持单进程直接在多个频道内发布音视频流。

1. 发布摄像头流。

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    options.publishCameraTrack = true;
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 发布屏幕共享流。

    ```cpp
    // 指定待分享的屏幕
    agora::rtc::Rectangle rc;
    ScreenCaptureParameters scp;
    scp.frameRate = 15;
    scp.bitrate = 0;
    HWND hWnd = ::GetDesktopWindow();
    RECT destop_rc;
    ::GetWindowRect(hWnd, &destop_rc);
    scp.dimensions.width = destop_rc.right - destop_rc.left;
    scp.dimensions.height = destop_rc.bottom - destop_rc.top;
    m_rtcEngine->startScreenCaptureByScreenRect(rc, rc, scp);
    // 加入多频道
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    // 如果是加入同一频道，则不必重复订阅音频流
    options.autoSubscribeAudio = false;
    // 如果是加入同一频道，则不必重复订阅视频流
    options.autoSubscribeVideo = false;
    // ex 频道不发布摄像头流
    options.publishCameraTrack = false;
    // ex 频道不发布麦克风流
    options.publishMicrophoneTrack = false;
    // ex 频道发布屏幕共享流
    options.publishScreenTrack = true;
    agora::rtc::RtcConnection connection;
    connection.channelId = szChannelId;
    // 自定义 uid
    connection.localUid = screenId;
    m_rtcEngine->joinChannelEx(APP_TOKEN, connection, options, &eventHandlerScreen);
    ```

### 屏幕共享 [#屏幕共享-5]

本节提供屏幕共享的示例代码。

#### 集成方式 [#集成方式-5]
**v2.x & v3.x**
直接调用屏幕共享方法，无需集成屏幕共享插件。

**v4.x**
需在调用屏幕共享方法之前集成如下屏幕共享插件：

- Android: `AgoraScreenShareExtension.aar` 和 `libagora_screen_capture_extension.so`
- iOS/macOS: `AgoraReplayKitExtension.xcframework`
- Windows: `libagora_screen_capture_extension.dll`

#### 实现方法 [#实现方法-5]

**v2.x & v3.x**

- Android：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiProcess.java)
- iOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)
- Windows：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)
- macOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/ScreenShare)

**v4.x**

- Android：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchCameraScreenShare.java)
- iOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/Agora-ScreenShare-Extension)
- Windows：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp)
- macOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/ScreenShare)

### 自定义采集 [#自定义采集-5]

如果你在 v2.x 或 v3.x 使用了自采集功能，例如通过视频自采集使用第三方美颜，声网推荐你在 v4.x 使用功能完善且更易用的 SDK 采集。

:::info[信息]
v4.x 完善了 SDK 的视频模块并在 Android 上支持了 Texture 格式。一般情况下，声网推荐用户在升级后使用 SDK 采集。在特殊场景下，例如用户需要统一对接不同厂商的 SDK，则可沿用原有自采集方案。v4.x 的 SDK 采集相对于自采集有如下优势：

    - 易用性高：用户不需要处理视频采集、机型适配、采集 Profile 策略，最大程度降低 App 代码复杂度并减少因采集导致的问题。此外，SDK 采集可以更好地避免音画不同步的问题。
    - 问题调查成本低：SDK 支持上传采集分辨率、帧率、美颜耗时等数据，声网后台会进行数据分析，从而快速、清晰地定位丢帧等问题原因。
    - 维护成本低：SDK 采集有研发团队持续迭代优化，QA 测试也比较完善。自采集插件主要是重要问题修复，缺乏持续迭代。
    - 问题修复速度快：采集策略可以配置下发，部分机型问题可以快速修复。
    - 其他须知：MediaIO 相关的 API 在 v4.x 中已删除，需要改用 Push 模式。
:::

在设置视频采集的过程中，你可能会有如下疑问：

Q: `stopPreview`、`enableLocalVideo`、`muteLocalVideoStream` 有什么区别？

A: 三个 API 区别如下：

- `stopPreview` 用于停止本地预览，不会停止本地视频采集或发布本地视频流。
- `enableLocalVideo(false)` 用于停止本地视频采集。例如，App 切后台需要停止视频采集的情况。
- `muteLocalVideoStream(true)` 用于停止发布本地视频流。例如，App 希望保持占用摄像头但停止发布视频流的情况。

Q: 推荐在什么时机注册原始数据回调？

A: 用户在主播角色下调用 `joinChannel` 时会自动启动摄像头，所以建议用户在初始化引擎后直接调用 `registerVideoFrameObserver`。

## 升级前版本为 v4.0.0 Preview 或 v4.0.0 Beta [#升级前版本为-v400-preview-或-v400-beta-5]

#### 中断性变化 [#中断性变化-5]

- 删除了 `AUDIO_SCENARIO_TYPE` 中的 `AUDIO_SCENARIO_HIGH_DEFINITION`，改用功能一致的 `AUDIO_SCENARIO_GAME_STREAMING`。
- 修改了 `option` 命名，明确了对于 microphone track 的控制定义。将 `ChannelMediaOptions` 中的 `publishAudioTrack` 变更为 `publishMicrophoneTrack`。
- 为了丰富多路流功能的多样性，在视频流相关的回调事件中增加了视频源类型参数。例如：`onFirstLocalVideoFrame`、`onFirstLocalVideoFramePublished`、`onVideoSizeChanged`、`onVideoPublishStateChanged`、`onLocalVideoStats`、`onLocalVideoStateChanged`。
- 旁路推流  API 优化：
  - 为降低旁路推流集成难度，该版本优化了推流 API 设计，并改善了推流客户端和服务端内部对网络问题的处理机制。你可以通过如下方法体验优化后的旁路推流功能：
    - `startRtmpStreamWithoutTranscoding`: 开始非转码推流。与旧推流方法 `addPublishStreamUrl(false)` 作用相同。
    - `startRtmpStreamWithTranscoding`: 开始 CDN 直播推流并设置转码属性。与依次调用旧推流方法 `setLiveTranscoding`、`addPublishStreamUrl(true)` 的作用相同。
    - `updateRtmpTranscoding`: 更新转码属性。与非首次调用旧推流方法 `setLiveTranscoding` 的作用相同。
    - `stopRtmpStream`: 结束 CDN 直播推流。与旧推流方法 `removePublishStreamUrl` 作用相同。
    - （仅 Android 平台）`onRtmpStreamingStateChanged` 回调中的所有参数类型改为 Int 类型。
  - 该版本废弃 `addPublishStreamUrl`、`setLiveTranscoding`、`removePublishStreamUrl` 这三个旧推流方法，声网推荐你使用新的推流方法，并参考[旁路推流](/zh-CN/realtime-media/media-push)更新你的业务代码逻辑。
- 删除 `startAudioMixing` 中的 `replace`（Bool 类型）参数。`startAudioMixing` 默认发送麦克风音频和媒体播放器音频的混音，如果需要停止发送麦克风音频，你可以根据是否要继续录音，调用以下方法：
  - 需要录音：调用 `updateChannelMediaOptions` 将 `publishMicrophoneTrack` 设置为 `false`，此时麦克风仍然打开。
  - 不需要录音：调用 `enableLocalAudio` 关闭麦克风。
- （仅 Android 平台）`onRemoteAudioStateChanged` 回调中的所有参数类型改为 Int 类型。

#### 行为变更 & 新增 API [#行为变更--新增-api-5]

- `IAudioFrameObserver` 新增回调 `getObservedAudioFramePosition`、`getRecordAudioParams`、`getPlaybackAudioParams`、`getMixedAudioParams`。
- 屏幕共享采用插件方式，详见[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)。
- `enableVirtualBackground` 方法新增 `SegmentationProperty` 和 `segProperty` 参数。

## 参考信息 [#参考信息-5]

下表展示一些常用 API 在不同版本的区别：

<Tabs defaultValue="stream-controls" groupId="rtc-upgrade-reference-unity">
<TabsList>
  <TabsTrigger value="stream-controls">音视频流控制</TabsTrigger>
  <TabsTrigger value="role-preview">角色与预览</TabsTrigger>
  <TabsTrigger value="local-capture">本地采集</TabsTrigger>
</TabsList>

<TabsContent value="stream-controls">

| 常用 API | muteLocalAudioStream | muteLocalVideoStream |
| --- | --- | --- |
| v2.x & v3.x | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalAudioStream` 的设置。 | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalVideoStream` 设置。 |
| v4.0.0 Preview 或 v4.0.0 Beta | 功能等同于更新发布流控制 `ChannelMediaOptions.publishAudioTrack`。如果频道内主播调用该方法并将参数设置为 `false` 则会打开麦克风。 | 等同于更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-5) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-5) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-5"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalAudioStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishMicrophoneTrack` 为 `true`， `muteLocalAudioStream` 为  `true`，则仍然不发送音频。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-5"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalVideoStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishCameraTrack` 为 `true`，`muteLocalVideoStream` 为 `true`，  仍然不发送视频。

</TabsContent>

<TabsContent value="role-preview">

| 常用 API | setClientRole | startPreview |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x（不支持多路上行流，不能同时在多频道中设置为主播）。 | 同 v4.x。 |
| v4.0.0 Preview 或 v4.0.0 Beta | `setClientRole` 会受到 `muteLocalAudioStream` 和 `muteLocalVideoStream` 的影响。例如，如果先调用 `muteLocalAudioStream(true)` 和 `muteLocalVideoStream(true)`， 再调用 `setClientRole` 为主播，主播仍然不能发流。 | 需要主动调用 `startPreview`/`stopPreview`，以开启/关闭本地视图。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-5) | 加入频道时，主播角色发布摄像头采集的视频流时，会自动开启本地视图。如果 App 主动调用 `startPreview`，则离开频道时也需要主动调用 `stopPreview` 以关闭本地视图。 |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-5"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details**

- `setClientRole` 优先级高于  `enableLocalAudio`/`enableLocalVideo`。
- 如果在加入频道前调用该方法，SDK  会先记录该状态。
- 如果进频道后切换用户角色为主播，会根据 `enableLocalAudio`/`enableLocalVideo` 的状态，打开媒体采集并自动发布。
- 如果切换用户角色为观众，则会关闭采集并停止发布。
- 在多频道场景中，用户可以在每个频道都切换为主播角色，从而进行发流。在频道中，通过  `updateChannelMediaOptionsEx` 控制流发布。

</TabsContent>

<TabsContent value="local-capture">

| 常用 API | enableLocalAudio | enableLocalVideo |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x | 同 v4.x |
| v4.0.0 Preview 或 v4.0.0 Beta | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-5) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-5) |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-5) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-5) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-5"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭麦克风。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制  `ChannelMediaOptions.publishAudioTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-5"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭摄像头。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-5"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details**

- 如果在频道外调用，不会打开/关闭麦克风，且加入频道后会自动打开/关闭麦克风。
- 如果在频道内调用，会打开/关闭麦克风。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-5"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details**

- 如果在频道外调用，不会打开/关闭摄像头，且加入频道后会自动打开/关闭摄像头。
- 如果在频道内调用，会打开/关闭摄像头。

</TabsContent>
</Tabs>
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="flutter" />
声网支持将 RTC SDK 从 2.x、3.x、4.0.0 Preview 或 4.0.0 Beta 版本升级到 4.x 版本，升级步骤以及版本间的变更介绍见[迁移指南](/zh-CN/realtime-media/rtc/reference/migration-guide)。

本文介绍在 SDK 升级后需要修改 API 以及相关实现代码的场景，以帮助你顺利完成迁移。

:::info[信息]
如无特别说明，本文 API 名称均以 C++ 为例，平台均以 Windows 为例。
:::

## 升级前版本为 2.x 或 3.x [#升级前版本为-2x-或-3x-6]

如果你已经在 v2.x 或 v3.x 中用到了本节介绍的功能和场景，可参考对应示例更新 App 代码。

### 单频道 [#单频道-6]

本节提供单频道中常用功能的示例代码。

#### 初始化引擎 [#初始化引擎-6]

**v2.x & v3.x**

- Android: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Basic/JoinChannelVideo)

**v4.x**

- Android: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Basic/JoinChannelVideo)

#### 默认发布麦克风和摄像头采集的音视频流 [#默认发布麦克风和摄像头采集的音视频流-6]

**v2.x & v3.x**

```cpp
// 通过 muteLocalAudioStream 和 muteLocalVideoStream 控制是否发流
// true 为暂停发布音频流，false 为继续发布音频流
m_rtcEngine->muteLocalAudioStream(false);
// true 为暂停发布视频流，false 为继续发布视频流
m_rtcEngine->muteLocalVideoStream(false);
```

**v4.x**

```cpp
// m_rtcEngine 可以定义为 IRtcEngine* 或者 IRtcEngineEx*
// IRtcEngineEx 继承自 IRtcEngine，拥有更丰富的 API 以及多频道的能力
// 建议通过 ChannelMediaOptions 精细化控制音视频流的发布
// 注意：v4.x 默认可通过 ChannelMediaOptions 精细化控制音视频的发布及订阅
ChannelMediaOptions options;
options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
// true 为订阅音频流，false 为不订阅音频流
options.autoSubscribeAudio = true;
// true 为订阅视频流，false 为不订阅视频流
options.autoSubscribeVideo = true;
// true 为发布麦克风采集的音频流，false 为不发布
options.publishMicrophoneTrack = true;
// true 为发布摄像头采集的视频流，false 为不发布
options.publishCameraTrack = true;
// ex 频道则需使用 updateChannelMediaOptionsEx 替代
m_rtcEngine->updateChannelMediaOptions(options);
```

#### 将视频源从摄像头切换为共享的屏幕 [#将视频源从摄像头切换为共享的屏幕-6]

**v2.x & v3.x**

```cpp
SIZE size; size.cx = 100;
size.cy = 100;
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index);
ScreenCaptureParameters capParam;
// 根据实际需求，调用 startScreenCaptureByDisplayId、startScreenCaptureByWindowId 或 startScreenCaptureByScreenRect 来共享屏幕
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

**v4.x**

```cpp
SIZE size;
size.cx = 100;
size.cy = 100;
agora::rtc::Rectangle regionRect = { 0, 0, 0, 0 };
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index); ScreenCaptureParameters capParam;
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
ChannelMediaOptions options;
options.publishCameraTrack = false;
// 发布屏幕共享流
options.publishScreenTrack = true;
m_rtcEngine->updateChannelMediaOptions(options);
......
// 停止发布屏幕共享流
options.publishScreenTrack = false;
m_rtcEngine->updateChannelMediaOptions(options)
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

#### 发布 mp4 视频 [#发布-mp4-视频-6]

**v2.x & v3.x**
需要独立进程并通过 MediaPlayer Kit 实现，详见[媒体播放器组件（3.x）](/zh-CN/realtime-media/rtc/build/audio/media-player)。

**v4.x**
初始化 MediaPlayer。

1. 发布麦克风和摄像头采集的流

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    // 默认发布麦克风采集的音频流
    options.publishMicrophoneTrack = true;
    // 默认发布摄像头采集的视频流
    options.publishCameraTrack = true;
    // 加入频道
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 切换为发布媒体播放器的音视频流

    ```cpp
    IMediaPlayer* m_mediaPlayer = m_rtcEngine->createMediaPlayer().get();
    ChannelMediaOptions options;
    // 停止发布麦克风采集的音频流
    options.publishMicrophoneTrack = false;
    // 停止发布摄像头采集的视频流
    options.publishCameraTrack = false;
    // 指定发布的媒体播放器的 playerId
    options.publishMediaPlayerId = m_mediaPlayer->getMediaPlayerId();
    // 切换为媒体播放器的音频流
    options.publishMediaPlayerAudioTrack = true;
    // 切换为媒体播放器的视频流
    options.publishMediaPlayerVideoTrack = true;
    m_rtcEngine->updateChannelMediaOptions(options);
    ```

### 多频道 [#多频道-6]

本节提供多频道中常用功能的示例代码。

#### 默认在两个频道发布流 [#默认在两个频道发布流-6]
例如：

- 在 `channel1` 发布麦克风和摄像头采集的流。
- 在 `channel2` 发布屏幕共享流。

**v2.x & v3.x**
不支持单进程同时在两个频道发布音视频流，所以需要通过多进程分别创建引擎。

1. 进程 1 发布摄像头流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->enableVideo();
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    ```

2. 进程 2 发布屏幕共享流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
    ```

**v4.x**
支持单进程直接在多个频道内发布音视频流。

1. 发布摄像头流。

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    options.publishCameraTrack = true;
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 发布屏幕共享流。

    ```cpp
    // 指定待分享的屏幕
    agora::rtc::Rectangle rc;
    ScreenCaptureParameters scp;
    scp.frameRate = 15;
    scp.bitrate = 0;
    HWND hWnd = ::GetDesktopWindow();
    RECT destop_rc;
    ::GetWindowRect(hWnd, &destop_rc);
    scp.dimensions.width = destop_rc.right - destop_rc.left;
    scp.dimensions.height = destop_rc.bottom - destop_rc.top;
    m_rtcEngine->startScreenCaptureByScreenRect(rc, rc, scp);
    // 加入多频道
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    // 如果是加入同一频道，则不必重复订阅音频流
    options.autoSubscribeAudio = false;
    // 如果是加入同一频道，则不必重复订阅视频流
    options.autoSubscribeVideo = false;
    // ex 频道不发布摄像头流
    options.publishCameraTrack = false;
    // ex 频道不发布麦克风流
    options.publishMicrophoneTrack = false;
    // ex 频道发布屏幕共享流
    options.publishScreenTrack = true;
    agora::rtc::RtcConnection connection;
    connection.channelId = szChannelId;
    // 自定义 uid
    connection.localUid = screenId;
    m_rtcEngine->joinChannelEx(APP_TOKEN, connection, options, &eventHandlerScreen);
    ```

### 屏幕共享 [#屏幕共享-6]

本节提供屏幕共享的示例代码。

#### 集成方式 [#集成方式-6]
**v2.x & v3.x**
直接调用屏幕共享方法，无需集成屏幕共享插件。

**v4.x**
需在调用屏幕共享方法之前集成如下屏幕共享插件：

- Android: `AgoraScreenShareExtension.aar` 和 `libagora_screen_capture_extension.so`
- iOS/macOS: `AgoraReplayKitExtension.xcframework`
- Windows: `libagora_screen_capture_extension.dll`

#### 实现方法 [#实现方法-6]

**v2.x & v3.x**

- Android：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiProcess.java)
- iOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)
- Windows：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)
- macOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/ScreenShare)

**v4.x**

- Android：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchCameraScreenShare.java)
- iOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/Agora-ScreenShare-Extension)
- Windows：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp)
- macOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/ScreenShare)

### 自定义采集 [#自定义采集-6]

如果你在 v2.x 或 v3.x 使用了自采集功能，例如通过视频自采集使用第三方美颜，声网推荐你在 v4.x 使用功能完善且更易用的 SDK 采集。

:::info[信息]
v4.x 完善了 SDK 的视频模块并在 Android 上支持了 Texture 格式。一般情况下，声网推荐用户在升级后使用 SDK 采集。在特殊场景下，例如用户需要统一对接不同厂商的 SDK，则可沿用原有自采集方案。v4.x 的 SDK 采集相对于自采集有如下优势：

    - 易用性高：用户不需要处理视频采集、机型适配、采集 Profile 策略，最大程度降低 App 代码复杂度并减少因采集导致的问题。此外，SDK 采集可以更好地避免音画不同步的问题。
    - 问题调查成本低：SDK 支持上传采集分辨率、帧率、美颜耗时等数据，声网后台会进行数据分析，从而快速、清晰地定位丢帧等问题原因。
    - 维护成本低：SDK 采集有研发团队持续迭代优化，QA 测试也比较完善。自采集插件主要是重要问题修复，缺乏持续迭代。
    - 问题修复速度快：采集策略可以配置下发，部分机型问题可以快速修复。
    - 其他须知：MediaIO 相关的 API 在 v4.x 中已删除，需要改用 Push 模式。
:::

在设置视频采集的过程中，你可能会有如下疑问：

Q: `stopPreview`、`enableLocalVideo`、`muteLocalVideoStream` 有什么区别？

A: 三个 API 区别如下：

- `stopPreview` 用于停止本地预览，不会停止本地视频采集或发布本地视频流。
- `enableLocalVideo(false)` 用于停止本地视频采集。例如，App 切后台需要停止视频采集的情况。
- `muteLocalVideoStream(true)` 用于停止发布本地视频流。例如，App 希望保持占用摄像头但停止发布视频流的情况。

Q: 推荐在什么时机注册原始数据回调？

A: 用户在主播角色下调用 `joinChannel` 时会自动启动摄像头，所以建议用户在初始化引擎后直接调用 `registerVideoFrameObserver`。

## 升级前版本为 v4.0.0 Preview 或 v4.0.0 Beta [#升级前版本为-v400-preview-或-v400-beta-6]

#### 中断性变化 [#中断性变化-6]

- 删除了 `AUDIO_SCENARIO_TYPE` 中的 `AUDIO_SCENARIO_HIGH_DEFINITION`，改用功能一致的 `AUDIO_SCENARIO_GAME_STREAMING`。
- 修改了 `option` 命名，明确了对于 microphone track 的控制定义。将 `ChannelMediaOptions` 中的 `publishAudioTrack` 变更为 `publishMicrophoneTrack`。
- 为了丰富多路流功能的多样性，在视频流相关的回调事件中增加了视频源类型参数。例如：`onFirstLocalVideoFrame`、`onFirstLocalVideoFramePublished`、`onVideoSizeChanged`、`onVideoPublishStateChanged`、`onLocalVideoStats`、`onLocalVideoStateChanged`。
- 旁路推流  API 优化：
  - 为降低旁路推流集成难度，该版本优化了推流 API 设计，并改善了推流客户端和服务端内部对网络问题的处理机制。你可以通过如下方法体验优化后的旁路推流功能：
    - `startRtmpStreamWithoutTranscoding`: 开始非转码推流。与旧推流方法 `addPublishStreamUrl(false)` 作用相同。
    - `startRtmpStreamWithTranscoding`: 开始 CDN 直播推流并设置转码属性。与依次调用旧推流方法 `setLiveTranscoding`、`addPublishStreamUrl(true)` 的作用相同。
    - `updateRtmpTranscoding`: 更新转码属性。与非首次调用旧推流方法 `setLiveTranscoding` 的作用相同。
    - `stopRtmpStream`: 结束 CDN 直播推流。与旧推流方法 `removePublishStreamUrl` 作用相同。
    - （仅 Android 平台）`onRtmpStreamingStateChanged` 回调中的所有参数类型改为 Int 类型。
  - 该版本废弃 `addPublishStreamUrl`、`setLiveTranscoding`、`removePublishStreamUrl` 这三个旧推流方法，声网推荐你使用新的推流方法，并参考[旁路推流](/zh-CN/realtime-media/media-push)更新你的业务代码逻辑。
- 删除 `startAudioMixing` 中的 `replace`（Bool 类型）参数。`startAudioMixing` 默认发送麦克风音频和媒体播放器音频的混音，如果需要停止发送麦克风音频，你可以根据是否要继续录音，调用以下方法：
  - 需要录音：调用 `updateChannelMediaOptions` 将 `publishMicrophoneTrack` 设置为 `false`，此时麦克风仍然打开。
  - 不需要录音：调用 `enableLocalAudio` 关闭麦克风。
- （仅 Android 平台）`onRemoteAudioStateChanged` 回调中的所有参数类型改为 Int 类型。

#### 行为变更 & 新增 API [#行为变更--新增-api-6]

- `IAudioFrameObserver` 新增回调 `getObservedAudioFramePosition`、`getRecordAudioParams`、`getPlaybackAudioParams`、`getMixedAudioParams`。
- 屏幕共享采用插件方式，详见[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)。
- `enableVirtualBackground` 方法新增 `SegmentationProperty` 和 `segProperty` 参数。

## 参考信息 [#参考信息-6]

下表展示一些常用 API 在不同版本的区别：

<Tabs defaultValue="stream-controls" groupId="rtc-upgrade-reference-flutter">
<TabsList>
  <TabsTrigger value="stream-controls">音视频流控制</TabsTrigger>
  <TabsTrigger value="role-preview">角色与预览</TabsTrigger>
  <TabsTrigger value="local-capture">本地采集</TabsTrigger>
</TabsList>

<TabsContent value="stream-controls">

| 常用 API | muteLocalAudioStream | muteLocalVideoStream |
| --- | --- | --- |
| v2.x & v3.x | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalAudioStream` 的设置。 | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalVideoStream` 设置。 |
| v4.0.0 Preview 或 v4.0.0 Beta | 功能等同于更新发布流控制 `ChannelMediaOptions.publishAudioTrack`。如果频道内主播调用该方法并将参数设置为 `false` 则会打开麦克风。 | 等同于更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-6) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-6) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-6"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalAudioStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishMicrophoneTrack` 为 `true`， `muteLocalAudioStream` 为  `true`，则仍然不发送音频。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-6"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalVideoStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishCameraTrack` 为 `true`，`muteLocalVideoStream` 为 `true`，  仍然不发送视频。

</TabsContent>

<TabsContent value="role-preview">

| 常用 API | setClientRole | startPreview |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x（不支持多路上行流，不能同时在多频道中设置为主播）。 | 同 v4.x。 |
| v4.0.0 Preview 或 v4.0.0 Beta | `setClientRole` 会受到 `muteLocalAudioStream` 和 `muteLocalVideoStream` 的影响。例如，如果先调用 `muteLocalAudioStream(true)` 和 `muteLocalVideoStream(true)`， 再调用 `setClientRole` 为主播，主播仍然不能发流。 | 需要主动调用 `startPreview`/`stopPreview`，以开启/关闭本地视图。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-6) | 加入频道时，主播角色发布摄像头采集的视频流时，会自动开启本地视图。如果 App 主动调用 `startPreview`，则离开频道时也需要主动调用 `stopPreview` 以关闭本地视图。 |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-6"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details**

- `setClientRole` 优先级高于  `enableLocalAudio`/`enableLocalVideo`。
- 如果在加入频道前调用该方法，SDK  会先记录该状态。
- 如果进频道后切换用户角色为主播，会根据 `enableLocalAudio`/`enableLocalVideo` 的状态，打开媒体采集并自动发布。
- 如果切换用户角色为观众，则会关闭采集并停止发布。
- 在多频道场景中，用户可以在每个频道都切换为主播角色，从而进行发流。在频道中，通过  `updateChannelMediaOptionsEx` 控制流发布。

</TabsContent>

<TabsContent value="local-capture">

| 常用 API | enableLocalAudio | enableLocalVideo |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x | 同 v4.x |
| v4.0.0 Preview 或 v4.0.0 Beta | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-6) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-6) |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-6) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-6) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-6"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭麦克风。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制  `ChannelMediaOptions.publishAudioTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-6"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭摄像头。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-6"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details**

- 如果在频道外调用，不会打开/关闭麦克风，且加入频道后会自动打开/关闭麦克风。
- 如果在频道内调用，会打开/关闭麦克风。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-6"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details**

- 如果在频道外调用，不会打开/关闭摄像头，且加入频道后会自动打开/关闭摄像头。
- 如果在频道内调用，会打开/关闭摄像头。

</TabsContent>
</Tabs>
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="react-native" />
声网支持将 RTC SDK 从 2.x、3.x、4.0.0 Preview 或 4.0.0 Beta 版本升级到 4.x 版本，升级步骤以及版本间的变更介绍见[迁移指南](/zh-CN/realtime-media/rtc/reference/migration-guide)。

本文介绍在 SDK 升级后需要修改 API 以及相关实现代码的场景，以帮助你顺利完成迁移。

:::info[信息]
如无特别说明，本文 API 名称均以 C++ 为例，平台均以 Windows 为例。
:::

## 升级前版本为 2.x 或 3.x [#升级前版本为-2x-或-3x-7]

如果你已经在 v2.x 或 v3.x 中用到了本节介绍的功能和场景，可参考对应示例更新 App 代码。

### 单频道 [#单频道-7]

本节提供单频道中常用功能的示例代码。

#### 初始化引擎 [#初始化引擎-7]

**v2.x & v3.x**

- Android: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/iOS/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现互动直播](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Basic/JoinChannelVideo)

**v4.x**

- Android: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java)
- iOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo)
- Windows: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp)
- macOS: [实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)及[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Basic/JoinChannelVideo)

#### 默认发布麦克风和摄像头采集的音视频流 [#默认发布麦克风和摄像头采集的音视频流-7]

**v2.x & v3.x**

```cpp
// 通过 muteLocalAudioStream 和 muteLocalVideoStream 控制是否发流
// true 为暂停发布音频流，false 为继续发布音频流
m_rtcEngine->muteLocalAudioStream(false);
// true 为暂停发布视频流，false 为继续发布视频流
m_rtcEngine->muteLocalVideoStream(false);
```

**v4.x**

```cpp
// m_rtcEngine 可以定义为 IRtcEngine* 或者 IRtcEngineEx*
// IRtcEngineEx 继承自 IRtcEngine，拥有更丰富的 API 以及多频道的能力
// 建议通过 ChannelMediaOptions 精细化控制音视频流的发布
// 注意：v4.x 默认可通过 ChannelMediaOptions 精细化控制音视频的发布及订阅
ChannelMediaOptions options;
options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
// true 为订阅音频流，false 为不订阅音频流
options.autoSubscribeAudio = true;
// true 为订阅视频流，false 为不订阅视频流
options.autoSubscribeVideo = true;
// true 为发布麦克风采集的音频流，false 为不发布
options.publishMicrophoneTrack = true;
// true 为发布摄像头采集的视频流，false 为不发布
options.publishCameraTrack = true;
// ex 频道则需使用 updateChannelMediaOptionsEx 替代
m_rtcEngine->updateChannelMediaOptions(options);
```

#### 将视频源从摄像头切换为共享的屏幕 [#将视频源从摄像头切换为共享的屏幕-7]

**v2.x & v3.x**

```cpp
SIZE size; size.cx = 100;
size.cy = 100;
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index);
ScreenCaptureParameters capParam;
// 根据实际需求，调用 startScreenCaptureByDisplayId、startScreenCaptureByWindowId 或 startScreenCaptureByScreenRect 来共享屏幕
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

**v4.x**

```cpp
SIZE size;
size.cx = 100;
size.cy = 100;
agora::rtc::Rectangle regionRect = { 0, 0, 0, 0 };
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(index); ScreenCaptureParameters capParam;
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
ChannelMediaOptions options;
options.publishCameraTrack = false;
// 发布屏幕共享流
options.publishScreenTrack = true;
m_rtcEngine->updateChannelMediaOptions(options);
......
// 停止发布屏幕共享流
options.publishScreenTrack = false;
m_rtcEngine->updateChannelMediaOptions(options)
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
```

#### 发布 mp4 视频 [#发布-mp4-视频-7]

**v2.x & v3.x**
需要独立进程并通过 MediaPlayer Kit 实现，详见[媒体播放器组件（3.x）](/zh-CN/realtime-media/rtc/build/audio/media-player)。

**v4.x**
初始化 MediaPlayer。

1. 发布麦克风和摄像头采集的流

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    // 默认发布麦克风采集的音频流
    options.publishMicrophoneTrack = true;
    // 默认发布摄像头采集的视频流
    options.publishCameraTrack = true;
    // 加入频道
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 切换为发布媒体播放器的音视频流

    ```cpp
    IMediaPlayer* m_mediaPlayer = m_rtcEngine->createMediaPlayer().get();
    ChannelMediaOptions options;
    // 停止发布麦克风采集的音频流
    options.publishMicrophoneTrack = false;
    // 停止发布摄像头采集的视频流
    options.publishCameraTrack = false;
    // 指定发布的媒体播放器的 playerId
    options.publishMediaPlayerId = m_mediaPlayer->getMediaPlayerId();
    // 切换为媒体播放器的音频流
    options.publishMediaPlayerAudioTrack = true;
    // 切换为媒体播放器的视频流
    options.publishMediaPlayerVideoTrack = true;
    m_rtcEngine->updateChannelMediaOptions(options);
    ```

### 多频道 [#多频道-7]

本节提供多频道中常用功能的示例代码。

#### 默认在两个频道发布流 [#默认在两个频道发布流-7]
例如：

- 在 `channel1` 发布麦克风和摄像头采集的流。
- 在 `channel2` 发布屏幕共享流。

**v2.x & v3.x**
不支持单进程同时在两个频道发布音视频流，所以需要通过多进程分别创建引擎。

1. 进程 1 发布摄像头流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->enableVideo();
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    ```

2. 进程 2 发布屏幕共享流。

    ```cpp
    m_rtcEngine->setClientRole(CLIENT_ROLE_BROADCASTER);
    m_rtcEngine->joinChannel(accessToken, channelId, "", uid);
    m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
    ```

**v4.x**
支持单进程直接在多个频道内发布音视频流。

1. 发布摄像头流。

    ```cpp
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    options.autoSubscribeAudio = true;
    options.autoSubscribeVideo = true;
    options.publishCameraTrack = true;
    m_rtcEngine->joinChannel(APP_TOKEN, szChannelId, 0, options);
    ```

2. 发布屏幕共享流。

    ```cpp
    // 指定待分享的屏幕
    agora::rtc::Rectangle rc;
    ScreenCaptureParameters scp;
    scp.frameRate = 15;
    scp.bitrate = 0;
    HWND hWnd = ::GetDesktopWindow();
    RECT destop_rc;
    ::GetWindowRect(hWnd, &destop_rc);
    scp.dimensions.width = destop_rc.right - destop_rc.left;
    scp.dimensions.height = destop_rc.bottom - destop_rc.top;
    m_rtcEngine->startScreenCaptureByScreenRect(rc, rc, scp);
    // 加入多频道
    ChannelMediaOptions options;
    options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
    options.clientRoleType = CLIENT_ROLE_BROADCASTER;
    // 如果是加入同一频道，则不必重复订阅音频流
    options.autoSubscribeAudio = false;
    // 如果是加入同一频道，则不必重复订阅视频流
    options.autoSubscribeVideo = false;
    // ex 频道不发布摄像头流
    options.publishCameraTrack = false;
    // ex 频道不发布麦克风流
    options.publishMicrophoneTrack = false;
    // ex 频道发布屏幕共享流
    options.publishScreenTrack = true;
    agora::rtc::RtcConnection connection;
    connection.channelId = szChannelId;
    // 自定义 uid
    connection.localUid = screenId;
    m_rtcEngine->joinChannelEx(APP_TOKEN, connection, options, &eventHandlerScreen);
    ```

### 屏幕共享 [#屏幕共享-7]

本节提供屏幕共享的示例代码。

#### 集成方式 [#集成方式-7]
**v2.x & v3.x**
直接调用屏幕共享方法，无需集成屏幕共享插件。

**v4.x**
需在调用屏幕共享方法之前集成如下屏幕共享插件：

- Android: `AgoraScreenShareExtension.aar` 和 `libagora_screen_capture_extension.so`
- iOS/macOS: `AgoraReplayKitExtension.xcframework`
- Windows: `libagora_screen_capture_extension.dll`

#### 实现方法 [#实现方法-7]

**v2.x & v3.x**

- Android：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/legacy/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MultiProcess.java)
- iOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[示例代码](/zh-CN/realtime-media/rtc/build/video/screen-share)
- Windows：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)
- macOS：[屏幕共享介绍](/zh-CN/realtime-media/rtc/build/video/screen-share)及[实现方法](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/legacy/macOS/APIExample/Examples/Advanced/ScreenShare)

**v4.x**

- Android：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SwitchCameraScreenShare.java)
- iOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/Agora-ScreenShare-Extension)
- Windows：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/blob/main/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp)
- macOS：[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)，[示例项目](https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/ScreenShare)

### 自定义采集 [#自定义采集-7]

如果你在 v2.x 或 v3.x 使用了自采集功能，例如通过视频自采集使用第三方美颜，声网推荐你在 v4.x 使用功能完善且更易用的 SDK 采集。

:::info[信息]
v4.x 完善了 SDK 的视频模块并在 Android 上支持了 Texture 格式。一般情况下，声网推荐用户在升级后使用 SDK 采集。在特殊场景下，例如用户需要统一对接不同厂商的 SDK，则可沿用原有自采集方案。v4.x 的 SDK 采集相对于自采集有如下优势：

    - 易用性高：用户不需要处理视频采集、机型适配、采集 Profile 策略，最大程度降低 App 代码复杂度并减少因采集导致的问题。此外，SDK 采集可以更好地避免音画不同步的问题。
    - 问题调查成本低：SDK 支持上传采集分辨率、帧率、美颜耗时等数据，声网后台会进行数据分析，从而快速、清晰地定位丢帧等问题原因。
    - 维护成本低：SDK 采集有研发团队持续迭代优化，QA 测试也比较完善。自采集插件主要是重要问题修复，缺乏持续迭代。
    - 问题修复速度快：采集策略可以配置下发，部分机型问题可以快速修复。
    - 其他须知：MediaIO 相关的 API 在 v4.x 中已删除，需要改用 Push 模式。
:::

在设置视频采集的过程中，你可能会有如下疑问：

Q: `stopPreview`、`enableLocalVideo`、`muteLocalVideoStream` 有什么区别？

A: 三个 API 区别如下：

- `stopPreview` 用于停止本地预览，不会停止本地视频采集或发布本地视频流。
- `enableLocalVideo(false)` 用于停止本地视频采集。例如，App 切后台需要停止视频采集的情况。
- `muteLocalVideoStream(true)` 用于停止发布本地视频流。例如，App 希望保持占用摄像头但停止发布视频流的情况。

Q: 推荐在什么时机注册原始数据回调？

A: 用户在主播角色下调用 `joinChannel` 时会自动启动摄像头，所以建议用户在初始化引擎后直接调用 `registerVideoFrameObserver`。

## 升级前版本为 v4.0.0 Preview 或 v4.0.0 Beta [#升级前版本为-v400-preview-或-v400-beta-7]

#### 中断性变化 [#中断性变化-7]

- 删除了 `AUDIO_SCENARIO_TYPE` 中的 `AUDIO_SCENARIO_HIGH_DEFINITION`，改用功能一致的 `AUDIO_SCENARIO_GAME_STREAMING`。
- 修改了 `option` 命名，明确了对于 microphone track 的控制定义。将 `ChannelMediaOptions` 中的 `publishAudioTrack` 变更为 `publishMicrophoneTrack`。
- 为了丰富多路流功能的多样性，在视频流相关的回调事件中增加了视频源类型参数。例如：`onFirstLocalVideoFrame`、`onFirstLocalVideoFramePublished`、`onVideoSizeChanged`、`onVideoPublishStateChanged`、`onLocalVideoStats`、`onLocalVideoStateChanged`。
- 旁路推流  API 优化：
  - 为降低旁路推流集成难度，该版本优化了推流 API 设计，并改善了推流客户端和服务端内部对网络问题的处理机制。你可以通过如下方法体验优化后的旁路推流功能：
    - `startRtmpStreamWithoutTranscoding`: 开始非转码推流。与旧推流方法 `addPublishStreamUrl(false)` 作用相同。
    - `startRtmpStreamWithTranscoding`: 开始 CDN 直播推流并设置转码属性。与依次调用旧推流方法 `setLiveTranscoding`、`addPublishStreamUrl(true)` 的作用相同。
    - `updateRtmpTranscoding`: 更新转码属性。与非首次调用旧推流方法 `setLiveTranscoding` 的作用相同。
    - `stopRtmpStream`: 结束 CDN 直播推流。与旧推流方法 `removePublishStreamUrl` 作用相同。
    - （仅 Android 平台）`onRtmpStreamingStateChanged` 回调中的所有参数类型改为 Int 类型。
  - 该版本废弃 `addPublishStreamUrl`、`setLiveTranscoding`、`removePublishStreamUrl` 这三个旧推流方法，声网推荐你使用新的推流方法，并参考[旁路推流](/zh-CN/realtime-media/media-push)更新你的业务代码逻辑。
- 删除 `startAudioMixing` 中的 `replace`（Bool 类型）参数。`startAudioMixing` 默认发送麦克风音频和媒体播放器音频的混音，如果需要停止发送麦克风音频，你可以根据是否要继续录音，调用以下方法：
  - 需要录音：调用 `updateChannelMediaOptions` 将 `publishMicrophoneTrack` 设置为 `false`，此时麦克风仍然打开。
  - 不需要录音：调用 `enableLocalAudio` 关闭麦克风。
- （仅 Android 平台）`onRemoteAudioStateChanged` 回调中的所有参数类型改为 Int 类型。

#### 行为变更 & 新增 API [#行为变更--新增-api-7]

- `IAudioFrameObserver` 新增回调 `getObservedAudioFramePosition`、`getRecordAudioParams`、`getPlaybackAudioParams`、`getMixedAudioParams`。
- 屏幕共享采用插件方式，详见[屏幕共享](/zh-CN/realtime-media/rtc/build/video/screen-share)。
- `enableVirtualBackground` 方法新增 `SegmentationProperty` 和 `segProperty` 参数。

## 参考信息 [#参考信息-7]

下表展示一些常用 API 在不同版本的区别：

<Tabs defaultValue="stream-controls" groupId="rtc-upgrade-reference-react-native">
<TabsList>
  <TabsTrigger value="stream-controls">音视频流控制</TabsTrigger>
  <TabsTrigger value="role-preview">角色与预览</TabsTrigger>
  <TabsTrigger value="local-capture">本地采集</TabsTrigger>
</TabsList>

<TabsContent value="stream-controls">

| 常用 API | muteLocalAudioStream | muteLocalVideoStream |
| --- | --- | --- |
| v2.x & v3.x | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalAudioStream` 的设置。 | 带 `options` 参数的 `joinChannel` 方法会覆盖 `muteLocalVideoStream` 设置。 |
| v4.0.0 Preview 或 v4.0.0 Beta | 功能等同于更新发布流控制 `ChannelMediaOptions.publishAudioTrack`。如果频道内主播调用该方法并将参数设置为 `false` 则会打开麦克风。 | 等同于更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-7) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-7) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1-7"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-1 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalAudioStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishMicrophoneTrack` 为 `true`， `muteLocalAudioStream` 为  `true`，则仍然不发送音频。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2-7"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-0-3-2 details**

- 加入频道前后调用该方法都会生效。
- 网络控制  `muteLocalVideoStream` 和发布流控制 `ChannelMediaOptions` 相互独立：如果设置  `publishCameraTrack` 为 `true`，`muteLocalVideoStream` 为 `true`，  仍然不发送视频。

</TabsContent>

<TabsContent value="role-preview">

| 常用 API | setClientRole | startPreview |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x（不支持多路上行流，不能同时在多频道中设置为主播）。 | 同 v4.x。 |
| v4.0.0 Preview 或 v4.0.0 Beta | `setClientRole` 会受到 `muteLocalAudioStream` 和 `muteLocalVideoStream` 的影响。例如，如果先调用 `muteLocalAudioStream(true)` 和 `muteLocalVideoStream(true)`， 再调用 `setClientRole` 为主播，主播仍然不能发流。 | 需要主动调用 `startPreview`/`stopPreview`，以开启/关闭本地视图。 |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-7) | 加入频道时，主播角色发布摄像头采集的视频流时，会自动开启本地视图。如果 App 主动调用 `startPreview`，则离开频道时也需要主动调用 `stopPreview` 以关闭本地视图。 |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1-7"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-1-3-1 details**

- `setClientRole` 优先级高于  `enableLocalAudio`/`enableLocalVideo`。
- 如果在加入频道前调用该方法，SDK  会先记录该状态。
- 如果进频道后切换用户角色为主播，会根据 `enableLocalAudio`/`enableLocalVideo` 的状态，打开媒体采集并自动发布。
- 如果切换用户角色为观众，则会关闭采集并停止发布。
- 在多频道场景中，用户可以在每个频道都切换为主播角色，从而进行发流。在频道中，通过  `updateChannelMediaOptionsEx` 控制流发布。

</TabsContent>

<TabsContent value="local-capture">

| 常用 API | enableLocalAudio | enableLocalVideo |
| --- | --- | --- |
| v2.x & v3.x | 同 v4.x | 同 v4.x |
| v4.0.0 Preview 或 v4.0.0 Beta | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-7) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-7) |
| v4.x | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-7) | [after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details](#table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-7) |

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1-7"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-1 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭麦克风。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制  `ChannelMediaOptions.publishAudioTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2-7"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-2-2 details**

- 主播角色调用（包括频道内和频道外）会打开/关闭摄像头。
- 观众角色调用返回错误码。
- 如果在频道内调用，还会更新发布流控制 `ChannelMediaOptions.publishCameraTrack`。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1-7"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-1 details**

- 如果在频道外调用，不会打开/关闭麦克风，且加入频道后会自动打开/关闭麦克风。
- 如果在频道内调用，会打开/关闭麦克风。

<a id="table-slot-after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2-7"></a>

**after-migrate-android-ios-macos-windows-electron-rn-flutter-unity-html-2-3-2 details**

- 如果在频道外调用，不会打开/关闭摄像头，且加入频道后会自动打开/关闭摄像头。
- 如果在频道内调用，会打开/关闭摄像头。

</TabsContent>
</Tabs>
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>
