# Migrate from Video SDK 3.x (/en/realtime-media/broadcast-streaming/reference/migration-guide)

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

<_PlatformTabsGroup groupMode="structured" canonicalPlatform="web" platforms="[&#x22;android&#x22;,&#x22;ios&#x22;,&#x22;web&#x22;]" showTabs="true">
  <_PlatformPanel platform="android">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="android" />

    * [Migration steps](#migration-steps) to upgrade your app to Broadcast Streaming v4.x.

    * [What's changed](#what-has-changed) between Broadcast Streaming v2.x and v4.x.

    ## Migration steps [#migration-steps]

    This section introduces the main steps to upgrade the SDK from v2.x or v3.7.x to v4.x.

    1. Integrate the SDK

    See [Get started](../../../index) for more information about integrating the v4.x SDK into your project.

    2. Rename imported classes

    After successfully integrating the SDK, you need to update the codes of imported classes from the `io.agora.rtc` prefix to the `io.agora.rtc2` prefix in the `/app/java/com.example.<projectname>/MainActivity` file of your project.

    <CalloutContainer type="info">
      <CalloutDescription>
        The location of `AgoraRtcChannelMediaOptions.java` in the 4.x SDK is also changed from `/models` to the root directory.
      </CalloutDescription>
    </CalloutContainer>

    3. Update the Agora code in your app

    The 4.x SDK has optimized or modified the implementation of some functions, resulting in incompatibility with the v3.7.x SDK. In order to retain Agora functionality in your app, update the code in your app according to [What has changed](#what-has-changed).

    ## What has changed [#what-has-changed]

    This section introduces the main changes of 4.x compared to v3.7.x in the following categories. You need to update the code of your app according to your business use-case.

    * [Breaking changes](#breaking-changes): Introduces API compatibility changes that have a big impact. You need to spend significant time modifying the related implementation.

    * [Behavior changes](#behavior-changes): Introduces changes caused by reasonable optimization of the SDK default behavior and API behavior. Less time is required to modify the related implementation, if any.

    * [Function gaps](#function-gaps): Introduces functions that were supported in v3.7.x but are not supported in 4.x. However, these functions are intended to be added in a future release.

    * [Removed APIs](#removed-apis): Introduces APIs that were supported in v3.7.x but removed in 4.x. Most of these APIs have alternatives in 4.x. Modifying the related implementation should require less time.

    * [Naming and data type changes](#naming-and-data-type-changes): Introduces the naming and data type changes of the main APIs. You can update the relevant implementation according to the error message in the IDE, which is expected to take less time.

    ### Breaking changes [#breaking-changes]

    After upgrading from v3.7.x to 4.x, the way the APIs implement some functions is different. This section introduces compatibility changes for these APIs and the logic for updating the code of your app.

    #### Multiple channels [#multiple-channels]

    In v3.7.x, the SDK provides the `RtcChannel` and `IRtcChannelEventHandler` classes to implement multi-channel control. The v3.7.x SDK supports subscribing to the audio and video streams of multiple channels, but only supports publishing one group of audio and video streams in one channel.

    4.x introduces the following changes:

    * The SDK provides a `RtcEngineEx` class to implement multi-channel functions. Combined with the multi-channel capabilities, an `RtcEngine` instance can simultaneously collect multiple audio and video streams and publish them to the remote end to adapt to various business use-cases.

    After calling `joinChannel` to join the first channel, call `joinChannelEx` multiple times to join multiple channels to publish the specified stream to different channels using different user IDs (`localUid`) and `ChannelMediaOptions` settings.

    * A new `RtcConnection` class is added to represent the connection established by `joinChannel`. A connection is determined by the channel name (`channelId`) and `localUid`. You can control the publishing and subscribing state of different connections through `RtcConnection`. The SDK adds `Ex` in the name of all APIs with a `connection` parameter, corresponding to the `RtcConnection` class, to distinguish them, and gathers these APIs in the `RtcEngineEx` class to implement more multi-stream functions.

    Setting `ChannelMediaOptions`, 4.x supports using one `RtcEngine` instance to capture audio and video streams from multiple sources at the same time and publish them to the remote user, adapting to various business use-cases. For example:

    * Simultaneously publish video streams collected by multiple cameras or multiple screen sharing streams.
    * Simultaneously publish a media player stream, a screen-sharing stream, and a video stream captured by the front and rear cameras.
    * Simultaneously publish one audio stream captured by the microphone and one by the custom audio source, and one media player steam.

    Combined with the multi-channel capability, you can also experience the following functions:

    * Publish multiple groups of audio and video streams to the remote user through different `localUid`s.
    * Mix multiple audio streams and publish them to the remote user through one `localUid`.
    * Mix multiple video streams and publish them to the remote user through one `localUid`.

    `RtcChannel` and `RtcEngine` of v3.7.x are partially duplicated and overlap in their functionality, so 4.x hides the `RtcChannel` and `IRtcChannelEventHandler` classes. See the [JoinMultiChannel](https://github.com/AgoraIO/API-Examples/tree/master/windows/APIExample/APIExample/Advanced/MultiChannel) sample project for more details on how to replace `RtcChannel` with `joinChannel` and `ChannelMediaOptions`. The expected migration cost is one day or less.

    If you need to continue to use the `RtcChannel` and `IRtcChannelEventHandler` classes, contact [support@agora.io](mailto\:support@agora.io). The decision whether to maintain compatibility in a future release is based on your feedback.

    #### Media stream publishing control [#media-stream-publishing-control]

    In v3.7.x, the SDK uses the `publishLocalAudio` and `publishLocalVideo` members in `ChannelMediaOptions` to control the audio and video publishing state in the channel.

    In 4.x, the SDK gathers more channel-related settings into `ChannelMediaOptions`, including publishing of audio and video streams from different sources, automatic subscribing of audio and video streams, user role switching, token updating, and default dual stream options. You can determine the media stream publishing and subscribing behavior by calling `joinChannel` or `joinChannelEx` when joining a channel, or you can flexibly update the media options by calling `updateChannelMediaOptions` after joining a channel, such as switching video sources.

    See the [JoinChannelVideo](https://github.com/AgoraIO/API-Examples/tree/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java) sample project to update the code in your app.

    #### Custom video source and renderer [#custom-video-source-and-renderer]

    In v3.7.x, the SDK provides the following ways to implement the custom video source and renderer:

    * Push mode for custom video source
    * Raw video data mode for custom video renderer
    * MediaIO mode (`IVideoSource`) for custom video source
    * MediaIO mode (`IVideoSink`) for custom video renderer

    4.x unifies the audio and video processing pipeline internally. Push mode and raw video data mode are simpler for integration, so Agora recommends using them for custom video source and renderer and removes the following related APIs of the MediaIO mode:

    * `IVideoSource`
    * `IVideoSink`
    * `IVideoFrameConsumer`
    * `setVideoSource`
    * `setLocalVideoRenderer`
    * `setRemoteVideoRenderer`

    If you use the MediaIO mode in v3.7.x to implement custom video source, custom video renderer, switching video source, and other functions, Agora recommends updating the code of your app by referring to the following sample projects:

    * Custom video source: [CustomVideoSourcePush](https://github.com/AgoraIO/API-Examples/tree/master/windows/APIExample/APIExample/Advanced/CustomVideoCapture)

    * Custom video renderer: [CustomVideoRender](https://github.com/AgoraIO/API-Examples/tree/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/CustomRemoteVideoRender.java)

    * Switching video source: [ScreenShare](https://github.com/AgoraIO/API-Examples/tree/master/windows/APIExample/APIExample/Advanced/ScreenShare)

    #### Error codes and warning codes [#error-codes-and-warning-codes]

    In v3.7.x, the SDK returns warning codes through the `onWarning` callback.

    To facilitate locating and troubleshooting issues, 4.x reports problems and causes through the return values of APIs or different callbacks for listening to states. For example:

    * `getConnectionState`: Reports the network connection state.

    * `onLocalAudioStateChanged`: Reports the local audio state.

    * `onLocalVideoStateChanged`: Reports the local video state.

    * `onRemoteAudioStateChanged`: Reports the remote audio state.

    * `onRemoteVideoStateChanged`: Reports the remote video state.

    As a consequence, 4.x removes the `onWarning` callback.

    ### Behavior changes [#behavior-changes]

    This section introduces changes caused by reasonable optimization of the SDK default behavior and API behavior.

    #### Channel profile [#channel-profile]

    In v3.7.x, the default channel profile is `CHANNEL_PROFILE_COMMUNICATION` (the communication profile).

    Since the interactive streaming profile supports seamless switching from one-to-one calls to multi-user interaction, since v3.0.0, Agora has changed the internal transmission protocol and the ability to resist poor network conditions in the communication profile to be consistent with the interactive streaming profile. In 4.x, Agora also changed the default channel profile to `CHANNEL_PROFILE_LIVE_BROADCASTING` (the interactive streaming profile).

    #### Default log file [#default-log-file]

    In v3.7.x, when the SDK creates multiple log files, the earlier files are named in a agorasdk\_x.log format, such as agorasdk\_1.log. 4.x modified the naming format to agorasdk.x.log, such as agorasdk.1.log. Additionally, 4.x adds the `agoraapi.log` file to record API logs.

    #### Fast channel switching [#fast-channel-switching]

    In v3.7.x, you need to call `switchChannel` to quickly switch a channel.

    In 4.x, you can achieve the same switching speed as `switchChannel` in v3.7.x by switching a channel through `leaveChannel` and `joinChannel`. Therefore, 4.x removes `switchChannel`. If you call `switchChannel` to quickly switch a channel in v3.7.x, see the [VideoQuickSwitch](https://github.com/AgoraIO/API-Examples/tree/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/VideoQuickSwitch.java) sample project to update the code in your app.

    #### Agora self-developed extensions [#agora-self-developed-extensions]

    v4.0.0 adds the feature of automatically loading self-developed dynamic libraries based on v4.0.0 Beta. As of this release, when using an Agora self-developed extension, you do not need to manually integrate the dynamic library in the project. The SDK automatically loads the dynamic library during the initialization phase of `RtcEngine`. You can directly call the corresponding method of the extension to enable this feature.

    | API                                                                                                                | Extension type               |
    | :----------------------------------------------------------------------------------------------------------------- | :--------------------------- |
    | `enableVirtualBackground`                                                                                          | Virtual background extension |
    | * `setBeautyEffectOptions`

    * `setVideoDenoiserOptions`

    * `setLowlightEnhanceOptions`

    * `setColorEnhanceOptions` | Video enhancement extension  |
    | `enableRemoteSuperResolution`                                                                                      | Super resolution extension   |
    | - `setAudioEffectPreset`

    - `setVoiceBeautifierPreset`

    - `setVoiceConversionPreset`                               | Voice beautifier extension   |
    | `enableSpatialAudio`                                                                                               | Spatial audio extension      |
    | `enableContentInspect`                                                                                             | Content moderation extension |

    #### Virtual metronome [#virtual-metronome]

    When you call `startRhythmPlayer`, the SDK publishes the sound of the virtual metronome to the remote by default. If you do not want the remote users to hear the virtual metronome, refer to the following operations:

    * In v3.7.0, call the `configRhythmPlayer,` and set `publish` to `false`.
    * In v4.0.0, set `publishRhythmPlayerTrack` in `ChannelMediaOptions` to `false`.

    #### Volume indication [#volume-indication]

    You can call the `enableAudioVolumeIndication` method to enable the user's volume indication function. There is a difference in the definition of the `interval` parameter in the `enableAudioVolumeIndication` method between v3.7.0 and v4.0.0, as follows:

    * In v3.7.0, Agora recommends that you set the `interval` to be greater than 200 ms. The minimum is 10 ms; otherwise, the `onAudioVolumeIndication` callback is not received.
    * In v4.0.0, you must set the `interval `to an integer that is a multiple of 200 ms. If the value of `interval` is lower than 200, the SDK automatically adjusts it to 200.

    When the user's volume indication is enabled, the SDK triggers the `onAudioVolumeIndication` callback at the time interval set in this method. If the local user calls `muteLocalAudioStream` to mute themselves, the SDK behaves inconsistently between v3.7.0 and v4.0.0:

    * In v3.7.0, the SDK immediately stops reporting the local user's volume indication callback.
    * In v4.0.0, the SDK continues to report the local user's volume indication callback.

    #### Device permissions [#device-permissions]

    * In v3.7.0, `LOCAL_AUDIO_STREAM_ERROR_DEVICE_NO_PERMISSION` in `onLocalAudioStateChanged` reports that there is no permission to start the capture device, and `LOCAL_VIDEO_STREAM_ERROR_DEVICE_NO_PERMISSION` in `onLocalVideoStateChanged` reports that there is no permission to start the video capture device.

    * In v4.0.0, the permission statuses of the audio and video capture devices are both reported in the `onPermissionError` callback.

    #### Pre-call network test [#pre-call-network-test]

    If you need to start or stop the network connection quality test, note the following:

    * In v3.7.0, you can call `enableLastmileTest` to start the network quality test. If you want to stop the network test, you need to call `disableLastmileTest`.

    * In v4.0.0, you can call `startLastmileProbeTest` to enable network quality testing. If you want to stop network testing, you need to call `stopLastmileProbeTest`.

    #### Remote media event triggering mechanism [#remote-media-event-triggering-mechanism]

    In the following use-cases, the mechanism of triggering remote media events is changed:

    * Use-case 1: When the host calls `muteLocalAudioStream` or `muteLocalVideoStream` outside the channel to change the publishing status of the local audio or video stream and then joins the channel.
    * Use-case 2: When the host calls `muteLocalAudioStream` or `muteLocalVideoStream` within the channel to change the publishing status of the local audio or video stream, and then other users join the channel.

    The behavior differences of Agora SDK between v3.7.0 and v4.0.0 are listed as follow:

    * In v3.7.0, the local user receives the `onRemoteAudioStateChanged` or `onRemoteVideoStateChanged` callback, which reports the status changes of the remote host's audio or video streams.
    * In v4.0.0, instead of the `onRemoteAudioStateChanged` or `onRemoteVideoStateChanged` callback, the local user receives the `onUserMuteAudio` or `onUserMuteVideo` callback, which reports the changes in the remote host's publishing status.

    #### Media options [#media-options]

    There are differences in the behavior of the SDK when setting channel media options while joining a channel between v3.7.x and 4.x:

    * In v3.7.x, if you set `publishLocalAudio` in `ChannelMediaOptions` to `false`, it will stop publishing the local audio stream within the channel.
    * In 4.x, if you set `publishMicrophoneTrack` in `ChannelMediaOptions` to `false`, it will not only stop publishing the local audio stream within the channel but also stop local microphone capture.

    ### Function gaps [#function-gaps]

    This section introduces functions that were supported in v3.7.x but are no longer supported or behave inconsistently in 4.x. Plans exist to support them or make them consistent in a future release, however.

    #### Audio application use-cases. [#audio-application-use-cases]

    4.x reconstructs the audio application scenarios, which can replace most of the audio application scenarios of v3.7.x. The following table shows the correspondence of audio application scenarios in the two releases:

    | v3.7.x                                  | v4.x                            |
    | --------------------------------------- | ------------------------------- |
    | `AUDIO_SCENARIO_DEFAULT`                | `AUDIO_SCENARIO_DEFAULT`        |
    | `AUDIO_SCENARIO_CHATROOM_ENTERTAINMENT` | `AUDIO_SCENARIO_CHATROOM`       |
    | `AUDIO_SCENARIO_EDUCATION`              | `AUDIO_SCENARIO_DEFAULT`        |
    | `AUDIO_SCENARIO_GAME_STREAMING`         | `AUDIO_SCENARIO_GAME_STREAMING` |
    | `AUDIO_SCENARIO_SHOWROOM`               | `AUDIO_SCENARIO_DEFAULT`        |
    | `AUDIO_SCENARIO_CHATROOM_GAMING`        | `AUDIO_SCENARIO_CHATROOM`       |
    | `AUDIO_SCENARIO_IOT`                    | `AUDIO_SCENARIO_DEFAULT`        |
    | `AUDIO_SCENARIO_MEETING`                | `AUDIO_SCENARIO_MEETING`        |

    The following table shows the differences in the behavior of APIs related to the audio route between v3.7.x and 4.x:

    | API                                  | v3.x                                                                                                                                                                                                                                                                                                                                                                                            | v4.x                                                                                                                                                                                                                                                                                                                                                                        |
    | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `setDefaultAudioRouteToSpeakerphone` | * You can only set the audio route before joining a channel.
    * This method only controls the initial state of the audio route and does not change the default audio route of the system. For example, regardless of whether you set the parameter of `setDefaultAudioRouteToSpeakerphone` to `true` or `false`, calling `setEnableSpeakerphone(false)` changes the audio route to the earpiece. | - You can set the audio route either before or after joining a channel.
    - This method is a steady API and can change the default audio route of the system. For example, after calling `setDefaultAudioRouteToSpeakerphone(true)` to set the initial audio route to the speakerphone, calling `setEnableSpeakerphone(false)` cannot change the audio route to the earpiece. |
    | `setEnableSpeakerphone`              | After connecting external playback devices such as Bluetooth and wired headphones, calling `setEnableSpeakerphone` cannot switch the audio route to the speakerphone or earpiece.                                                                                                                                                                                                               | Not recommended.                                                                                                                                                                                                                                                                                                                                                            |

    Also, when an external playback device is removed, for example, by disconnecting the Bluetooth headset, the audio route change is different between v3.5.0 and 4.x:

    * In v3.7.x, the audio route changes as follows (in terms of priority): The external device connected next to last (if any) > … > The external device connected first > `setEnableSpeakerphone` > `setDefaultAudioRoutetoSpeakerphone` > The default audio route.

    * In 4.x, the audio route changes as follows (in terms of priority): The external device connected next to last (if any) > … > The external device connected first > `setDefaultAudioRoutetoSpeakerphone` > The default audio route.

    #### Default video bitrate [#default-video-bitrate]

    In v3.7.x, if you set the video bitrate in VideoEncoderConfiguration as `STANDARD_BITRATE`, the default video bitrate in the `CHANNEL_PROFILE_LIVE_BROADCASTING` profile is twice that of the `CHANNEL_PROFILE_COMMUNICATION` profile.

    In 4.x, the video bitrate in the `CHANNEL_PROFILE_COMMUNICATION` profile is the same as that in the `CHANNEL_PROFILE_LIVE_BROADCASTING` profile, which means the video bitrate in the `CHANNEL_PROFILE_COMMUNICATION` profile is doubled.

    #### Virtual background [#virtual-background]

    See [Virtual Background](/en/realtime-media/video/build/apply-video-effects/virtual-background) to update the code in your app.

    #### Image enhancement [#image-enhancement]

    4.x modifies the calling logic of `setBeautyEffectOptions`. Before calling `setBeautyEffectOptions`, you need to do the following:

    1. Call `addExtension(agora_video_process)` during `RtcEngine` initialization to specify the extension’s library path.

    2. Call `enableExtension (agora, beauty, true)` to enable the extension.

    3. Call `enableVideo` to enable the video module.

    See the [VideoProcessExtensionVideoProcessExtension](https://github.com/AgoraIO/API-Examples/tree/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/VideoProcessExtension.java) sample project to update the code in your app.

    #### Unsupported functions [#unsupported-functions]

    Compared to v3.7.x, some features are not supported or only partially supported in 4.x. This section shows the APIs currently unsupported but for which support is planned for a future release.

    Remote video stream fallback:

    * `setRemoteUserPriority`

    Screen sharing:

    * `onScreenCaptureInfoUpdated`

    ### Removed APIs [#removed-apis]

    The 4.x removes deprecated or unrecommended APIs. Alternatives to the removed API or reasons for their removal are shown as follows:

    * `onVirtualBackgroundSourceEnabled`: Use the return value of `enableVirtualBackground` instead.

    * `onUserSuperResolutionEnabled`: Use the `RemoteVideoStats` member of the `superResolutionType` class instead.

    * `setAudioMixingPlaybackSpeed`: Use `setPlaybackSpeed` instead.

    * `setExternalAudioSourceVolume`: Use `adjustCustomAudioPublishVolume` instead.

    * `setAudioMixingDualMonoMode`: Use `setAudioDualMonoMode` instead.

    * `getEffectCurrentPosition`: Use `getPosition` instead.

    * `setEffectPosition`: Use `seek` instead.

    * `getEffectDuration`：Use `getDuration` instead.

    * `setAgoraLibPath`: Use the `mNativeLibPath` member in `RtcEngineConfig` instead when calling `create` \[2/2].

    * `getAudioFileInfo` and `onRequestAudioFileInfo`：Use `getDuration` instead.

    * `onAudioDeviceTestVolumeIndication`：Use `onAudioVolumeIndication` instead.

    * `onFirstLocalAudioFrame`：Use `onFirstLocalAudioFramePublished` instead.

    * `getRecordAudioParams`：Use `setRecordingAudioFrameParameters` instead.

    * `getMixedAudioParams`：Use `setMixedAudioFrameParameters` instead.

    * `getPlaybackAudioParams`：Use `setPlaybackAudioFrameParameters` instead.

    * The `pushMode` parameter in `setExternalVideoSource`: The default value of this parameter is `true`, and this parameter only takes effect when it is set to `true`. After deletion, it does not affect the function.

    * The `channel` parameter in `takeSnapshot` and `onSnapshotTaken` has been removed: This change was made as the `channel` parameter was found to be redundant and was not essential for the functionality of these APIs.

    * `setLocalPublishFallbackOption` and `onLocalPublishFallbackToAudioOnly`: Rarely used in v3.7.x.

    * `RENDER_MODE_FILL(4)` in `RENDER_MODE_TYPE`: This mode might cause image overstretch and is not recommended.

    * The following enumerations of audio mixing: Rarely used in v3.7.x.

    * `AUDIO_MIXING_REASON_STARTED_BY_USER`

    * `AUDIO_MIXING_REASON_ONE_LOOP_COMPLETED`

    * `AUDIO_MIXING_REASON_START_NEW_LOOP`

    * `AUDIO_MIXING_REASON_ALL_LOOPS_COMPLETED`

    * `AUDIO_MIXING_REASON_STOPPED_BY_USER`

    * `AUDIO_MIXING_REASON_PAUSED_BY_USER`

    * `AUDIO_MIXING_REASON_RESUMED_BY_USER`

    * `onAudioMixingFinished`: Use `onAudioMixingStateChanged` instead.

    * The `info` parameter in `joinChannel` \[2/2]: This parameter is optional and rarely used in v3.7.x.

    * `enableDeepLearningDenoise`: The SDK will add deep-learning noise reduction as one of its capability in a future release instead of implementing through an API.

    * `setDefaultMuteAllRemoteVideoStreams`: Use `autoSubscribeVideo` in `ChannelMediaOptions`.

    * `setDefaultMuteAllRemoteAudioStreams`: Use `autoSubscribeAudio` in `ChannelMediaOptions`.

    * The `replace` parameter in `startAudioMixing`: Use `publishMicrophoneTrack` in the `ChannelMediaOptions` instead.

    ### Naming and data type changes [#naming-and-data-type-changes]

    The naming and data type changes in 4.x cause error messages in the IDE when you compile your project, and you need to update the code of your app according to each error message.

    #### Naming changes [#naming-changes]

    The main API and parameter name changes are as follows:

    * `adjustLoopbackRecordingSignalVolume` is changed to `adjustLoopbackRecordingVolume`.

    * The `fileSize` member in `LogConfig` is renamed to `fileSizeInKB`.

    * The `options` parameter in `joinChannel`\[2/2] is changed to `mediaOptions`.

    * The `report_vad` parameter in enableAudioVolumeIndication is changed to `reportVad`.

    * `registerVideoEncodedFrameObserver` is changed to `registerVideoEncodedImageReceiver`.

    #### Data type changes [#data-type-changes]

    The main API data type changes are as follows:

    * The `state` and `reason` parameters in `onRemoteAudioStateChanged` are changed from integer to enumeration.

    * The `oldState` and `newState` parameters in `onAudioPublishStateChanged`, `onVideoPublishStateChanged`, `onAudioSubscribeStateChanged`, and `onVideoSubscribeStateChanged` are changed from integer to enumeration.

    * The `state` and `error` parameters in `onLocalAudioStateChanged` are changed from integer to enumeration.

    * The `state` and `error` parameters in `onRtmpStreamingStateChanged` are changed from integer to enumeration

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="ios">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="ios" />

    * [Migration steps](#migration-steps) to upgrade your app to Broadcast Streaming v4.x.

    * [What's changed](#what-has-changed) between Broadcast Streaming v2.x and v4.x.

    ## Migration steps [#migration-steps-1]

    This section introduces the main steps to upgrade the SDK from v2.x or 3.7.x to v4.x.

    1. Integrate the SDK

    See [Get started](../../../index) for more information about integrating the v4.x SDK into your project.

    2. Update the Agora code in your app

    The v4.x SDK has optimized or modified the implementation of some functions, resulting in incompatibility with the v3.7.x SDK. In order to retain Agora functionality in your app, update the code in your app according to the **What has changed** section below.

    ## What has changed [#what-has-changed-1]

    This section introduces the main changes of v4.x compared to v3.7.x in the following categories. You need to update the code of your app according to your business use-case.

    <CalloutContainer type="info">
      <CalloutDescription>
        If the version before upgrading is a version before v3.7.0, please check the [v3.x release notes](/en/realtime-media/video/reference/release-notes) to obtain the changes between this version and v3.7.0.
      </CalloutDescription>
    </CalloutContainer>

    * [Breaking changes](#breaking-changes): Introduces API compatibility changes that have a big impact. You need to spend significant time modifying the related implementation.

    * [Behavior changes](#behavior-changes): Introduces changes caused by reasonable optimization of the SDK default behavior and API behavior. Less time is required to modify the related implementation, if any.

    * [Function gaps](#function-gaps): Introduces functions that were supported in v3.7.x but are not supported in 4.x. However, these functions are intended to be added in a future release.

    * [Removed APIs](#removed-apis): Introduces APIs that were supported in v3.7.x but removed in 4.x. Most of these APIs have alternatives in 4.x. Modifying the related implementation should require less time.

    * [Naming and data type changes](#naming-changes): Introduces the naming changes of the main APIs. You can update the relevant implementation according to the error message in the IDE, which is expected to take less time.

    ### Breaking changes [#breaking-changes-1]

    After upgrading from v3.7.x to v4.x, the way the APIs implement some functions is different. This section introduces compatibility changes for these APIs and the logic for updating the code of your app.

    #### Multiple channels [#multiple-channels-1]

    In v3.7.x, the SDK provides the `AgoraRtcChannel` and `AgoraRtcChannelDelegate` classes to implement multi-channel control. The v3.7.x SDK supports subscribing to the audio and video streams of multiple channels, but only supports publishing one group of audio and video streams in one channel.

    v4.x introduces the following changes:

    * The SDK supports capturing or publishing multiple groups of audio and video streams at the same time. For example, simultaneously publishing video streams captured by multiple cameras or multiple screens.

    * The SDK retains the following behavior of `AgoraRtcEngineKit`: you can call `joinChannelExByToken` (replacing `joinChannelByToken` of the `AgoraRtcChannel` class in v3.7.x) multiple times, and publish the specified stream to different channels through different user IDs (`localUid`) and `AgoraRtcChannelMediaOptions` settings.

    * Added a binary group `AgoraRtcConnection` to represent the connection established by `joinChannelExByToken`. A connection is determined by the channel name (`channelId`) and `localUid`. You can control the publishing and subscribing state of different connections through `AgoraRtcConnection`. The SDK adds Ex in the name of all APIs with a `connection` parameter (corresponding to the `AgoraRtcConnection` class) to distinguish them, and gathers these APIs in the `AgoraRtcEngineKit(Ex)` class to implement more multi-stream functions.

    By setting `AgoraRtcChannelMediaOptions`, v4.x supports using one `AgoraRtcEngineKit` instance to capture audio and video streams from multiple sources at the same time and publish them to the remote user, adapting to various business use-cases. For example:

    * Simultaneously publish a media player stream, a screen-sharing stream, and a video stream captured by the camera.

    * Simultaneously publish one audio stream captured by the microphone and one by the custom audio source, and one media player steam.

    Combined with the multi-channel capability, you can also experience the following functions:

    * Publish multiple groups of audio and video streams to the remote user through different `localUid`s.

    * Mix multiple audio streams and publish them to the remote user through one `localUid`.

    * Mix multiple video streams and publish them to the remote user through one `localUid`.

    `AgoraRtcChannel` and `AgoraRtcEngineKit` of v3.7.x are partially duplicated and overlap in their functionality, so v4.x hides the `AgoraRtcChannel` and `AgoraRtcChannelDelegate` classes. See the [JoinMultiChannel](https://github.com/AgoraIO/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/JoinMultiChannel) sample project for more details on how to replace `AgoraRtcChannel` with `joinChannelExByToken` and `AgoraRtcChannelMediaOptions`. The expected migration cost is one day or less.

    If you need to continue to use the `AgoraRtcChannel` and `AgoraRtcChannelDelegate` classes, contact [support@agora.io](mailto\:support@agora.io). The decision whether to maintain compatibility in a future release is based on your feedback.

    #### Media stream publishing control [#media-stream-publishing-control-1]

    In v3.7.x, the SDK uses the `publishLocalAudio` and `publishLocalVideo` members in `AgoraRtcChannelMediaOptions` to control the audio and video publishing state in the channel.

    In v4.x, the SDK gathers more channel-related settings into `AgoraRtcChannelMediaOptions`, including publishing of audio and video streams from different sources, automatic subscribing of audio and video streams, user role switching, token updating, and default dual stream options. You can determine the media stream publishing and subscribing behavior by calling `joinChannelByToken` or `joinChannelExByToken` when joining a channel, or you can flexibly update the media options by calling `updateChannelWithMediaOptions` after joining achannel, such as switching video sources.

    See the [JoinChannelVideo](https://github.com/AgoraIO/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo) sample project to update the code in your app.

    #### Custom video source and renderer [#custom-video-source-and-renderer-1]

    In v3.7.x, the SDK provides the following ways to implement the custom video source and renderer:

    * Push mode for custom video source

    * Raw video data mode for custom video renderer

    * MediaIO mode (`AgoraVideoSourceProtocol`) for custom video source

    * MediaIO mode (`AgoraVideoSinkProtocol`) for custom video renderer

    v4.x unifies the audio and video processing pipeline internally. Push mode and raw video data mode are simpler for integration, so Agora recommends using them for custom video source and renderer and removes the following related APIs of the MediaIO mode:

    * `AgoraVideoSourceProtocal`

    * `AgoraVideoSinkProtocal`

    * `AgoraVideoFrameConsumer`

    * `setVideoSource`

    * `setLocalVideoRenderer`

    * `setRemoteVideoRenderer`

    * `videoSource`

    * `localVideoRenderer`

    * `remoteVideoRendererOfUserId`

    If you use the MediaIO mode in v3.7.x to implement custom video source, custom video renderer, switching video source, and other functions, Agora recommends updating the code of your app by referring to the following sample projects:

    * Custom video source: [CustomVideoSourcePush](https://github.com/AgoraIO/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomVideoSourcePush)

    * Custom video renderer: [CustomVideoRender](https://github.com/AgoraIO/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomVideoRender)

    * Switching video source: [ScreenShare](https://github.com/AgoraIO/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/ScreenShare)

    #### Error codes and warning codes [#error-codes-and-warning-codes-1]

    In v3.7.x, the SDK returns error codes and warning codes through the `didOccurError` and `didOccurWarning` callbacks.

    To facilitate locating and troubleshooting issues, v4.x reports problems and causes through the return values of APIs or different callbacks for listening to states. For example:

    * `connectionChangedToState`: Reports the network connection state.

    * `localAudioStateChanged`: Reports the local audio state.

    * `localVideoStateChangedOfState`: Reports the local video state.

    * `remoteAudioStateChangedOfUid`: Reports the remote audio state.

    * `remoteVideoStateChangedOfUid`: Reports the remote video state.

    As a consequence, v4.x removes the `didOccurError` and `didOccurWarning` callbacks.

    <CalloutContainer type="info">
      <CalloutDescription>
        In addition to the previously mentioned breaking changes relative to v3.7.0, v4.0.0 Beta introduces a few additional breaking changes for the final release of v4.0.0. Notable changes include:

        * Replacing `publishAudioTrack` with `publishMicrophoneTrack` in `AgoraRtcChannelMediaOptions`.
        * Replacing `publishScreenTrack` with `publishScreenCaptureVideo` in `AgoraRtcChannelMediaOptions` .
          If you used this feature in v4.0.0 and wish to upgrade to v4.0.0, modify the implementation code of the feature after upgrading the SDK.
      </CalloutDescription>
    </CalloutContainer>

    ### Behavior changes [#behavior-changes-1]

    This section introduces changes caused by reasonable optimization of the SDK default behavior and API behavior.

    #### Channel profile [#channel-profile-1]

    In v3.7.x, the default channel profile is `AgoraChannelProfileCommunication` (the communication profile).

    Because the interactive streaming profile supports seamless switching from one-to-one calls to multi-user interaction, since v3.0.0, Agora has changed the internal transmission protocol and the ability to resist poor network conditions in the communication profile to be consistent with the interactive streaming profile. In v4.x, Agora also changed the default channel profile to `AgoraChannelProfileLiveBroadcasting` (the interactive streaming profile).

    #### Default log file [#default-log-file-1]

    In v3.7.x, when the SDK creates multiple log files, the earlier files are named in a `agorasdk_x.log` format, such as `agorasdk_1.log`. v4.x modified the naming format to `agorasdk.x.log`, such as `agorasdk.1.log`. Additionally, v4.x adds the `agoraapi.log` file to record API logs.

    #### Fast channel switching [#fast-channel-switching-1]

    In v3.7.x, you need to call `switchChannelByToken` to quickly switch a channel.

    In v4.x, you can achieve the same switching speed as `switchChannelByToken` in v3.7.x by switching a channel through `leaveChannel` and `joinChannelByToken`. Therefore, v4.x removes `switchChannelByToken`. If you call `switchChannelByToken` to quickly switch a channel in v3.7.x, see the [QuickSwitchChannel](https://github.com/AgoraIO/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/QuickSwitchChannel) sample project to update the code in your app.

    #### Agora self-developed extensions [#agora-self-developed-extensions-1]

    v4.0.0 adds the feature of automatically loading self-developed dynamic libraries based on v4.0.0. As of this release, when using an Agora self-developed extension, you do not need to manually integrate the dynamic library in the project. The SDK automatically loads the dynamic library during the initialization phase of `AgoraRtcEngineKit`. You can directly call the corresponding method of the extension to enable this feature.

    | API                                                                                                             | Extension type               |
    | :-------------------------------------------------------------------------------------------------------------- | :--------------------------- |
    | `enableVirtualBackground`                                                                                       | Virtual background extension |
    | * `setBeautyEffectOptions`
    * `setVideoDenoiserOptions`
    * `setLowlightEnhanceOptions`
    * `setColorEnhanceOptions` | Video enhancement extension  |
    | `enableRemoteSuperResolution`                                                                                   | Super resolution extension   |
    | - `setAudioEffectPreset`
    - `setVoiceBeautifierPreset`
    - `setVoiceConversionPreset`                              | Voice beautifier extension   |
    | `enableSpatialAudio`                                                                                            | Spatial audio extension      |
    | `enableContentInspect`                                                                                          | Content moderation extension |

    #### Virtual metronome [#virtual-metronome-1]

    When you call `startRhythmPlayer`, the SDK publishes the sound of the virtual metronome to the remote by default. If you do not want the remote users to hear the virtual metronome, refer to the following operations:

    In v3.7.0, call the `configRhythmPlayer,` and set `publish` to `false`.
    In v4.0.0, set `publishRhythmPlayerTrack` in `AgoraRtcChannelMediaOptions` to `false`.

    #### Volume indication [#volume-indication-1]

    You can call the `enableAudioVolumeIndication` method to enable the user's volume indication function. There is a difference in the definition of the `interval` parameter in the `enableAudioVolumeIndication` method between v3.7.0 and v4.0.0, as follows:

    In v3.7.0, Agora recommends that you set the `interval` to be greater than 200 ms. The minimum is 10 ms; otherwise, the `reportAudioVolumeIndicationOfSpeakers` callback is not received.
    In v4.0.0, you must set the `interval `to an integer that is a multiple of 200 ms. If the value of `interval` is lower than 200, the SDK automatically adjusts it to 200.

    When the user's volume indication is enabled, the SDK triggers the `reportAudioVolumeIndicationOfSpeakers` callback at the time interval set in this method. If the local user calls `muteLocalAudioStream` to mute themselves, the SDK behaves inconsistently between v3.7.0 and v4.0.0:

    In v3.7.0, the SDK immediately stops reporting the local user's volume indication callback.

    In v4.0.0, the SDK continues to report the local user's volume indication callback.

    #### Device permissions [#device-permissions-1]

    In v3.7.0, `AgoraAudioLocalErrorDeviceNoPermission` in `localAudioStateChange` reports that there is no permission to start the capture device, and `AgoraLocalVideoStreamErrorDeviceNoPermission` in `localVideoStateChange` reports that there is no permission to start the video capture device.

    In v4.0.0, the permission statuses of the audio and video capture devices are both reported in the `permissionError` callback.

    #### Pre-call network test [#pre-call-network-test-1]

    If you need to start or stop the network connection quality test, note the following:

    In v3.7.0, you can call `enableLastmileTest` to start the network quality test. If you want to stop the network test, you need to call `disableLastmileTest`.

    In v4.0.0, you can call `startLastmileProbeTest` to enable network quality testing. If you want to stop network testing, you need to call `stopLastmileProbeTest`.

    #### Remote media event triggering mechanism [#remote-media-event-triggering-mechanism-1]

    In the following use-cases, the mechanism of triggering remote media events is changed:

    * Use-case 1: When the host calls `muteLocalAudioStream` or `muteLocalVideoStream` outside the channel to change the publishing status of the local audio or video stream and then joins the channel.
    * Use-case 2: When the host calls `muteLocalAudioStream` or `muteLocalVideoStream` within the channel to change the publishing status of the local audio or video stream, and then other users join the channel.

    The behavior differences of Agora SDK between v3.7.0 and v4.0.0 are listed as follow:

    * In v3.7.0, the local user receives the `remoteAudioStateChangedOfUid` or `remoteVideoStateChangedOfUid` callback, which reports the status changes of the remote host's audio or video streams.
    * In v4.0.0, instead of the `remoteAudioStateChangedOfUid` or `remoteVideoStateChangedOfUid` callback, the local user receives the `didAudioMuted` or `didVideoMuted` callback, which reports the changes in the remote host's publishing status.

    #### Media options [#media-options-1]

    There are differences in the behavior of the SDK when setting channel media options while joining a channel between v3.7.0 and v4.0.0:

    * In v3.7.0, if you set `publishLocalAudio` in `AgoraRtcChannelMediaOptions` to `NO`, it will stop publishing the local audio stream within the channel.
    * In v4.0.0, if you set `publishMicrophoneTrack` in `AgoraRtcChannelMediaOptions` to `NO`, it will not only stop publishing the local audio stream within the channel but also stop local microphone capture.

    #### Video information change event [#video-information-change-event]

    If the video capture device is put into the landscape or portrait mode during video capture, in v3.7.0 and v4.0.0, the following differences exist in the video information change events reported by the SDK:

    * In v3.7.0, the `rotation` parameter in the `videoSizeChangedOfUid` callback displays the current device rotation information.
    * In v4.0.0, the `rotation` parameter in the `videoSizeChangedOfSourceType` callback is always `0`.

    ### Function gaps [#function-gaps-1]

    This section introduces functions that were supported in v3.7.x but are no longer supported or behave inconsistently in v4.x. Plans exist to support them or make them consistent in a future release, however.

    #### Audio application scenarios [#audio-application-scenarios]

    v4.x reconstructs the audio application scenarios, which can replace most of the audio application scenarios of v3.7.x. The following table shows the correspondence of audio application scenarios in the two releases:

    | v3.7.x                                    | v4.x                                                                    |
    | ----------------------------------------- | ----------------------------------------------------------------------- |
    | `AgoraAudioScenarioDefault`               | `AgoraAudioScenarioDefault`                                             |
    | `AgoraAudioScenarioChatRoomEntertainment` | `AgoraAudioScenarioChatRoom`                                            |
    | `AgoraAudioScenarioEducation`             | `AgoraAudioScenarioDefault`                                             |
    | `AgoraAudioScenarioGameStreaming`         | `AgoraAudioScenarioGameStreaming` or `AgoraAudioScenarioHighDefinition` |
    | `AgoraAudioScenarioShowRoom`              | `AgoraAudioScenarioDefault`                                             |
    | `AgoraAudioScenarioChatRoomGaming`        | `AgoraAudioScenarioChatRoom`                                            |
    | `AgoraAudioScenarioIot`                   | `AgoraAudioScenarioDefault`                                             |
    | `AgoraAudioScenarioMeeting`               | `AgoraAudioScenarioMeeting`                                             |

    #### Audio route [#audio-route]

    The following table shows the differences in the behavior of APIs related to the audio route between v3.7.x and v4.x:

    | API                                  | v3.x                                                                                                                                                                                                                                                                                                                                                                                     | v4.x                                                                                                                                                                                                                                                                                                                                                                    |
    | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `setDefaultAudioRouteToSpeakerphone` | * You can only set the audio route before joining a channel.
    * This method only controls the initial state of the audio route and does not change the default audio route of the system. For example, regardless of whether you set the parameter of `setDefaultAudioRouteToSpeakerphone` to `YES` or `NO`, calling `setEnableSpeakerphone(NO)` changes the audio route to the earpiece. | - You can set the audio route either before or after joining a channel.
    - This method is a steady API and can change the default audio route of the system. For example, after calling `setDefaultAudioRouteToSpeakerphone(YES)` to set the initial audio route to the speakerphone, calling `setEnableSpeakerphone(NO)` cannot change the audio route to the earpiece. |
    | `setEnableSpeakerphone`              | After connecting external playback devices such as Bluetooth and wired headphones, calling `setEnableSpeakerphone` cannot switch the audio route to the speakerphone or earpiece.                                                                                                                                                                                                        | Not recommended.                                                                                                                                                                                                                                                                                                                                                        |

    Also, when an external playback device is removed, for example, by disconnecting the Bluetooth headset, the audio route change is different between v3.5.0 and v4.x:

    * In v3.7.x, the audio route changes as follows (in terms of priority): The external device connected next to last (if any) > … > The external device connected first > `setEnableSpeakerphone` > `setDefaultAudioRoutetoSpeakerphone` > The default audio route.

    * In v4.x, the audio route changes as follows (in terms of priority): The external device connected next to last (if any) > … > The external device connected first > `setDefaultAudioRoutetoSpeakerphone` > The default audio route.

    #### Default video bitrate [#default-video-bitrate-1]

    In v3.7.x, if you set the video bitrate in `AgoraVideoEncoderConfiguration` as `AgoraVideoBitrateStandard`, the default video bitrate in the `AgoraChannelProfileLiveBroadcasting` profile is twice that of the `AgoraChannelProfileCommunication` profile.

    In v4.x, the video bitrate in the `AgoraChannelProfileCommunication` profile is the same as that in the `AgoraChannelProfileLiveBroadcasting` profile, which means the video bitrate in the `AgoraChannelProfileCommunication` profile is doubled.

    #### Virtual background [#virtual-background-1]

    See [Virtual Background](/en/realtime-media/video/build/apply-video-effects/virtual-background) to update the code in your app.

    #### Image enhancement [#image-enhancement-1]

    v4.x modifies the calling logic of `setBeautyEffectOptions`. Before calling `setBeautyEffectOptions`, you need to do the following:

    1. Integrate the `AgoraVideoProcessExtension.xcframework` dynamic library in the project.

    2. Call `enableExtension ("agora", "beauty", "YES")` before joining a channel to enable the image enhancement extension.

    3. Call `enableVideo` to enable the video module.

    See the [VideoProcess](https://github.com/AgoraIO/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess) sample project to update the code in your app.

    #### Unsupported functions [#unsupported-functions-1]

    Compared to v3.7.x, some features are not supported or only partially supported in v4.x. This section shows the APIs currently unsupported but for which support is planned for a future release.

    Remote video stream fallback:

    * `setRemoteUserPriority`

    * `setRemoteSubscribeFallbackOption`

    * `didRemoteSubscribeFallbackToAudioOnly`

    Raw audio data:

    * `getObservedAudioFramePosition`

    * `getRecordAudioParams`

    * `getMixedAudioParams`

    * `getPlaybackAudioParams`

    Raw video data:

    * `getVideoFormatPreference`

    Audio and video statistics:

    * `qualityChangedReason` member in `RemoteAudioStats`

    * `captureBrightnessLevel` members in `LocalVideoStats`

    Network type:

    * `AgoraNetworkTypeMobile5G` in `AgoraNetworkType`

    Audio and video errors:

    * `AgoraAudioLocalErrorInterrupted(8)`

    * `AgoraLocalVideoStreamErrorCaptureNoDeviceFound(8)`

    Selecting the playback track of the audio file:

    * `selectAudioTrack`

    Pre-call network test: Before supporting the following APIs, you can use `startLastmileProbeTest` and `stopLastmileProbeTest` instead.

    * `enableLastmileTest`

    * `disableLastmileTest`

    Call loop test:

    * `startEchoTestWithInterval` (with the `config` parameter)

    Audio recording on the client:

    * `recordingChannel` in `AgoraAudioRecordingConfiguration`

    * `AgoraMediaRecorder`

    * `sharedMediaRecorderWithRtcEngine`

    * `startRecording`

    * `stopRecording`

    * `destroy`

    * `stateDidChanged`

    * `informationDidUpdated`

    Wi-Fi acceleration:

    * `enableWirelessAccelerate`

    * `wlAccMessage`

    * `wlAccStats`

    Video content inspection:

    * `enableContentInspect`

    * `contentInspectResult`

    Cloud proxy connection state:

    * `didProxyConnected`

    External audio data:

    * `pushExternalAudioFrameRawData` (with the `sourcePos` parameter)

    * `pushExternalAudioFrameSampleBuffer` (with the `sourcePos` parameter)

    ### Removed APIs [#removed-apis-1]

    The v4.x removes deprecated or unrecommended APIs. Alternatives to the removed API or reasons for their removal are shown as follows:

    * `setVideoDenoiserOptions`, `setLowlightEnhanceOptions`, and `setColorEnhanceOptions`: Use `setExtensionPropertyWithVendor` instead.

    * `virtualBackgroundSourceEnabled`: Use the return value of `enableVirtualBackground` instead.

    * `superResolutionEnabledOfUid`: Use the `superResolutionType` member of the `AgoraRtcRemoteVideoStats` class instead.

    * `setAudioMixingPlaybackSpeed`: Use `setPlaybackSpeed` instead.

    * `setExternalAudioSourceVolume`: Use `adjustCustomAudioPublishVolume` instead.

    * `setAudioMixingDualMonoMode`: Use `setAudioDualMonoMode` instead.

    * `getEffectCurrentPosition`: Use `getPosition` instead.

    * `setEffectPosition`: Use `seekToPosition` instead.

    * `getEffectDuration`: Use `getDuration` instead.

    * `getAudioFileInfo` and `didRequestAudioFileInfo`: Use `getDuration` instead.

    * `reportAudioDeviceTestVolume`: Use `reportAudioVolumeIndicationOfSpeakers` instead.

    * `firstLocalAudioFrame`: Use `firstLocalAudioFramePublished` instead.

    * `getRecordAudioParams`: Use `setRecordingAudioFrameParametersWithSampleRate` instead.

    * `getMixedAudioParams`: Use `setMixedAudioFrameParametersWithSampleRate` instead.

    * `getPlaybackAudioParams`: Use `setPlaybackAudioFrameParametersWithSampleRate` instead.

    * The `pushMode` parameter in `setExternalVideoSource`: The default value of this parameter is `YES`, and this parameter only takes effect when it is set to `YES`. After deletion, it does not affect the function.

    * `setLocalPublishFallbackOption` and `didLocalPublishFallbackToAudioOnly`: Rarely used in v3.7.x.

    * `AgoraVideoRenderModeFill(4)` in `AgoraVideoRenderMode`: This mode might cause image overstretch and is not recommended.

    * The following enumerations in `AgoraAudioMixingReasonCode`: Rarely used in v3.7.x.

    * `AgoraAudioMixingReasonStartedByUser`

    * `AgoraAudioMixingReasonOneLoopCompleted`

    * `AgoraAudioMixingReasonStartNewLoop`

    * `AgoraAudioMixingReasonAllLoopsCompleted`

    * `AgoraAudioMixingReasonStoppedByUser`

    * `AgoraAudioMixingReasonPausedByUser`

    * `AgoraAudioMixingReasonResumedByUser`

    * `rtcEngineLocalAudioMixingDidFinish`: Use `audioMixingStateChanged` instead.

    * The `info` parameter in `joinChannelByToken` \[2/2]: This parameter is optional and rarely used in v3.7.x.

    * `enableDeepLearningDenoise`: The SDK will add deep-learning noise reduction as one of its capability in a future release instead of implementing through an API.

    * The `channel` parameter in `takeSnapshot` and `snapshotTaken` has been removed: This change was made as the `channel` parameter was found to be redundant and was not essential for the functionality of these APIs.

    * `setDefaultMuteAllRemoteVideoStreams`: Use `autoSubscribeVideo` in `AgoraRtcChannelMediaOptions`.

    * `setDefaultMuteAllRemoteAudioStreams`: Use `autoSubscribeAudio` in `AgoraRtcChannelMediaOptions`.

    * The `replace` parameter in `startAudioMixing`: Use `publishMicrophoneTrack` in the `AgoraRtcChannelMediaOptions` instead.

    ### Naming changes [#naming-changes-1]

    The naming changes in v4.x cause error messages in the IDE when you compile your project, and you need to update the code of your app according to each error message.

    The main API and parameter name changes are as follows:

    * `localVideoStateChange` is changed to `localVideoStateChangedOfState`.

    * `localVideoStats` is changed to `localVideoStatssourceType`.

    * `sourceType` is added in `didVideoPublishStateChange`.

    * `firstLocalVideoFramePublished` is changed to `firstLocalVideoFramePublishedWithElapsed`.

    * `videoSizeChangedOfUid` is changed to `videoSizeChangedOfSourceType`.

    * `adjustLoopbackRecordingSignalVolume` is changed to `adjustLoopbackSignalVolume`.

    * `sourceType` is added in `firstLocalVideoFrameWithSize`.

    * `firstLocalAudioFrame` is changed to `firstLocalAudioFramePublished`.

    * The `fileSize` member in `AgoraLogConfig` is renamed to `fileSizeInKB`.

    * The `options` parameter in `joinChannelByToken`\[2/2] is changed to `mediaOptions`.

    * `localVideoStateChange` is changed to `localVideoStateChangedOfState`, and `AgoraLocalVideoStreamState` is changed to `AgoraVideoLocalState`.

    * The `report_vad` parameter in `enableAudioVolumeIndication` is changed to `reportVad`.

    * The `errorCode` parameter in `rtmpStreamingChangedToState` is changed to `errCode`.

    * `localAudioMixingStateDidChanged` is changed to `audioMixingStateChanged`.

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="web">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="web" />

    Web SDK v4.x represents a complete overhaul of Web SDK v3.x, featuring optimized internal architecture and enhanced API usability. Key advantages include:

    * Promise-based APIs for asynchronous operations, improving code robustness and readability.
    * Full TypeScript support for enhanced development experience.
    * Introduction of Track objects to independently control audio and video, offering increased flexibility and separation of concerns.
    * Streamlined channel event notification mechanism, with unified event naming and callback parameter formats, reducing complexity in handling disconnections and reconnections.
    * Clear and comprehensive error code system to facilitate troubleshooting.

    This version provides a clearer and more concise overview of the improvements in Web SDK v4.x while maintaining focus on the key advantages for users.

    <CalloutContainer type="info">
      <CalloutDescription>
        * Agora has ceased support for Web SDK v3.x. To upgrade to version v4.x, refer to the provided documentation and migration guides.
          * Note that Web SDK v4.x introduces major changes in API and product behavior, and is not backward compatible with version 3.x.
          * In Web SDK v4.x, user role switching in live broadcast use-cases is decoupled from track release. Calling `publish` and `unpublish` will no longer automatically switch user roles. Refer to the [Migration steps](#migration-steps) for detailed instructions.
      </CalloutDescription>
    </CalloutContainer>

    This page tells you about:

    * [Migration steps](#migration-steps) to upgrade your app to Broadcast Streaming v4.x.

    * [What's changed](#whats-changed) between Broadcast Streaming v3.x and v4.x.

    * [Core API change list](#core-api-change-list) between Broadcast Streaming v3.x and v4.x.

    ## Migration steps [#migration-steps-2]

    This section takes building a video conferencing app as an example and introduces the differences between implementing the Broadcast Streaming v4.x and the Broadcast Streaming v3.x in detail.

    ### Join a channel [#join-a-channel]

    First, create a `Client` object and join a specified channel.

    * Using Video SDK v3.x

      ```js
      const client = AgoraRTC.createClient({ mode: "live", codec: "vp9" });
      client.init("APPID", () => {
       client.join("Token", "Channel", null, (uid) => {
        console.log("join success", uid);
       }, (e) => {
        console.log("join failed", e);
       });
      });
      ```

    * Using Video SDK v4.x
      ```js
        const client = AgoraRTC.createClient({ mode: "live", codec: "vp9" });

        try {
         const uid = await client.join("APPID", "Channel", "Token", uid);
         console.log("join success");
        } catch (e) {
         console.log("join failed", e);
        }
      ```

    Here we assume that our code runs within in an `async` function and use `await` in the following code snippets.

    Key points:

    * In the Broadcast Streaming v4.x, we use the `Promise` object together with `async/await` for the asynchronous operation `join`.

    * The Broadcast Streaming v4.x removes the `client.init` method and you pass `APPID` when calling `client.join`. If you want to join another channel that uses a different App ID, you do not need to create another client object.

    ### Create an audio track and a video track [#create-an-audio-track-and-a-video-track]

    Second, create an audio track object from the audio sampled by a microphone and create a local video track from the video captured by a camera. In the sample code, by default, we play the local video track and do not play the local audio track.

    * Using Video SDK v3.x

      ```js
      const localStream = AgoraRTC.createStream({ audio: true, video: true });
      localStream.init(() => {
       console.log("init stream success");
       localStream.play("DOM_ELEMENT_ID", { muted: true });
      }, (e) => {
       console.log("init local stream failed", e);
      });
      ```

    * Using Video SDK v4.x

      ```js
        const localAudio = await AgoraRTC.createMicrophoneAudioTrack();
        const localVideo = await AgoraRTC.createCameraVideoTrack();
        console.log("create local audio/video track success");

        localVideo.play("DOM_ELEMENT_ID");
      ```

    Key points:

    * The Broadcast Streaming v4.x removes the `Stream` object. Call `createMicrophoneAudioTrack` to create an audio track and call `createCameraVideoTrack` to create a video track.

    * The audio and video track objects in the Broadcast Streaming v4.x do not provide the `init` method because the SDK initializes the microphone and camera when creating the tracks and notifies you of the result with promises.

    * The Broadcast Streaming v4.x can control the playback of local audio and video tracks separately and removes the `muted` parameter in the `play` method. If you do not want to play the local audio track, do not call `play` in the local audio track object.

    ### Publish the local audio and video tracks [#publish-the-local-audio-and-video-tracks]

    After creating the local audio and video tracks, publish these tracks to the channel.

    * Using Video SDK v3.x

      ```js
      client.publish(localStream, err => {
       console.log("publish failed", err);
      });
      client.on("stream-published", () => {
       console.log("publish success");
      });
      ```

    * Using Video SDK v4.x
      ```js
      try {
       // Remove this line if the channel profile is not live broadcast.
       await client.setClientRole("host");
       await client.publish([localAudio, localVideo]);
       console.log("publish success");
      } catch (e) {
       console.log("publish failed", e);
      }
      ```

    Key points:

    * If your channel profile is [live broadcast](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#setclientrole), the Broadcast Streaming v3.x automatically sets the user role as `host` when publishing the stream. However, in the Broadcast Streaming v4.x, you need to call `setClientRole` to set the user role as `host`.

    * In the Broadcast Streaming v4.x, `publish` returns a `Promise` object representing the eventual completion or failure of the asynchronous operation.

    * In the Broadcast Streaming v4.x, when calling `publish`, you need to pass one or multiple `LocalTrack` objects instead of the `Stream` object. You can call `publish` repeatedly to publish multiple tracks and call `unpublish` repeatedly to unpublish multiple tracks.

    ### Subscribe to remote media tracks and play [#subscribe-to-remote-media-tracks-and-play]

    When a remote user in the channel publishes media tracks, we need to automatically subscribe to these tracks and play. To do this, you need to listen for the `user-published` event and call `subscribe` when the SDK triggers this event.

    * Using Video SDK v3.x

      ```js
      client.on("stream-added", e => {
       client.subscribe(e.stream, { audio: true, video: true }, err => {
        console.log("subscribe failed", err);
       });
      });

      client.on("stream-subscribed", e => {
       console.log("subscribe success");
       e.stream.play("DOM_ELEMENT_ID");
      });
      ```

    * Using Video SDK v4.x
      ```js
      client.on("user-published", async (remoteUser, mediaType) => {
       await client.subscribe(remoteUser, mediaType);
       if (mediaType === "video" || mediaType === "all") {
        console.log("subscribe video success");
        remoteUser.videoTrack.play("DOM_ELEMENT_ID");
       }
       if (mediaType === "audio" || mediaType === "all") {
        console.log("subscribe audio success");
        remoteUser.audioTrack.play();
       }
      });
      ```

    Key points:

    * The Broadcast Streaming v4.x replaces the `stream-added`, `stream-removed`, and `stream-updated` events with the `user-published` and `user-unpublished` events.

    Pay attention to the `mediaType` parameter of the `user-published` event, which marks the type of the current track the remote user publishes. It can be `"video"` or `"audio"`. If the remote user publishes an audio track and a video track at the same time, the SDK triggers two `user-published` events, in which `mediaType` is `"audio"` and `"video"` respectively.

    * In the Broadcast Streaming v4.x, `subscribe` returns a `Promise` object representing the eventual completion or failure of the asynchronous operation. When calling `subscribe`, pass a `remoteUser` object. For details, see [AgoraRTCRemoteUser](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcremoteuser.html).

    * When the subscription succeeds, the subscribed tracks are updated to `remoteUser` and you can go on to call `play`.

    ## What’s changed [#whats-changed]

    This section lists the major changes to Broadcast Streaming.

    ### Use promises for asynchronous operations [#use-promises-for-asynchronous-operations]

    For asynchronous methods such as joining and leaving a channel, publishing and subscribing, enumerating media input devices, and starting and stopping live transcoding, the Broadcast Streaming notifies users of the results of these asynchronous operations with callbacks or events, while the Broadcast Streaming v4.x uses promises.

    ### Fine control over audio and video tracks [#fine-control-over-audio-and-video-tracks]

    For the Broadcast Streaming v4.x, we replace the [Stream](https://api-ref.agora.io/en/video-sdk/web/3.x/interfaces/agorartc.stream.html) object with `Track` objects. You create, publish, or subscribe to one or multiple audio and video tracks. Tracks make up a stream. The advantage of dividing a stream up into tracks is that audio and video are controllable separately. And these new methods are easier to use than the `Stream.addTrack` and `Stream.removeTrack` methods in the Broadcast Streaming.

    For now, the Broadcast Streaming v4.x allows publishing multiple audio tracks but only one video track. The SDK automatically mixes multiple audio tracks into one when publishing.

    In addition to replacing the `Stream` object with `Track` objects, the Broadcast Streaming v4.x provides different interfaces for the local and remote tracks. Some methods and objects are only available locally, and some are only available remotely. This change affects multiple API methods, including creating objects, publishing, and subscribing to tracks. For details, see [Create an audio track and a video track](#create-an-audio-track-and-a-video-track) and [Publish the local audio and video tracks](#publish-the-local-audio-and-video-tracks).

    ### Improved channel events [#improved-channel-events]

    The improved events are:

    * **Rename events**

    The Broadcast Streaming v4.x ensures the consistency of all event names. For example, Agora renames `onTokenPrivilegeWillExpire` as `token-privilege-will-expire`. Agora also renames several events to ensure developers can better understand how they work. For example, Agora renames `peer-online` and `peer-offline` as `user-joined` and `user-left`, `stream-added` and `stream-removed` as `user-published` and `user-unpublished`.

    * **Change the format of parameters in events**

    In the Broadcast Streaming v3.x, the parameters of events must be wrapped in an object, while in the Broadcast Streaming v4.x, you can directly pass multiple parameters in events.

    Take the `"connection-state-change"` event as an example:

    * Using Video SDK v3.x

      ```js
      client.on("connection-state-change", e => {
       console.log("current", e.curState, "prev", e.prevState);
      });
      ```

    * Using Video SDK v4.x
      ```js
      client.on("connection-state-change", (curState, prevState) => {
       console.log("current", curState, "prev", prevState);
      });
      ```

    * **Improve the event notification mechanism**

    The Broadcast Streaming v4.x improves its event notification mechanism, and does not trigger channel events repeatedly.

    For example, assume that a local user A and remote users B, C, and D joins a channel at the same time, and B, C, and D all publishes their streams. If A suddenly loses connection with the channel due to bad network conditions, the SDK automatically reconnects A to the channel. While A is reconnecting to the channel, B leaves the channel and C unpublishes the stream. My question is, what events that the SDK triggers during the whole process?

    When A joins the channel, the Broadcast Streaming v3.x and Broadcast Streaming v4.x trigger the same events:

    * Events indicating B, C, D joining the channel.

    * Events indicating B, C, D publishing their streams.

    When A loses connection with the channel due to poor network conditions and reconnects to the channel:

    * If A uses the Broadcast Streaming v3.x: When A loses connection with the channel due to poor network conditions, the SDK assumes A has left the channel and clears all the states in the channel. When A successfully reconnects to the channel, it receives:

    * Events indicating C, D joining the channel.

    * Events indicating D publishing the stream.

    In the Broadcast Streaming v3.x, you can expect to receive the same events multiple times due to disconnection and reconnection, which may cause unexpected problems for dealing with these events on the app level. You need to listen for connection state changes and reset the states on the app level to avoid unexpected problems when receiving these events for the second time.

    * If A uses the Broadcast Streaming v4.x: When A loses connection with the channel due to poor network conditions, the SDK assumes that A is still in the channel and does not clear all the states in the channel. When A successfully reconnects to the channel, the SDK only sends A events that are lost during the reconnection process, including:

    * The event indicating B leaving the channel.

    * The event indicating C unpublishing the stream.

      The Broadcast Streaming v4.x does not send you the same events repeatedly and ensures your app works properly during reconnection.

      As these hypothetical examples demonstrate, the event notification mechanism in the Broadcast Streaming v4.x is more intuitive and does not need extra work.

    ## Core API change list [#core-api-change-list]

    ### `AgoraRTC` [#agorartc]

    * Rename `getScreenSources` as [getElectronScreenSources](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#getelectronscreensources), remove callbacks, and return a promise

    * [getDevices](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#getdevices) returns a promise. Add [getCameras](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#getcameras) and [getMicrophones](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#getmicrophones)

    * Remove the `Logger` object, and add [disableLogUpload](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#disablelogupload), [enableLogUpload](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#enablelogupload), and [setLogLevel](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#setloglevel)

    * Replace `createStream` with the following methods:

    * [createMicrophoneAudioTrack](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createmicrophoneaudiotrack)

    * [createCameraVideoTrack](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createcameravideotrack)

    * [createScreenVideoTrack](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createscreenvideotrack)

    * [createBufferSourceAudioTrack](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createbuffersourceaudiotrack)

    * [createCustomAudioTrack](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createcustomaudiotrack)

    * [createCustomVideoTrack](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createcustomvideotrack)

    ### `Client` [#client]

    * Remove `Client.init`

    * Remove `Client.getConnectionState` and add [Client.connectionState](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#connectionstate)

    * Add `RECONNECTING` in [ConnectionState](https://api-ref.agora.io/en/video-sdk/web/4.x/globals.html#connectionstate)

    * Add [Client.uid](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#uid)

    * Add [Client.remoteUsers](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#remoteusers)

    * Remove `Client.on("streamInjectStatus")`

    * Remove `Client.removeInjectStream`

    * Remove the callbacks of [Client.enableDualStream](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#enabledualstream) / [Client.disableDualStream](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#disabledualstream) and return a promise

    * Move `Client.getCameras`, `Client.getDevices`, `Client.getRecordingDevices` to the `AgoraRTC` interface

    * Remove `Client.getPlayoutDevices`

    * Replace `Client.getLocalAudioStats`, `Client.getLocalVideoStats`, `Client.getRemoteAudioStats`, and `Client.getRemoteVideoStats` with [LocalAudioTrack.getStats](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/ilocalaudiotrack.html#getstats), [LocalVideoTrack.getStats](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/ilocalvideotrack.html#getstats), [RemoteAudioTrack.getStats](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iremoteaudiotrack.html#getstats), and [RemoteVideoTrack.getStats](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iremotevideotrack.html#getstats).

    * Remove `Client.getSystemStats`

    * Replace `Client.getSessionStats` and `Client.getTransportStats` with [Client.getRTCStats](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#getrtcstats)

    * Remove the callback in [Client.join](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#join) and return a promise. Also add the `appid` parameter in this method

    * Remove the callback in [Client.leave](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#leave) and return a promise.

    * Add [Client.once](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#once)

    * Add [Client.removeAllListeners](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#removealllisteners)

    * Add the `tracks` parameter in [Client.publish](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#publish) for passing [LocalTrack](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/ilocaltrack.html). This method returns a promise. Remove `Client.on("stream-published")`

    * [Client.unpublish](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#publish) returns a promise.

    * Add the `user` parameter in [Client.subscribe](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#subscribe) for passing [AgoraRTCRemoteUser](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcremoteuser.html). This method returns a promise. Remove `Client.on("stream-subscribed")`.

    * Add the `user` parameter in [Client.unsubscribe](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#unsubscribe) for passing [AgoraRTCRemoteUser](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcremoteuser.html). This method returns a promise.

    * [Client.renewToken](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#renewtoken) returns a promise.

    * Remove the callback in [Client.setClientRole](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#setclientrole) and return a promise. In the Broadcast Streaming v4.x, setting the user role as `audience` does not unpublish, and when calling `publish`, the SDK does not automatically set the user role as `host`

    * Replace `Client.setEncryptionMode` and `Client.setEncryptionSecret` with [Client.setEncryptionConfig](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#setencryptionconfig)

    * [Client.setLiveTranscoding](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#setlivetranscoding), [Client.startLiveStreaming](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#startlivestreaming), and [Client.stopLiveStreaming](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#stoplivestreaming) all return a promise. Remove `Client.on("liveTranscodingUpdated")`, `Client.on("liveStreamingStarted")`, `Client.on("liveStreamingFailed")`, and `Client.on("liveStreamingStopped")` events.

    * `Client.startChannelMediaRelay` return a promise

    * Replace `setDestChannelInfo` in [ChannelMediaRelayConfiguration](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/ichannelmediarelayconfiguration.html) with [addDestChannelInfo](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/ichannelmediarelayconfiguration.html#adddestchannelinfo), remove several parameters

    * Remove several parameters in [setSrcChannelInfo](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/ichannelmediarelayconfiguration.html#setsrcchannelinfo) of [ChannelMediaRelayConfiguration](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/ichannelmediarelayconfiguration.html)

    * [Client.stopChannelMediaRelay](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#stopchannelmediarelay) return a promise.

    * Remove the callback in [Client.updateChannelMediaRelay](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#updatechannelmediarelay) and this method returns a promise.

    * Replace `Client.on("first-video-frame-decode")` and `Client.on("first-audio-frame-decode")` with [RemoteTrack.on("first-frame-decode")](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iremotetrack.html#event_first_frame_decoded)

    * Replace `Client.on("mute-audio")`, `Client.on("mute-video")`, `Client.on("unmute-audio")`, and `Client.on("unmute-video")` with [Client.on("user-mute-updated")](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#event_user_mute_updated)

    * Replace `Client.on("active-speaker")` with [Client.on("volume-indicator")](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#event_volume_indicator)

    * Rename `Client.on("onTokenPrivilegeWillExpire")` and `Client.on("onTokenPrivilegeDidExpire")` as [Client.on("token-privilege-will-expire")](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#event_token_privilege_will_expire) and [Client.on("token-privilege-did-expire")](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#event_token_privilege_did_expire)

    * Remove `Client.on("network-type-changed")`

    * Remove `Client.on("connected")` and `Client.on("reconnect")`. You can get events related to connection states from [Client.on("connection-state-change")](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#event_connection_state_change)

    * Add the `isFallbackOrRecover` parameter in [Client.on("stream-fallback")](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#event_stream_fallback)

    <CalloutContainer type="info">
      <CalloutDescription>
        Remove `Stream.setAudioOutput`. Agora does not recommends setting the audio output device on the web page. Instead, use the default audio output device.
      </CalloutDescription>
    </CalloutContainer>

    ### Stream [#stream]

    In the Broadcast Streaming v4.x, Agora replaces the [Stream](https://api-ref.agora.io/en/video-sdk/web/3.x/interfaces/agorartc.stream.html) object with `Track` objects. Tracks make up a stream. You create, publish, or subscribe to one or multiple audio and video tracks to control the media stream. The advantage of dividing a stream up into tracks is that audio and video are controllable separately. Additionally, the Broadcast Streaming v4.x provides different interfaces for the local and remote tracks. Some methods and objects are only available locally, and some are only available remotely.

    Listed below are the major differences on media control between the Broadcast Streaming v4.x and Broadcast Streaming v3.x:

    * Enable/disable a local track: The Broadcast Streaming v4.x replaces the `Stream.muteAudio` and `Stream.muteVideo` methods with [ILocalTrack.setEnabled](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/ilocaltrack.html#setenabled) for enabling or disabling a local audio or video track. This replacement changes the following SDK behaviors:

    * In the Broadcast Streaming v3.x, when the mute state changes, the SDK triggers the `Client.on("mute-audio")`, `Client.on("mute-video")`, `Client.on("unmute-audio")`, or `Client.on("unmute-video")` events. The Broadcast Streaming v4.x removes these events. When you call `setEnabled` to enable or disable a published local track, the SDK triggers the `Client.on("user-published")` or `Client.on("user-unpublished")` events on the remote client.

    * In the Broadcast Streaming v3.x, after you call `Stream.muteVideo(true)` to disable a local video stream, the camera light stays on, which might adversely impact the user experience. In contrast, if you call `setEnabled(false)` in the Broadcast Streaming v4.x to disable a local video track, the SDK immediately turns off the camera.

    * Set the media device:

    * The Broadcast Streaming v4.x replaces `Stream.switchDevice` with [IMicrophoneAudioTrack.setDevice](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/imicrophoneaudiotrack.html#setdevice) and [ICameraVideoTrack.setDevice](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/icameravideotrack.html#setdevice) for setting the media input device.

    * The Broadcast Streaming v4.x replaces `Stream.setAudioOutput` with [IRemoteAudioTrack.setPlaybackDevice](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iremoteaudiotrack.html#setplaybackdevice) for setting the audio output device.

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>
</_PlatformTabsGroup>
