diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..5d401a7da --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,98 @@ +version: 2.1 + +executors: + default: + docker: + - image: circleci/node:10 + working_directory: ~/project + +commands: + attach_project: + steps: + - attach_workspace: + at: ~/project + +jobs: + install-dependencies: + executor: default + steps: + - checkout + - attach_project + - restore_cache: + keys: + - dependencies-{{ checksum "package.json" }} + - dependencies- + - restore_cache: + keys: + - dependencies-example-{{ checksum "example/package.json" }} + - dependencies-example- + - run: + name: Install dependencies + command: | + yarn install --cwd example --frozen-lockfile + yarn install --frozen-lockfile + - save_cache: + key: dependencies-{{ checksum "package.json" }} + paths: node_modules + - save_cache: + key: dependencies-example-{{ checksum "example/package.json" }} + paths: example/node_modules + - persist_to_workspace: + root: . + paths: . + + lint: + executor: default + steps: + - attach_project + - run: + name: Lint files + command: | + yarn lint + + typescript: + executor: default + steps: + - attach_project + - run: + name: Typecheck files + command: | + yarn typescript + + unit-tests: + executor: default + steps: + - attach_project + - run: + name: Run unit tests + command: | + yarn test --coverage + - store_artifacts: + path: coverage + destination: coverage + + build-package: + executor: default + steps: + - attach_project + - run: + name: Build package + command: | + yarn prepare + +workflows: + build-and-test: + jobs: + - install-dependencies + - lint: + requires: + - install-dependencies + - typescript: + requires: + - install-dependencies + - unit-tests: + requires: + - install-dependencies + - build-package: + requires: + - install-dependencies diff --git a/CHANGELOG.md b/CHANGELOG.md index 72ae4b13f..433229e61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +# [3.2.0](https://github.com/AgoraIO-Community/react-native-agora/compare/v3.2.0-rc.0...v3.2.0) (2020-12-23) + + +### Features + +* upgrade native SDK to 3.2.1 ([3dcc489](https://github.com/AgoraIO-Community/react-native-agora/commit/3dcc489bb52daaf8a794554f6048f343cbff5d8f)) + +# [3.2.0-rc.0](https://github.com/AgoraIO-Community/react-native-agora/compare/v3.1.6...v3.2.0-rc.0) (2020-12-21) + + +### Features + +* add `setClientRole(role: ClientRole, options?: ClientRoleOptions): Promise` ([721604e](https://github.com/AgoraIO-Community/react-native-agora/commit/721604ee94c3f7e3a0485b5b5db7fb5973e30665)) +* add `setClientRole(role: ClientRole, options?: ClientRoleOptions): Promise` ([2fef3ae](https://github.com/AgoraIO-Community/react-native-agora/commit/2fef3aee038b31808af53cee80a0fddc8d444fe8)) +* add `setClientRole(role: ClientRole, options?: ClientRoleOptions): Promise` ([3a55997](https://github.com/AgoraIO-Community/react-native-agora/commit/3a55997db81dcd16e68ee551d69b9079ff8052b0)) +* upgrade to 3.2.0 ([fcb57cc](https://github.com/AgoraIO-Community/react-native-agora/commit/fcb57cc3e2cbb3e16750e9ce8ddca069184ac1c0)) +* upgrade to 3.2.0 ([4ee51a9](https://github.com/AgoraIO-Community/react-native-agora/commit/4ee51a9b405deb17b467f5359f6717033c3961a2)) +* upgrade to 3.2.0 ([680048f](https://github.com/AgoraIO-Community/react-native-agora/commit/680048f7836940f586ce7228559ba2cde9e0de62)) + ## [3.1.6](https://github.com/AgoraIO-Community/react-native-agora/compare/v3.1.5...v3.1.6) (2020-12-21) diff --git a/android/build.gradle b/android/build.gradle index c7d29769a..c58fca2e9 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -65,8 +65,8 @@ repositories { defaultDir = rootProject.ext.get('reactNativeAndroidRoot') } else { defaultDir = new File( - projectDir, - '/../../../node_modules/react-native/android' + projectDir, + '/../../../node_modules/react-native/android' ) } @@ -86,13 +86,13 @@ repositories { parentDir = parentDir.parentFile def androidSourcesDir = new File( - parentDir, - 'node_modules/react-native' + parentDir, + 'node_modules/react-native' ) def androidPrebuiltBinaryDir = new File( - parentDir, - 'node_modules/react-native/android' + parentDir, + 'node_modules/react-native/android' ) if (androidPrebuiltBinaryDir.exists()) { @@ -117,8 +117,8 @@ repositories { if (!found) { throw new GradleException( - "${project.name}: unable to locate React Native android sources. " + - "Ensure you have you installed React Native as a dependency in your project and try again." + "${project.name}: unable to locate React Native android sources. " + + "Ensure you have you installed React Native as a dependency in your project and try again." ) } } @@ -128,7 +128,7 @@ def kotlin_version = getExtOrDefault('kotlinVersion') dependencies { // noinspection GradleDynamicVersion api 'com.facebook.react:react-native:+' - api "io.agora.rtc:full-sdk:3.1.3" + api "io.agora.rtc:full-sdk:3.2.1" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" } diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index c78e0b7c9..2ef550020 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,18 +1,18 @@ + xmlns:tools="http://schemas.android.com/tools" + package="io.agora.rtc.react"> - - - - - - - - - - + + + + + + + + + + diff --git a/android/src/main/java/io/agora/rtc/base/Annotations.java b/android/src/main/java/io/agora/rtc/base/Annotations.java index 56da5b894..64361ecc6 100644 --- a/android/src/main/java/io/agora/rtc/base/Annotations.java +++ b/android/src/main/java/io/agora/rtc/base/Annotations.java @@ -20,8 +20,14 @@ public class Annotations { AgoraRtcAppType.FLUTTER, AgoraRtcAppType.UNREAL, AgoraRtcAppType.XAMARIN, - AgoraRtcAppType.APICLOUD, - AgoraRtcAppType.REACTNATIVE, + AgoraRtcAppType.API_CLOUD, + AgoraRtcAppType.REACT_NATIVE, + AgoraRtcAppType.PYTHON, + AgoraRtcAppType.COCOS_CREATOR, + AgoraRtcAppType.RUST, + AgoraRtcAppType.C_SHARP, + AgoraRtcAppType.CEF, + AgoraRtcAppType.UNI_APP, }) @Retention(RetentionPolicy.SOURCE) public @interface AgoraRtcAppType { @@ -32,8 +38,14 @@ public class Annotations { int FLUTTER = 4; int UNREAL = 5; int XAMARIN = 6; - int APICLOUD = 7; - int REACTNATIVE = 8; + int API_CLOUD = 7; + int REACT_NATIVE = 8; + int PYTHON = 9; + int COCOS_CREATOR = 10; + int RUST = 11; + int C_SHARP = 12; + int CEF = 13; + int UNI_APP = 14; } @IntDef({ @@ -217,6 +229,8 @@ public class Annotations { Constants.AUDIO_SCENARIO_GAME_STREAMING, Constants.AUDIO_SCENARIO_SHOWROOM, Constants.AUDIO_SCENARIO_CHATROOM_GAMING, + Constants.AUDIO_SCENARIO_IOT, + Constants.AUDIO_SCENARIO_MEETING, }) @Retention(RetentionPolicy.SOURCE) public @interface AgoraAudioScenario { @@ -614,7 +628,7 @@ public class Annotations { @IntDef({ Constants.USER_PRIORITY_HIGH, - Constants.USER_PRIORITY_NORANL, + Constants.USER_PRIORITY_NORMAL, }) @Retention(RetentionPolicy.SOURCE) public @interface AgoraUserPriority { @@ -751,7 +765,11 @@ public class Annotations { Constants.WARN_ADM_RECORD_IS_OCCUPIED, Constants.WARN_APM_HOWLING, Constants.WARN_ADM_GLITCH_STATE, - Constants.WARN_APM_RESIDUAL_ECHO, + // TODO(3.3.0) WARN_APM_RESIDUAL_ECHO + Constants.WARN_ADM_IMPROPER_SETTINGS, + Constants.WARN_SUPER_RESOLUTION_STREAM_OVER_LIMITATION, + Constants.WARN_SUPER_RESOLUTION_USER_COUNT_OVER_LIMITATION, + Constants.WARN_SUPER_RESOLUTION_DEVICE_NOT_SUPPORTED, }) @Retention(RetentionPolicy.SOURCE) public @interface AgoraWarningCode { @@ -796,4 +814,55 @@ public class Annotations { @Retention(RetentionPolicy.SOURCE) public @interface AgoraRtmpStreamingEvent { } + + @IntDef({ + Constants.AUDIO_EFFECT_OFF, + Constants.ROOM_ACOUSTICS_KTV, + Constants.ROOM_ACOUSTICS_VOCAL_CONCERT, + Constants.ROOM_ACOUSTICS_STUDIO, + Constants.ROOM_ACOUSTICS_PHONOGRAPH, + Constants.ROOM_ACOUSTICS_VIRTUAL_STEREO, + Constants.ROOM_ACOUSTICS_SPACIAL, + Constants.ROOM_ACOUSTICS_ETHEREAL, + Constants.ROOM_ACOUSTICS_3D_VOICE, + Constants.VOICE_CHANGER_EFFECT_UNCLE, + Constants.VOICE_CHANGER_EFFECT_OLDMAN, + Constants.VOICE_CHANGER_EFFECT_BOY, + Constants.VOICE_CHANGER_EFFECT_SISTER, + Constants.VOICE_CHANGER_EFFECT_GIRL, + Constants.VOICE_CHANGER_EFFECT_PIGKING, + Constants.VOICE_CHANGER_EFFECT_HULK, + Constants.STYLE_TRANSFORMATION_RNB, + Constants.STYLE_TRANSFORMATION_POPULAR, + Constants.PITCH_CORRECTION, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AgoraAudioEffectPreset { + } + + @IntDef({ + Constants.VOICE_BEAUTIFIER_OFF, + Constants.CHAT_BEAUTIFIER_MAGNETIC, + Constants.CHAT_BEAUTIFIER_FRESH, + Constants.CHAT_BEAUTIFIER_VITALITY, + Constants.TIMBRE_TRANSFORMATION_VIGOROUS, + Constants.TIMBRE_TRANSFORMATION_DEEP, + Constants.TIMBRE_TRANSFORMATION_MELLOW, + Constants.TIMBRE_TRANSFORMATION_FALSETTO, + Constants.TIMBRE_TRANSFORMATION_FULL, + Constants.TIMBRE_TRANSFORMATION_CLEAR, + Constants.TIMBRE_TRANSFORMATION_RESOUNDING, + Constants.TIMBRE_TRANSFORMATION_RINGING, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AgoraVoiceBeautifierPreset { + } + + @IntDef({ + Constants.AUDIENCE_LATENCY_LEVEL_LOW_LATENCY, + Constants.AUDIENCE_LATENCY_LEVEL_ULTRA_LOW_LATENCY, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AgoraAudienceLatencyLevelType { + } } diff --git a/android/src/main/java/io/agora/rtc/base/BeanCovertor.kt b/android/src/main/java/io/agora/rtc/base/BeanCovertor.kt index d7a94fb9a..7001164c8 100644 --- a/android/src/main/java/io/agora/rtc/base/BeanCovertor.kt +++ b/android/src/main/java/io/agora/rtc/base/BeanCovertor.kt @@ -7,6 +7,7 @@ import io.agora.rtc.live.LiveInjectStreamConfig import io.agora.rtc.live.LiveTranscoding import io.agora.rtc.live.LiveTranscoding.TranscodingUser import io.agora.rtc.models.ChannelMediaOptions +import io.agora.rtc.models.ClientRoleOptions import io.agora.rtc.video.* fun mapToVideoDimensions(map: Map<*, *>): VideoEncoderConfiguration.VideoDimensions { @@ -177,3 +178,9 @@ fun mapToEncryptionConfig(map: Map<*, *>): EncryptionConfig { (map["encryptionKey"] as? String)?.let { encryptionKey = it } } } + +fun mapToClientRoleOptions(map: Map<*, *>): ClientRoleOptions { + return ClientRoleOptions().apply { + (map["audienceLatencyLevel"] as? Number)?.let { audienceLatencyLevel = it.toInt() } + } +} diff --git a/android/src/main/java/io/agora/rtc/base/RtcChannel.kt b/android/src/main/java/io/agora/rtc/base/RtcChannel.kt index 58432cee0..4734add1c 100644 --- a/android/src/main/java/io/agora/rtc/base/RtcChannel.kt +++ b/android/src/main/java/io/agora/rtc/base/RtcChannel.kt @@ -149,7 +149,12 @@ class RtcChannelManager( } override fun setClientRole(params: Map, callback: Callback) { - callback.code(this[params["channelId"] as String]?.setClientRole((params["role"] as Number).toInt())) + val role = (params["role"] as Number).toInt() + (params["options"] as? Map<*, *>)?.let { + callback.code(this[params["channelId"] as String]?.setClientRole(role, mapToClientRoleOptions(it))) + return@setClientRole + } + callback.code(this[params["channelId"] as String]?.setClientRole(role)) } override fun joinChannel(params: Map, callback: Callback) { diff --git a/android/src/main/java/io/agora/rtc/base/RtcEngine.kt b/android/src/main/java/io/agora/rtc/base/RtcEngine.kt index 875264922..90d9a7343 100644 --- a/android/src/main/java/io/agora/rtc/base/RtcEngine.kt +++ b/android/src/main/java/io/agora/rtc/base/RtcEngine.kt @@ -170,8 +170,10 @@ class IRtcEngine { } interface RtcVoiceChangerInterface { + @Deprecated("") fun setLocalVoiceChanger(params: Map, callback: Callback) + @Deprecated("") fun setLocalVoiceReverbPreset(params: Map, callback: Callback) fun setLocalVoicePitch(params: Map, callback: Callback) @@ -179,6 +181,12 @@ class IRtcEngine { fun setLocalVoiceEqualization(params: Map, callback: Callback) fun setLocalVoiceReverb(params: Map, callback: Callback) + + fun setAudioEffectPreset(params: Map, callback: Callback) + + fun setVoiceBeautifierPreset(params: Map, callback: Callback) + + fun setAudioEffectParameters(params: Map, callback: Callback) } interface RtcVoicePositionInterface { @@ -264,8 +272,10 @@ class IRtcEngine { } interface RtcEncryptionInterface { + @Deprecated("") fun setEncryptionSecret(params: Map, callback: Callback) + @Deprecated("") fun setEncryptionMode(params: Map, callback: Callback) fun enableEncryption(params: Map, callback: Callback) @@ -354,7 +364,12 @@ class RtcEngineManager( } override fun setClientRole(params: Map, callback: Callback) { - callback.code(engine?.setClientRole((params["role"] as Number).toInt())) + val role = (params["role"] as Number).toInt() + (params["options"] as? Map<*, *>)?.let { + callback.code(engine?.setClientRole(role, mapToClientRoleOptions(it))) + return@setClientRole + } + callback.code(engine?.setClientRole(role)) } override fun joinChannel(params: Map, callback: Callback) { @@ -657,6 +672,18 @@ class RtcEngineManager( callback.code(engine?.setLocalVoiceReverb((params["reverbKey"] as Number).toInt(), (params["value"] as Number).toInt())) } + override fun setAudioEffectPreset(params: Map, callback: Callback) { + callback.code(engine?.setAudioEffectPreset((params["preset"] as Number).toInt())) + } + + override fun setVoiceBeautifierPreset(params: Map, callback: Callback) { + callback.code(engine?.setVoiceBeautifierPreset((params["preset"] as Number).toInt())) + } + + override fun setAudioEffectParameters(params: Map, callback: Callback) { + callback.code(engine?.setAudioEffectParameters((params["preset"] as Number).toInt(), (params["param1"] as Number).toInt(), (params["param2"] as Number).toInt())) + } + override fun enableSoundPositionIndication(params: Map, callback: Callback) { callback.code(engine?.enableSoundPositionIndication(params["enabled"] as Boolean)) } diff --git a/android/src/main/java/io/agora/rtc/react/PromiseCallback.kt b/android/src/main/java/io/agora/rtc/react/PromiseCallback.kt index 642d7a842..15cf544e7 100644 --- a/android/src/main/java/io/agora/rtc/react/PromiseCallback.kt +++ b/android/src/main/java/io/agora/rtc/react/PromiseCallback.kt @@ -5,23 +5,23 @@ import com.facebook.react.bridge.Promise import io.agora.rtc.base.Callback class PromiseCallback( - private val promise: Promise? + private val promise: Promise? ) : Callback() { - override fun success(data: Any?) { - if (data is Map<*, *>) { - val map = mutableMapOf() - data.forEach { - if (it.key is String) { - map[it.key as String] = it.value - } - } - promise?.resolve(Arguments.makeNativeMap(map)) - } else { - promise?.resolve(data) + override fun success(data: Any?) { + if (data is Map<*, *>) { + val map = mutableMapOf() + data.forEach { + if (it.key is String) { + map[it.key as String] = it.value } + } + promise?.resolve(Arguments.makeNativeMap(map)) + } else { + promise?.resolve(data) } + } - override fun failure(code: String, message: String) { - promise?.reject(code, message) - } + override fun failure(code: String, message: String) { + promise?.reject(code, message) + } } diff --git a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcChannelModule.kt b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcChannelModule.kt index 4996d4dd1..a2c8da43b 100644 --- a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcChannelModule.kt +++ b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcChannelModule.kt @@ -13,59 +13,59 @@ import kotlin.reflect.jvm.javaMethod @ReactModule(name = REACT_CLASS) class RCTAgoraRtcChannelModule( - reactContext: ReactApplicationContext + reactContext: ReactApplicationContext ) : ReactContextBaseJavaModule(reactContext) { - companion object { - const val REACT_CLASS = "RCTAgoraRtcChannelModule" - } + companion object { + const val REACT_CLASS = "RCTAgoraRtcChannelModule" + } - private val manager = RtcChannelManager { methodName, data -> emit(methodName, data) } + private val manager = RtcChannelManager { methodName, data -> emit(methodName, data) } - override fun getName(): String { - return REACT_CLASS - } + override fun getName(): String { + return REACT_CLASS + } - override fun getConstants(): MutableMap { - return mutableMapOf( - "prefix" to RtcChannelEventHandler.PREFIX - ) - } + override fun getConstants(): MutableMap { + return mutableMapOf( + "prefix" to RtcChannelEventHandler.PREFIX + ) + } - override fun onCatalystInstanceDestroy() { - super.onCatalystInstanceDestroy() - manager.release() - } + override fun onCatalystInstanceDestroy() { + super.onCatalystInstanceDestroy() + manager.release() + } - private fun emit(methodName: String, data: Map?) { - reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) - .emit("${RtcChannelEventHandler.PREFIX}$methodName", Arguments.makeNativeMap(data)) - } + private fun emit(methodName: String, data: Map?) { + reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) + .emit("${RtcChannelEventHandler.PREFIX}$methodName", Arguments.makeNativeMap(data)) + } - private fun engine(): RtcEngine? { - return reactApplicationContext.getNativeModule(RCTAgoraRtcEngineModule::class.java).engine() - } + private fun engine(): RtcEngine? { + return reactApplicationContext.getNativeModule(RCTAgoraRtcEngineModule::class.java).engine() + } - fun channel(channelId: String): RtcChannel? { - return manager[channelId] - } + fun channel(channelId: String): RtcChannel? { + return manager[channelId] + } - @ReactMethod - fun callMethod(methodName: String, params: ReadableMap?, callback: Promise?) { - manager::class.declaredMemberFunctions.find { it.name == methodName }?.let { function -> - function.javaMethod?.let { method -> - try { - val parameters = mutableListOf() - params?.toHashMap()?.toMutableMap()?.let { - if (methodName == "create") { - it["engine"] = engine() - } - parameters.add(it) - } - method.invoke(manager, *parameters.toTypedArray(), PromiseCallback(callback)) - } catch (e: Exception) { - e.printStackTrace() - } + @ReactMethod + fun callMethod(methodName: String, params: ReadableMap?, callback: Promise?) { + manager::class.declaredMemberFunctions.find { it.name == methodName }?.let { function -> + function.javaMethod?.let { method -> + try { + val parameters = mutableListOf() + params?.toHashMap()?.toMutableMap()?.let { + if (methodName == "create") { + it["engine"] = engine() } + parameters.add(it) + } + method.invoke(manager, *parameters.toTypedArray(), PromiseCallback(callback)) + } catch (e: Exception) { + e.printStackTrace() } + } } + } } diff --git a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcEngineModule.kt b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcEngineModule.kt index 6ac8d4a03..34bb84244 100644 --- a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcEngineModule.kt +++ b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcEngineModule.kt @@ -12,55 +12,55 @@ import kotlin.reflect.jvm.javaMethod @ReactModule(name = REACT_CLASS) class RCTAgoraRtcEngineModule( - reactContext: ReactApplicationContext + reactContext: ReactApplicationContext ) : ReactContextBaseJavaModule(reactContext) { - companion object { - const val REACT_CLASS = "RCTAgoraRtcEngineModule" - } + companion object { + const val REACT_CLASS = "RCTAgoraRtcEngineModule" + } - private val manager = RtcEngineManager { methodName, data -> emit(methodName, data) } + private val manager = RtcEngineManager { methodName, data -> emit(methodName, data) } - override fun getName(): String { - return REACT_CLASS - } + override fun getName(): String { + return REACT_CLASS + } - override fun getConstants(): MutableMap { - return mutableMapOf( - "prefix" to RtcEngineEventHandler.PREFIX - ) - } + override fun getConstants(): MutableMap { + return mutableMapOf( + "prefix" to RtcEngineEventHandler.PREFIX + ) + } - override fun onCatalystInstanceDestroy() { - super.onCatalystInstanceDestroy() - manager.release() - } + override fun onCatalystInstanceDestroy() { + super.onCatalystInstanceDestroy() + manager.release() + } - private fun emit(methodName: String, data: Map?) { - reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) - .emit("${RtcEngineEventHandler.PREFIX}$methodName", Arguments.makeNativeMap(data)) - } + private fun emit(methodName: String, data: Map?) { + reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) + .emit("${RtcEngineEventHandler.PREFIX}$methodName", Arguments.makeNativeMap(data)) + } - fun engine(): RtcEngine? { - return manager.engine - } + fun engine(): RtcEngine? { + return manager.engine + } - @ReactMethod - fun callMethod(methodName: String, params: ReadableMap?, callback: Promise?) { - manager::class.declaredMemberFunctions.find { it.name == methodName }?.let { function -> - function.javaMethod?.let { method -> - try { - val parameters = mutableListOf() - params?.toHashMap()?.toMutableMap()?.let { - if (methodName == "create") { - it["context"] = reactApplicationContext.applicationContext - } - parameters.add(it) - } - method.invoke(manager, *parameters.toTypedArray(), PromiseCallback(callback)) - } catch (e: Exception) { - e.printStackTrace() - } + @ReactMethod + fun callMethod(methodName: String, params: ReadableMap?, callback: Promise?) { + manager::class.declaredMemberFunctions.find { it.name == methodName }?.let { function -> + function.javaMethod?.let { method -> + try { + val parameters = mutableListOf() + params?.toHashMap()?.toMutableMap()?.let { + if (methodName == "create") { + it["context"] = reactApplicationContext.applicationContext } + parameters.add(it) + } + method.invoke(manager, *parameters.toTypedArray(), PromiseCallback(callback)) + } catch (e: Exception) { + e.printStackTrace() } + } } + } } diff --git a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcPackage.kt b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcPackage.kt index a0748ef30..66153008e 100644 --- a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcPackage.kt +++ b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcPackage.kt @@ -7,22 +7,22 @@ import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.uimanager.ViewManager class RCTAgoraRtcPackage : ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext): List { - return listOf( - RCTAgoraRtcEngineModule(reactContext), - RCTAgoraRtcChannelModule(reactContext) - ) - } + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return listOf( + RCTAgoraRtcEngineModule(reactContext), + RCTAgoraRtcChannelModule(reactContext) + ) + } - // Deprecated in RN 0.47 - fun createJSModules(): List> { - return emptyList() - } + // Deprecated in RN 0.47 + fun createJSModules(): List> { + return emptyList() + } - override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return listOf( - RCTAgoraRtcSurfaceViewManager(), - RCTAgoraRtcTextureViewManager() - ) - } + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return listOf( + RCTAgoraRtcSurfaceViewManager(), + RCTAgoraRtcTextureViewManager() + ) + } } diff --git a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcSurfaceViewManager.kt b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcSurfaceViewManager.kt index 9aaed148a..42506fbd0 100644 --- a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcSurfaceViewManager.kt +++ b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcSurfaceViewManager.kt @@ -9,59 +9,59 @@ import io.agora.rtc.RtcEngine import io.agora.rtc.base.RtcSurfaceView class RCTAgoraRtcSurfaceViewManager : SimpleViewManager() { - companion object { - const val REACT_CLASS = "RCTAgoraRtcSurfaceView" - } + companion object { + const val REACT_CLASS = "RCTAgoraRtcSurfaceView" + } - private var reactContext: ThemedReactContext? = null + private var reactContext: ThemedReactContext? = null - override fun createViewInstance(reactContext: ThemedReactContext): RtcSurfaceView { - this.reactContext = reactContext - return RtcSurfaceView(reactContext) - } + override fun createViewInstance(reactContext: ThemedReactContext): RtcSurfaceView { + this.reactContext = reactContext + return RtcSurfaceView(reactContext) + } - override fun onDropViewInstance(view: RtcSurfaceView) { - // getEngine()?.let { view.resetVideoCanvas(it) } - super.onDropViewInstance(view) - } + override fun onDropViewInstance(view: RtcSurfaceView) { + // getEngine()?.let { view.resetVideoCanvas(it) } + super.onDropViewInstance(view) + } - override fun getName(): String { - return REACT_CLASS - } + override fun getName(): String { + return REACT_CLASS + } - @ReactProp(name = "zOrderMediaOverlay") - fun setZOrderMediaOverlay(view: RtcSurfaceView, isMediaOverlay: Boolean) { - view.setZOrderMediaOverlay(isMediaOverlay) - } + @ReactProp(name = "zOrderMediaOverlay") + fun setZOrderMediaOverlay(view: RtcSurfaceView, isMediaOverlay: Boolean) { + view.setZOrderMediaOverlay(isMediaOverlay) + } - @ReactProp(name = "zOrderOnTop") - fun setZOrderOnTop(view: RtcSurfaceView, onTop: Boolean) { - view.setZOrderOnTop(onTop) - } + @ReactProp(name = "zOrderOnTop") + fun setZOrderOnTop(view: RtcSurfaceView, onTop: Boolean) { + view.setZOrderOnTop(onTop) + } - @ReactProp(name = "data") - fun setData(view: RtcSurfaceView, data: ReadableMap) { - data.toHashMap().let { map -> - val channel = (map["channelId"] as? String)?.let { getChannel(it) } - getEngine()?.let { view.setData(it, channel, (map["uid"] as Number).toInt()) } - } + @ReactProp(name = "data") + fun setData(view: RtcSurfaceView, data: ReadableMap) { + data.toHashMap().let { map -> + val channel = (map["channelId"] as? String)?.let { getChannel(it) } + getEngine()?.let { view.setData(it, channel, (map["uid"] as Number).toInt()) } } + } - @ReactProp(name = "renderMode") - fun setRenderMode(view: RtcSurfaceView, renderMode: Int) { - getEngine()?.let { view.setRenderMode(it, renderMode) } - } + @ReactProp(name = "renderMode") + fun setRenderMode(view: RtcSurfaceView, renderMode: Int) { + getEngine()?.let { view.setRenderMode(it, renderMode) } + } - @ReactProp(name = "mirrorMode") - fun setMirrorMode(view: RtcSurfaceView, mirrorMode: Int) { - getEngine()?.let { view.setMirrorMode(it, mirrorMode) } - } + @ReactProp(name = "mirrorMode") + fun setMirrorMode(view: RtcSurfaceView, mirrorMode: Int) { + getEngine()?.let { view.setMirrorMode(it, mirrorMode) } + } - private fun getEngine(): RtcEngine? { - return reactContext?.getNativeModule(RCTAgoraRtcEngineModule::class.java)?.engine() - } + private fun getEngine(): RtcEngine? { + return reactContext?.getNativeModule(RCTAgoraRtcEngineModule::class.java)?.engine() + } - private fun getChannel(channelId: String): RtcChannel? { - return reactContext?.getNativeModule(RCTAgoraRtcChannelModule::class.java)?.channel(channelId) - } + private fun getChannel(channelId: String): RtcChannel? { + return reactContext?.getNativeModule(RCTAgoraRtcChannelModule::class.java)?.channel(channelId) + } } diff --git a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcTextureViewManager.kt b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcTextureViewManager.kt index 5e36072e2..e3bf7f8a0 100644 --- a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcTextureViewManager.kt +++ b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcTextureViewManager.kt @@ -9,49 +9,49 @@ import io.agora.rtc.RtcEngine import io.agora.rtc.base.RtcTextureView class RCTAgoraRtcTextureViewManager : SimpleViewManager() { - companion object { - const val REACT_CLASS = "RCTAgoraRtcTextureView" - } - - private var reactContext: ThemedReactContext? = null - - override fun createViewInstance(reactContext: ThemedReactContext): RtcTextureView { - this.reactContext = reactContext - return RtcTextureView(reactContext) - } - - override fun onDropViewInstance(view: RtcTextureView) { - // getEngine()?.let { view.resetVideoRender(it) } - super.onDropViewInstance(view) - } - - override fun getName(): String { - return REACT_CLASS - } - - @ReactProp(name = "data") - fun setData(view: RtcTextureView, data: ReadableMap) { - data.toHashMap().let { map -> - val channel = (map["channelId"] as? String)?.let { getChannel(it) } - getEngine()?.let { view.setData(it, channel, (map["uid"] as Number).toInt()) } - } - } - - @ReactProp(name = "renderMode") - fun setRenderMode(view: RtcTextureView, renderMode: Int) { - getEngine()?.let { view.setRenderMode(it, renderMode) } - } - - @ReactProp(name = "mirrorMode") - fun setMirrorMode(view: RtcTextureView, mirrorMode: Int) { - getEngine()?.let { view.setMirrorMode(it, mirrorMode) } - } - - private fun getEngine(): RtcEngine? { - return reactContext?.getNativeModule(RCTAgoraRtcEngineModule::class.java)?.engine() - } - - private fun getChannel(channelId: String): RtcChannel? { - return reactContext?.getNativeModule(RCTAgoraRtcChannelModule::class.java)?.channel(channelId) - } + companion object { + const val REACT_CLASS = "RCTAgoraRtcTextureView" + } + + private var reactContext: ThemedReactContext? = null + + override fun createViewInstance(reactContext: ThemedReactContext): RtcTextureView { + this.reactContext = reactContext + return RtcTextureView(reactContext) + } + + override fun onDropViewInstance(view: RtcTextureView) { + // getEngine()?.let { view.resetVideoRender(it) } + super.onDropViewInstance(view) + } + + override fun getName(): String { + return REACT_CLASS + } + + @ReactProp(name = "data") + fun setData(view: RtcTextureView, data: ReadableMap) { + data.toHashMap().let { map -> + val channel = (map["channelId"] as? String)?.let { getChannel(it) } + getEngine()?.let { view.setData(it, channel, (map["uid"] as Number).toInt()) } + } + } + + @ReactProp(name = "renderMode") + fun setRenderMode(view: RtcTextureView, renderMode: Int) { + getEngine()?.let { view.setRenderMode(it, renderMode) } + } + + @ReactProp(name = "mirrorMode") + fun setMirrorMode(view: RtcTextureView, mirrorMode: Int) { + getEngine()?.let { view.setMirrorMode(it, mirrorMode) } + } + + private fun getEngine(): RtcEngine? { + return reactContext?.getNativeModule(RCTAgoraRtcEngineModule::class.java)?.engine() + } + + private fun getChannel(channelId: String): RtcChannel? { + return reactContext?.getNativeModule(RCTAgoraRtcChannelModule::class.java)?.channel(channelId) + } } diff --git a/example/agora.config.json b/example/agora.config.json index f95ac6dcc..35a80e7e3 100644 --- a/example/agora.config.json +++ b/example/agora.config.json @@ -1,5 +1,9 @@ { - "appId": YOUR_APP_ID, - "channelId": "APIExample", - "token": YOUR_TOEKN + "//appId": "Get your own App ID at https://dashboard.agora.io/", + "appId": YOUR_APP_ID, + "//token": "Please refer to https://docs.agora.io/en/Agora%20Platform/token", + "token": YOUR_TOEKN, + "channelId": YOUR_CHANNEL_ID, + "uid": YOUR_UID, + "stringUid": YOUR_STRING_UID } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index e03738298..8257d6e2d 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -76,7 +76,7 @@ import com.android.build.OutputFile */ project.ext.react = [ - enableHermes: false, // clean and rebuild if changing + enableHermes: false, // clean and rebuild if changing ] apply from: "../../node_modules/react-native/react.gradle" @@ -119,105 +119,105 @@ def jscFlavor = 'org.webkit:android-jsc:+' def enableHermes = project.ext.react.get("enableHermes", false); android { - compileSdkVersion rootProject.ext.compileSdkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - defaultConfig { - applicationId "com.example.reactnativeagora" - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 - versionName "1.0" - multiDexEnabled true + compileSdkVersion rootProject.ext.compileSdkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + applicationId "com.example.reactnativeagora" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + multiDexEnabled true + } + splits { + abi { + reset() + enable enableSeparateBuildPerCPUArchitecture + universalApk false // If true, also generate a universal APK + include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" } - splits { - abi { - reset() - enable enableSeparateBuildPerCPUArchitecture - universalApk false // If true, also generate a universal APK - include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" - } + } + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' } - signingConfigs { - debug { - storeFile file('debug.keystore') - storePassword 'android' - keyAlias 'androiddebugkey' - keyPassword 'android' - } + } + buildTypes { + debug { + signingConfig signingConfigs.debug } - buildTypes { - debug { - signingConfig signingConfigs.debug - } - release { - // Caution! In production, you need to generate your own keystore file. - // see https://facebook.github.io/react-native/docs/signed-apk-android. - signingConfig signingConfigs.debug - minifyEnabled enableProguardInReleaseBuilds - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - } - } - // applicationVariants are e.g. debug, release - applicationVariants.all { variant -> - variant.outputs.each { output -> - // For each separate APK per architecture, set a unique version code as described here: - // https://developer.android.com/studio/build/configure-apk-splits.html - def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] - def abi = output.getFilter(OutputFile.ABI) - if (abi != null) { // null for the universal-debug, universal-release variants - output.versionCodeOverride = - versionCodes.get(abi) * 1048576 + defaultConfig.versionCode - } - - } + release { + // Caution! In production, you need to generate your own keystore file. + // see https://facebook.github.io/react-native/docs/signed-apk-android. + signingConfig signingConfigs.debug + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } + } + // applicationVariants are e.g. debug, release + applicationVariants.all { variant -> + variant.outputs.each { output -> + // For each separate APK per architecture, set a unique version code as described here: + // https://developer.android.com/studio/build/configure-apk-splits.html + def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] + def abi = output.getFilter(OutputFile.ABI) + if (abi != null) { // null for the universal-debug, universal-release variants + output.versionCodeOverride = + versionCodes.get(abi) * 1048576 + defaultConfig.versionCode + } - packagingOptions { - pickFirst "lib/armeabi-v7a/libc++_shared.so" - pickFirst "lib/arm64-v8a/libc++_shared.so" - pickFirst "lib/x86/libc++_shared.so" - pickFirst "lib/x86_64/libc++_shared.so" } + } + + packagingOptions { + pickFirst "lib/armeabi-v7a/libc++_shared.so" + pickFirst "lib/arm64-v8a/libc++_shared.so" + pickFirst "lib/x86/libc++_shared.so" + pickFirst "lib/x86_64/libc++_shared.so" + } } dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) - //noinspection GradleDynamicVersion - implementation "com.facebook.react:react-native:+" // From node_modules - - - implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { - exclude group: 'com.facebook.fbjni' - } - debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { - exclude group: 'com.facebook.flipper' - } - debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") { - exclude group: 'com.facebook.flipper' - } - - if (enableHermes) { - def hermesPath = "../../node_modules/hermes-engine/android/"; - debugImplementation files(hermesPath + "hermes-debug.aar") - releaseImplementation files(hermesPath + "hermes-release.aar") - } else { - implementation jscFlavor - } - - implementation project(':react-native-agora') + implementation fileTree(dir: "libs", include: ["*.jar"]) + //noinspection GradleDynamicVersion + implementation "com.facebook.react:react-native:+" // From node_modules + + + implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" + debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { + exclude group: 'com.facebook.fbjni' + } + debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { + exclude group: 'com.facebook.flipper' + } + debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") { + exclude group: 'com.facebook.flipper' + } + + if (enableHermes) { + def hermesPath = "../../node_modules/hermes-engine/android/"; + debugImplementation files(hermesPath + "hermes-debug.aar") + releaseImplementation files(hermesPath + "hermes-release.aar") + } else { + implementation jscFlavor + } + + implementation project(':react-native-agora') } // Run this once to be able to run the application with BUCK // puts all compile dependencies into folder libs for BUCK to use task copyDownloadableDepsToLibs(type: Copy) { - from configurations.compile - into 'libs' + from configurations.compile + into 'libs' } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/example/android/build.gradle b/example/android/build.gradle index 5d5d188b3..345e101b7 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,38 +1,38 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext { - buildToolsVersion = "28.0.3" - minSdkVersion = 16 - compileSdkVersion = 28 - targetSdkVersion = 28 - } - repositories { - google() - jcenter() - } - dependencies { - classpath("com.android.tools.build:gradle:3.5.2") + ext { + buildToolsVersion = "28.0.3" + minSdkVersion = 16 + compileSdkVersion = 28 + targetSdkVersion = 28 + } + repositories { + google() + jcenter() + } + dependencies { + classpath("com.android.tools.build:gradle:3.5.2") - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } } allprojects { - repositories { - mavenLocal() - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url("$rootDir/../node_modules/react-native/android") - } - maven { - // Android JSC is installed from npm - url("$rootDir/../node_modules/jsc-android/dist") - } - - google() - jcenter() - maven { url 'https://www.jitpack.io' } + repositories { + mavenLocal() + maven { + // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + url("$rootDir/../node_modules/react-native/android") + } + maven { + // Android JSC is installed from npm + url("$rootDir/../node_modules/jsc-android/dist") } + + google() + jcenter() + maven { url 'https://www.jitpack.io' } + } } diff --git a/example/ios/AgoraExample.xcodeproj/project.pbxproj b/example/ios/AgoraExample.xcodeproj/project.pbxproj index 72af6b196..77cf996d3 100644 --- a/example/ios/AgoraExample.xcodeproj/project.pbxproj +++ b/example/ios/AgoraExample.xcodeproj/project.pbxproj @@ -202,13 +202,17 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-AgoraExample/Pods-AgoraExample-frameworks.sh", - "${PODS_ROOT}/AgoraRtcEngine_iOS_Crypto/Agora_Native_SDK_for_iOS_FULL/libs/AgoraRtcKit.framework", - "${PODS_ROOT}/AgoraRtcEngine_iOS_Crypto/Agora_Native_SDK_for_iOS_FULL/libs/AgoraRtcCryptoLoader.framework", + "${PODS_ROOT}/AgoraRtcEngine_iOS/AgoraRtcKit.framework", + "${PODS_ROOT}/AgoraRtcEngine_iOS/Agorafdkaac.framework", + "${PODS_ROOT}/AgoraRtcEngine_iOS/Agoraffmpeg.framework", + "${PODS_ROOT}/AgoraRtcEngine_iOS/AgoraSoundTouch.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AgoraRtcKit.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AgoraRtcCryptoLoader.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Agorafdkaac.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Agoraffmpeg.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AgoraSoundTouch.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/example/src/examples/basic/JoinChannelAudio.tsx b/example/src/examples/basic/JoinChannelAudio.tsx index a53d288b6..f9ee6d185 100644 --- a/example/src/examples/basic/JoinChannelAudio.tsx +++ b/example/src/examples/basic/JoinChannelAudio.tsx @@ -70,7 +70,7 @@ export default class JoinChannelAudio extends Component<{}, State, any> { config.token, this.state.channelId, null, - 0 + config.uid ); }; diff --git a/example/src/examples/basic/JoinChannelVideo.tsx b/example/src/examples/basic/JoinChannelVideo.tsx index 13bf561ac..67e96fe19 100644 --- a/example/src/examples/basic/JoinChannelVideo.tsx +++ b/example/src/examples/basic/JoinChannelVideo.tsx @@ -91,7 +91,7 @@ export default class JoinChannelAudio extends Component<{}, State, any> { config.token, this.state.channelId, null, - 0 + config.uid ); }; diff --git a/example/src/examples/basic/StringUid.tsx b/example/src/examples/basic/StringUid.tsx index 2dc7a45e9..85b5a953e 100644 --- a/example/src/examples/basic/StringUid.tsx +++ b/example/src/examples/basic/StringUid.tsx @@ -18,7 +18,7 @@ export default class StringUid extends Component<{}, State, any> { super(props); this.state = { channelId: config.channelId, - stringUid: '', + stringUid: config.stringUid, isJoined: false, }; } diff --git a/ios/RCTAgora/Base/BeanCovertor.swift b/ios/RCTAgora/Base/BeanCovertor.swift index 6ffef37e5..bbb869ac7 100644 --- a/ios/RCTAgora/Base/BeanCovertor.swift +++ b/ios/RCTAgora/Base/BeanCovertor.swift @@ -305,3 +305,13 @@ func mapToEncryptionConfig(_ map: Dictionary) -> AgoraEncryptionCon } return encryptionConfig } + +func mapToClientRoleOptions(_ map: Dictionary) -> AgoraClientRoleOptions { + let clientRoleOptions = AgoraClientRoleOptions() + if let audienceLatencyLevel = map["audienceLatencyLevel"] as? Int { + if let audienceLatencyLevel = AgoraAudienceLatencyLevelType(rawValue: audienceLatencyLevel) { + clientRoleOptions.audienceLatencyLevel = audienceLatencyLevel + } + } + return clientRoleOptions +} diff --git a/ios/RCTAgora/Base/RtcChannel.swift b/ios/RCTAgora/Base/RtcChannel.swift index 60367599d..08944703c 100644 --- a/ios/RCTAgora/Base/RtcChannel.swift +++ b/ios/RCTAgora/Base/RtcChannel.swift @@ -171,7 +171,12 @@ class RtcChannelManager: NSObject, RtcChannelInterface { } @objc func setClientRole(_ params: NSDictionary, _ callback: Callback) { - callback.code(self[params["channelId"] as! String]?.setClientRole(AgoraClientRole(rawValue: params["role"] as! Int)!)) + let role = AgoraClientRole(rawValue: params["role"] as! Int)! + if let options = params["options"] as? Dictionary { + callback.code(self[params["channelId"] as! String]?.setClientRole(role, options: mapToClientRoleOptions(options))) + return + } + callback.code(self[params["channelId"] as! String]?.setClientRole(role)) } @objc func joinChannel(_ params: NSDictionary, _ callback: Callback) { diff --git a/ios/RCTAgora/Base/RtcEngine.swift b/ios/RCTAgora/Base/RtcEngine.swift index e8bf9c70d..c3921c735 100644 --- a/ios/RCTAgora/Base/RtcEngine.swift +++ b/ios/RCTAgora/Base/RtcEngine.swift @@ -188,8 +188,10 @@ protocol RtcEngineAudioEffectInterface { } protocol RtcEngineVoiceChangerInterface { + @available(*, deprecated) func setLocalVoiceChanger(_ params: NSDictionary, _ callback: Callback) + @available(*, deprecated) func setLocalVoiceReverbPreset(_ params: NSDictionary, _ callback: Callback) func setLocalVoicePitch(_ params: NSDictionary, _ callback: Callback) @@ -197,6 +199,12 @@ protocol RtcEngineVoiceChangerInterface { func setLocalVoiceEqualization(_ params: NSDictionary, _ callback: Callback) func setLocalVoiceReverb(_ params: NSDictionary, _ callback: Callback) + + func setAudioEffectPreset(_ params: NSDictionary, _ callback: Callback) + + func setVoiceBeautifierPreset(_ params: NSDictionary, _ callback: Callback) + + func setAudioEffectParameters(_ params: NSDictionary, _ callback: Callback) } protocol RtcEngineVoicePositionInterface { @@ -282,8 +290,10 @@ protocol RtcEngineWatermarkInterface { } protocol RtcEngineEncryptionInterface { + @available(*, deprecated) func setEncryptionSecret(_ params: NSDictionary, _ callback: Callback) + @available(*, deprecated) func setEncryptionMode(_ params: NSDictionary, _ callback: Callback) func enableEncryption(_ params: NSDictionary, _ callback: Callback) @@ -377,7 +387,12 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func setClientRole(_ params: NSDictionary, _ callback: Callback) { - callback.code(engine?.setClientRole(AgoraClientRole(rawValue: params["role"] as! Int)!)) + let role = AgoraClientRole(rawValue: params["role"] as! Int)! + if let options = params["options"] as? Dictionary { + callback.code(engine?.setClientRole(role, options: mapToClientRoleOptions(options))) + return + } + callback.code(engine?.setClientRole(role)) } @objc func joinChannel(_ params: NSDictionary, _ callback: Callback) { @@ -693,6 +708,18 @@ class RtcEngineManager: NSObject, RtcEngineInterface { @objc func setLocalVoiceReverb(_ params: NSDictionary, _ callback: Callback) { callback.code(engine?.setLocalVoiceReverbOf(AgoraAudioReverbType(rawValue: params["reverbKey"] as! Int)!, withValue: params["value"] as! Int)) } + + @objc func setAudioEffectPreset(_ params: NSDictionary, _ callback: Callback) { + callback.code(engine?.setAudioEffectPreset(AgoraAudioEffectPreset(rawValue: params["preset"] as! Int)!)) + } + + @objc func setVoiceBeautifierPreset(_ params: NSDictionary, _ callback: Callback) { + callback.code(engine?.setVoiceBeautifierPreset(AgoraVoiceBeautifierPreset(rawValue: params["preset"] as! Int)!)) + } + + @objc func setAudioEffectParameters(_ params: NSDictionary, _ callback: Callback) { + callback.code(engine?.setAudioEffectParameters(AgoraAudioEffectPreset(rawValue: params["preset"] as! Int)!, param1: params["param1"] as! Int32, param2: params["param2"] as! Int32)) + } @objc func enableSoundPositionIndication(_ params: NSDictionary, _ callback: Callback) { callback.code(engine?.enableSoundPositionIndication(params["enabled"] as! Bool)) diff --git a/package.json b/package.json index 4dc466a0d..12b078a9d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-agora", - "version": "3.1.6", + "version": "3.2.0", "description": "Agora RTC SDK For React Native", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/react-native-agora.podspec b/react-native-agora.podspec index 4e605735b..2fbbd0ea2 100644 --- a/react-native-agora.podspec +++ b/react-native-agora.podspec @@ -20,5 +20,5 @@ Pod::Spec.new do |s| s.swift_version = "4.0" s.dependency "React" - s.dependency "AgoraRtcEngine_iOS_Crypto", "3.1.2" + s.dependency "AgoraRtcEngine_iOS", "3.2.1" end diff --git a/src/common/Classes.ts b/src/common/Classes.ts index 3370eeba5..babfb5f4b 100644 --- a/src/common/Classes.ts +++ b/src/common/Classes.ts @@ -1,4 +1,5 @@ import type { + AudienceLatencyLevelType, AudioChannel, AudioCodecProfileType, AudioSampleRateType, @@ -300,14 +301,16 @@ export class VideoEncoderConfiguration { degradationPrefer?: DegradationPreference; mirrorMode?: VideoMirrorMode; }) { - this.dimensions = params?.dimensions; - this.frameRate = params?.frameRate; - this.minFrameRate = params?.minFrameRate; - this.bitrate = params?.bitrate; - this.minBitrate = params?.minBitrate; - this.orientationMode = params?.orientationMode; - this.degradationPrefer = params?.degradationPrefer; - this.mirrorMode = params?.mirrorMode; + if (params) { + this.dimensions = params.dimensions; + this.frameRate = params.frameRate; + this.minFrameRate = params.minFrameRate; + this.bitrate = params.bitrate; + this.minBitrate = params.minBitrate; + this.orientationMode = params.orientationMode; + this.degradationPrefer = params.degradationPrefer; + this.mirrorMode = params.mirrorMode; + } } } @@ -340,10 +343,12 @@ export class BeautyOptions { smoothnessLevel?: number; rednessLevel?: number; }) { - this.lighteningContrastLevel = params?.lighteningContrastLevel; - this.lighteningLevel = params?.lighteningLevel; - this.smoothnessLevel = params?.smoothnessLevel; - this.rednessLevel = params?.rednessLevel; + if (params) { + this.lighteningContrastLevel = params.lighteningContrastLevel; + this.lighteningLevel = params.lighteningLevel; + this.smoothnessLevel = params.smoothnessLevel; + this.rednessLevel = params.rednessLevel; + } } } @@ -450,11 +455,13 @@ export class TranscodingUser { this.uid = uid; this.x = x; this.y = y; - this.width = params?.width; - this.height = params?.height; - this.zOrder = params?.zOrder; - this.alpha = params?.alpha; - this.audioChannel = params?.audioChannel; + if (params) { + this.width = params.width; + this.height = params.height; + this.zOrder = params.zOrder; + this.alpha = params.alpha; + this.audioChannel = params.audioChannel; + } } } @@ -586,21 +593,23 @@ export class LiveTranscoding { userConfigExtraInfo?: string; } ) { - this.width = params?.width; - this.height = params?.height; - this.videoBitrate = params?.videoBitrate; - this.videoFramerate = params?.videoFramerate; - this.lowLatency = params?.lowLatency; - this.videoGop = params?.videoGop; - this.watermark = params?.watermark; - this.backgroundImage = params?.backgroundImage; - this.audioSampleRate = params?.audioSampleRate; - this.audioBitrate = params?.audioBitrate; - this.audioChannels = params?.audioChannels; - this.audioCodecProfile = params?.audioCodecProfile; - this.videoCodecProfile = params?.videoCodecProfile; - this.backgroundColor = params?.backgroundColor; - this.userConfigExtraInfo = params?.userConfigExtraInfo; + if (params) { + this.width = params.width; + this.height = params.height; + this.videoBitrate = params.videoBitrate; + this.videoFramerate = params.videoFramerate; + this.lowLatency = params.lowLatency; + this.videoGop = params.videoGop; + this.watermark = params.watermark; + this.backgroundImage = params.backgroundImage; + this.audioSampleRate = params.audioSampleRate; + this.audioBitrate = params.audioBitrate; + this.audioChannels = params.audioChannels; + this.audioCodecProfile = params.audioCodecProfile; + this.videoCodecProfile = params.videoCodecProfile; + this.backgroundColor = params.backgroundColor; + this.userConfigExtraInfo = params.userConfigExtraInfo; + } this.transcodingUsers = transcodingUsers; } } @@ -623,8 +632,10 @@ export class ChannelMediaInfo { uid: number; constructor(uid: number, params?: { channelName?: string; token?: string }) { - this.channelName = params?.channelName; - this.token = params?.token; + if (params) { + this.channelName = params.channelName; + this.token = params.token; + } this.uid = uid; } } @@ -814,14 +825,16 @@ export class LiveInjectStreamConfig { audioBitrate?: number; audioChannels?: AudioChannel; }) { - this.width = params?.width; - this.height = params?.height; - this.videoGop = params?.videoGop; - this.videoFramerate = params?.videoFramerate; - this.videoBitrate = params?.videoBitrate; - this.audioSampleRate = params?.audioSampleRate; - this.audioBitrate = params?.audioBitrate; - this.audioChannels = params?.audioChannels; + if (params) { + this.width = params.width; + this.height = params.height; + this.videoGop = params.videoGop; + this.videoFramerate = params.videoFramerate; + this.videoBitrate = params.videoBitrate; + this.audioSampleRate = params.audioSampleRate; + this.audioBitrate = params.audioBitrate; + this.audioChannels = params.audioChannels; + } } } @@ -1214,6 +1227,10 @@ export interface RemoteAudioStats { networkTransportDelay: number; /** * Network delay (ms) from the receiver to the jitter buffer. + * + * **Note** + * + * When the receiver is an audience member and `AudienceLatencyLevelType` is `1`, this parameter does not take effect. */ jitterBufferDelay: number; /** @@ -1348,3 +1365,19 @@ export interface FacePositionInfo { */ distance: number; } + +/** + * The detailed options of a user. + * + * @since v3.2.0. + */ +export class ClientRoleOptions { + /** + * The latency level of an audience member in a live interactive streaming. See {@link AudienceLatencyLevelType}. + */ + audienceLatencyLevel: AudienceLatencyLevelType; + + constructor(audienceLatencyLevel: AudienceLatencyLevelType) { + this.audienceLatencyLevel = audienceLatencyLevel; + } +} diff --git a/src/common/Enums.ts b/src/common/Enums.ts index 40bb33011..dc16f0ae9 100644 --- a/src/common/Enums.ts +++ b/src/common/Enums.ts @@ -389,7 +389,7 @@ export enum AudioReverbPreset { */ FX_VOCAL_CONCERT = 0x00100002, /** - * The reverberation style typical of an uncle’s voice. + * The reverberation style typical of a middle-aged man’s voice. */ FX_UNCLE = 0x00100003, /** @@ -470,29 +470,41 @@ export enum AudioSampleRateType { */ export enum AudioScenario { /** - * 0: Default. + * 0: Default audio scenario. */ Default = 0, /** - * 1: Entertainment scenario, supporting voice during gameplay. + * 1: Entertainment scenario where users need to frequently switch the user role. */ ChatRoomEntertainment = 1, /** - * 2: Education scenario, prioritizing fluency and stability. + * 2: Education scenario where users want smoothness and stability. */ Education = 2, /** - * 3: Live gaming scenario, enabling the gaming audio effects in the speaker mode in a live broadcast scenario. Choose this scenario for high-fidelity music playback. + * 3: High-quality audio chatroom scenario where hosts mainly play music. */ GameStreaming = 3, /** - * 4: Showroom scenario, optimizing the audio quality with external professional equipment. + * 4: Showroom scenario where a single host wants high-quality audio. */ ShowRoom = 4, /** - * 5: Gaming scenario. + * 5: Gaming scenario for group chat that only contains the human voice. */ ChatRoomGaming = 5, + /** + * IoT (Internet of Things) scenario where users use IoT devices with low power consumption. + * + * @since v3.2.0. + */ + IOT = 6, + /** + * Meeting scenario that mainly contains the human voice. + * + * @since v3.2.0. + */ + MEETING = 8, } /** @@ -1150,7 +1162,7 @@ export enum ErrorCode { */ PublishStreamNotFound = 155, /** - * 156: The format of the RTMP stream URL is not supported. Check whether the URL format is correct. + * 156: The format of the RTMP or RTMPS stream URL is not supported. Check whether the URL format is correct. */ PublishStreamFormatNotSuppported = 156, /** @@ -1525,7 +1537,7 @@ export enum NetworkType { */ export enum RtmpStreamingErrorCode { /** - * 0: The RTMP streaming publishes successfully. + * 0: The RTMP or RTMPS streaming publishes successfully. */ OK = 0, /** @@ -1535,11 +1547,11 @@ export enum RtmpStreamingErrorCode { */ InvalidParameters = 1, /** - * 2: The RTMP streaming is encrypted and cannot be published. + * 2: The RTMP or RTMPS streaming is encrypted and cannot be published. */ EncryptedStreamNotAllowed = 2, /** - * 3: Timeout for the RTMP streaming. Call the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method to publish the streaming again. + * 3: Timeout for the RTMP or RTMPS streaming. Call the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method to publish the streaming again. */ ConnectionTimeout = 3, /** @@ -1547,11 +1559,11 @@ export enum RtmpStreamingErrorCode { */ InternalServerError = 4, /** - * 5: An error occurs in the RTMP server. + * 5: An error occurs in the CDN server. */ RtmpServerError = 5, /** - * 6: The RTMP streaming publishes too frequently. + * 6: The RTMP or RTMPS streaming publishes too frequently. */ TooOften = 6, /** @@ -1563,36 +1575,36 @@ export enum RtmpStreamingErrorCode { */ NotAuthorized = 8, /** - * 9: Agora’s server fails to find the RTMP streaming. + * 9: Agora’s server fails to find the RTMP or RTMPS streaming. */ StreamNotFound = 9, /** - * 10: The format of the RTMP streaming URL is not supported. Check whether the URL format is correct. + * 10: The format of the RTMP or RTMPS streaming URL is not supported. Check whether the URL format is correct. */ FormatNotSupported = 10, } /** - * The RTMP streaming state. + * The RTMP or RTMPS streaming state. */ export enum RtmpStreamingState { /** - * 0: The RTMP streaming has not started or has ended. This state is also triggered after you - * remove an RTMP address from the CDN by calling [`removePublishStreamUrl`]{@link RtcEngine.removePublishStreamUrl}. + * 0: The RTMP or RTMPS streaming has not started or has ended. This state is also triggered after you + * remove an RTMP or RTMPS stream* from the CDN by calling [`removePublishStreamUrl`]{@link RtcEngine.removePublishStreamUrl}. */ Idle = 0, /** - * 1: The SDK is connecting to Agora’s streaming server and the RTMP server. + * 1: The SDK is connecting to Agora’s streaming server and the CDN server. * This state is triggered after you call the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method. */ Connecting = 1, /** - * 2: The RTMP streaming is being published. The SDK successfully publishes the RTMP streaming and returns this state. + * 2: The RTMP or RTMPS streaming is being published. The SDK successfully publishes the RTMP or RTMPS streaming and returns this state. */ Running = 2, /** - * 3: The RTMP streaming is recovering. When exceptions occur to the CDN, or the streaming is interrupted, - * the SDK attempts to resume RTMP streaming and returns this state. + * 3: The RTMP or RTMPS streaming is recovering. When exceptions occur to the CDN, or the streaming is interrupted, + * the SDK attempts to resume RTMP or RTMPS streaming and returns this state. * * - If the SDK successfully resumes the streaming, [`Running`]{@link RtmpStreamingState.Running} returns. * - If the streaming does not resume within 60 seconds or server errors occur, @@ -1602,8 +1614,8 @@ export enum RtmpStreamingState { */ Recovering = 3, /** - * 4: The RTMP streaming fails. See the errorCode parameter for the detailed error information. - * You can also call the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method to publish the RTMP streaming again. + * 4: The RTMP or RTMPS streaming fails. See the errorCode parameter for the detailed error information. + * You can also call the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method to publish the RTMP or RTMPS streaming again. */ Failure = 4, } @@ -2205,17 +2217,29 @@ export enum WarningCode { */ AdmInconsistentDevices = 1042, /** - * 1051: Audio Device Module: howling is detected. + * 1051: Audio Device Module: Howling is detected. */ ApmHowling = 1051, /** - * 1052: Audio Device Module: the device is in the glitch state. + * 1052: Audio Device Module: The device is in the glitch state. */ AdmGlitchState = 1052, /** * 1053: Audio processing module: A residual echo is detected, which may be caused by the belated scheduling of system threads or the signal overflow. */ ApmResidualEcho = 1053, + /** + * 1610: Super-resolution warning: The origin resolution of the remote video is beyond the range where the super-resolution algorithm can be applied. + */ + SuperResolutionStreamOverLimitation = 1610, + /** + * 1611: Super-resolution warning: Another user is already using the super-resolution algorithm. + */ + SuperResolutionUserCountOverLimitation = 1611, + /** + * 1612: Super-resolution warning: The device does not support the super-resolution algorithm. + */ + SuperResolutionDeviceNotSupported = 1612, } /** @@ -2331,11 +2355,11 @@ export enum StreamSubscribeState { } /** - * Events during the RTMP streaming. + * Events during the RTMP or RTMPS streaming. */ export enum RtmpStreamingEvent { /** - * 1: An error occurs when you add a background image or a watermark image to the RTMP stream. + * 1: An error occurs when you add a background image or a watermark image to the RTMP or RTMPS stream. */ FailedLoadImage = 1, } @@ -2365,3 +2389,296 @@ export enum AudioSessionOperationRestriction { */ All = 1 << 7, } + +/** + * The options for SDK preset audio effects. + */ +export enum AudioEffectPreset { + /** + * Turn off audio effects and use the original voice. + */ + AudioEffectOff = 0x00000000, + + /** + * An audio effect typical of a KTV venue. + * + * **Note** + * + * To achieve better audio effect quality, Agora recommends calling setAudioProfile and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + RoomAcousticsKTV = 0x02010100, + /** + * An audio effect typical of a concert hall. + * + * **Note** + * + * To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + RoomAcousticsVocalConcert = 0x02010200, + + /** + * An audio effect typical of a recording studio. + * + * **Note** + * + * To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + RoomAcousticsStudio = 0x02010300, + + /** + * An audio effect typical of a vintage phonograph. + * + * **Note** + * + * To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + RoomAcousticsPhonograph = 0x02010400, + + /** + * A virtual stereo effect that renders monophonic audio as stereo audio. + * + * **Note** + * + * Call `setAudioProfile` and set the profile parameter to `MusicStandardStereo(3)` or `MusicHighQualityStereo(5)` + * before setting this enumerator; otherwise, the enumerator setting does not take effect. + */ + RoomAcousticsVirtualStereo = 0x02010500, + + /** + * A more spatial audio effect. + * + * **Note** + * + * To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + RoomAcousticsSpacial = 0x02010600, + + /** + * A more ethereal audio effect. + * + * **Note** + * + * To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + RoomAcousticsEthereal = 0x02010700, + + /** + * A 3D voice effect that makes the voice appear to be moving around the user. + * The default cycle period of the 3D voice effect is 10 seconds. To change the cycle period, call `setAudioEffectParameters` after this method. + * + * **Note** + * + * - Call `setAudioProfile` and set the profile parameter to `MusicStandardStereo(3)` or `MusicHighQualityStereo(5)` before setting this enumerator; + * otherwise, the enumerator setting does not take effect. + * - If the 3D voice effect is enabled, users need to use stereo audio playback devices to hear the anticipated voice effect. + */ + RoomAcoustics3DVoice = 0x02010800, + + /** + * The voice of a middle-aged man. + * + * **Note** + * + * - Agora recommends using this enumerator to process a male-sounding voice; otherwise, you may not hear the anticipated voice effect. + * - To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + VoiceChangerEffectUncle = 0x02020100, + + /** + * The voice of an old man. + * + * **Note** + * + * - Agora recommends using this enumerator to process a male-sounding voice; otherwise, you may not hear the anticipated voice effect. + * - To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + VoiceChangerEffectOldMan = 0x02020200, + + /** + * The voice of a boy. + * + * **Note** + * + * - Agora recommends using this enumerator to process a male-sounding voice; otherwise, you may not hear the anticipated voice effect. + * - To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + VoiceChangerEffectBoy = 0x02020300, + + /** + * The voice of a young woman. + * + * **Note** + * + * - Agora recommends using this enumerator to process a male-sounding voice; otherwise, you may not hear the anticipated voice effect. + * - To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + VoiceChangerEffectSister = 0x02020400, + + /** + * The voice of a girl. + * + * **Note** + * + * - Agora recommends using this enumerator to process a male-sounding voice; otherwise, you may not hear the anticipated voice effect. + * - To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + VoiceChangerEffectGirl = 0x02020500, + + /** + * The voice of Pig King, a character in Journey to the West who has a voice like a growling bear. + * + * **Note** + * + * To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + VoiceChangerEffectPigKing = 0x02020600, + + /** + * The voice of Hulk. + * + * **Note** + * + * To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + VoiceChangerEffectHulk = 0x02020700, + + /** + * An audio effect typical of R&B music. + * + * **Note** + * + * Call `setAudioProfile` and set the profile parameter to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator; + * otherwise, the enumerator setting does not take effect. + */ + StyleTransformationRnB = 0x02030100, + + /** + * An audio effect typical of popular music. + * + * **Note** + * + * Call `setAudioProfile` and set the profile parameter to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator; + * otherwise, the enumerator setting does not take effect. + */ + StyleTransformationPopular = 0x02030200, + + /** + * A pitch correction effect that corrects the user's pitch based on the pitch of the natural C major scale. + * To change the basic mode and tonic pitch, call `setAudioEffectParameters` after this method. + * + * **Note** + * + * To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter + * to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + */ + PitchCorrection = 0x02040100, +} + +/** + * The options for SDK preset voice beautifier effects. + */ +export enum VoiceBeautifierPreset { + /** + * Turn off voice beautifier effects and use the original voice. + */ + VoiceBeautifierOff = 0x00000000, + + /** + * A more magnetic voice. + * + * **Note** + * + * Agora recommends using this enumerator to process a male-sounding voice; otherwise, you may experience vocal distortion. + */ + ChatBeautifierMagnetic = 0x01010100, + + /** + * A fresher voice. + * + * **Note** + * + * Agora recommends using this enumerator to process a female-sounding voice; otherwise, you may experience vocal distortion. + */ + ChatBeautifierFresh = 0x01010200, + + /** + * A more vital voice. + * + * **Note** + * + * Agora recommends using this enumerator to process a female-sounding voice; otherwise, you may experience vocal distortion. + */ + ChatBeautifierVitality = 0x01010300, + + /** + * A more vigorous voice. + */ + TimbreTransformationVigorous = 0x01030100, + + /** + * A deeper voice. + */ + TimbreTransformationDeep = 0x01030200, + + /** + * A mellower voice. + */ + TimbreTransformationMellow = 0x01030300, + + /** + * A falsetto voice. + */ + TimbreTransformationFalsetto = 0x01030400, + + /** + * A fuller voice. + */ + TimbreTransformationFull = 0x01030500, + + /** + * A clearer voice. + */ + TimbreTransformationClear = 0x01030600, + + /** + * A more resounding voice. + */ + TimbreTransformationResounding = 0x01030700, + + /** + * A more ringing voice. + */ + TimbreTransformationRinging = 0x01030800, +} + +/** + * The latency level of an audience member in interactive live streaming. + * + * **Note** + * + * Takes effect only when the user role is `Broadcaster`. + */ +export enum AudienceLatencyLevelType { + /** + * 1: Low latency. + */ + LowLatency = 1, + + /** + * 2: (Default) Ultra low latency. + */ + UltraLowLatency = 2, +} diff --git a/src/common/RtcChannel.native.ts b/src/common/RtcChannel.native.ts index 2eae8c622..b31c562dd 100644 --- a/src/common/RtcChannel.native.ts +++ b/src/common/RtcChannel.native.ts @@ -3,15 +3,18 @@ import { NativeEventEmitter, NativeModules } from 'react-native'; import type { ChannelMediaOptions, ChannelMediaRelayConfiguration, - ClientRole, - ConnectionStateType, + ClientRoleOptions, EncryptionConfig, - EncryptionMode, LiveInjectStreamConfig, LiveTranscoding, +} from './Classes'; +import type { + ClientRole, + ConnectionStateType, + EncryptionMode, UserPriority, VideoStreamType, -} from '../Types'; +} from './Enums'; import type { Listener, RtcChannelEvents, Subscription } from './RtcEvents'; const { @@ -111,6 +114,11 @@ export default class RtcChannel implements RtcChannelInterface { /** * Destroys the [`RtcChannel`]{@link RtcChannel} instance. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 7(NotInitialized): The `RtcChannel` instance is not initialized before calling this method. */ destroy(): Promise { this.removeAllListeners(); @@ -189,19 +197,30 @@ export default class RtcChannel implements RtcChannelInterface { } /** - * Sets the role of a user. + * Sets the role of a user in live interactive streaming. * - * This method sets the role of a user, such as a host or an audience member. In a `LiveBroadcasting` channel, - * only a host can call the [`publish`]{@link publish} method in the [`RtcChannel`]{@link RtcChannel} class. - * - * A successful call of this method triggers the following callbacks: + * You can call this method either before or after joining the channel to set the user role as audience or host. If you call this method to switch the user role after joining the channel, the SDK triggers the following callbacks: * - The local client: [`ClientRoleChanged`]{@link RtcChannelEvents.ClientRoleChanged}. - * - The remote client: [`UserJoined`]{@link RtcChannelEvents.UserJoined} - * or [`UserOffline(BecomeAudience)`]{@link UserOfflineReason.BecomeAudience}. - * @param role The role of the user. + * - The remote client: [`UserJoined`]{@link RtcChannelEvents.UserJoined} or [`UserOffline(BecomeAudience)`]{@link UserOfflineReason.BecomeAudience}. + * + * **Note** + * - This method applies to the `LiveBroadcasting` profile only (when the `profile` parameter in `setChannelProfile` is set as `LiveBroadcasting`). + * - As of v3.2.0, this method can set the user level in addition to the user role. + * - The user role determines the permissions that the SDK grants to a user, such as permission to send local streams, receive remote streams, and push streams to a CDN address. + * - The user level determines the level of services that a user can enjoy within the permissions of the user's role. For example, an audience can choose to receive remote streams with low latency or ultra low latency. **Levels affect prices**. + * + * @param role The role of a user in interactive live streaming. See {@link ClientRole}. + * @param options? The detailed options of a user, including user level. See {@link ClientRoleOptions}. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 1(Failed): A general error occurs (no specified reason). + * - 2(InvalidArgument): The parameter is invalid. + * - 7(NotInitialized): The SDK is not initialized. */ - setClientRole(role: ClientRole): Promise { - return this._callMethod('setClientRole', { role }); + setClientRole(role: ClientRole, options?: ClientRoleOptions): Promise { + return this._callMethod('setClientRole', { role, options }); } /** @@ -213,12 +232,24 @@ export default class RtcChannel implements RtcChannelInterface { * - If you want to join the same channel from different devices, ensure that the UIDs in all devices are different. * - Ensure that the app ID you use to generate the token is the same with the app ID used when creating the [`RtcEngine`]{@link RtcEngine} instance. * + * Once the user joins the channel (switches to another channel), the user subscribes to the audio and video streams of all the other users in the channel by default, giving rise to usage and billing calculation. If you do not want to subscribe to a specified stream or all remote streams, call the `mute` methods accordingly. + * * @param token The token generated at your server. * - In situations not requiring high security: You can use the temporary token generated at Console. For details, see [Get a temporary token](https://docs.agora.io/en/Agora%20Platform/token?platform=All%20Platforms#get-a-temporary-token). * - In situations requiring high security: Set it as the token generated at your server. For details, see [Generate a token](https://docs.agora.io/en/Agora%20Platform/token?platform=All%20Platforms#generatetoken). * @param optionalInfo Additional information about the channel. This parameter can be set as null. Other users in the channel do not receive this information. * @param optionalUid The user ID. A 32-bit unsigned integer with a value ranging from 1 to (232-1). This parameter must be unique. If uid is not assigned (or set as 0), the SDK assigns a uid and reports it in the [`JoinChannelSuccess`]{@link RtcChannelEvents.JoinChannelSuccess} callback. The app must maintain this user ID. * @param options The channel media options. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): The parameter is invalid. + * - 3(NotReady): The SDK fails to be initialized. You can try re-initializing the SDK. + * - 5(Refused): The request is rejected. Possible reasons: + * - You have created an `RtcChannel` object with the same channel name. + * - You have joined and published a stream in a channel created by the `RtcChannel` object. + * - 7(NotInitialized): The SDK is not initialized. */ joinChannel( token: string | undefined | null, @@ -243,6 +274,8 @@ export default class RtcChannel implements RtcChannelInterface { * - If you want to join the same channel from different devices, ensure that the user accounts in all devices are different. * - Ensure that the app ID you use to generate the token is the same with the app ID used when creating the [`RtcEngine`]{@link RtcEngine} instance. * + * Once the user joins the channel (switches to another channel), the user subscribes to the audio and video streams of all the other users in the channel by default, giving rise to usage and billing calculation. If you do not want to subscribe to a specified stream or all remote streams, call the `mute` methods accordingly. + * * @param token The token generated at your server. * - In situations not requiring high security: You can use the temporary token generated at Console. For details, see [Get a temporary token](https://docs.agora.io/en/Agora%20Platform/token?platform=All%20Platforms#get-a-temporary-token). * - In situations requiring high security: Set it as the token generated at your server. For details, see [Generate a token](https://docs.agora.io/en/Agora%20Platform/token?platform=All%20Platforms#generatetoken). @@ -253,6 +286,13 @@ export default class RtcChannel implements RtcChannelInterface { * - The space character. * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". * @param options The channel media options. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): The parameter is invalid. + * - 3(NotReady): The SDK fails to be initialized. You can try re-initializing the SDK. + * - 5(Refused): The request is rejected. */ joinChannelWithUserAccount( token: string | undefined | null, @@ -272,6 +312,13 @@ export default class RtcChannel implements RtcChannelInterface { * A successful call of this method triggers the following callbacks: * - The local client: [`LeaveChannel`]{@link RtcChannelEvents.LeaveChannel}. * - The remote client: [`UserOffline`]{@link RtcChannelEvents.UserOffline}, if the user leaving the channel is in a `Communication` channel, or is a host in a `LiveBroadcasting` channel. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 1(Failed): A general error occurs (no specified reason). + * - 2(InvalidArgument): The parameter is invalid. + * - 7(NotInitialized): The SDK is not initialized. */ leaveChannel(): Promise { return this._callMethod('leaveChannel'); @@ -286,6 +333,13 @@ export default class RtcChannel implements RtcChannelInterface { * * You should get a new token from your server and call this method to renew it. Failure to do so results in the SDK disconnecting from the Agora server. * @param token The new token. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 1(Failed): A general error occurs (no specified reason). + * - 2(InvalidArgument): The parameter is invalid. + * - 7(NotInitialized): The SDK is not initialized. */ renewToken(token: string): Promise { return this._callMethod('renewToken', { token }); @@ -444,7 +498,9 @@ export default class RtcChannel implements RtcChannelInterface { } /** - * Publishes the local stream to the CDN. + * Publishes the local stream to a specified CDN streaming URL. + * + * After calling this method, you can push media streams in RTMP or RTMPS protocol to the CDN. * * This method call triggers the [`RtmpStreamingStateChanged`]{@link RtcChannelEvents.RtmpStreamingStateChanged} * callback on the local client to report the state of adding a local stream to the CDN. @@ -453,30 +509,37 @@ export default class RtcChannel implements RtcChannelInterface { * - Ensure that you enable the RTMP Converter service before using this function. See Prerequisites in *Push Streams to CDN*. * - Ensure that the user joins a channel before calling this method. * - This method can only be called by a host in a `LiveBroadcasting` channel. - * - This method adds only one stream HTTP/HTTPS URL address each time it is called. + * - This method adds only one CDN streaming URL each time it is called. + * - Agora supports pushing media streams in RTMPS protocol to the CDN only when you enable transcoding. * - * @param url The CDN streaming URL in the RTMP format. The maximum length of this parameter is 1024 bytes. The URL address must not contain special characters, such as Chinese language characters. - * @param transcodingEnabled Sets whether transcoding is enabled/disabled. If you set this parameter as true, + * @param url The CDN streaming URL in the RTMP or RTMPS format. The maximum length of this parameter is 1024 bytes. The URL address must not contain special characters, such as Chinese language characters. + * @param transcodingEnabled Whether to enable transcoding. If you set this parameter as true, * ensure that you call the [`setLiveTranscoding`]{@link RtcChannel.setLiveTranscoding} method before this method. * - `true`: Enable transcoding. To transcode the audio or video streams when publishing them to CDN live, often used for combining the audio and video streams of multiple hosts in CDN live. * - `false`: Disable transcoding. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): Invalid parameter, usually because the URL address is null or the string length is 0. + * - 7(NotInitialized): You have not initialized `RtcEngine` when publishing the stream. */ addPublishStreamUrl(url: string, transcodingEnabled: boolean): Promise { return this._callMethod('addPublishStreamUrl', { url, transcodingEnabled }); } /** - * Removes an RTMP stream from the CDN. + * Removes an RTMP or RTMPS stream from the CDN. * - * This method removes the RTMP URL address (added by [`addPublishStreamUrl`]{@link RtcChannel.addPublishStreamUrl}) from a CDN live stream. + * This method removes the CDN streaming URL (added by [`addPublishStreamUrl`]{@link RtcChannel.addPublishStreamUrl}) from a CDN live stream. * The SDK reports the result of this method call in the [`RtmpStreamingStateChanged`]{@link RtcChannelEvents.RtmpStreamingStateChanged} callback. * * **Note** * - Ensure that you enable the RTMP Converter service before using this function. See Prerequisites in *Push Streams to CDN*. * - This method can only be called by a host in a `LiveBroadcasting` channel. - * - This method removes only one stream HTTP/HTTPS URL address each time it is called. + * - This method removes only one CDN streaming URL each time it is called. * - * @param url The RTMP URL address to be removed. The maximum length of this parameter is 1024 bytes. The URL address must not contain special characters, + * @param url The CDN streaming URL to be removed. The maximum length of this parameter is 1024 bytes. The URL address must not contain special characters, * such as Chinese language characters. */ removePublishStreamUrl(url: string): Promise { @@ -495,6 +558,7 @@ export default class RtcChannel implements RtcChannelInterface { * - Ensure that the user joins a channel before calling this method. * - This method can only be called by a host in a `LiveBroadcasting` channel. * - Ensure that you call this method before calling the [`addPublishStreamUrl`]{@link RtcChannel.addPublishStreamUrl} method. + * - Agora supports pushing media streams in RTMPS protocol to the CDN only when you enable transcoding. * * @param transcoding Sets the CDN live audio/video transcoding settings. */ @@ -667,7 +731,7 @@ export default class RtcChannel implements RtcChannelInterface { * All users in the same channel must use the same encryption mode and encryption key. Once all users leave the channel, the encryption key of this channel is automatically cleared. * * **Note** - * - If you enable the built-in encryption, you cannot use the RTMP streaming function. + * - If you enable the built-in encryption, you cannot use the RTMP or RTMPS streaming function. * - Agora supports four encryption modes. If you choose an encryption mode (excepting `SM4128ECB` mode), you need to add an external encryption library when integrating the SDK. For details, see the advanced guide *Channel Encryption*. * * @@ -675,6 +739,13 @@ export default class RtcChannel implements RtcChannelInterface { * - `true`: Enable the built-in encryption. * - `false`: Disable the built-in encryption. * @param config Configurations of built-in encryption schemas. See [`EncryptionConfig`]{@link EncryptionConfig}. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): An invalid parameter is used. Set the parameter with a valid value. + * - 4(NotSupported): The encryption mode is incorrect or the SDK fails to load the external encryption library. Check the enumeration or reload the external encryption library. + * - 7(NotInitialized): The SDK is not initialized. Initialize the `RtcEngine` instance before calling this method. */ enableEncryption(enabled: boolean, config: EncryptionConfig): Promise { return this._callMethod('enableEncryption', { enabled, config }); @@ -743,6 +814,14 @@ export default class RtcChannel implements RtcChannelInterface { * - Supported FLV audio codec type: AAC. * - Supported FLV video codec type: H264 (AVC). * @param config The [`LiveInjectStreamConfig`]{@link LiveInjectStreamConfig} object, which contains the configuration information for the added voice or video stream. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): The injected URL does not exist. Call this method again to inject the stream and ensure that the URL is valid. + * - 3(NotReady): The user is not in the channel. + * - 4(NotSupported): The channel profile is not `LiveBroadcasting`. Call the `setChannelProfile` method and set the channel profile to `LiveBroadcasting` before calling this method. + * - 7(NotInitialized): The SDK is not initialized. Initialize the `RtcEngine` instance before calling this method. */ addInjectStreamUrl( url: string, @@ -784,7 +863,7 @@ export default class RtcChannel implements RtcChannelInterface { * - `false`: The recipients do not receive the data in the sent order. * @returns * - Returns the stream ID, if the method call is successful. - * - < 0: Failure. The error code is related to the integer displayed in [Error Codes]{@link ErrorCode}. + * - Error codes: Failure. The error code is related to the integer displayed in [Error Codes]{@link ErrorCode}. */ createDataStream(reliable: boolean, ordered: boolean): Promise { return this._callMethod('createDataStream', { reliable, ordered }); @@ -828,7 +907,7 @@ interface RtcChannelInterface RtcStreamMessageInterface { destroy(): Promise; - setClientRole(role: ClientRole): Promise; + setClientRole(role: ClientRole, options?: ClientRoleOptions): Promise; joinChannel( token: string | undefined | null, diff --git a/src/common/RtcEngine.native.ts b/src/common/RtcEngine.native.ts index ef0419511..1b57efb5d 100644 --- a/src/common/RtcEngine.native.ts +++ b/src/common/RtcEngine.native.ts @@ -1,7 +1,21 @@ import { NativeEventEmitter, NativeModules } from 'react-native'; +import type { + BeautyOptions, + CameraCapturerConfiguration, + ChannelMediaRelayConfiguration, + ClientRoleOptions, + EncryptionConfig, + LastmileProbeConfig, + LiveInjectStreamConfig, + LiveTranscoding, + UserInfo, + VideoEncoderConfiguration, + WatermarkOptions, +} from './Classes'; import { AreaCode, + AudioEffectPreset, AudioEqualizationBandFrequency, AudioProfile, AudioRecordingQuality, @@ -11,25 +25,16 @@ import { AudioScenario, AudioSessionOperationRestriction, AudioVoiceChanger, - BeautyOptions, - CameraCapturerConfiguration, - ChannelMediaRelayConfiguration, ChannelProfile, ClientRole, ConnectionStateType, - EncryptionConfig, EncryptionMode, - LastmileProbeConfig, - LiveInjectStreamConfig, - LiveTranscoding, LogFilter, StreamFallbackOptions, - UserInfo, UserPriority, - VideoEncoderConfiguration, VideoStreamType, - WatermarkOptions, -} from '../Types'; + VoiceBeautifierPreset, +} from './Enums'; import type { Listener, RtcEngineEvents, Subscription } from './RtcEvents'; import RtcChannel from './RtcChannel.native'; @@ -108,6 +113,7 @@ export default class RtcEngine implements RtcEngineInterface { * @returns * - The `RtcEngine` instance, if the method call succeeds. * - The error code, if the method call fails. + * - 101(InvalidAppId): The app ID is invalid. Check if it is in the correct format. */ static async create(appId: string): Promise { return RtcEngine.createWithAreaCode(appId, AreaCode.GLOB); @@ -134,6 +140,7 @@ export default class RtcEngine implements RtcEngineInterface { * @returns * - The `RtcEngine` instance, if the method call succeeds. * - The error code, if the method call fails. + * - 101(InvalidAppId): The app ID is invalid. Check if it is in the correct format. */ static async createWithAreaCode( appId: string, @@ -243,24 +250,42 @@ export default class RtcEngine implements RtcEngineInterface { * The Agora [`RtcEngine`]{@link RtcEngine} differentiates channel profiles and applies different optimization algorithms accordingly. * For example, it prioritizes smoothness and low latency for a video call, and prioritizes video quality for live interactive video streaming. * @param profile The channel profile of the Agora [`RtcEngine`]{@link RtcEngine}. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): The parameter is invalid. + * - 7(NotInitialized): The SDK is not initialized. */ setChannelProfile(profile: ChannelProfile): Promise { return RtcEngine._callMethod('setChannelProfile', { profile }); } /** - * Sets the role of a user ([`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} only). - * - * This method sets the role of a user, such as a host or an audience (default), before joining a channel. + * Sets the role of a user in live interactive streaming. * - * This method can be used to switch the user role after a user joins a channel. In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile, when a user switches user roles after joining a channel, a successful call of this method triggers the following callbacks: + * You can call this method either before or after joining the channel to set the user role as audience or host. If you call this method to switch the user role after joining the channel, the SDK triggers the following callbacks: * - The local client: [`ClientRoleChanged`]{@link RtcEngineEvents.ClientRoleChanged}. * - The remote client: [`UserJoined`]{@link RtcEngineEvents.UserJoined} or [`UserOffline`]{@link RtcEngineEvents.UserOffline} ([`BecomeAudience`]{@link UserOfflineReason.BecomeAudience}). * - * @param role Sets the role of a user. + * **Note** + * - This method applies to the `LiveBroadcasting` profile only (when the `profile` parameter in `setChannelProfile` is set as `LiveBroadcasting`). + * - As of v3.2.0, this method can set the user level in addition to the user role. + * - The user role determines the permissions that the SDK grants to a user, such as permission to send local streams, receive remote streams, and push streams to a CDN address. + * - The user level determines the level of services that a user can enjoy within the permissions of the user's role. For example, an audience can choose to receive remote streams with low latency or ultra low latency. **Levels affect prices**. + * + * @param role The role of a user in interactive live streaming. See {@link ClientRole}. + * @param options? The detailed options of a user, including user level. See {@link ClientRoleOptions}. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 1(Failed): A general error occurs (no specified reason). + * - 2(InvalidArgument): The parameter is invalid. + * - 7(NotInitialized): The SDK is not initialized. */ - setClientRole(role: ClientRole): Promise { - return RtcEngine._callMethod('setClientRole', { role }); + setClientRole(role: ClientRole, options?: ClientRoleOptions): Promise { + return RtcEngine._callMethod('setClientRole', { role, options }); } /** @@ -279,6 +304,8 @@ export default class RtcEngine implements RtcEngineInterface { * When the connection between the client and Agora server is interrupted due to poor network conditions, * the SDK tries reconnecting to the server. When the local client successfully rejoins the channel, the SDK triggers the [`RejoinChannelSuccess`]{@link RtcEngineEvents.RejoinChannelSuccess} callback on the local client. * + * Once the user joins the channel (switches to another channel), the user subscribes to the audio and video streams of all the other users in the channel by default, giving rise to usage and billing calculation. If you do not want to subscribe to a specified stream or all remote streams, call the `mute` methods accordingly. + * * **Note** * * A channel does not accept duplicate uids, such as two users with the same `uid`. If you set `uid` as `0`, the system automatically assigns a uid. @@ -302,6 +329,16 @@ export default class RtcEngine implements RtcEngineInterface { * * The uid is represented as a 32-bit unsigned integer in the SDK. Since unsigned integers are not supported by Java, the uid is handled as a 32-bit signed integer and larger numbers are interpreted as negative numbers in Java. * If necessary, the uid can be converted to a 64-bit integer through “uid&0xffffffffL”. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): The parameter is invalid. + * - 3(NotReady): The SDK fails to be initialized. You can try re-initializing the SDK. + * - 5(Refused): The request is rejected. Possible reasons: + * - You have created an `RtcChannel` object with the same channel name. + * - You have joined and published a stream in a channel created by the `RtcChannel` object. + * - 7(NotInitialized): The SDK is not initialized. */ joinChannel( token: string | undefined | null, @@ -325,6 +362,8 @@ export default class RtcEngine implements RtcEngineInterface { * After the user successfully switches to another channel, the [`LeaveChannel`]{@link RtcEngineEvents.LeaveChannel} and [`JoinChannelSuccess`]{@link RtcEngineEvents.JoinChannelSuccess} callbacks are triggered to * indicate that the user has left the original channel and joined a new one. * + * Once the user joins the channel (switches to another channel), the user subscribes to the audio and video streams of all the other users in the channel by default, giving rise to usage and billing calculation. If you do not want to subscribe to a specified stream or all remote streams, call the `mute` methods accordingly. + * * **Note** * * This method applies to the [`Audience`]{@link ClientRole.Audience} role in a [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} channel only. @@ -338,6 +377,16 @@ export default class RtcEngine implements RtcEngineInterface { * - All numeric characters: 0 to 9. * - The space character. * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 1(Failed): A general error occurs (no specified reason). + * - 2(InvalidArgument): The parameter is invalid. + * - 5(Refused): The request is rejected, probably because the user is not an audience. + * - 7(NotInitialized): The SDK is not initialized. + * - 102(InvalidChannelId): The channel name is invalid. + * - 113(NotInChannel): The user is not in the channel. */ switchChannel( token: string | undefined | null, @@ -363,7 +412,14 @@ export default class RtcEngine implements RtcEngineInterface { * **Note** * - If you call [`destroy`]{@link destroy} immediately after calling [`leaveChannel`]{@link leaveChannel}, the [`leaveChannel`]{@link leaveChannel} process interrupts, and the SDK does not trigger the [`LeaveChannel`]{@link RtcEngineEvents.LeaveChannel} callback. * - * - If you call [`leaveChannel`]{@link leaveChannel} during CDN live streaming, the SDK triggers the [`removeInjectStreamUrl`]{@link removeInjectStreamUrl} method. + * - If you call [`leaveChannel`]{@link leaveChannel} during CDN live streaming, the SDK triggers the [`removePublishStreamUrl`]{@link removePublishStreamUrl} method. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 1(Failed): A general error occurs (no specified reason). + * - 2(InvalidArgument): The parameter is invalid. + * - 7(NotInitialized): The SDK is not initialized. */ leaveChannel(): Promise { return RtcEngine._callMethod('leaveChannel'); @@ -379,6 +435,13 @@ export default class RtcEngine implements RtcEngineInterface { * * The app should retrieve a new token from the server and call this method to renew it. Failure to do so results in the SDK disconnecting from the server. * @param token The new token. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 1(Failed): A general error occurs (no specified reason). + * - 2(InvalidArgument): The parameter is invalid. + * - 7(NotInitialized): The SDK is not initialized. */ renewToken(token: string): Promise { return RtcEngine._callMethod('renewToken', { token }); @@ -429,6 +492,12 @@ export default class RtcEngine implements RtcEngineInterface { * @param rating Rating of the call. The value is between 1 (lowest score) and 5 (highest score). * If you set a value out of this range, the [`InvalidArgument(-2)`]{@link ErrorCode.InvalidArgument} error occurs. * @param description (Optional) The description of the rating. The string length must be less than 800 bytes. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): The parameter is invalid. + * - 3(NotReady): The SDK fails to be initialized. You can try re-initializing the SDK. */ rate(callId: string, rating: Rate, description?: string): Promise { return RtcEngine._callMethod('rate', { callId, rating, description }); @@ -439,6 +508,12 @@ export default class RtcEngine implements RtcEngineInterface { * * @param callId ID of the call retrieved from the [`getCallId`]{@link getCallId} method. * @param description (Optional) The description of the complaint. The string length must be less than 800 bytes. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): The parameter is invalid. + * - 3(NotReady): The SDK fails to be initialized. You can try re-initializing the SDK. */ complain(callId: string, description: string): Promise { return RtcEngine._callMethod('complain', { callId, description }); @@ -529,6 +604,8 @@ export default class RtcEngine implements RtcEngineInterface { * * - The remote client: [`UserJoined`]{@link RtcEngineEvents.UserJoined} and [`UserInfoUpdated`]{@link RtcEngineEvents.UserInfoUpdated}, if the user joining the channel is in the [`Communication`]{@link ChannelProfile.Communication} profile, or is a [`Broadcaster`]{@link ClientRole.Broadcaster} in the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile. * + * Once the user joins the channel (switches to another channel), the user subscribes to the audio and video streams of all the other users in the channel by default, giving rise to usage and billing calculation. If you do not want to subscribe to a specified stream or all remote streams, call the `mute` methods accordingly. + * * **Note** * * To ensure smooth communication, use the same parameter type to identify the user. @@ -550,6 +627,14 @@ export default class RtcEngine implements RtcEngineInterface { * - All numeric characters: 0 to 9. * - The space character. * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): The parameter is invalid. + * - 3(NotReady): The SDK fails to be initialized. You can try re-initializing the SDK. + * - 5(Refused): The request is rejected. + * */ joinChannelWithUserAccount( token: string | undefined | null, @@ -656,11 +741,11 @@ export default class RtcEngine implements RtcEngineInterface { * * **Note** * - * - This method affects the internal engine and can be called after calling [`leaveChannel`]{@link leaveChannel}. + * - This method affects the audio module and can be called after calling [`leaveChannel`]{@link leaveChannel}. * You can call this method either before or after joining a channel. * - * - This method resets the engine and takes some time to take effect. - * We recommend using the following API methods to control the audio engine modules separately: + * - This method enables/disables the audio module and takes some time to take effect. + * We recommend using the following API methods to control the audio module separately: * * - [`enableLocalAudio`]{@link enableLocalAudio}: Whether to enable the microphone to create the local audio stream. * @@ -681,11 +766,11 @@ export default class RtcEngine implements RtcEngineInterface { * * **Note** * - * - This method affects the internal engine and can be called after calling [`leaveChannel`]{@link leaveChannel}. + * - This method affects the audio module and can be called after calling [`leaveChannel`]{@link leaveChannel}. * You can call this method either before or after joining a channel. * - * - This method resets the internal engine and takes some time to take effect. - * We recommend using the following API methods to control the audio engine modules separately: + * - This method enables/disables the audio module and takes some time to take effect. + * We recommend using the following API methods to control the audio module separately: * * - [`enableLocalAudio`]{@link enableLocalAudio}: Whether to enable the microphone to create the local audio stream. * @@ -712,7 +797,7 @@ export default class RtcEngine implements RtcEngineInterface { * The recommended value is 3. * @param report_vad * - `true`: Enable the voice activity detection of the local user. Once it is enabled, the `vad` parameter of the [`AudioVolumeIndication`]{@link RtcEngineEvents.AudioVolumeIndication} callback reports the voice activity status of the local user. - * - `false`: (Default) Disable the voice activity detection of the local user. Once it is enabled, the `vad` parameter of the [`AudioVolumeIndication`]{@link RtcEngineEvents.AudioVolumeIndication} callback does not report the voice activity status of the local user, + * - `false`: (Default) Disable the voice activity detection of the local user. Once it is disabled, the `vad` parameter of the [`AudioVolumeIndication`]{@link RtcEngineEvents.AudioVolumeIndication} callback does not report the voice activity status of the local user, * except for scenarios where the engine automatically detects the voice activity of the local user. */ enableAudioVolumeIndication( @@ -741,7 +826,7 @@ export default class RtcEngine implements RtcEngineInterface { * * **Note** * - * - This method is different from the [`muteLocalAudioStream`]{@link muteLocalAudioStream} method: + * This method is different from the [`muteLocalAudioStream`]{@link muteLocalAudioStream} method: * * - [`enableLocalAudio`]{@link enableLocalAudio}: Disables/Re-enables the local audio capture and processing. * If you disable or re-enable local audio recording using [`enableLocalAudio`]{@link enableLocalAudio}, the local user may hear a pause in the remote audio playback. @@ -810,11 +895,11 @@ export default class RtcEngine implements RtcEngineInterface { * * - You must call this method before calling [`joinChannel`]{@link joinChannel}. * - In the [`Communication`]{@link ChannelProfile.Communication} and [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profiles, the bitrates may be different from your settings due to network self-adaptation. - * - In scenarios requiring high-quality audio, we recommend setting profile as [`MusicHighQuality(4)`]{@link AudioProfile.MusicHighQuality} and scenario as [`GameStreaming(3)`]{@link AudioScenario.GameStreaming}. - * For example, for music education scenarios. + * - In scenarios requiring high-quality audio, we recommend setting profile as `ShowRoom(4)` and scenario as `GameStreaming(3)`. For example, for music education scenarios. * - * @param profile Sets the sample rate, bitrate, encoding mode, and the number of channels. - * @param scenario Sets the audio application scenarios. Under different audio scenarios, the device uses different volume tracks, i.e. either the in-call volume or the media volume. + * @param profile Sets the sample rate, bitrate, encoding mode, and the number of channels. See [`AudioProfile`]{@link AudioProfile}. + * @param scenario Sets the audio application scenarios. See [`AudioScenario`]{@link AudioScenario}. Under different audio scenarios, the device uses different volume tracks, i.e. either the in-call volume or the media volume. + * For details, see [What is the difference between the in-call volume and the media volume?](https://docs.agora.io/en/Voice/faq/system_volume). */ setAudioProfile( profile: AudioProfile, @@ -993,6 +1078,12 @@ export default class RtcEngine implements RtcEngineInterface { * - `true`: Enable image enhancement. * - `false`: Disable image enhancement. * @param options The image enhancement options. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 4(NotSupported): The system version is earlier than Android 4.4, which does not support this function. + * */ setBeautyEffectOptions( enabled: boolean, @@ -1113,7 +1204,7 @@ export default class RtcEngine implements RtcEngineInterface { * * @returns * - Returns the current playback position of the audio mixing, if the method call is successful. - * - < 0: Failure. + * - Error codes: Failure. */ getAudioMixingCurrentPosition(): Promise { return RtcEngine._callMethod('getAudioMixingCurrentPosition'); @@ -1128,7 +1219,7 @@ export default class RtcEngine implements RtcEngineInterface { * * @returns * - Returns the audio mixing duration, if the method call is successful. - * - < 0: Failure. + * - Error codes: Failure. */ getAudioMixingDuration(): Promise { return RtcEngine._callMethod('getAudioMixingDuration'); @@ -1141,7 +1232,7 @@ export default class RtcEngine implements RtcEngineInterface { * * @returns * - Returns the audio mixing volume for local playback, if the method call is successful. The value range is [0,100]. - * - < 0: Failure. + * - Error codes: Failure. */ getAudioMixingPlayoutVolume(): Promise { return RtcEngine._callMethod('getAudioMixingPlayoutVolume'); @@ -1154,7 +1245,7 @@ export default class RtcEngine implements RtcEngineInterface { * * @returns * - Returns the audio mixing volume for publishing, if the method call is successful. The value range is [0,100]. - * - < 0: Failure. + * - Error codes: Failure. */ getAudioMixingPublishVolume(): Promise { return RtcEngine._callMethod('getAudioMixingPublishVolume'); @@ -1244,6 +1335,7 @@ export default class RtcEngine implements RtcEngineInterface { * @param cycle Sets the number of playback loops: * - Positive integer: Number of playback loops. * - -1: Infinite playback loops. + * */ startAudioMixing( filePath: string, @@ -1275,7 +1367,7 @@ export default class RtcEngine implements RtcEngineInterface { * * @returns * - Returns the volume, if the method call is successful. - * - < 0: Failure. + * - Error codes: Failure. */ getEffectsVolume(): Promise { return RtcEngine._callMethod('getEffectsVolume'); @@ -1429,6 +1521,8 @@ export default class RtcEngine implements RtcEngineInterface { /** * Sets the local voice changer option. * + * @deprecated Deprecated as of v3.2.0. Use `setAudioEffectPreset` or `setVoiceBeautifierPreset` instead. + * * **Note** * * Do not use this method together with [`setLocalVoiceReverbPreset`]{@link setLocalVoiceReverbPreset}, or the method called earlier does not take effect. @@ -1488,6 +1582,8 @@ export default class RtcEngine implements RtcEngineInterface { /** * Sets the preset local voice reverberation effect. * + * @deprecated Deprecated as of v3.2.0. Use `setAudioEffectPreset` or `setVoiceBeautifierPreset` instead. + * * **Note** * * - Do not use this method together with [`setLocalVoiceReverb`]{@link setLocalVoiceReverb}. @@ -1546,22 +1642,32 @@ export default class RtcEngine implements RtcEngineInterface { } /** - * Publishes the local stream to the CDN. + * Publishes the local stream to a specified CDN streaming URL. * - * This method call triggers the [`RtmpStreamingStateChanged`]{@link RtcEngineEvents.RtmpStreamingStateChanged} callback on the local client to report the state of adding a local stream to the CDN. + * After calling this method, you can push media streams in RTMP or RTMPS protocol to the CDN. + * + * This SDK triggers the [`RtmpStreamingStateChanged`]{@link RtcEngineEvents.RtmpStreamingStateChanged} callback on the local client to report the state of adding a local stream to the CDN. * * **Note** * - Ensure that you enable the RTMP Converter service before using this function. See Prerequisites in *Push Streams to CDN*. * - This method applies to [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} only. * - Ensure that the user joins a channel before calling this method. - * - This method adds only one stream HTTP/HTTPS URL address each time it is called. - * @param url The CDN streaming URL in the RTMP format. The maximum length of this parameter is 1024 bytes. + * - This method adds only one CDN streaming URL each time it is called. + * - Agora supports pushing media streams in RTMPS protocol to the CDN only when you enable transcoding. + * + * @param url The CDN streaming URL in the RTMP or RTMPS format. The maximum length of this parameter is 1024 bytes. * The URL address must not contain special characters, such as Chinese language characters. - * @param transcodingEnabled Sets whether transcoding is enabled/disabled. + * @param transcodingEnabled Whether to enable transcoding. * If you set this parameter as `true`, ensure that you call [`setLiveTranscoding`]{@link setLiveTranscoding} before this method. * * - `true`: Enable transcoding. To transcode the audio or video streams when publishing them to CDN live, often used for combining the audio and video streams of multiple hosts in CDN live. * - `false`: Disable transcoding. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): Invalid parameter, usually because the URL address is null or the string length is 0. + * - 7(NotInitialized): You have not initialized `RtcEngine` when publishing the stream. */ addPublishStreamUrl(url: string, transcodingEnabled: boolean): Promise { return RtcEngine._callMethod('addPublishStreamUrl', { @@ -1571,17 +1677,18 @@ export default class RtcEngine implements RtcEngineInterface { } /** - * Removes an RTMP stream from the CDN. + * Removes an RTMP or RTMPS stream from the CDN. * - * This method removes the RTMP URL address (added by [`addPublishStreamUrl`]{@link addPublishStreamUrl}) from a CDN live stream. + * This method removes the CDN streaming URL (added by [`addPublishStreamUrl`]{@link addPublishStreamUrl}) from a CDN live stream. * The SDK reports the result of this method call in the [`RtmpStreamingStateChanged`]{@link RtcEngineEvents.RtmpStreamingStateChanged} callback. * * **Note** * - Ensure that you enable the RTMP Converter service before using this function. See Prerequisites in *Push Streams to CDN*. * - Ensure that the user joins a channel before calling this method. * - This method applies to [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} only. - * - This method removes only one stream RTMP URL address each time it is called. - * @param url The RTMP URL address to be removed. The maximum length of this parameter is 1024 bytes. + * - This method removes only one CDN streaming URL each time it is called. + * + * @param url The CDN streaming URL to be removed. The maximum length of this parameter is 1024 bytes. * The URL address must not contain special characters, such as Chinese language characters. */ removePublishStreamUrl(url: string): Promise { @@ -1601,6 +1708,7 @@ export default class RtcEngine implements RtcEngineInterface { * - Ensure that you enable the RTMP Converter service before using this function. See Prerequisites in Push Streams to CDN. * - Ensure that you call [`setClientRole`]{@link setClientRole} and set the user role as the host. * - Ensure that you call [`setLiveTranscoding`]{@link setLiveTranscoding} before calling [`addPublishStreamUrl`]{@link addPublishStreamUrl}. + * - Agora supports pushing media streams in RTMPS protocol to the CDN only when you enable transcoding. * * @param transcoding Sets the CDN live audio/video transcoding settings. */ @@ -1732,8 +1840,13 @@ export default class RtcEngine implements RtcEngineInterface { * * - This method is invalid for audience users in the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile. * + * - Settings of `setAudioProfile` and `setChannelProfile` affect the call result of `setEnableSpeakerphone`. The following are scenarios where `setEnableSpeakerphone` does not take effect: + * - If you set `scenario` as `GameStreaming`, no user can change the audio playback route. + * - If you set `scenario` as `Default` or `ShowRoom`, the audience cannot change the audio playback route. If there is only one host is in the channel, the host cannot change the audio playback route either. + * - If you set `scenario` as `Education`, the audience cannot change the audio playback route. + * * @param enabled Sets whether to route the audio to the speakerphone or earpiece: - * - `true`: Route the audio to the speakerphone. + * - `true`: Route the audio to the speakerphone. If the playback device connects to the earpiece or Bluetooth, the audio cannot be routed to the speakerphone. * - `false`: Route the audio to the earpiece. If the headset is plugged in, the audio is routed to the headset. */ setEnableSpeakerphone(enabled: boolean): Promise { @@ -2064,7 +2177,7 @@ export default class RtcEngine implements RtcEngineInterface { * All users in the same channel must use the same encryption mode and encryption key. Once all users leave the channel, the encryption key of this channel is automatically cleared. * * **Note** - * - If you enable the built-in encryption, you cannot use the RTMP streaming function. + * - If you enable the built-in encryption, you cannot use the RTMP or RTMPS streaming function. * - Agora supports four encryption modes. If you choose an encryption mode (excepting `SM4128ECB` mode), you need to add an external encryption library when integrating the SDK. For details, see the advanced guide *Channel Encryption*. * * @@ -2072,6 +2185,13 @@ export default class RtcEngine implements RtcEngineInterface { * - `true`: Enable the built-in encryption. * - `false`: Disable the built-in encryption. * @param config Configurations of built-in encryption schemas. See [`EncryptionConfig`]{@link EncryptionConfig}. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): An invalid parameter is used. Set the parameter with a valid value. + * - 4(NotSupported): The encryption mode is incorrect or the SDK fails to load the external encryption library. Check the enumeration or reload the external encryption library. + * - 7(NotInitialized): The SDK is not initialized. Initialize the `RtcEngine` instance before calling this method. */ enableEncryption(enabled: boolean, config: EncryptionConfig): Promise { return RtcEngine._callMethod('enableEncryption', { enabled, config }); @@ -2188,6 +2308,14 @@ export default class RtcEngine implements RtcEngineInterface { * - Supported audio codec type: AAC. * - Supported video codec type: H264(AVC). * @param config The `LiveInjectStreamConfig` object which contains the configuration information for the added voice or video stream. + * + * @returns + * - 0(NoError): Success. + * - Error codes: Failure. + * - 2(InvalidArgument): The injected URL does not exist. Call this method again to inject the stream and ensure that the URL is valid. + * - 3(NotReady): The user is not in the channel. + * - 4(NotSupported): The channel profile is not `LiveBroadcasting`. Call the `setChannelProfile` method and set the channel profile to `LiveBroadcasting` before calling this method. + * - 7(NotInitialized): The SDK is not initialized. Initialize the `RtcEngine` instance before calling this method. */ addInjectStreamUrl( url: string, @@ -2414,7 +2542,7 @@ export default class RtcEngine implements RtcEngineInterface { * * @return * - Returns the stream ID, if the method call is successful. - * - < 0: Failure. The error code is related to the integer displayed in [Error Codes]{@link ErrorCode}. + * - Error codes: Failure. The error code is related to the integer displayed in [Error Codes]{@link ErrorCode}. */ createDataStream(reliable: boolean, ordered: boolean): Promise { return RtcEngine._callMethod('createDataStream', { reliable, ordered }); @@ -2470,6 +2598,8 @@ export default class RtcEngine implements RtcEngineInterface { } /** + * The method applies to the iOS platform only. You can call this method either before or after joining a channel. + * * The SDK and the app can both configure the audio session by default. The app may occasionally use other apps or third-party components to manipulate the audio session and restrict the SDK from doing so. This method allows the app to restrict the SDK’s manipulation of the audio session. * * You can call this method at any time to return the control of the audio sessions to the SDK. @@ -2495,6 +2625,151 @@ export default class RtcEngine implements RtcEngineInterface { getNativeHandle(): Promise { return RtcEngine._callMethod('getNativeHandle'); } + + /** + * Sets parameters for SDK preset audio effects. + * + * @since v3.2.0. + * + * Call this method to set the following parameters for the local user who send an audio stream: + * - 3D voice effect: Sets the cycle period of the 3D voice effect. + * - Pitch correction effect: Sets the basic mode and tonic pitch of the pitch correction effect. Different songs have different modes and tonic pitches. + * Agora recommends bounding this method with interface elements to enable users to adjust the pitch correction interactively. + * + * After setting parameters, all users in the channel can hear the relevant effect. + * + * You can call this method directly or after `setAudioEffectPreset`. If you call this method after `setAudioEffectPreset`, ensure that you set the preset parameter of `setAudioEffectPreset` to `RoomAcoustics3DVoice` or `PitchCorrection` and + * then call this method to set the same enumerator; otherwise, this method overrides `setAudioEffectPreset`. + * + * **Note** + * - To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the scenario parameter + * to `GameStreaming(3)` before calling this method. + * - Do not set the profile parameter of `setAudioProfile` to `SpeechStandard(1)` or `AUDIO_PROFILE_IOT(6)`; otherwise, this method call fails. + * - This method works best with the human voice. Agora does not recommend using this method for audio containing music. + * - After calling this method, Agora recommends not calling the following methods, because they can override `setAudioEffectParameters`: + * - `setAudioEffectPreset` + * - `setVoiceBeautifierPreset` + * - `setLocalVoiceReverbPreset` + * - `setLocalVoiceChanger` + * - `setLocalVoicePitch` + * - `setLocalVoiceEqualization` + * - `setLocalVoiceReverb` + * + * @param preset The options for SDK preset audio effects: + * - 3D voice effect: `RoomAcoustics3DVoice`. + * - Call `setAudioProfile` and set the profile parameter to `MusicStandardStereo(3)` or `MusicHighQualityStereo(5)` before setting this enumerator; + * otherwise, the enumerator setting does not take effect. + * - If the 3D voice effect is enabled, users need to use stereo audio playback devices to hear the anticipated voice effect. + * - Pitch correction effect: `PitchCorrection`. To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the profile parameter to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before setting this enumerator. + * + * @param param1 + * - If you set preset to `RoomAcoustics3DVoice`, the `param1` sets the cycle period of the 3D voice effect. + * The value range is [1,60] and the unit is a second. The default value is 10 seconds, indicating that the voice moves around you every 10 seconds. + * - If you set preset to `PitchCorrection`, `param1` sets the basic mode of the pitch correction effect: + * - 1: (Default) Natural major scale. + * - 2: Natural minor scale. + * - 3: Japanese pentatonic scale. + * + * @param param2 + * - If you set `preset` to `RoomAcoustics3DVoice`, you need to set `param2` to `0`. + * - If you set `preset` to `PitchCorrection`, `param2` sets the tonic pitch of the pitch correction effect: + * - 1: A + * - 2: A# + * - 3: B + * - 4: (Default) C + * - 5: C# + * - 6: D + * - 7: D# + * - 8: E + * - 9: F + * - 10: F# + * - 11: G + * - 12: G# + * + * @returns + * - 0: Success. + * - Error codes: Failure. + */ + setAudioEffectParameters( + preset: AudioEffectPreset, + param1: number, + param2: number + ): Promise { + return RtcEngine._callMethod('setAudioEffectParameters', { + preset, + param1, + param2, + }); + } + + /** + * Sets an SDK preset audio effect. + * + * @since v3.2.0. + * + * Call this method to set an SDK preset audio effect for the local user who sends an audio stream. + * This audio effect does not change the gender characteristics of the original voice. After setting an audio effect, all users in the channel can hear the effect. + * + * You can set different audio effects for different scenarios. + * + * To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the scenario parameter to `GameStreaming(3)` before calling this method. + * + * **Note** + * - You can call this method either before or after joining a channel. + * - Do not set the profile parameter of `setAudioProfile` to `SpeechStandard(1)`; otherwise, this method call fails. + * - This method works best with the human voice. Agora does not recommend using this method for audio containing music. + * - If you call this method and set the preset parameter to enumerators except `RoomAcoustics3DVoice` or `PitchCorrection`, do not call `setAudioEffectParameters`; otherwise, `setAudioEffectParameters` overrides this method. + * - After calling this method, Agora recommends not calling the following methods, because they can override `setAudioEffectPreset`: + * - `setVoiceBeautifierPreset` + * - `setLocalVoiceReverbPreset` + * - `setLocalVoiceChanger` + * - `setLocalVoicePitch` + * - `setLocalVoiceEqualization` + * - `setLocalVoiceReverb` + * + * @param preset The options for SDK preset audio effects. See [`AudioEffectPreset`]{@link AudioEffectPreset}. + * + * @returns + * - 0: Success. + * - Error codes: Failure. + */ + setAudioEffectPreset(preset: AudioEffectPreset): Promise { + return RtcEngine._callMethod('setAudioEffectPreset', { preset }); + } + + /** + * Sets an SDK preset voice beautifier effect. + * + * @since v3.2.0. + * + * Call this method to set an SDK preset voice beautifier effect for the local user who sends an audio stream. + * After setting a voice beautifier effect, all users in the channel can hear the effect. + * + * You can set different voice beautifier effects for different scenarios. + * + * To achieve better audio effect quality, Agora recommends calling `setAudioProfile` and setting the scenario parameter to `GameStreaming(3)` and the profile parameter to `MusicHighQuality(4)` or `MusicHighQualityStereo(5)` before calling this method. + * + * **Note** + * - You can call this method either before or after joining a channel. + * - Do not set the profile parameter of `setAudioProfile` to `SpeechStandard(1)`; otherwise, this method call fails. + * - This method works best with the human voice. Agora does not recommend using this method for audio containing music. + * - After calling this method, Agora recommends not calling the following methods, because they can override `setVoiceBeautifierPreset`: + * - `setAudioEffectPreset` + * - `setLocalVoiceReverbPreset` + * - `setLocalVoiceChanger` + * - `setLocalVoicePitch` + * - `setLocalVoiceEqualization` + * - `setLocalVoiceReverb` + * + * @param preset The options for SDK preset voice beautifier effects. See [`VoiceBeautifierPreset`]{@link VoiceBeautifierPreset}. + * + * @returns + * - 0: Success. + * - Error codes: Failure. + */ + setVoiceBeautifierPreset(preset: VoiceBeautifierPreset): Promise { + return RtcEngine._callMethod('setVoiceBeautifierPreset', { preset }); + } } /** @@ -2526,7 +2801,7 @@ interface RtcEngineInterface setChannelProfile(profile: ChannelProfile): Promise; - setClientRole(role: ClientRole): Promise; + setClientRole(role: ClientRole, options?: ClientRoleOptions): Promise; joinChannel( token: string | undefined | null, @@ -2751,6 +3026,16 @@ interface RtcVoiceChangerInterface { ): Promise; setLocalVoiceReverb(reverbKey: AudioReverbType, value: number): Promise; + + setAudioEffectPreset(preset: AudioEffectPreset): Promise; + + setVoiceBeautifierPreset(preset: VoiceBeautifierPreset): Promise; + + setAudioEffectParameters( + preset: AudioEffectPreset, + param1: number, + param2: number + ): Promise; } /** diff --git a/src/common/RtcEvents.ts b/src/common/RtcEvents.ts index 55197ba82..28f6f82b0 100644 --- a/src/common/RtcEvents.ts +++ b/src/common/RtcEvents.ts @@ -1,3 +1,15 @@ +import type { + AudioVolumeInfo, + FacePositionInfo, + LastmileProbeResult, + LocalAudioStats, + LocalVideoStats, + Rect, + RemoteAudioStats, + RemoteVideoStats, + RtcStats, + UserInfo, +} from './Classes'; import type { AudioLocalError, AudioLocalState, @@ -6,7 +18,6 @@ import type { AudioOutputRouting, AudioRemoteState, AudioRemoteStateReason, - AudioVolumeInfo, ChannelMediaRelayError, ChannelMediaRelayEvent, ChannelMediaRelayState, @@ -14,30 +25,21 @@ import type { ConnectionChangedReason, ConnectionStateType, ErrorCode, - FacePositionInfo, InjectStreamStatus, - LastmileProbeResult, - LocalAudioStats, - LocalVideoStats, LocalVideoStreamError, LocalVideoStreamState, NetworkQuality, NetworkType, - Rect, - RemoteAudioStats, - RemoteVideoStats, - RtcStats, RtmpStreamingErrorCode, RtmpStreamingEvent, RtmpStreamingState, StreamPublishState, StreamSubscribeState, - UserInfo, UserOfflineReason, VideoRemoteState, VideoRemoteStateReason, WarningCode, -} from '../Types'; +} from './Enums'; /** * @internal @@ -330,8 +332,8 @@ export type SoundIdCallback = (soundId: number) => void; export type RtmpStreamingStateCallback = /** - * @param url The RTMP URL address. - * @param state The RTMP streaming state. + * @param url The CDN streaming URL. + * @param state The RTMP or RTMPS streaming state. * @param errCode The detailed error information for streaming. */ ( @@ -390,13 +392,13 @@ export type VideoFrameWithUidCallback = (uid: number, width: number, height: number, elapsed: number) => void; export type UrlWithErrorCallback = /** - * @param url The RTMP streaming URL. + * @param url The RTMP or RTMPS streaming URL. * @param error The detailed error information. */ (url: string, error: ErrorCode) => void; export type UrlCallback = /** - * @param url The RTMP URL address. + * @param url The CDN streaming URL. */ (url: string) => void; export type TransportStatsCallback = @@ -479,7 +481,7 @@ export type StreamSubscribeStateCallback = ) => void; export type RtmpStreamingEventCallback = /** - * @param url The RTMP streaming URL. + * @param url The RTMP or RTMPS streaming URL. * @param eventCode The event code. See [`RtmpStreamingEvent`]{@link RtmpStreamingEvent}. */ (url: string, eventCode: RtmpStreamingEvent) => void; @@ -961,12 +963,12 @@ export interface RtcEngineEvents { AudioEffectFinished: SoundIdCallback; /** - * Occurs when the state of the RTMP streaming changes. + * Occurs when the state of the RTMP or RTMPS streaming changes. * * The SDK triggers this callback to report the result of the local user calling [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} or [`removePublishStreamUrl`]{@link RtcEngine.removePublishStreamUrl}. * This callback returns the URL and its current streaming state. When the streaming state is [`Failure`]{@link RtmpStreamingState.Failure}, see the errCode parameter for details. * - * This callback indicates the state of the RTMP streaming. When exceptions occur, you can troubleshoot issues by referring to the detailed error descriptions in the `errCode` parameter. + * This callback indicates the state of the RTMP or RTMPS streaming. When exceptions occur, you can troubleshoot issues by referring to the detailed error descriptions in the `errCode` parameter. * * @event RtmpStreamingStateChanged */ @@ -1109,7 +1111,7 @@ export interface RtcEngineEvents { * * Use [`RtmpStreamingStateChanged`]{@link RtmpStreamingStateChanged} instead. * - * This callback indicates whether you have successfully added an RTMP stream to the CDN. + * This callback indicates whether you have successfully added an RTMP or RTMPS stream to the CDN. * * @event StreamPublished */ @@ -1122,7 +1124,7 @@ export interface RtcEngineEvents { * * Use [`RtmpStreamingStateChanged`]{@link RtmpStreamingStateChanged} instead. * - * This callback indicates whether you have successfully removed an RTMP stream from the CDN. + * This callback indicates whether you have successfully removed an RTMP or RTMPS stream from the CDN. * * @event StreamUnpublished */ @@ -1376,7 +1378,7 @@ export interface RtcEngineEvents { VideoSubscribeStateChanged: StreamSubscribeStateCallback; /** - * Reports events during the RTMP streaming. + * Reports events during the RTMP or RTMPS streaming. * * @since v3.1.2. * @@ -1612,11 +1614,11 @@ export interface RtcChannelEvents { RemoteAudioStats: RemoteAudioStatsCallback; /** - * Occurs when the state of the RTMP streaming changes. + * Occurs when the state of the RTMP or RTMPS streaming changes. * * The SDK triggers this callback to report the result of the local user calling the [`addPublishStreamUrl`]{@link RtcChannel.addPublishStreamUrl} or [`removePublishStreamUrl`]{@link RtcChannel.removePublishStreamUrl} method. This callback returns the URL and its current streaming state. When the streaming state is [`Failure`]{@link RtmpStreamingState.Failure}, see the errCode parameter for details. * - * This callback indicates the state of the RTMP streaming. When exceptions occur, you can troubleshoot issues by referring to the detailed error descriptions in the errCode parameter. + * This callback indicates the state of the RTMP or RTMPS streaming. When exceptions occur, you can troubleshoot issues by referring to the detailed error descriptions in the errCode parameter. * * @event RtmpStreamingStateChanged */ @@ -1728,7 +1730,7 @@ export interface RtcChannelEvents { VideoSubscribeStateChanged: StreamSubscribeStateCallback; /** - * Reports events during the RTMP streaming. + * Reports events during the RTMP or RTMPS streaming. * * @since v3.1.2. *