From d02a0acf87dc899d82375c85e973d2f92a15a918 Mon Sep 17 00:00:00 2001 From: sda_rob Date: Fri, 4 Jul 2025 07:04:08 +0000 Subject: [PATCH 01/25] chore: release 4.5.2-build.140-rc.1 --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5639f946..16ebb982 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ +## [4.5.2-build.140-rc.1](https://github.com/AgoraIO-Extensions/react-native-agora/compare/v4.5.3...v4.5.2-build.140-rc.1) (2025-07-04) + ## [4.5.3](https://github.com/AgoraIO-Extensions/react-native-agora/compare/v4.5.2...v4.5.3) (2025-05-07) diff --git a/package.json b/package.json index 0df45010..a871215a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-agora", - "version": "4.5.3", + "version": "4.5.2-build.140-rc.1", "description": "Agora RTC SDK For React Native", "main": "lib/commonjs/index", "module": "lib/module/index", From 3fca6e4c8d76cec211d411214fa0c7279cc04aa2 Mon Sep 17 00:00:00 2001 From: sda_rob Date: Mon, 7 Jul 2025 02:56:53 +0000 Subject: [PATCH 02/25] chore: release 4.5.2-build.140-rc.2 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16ebb982..eab98f28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ +## [4.5.2-build.140-rc.2](https://github.com/AgoraIO-Extensions/react-native-agora/compare/v4.5.2-build.140-rc.1...v4.5.2-build.140-rc.2) (2025-07-07) + + +### Bug Fixes + +* picture in picture issue in iOS ([b825c78](https://github.com/AgoraIO-Extensions/react-native-agora/commit/b825c787cf8daaed1b23842499d496b85e31dacb)) + ## [4.5.2-build.140-rc.1](https://github.com/AgoraIO-Extensions/react-native-agora/compare/v4.5.3...v4.5.2-build.140-rc.1) (2025-07-04) ## [4.5.3](https://github.com/AgoraIO-Extensions/react-native-agora/compare/v4.5.2...v4.5.3) (2025-05-07) diff --git a/package.json b/package.json index a871215a..69f04d1e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-agora", - "version": "4.5.2-build.140-rc.1", + "version": "4.5.2-build.140-rc.2", "description": "Agora RTC SDK For React Native", "main": "lib/commonjs/index", "module": "lib/module/index", From 461c8b292d23a234c6b74417d063a523c780b78c Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 29 Sep 2025 18:43:44 +0800 Subject: [PATCH 03/25] chore: optimize --- .github/workflows/dep.yml | 12 ++++++++++++ scripts/dep.sh | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/.github/workflows/dep.yml b/.github/workflows/dep.yml index 322609b6..85239dcb 100644 --- a/.github/workflows/dep.yml +++ b/.github/workflows/dep.yml @@ -25,6 +25,18 @@ jobs: run: | sh scripts/dep.sh ${{ steps.dep.outputs.matches }} + - name: Generate code and comment by terra + uses: AgoraIO-Extensions/actions/.github/actions/generate@main + with: + github-token: ${{ secrets.GH_TOKEN }} + generate-code: true + generate-comment: true + generate-code-command: | + sh generate-prepare.sh + sh generate-code.sh + generate-comment-command: | + sh generate-comment.sh + - name: Setup uses: ./.github/actions/setup diff --git a/scripts/dep.sh b/scripts/dep.sh index 31a7e7fc..e44ec0cb 100644 --- a/scripts/dep.sh +++ b/scripts/dep.sh @@ -6,6 +6,8 @@ PROJECT_ROOT=$(realpath ${MY_PATH}/..) ANDROID_BUILD_GRADLE_PATH="${PROJECT_ROOT}/android/build.gradle" iOS_PODSPEC_PATH="${PROJECT_ROOT}/react-native-agora.podspec" EXAMPLE_IOS_PODFILE_PATH="${PROJECT_ROOT}/example/ios/Podfile" +TERRA_CONFIG_PATH1="${PROJECT_ROOT}/scripts/terra/config/types_config.yaml" +TERRA_CONFIG_PATH2="${PROJECT_ROOT}/scripts/terra/config/impl_config.yaml" if [ "$#" -lt 1 ]; then exit 1 fi @@ -13,6 +15,7 @@ INPUT=$1 MAVEN_DEPENDENCIES=$(echo "$INPUT" | jq -r '.[] | select(.platform == "Android") | .maven[]') IRIS_MAVEN_DEPENDENCIES=$(echo "$INPUT" | jq -r '.[] | select(.platform == "Android") | .iris_maven[]') +DEP_VERSION=$(echo "$INPUT" | jq -r '.[] | select(.platform == "Android") | .version') # Function to modify dependencies modify_dependencies() { @@ -63,3 +66,13 @@ else rm "$TEMP_FILE" echo "example/ios/Podfile updated." fi + +if [ -z "$DEP_VERSION" ]; then + echo "can not find dependencies version." +else + echo "update dependencies version to $TERRA_CONFIG_PATH1" + sed 's|sdkVersion: \(.*\)|sdkVersion: '$DEP_VERSION'|g' $TERRA_CONFIG_PATH1 > tmp + mv tmp $TERRA_CONFIG_PATH1 + sed 's|sdkVersion: \(.*\)|sdkVersion: '$DEP_VERSION'|g' $TERRA_CONFIG_PATH2 > tmp + mv tmp $TERRA_CONFIG_PATH2 +fi From 70ff582b0af45f456aefd32b6d1d4b72377e3f27 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 29 Sep 2025 19:11:53 +0800 Subject: [PATCH 04/25] chore: optimize --- .github/workflows/dep.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dep.yml b/.github/workflows/dep.yml index 85239dcb..4ea2fb1f 100644 --- a/.github/workflows/dep.yml +++ b/.github/workflows/dep.yml @@ -15,6 +15,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Setup + uses: ./.github/actions/setup + - name: Get dependencies id: dep uses: AgoraIO-Extensions/actions/.github/actions/dep@main @@ -37,9 +40,6 @@ jobs: generate-comment-command: | sh generate-comment.sh - - name: Setup - uses: ./.github/actions/setup - - name: Update example run: | rm -rf example/ios/Podfile.lock From c1e8dc97bb22f616c71934068e6b028cce8ccd2a Mon Sep 17 00:00:00 2001 From: sda-rob <149643938+sda-rob@users.noreply.github.com> Date: Mon, 29 Sep 2025 19:41:45 +0800 Subject: [PATCH 05/25] [AUTO] Update dependencies (#908) * [AUTO] Update dependencies * chore: optimize --------- Co-authored-by: guoxianzhe Co-authored-by: gxz --- android/build.gradle | 5 +- example/ios/Podfile | 2 +- example/ios/Podfile.lock | 24 +-- react-native-agora.podspec | 4 +- scripts/terra/config/impl_config.yaml | 2 +- scripts/terra/config/types_config.yaml | 2 +- src/AgoraBase.ts | 62 ++++--- src/AgoraMediaBase.ts | 156 +++++++++--------- src/IAgoraMediaPlayer.ts | 2 +- src/IAgoraPip.ts | 213 ++++++++----------------- src/IAgoraRtcEngine.ts | 33 ++-- src/IAgoraRtcEngineEx.ts | 20 ++- src/impl/IAgoraRtcEngineExImpl.ts | 35 ++++ src/index.ts | 2 +- 14 files changed, 273 insertions(+), 289 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 935bc98c..ba4251de 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -165,9 +165,8 @@ dependencies { implementation "com.facebook.react:react-native:+" implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs') /// dependencies start - api 'io.agora.rtc:full-screen-sharing:4.5.2.140' - api 'io.agora.rtc:agora-special-full:4.5.2.140' - api 'io.agora.rtc:iris-rtc:4.5.2.140-build.4' + api 'io.agora.rtc:agora-special-full:4.5.2.2.LITE' + api 'io.agora.rtc:iris-rtc:4.5.2.2-lite.1' /// dependencies end } diff --git a/example/ios/Podfile b/example/ios/Podfile index ad75e689..8da709f7 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -41,6 +41,6 @@ end target 'ScreenShare' do #dependencies start - pod 'AgoraRtcEngine_Special_iOS', '4.5.2.140' + pod 'AgoraRtcEngine_Special_iOS', '4.5.2.2.LITE' #dependencies end end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f6ee1d19..86aa9b7d 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,6 +1,6 @@ PODS: - - AgoraIrisRTC_iOS (4.5.2.140-build.6) - - AgoraRtcEngine_Special_iOS (4.5.2.140) + - AgoraIrisRTC_iOS (4.5.2.2-lite.1) + - AgoraRtcEngine_Special_iOS (4.5.2.2.LITE) - boost (1.84.0) - DoubleConversion (1.1.6) - fast_float (6.1.4) @@ -1212,9 +1212,9 @@ PODS: - React-jsiexecutor - React-RCTFBReactNativeSpec - ReactCommon/turbomodule/core - - react-native-agora (4.5.3): - - AgoraIrisRTC_iOS (= 4.5.2.140-build.6) - - AgoraRtcEngine_Special_iOS (= 4.5.2.140) + - react-native-agora (4.5.2-build.140-rc.2): + - AgoraIrisRTC_iOS (= 4.5.2.2-lite.1) + - AgoraRtcEngine_Special_iOS (= 4.5.2.2.LITE) - DoubleConversion - glog - hermes-engine @@ -1892,7 +1892,7 @@ PODS: - Yoga (0.0.0) DEPENDENCIES: - - AgoraRtcEngine_Special_iOS (= 4.5.2.140) + - AgoraRtcEngine_Special_iOS (= 4.5.2.2.LITE) - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - fast_float (from `../node_modules/react-native/third-party-podspecs/fast_float.podspec`) @@ -2137,8 +2137,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - AgoraIrisRTC_iOS: 41a033327414eeea7a8666e69aa7cd2530b70a76 - AgoraRtcEngine_Special_iOS: aa5c57a16e9b43734f38da4c6105a15d55c33873 + AgoraIrisRTC_iOS: a181e24ca69052c9b8dd03a42e2b56b0ad655d9d + AgoraRtcEngine_Special_iOS: 6240ca22a740b9ca12394857b58aad74ade72e1c boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6 @@ -2146,7 +2146,7 @@ SPEC CHECKSUMS: fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: eb93e2f488219332457c3c4eafd2738ddc7e80b8 hermes-engine: ccc24d29d650ea725d582a9a53d57cd417fbdb53 - RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82 + RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809 RCTDeprecation: 664055db806cce35c3c1b43c84414dd66e117ae6 RCTRequired: dc9a83fa1012054f94430d210337ca3a1afe6fc0 RCTTypeSafety: 031cefa254a1df313a196f105b8fcffdab1c5ab6 @@ -2175,7 +2175,7 @@ SPEC CHECKSUMS: React-logger: 1935d6e6461e9c8be4c87af56c56a4876021171e React-Mapbuffer: 212171f037e3b22e6c2df839aa826806da480b85 React-microtasksnativemodule: 72564d5469003687d39bfc4efad281df8efc0684 - react-native-agora: 3b05cc231004bb8473646bf847257dfc61796272 + react-native-agora: 2b94cc8489af0ac85b2ade84cb867eaf051e5072 react-native-image-tools: 88218449791389bbf550a2c475a3b564c8233c8b react-native-safe-area-context: 9c33120e9eac7741a5364cc2d9f74665049b76b3 react-native-slider: e7f302c8d3296ddb49c642473f77f8f98809d53b @@ -2218,6 +2218,6 @@ SPEC CHECKSUMS: SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 Yoga: 2957d0e744897870b5a377f26522e3f08cadd7ac -PODFILE CHECKSUM: e88970b0fe9c6f7c4bd598eb3a75f32a38339d8f +PODFILE CHECKSUM: 7a13221579e060f11d34482113b3022a25bd3056 -COCOAPODS: 1.16.2 +COCOAPODS: 1.13.0 diff --git a/react-native-agora.podspec b/react-native-agora.podspec index 8f7492e4..97b6fd80 100644 --- a/react-native-agora.podspec +++ b/react-native-agora.podspec @@ -41,8 +41,8 @@ Pod::Spec.new do |s| end #dependencies start - s.dependency 'AgoraRtcEngine_Special_iOS', '4.5.2.140' - s.dependency 'AgoraIrisRTC_iOS', '4.5.2.140-build.6' + s.dependency 'AgoraRtcEngine_Special_iOS', '4.5.2.2.LITE' + s.dependency 'AgoraIrisRTC_iOS', '4.5.2.2-lite.1' #dependencies end s.libraries = 'stdc++' diff --git a/scripts/terra/config/impl_config.yaml b/scripts/terra/config/impl_config.yaml index d11128ef..c997afb1 100644 --- a/scripts/terra/config/impl_config.yaml +++ b/scripts/terra/config/impl_config.yaml @@ -2,7 +2,7 @@ parsers: - name: RTCParser package: '@agoraio-extensions/terra_shared_configs' args: - sdkVersion: 4.5.2 + sdkVersion: 4.5.2.2 FixEnumConstantParser: skipCalEnumValue: true diff --git a/scripts/terra/config/types_config.yaml b/scripts/terra/config/types_config.yaml index df456ad3..cd4b09f1 100644 --- a/scripts/terra/config/types_config.yaml +++ b/scripts/terra/config/types_config.yaml @@ -2,7 +2,7 @@ parsers: - name: RTCParser package: '@agoraio-extensions/terra_shared_configs' args: - sdkVersion: 4.5.2 + sdkVersion: 4.5.2.2 FixEnumConstantParser: skipCalEnumValue: true diff --git a/src/AgoraBase.ts b/src/AgoraBase.ts index cdfc5519..c8814464 100644 --- a/src/AgoraBase.ts +++ b/src/AgoraBase.ts @@ -1154,11 +1154,11 @@ export enum H264PacketizeMode { */ export enum VideoStreamType { /** - * 0: High-quality video stream. + * 0: High-quality video stream, that is, a video stream with the highest resolution and bitrate. */ VideoStreamHigh = 0, /** - * 1: Low-quality video stream. + * 1: Low-quality video stream, that is, a video stream with the lowest resolution and bitrate. */ VideoStreamLow = 1, /** @@ -1558,7 +1558,7 @@ export class SimulcastStreamConfig { */ dimensions?: VideoDimensions; /** - * Video receive bitrate (Kbps), represented by an instantaneous value. This parameter does not need to be set. The SDK automatically matches the most suitable bitrate based on the video resolution and frame rate you set. + * Video bitrate (Kbps). The default value is -1. This parameter does not need to be set. The SDK automatically matches the most suitable bitrate based on the video resolution and frame rate you set. */ kBitrate?: number; /** @@ -1678,7 +1678,9 @@ export class WatermarkRatio { } /** - * Configurations of the watermark image. + * Watermark image configurations. + * + * Configuration options for setting the watermark image to be added. */ export class WatermarkOptions { /** @@ -4411,10 +4413,42 @@ export enum VoiceAiTunerType { VoiceAiTunerDreamyFemaleSinging = 9, } +/** + * The audio configuration for the shared screen stream. + * + * Only available where captureAudio is true. + */ +export class ScreenAudioParameters { + /** + * Audio sample rate (Hz). The default value is 16000. + */ + sampleRate?: number; + /** + * The number of audio channels. The default value is 2, which means stereo. + */ + channels?: number; + /** + * The volume of the captured system audio. The value range is [0, 100]. The default value is 100. + */ + captureSignalVolume?: number; + /** + * @ignore + */ + excludeCurrentProcessAudio?: boolean; +} + /** * @ignore */ export class ScreenCaptureParameters { + /** + * @ignore + */ + captureAudio?: boolean; + /** + * @ignore + */ + audioParams?: ScreenAudioParameters; /** * @ignore */ @@ -5180,26 +5214,6 @@ export class ScreenVideoParameters { contentHint?: VideoContentHint; } -/** - * The audio configuration for the shared screen stream. - * - * Only available where captureAudio is true. - */ -export class ScreenAudioParameters { - /** - * Audio sample rate (Hz). The default value is 16000. - */ - sampleRate?: number; - /** - * The number of audio channels. The default value is 2, which means stereo. - */ - channels?: number; - /** - * The volume of the captured system audio. The value range is [0, 100]. The default value is 100. - */ - captureSignalVolume?: number; -} - /** * Screen sharing configurations. */ diff --git a/src/AgoraMediaBase.ts b/src/AgoraMediaBase.ts index 95b161d4..ee53beef 100644 --- a/src/AgoraMediaBase.ts +++ b/src/AgoraMediaBase.ts @@ -305,82 +305,6 @@ export enum MediaSourceType { UnknownMediaSource = 100, } -/** - * @ignore - */ -export enum ContentInspectResult { - /** - * @ignore - */ - ContentInspectNeutral = 1, - /** - * @ignore - */ - ContentInspectSexy = 2, - /** - * @ignore - */ - ContentInspectPorn = 3, -} - -/** - * The type of video content moderation module. - */ -export enum ContentInspectType { - /** - * 0: (Default) This module has no actual function. Do not set type to this value. - */ - ContentInspectInvalid = 0, - /** - * @ignore - */ - ContentInspectModeration = 1, - /** - * 2: Video screenshot and upload via Agora self-developed extension. SDK takes screenshots of the video stream in the channel and uploads them. - */ - ContentInspectSupervision = 2, - /** - * 3: Video screenshot and upload via extensions from Agora Extensions Marketplace. SDK uses video moderation extensions from Agora Extensions Marketplace to take screenshots of the video stream in the channel and uploads them. - */ - ContentInspectImageModeration = 3, -} - -/** - * ContentInspectModule A structure used to configure the frequency of video screenshot and upload. - */ -export class ContentInspectModule { - /** - * Types of functional module. See ContentInspectType. - */ - type?: ContentInspectType; - /** - * The frequency (s) of video screenshot and upload. The value should be set as larger than 0. The default value is 0, the SDK does not take screenshots. Agora recommends that you set the value as 10; you can also adjust it according to your business needs. - */ - interval?: number; -} - -/** - * Screenshot and upload configuration. - */ -export class ContentInspectConfig { - /** - * Additional information on the video content (maximum length: 1024 Bytes). The SDK sends the screenshots and additional information on the video content to the Agora server. Once the video screenshot and upload process is completed, the Agora server sends the additional information and the callback notification to your server. - */ - extraInfo?: string; - /** - * (Optional) Server configuration related to uploading video screenshots via extensions from Agora Extensions Marketplace. This parameter only takes effect when type in ContentInspectModule is set to ContentInspectImageModeration. If you want to use it, contact. - */ - serverConfig?: string; - /** - * Functional module. See ContentInspectModule. A maximum of 32 ContentInspectModule instances can be configured, and the value range of MAX_CONTENT_INSPECT_MODULE_COUNT is an integer in [1,32]. A function module can only be configured with one instance at most. Currently only the video screenshot and upload function is supported. - */ - modules?: ContentInspectModule[]; - /** - * The number of functional modules, that is,the number of configured ContentInspectModule instances, must be the same as the number of instances configured in modules. The maximum number is 32. - */ - moduleCount?: number; -} - /** * @ignore */ @@ -1181,6 +1105,86 @@ export enum VideoModulePosition { PositionPostCapturerOrigin = 1 << 3, } +/** + * @ignore + */ +export enum ContentInspectResult { + /** + * @ignore + */ + ContentInspectNeutral = 1, + /** + * @ignore + */ + ContentInspectSexy = 2, + /** + * @ignore + */ + ContentInspectPorn = 3, +} + +/** + * The type of video content moderation module. + */ +export enum ContentInspectType { + /** + * 0: (Default) This module has no actual function. Do not set type to this value. + */ + ContentInspectInvalid = 0, + /** + * @ignore + */ + ContentInspectModeration = 1, + /** + * 2: Video screenshot and upload via Agora self-developed extension. SDK takes screenshots of the video stream in the channel and uploads them. + */ + ContentInspectSupervision = 2, + /** + * 3: Video screenshot and upload via extensions from Agora Extensions Marketplace. SDK uses video moderation extensions from Agora Extensions Marketplace to take screenshots of the video stream in the channel and uploads them. + */ + ContentInspectImageModeration = 3, +} + +/** + * ContentInspectModule A structure used to configure the frequency of video screenshot and upload. + */ +export class ContentInspectModule { + /** + * Types of functional module. See ContentInspectType. + */ + type?: ContentInspectType; + /** + * The frequency (s) of video screenshot and upload. The value should be set as larger than 0. The default value is 0, the SDK does not take screenshots. Agora recommends that you set the value as 10; you can also adjust it according to your business needs. + */ + interval?: number; + /** + * @ignore + */ + position?: VideoModulePosition; +} + +/** + * Screenshot and upload configuration. + */ +export class ContentInspectConfig { + /** + * Additional information on the video content (maximum length: 1024 Bytes). The SDK sends the screenshots and additional information on the video content to the Agora server. Once the video screenshot and upload process is completed, the Agora server sends the additional information and the callback notification to your server. + */ + extraInfo?: string; + /** + * (Optional) Server configuration related to uploading video screenshots via extensions from Agora Extensions Marketplace. This parameter only takes effect when type in ContentInspectModule is set to ContentInspectImageModeration. If you want to use it, contact. + */ + serverConfig?: string; + /** + * Functional module. See ContentInspectModule. A maximum of 32 ContentInspectModule instances can be configured, and the value range of MAX_CONTENT_INSPECT_MODULE_COUNT is an integer in [1,32]. A function module can only be configured with one instance at most. Currently only the video screenshot and upload function is supported. + */ + modules?: ContentInspectModule[]; + /** + * The number of functional modules, that is,the number of configured ContentInspectModule instances, must be the same as the number of instances configured in modules. The maximum number is 32. + */ + moduleCount?: number; +} + /** * The snapshot configuration. */ diff --git a/src/IAgoraMediaPlayer.ts b/src/IAgoraMediaPlayer.ts index 919d6850..e4d56924 100644 --- a/src/IAgoraMediaPlayer.ts +++ b/src/IAgoraMediaPlayer.ts @@ -152,7 +152,7 @@ export abstract class IMediaPlayer { * @param index The index of the media stream. This parameter must be less than the return value of getStreamCount. * * @returns - * If the call succeeds, returns the detailed information of the media stream. See PlayerStreamInfo. null, if the method call fails. + * If the call succeeds, returns the detailed information of the media stream. See PlayerStreamInfo. null is returned, if the method call fails. */ abstract getStreamInfo(index: number): PlayerStreamInfo; diff --git a/src/IAgoraPip.ts b/src/IAgoraPip.ts index aabdb8c5..48b8c3ff 100644 --- a/src/IAgoraPip.ts +++ b/src/IAgoraPip.ts @@ -1,282 +1,205 @@ -/** - * Represents a video stream configuration for Picture-in-Picture (PiP) mode. - * - * This class holds the connection and canvas settings needed to display - * a video stream within the PiP window. - */ - import { RtcRendererViewProps } from './AgoraRtcRenderView'; /** - * Layout configuration for Picture-in-Picture (PiP) video streams. - * - * This class defines how multiple video streams should be arranged in a flow layout, - * where streams are placed from left to right and top to bottom in sequence. - * - * Example layout with padding=10, spacing=5, column=3: - * ``` - * ┌────────────────────────────────────┐ - * │ │ - * │ ┌────┐ ┌────┐ ┌────┐ │ - * │ │ 1 │ │ 2 │ │ 3 │ │ - * │ └────┘ └────┘ └────┘ │ - * │ │ - * │ ┌────┐ ┌────┐ ┌────┐ │ - * │ │ 4 │ │ 5 │ │ 6 │ │ - * │ └────┘ └────┘ └────┘ │ - * │ │ - * │ ┌────┐ │ - * │ │ 7 │ │ - * │ └────┘ │ - * │ │ - * └────────────────────────────────────┘ - * ``` + * @ignore */ export class AgoraPipContentViewLayout { /** - * The padding around the entire layout in pixels. - * Creates space between the layout edges and the streams. - * If null, no padding will be applied. + * @ignore */ padding?: number; /** - * The horizontal and vertical spacing between streams in pixels. - * Creates consistent gaps between adjacent streams. - * If null, streams will be placed directly adjacent to each other. + * @ignore */ spacing?: number; /** - * Maximum number of rows allowed in the layout. - * When reached, no more rows will be created even if more streams exist. - * If null, rows will be created as needed to fit all streams. - * Must be greater than 0 or null. + * @ignore */ row?: number; /** - * Maximum number of streams per row. - * When reached, a new row will be started. - * If null, streams will flow to fill the available width. - * Must be greater than 0 or null. + * @ignore */ column?: number; } /** - * Configuration options for Agora Picture-in-Picture (PiP) mode. - * - * This class provides platform-specific options to configure PiP behavior - * for both Android and iOS platforms. + * @ignore */ export class AgoraPipOptions { /** - * Whether to automatically enter PiP mode. - * + * @ignore */ autoEnterEnabled?: boolean; /** - * The horizontal aspect ratio of the PiP window. - * - * Platform: Android only + * @ignore */ aspectRatioX?: number; /** - * The vertical aspect ratio of the PiP window. - * - * Platform: Android only + * @ignore */ aspectRatioY?: number; /** - * The left coordinate of the source rectangle hint. - * - * Used to specify the initial position of the PiP window. - * Platform: Android only + * @ignore */ sourceRectHintLeft?: number; /** - * The top coordinate of the source rectangle hint. - * - * Used to specify the initial position of the PiP window. - * Platform: Android only + * @ignore */ sourceRectHintTop?: number; /** - * The right coordinate of the source rectangle hint. - * - * Used to specify the initial position of the PiP window. - * Platform: Android only + * @ignore */ sourceRectHintRight?: number; /** - * The bottom coordinate of the source rectangle hint. - * - * Used to specify the initial position of the PiP window. - * Platform: Android only + * @ignore */ sourceRectHintBottom?: number; /** - * Whether to enable seamless resize for the PiP window. - * - * When enabled, the PiP window will resize smoothly. - * Defaults to false. - * Platform: Android only + * @ignore */ seamlessResizeEnabled?: boolean; /** - * Whether to use external state monitoring. - * - * When enabled, creates a dedicated thread to monitor PiP window state. - * Use externalStateMonitorInterval to configure monitoring frequency. - * Defaults to true. - * Platform: Android only + * @ignore */ useExternalStateMonitor?: boolean; /** - * The interval for external state monitoring in milliseconds. - * - * Only takes effect when useExternalStateMonitor is true. - * Defaults to 100ms. - * Platform: Android only + * @ignore */ externalStateMonitorInterval?: number; /** - * Configuration for video transcoding. - * - * Only takes effect when contentView is set to 0. - * When user let the SDK manage the view, all video streams will place in a root view in the PIP window. - * Platform: iOS only + * @ignore */ videoStreams?: RtcRendererViewProps[]; /** - * Layout configuration for PiP video streams. - * - * Only takes effect when contentView is set to 0. - * Platform: iOS only + * @ignore */ contentViewLayout?: AgoraPipContentViewLayout; /** - * The sourceContentView determines the source frame for the PiP animation and restore target. - * Pass 0 to use the app's root view. For optimal animation, set this to the view containing - * your video content. The system uses this view for the PiP enter/exit animations and as the - * restore target when returning to the app or stopping PiP. + * @ignore */ sourceContentView?: number; /** - * The contentView determines which view will be displayed in the PIP window. - * If you pass 0, the PIP controller will automatically manage and display all video streams. - * If you pass a specific view ID, you become responsible for managing the content shown in the PIP window. + * @ignore */ contentView?: number; /** - * The preferred width of the PiP content. - * - * Platform: iOS only + * @ignore */ preferredContentWidth?: number; /** - * The preferred height of the PiP content. - * - * Platform: iOS only + * @ignore */ preferredContentHeight?: number; /** - * The control style for the PiP window. - * - * Available styles: - * * 0: Show all system controls (default) - * * 1: Hide forward and backward buttons - * * 2: Hide play/pause button and progress bar (recommended) - * * 3: Hide all system controls including close and restore buttons - * - * Platform: iOS only + * @ignore */ controlStyle?: number; } -/** Represents the current state of Picture-in-Picture mode. */ +/** + * @ignore + */ export enum AgoraPipState { - /** PiP mode has been successfully started. */ + /** + * @ignore + */ pipStateStarted = 0, - /** PiP mode has been stopped. */ + /** + * @ignore + */ pipStateStopped = 1, - /** PiP mode failed to start or encountered an error. */ + /** + * @ignore + */ pipStateFailed = 2, } /** - * Observer for Picture-in-Picture state changes. - * - * Implement this class to receive notifications about PiP state transitions - * and potential errors. + * @ignore */ export interface AgoraPipStateChangedObserver { /** - * Callback function for PiP state changes. - * - * @param state - The new PiP state - * @param error - Error message if the state change failed, null otherwise + * @ignore */ onPipStateChanged: (state: AgoraPipState, error: string | null) => void; } /** - * Controller interface for managing Picture-in-Picture functionality. - * - * This abstract class defines the methods required to control PiP mode, - * including setup, state management, and lifecycle operations. + * @ignore */ export abstract class AgoraPip { - /** Releases resources associated with PiP mode. */ + /** + * @ignore + */ abstract release(): void; - /** Registers an observer for PiP state changes. */ + /** + * @ignore + */ abstract registerPipStateChangedObserver( observer: AgoraPipStateChangedObserver ): void; - /** Unregister an observer PiP state observer. */ + /** + * @ignore + */ abstract unregisterPipStateChangedObserver( observer: AgoraPipStateChangedObserver ): void; - /** Checks if PiP mode is supported on the current device. */ + /** + * @ignore + */ abstract pipIsSupported(): boolean; - /** Checks if automatic PiP mode entry is supported. */ + /** + * @ignore + */ abstract pipIsAutoEnterSupported(): boolean; - /** Checks if PiP mode is currently active. */ + /** + * @ignore + */ abstract isPipActivated(): boolean; - /** Configures PiP mode with the specified options. */ + /** + * @ignore + */ abstract pipSetup(options: AgoraPipOptions): boolean; - /** Starts PiP mode with the current configuration. */ + /** + * @ignore + */ abstract pipStart(): boolean; - /** Stops PiP mode. */ + /** + * @ignore + */ abstract pipStop(): void; - /** Releases resources associated with PiP mode. */ + /** + * @ignore + */ abstract pipDispose(): void; } diff --git a/src/IAgoraRtcEngine.ts b/src/IAgoraRtcEngine.ts index 8332dda8..0bfeede3 100644 --- a/src/IAgoraRtcEngine.ts +++ b/src/IAgoraRtcEngine.ts @@ -1132,14 +1132,14 @@ export class ChannelMediaOptions { * Whether to publish the audio captured by the microphone: true : Publish the audio captured by the microphone. false : Do not publish the audio captured by the microphone. */ publishMicrophoneTrack?: boolean; - /** - * Whether to publish the video captured from the screen: true : Publish the video captured from the screen. false : Do not publish the video captured from the screen. - */ - publishScreenCaptureVideo?: boolean; /** * Whether to publish the audio captured from the screen: true : Publish the audio captured from the screen. false : Publish the audio captured from the screen. */ publishScreenCaptureAudio?: boolean; + /** + * Whether to publish the video captured from the screen: true : Publish the video captured from the screen. false : Do not publish the video captured from the screen. + */ + publishScreenCaptureVideo?: boolean; /** * @ignore */ @@ -1487,7 +1487,7 @@ export interface IRtcEngineEventHandler { * * This callback occurs when the local audio effect file finishes playing. * - * @param soundId The ID of the audio effect. The ID of each audio effect file is unique. + * @param soundId The ID of the audio effect. The unique ID of each audio effect file. */ onAudioEffectFinished?(soundId: number): void; @@ -2958,7 +2958,7 @@ export abstract class IRtcEngine { * Gets the SDK version. * * @returns - * One SDKBuildInfo object. + * SDKBuildInfo object. */ abstract getVersion(): SDKBuildInfo; @@ -3134,7 +3134,7 @@ export abstract class IRtcEngine { /** * Renews the token. * - * You can call this method to pass a new token to the SDK. A token will expire after a certain period of time, at which point the SDK will be unable to establish a connection with the server. + * This method is used to update the token. After successfully calling this method, the SDK will trigger the callback. A token will expire after a certain period of time, at which point the SDK will be unable to establish a connection with the server. * * @param token The new token. * @@ -3664,7 +3664,7 @@ export abstract class IRtcEngine { * Enables/Disables the local video capture. * * This method disables or re-enables the local video capture, and does not affect receiving the remote video stream. After calling enableVideo, the local video capture is enabled by default. If you call enableLocalVideo (false) to disable local video capture within the channel, it also simultaneously stops publishing the video stream within the channel. If you want to restart video catpure, you can call enableLocalVideo (true) and then call updateChannelMediaOptions to set the options parameter to publish the locally captured video stream in the channel. After the local video capturer is successfully disabled or re-enabled, the SDK triggers the onRemoteVideoStateChanged callback on the remote client. - * You can call this method either before or after joining a channel. + * You can call this method either before or after joining a channel. However, if you call it before joining, the settings will only take effect once you have joined the channel. * This method enables the internal engine and is valid after leaving the channel. * * @param enabled Whether to enable the local video capture. true : (Default) Enable the local video capture. false : Disable the local video capture. Once the local video is disabled, the remote users cannot receive the video stream of the local user, while the local user can still receive the video streams of remote users. When set to false, this method does not require a local camera. @@ -3915,7 +3915,7 @@ export abstract class IRtcEngine { /** * Destroys the media player instance. * - * @param mediaPlayer One IMediaPlayer object. + * @param mediaPlayer IMediaPlayer object. * * @returns * ≥ 0: Success. Returns the ID of media player instance. @@ -4280,7 +4280,7 @@ export abstract class IRtcEngine { /** * Gets the volume of a specified audio effect file. * - * @param soundId The ID of the audio effect. The ID of each audio effect file is unique. + * @param soundId The ID of the audio effect. The unique ID of each audio effect file. * @param volume The playback volume. The value range is [0, 100]. The default value is 100, which represents the original volume. * * @returns @@ -5444,7 +5444,7 @@ export abstract class IRtcEngine { * For iOS devices equipped with multi-lens rear cameras, such as those featuring dual-camera (wide-angle and ultra-wide-angle) or triple-camera (wide-angle, ultra-wide-angle, and telephoto), you can call setCameraCapturerConfiguration first to set the cameraFocalLengthType as CameraFocalLengthDefault (0) (standard lens). Then, adjust the camera zoom factor to a value less than 1.0. This configuration allows you to capture video with an ultra-wide-angle perspective. * You must call this method after enableVideo. The setting result will take effect after the camera is successfully turned on, that is, after the SDK triggers the onLocalVideoStateChanged callback and returns the local video state as LocalVideoStreamStateCapturing (1). * - * @param factor The camera zoom factor. For devices that do not support ultra-wide-angle, the value ranges from 1.0 to the maximum zoom factor; for devices that support ultra-wide-angle, the value ranges from 0.5 to the maximum zoom factor. You can get the maximum zoom factor supported by the device by calling the getCameraMaxZoomFactor method. + * @param factor Camera zoom factor. For devices that do not support ultra-wide-angle, the value ranges from 1.0 to the maximum zoom factor; for devices that support ultra-wide-angle, the value ranges from 0.5 to the maximum zoom factor. You can get the maximum zoom factor supported by the device by calling the getCameraMaxZoomFactor method. * * @returns * The camera zoom factor value, if successful. @@ -5464,12 +5464,12 @@ export abstract class IRtcEngine { abstract enableFaceDetection(enabled: boolean): number; /** - * Gets the maximum zoom ratio supported by the camera. + * Get the maximum zoom ratio supported by the camera. * * This method must be called after the SDK triggers the onLocalVideoStateChanged callback and returns the local video state as LocalVideoStreamStateCapturing (1). * * @returns - * The maximum zoom factor. + * The maximum zoom ratio supported by the camera. */ abstract getCameraMaxZoomFactor(): number; @@ -6246,7 +6246,7 @@ export abstract class IRtcEngine { /** * Adds a watermark image to the local video. * - * This method adds a PNG watermark image to the local video in the live streaming. Once the watermark image is added, all the audience in the channel (CDN audience included), and the capturing device can see and capture it. The Agora SDK supports adding only one watermark image onto a local video or CDN live stream. The newly added watermark image replaces the previous one. The watermark coordinates are dependent on the settings in the setVideoEncoderConfiguration method: + * This method adds a PNG watermark image to the local video in the live streaming. Once the watermark image is added, all the audience in the channel (CDN audience included), and the capturing device can see and capture it. The Agora SDK supports adding only one watermark image onto a live video stream. The newly added watermark image replaces the previous one. The watermark coordinates are dependent on the settings in the setVideoEncoderConfiguration method: * If the orientation mode of the encoding video (OrientationMode) is fixed landscape mode or the adaptive landscape mode, the watermark uses the landscape orientation. * If the orientation mode of the encoding video (OrientationMode) is fixed portrait mode or the adaptive portrait mode, the watermark uses the portrait orientation. * When setting the watermark position, the region must be less than the dimensions set in the setVideoEncoderConfiguration method; otherwise, the watermark image will be cropped. @@ -6394,6 +6394,7 @@ export abstract class IRtcEngine { * Once registered, the user account can be used to identify the local user when the user joins the channel. After the registration is successful, the user account can identify the identity of the local user, and the user can use it to join the channel. This method is optional. If you want to join a channel using a user account, you can choose one of the following methods: * Call the registerLocalUserAccount method to register a user account, and then call the joinChannelWithUserAccount method to join a channel, which can shorten the time it takes to enter the channel. * Call the joinChannelWithUserAccount method to join a channel. + * Starting from v4.6.0, the SDK will no longer automatically map Int UID to the String userAccount used when registering a User Account. If you want to join a channel with the original String userAccount used during registration, call the joinChannelWithUserAccount method to join the channel, instead of calling joinChannel and pass in the Int UID obtained through this method * Ensure that the userAccount is unique in the channel. * To ensure smooth communication, use the same parameter type to identify the user. For example, if a user joins the channel with a UID, then ensure all the other users use the UID too. The same applies to the user account. If a user joins the channel with the Agora Web SDK, ensure that the ID of the user is set to the same parameter type. * @@ -6867,8 +6868,8 @@ export abstract class IRtcEngine { * Enables tracing the video frame rendering process. * * The SDK starts tracing the rendering status of the video frames in the channel from the moment this method is successfully called and reports information about the event through the onVideoRenderingTracingResult callback. - * The SDK automatically starts tracking the rendering events of the video from the moment that you call joinChannel to join the channel. You can call this method at an appropriate time according to the actual application scenario to customize the tracing process. - * After the local user leaves the current channel, the SDK automatically resets the time point to the next time when the user successfully joins the channel. + * If you have not called this method, the SDK tracks the rendering events of the video frames from the moment you call joinChannel to join the channel. You can call this method at an appropriate time according to the actual application scenario to set the starting position for tracking video rendering events. + * After the local user leaves the current channel, the SDK automatically tracks the video rendering events from the moment you join a channel. * * @returns * 0: Success. diff --git a/src/IAgoraRtcEngineEx.ts b/src/IAgoraRtcEngineEx.ts index e7f8f03e..2ec431c3 100644 --- a/src/IAgoraRtcEngineEx.ts +++ b/src/IAgoraRtcEngineEx.ts @@ -25,6 +25,7 @@ import { import { ChannelMediaOptions, IRtcEngine, + ImageTrackOptions, LeaveChannelOptions, StreamFallbackOptions, } from './IAgoraRtcEngine'; @@ -191,9 +192,7 @@ export abstract class IRtcEngineEx extends IRtcEngine { * The SDK will dynamically adjust the size of the corresponding video stream based on the size of the video window to save bandwidth and computing resources. The default aspect ratio of the low-quality video stream is the same as that of the high-quality video stream. According to the current aspect ratio of the high-quality video stream, the system will automatically allocate the resolution, frame rate, and bitrate of the low-quality video stream. Depending on the default behavior of the sender and the specific settings when calling setDualStreamMode, the scenarios for the receiver calling this method are as follows: * The SDK enables low-quality video stream adaptive mode (AutoSimulcastStream) on the sender side by default, meaning only the high-quality video stream is transmitted. Only the receiver with the role of the host can call this method to initiate a low-quality video stream request. Once the sender receives the request, it starts automatically sending the low-quality video stream. At this point, all users in the channel can call this method to switch to low-quality video stream subscription mode. * If the sender calls setDualStreamMode and sets mode to DisableSimulcastStream (never send low-quality video stream), then calling this method will have no effect. - * If the sender calls setDualStreamMode and sets mode to EnableSimulcastStream (always send low-quality video stream), both the host and audience receivers can call this method to switch to low-quality video stream subscription mode. - * If the publisher has already called setDualStreamModeEx and set mode to DisableSimulcastStream (never send low-quality video stream), calling this method will not take effect, you should call setDualStreamModeEx again on the sending end and adjust the settings. - * Calling this method on the receiving end of the audience role will not take effect. + * If the sender calls setDualStreamMode and sets mode to EnableSimulcastStream (always send low-quality video stream), both the host and audience receivers can call this method to switch to low-quality video stream subscription mode. If the publisher has already called setDualStreamModeEx and set mode to DisableSimulcastStream (never send low-quality video stream), calling this method will not take effect, you should call setDualStreamModeEx again on the sending end and adjust the settings. * * @param uid The user ID. * @param streamType The video stream type, see VideoStreamType. @@ -568,7 +567,7 @@ export abstract class IRtcEngineEx extends IRtcEngine { /** * Adds a watermark image to the local video. * - * This method adds a PNG watermark image to the local video in the live streaming. Once the watermark image is added, all the audience in the channel (CDN audience included), and the capturing device can see and capture it. The Agora SDK supports adding only one watermark image onto a local video or CDN live stream. The newly added watermark image replaces the previous one. The watermark coordinates are dependent on the settings in the setVideoEncoderConfigurationEx method: + * This method adds a PNG watermark image to the local video in the live streaming. Once the watermark image is added, all the audience in the channel (CDN audience included), and the capturing device can see and capture it. The Agora SDK supports adding only one watermark image onto a live video stream. The newly added watermark image replaces the previous one. The watermark coordinates are dependent on the settings in the setVideoEncoderConfigurationEx method: * If the orientation mode of the encoding video (OrientationMode) is fixed landscape mode or the adaptive landscape mode, the watermark uses the landscape orientation. * If the orientation mode of the encoding video (OrientationMode) is fixed portrait mode or the adaptive portrait mode, the watermark uses the portrait orientation. * When setting the watermark position, the region must be less than the dimensions set in the setVideoEncoderConfigurationEx method; otherwise, the watermark image will be cropped. @@ -905,8 +904,8 @@ export abstract class IRtcEngineEx extends IRtcEngine { /** * Enables tracing the video frame rendering process. * - * The SDK automatically starts tracking the rendering events of the video from the moment that you call joinChannel to join the channel. You can call this method at an appropriate time according to the actual application scenario to customize the tracing process. - * After the local user leaves the current channel, the SDK automatically resets the time point to the next time when the user successfully joins the channel. The SDK starts tracing the rendering status of the video frames in the channel from the moment this method is successfully called and reports information about the event through the onVideoRenderingTracingResult callback. + * If you have not called this method, the SDK tracks the rendering events of the video frames from the moment you call joinChannel to join the channel. You can call this method at an appropriate time according to the actual application scenario to set the starting position for tracking video rendering events. + * After the local user leaves the current channel, the SDK automatically tracks the video rendering events from the moment you join a channel. The SDK starts tracing the rendering status of the video frames in the channel from the moment this method is successfully called and reports information about the event through the onVideoRenderingTracingResult callback. * * @param connection The connection information. See RtcConnection. * @@ -946,6 +945,15 @@ export abstract class IRtcEngineEx extends IRtcEngine { length: number ): number; + /** + * @ignore + */ + abstract enableVideoImageSourceEx( + enable: boolean, + options: ImageTrackOptions, + connection: RtcConnection + ): number; + /** * Gets a video screenshot of the specified observation point using the connection ID. * diff --git a/src/impl/IAgoraRtcEngineExImpl.ts b/src/impl/IAgoraRtcEngineExImpl.ts index f454f6d2..d897b5a2 100644 --- a/src/impl/IAgoraRtcEngineExImpl.ts +++ b/src/impl/IAgoraRtcEngineExImpl.ts @@ -23,6 +23,7 @@ import { } from '../AgoraMediaBase'; import { ChannelMediaOptions, + ImageTrackOptions, LeaveChannelOptions, StreamFallbackOptions, } from '../IAgoraRtcEngine'; @@ -1634,6 +1635,40 @@ export class IRtcEngineExImpl extends IRtcEngineImpl implements IRtcEngineEx { return 'RtcEngineEx_sendAudioMetadataEx_e2bf1c4'; } + enableVideoImageSourceEx( + enable: boolean, + options: ImageTrackOptions, + connection: RtcConnection + ): number { + const apiType = this.getApiTypeFromEnableVideoImageSourceEx( + enable, + options, + connection + ); + const jsonParams = { + enable: enable, + options: options, + connection: connection, + toJSON: () => { + return { + enable: enable, + options: options, + connection: connection, + }; + }, + }; + const jsonResults = callIrisApi.call(this, apiType, jsonParams); + return jsonResults.result; + } + + protected getApiTypeFromEnableVideoImageSourceEx( + enable: boolean, + options: ImageTrackOptions, + connection: RtcConnection + ): string { + return 'RtcEngineEx_enableVideoImageSourceEx_b63f346'; + } + takeSnapshotWithConfigEx( connection: RtcConnection, uid: number, diff --git a/src/index.ts b/src/index.ts index 69237c76..79d7cd0e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,7 +36,7 @@ const instance = new RtcEngineExInternal(); * Currently, the Agora RTC SDK v4.x supports creating only one IRtcEngine object for each app. * * @returns - * One IRtcEngine object. + * IRtcEngine object. */ export function createAgoraRtcEngine(): IRtcEngine { return instance; From cb55679bc8e63a217954981f7d397776d07a0f08 Mon Sep 17 00:00:00 2001 From: sda_rob Date: Tue, 30 Sep 2025 07:21:29 +0000 Subject: [PATCH 06/25] chore: release 4.5.2-build.2-rc.1 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eab98f28..a5e64182 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ +## [4.5.2-build.2-rc.1](https://github.com/AgoraIO-Extensions/react-native-agora/compare/v4.5.2-build.140-rc.2...v4.5.2-build.2-rc.1) (2025-09-30) + + +### Bug Fixes + +* script ([#885](https://github.com/AgoraIO-Extensions/react-native-agora/issues/885)) ([4dbdffd](https://github.com/AgoraIO-Extensions/react-native-agora/commit/4dbdffd7682ddac1e8541f61a99866d4ab5db75d)) + ## [4.5.2-build.140-rc.2](https://github.com/AgoraIO-Extensions/react-native-agora/compare/v4.5.2-build.140-rc.1...v4.5.2-build.140-rc.2) (2025-07-07) diff --git a/package.json b/package.json index 69f04d1e..e34ddc42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-agora", - "version": "4.5.2-build.140-rc.2", + "version": "4.5.2-build.2-rc.1", "description": "Agora RTC SDK For React Native", "main": "lib/commonjs/index", "module": "lib/module/index", From abb7a85274b694148a87a9ed1b69fe5373861622 Mon Sep 17 00:00:00 2001 From: gxz Date: Tue, 30 Sep 2025 15:52:53 +0800 Subject: [PATCH 07/25] chore: change to deploy-pages@v4 --- .github/workflows/typedoc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/typedoc.yml b/.github/workflows/typedoc.yml index 7091ce5c..ee6e22b2 100644 --- a/.github/workflows/typedoc.yml +++ b/.github/workflows/typedoc.yml @@ -63,4 +63,4 @@ jobs: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v4 From e58fe1ffc95147817f33b1145c4abe3743556ed0 Mon Sep 17 00:00:00 2001 From: guoxianzhe <53285945+guoxianzhe@users.noreply.github.com> Date: Tue, 30 Sep 2025 16:11:56 +0800 Subject: [PATCH 08/25] ci: make some print info (#909) * chore: optimize * chore: optimize --- .github/workflows/publish.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 16422536..5bb7b0e7 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -42,3 +42,8 @@ jobs: git config --global user.email "${{ secrets.GIT_EMAIL }}" git config --global user.name "${{ secrets.GIT_USERNAME }}" yarn release ${{ inputs.increment }} --ci --npm.allowSameVersion + + - name: print publish info + run: | + echo "[publish info][tag]: https://github.com/AgoraIO-Extensions/react-native-agora/releases/tag/v${{ inputs.increment }}" + echo "[publish info][url]: https://www.npmjs.com/package/react-native-agora/v/${{ inputs.increment }}" From aaf49c3b8004b03bfada8a752cc5a6011b15a173 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 3 Nov 2025 17:33:22 +0800 Subject: [PATCH 09/25] chore: change publish --- .github/workflows/publish.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5bb7b0e7..87e529e1 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -6,13 +6,17 @@ on: increment: description: 'Increment "major", "minor", "patch", or "pre*" version; or specify version [default: "patch"]' required: true - default: 'patch' + default: "patch" type: string dry-run: - description: 'Do not touch or write anything, but show the commands' + description: "Do not touch or write anything, but show the commands" default: true type: boolean +permissions: + id-token: write # Required for OIDC + contents: read + jobs: release-it: runs-on: ubuntu-latest @@ -27,9 +31,14 @@ jobs: - name: Setup uses: ./.github/actions/setup - - name: Setup NPM auth token + - name: Update Node.js + uses: actions/setup-node@v3 + with: + node-version: 23.7.0 + + - name: Update NPM run: | - npm set "//registry.npmjs.org/:_authToken" ${{ secrets.NPM_TOKEN }} + npm install -g npm@11.5.1 - name: Dry Run Release if: ${{ inputs.dry-run }} From f5bdea071d9251d9e8b233f0c4a0aeaeb169c6dc Mon Sep 17 00:00:00 2001 From: guoxianzhe <53285945+guoxianzhe@users.noreply.github.com> Date: Mon, 3 Nov 2025 17:38:25 +0800 Subject: [PATCH 10/25] feat: expo example (#886) --- .github/actions/setup/action.yml | 2 +- .github/workflows/build.yml | 79 +- .github/workflows/ci.yml | 69 +- .github/workflows/dep.yml | 4 +- .gitignore | 4 +- .yarnrc.yml | 1 - examples/expo/.detoxrc.js | 87 + examples/expo/.gitignore | 40 + {example => examples/expo}/.node-version | 0 {example => examples/expo}/.ruby-version | 0 {example => examples/expo}/Gemfile | 0 {example => examples/expo}/Gemfile.lock | 0 examples/expo/README.md | 361 + examples/expo/android/.gitignore | 16 + examples/expo/android/app/build.gradle | 185 + .../expo}/android/app/debug.keystore | Bin examples/expo/android/app/proguard-rules.pro | 14 + .../DetoxTest.java | 29 + .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 31 + .../app/src/main/assets/agora-logo.png | Bin .../android/app/src/main/assets/dang.mp3 | Bin .../android/app/src/main/assets/ding.mp3 | Bin .../android/app/src/main/assets/effect.mp3 | Bin .../AgoraForegroundService.kt | 69 + .../AgoraServiceManager.kt | 32 + .../AgoraServicePackage.kt | 16 + .../MainActivity.kt | 61 + .../MainApplication.kt | 58 + .../VideoRawDataNativeModule.kt | 100 + .../VideoRawDataNativeModulePackage.kt | 20 + .../res/drawable-hdpi/splashscreen_logo.png | Bin 0 -> 20754 bytes .../res/drawable-mdpi/splashscreen_logo.png | Bin 0 -> 12863 bytes .../res/drawable-xhdpi/splashscreen_logo.png | Bin 0 -> 29081 bytes .../res/drawable-xxhdpi/splashscreen_logo.png | Bin 0 -> 47123 bytes .../drawable-xxxhdpi/splashscreen_logo.png | Bin 0 -> 66529 bytes .../res/drawable/ic_launcher_background.xml | 6 + .../res/drawable/rn_edit_text_material.xml | 37 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 3300 bytes .../mipmap-hdpi/ic_launcher_foreground.webp | Bin 0 -> 8031 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 4103 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 2048 bytes .../mipmap-mdpi/ic_launcher_foreground.webp | Bin 0 -> 5079 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 2613 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 4535 bytes .../mipmap-xhdpi/ic_launcher_foreground.webp | Bin 0 -> 11145 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 5673 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 7345 bytes .../mipmap-xxhdpi/ic_launcher_foreground.webp | Bin 0 -> 18064 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 9091 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 10108 bytes .../ic_launcher_foreground.webp | Bin 0 -> 25030 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 12469 bytes .../app/src/main/res/values-night/colors.xml | 1 + .../app/src/main/res/values/colors.xml | 6 + .../app/src/main/res/values/strings.xml | 5 + .../app/src/main/res/values/styles.xml | 10 + .../main/res/xml/network_security_config.xml | 0 examples/expo/android/build.gradle | 64 + examples/expo/android/gradle.properties | 61 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + examples/expo/android/gradlew | 251 + .../expo}/android/gradlew.bat | 0 examples/expo/android/settings.gradle | 39 + examples/expo/app.json | 62 + examples/expo/app/_layout.tsx | 99 + .../AudioCallRoute/AudioCallRoute.tsx | 162 + .../advanced/AudioMixing/AudioMixing.tsx | 270 + .../advanced/AudioSpectrum/AudioSpectrum.tsx | 226 + .../advanced/BeautyEffect/BeautyEffect.tsx | 256 + .../ChannelMediaRelay/ChannelMediaRelay.tsx | 246 + .../ContentInspect/ContentInspect.tsx | 237 + .../DirectCdnStreaming/DirectCdnStreaming.tsx | 382 + .../advanced/Encryption/Encryption.tsx | 210 + .../examples/advanced/Extension/Extension.tsx | 258 + .../JoinMultipleChannel.tsx | 498 + .../LocalSpatialAudioEngine.tsx | 313 + .../LocalVideoTranscoder.tsx | 430 + .../advanced/MediaPlayer/MediaPlayer.tsx | 391 + .../advanced/MediaRecorder/MediaRecorder.tsx | 312 + .../MusicContentCenter/MusicContentCenter.tsx | 540 + .../PictureInPicture/PictureInPicture.md | 0 .../PictureInPicture/PictureInPicture.tsx | 688 + .../advanced/PlayEffect/PlayEffect.tsx | 299 + .../ProcessVideoRawData.tsx | 161 + .../PushVideoFrame/PushVideoFrame.tsx | 198 + .../advanced/RTMPStreaming/RTMPStreaming.tsx | 541 + .../advanced/RhythmPlayer/RhythmPlayer.tsx | 262 + .../advanced/ScreenShare/ScreenShare.tsx | 590 + .../advanced/SendMetadata/SendMetadata.tsx | 183 + .../SendMultiVideoStream.tsx | 364 + .../advanced/SpatialAudio/SpatialAudio.tsx | 281 + .../advanced/StreamMessage/StreamMessage.tsx | 255 + .../advanced/TakeSnapshot/TakeSnapshot.tsx | 218 + .../VideoEncoderConfiguration.tsx | 281 + .../VirtualBackground/VirtualBackground.tsx | 240 + .../advanced/VoiceChanger/VoiceChanger.tsx | 440 + examples/expo/app/examples/advanced/index.ts | 158 + .../JoinChannelAudio/JoinChannelAudio.tsx | 569 + .../JoinChannelVideo/JoinChannelVideo.tsx | 443 + .../examples/basic/StringUid/StringUid.tsx | 231 + examples/expo/app/examples/basic/index.ts | 23 + .../examples/hook/AudioMixing/AudioMixing.tsx | 252 + .../JoinChannelAudio/JoinChannelAudio.tsx | 391 + .../JoinChannelVideo/JoinChannelVideo.tsx | 226 + .../JoinMultipleChannel.tsx | 382 + .../examples/hook/ScreenShare/ScreenShare.tsx | 531 + .../app/examples/hook/StringUid/StringUid.tsx | 140 + .../hook/TakeSnapshot/TakeSnapshot.tsx | 207 + .../VirtualBackground/VirtualBackground.tsx | 209 + .../examples/hook/hooks/useInitRtcEngine.tsx | 206 + .../examples/hook/hooks/useResetState.tsx | 0 examples/expo/app/examples/hook/index.ts | 47 + examples/expo/app/index.tsx | 100 + examples/expo/assets/adaptive-icon.png | Bin 0 -> 17547 bytes examples/expo/assets/favicon.png | Bin 0 -> 1466 bytes examples/expo/assets/icon.png | Bin 0 -> 22380 bytes examples/expo/assets/splash-icon.png | Bin 0 -> 17547 bytes examples/expo/babel.config.js | 21 + {example => examples/expo}/e2e/jest.config.js | 0 examples/expo/e2e/starter.test.js | 31 + examples/expo/ios/.gitignore | 30 + {example => examples/expo}/ios/.xcode.env | 0 .../NativeModules/VideoRawDataNativeModule.h | 0 .../NativeModules/VideoRawDataNativeModule.m | 0 examples/expo/ios/Podfile | 70 + examples/expo/ios/Podfile.lock | 2805 ++++ examples/expo/ios/Podfile.properties.json | 6 + .../expo}/ios/Resources/agora-logo.png | Bin .../expo}/ios/Resources/dang.mp3 | Bin .../expo}/ios/Resources/ding.mp3 | Bin .../expo}/ios/Resources/effect.mp3 | Bin .../expo}/ios/ScreenShare/Info.plist | 0 examples/expo/ios/ScreenShare/SampleHandler.h | 12 + examples/expo/ios/ScreenShare/SampleHandler.m | 47 + .../project.pbxproj | 895 ++ .../reactnativeagoraexampleexpo.xcscheme | 88 + .../contents.xcworkspacedata | 10 + .../xcshareddata/WorkspaceSettings.xcsettings | 5 + .../AppDelegate.swift | 70 + .../App-Icon-1024x1024@1x.png | Bin 0 -> 59468 bytes .../AppIcon.appiconset/Contents.json | 14 + .../Images.xcassets/Contents.json | 6 + .../Contents.json | 20 + .../SplashScreenLogo.imageset/Contents.json | 23 + .../SplashScreenLogo.imageset/image.png | Bin 0 -> 60870 bytes .../SplashScreenLogo.imageset/image@2x.png | Bin 0 -> 60870 bytes .../SplashScreenLogo.imageset/image@3x.png | Bin 0 -> 60870 bytes .../reactnativeagoraexampleexpo/Info.plist | 98 + .../PrivacyInfo.xcprivacy | 48 + .../SplashScreen.storyboard | 44 + .../Supporting/Expo.plist | 12 + ...ctnativeagoraexampleexpo-Bridging-Header.h | 3 + .../reactnativeagoraexampleexpo.entitlements | 5 + {example => examples/expo}/jest.config.js | 0 examples/expo/metro.config.js | 30 + examples/expo/package.json | 54 + examples/expo/react-native.config.js | 9 + .../expo/src/components/BaseComponent.tsx | 313 + examples/expo/src/components/LogSink.tsx | 61 + .../src/components/hook/BaseComponent.tsx | 64 + .../src/components/hook/BaseRenderChannel.tsx | 39 + .../src/components/hook/BaseRenderUsers.tsx | 72 + .../expo}/src/components/ui/index.tsx | 0 .../expo/src/config}/VoiceChangerConfig.tsx | 0 .../expo}/src/config/agora.config.ts | 2 +- examples/expo/src/context/pip.tsx | 41 + .../expo}/src/utils/AgoraServiceHelper.ts | 0 {example => examples/expo}/src/utils/index.ts | 0 examples/expo/src/utils/log.ts | 50 + .../expo}/src/utils/permissions.ts | 0 examples/expo/tsconfig.json | 9 + {example => examples/legacy}/.bundle/config | 0 {example => examples/legacy}/.detoxrc.js | 0 examples/legacy/.node-version | 1 + examples/legacy/.ruby-version | 1 + {example => examples/legacy}/.watchmanconfig | 0 examples/legacy/Gemfile | 10 + examples/legacy/Gemfile.lock | 101 + {example => examples/legacy}/README.md | 0 .../legacy}/android/app/build.gradle | 0 examples/legacy/android/app/debug.keystore | Bin 0 -> 2257 bytes .../legacy}/android/app/proguard-rules.pro | 0 .../java/com/agorartcngexample/DetoxTest.java | 0 .../android/app/src/debug/AndroidManifest.xml | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../app/src/main/assets/agora-logo.png | Bin 0 -> 1188 bytes .../android/app/src/main/assets/dang.mp3 | Bin 0 -> 20292 bytes .../android/app/src/main/assets/ding.mp3 | Bin 0 -> 20292 bytes .../android/app/src/main/assets/effect.mp3 | Bin 0 -> 105369 bytes .../AgoraForegroundService.kt | 0 .../agorartcngexample/AgoraServiceManager.kt | 0 .../agorartcngexample/AgoraServicePackage.kt | 0 .../com/agorartcngexample/MainActivity.kt | 0 .../com/agorartcngexample/MainApplication.kt | 0 .../VideoRawDataNativeModule.kt | 0 .../VideoRawDataNativeModulePackage.kt | 0 .../res/drawable/rn_edit_text_material.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../res/mipmap-hdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../res/mipmap-mdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../res/mipmap-xhdpi/ic_launcher_round.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin .../app/src/main/res/values/strings.xml | 0 .../app/src/main/res/values/styles.xml | 0 .../main/res/xml/network_security_config.xml | 7 + .../agorartcngexample/ReactNativeFlipper.java | 0 .../legacy}/android/build.gradle | 0 .../legacy}/android/gradle.properties | 0 .../android/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 {example => examples/legacy}/android/gradlew | 0 examples/legacy/android/gradlew.bat | 94 + .../legacy}/android/settings.gradle | 0 {example => examples/legacy}/app.json | 0 {example => examples/legacy}/babel.config.js | 4 +- examples/legacy/e2e/jest.config.js | 12 + .../legacy}/e2e/starter.test.js | 0 {example => examples/legacy}/example.jpg | Bin {example => examples/legacy}/index.js | 0 examples/legacy/ios/.xcode.env | 11 + .../ios/AgoraRtcNgExample-Bridging-Header.h | 0 .../project.pbxproj | 0 .../xcschemes/AgoraRtcNgExample.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../ios/AgoraRtcNgExample/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../Images.xcassets/Contents.json | 0 .../legacy}/ios/AgoraRtcNgExample/Info.plist | 0 .../AgoraRtcNgExample/LaunchScreen.storyboard | 0 .../AgoraRtcNgExample/PrivacyInfo.xcprivacy | 0 .../AgoraRtcNgExampleTests.m | 0 .../ios/AgoraRtcNgExampleTests/Info.plist | 0 {example => examples/legacy}/ios/File.swift | 0 .../NativeModules/VideoRawDataNativeModule.h | 13 + .../NativeModules/VideoRawDataNativeModule.m | 56 + {example => examples/legacy}/ios/Podfile | 0 {example => examples/legacy}/ios/Podfile.lock | 48 +- examples/legacy/ios/Resources/agora-logo.png | Bin 0 -> 1188 bytes examples/legacy/ios/Resources/dang.mp3 | Bin 0 -> 20292 bytes examples/legacy/ios/Resources/ding.mp3 | Bin 0 -> 20292 bytes examples/legacy/ios/Resources/effect.mp3 | Bin 0 -> 105369 bytes examples/legacy/ios/ScreenShare/Info.plist | 15 + .../legacy}/ios/ScreenShare/SampleHandler.h | 0 .../legacy}/ios/ScreenShare/SampleHandler.m | 0 examples/legacy/jest.config.js | 3 + {example => examples/legacy}/metro.config.js | 4 +- {example => examples/legacy}/package.json | 4 +- .../legacy}/react-native.config.js | 4 +- {example => examples/legacy}/src/App.tsx | 0 .../legacy}/src/components/BaseComponent.tsx | 0 .../legacy}/src/components/LogSink.tsx | 0 examples/legacy/src/components/ui/index.tsx | 327 + examples/legacy/src/config/agora.config.ts | 19 + .../legacy}/src/context/pip.tsx | 0 .../AudioCallRoute/AudioCallRoute.tsx | 0 .../advanced/AudioMixing/AudioMixing.tsx | 0 .../advanced/AudioSpectrum/AudioSpectrum.tsx | 0 .../advanced/BeautyEffect/BeautyEffect.tsx | 0 .../ChannelMediaRelay/ChannelMediaRelay.tsx | 0 .../ContentInspect/ContentInspect.tsx | 0 .../DirectCdnStreaming/DirectCdnStreaming.tsx | 0 .../advanced/Encryption/Encryption.tsx | 0 .../examples/advanced/Extension/Extension.tsx | 0 .../JoinMultipleChannel.tsx | 0 .../LocalSpatialAudioEngine.tsx | 0 .../LocalVideoTranscoder.tsx | 0 .../advanced/MediaPlayer/MediaPlayer.tsx | 0 .../advanced/MediaRecorder/MediaRecorder.tsx | 0 .../MusicContentCenter/MusicContentCenter.tsx | 0 .../PictureInPicture/PictureInPicture.md | 109 + .../PictureInPicture/PictureInPicture.tsx | 0 .../advanced/PlayEffect/PlayEffect.tsx | 0 .../ProcessVideoRawData.tsx | 0 .../PushVideoFrame/PushVideoFrame.tsx | 0 .../advanced/RTMPStreaming/RTMPStreaming.tsx | 0 .../advanced/RhythmPlayer/RhythmPlayer.tsx | 0 .../advanced/ScreenShare/ScreenShare.tsx | 0 .../advanced/SendMetadata/SendMetadata.tsx | 0 .../SendMultiVideoStream.tsx | 0 .../advanced/SpatialAudio/SpatialAudio.tsx | 0 .../advanced/StreamMessage/StreamMessage.tsx | 0 .../advanced/TakeSnapshot/TakeSnapshot.tsx | 0 .../VideoEncoderConfiguration.tsx | 0 .../VirtualBackground/VirtualBackground.tsx | 0 .../advanced/VoiceChanger/VoiceChanger.tsx | 0 .../VoiceChanger/VoiceChangerConfig.tsx | 79 + .../legacy}/src/examples/advanced/index.ts | 0 .../JoinChannelAudio/JoinChannelAudio.tsx | 0 .../JoinChannelVideo/JoinChannelVideo.tsx | 0 .../examples/basic/StringUid/StringUid.tsx | 0 .../legacy}/src/examples/basic/index.ts | 0 .../examples/hook/AudioMixing/AudioMixing.tsx | 0 .../JoinChannelAudio/JoinChannelAudio.tsx | 0 .../JoinChannelVideo/JoinChannelVideo.tsx | 0 .../JoinMultipleChannel.tsx | 0 .../examples/hook/ScreenShare/ScreenShare.tsx | 0 .../src/examples/hook/StringUid/StringUid.tsx | 0 .../hook/TakeSnapshot/TakeSnapshot.tsx | 0 .../VirtualBackground/VirtualBackground.tsx | 0 .../hook/components/BaseComponent.tsx | 0 .../hook/components/BaseRenderChannel.tsx | 0 .../hook/components/BaseRenderUsers.tsx | 0 .../examples/hook/hooks/useInitRtcEngine.tsx | 0 .../src/examples/hook/hooks/useResetState.tsx | 18 + .../legacy}/src/examples/hook/index.ts | 0 .../legacy/src/utils/AgoraServiceHelper.ts | 31 + examples/legacy/src/utils/index.ts | 59 + {example => examples/legacy}/src/utils/log.ts | 0 examples/legacy/src/utils/permissions.ts | 42 + package.json | 21 +- scripts/dep.sh | 4 +- scripts/mirror.sh | 4 +- scripts/pod-install.cjs | 47 - scripts/publishCN/rewrite-example.sh | 4 +- .../templates/impl/file_content.mustache | 6 +- src/Utils.ts | 16 + src/__tests__/AgoraH265Transcoder.test.ts | 4 +- src/__tests__/MediaEngineInternal.test.ts | 4 +- src/__tests__/MediaPlayerInternal.test.ts | 4 +- src/__tests__/MediaRecorderInternal.test.ts | 4 +- .../MusicContentCenterInternal.test.ts | 4 +- src/__tests__/RtcEngineExInternal.test.ts | 5 +- src/impl/AgoraMediaBaseImpl.ts | 4 +- src/impl/IAgoraH265TranscoderImpl.ts | 4 +- src/impl/IAgoraMediaEngineImpl.ts | 3 +- src/impl/IAgoraMediaPlayerImpl.ts | 3 +- src/impl/IAgoraMediaRecorderImpl.ts | 3 +- src/impl/IAgoraMusicContentCenterImpl.ts | 3 +- src/impl/IAgoraRtcEngineExImpl.ts | 3 +- src/impl/IAgoraRtcEngineImpl.ts | 3 +- src/impl/IAgoraSpatialAudioImpl.ts | 3 +- src/impl/IAudioDeviceManagerImpl.ts | 3 +- src/index.ts | 16 +- src/internal/AgoraH265TranscoderInternal.ts | 6 +- src/internal/AgoraPipInternal.ts | 6 +- src/internal/IrisApiEngine.ts | 266 +- src/internal/MediaEngineInternal.ts | 6 +- src/internal/MediaPlayerInternal.ts | 6 +- src/internal/MediaRecorderInternal.ts | 6 +- src/internal/MusicContentCenterInternal.ts | 6 +- src/internal/RtcEngineExInternal.ts | 8 +- src/internal/call.ts | 140 + src/internal/event.ts | 100 + tsconfig.build.json | 2 +- yarn.lock | 10942 +++++++++------- 356 files changed, 28183 insertions(+), 5455 deletions(-) create mode 100644 examples/expo/.detoxrc.js create mode 100644 examples/expo/.gitignore rename {example => examples/expo}/.node-version (100%) rename {example => examples/expo}/.ruby-version (100%) rename {example => examples/expo}/Gemfile (100%) rename {example => examples/expo}/Gemfile.lock (100%) create mode 100644 examples/expo/README.md create mode 100644 examples/expo/android/.gitignore create mode 100644 examples/expo/android/app/build.gradle rename {example => examples/expo}/android/app/debug.keystore (100%) create mode 100644 examples/expo/android/app/proguard-rules.pro create mode 100644 examples/expo/android/app/src/androidTest/java/com/reactnativeagoraexampleexpo/DetoxTest.java create mode 100644 examples/expo/android/app/src/debug/AndroidManifest.xml create mode 100644 examples/expo/android/app/src/main/AndroidManifest.xml rename {example => examples/expo}/android/app/src/main/assets/agora-logo.png (100%) rename {example => examples/expo}/android/app/src/main/assets/dang.mp3 (100%) rename {example => examples/expo}/android/app/src/main/assets/ding.mp3 (100%) rename {example => examples/expo}/android/app/src/main/assets/effect.mp3 (100%) create mode 100644 examples/expo/android/app/src/main/java/com/reactnativeagoraexampleexpo/AgoraForegroundService.kt create mode 100644 examples/expo/android/app/src/main/java/com/reactnativeagoraexampleexpo/AgoraServiceManager.kt create mode 100644 examples/expo/android/app/src/main/java/com/reactnativeagoraexampleexpo/AgoraServicePackage.kt create mode 100644 examples/expo/android/app/src/main/java/com/reactnativeagoraexampleexpo/MainActivity.kt create mode 100644 examples/expo/android/app/src/main/java/com/reactnativeagoraexampleexpo/MainApplication.kt create mode 100644 examples/expo/android/app/src/main/java/com/reactnativeagoraexampleexpo/VideoRawDataNativeModule.kt create mode 100644 examples/expo/android/app/src/main/java/com/reactnativeagoraexampleexpo/VideoRawDataNativeModulePackage.kt create mode 100644 examples/expo/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png create mode 100644 examples/expo/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png create mode 100644 examples/expo/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png create mode 100644 examples/expo/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png create mode 100644 examples/expo/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png create mode 100644 examples/expo/android/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 examples/expo/android/app/src/main/res/drawable/rn_edit_text_material.xml create mode 100644 examples/expo/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 examples/expo/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 examples/expo/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp create mode 100644 examples/expo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 examples/expo/android/app/src/main/res/values-night/colors.xml create mode 100644 examples/expo/android/app/src/main/res/values/colors.xml create mode 100644 examples/expo/android/app/src/main/res/values/strings.xml create mode 100644 examples/expo/android/app/src/main/res/values/styles.xml rename {example => examples/expo}/android/app/src/main/res/xml/network_security_config.xml (100%) create mode 100644 examples/expo/android/build.gradle create mode 100644 examples/expo/android/gradle.properties create mode 100644 examples/expo/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/expo/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/expo/android/gradlew rename {example => examples/expo}/android/gradlew.bat (100%) create mode 100644 examples/expo/android/settings.gradle create mode 100644 examples/expo/app.json create mode 100644 examples/expo/app/_layout.tsx create mode 100644 examples/expo/app/examples/advanced/AudioCallRoute/AudioCallRoute.tsx create mode 100644 examples/expo/app/examples/advanced/AudioMixing/AudioMixing.tsx create mode 100644 examples/expo/app/examples/advanced/AudioSpectrum/AudioSpectrum.tsx create mode 100644 examples/expo/app/examples/advanced/BeautyEffect/BeautyEffect.tsx create mode 100644 examples/expo/app/examples/advanced/ChannelMediaRelay/ChannelMediaRelay.tsx create mode 100644 examples/expo/app/examples/advanced/ContentInspect/ContentInspect.tsx create mode 100644 examples/expo/app/examples/advanced/DirectCdnStreaming/DirectCdnStreaming.tsx create mode 100644 examples/expo/app/examples/advanced/Encryption/Encryption.tsx create mode 100644 examples/expo/app/examples/advanced/Extension/Extension.tsx create mode 100644 examples/expo/app/examples/advanced/JoinMultipleChannel/JoinMultipleChannel.tsx create mode 100644 examples/expo/app/examples/advanced/LocalSpatialAudioEngine/LocalSpatialAudioEngine.tsx create mode 100644 examples/expo/app/examples/advanced/LocalVideoTranscoder/LocalVideoTranscoder.tsx create mode 100644 examples/expo/app/examples/advanced/MediaPlayer/MediaPlayer.tsx create mode 100644 examples/expo/app/examples/advanced/MediaRecorder/MediaRecorder.tsx create mode 100644 examples/expo/app/examples/advanced/MusicContentCenter/MusicContentCenter.tsx rename {example/src => examples/expo/app}/examples/advanced/PictureInPicture/PictureInPicture.md (100%) create mode 100644 examples/expo/app/examples/advanced/PictureInPicture/PictureInPicture.tsx create mode 100644 examples/expo/app/examples/advanced/PlayEffect/PlayEffect.tsx create mode 100644 examples/expo/app/examples/advanced/ProcessVideoRawData/ProcessVideoRawData.tsx create mode 100644 examples/expo/app/examples/advanced/PushVideoFrame/PushVideoFrame.tsx create mode 100644 examples/expo/app/examples/advanced/RTMPStreaming/RTMPStreaming.tsx create mode 100644 examples/expo/app/examples/advanced/RhythmPlayer/RhythmPlayer.tsx create mode 100644 examples/expo/app/examples/advanced/ScreenShare/ScreenShare.tsx create mode 100644 examples/expo/app/examples/advanced/SendMetadata/SendMetadata.tsx create mode 100644 examples/expo/app/examples/advanced/SendMultiVideoStream/SendMultiVideoStream.tsx create mode 100644 examples/expo/app/examples/advanced/SpatialAudio/SpatialAudio.tsx create mode 100644 examples/expo/app/examples/advanced/StreamMessage/StreamMessage.tsx create mode 100644 examples/expo/app/examples/advanced/TakeSnapshot/TakeSnapshot.tsx create mode 100644 examples/expo/app/examples/advanced/VideoEncoderConfiguration/VideoEncoderConfiguration.tsx create mode 100644 examples/expo/app/examples/advanced/VirtualBackground/VirtualBackground.tsx create mode 100644 examples/expo/app/examples/advanced/VoiceChanger/VoiceChanger.tsx create mode 100644 examples/expo/app/examples/advanced/index.ts create mode 100644 examples/expo/app/examples/basic/JoinChannelAudio/JoinChannelAudio.tsx create mode 100644 examples/expo/app/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx create mode 100644 examples/expo/app/examples/basic/StringUid/StringUid.tsx create mode 100644 examples/expo/app/examples/basic/index.ts create mode 100644 examples/expo/app/examples/hook/AudioMixing/AudioMixing.tsx create mode 100644 examples/expo/app/examples/hook/JoinChannelAudio/JoinChannelAudio.tsx create mode 100644 examples/expo/app/examples/hook/JoinChannelVideo/JoinChannelVideo.tsx create mode 100644 examples/expo/app/examples/hook/JoinMultipleChannel/JoinMultipleChannel.tsx create mode 100644 examples/expo/app/examples/hook/ScreenShare/ScreenShare.tsx create mode 100644 examples/expo/app/examples/hook/StringUid/StringUid.tsx create mode 100644 examples/expo/app/examples/hook/TakeSnapshot/TakeSnapshot.tsx create mode 100644 examples/expo/app/examples/hook/VirtualBackground/VirtualBackground.tsx create mode 100644 examples/expo/app/examples/hook/hooks/useInitRtcEngine.tsx rename {example/src => examples/expo/app}/examples/hook/hooks/useResetState.tsx (100%) create mode 100644 examples/expo/app/examples/hook/index.ts create mode 100644 examples/expo/app/index.tsx create mode 100644 examples/expo/assets/adaptive-icon.png create mode 100644 examples/expo/assets/favicon.png create mode 100644 examples/expo/assets/icon.png create mode 100644 examples/expo/assets/splash-icon.png create mode 100644 examples/expo/babel.config.js rename {example => examples/expo}/e2e/jest.config.js (100%) create mode 100644 examples/expo/e2e/starter.test.js create mode 100644 examples/expo/ios/.gitignore rename {example => examples/expo}/ios/.xcode.env (100%) rename {example => examples/expo}/ios/NativeModules/VideoRawDataNativeModule.h (100%) rename {example => examples/expo}/ios/NativeModules/VideoRawDataNativeModule.m (100%) create mode 100644 examples/expo/ios/Podfile create mode 100644 examples/expo/ios/Podfile.lock create mode 100644 examples/expo/ios/Podfile.properties.json rename {example => examples/expo}/ios/Resources/agora-logo.png (100%) rename {example => examples/expo}/ios/Resources/dang.mp3 (100%) rename {example => examples/expo}/ios/Resources/ding.mp3 (100%) rename {example => examples/expo}/ios/Resources/effect.mp3 (100%) rename {example => examples/expo}/ios/ScreenShare/Info.plist (100%) create mode 100644 examples/expo/ios/ScreenShare/SampleHandler.h create mode 100644 examples/expo/ios/ScreenShare/SampleHandler.m create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo.xcodeproj/project.pbxproj create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo.xcodeproj/xcshareddata/xcschemes/reactnativeagoraexampleexpo.xcscheme create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo.xcworkspace/contents.xcworkspacedata create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/AppDelegate.swift create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/Images.xcassets/Contents.json create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/Images.xcassets/SplashScreenBackground.colorset/Contents.json create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/Images.xcassets/SplashScreenLogo.imageset/Contents.json create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/Images.xcassets/SplashScreenLogo.imageset/image.png create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/Images.xcassets/SplashScreenLogo.imageset/image@2x.png create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/Images.xcassets/SplashScreenLogo.imageset/image@3x.png create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/Info.plist create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/PrivacyInfo.xcprivacy create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/SplashScreen.storyboard create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/Supporting/Expo.plist create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/reactnativeagoraexampleexpo-Bridging-Header.h create mode 100644 examples/expo/ios/reactnativeagoraexampleexpo/reactnativeagoraexampleexpo.entitlements rename {example => examples/expo}/jest.config.js (100%) create mode 100644 examples/expo/metro.config.js create mode 100644 examples/expo/package.json create mode 100644 examples/expo/react-native.config.js create mode 100644 examples/expo/src/components/BaseComponent.tsx create mode 100644 examples/expo/src/components/LogSink.tsx create mode 100644 examples/expo/src/components/hook/BaseComponent.tsx create mode 100644 examples/expo/src/components/hook/BaseRenderChannel.tsx create mode 100644 examples/expo/src/components/hook/BaseRenderUsers.tsx rename {example => examples/expo}/src/components/ui/index.tsx (100%) rename {example/src/examples/advanced/VoiceChanger => examples/expo/src/config}/VoiceChangerConfig.tsx (100%) rename {example => examples/expo}/src/config/agora.config.ts (89%) create mode 100644 examples/expo/src/context/pip.tsx rename {example => examples/expo}/src/utils/AgoraServiceHelper.ts (100%) rename {example => examples/expo}/src/utils/index.ts (100%) create mode 100644 examples/expo/src/utils/log.ts rename {example => examples/expo}/src/utils/permissions.ts (100%) create mode 100644 examples/expo/tsconfig.json rename {example => examples/legacy}/.bundle/config (100%) rename {example => examples/legacy}/.detoxrc.js (100%) create mode 100644 examples/legacy/.node-version create mode 100644 examples/legacy/.ruby-version rename {example => examples/legacy}/.watchmanconfig (100%) create mode 100644 examples/legacy/Gemfile create mode 100644 examples/legacy/Gemfile.lock rename {example => examples/legacy}/README.md (100%) rename {example => examples/legacy}/android/app/build.gradle (100%) create mode 100644 examples/legacy/android/app/debug.keystore rename {example => examples/legacy}/android/app/proguard-rules.pro (100%) rename {example => examples/legacy}/android/app/src/androidTest/java/com/agorartcngexample/DetoxTest.java (100%) rename {example => examples/legacy}/android/app/src/debug/AndroidManifest.xml (100%) rename {example => examples/legacy}/android/app/src/main/AndroidManifest.xml (100%) create mode 100644 examples/legacy/android/app/src/main/assets/agora-logo.png create mode 100644 examples/legacy/android/app/src/main/assets/dang.mp3 create mode 100644 examples/legacy/android/app/src/main/assets/ding.mp3 create mode 100644 examples/legacy/android/app/src/main/assets/effect.mp3 rename {example => examples/legacy}/android/app/src/main/java/com/agorartcngexample/AgoraForegroundService.kt (100%) rename {example => examples/legacy}/android/app/src/main/java/com/agorartcngexample/AgoraServiceManager.kt (100%) rename {example => examples/legacy}/android/app/src/main/java/com/agorartcngexample/AgoraServicePackage.kt (100%) rename {example => examples/legacy}/android/app/src/main/java/com/agorartcngexample/MainActivity.kt (100%) rename {example => examples/legacy}/android/app/src/main/java/com/agorartcngexample/MainApplication.kt (100%) rename {example => examples/legacy}/android/app/src/main/java/com/agorartcngexample/VideoRawDataNativeModule.kt (100%) rename {example => examples/legacy}/android/app/src/main/java/com/agorartcngexample/VideoRawDataNativeModulePackage.kt (100%) rename {example => examples/legacy}/android/app/src/main/res/drawable/rn_edit_text_material.xml (100%) rename {example => examples/legacy}/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename {example => examples/legacy}/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png (100%) rename {example => examples/legacy}/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename {example => examples/legacy}/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png (100%) rename {example => examples/legacy}/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename {example => examples/legacy}/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png (100%) rename {example => examples/legacy}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {example => examples/legacy}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png (100%) rename {example => examples/legacy}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {example => examples/legacy}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png (100%) rename {example => examples/legacy}/android/app/src/main/res/values/strings.xml (100%) rename {example => examples/legacy}/android/app/src/main/res/values/styles.xml (100%) create mode 100644 examples/legacy/android/app/src/main/res/xml/network_security_config.xml rename {example => examples/legacy}/android/app/src/release/java/com/agorartcngexample/ReactNativeFlipper.java (100%) rename {example => examples/legacy}/android/build.gradle (100%) rename {example => examples/legacy}/android/gradle.properties (100%) rename {example => examples/legacy}/android/gradle/wrapper/gradle-wrapper.jar (100%) rename {example => examples/legacy}/android/gradle/wrapper/gradle-wrapper.properties (100%) rename {example => examples/legacy}/android/gradlew (100%) create mode 100644 examples/legacy/android/gradlew.bat rename {example => examples/legacy}/android/settings.gradle (100%) rename {example => examples/legacy}/app.json (100%) rename {example => examples/legacy}/babel.config.js (73%) create mode 100644 examples/legacy/e2e/jest.config.js rename {example => examples/legacy}/e2e/starter.test.js (100%) rename {example => examples/legacy}/example.jpg (100%) rename {example => examples/legacy}/index.js (100%) create mode 100644 examples/legacy/ios/.xcode.env rename {example => examples/legacy}/ios/AgoraRtcNgExample-Bridging-Header.h (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample.xcodeproj/project.pbxproj (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample.xcodeproj/xcshareddata/xcschemes/AgoraRtcNgExample.xcscheme (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample.xcworkspace/contents.xcworkspacedata (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample/AppDelegate.swift (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample/Images.xcassets/AppIcon.appiconset/Contents.json (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample/Images.xcassets/Contents.json (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample/Info.plist (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample/LaunchScreen.storyboard (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExample/PrivacyInfo.xcprivacy (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExampleTests/AgoraRtcNgExampleTests.m (100%) rename {example => examples/legacy}/ios/AgoraRtcNgExampleTests/Info.plist (100%) rename {example => examples/legacy}/ios/File.swift (100%) create mode 100644 examples/legacy/ios/NativeModules/VideoRawDataNativeModule.h create mode 100644 examples/legacy/ios/NativeModules/VideoRawDataNativeModule.m rename {example => examples/legacy}/ios/Podfile (100%) rename {example => examples/legacy}/ios/Podfile.lock (98%) create mode 100644 examples/legacy/ios/Resources/agora-logo.png create mode 100644 examples/legacy/ios/Resources/dang.mp3 create mode 100644 examples/legacy/ios/Resources/ding.mp3 create mode 100644 examples/legacy/ios/Resources/effect.mp3 create mode 100644 examples/legacy/ios/ScreenShare/Info.plist rename {example => examples/legacy}/ios/ScreenShare/SampleHandler.h (100%) rename {example => examples/legacy}/ios/ScreenShare/SampleHandler.m (100%) create mode 100644 examples/legacy/jest.config.js rename {example => examples/legacy}/metro.config.js (93%) rename {example => examples/legacy}/package.json (96%) rename {example => examples/legacy}/react-native.config.js (54%) rename {example => examples/legacy}/src/App.tsx (100%) rename {example => examples/legacy}/src/components/BaseComponent.tsx (100%) rename {example => examples/legacy}/src/components/LogSink.tsx (100%) create mode 100644 examples/legacy/src/components/ui/index.tsx create mode 100644 examples/legacy/src/config/agora.config.ts rename {example => examples/legacy}/src/context/pip.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/AudioCallRoute/AudioCallRoute.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/AudioMixing/AudioMixing.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/AudioSpectrum/AudioSpectrum.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/BeautyEffect/BeautyEffect.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/ChannelMediaRelay/ChannelMediaRelay.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/ContentInspect/ContentInspect.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/DirectCdnStreaming/DirectCdnStreaming.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/Encryption/Encryption.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/Extension/Extension.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/JoinMultipleChannel/JoinMultipleChannel.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/LocalSpatialAudioEngine/LocalSpatialAudioEngine.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/LocalVideoTranscoder/LocalVideoTranscoder.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/MediaPlayer/MediaPlayer.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/MediaRecorder/MediaRecorder.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/MusicContentCenter/MusicContentCenter.tsx (100%) create mode 100644 examples/legacy/src/examples/advanced/PictureInPicture/PictureInPicture.md rename {example => examples/legacy}/src/examples/advanced/PictureInPicture/PictureInPicture.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/PlayEffect/PlayEffect.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/ProcessVideoRawData/ProcessVideoRawData.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/PushVideoFrame/PushVideoFrame.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/RTMPStreaming/RTMPStreaming.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/RhythmPlayer/RhythmPlayer.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/ScreenShare/ScreenShare.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/SendMetadata/SendMetadata.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/SendMultiVideoStream/SendMultiVideoStream.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/SpatialAudio/SpatialAudio.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/StreamMessage/StreamMessage.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/TakeSnapshot/TakeSnapshot.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/VideoEncoderConfiguration/VideoEncoderConfiguration.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/VirtualBackground/VirtualBackground.tsx (100%) rename {example => examples/legacy}/src/examples/advanced/VoiceChanger/VoiceChanger.tsx (100%) create mode 100644 examples/legacy/src/examples/advanced/VoiceChanger/VoiceChangerConfig.tsx rename {example => examples/legacy}/src/examples/advanced/index.ts (100%) rename {example => examples/legacy}/src/examples/basic/JoinChannelAudio/JoinChannelAudio.tsx (100%) rename {example => examples/legacy}/src/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx (100%) rename {example => examples/legacy}/src/examples/basic/StringUid/StringUid.tsx (100%) rename {example => examples/legacy}/src/examples/basic/index.ts (100%) rename {example => examples/legacy}/src/examples/hook/AudioMixing/AudioMixing.tsx (100%) rename {example => examples/legacy}/src/examples/hook/JoinChannelAudio/JoinChannelAudio.tsx (100%) rename {example => examples/legacy}/src/examples/hook/JoinChannelVideo/JoinChannelVideo.tsx (100%) rename {example => examples/legacy}/src/examples/hook/JoinMultipleChannel/JoinMultipleChannel.tsx (100%) rename {example => examples/legacy}/src/examples/hook/ScreenShare/ScreenShare.tsx (100%) rename {example => examples/legacy}/src/examples/hook/StringUid/StringUid.tsx (100%) rename {example => examples/legacy}/src/examples/hook/TakeSnapshot/TakeSnapshot.tsx (100%) rename {example => examples/legacy}/src/examples/hook/VirtualBackground/VirtualBackground.tsx (100%) rename {example => examples/legacy}/src/examples/hook/components/BaseComponent.tsx (100%) rename {example => examples/legacy}/src/examples/hook/components/BaseRenderChannel.tsx (100%) rename {example => examples/legacy}/src/examples/hook/components/BaseRenderUsers.tsx (100%) rename {example => examples/legacy}/src/examples/hook/hooks/useInitRtcEngine.tsx (100%) create mode 100644 examples/legacy/src/examples/hook/hooks/useResetState.tsx rename {example => examples/legacy}/src/examples/hook/index.ts (100%) create mode 100644 examples/legacy/src/utils/AgoraServiceHelper.ts create mode 100644 examples/legacy/src/utils/index.ts rename {example => examples/legacy}/src/utils/log.ts (100%) create mode 100644 examples/legacy/src/utils/permissions.ts delete mode 100644 scripts/pod-install.cjs create mode 100644 src/internal/call.ts create mode 100644 src/internal/event.ts diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 720118ef..44d99e20 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -24,7 +24,7 @@ runs: if: ${{ runner.os == 'macOS' }} uses: maxim-lobanov/setup-cocoapods@v1 with: - version: 1.13.0 + version: 1.16.2 - name: Cache dependencies id: yarn-cache diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 68133e1f..5179344f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,8 +14,6 @@ jobs: matrix: newArch: [false, true] env: - TURBO_CACHE_DIR: .turbo/android - turbo_cache_hit: 0 ORG_GRADLE_PROJECT_newArchEnabled: ${{ matrix.newArch }} steps: - name: Checkout @@ -24,71 +22,40 @@ jobs: - name: Setup uses: ./.github/actions/setup - - name: Cache turborepo for Android - uses: actions/cache@v3 - with: - path: ${{ env.TURBO_CACHE_DIR }} - key: ${{ runner.os }}-turborepo-android-${{ matrix.newArch }}-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-turborepo-android-${{ matrix.newArch }}- - - - name: Check turborepo cache for Android - run: | - TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:android').cache.status") - - if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then - echo "turbo_cache_hit=1" >> $GITHUB_ENV - fi - - name: Install JDK - if: env.turbo_cache_hit != 1 uses: actions/setup-java@v3 with: distribution: 'zulu' java-version: '17' - name: Finalize Android SDK - if: env.turbo_cache_hit != 1 run: | /bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null" - - name: Cache Gradle - if: env.turbo_cache_hit != 1 - uses: actions/cache@v3 - with: - path: | - ~/.gradle/wrapper - ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ matrix.newArch }}-${{ hashFiles('example/android/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle-${{ matrix.newArch }}- - - name: Modify APP ID run: | sed "s/localAppId = '\(.*\)'/localAppId = '${{ secrets.APP_ID }}'/g" agora.config.ts > tmp mv tmp agora.config.ts - working-directory: example/src/config + working-directory: examples/expo/src/config - name: Build example for Android run: | - yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --force=true + yarn example build:android - name: Upload APK uses: actions/upload-artifact@v4 with: - name: AgoraRtcNgExample-Android-${{ matrix.newArch && 'NewArch' || 'OldArch' }}-${{ github.run_id }} + name: AgoraRtcNgExampleExpo-Android-${{ matrix.newArch && 'NewArch' || 'OldArch' }}-${{ github.run_id }} path: | - example/android/app/build/outputs/apk/release/*.apk + examples/expo/android/app/build/outputs/apk/release/*.apk if-no-files-found: error build-ios: - runs-on: macos-latest + runs-on: macos-15 strategy: matrix: newArch: [false, true] env: - TURBO_CACHE_DIR: .turbo/ios - turbo_cache_hit: 0 RCT_NEW_ARCH_ENABLED: ${{ matrix.newArch }} steps: - name: Checkout @@ -101,34 +68,20 @@ jobs: run: | brew install fastlane - - name: Cache turborepo for iOS - uses: actions/cache@v3 - with: - path: ${{ env.TURBO_CACHE_DIR }} - key: ${{ runner.os }}-turborepo-ios-${{ matrix.newArch }}-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-turborepo-ios-${{ matrix.newArch }}- - - - name: Cache cocoapods - if: env.turbo_cache_hit != 1 - id: cocoapods-cache - uses: actions/cache@v3 - with: - path: | - **/ios/Pods - key: ${{ runner.os }}-cocoapods-${{ matrix.newArch }}-${{ hashFiles('example/ios/Podfile.lock') }} - restore-keys: | - ${{ runner.os }}-cocoapods-${{ matrix.newArch }}- + - name: Switch Xcode + run: | + #https://github.com/actions/runner-images/issues/12758 + sudo xcode-select --switch /Applications/Xcode_16.4.app - name: Install cocoapods run: | - yarn pod-install example/ios + yarn pod-install examples/expo/ios - name: Modify APP ID run: | sed "s/localAppId = '\(.*\)'/localAppId = '${{ secrets.APP_ID }}'/g" agora.config.ts > tmp mv tmp agora.config.ts - working-directory: example/src/config + working-directory: examples/expo/src/config - name: Install the Apple certificate and provisioning profile env: @@ -161,22 +114,22 @@ jobs: - name: Build example for iOS run: | - yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --force=true + yarn example build:ios - name: Upload IPA uses: actions/upload-artifact@v4 with: - name: AgoraRtcNgExample-iOS-${{ matrix.newArch && 'NewArch' || 'OldArch' }}-${{ github.run_id }} + name: AgoraRtcNgExampleExpo-iOS-${{ matrix.newArch && 'NewArch' || 'OldArch' }}-${{ github.run_id }} path: | - example/ios/*.ipa + examples/expo/ios/*.ipa if-no-files-found: error - name: Upload dSYM uses: actions/upload-artifact@v4 with: - name: AgoraRtcNgExampleSymbol-${{ matrix.newArch && 'NewArch' || 'OldArch' }}-${{ github.run_id }} + name: AgoraRtcNgExampleExpoSymbol-${{ matrix.newArch && 'NewArch' || 'OldArch' }}-${{ github.run_id }} path: | - example/ios/*.dSYM.zip + examples/expo/ios/*.dSYM.zip if-no-files-found: error notification: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f7f5f18..8183725a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,9 +68,7 @@ jobs: newArch: [true, false] runs-on: ubuntu-latest env: - TURBO_CACHE_DIR: .turbo/android ORG_GRADLE_PROJECT_newArchEnabled: ${{ matrix.newArch }} - turbo_cache_hit: 0 steps: - name: Checkout uses: actions/checkout@v4 @@ -78,45 +76,16 @@ jobs: - name: Setup uses: ./.github/actions/setup - - name: Cache turborepo for Android - uses: actions/cache@v3 - with: - path: ${{ env.TURBO_CACHE_DIR }} - key: ${{ runner.os }}-turborepo-android-detox-${{ matrix.newArch }}-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-turborepo-android-detox-${{ matrix.newArch }}- - - - name: Check turborepo cache for Android - run: | - TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run detox:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'detox:android').cache.status") - - if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then - echo "turbo_cache_hit=1" >> $GITHUB_ENV - fi - - name: Install JDK - if: env.turbo_cache_hit != 1 uses: actions/setup-java@v3 with: distribution: 'zulu' java-version: '17' - name: Finalize Android SDK - if: env.turbo_cache_hit != 1 run: | /bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null" - - name: Cache Gradle - if: env.turbo_cache_hit != 1 - uses: actions/cache@v3 - with: - path: | - ~/.gradle/wrapper - ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ matrix.newArch }}-${{ hashFiles('example/android/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle-${{ matrix.newArch }}- - - name: Install Detox dependencies shell: bash run: | @@ -126,23 +95,33 @@ jobs: run: | sed "s/localAppId = '\(.*\)'/localAppId = '${{ secrets.APP_ID }}'/g" agora.config.ts > tmp mv tmp agora.config.ts - working-directory: example/src/config + working-directory: examples/expo/src/config - name: Build example for Android run: | - yarn turbo run detox:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" + yarn example detox:android - name: Clean Useless cache run: | - rm -rf "${{ env.TURBO_CACHE_DIR }}" || true rm -rf ~/.gradle/caches || true rm -rf ~/.gradle/wrapper || true sudo apt-get clean npm cache clean --force - rm -rf example/ios + rm -rf examples/**/ios yarn cache clean df -h + - name: Free Disk Space + uses: jlumbroso/free-disk-space@main + with: + tool-cache: false + android: false + dotnet: true + haskell: true + large-packages: true + docker-images: true + swap-storage: true + - name: Enable KVM group perms run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -157,16 +136,15 @@ jobs: api-level: 31 arch: x86_64 avd-name: emulator - working-directory: example + working-directory: examples/expo script: detox test -c android.emu.release test-ios: strategy: matrix: newArch: [1, 0] - runs-on: macos-latest + runs-on: macos-15 env: - TURBO_CACHE_DIR: .turbo/ios RCT_NEW_ARCH_ENABLED: ${{ matrix.newArch }} steps: - name: Checkout @@ -177,7 +155,12 @@ jobs: - name: Install cocoapods run: | - yarn pod-install example/ios + yarn pod-install examples/expo/ios + + - name: Switch Xcode + run: | + #https://github.com/actions/runner-images/issues/12758 + sudo xcode-select --switch /Applications/Xcode_16.4.app - name: Install Detox dependencies shell: bash @@ -190,20 +173,20 @@ jobs: run: | sed "s/localAppId = '\(.*\)'/localAppId = '${{ secrets.APP_ID }}'/g" agora.config.ts > tmp mv tmp agora.config.ts - working-directory: example/src/config + working-directory: examples/expo/src/config - name: Build example for iOS run: | - yarn turbo run detox:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" + yarn example detox:ios - uses: futureware-tech/simulator-action@v4 with: - model: 'iPhone 15' + model: 'iPhone 16' - name: Run e2e tests # https://github.com/wix/Detox/issues/3720#issuecomment-1347855162 if: ${{ matrix.newArch == 0 }} - working-directory: example + working-directory: examples/expo run: | detox clean-framework-cache detox build-framework-cache diff --git a/.github/workflows/dep.yml b/.github/workflows/dep.yml index 4ea2fb1f..bc80f172 100644 --- a/.github/workflows/dep.yml +++ b/.github/workflows/dep.yml @@ -42,8 +42,8 @@ jobs: - name: Update example run: | - rm -rf example/ios/Podfile.lock - yarn pod-install example/ios + rm -rf examples/expo/ios/Podfile.lock + yarn pod-install examples/expo/ios - name: Create pull request uses: AgoraIO-Extensions/actions/.github/actions/pr@main diff --git a/.gitignore b/.gitignore index a93b523e..2c1f2a5c 100644 --- a/.gitignore +++ b/.gitignore @@ -44,11 +44,11 @@ android.iml # Cocoapods # -example/ios/Pods +examples/**/ios/Pods **/Pods/ # Ruby -example/vendor/ +examples/**/vendor/ # node.js # diff --git a/.yarnrc.yml b/.yarnrc.yml index d6817f4f..5237ebe9 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -4,7 +4,6 @@ nmHoistingLimits: workspaces plugins: - path: scripts/bootstrap.cjs - - path: scripts/pod-install.cjs - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs spec: "@yarnpkg/plugin-interactive-tools" - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs diff --git a/examples/expo/.detoxrc.js b/examples/expo/.detoxrc.js new file mode 100644 index 00000000..e7d6875e --- /dev/null +++ b/examples/expo/.detoxrc.js @@ -0,0 +1,87 @@ +/** @type {Detox.DetoxConfig} */ +module.exports = { + testRunner: { + args: { + $0: 'jest', + config: 'e2e/jest.config.js', + }, + jest: { + setupTimeout: 2100000, + }, + }, + apps: { + 'ios.debug': { + type: 'ios.app', + binaryPath: + 'ios/build/Build/Products/Debug-iphonesimulator/reactnativeagoraexampleexpo.app', + build: + 'xcodebuild -workspace ios/reactnativeagoraexampleexpo.xcworkspace -scheme reactnativeagoraexampleexpo -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build', + }, + 'ios.release': { + type: 'ios.app', + binaryPath: + 'ios/build/Build/Products/Release-iphonesimulator/reactnativeagoraexampleexpo.app', + build: + 'xcodebuild -workspace ios/reactnativeagoraexampleexpo.xcworkspace -scheme reactnativeagoraexampleexpo -configuration Release -sdk iphonesimulator -derivedDataPath ios/build', + }, + 'android.debug': { + type: 'android.apk', + binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk', + build: + 'cd android ; ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug ; cd -', + reversePorts: [8081], + }, + 'android.release': { + type: 'android.apk', + binaryPath: 'android/app/build/outputs/apk/release/app-release.apk', + build: + 'cd android ; ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release ; cd -', + }, + }, + devices: { + simulator: { + type: 'ios.simulator', + device: { + type: 'iPhone 16', + }, + }, + attached: { + type: 'android.attached', + device: { + adbName: '.*', + }, + }, + emulator: { + type: 'android.emulator', + device: { + avdName: 'emulator', + }, + }, + }, + configurations: { + 'ios.sim.debug': { + device: 'simulator', + app: 'ios.debug', + }, + 'ios.sim.release': { + device: 'simulator', + app: 'ios.release', + }, + 'android.att.debug': { + device: 'attached', + app: 'android.debug', + }, + 'android.att.release': { + device: 'attached', + app: 'android.release', + }, + 'android.emu.debug': { + device: 'emulator', + app: 'android.debug', + }, + 'android.emu.release': { + device: 'emulator', + app: 'android.release', + }, + }, +}; diff --git a/examples/expo/.gitignore b/examples/expo/.gitignore new file mode 100644 index 00000000..4957fbdb --- /dev/null +++ b/examples/expo/.gitignore @@ -0,0 +1,40 @@ +# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files + +# dependencies +node_modules/ + +# Expo +.expo/ +dist/ +web-build/ +expo-env.d.ts + +# Native +.kotlin/ +*.orig.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision + +# Metro +.metro-health-check* + +# debug +npm-debug.* +yarn-debug.* +yarn-error.* + +# macOS +.DS_Store +*.pem + +# local env files +.env*.local + +# typescript +*.tsbuildinfo + + +*.dSYM.zip diff --git a/example/.node-version b/examples/expo/.node-version similarity index 100% rename from example/.node-version rename to examples/expo/.node-version diff --git a/example/.ruby-version b/examples/expo/.ruby-version similarity index 100% rename from example/.ruby-version rename to examples/expo/.ruby-version diff --git a/example/Gemfile b/examples/expo/Gemfile similarity index 100% rename from example/Gemfile rename to examples/expo/Gemfile diff --git a/example/Gemfile.lock b/examples/expo/Gemfile.lock similarity index 100% rename from example/Gemfile.lock rename to examples/expo/Gemfile.lock diff --git a/examples/expo/README.md b/examples/expo/README.md new file mode 100644 index 00000000..8d75e988 --- /dev/null +++ b/examples/expo/README.md @@ -0,0 +1,361 @@ +# React Native Agora Expo Example + +## Overview + +This guide will walk you through simple instructions to create a real-time communication app using Agora SDK with Expo and test it using an emulator or your mobile device. The example demonstrates how to implement voice and video calling, stream sharing, and various advanced features using Agora's React Native SDK in an Expo-managed application. + +## Getting Started + +This section contains instructions to create a simple Expo app with Agora integration. We'll help you understand the project setup and provide complete code samples to implement functionality quickly. + +### Prerequisites + +- An Agora account - [Sign up](https://console.agora.io/) if you don't have one +- Working Expo development environment +- Familiarity with React Native basics +- VS Code or any other IDE / code editor + +### Setup Your Agora App + +1. Create a project in the [Agora Console](https://console.agora.io/) +2. Obtain your App ID from the Agora Console +3. For token-based authentication (recommended for production), generate a temporary token or set up an authentication server + +### Create an Expo App + +1. Open your Terminal and navigate to the directory where you'd like to create your app +2. Run the following command to create an Expo app: + +```bash +npx create-expo-app my-agora-app && cd my-agora-app +``` + +3. Install expo-dev-client to enable native module usage: + +```bash +npx expo install expo-dev-client +``` + +4. Test run your app: + +**Android** + +```bash +npx expo run:android +``` + +**iOS** + +```bash +npx expo run:ios +``` + +The above commands compile your project into a debug build of your app using locally installed Android SDK or Xcode. + +### Install Agora SDK and Dependencies + +After successfully testing your app, install the React Native Agora package: + +```bash +npx expo install react-native-agora +``` + +### Configure App Permissions + +1. Set up necessary permissions in your app.json: + +```json +{ + "expo": { + "android": { + "permissions": [ + "android.permission.CAMERA", + "android.permission.RECORD_AUDIO", + "android.permission.MODIFY_AUDIO_SETTINGS", + "android.permission.ACCESS_WIFI_STATE", + "android.permission.ACCESS_NETWORK_STATE", + "android.permission.BLUETOOTH", + "android.permission.FOREGROUND_SERVICE" + ] + } + } +} +``` + +2. For iOS, add the following to your app.json to configure the permission request messages: + +```json +{ + "expo": { + "plugins": [ + [ + "expo-camera", + { + "cameraPermission": "Allow $(PRODUCT_NAME) to access your camera for video calls", + "microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone for audio calls" + } + ] + ] + } +} +``` + +### Setup Minimum Deployment Targets + +Agora SDK requires minimum SDK versions: + +- Android: minSdkVersion = 24 +- iOS: iOS 12.4+ + +Install expo-build-properties to configure these: + +```bash +npx expo install expo-build-properties --save-dev +``` + +Add the following to your app.json: + +```json +{ + "expo": { + "plugins": [ + [ + "expo-build-properties", + { + "android": { + "minSdkVersion": 24 // depends on react-native and expo version that you choose + }, + "ios": { + "deploymentTarget": "12.4" // depends on react-native and expo version that you choose + } + } + ] + ] + } +} +``` + +### Configure Your Agora App ID + +Create a configuration file to store your Agora credentials: + +1. Create a file at `src/config/appID.js`: + +```javascript +export const appId = 'YOUR_AGORA_APP_ID'; +``` + +2. Make sure to add this file to your .gitignore to avoid exposing your App ID + +### Basic Integration Example + +Here's a simple example of how to implement a basic video call: + +```javascript +import React, { useEffect, useState } from 'react'; +import { Button, StyleSheet, View } from 'react-native'; +import { + ChannelProfileType, + ClientRoleType, + createAgoraRtcEngine, + IRtcEngineEventHandler, + RtcSurfaceView, + VideoSourceType, +} from 'react-native-agora'; + +import Config from '../config/agora.config'; +import { askMediaAccess } from '../utils/permissions'; + +export default function BasicVideoCall() { + const [engine, setEngine] = useState(undefined); + const [isJoined, setIsJoined] = useState(false); + const [remoteUsers, setRemoteUsers] = useState([]); + + useEffect(() => { + // Initialize Agora engine when component mounts + const init = async () => { + if (!Config.appId) { + console.error('App ID is missing'); + return; + } + + // Create Agora engine instance + const rtcEngine = createAgoraRtcEngine(); + setEngine(rtcEngine); + + // Initialize the engine + rtcEngine.initialize({ + appId: Config.appId, + channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, + }); + + // Request permissions and enable video + await askMediaAccess([ + 'android.permission.CAMERA', + 'android.permission.RECORD_AUDIO', + ]); + rtcEngine.enableVideo(); + + // Register event handlers + rtcEngine.addListener('onJoinChannelSuccess', () => { + setIsJoined(true); + console.log('Successfully joined the channel'); + }); + + rtcEngine.addListener('onUserJoined', (connection, uid) => { + console.log('Remote user joined:', uid); + setRemoteUsers((prev) => [...prev, uid]); + }); + + rtcEngine.addListener('onUserOffline', (connection, uid) => { + console.log('Remote user left:', uid); + setRemoteUsers((prev) => prev.filter((id) => id !== uid)); + }); + }; + + init(); + return () => { + // Clean up + engine?.leaveChannel(); + engine?.unregisterEventHandler({}); + }; + }, []); + + const joinChannel = async () => { + if (!engine) return; + + // Join a channel + engine.joinChannel(Config.token, Config.channelId, 0, { + clientRoleType: ClientRoleType.ClientRoleBroadcaster, + }); + }; + + const leaveChannel = () => { + if (!engine) return; + engine.leaveChannel(); + setIsJoined(false); + setRemoteUsers([]); + }; + + return ( + + {isJoined && ( + + {/* Local video */} + + + {/* Remote videos */} + {remoteUsers.map((uid) => ( + + ))} + + )} + + + {!isJoined ? ( +