From cd09ccc9cab07f301fc7cc011c659f956cfaa0fd Mon Sep 17 00:00:00 2001 From: HUI Date: Thu, 15 Oct 2020 20:21:19 +0800 Subject: [PATCH 01/18] iOS raw data plugin --- RtcEngine.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/RtcEngine.swift b/RtcEngine.swift index ba0e3009b..1d40ca5ee 100644 --- a/RtcEngine.swift +++ b/RtcEngine.swift @@ -67,6 +67,8 @@ protocol RtcEngineInterface: func setLogFileSize(_ params: NSDictionary, _ callback: Callback) func setParameters(_ params: NSDictionary, _ callback: Callback) + + func getNativeHandle(_ callback: Callback) } protocol RtcEngineUserInfoInterface { @@ -433,6 +435,12 @@ class RtcEngineManager: NSObject, RtcEngineInterface { @objc func setLogFileSize(_ params: NSDictionary, _ callback: Callback) { callback.code(engine?.setLogFileSize((params["fileSizeInKBytes"] as! UInt))) } + + @objc func getNativeHandle(_ callback: Callback) { + callback.resolve(engine) { it in + Int(bitPattern: it.getNativeHandle()) + } + } @objc func setParameters(_ params: NSDictionary, _ callback: Callback) { callback.code(engine?.setParameters(params["parameters"] as! String)) From c72a5278b2e990081d34e2e765e2e6a26ba792bb Mon Sep 17 00:00:00 2001 From: HUI Date: Wed, 21 Oct 2020 16:49:49 +0800 Subject: [PATCH 02/18] feat: migrating to @react-native-community/bob --- .gitattributes | 6 +- .gitignore | 81 +- CONTRIBUTING.md | 184 + LICENSE | 2 +- README.md | 29 +- README.zh.md | 29 +- android/build.gradle | 140 +- android/gradle.properties | 4 + babel.config.js | 3 + example/android/.project | 17 + .../org.eclipse.buildship.core.prefs | 2 + example/android/app/build.gradle | 222 + example/android/app/debug.keystore | Bin 0 -> 2257 bytes example/android/app/proguard-rules.pro | 10 + .../android/app/src/debug/AndroidManifest.xml | 8 + .../reactnativeagora/ReactNativeFlipper.java | 69 + .../android/app/src/main/AndroidManifest.xml | 27 + .../reactnativeagora/MainActivity.java | 15 + .../reactnativeagora/MainApplication.java | 81 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 9 + example/android/build.gradle | 38 + example/android/gradle.properties | 22 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 55616 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + example/android/gradlew | 188 + example/android/gradlew.bat | 100 + example/android/settings.gradle | 6 + example/app.json | 4 + example/babel.config.js | 16 + example/index.tsx | 5 + example/ios/AgoraExample-Bridging-Header.h | 3 + .../AgoraExample.xcodeproj/project.pbxproj | 462 ++ .../xcschemes/AgoraExample.xcscheme | 99 + .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + example/ios/AgoraExample/AppDelegate.h | 15 + example/ios/AgoraExample/AppDelegate.m | 63 + .../AgoraExample/Base.lproj/LaunchScreen.xib | 42 + .../AppIcon.appiconset/Contents.json | 38 + .../Images.xcassets/Contents.json | 6 + example/ios/AgoraExample/Info.plist | 57 + example/ios/AgoraExample/main.m | 16 + example/ios/File.swift | 6 + example/ios/Podfile | 68 + example/metro.config.js | 40 + example/package.json | 21 + example/src/App.tsx | 31 + example/yarn.lock | 4473 +++++++++++++++++ package.json | 168 +- react-native-agora.podspec | 33 +- samples/README.md | 5 - src/RtcLocalView.tsx | 41 +- src/RtcRemoteView.tsx | 52 +- src/Types.ts | 4 +- src/common/Classes.ts | 1350 +++++ src/common/Enums.ts | 2367 +++++++++ src/common/RtcChannel.native.ts | 977 ++++ src/common/RtcEngine.native.ts | 2947 +++++++++++ src/common/RtcEvents.ts | 1712 +++++++ src/common/RtcRenderView.native.tsx | 129 + src/index.ts | 18 +- src/src/Classes.ts | 1280 ----- src/src/Enums.ts | 2367 --------- src/src/RtcChannel.native.ts | 894 ---- src/src/RtcEngine.native.ts | 2678 ---------- src/src/RtcEvents.ts | 1681 ------- src/src/RtcRenderView.native.tsx | 113 - tsconfig.json | 88 +- 79 files changed, 16385 insertions(+), 9302 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 android/gradle.properties create mode 100644 babel.config.js create mode 100644 example/android/.project create mode 100644 example/android/.settings/org.eclipse.buildship.core.prefs create mode 100644 example/android/app/build.gradle create mode 100644 example/android/app/debug.keystore create mode 100644 example/android/app/proguard-rules.pro create mode 100644 example/android/app/src/debug/AndroidManifest.xml create mode 100644 example/android/app/src/debug/java/com/example/reactnativeagora/ReactNativeFlipper.java create mode 100644 example/android/app/src/main/AndroidManifest.xml create mode 100644 example/android/app/src/main/java/com/example/reactnativeagora/MainActivity.java create mode 100644 example/android/app/src/main/java/com/example/reactnativeagora/MainApplication.java create mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 example/android/app/src/main/res/values/strings.xml create mode 100644 example/android/app/src/main/res/values/styles.xml create mode 100644 example/android/build.gradle create mode 100644 example/android/gradle.properties create mode 100644 example/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 example/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 example/android/gradlew create mode 100644 example/android/gradlew.bat create mode 100644 example/android/settings.gradle create mode 100644 example/app.json create mode 100644 example/babel.config.js create mode 100644 example/index.tsx create mode 100644 example/ios/AgoraExample-Bridging-Header.h create mode 100644 example/ios/AgoraExample.xcodeproj/project.pbxproj create mode 100644 example/ios/AgoraExample.xcodeproj/xcshareddata/xcschemes/AgoraExample.xcscheme create mode 100644 example/ios/AgoraExample.xcworkspace/contents.xcworkspacedata create mode 100644 example/ios/AgoraExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 example/ios/AgoraExample/AppDelegate.h create mode 100644 example/ios/AgoraExample/AppDelegate.m create mode 100644 example/ios/AgoraExample/Base.lproj/LaunchScreen.xib create mode 100644 example/ios/AgoraExample/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 example/ios/AgoraExample/Images.xcassets/Contents.json create mode 100644 example/ios/AgoraExample/Info.plist create mode 100644 example/ios/AgoraExample/main.m create mode 100644 example/ios/File.swift create mode 100644 example/ios/Podfile create mode 100644 example/metro.config.js create mode 100644 example/package.json create mode 100644 example/src/App.tsx create mode 100644 example/yarn.lock delete mode 100644 samples/README.md create mode 100644 src/common/Classes.ts create mode 100644 src/common/Enums.ts create mode 100644 src/common/RtcChannel.native.ts create mode 100644 src/common/RtcEngine.native.ts create mode 100644 src/common/RtcEvents.ts create mode 100644 src/common/RtcRenderView.native.tsx delete mode 100644 src/src/Classes.ts delete mode 100644 src/src/Enums.ts delete mode 100644 src/src/RtcChannel.native.ts delete mode 100644 src/src/RtcEngine.native.ts delete mode 100644 src/src/RtcEvents.ts delete mode 100644 src/src/RtcRenderView.native.tsx diff --git a/.gitattributes b/.gitattributes index 375fc2e39..e27f70fa4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,3 @@ -*.psd filter=lfs diff=lfs merge=lfs -text -*.framework filter=lfs diff=lfs merge=lfs -text -*.so filter=lfs diff=lfs merge=lfs -text +*.pbxproj -text +# specific for windows script files +*.bat text eol=crlf diff --git a/.gitignore b/.gitignore index de9e60a06..e46043a99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,62 @@ -.tmp/ -build/ -gitpull.sh -gitpush.sh +# OSX +# +.DS_Store + +# XDE +.expo/ + +# VSCode +.vscode/ +jsconfig.json # Xcode -project.xcworkspace/ -xcuserdata/ -Pods/ -Podfile.lock - -# Android/IntelliJ/VSCode -.idea/ -.gradle/ -gradle/ +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# Android/IJ +# +.idea +.gradle local.properties -*.iml -.vscode/ -android/app/.settings/ -android/.settings/ -android/app/.classpath -android/app/.project -android/.project -typings/ -typings.json +android.iml + +# Cocoapods +# +example/ios/Pods +example/ios/Podfile.lock # node.js +# node_modules/ -__tests__/ -yarn.lock npm-debug.log -npm-lock.json -package-lock.json +yarn-debug.log +yarn-error.log +yarn.lock + +# BUCK +buck-out/ +\.buckd/ +android/app/libs +android/keystores/debug.keystore + +# Expo +.expo/* + +# generated by bob +lib/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..182f6f7b1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,184 @@ +# Contributing + +We want this community to be friendly and respectful to each other. Please follow it in all your interactions with the project. + +## Development workflow + +To get started with the project, run `yarn bootstrap` in the root directory to install the required dependencies for each package: + +```sh +yarn bootstrap +``` + +While developing, you can run the [example app](/example/) to test your changes. + +To start the packager: + +```sh +yarn example start +``` + +To run the example app on Android: + +```sh +yarn example android +``` + +To run the example app on iOS: + +```sh +yarn example ios +``` + +Make sure your code passes TypeScript and ESLint. Run the following to verify: + +```sh +yarn typescript +yarn lint +``` + +To fix formatting errors, run the following: + +```sh +yarn lint --fix +``` + +Remember to add tests for your change if possible. Run the unit tests by: + +```sh +yarn test +``` + +To edit the Objective-C files, open `example/ios/AgoraExample.xcworkspace` in XCode and find the source files at `Pods > Development Pods > react-native-agora`. + +To edit the Kotlin files, open `example/android` in Android studio and find the source files at `reactnativeagora` under `Android`. + +### Commit message convention + +We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages: + +- `fix`: bug fixes, e.g. fix crash due to deprecated method. +- `feat`: new features, e.g. add new method to the module. +- `refactor`: code refactor, e.g. migrate from class components to hooks. +- `docs`: changes into documentation, e.g. add usage example for the module.. +- `test`: adding or updating tests, eg add integration tests using detox. +- `chore`: tooling changes, e.g. change CI config. + +Our pre-commit hooks verify that your commit message matches this format when committing. + +### Linting and tests + +[ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [TypeScript](https://www.typescriptlang.org/) + +We use [TypeScript](https://www.typescriptlang.org/) for type checking, [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) for linting and formatting the code, and [Jest](https://jestjs.io/) for testing. + +Our pre-commit hooks verify that the linter and tests pass when committing. + +### Scripts + +The `package.json` file contains various scripts for common tasks: + +- `yarn bootstrap`: setup project by installing all dependencies and pods. +- `yarn typescript`: type-check files with TypeScript. +- `yarn lint`: lint files with ESLint. +- `yarn test`: run unit tests with Jest. +- `yarn example start`: start the Metro server for the example app. +- `yarn example android`: run the example app on Android. +- `yarn example ios`: run the example app on iOS. + +### Sending a pull request + +> **Working on your first pull request?** You can learn how from this _free_ series: [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). + +When you're sending a pull request: + +- Prefer small pull requests focused on one change. +- Verify that linters and tests are passing. +- Review the documentation to make sure it looks good. +- Follow the pull request template when opening a pull request. +- For pull requests that change the API or implementation, discuss with maintainers first by opening an issue. + +## Code of Conduct + +### Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +### Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or + advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email + address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +### Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +### Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +### Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [INSERT CONTACT METHOD]. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +### Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +#### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +#### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +#### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +#### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +### Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, +available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. diff --git a/LICENSE b/LICENSE index 49500e6b2..3f51f06a8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -The MIT License (MIT) +MIT License Copyright (c) 2020 syanbo luxuhui diff --git a/README.md b/README.md index c0b5b807e..fd31cf311 100644 --- a/README.md +++ b/README.md @@ -151,25 +151,10 @@ Source: https://github.com/facebook/react-native/issues/25154 * [File bugs about this sample](https://github.com/AgoraIO-Community/react-native-agora/issues) * [React Native Getting Started](https://facebook.github.io/react-native/docs/getting-started.html) -License --------- - - Copyright (c) 2020 syanbo luxuhui - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. +## Contributing + +See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow. + +## License + +MIT diff --git a/README.zh.md b/README.zh.md index 0e29159c3..fea166f57 100644 --- a/README.zh.md +++ b/README.zh.md @@ -151,25 +151,10 @@ React Native 0.59.9 已修复。 * [反馈问题](https://github.com/AgoraIO-Community/react-native-agora/issues) * [React Native 快速开始](https://facebook.github.io/react-native/docs/getting-started.html) -开源许可 --------- - - Copyright (c) 2020 syanbo luxuhui - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. +## 参与贡献 + +请参考 [contributing guide](CONTRIBUTING.md) 学习如何参与贡献并熟悉开发流程. + +## 开源许可 + +MIT diff --git a/android/build.gradle b/android/build.gradle index 376c77213..36b35e27e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,38 +1,134 @@ -def safeExtGet(prop, fallback) { - rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback -} - buildscript { - def kotlin_version = rootProject.ext.has('kotlin_version') ? rootProject.ext.get('kotlin_version') : '1.3.72' + // Buildscript is evaluated before everything else so we can't use getExtOrDefault + def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['Agora_kotlinVersion'] - repositories { - google() - jcenter() - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.2.1' + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } } apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +def getExtOrDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['Agora_' + name] +} + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['Agora_' + name]).toInteger() +} + android { - compileSdkVersion safeExtGet('compileSdkVersion', 28) - buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3') + compileSdkVersion getExtOrIntegerDefault('compileSdkVersion') + buildToolsVersion getExtOrDefault('buildToolsVersion') + defaultConfig { + minSdkVersion 16 + targetSdkVersion getExtOrIntegerDefault('targetSdkVersion') + versionCode 1 + versionName "1.0" + + consumerProguardFiles 'consumer-rules.pro' + } + + buildTypes { + release { + minifyEnabled false + } + } + lintOptions { + disable 'GradleCompatible' + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +repositories { + mavenCentral() + jcenter() + google() + + def found = false + def defaultDir = null + def androidSourcesName = 'React Native sources' - defaultConfig { - minSdkVersion safeExtGet('minSdkVersion', 16) - targetSdkVersion safeExtGet('targetSdkVersion', 28) + if (rootProject.ext.has('reactNativeAndroidRoot')) { + defaultDir = rootProject.ext.get('reactNativeAndroidRoot') + } else { + defaultDir = new File( + projectDir, + '/../../../node_modules/react-native/android' + ) + } - consumerProguardFiles 'consumer-rules.pro' + if (defaultDir.exists()) { + maven { + url defaultDir.toString() + name androidSourcesName } + + logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}") + found = true + } else { + def parentDir = rootProject.projectDir + + 1.upto(5, { + if (found) return true + parentDir = parentDir.parentFile + + def androidSourcesDir = new File( + parentDir, + 'node_modules/react-native' + ) + + def androidPrebuiltBinaryDir = new File( + parentDir, + 'node_modules/react-native/android' + ) + + if (androidPrebuiltBinaryDir.exists()) { + maven { + url androidPrebuiltBinaryDir.toString() + name androidSourcesName + } + + logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}") + found = true + } else if (androidSourcesDir.exists()) { + maven { + url androidSourcesDir.toString() + name androidSourcesName + } + + logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}") + found = true + } + }) + } + + 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." + ) + } } +def kotlin_version = getExtOrDefault('kotlinVersion') + dependencies { - implementation "com.facebook.react:react-native:+" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${safeExtGet('kotlin_version', '1.3.72')}" - implementation "org.jetbrains.kotlin:kotlin-reflect:${safeExtGet('kotlin_version', '1.3.72')}" - implementation "io.agora.rtc:full-sdk:3.1.2" + // noinspection GradleDynamicVersion + api 'com.facebook.react:react-native:+' + api "io.agora.rtc:full-sdk:3.1.2" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" } diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 000000000..fc4ef54a2 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +Agora_kotlinVersion=1.3.50 +Agora_compileSdkVersion=28 +Agora_buildToolsVersion=28.0.3 +Agora_targetSdkVersion=28 diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..f842b77fc --- /dev/null +++ b/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ['module:metro-react-native-babel-preset'], +}; diff --git a/example/android/.project b/example/android/.project new file mode 100644 index 000000000..3964dd3f5 --- /dev/null +++ b/example/android/.project @@ -0,0 +1,17 @@ + + + android + Project android created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/example/android/.settings/org.eclipse.buildship.core.prefs b/example/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..e8895216f --- /dev/null +++ b/example/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir= +eclipse.preferences.version=1 diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle new file mode 100644 index 000000000..cdc98bab0 --- /dev/null +++ b/example/android/app/build.gradle @@ -0,0 +1,222 @@ +apply plugin: "com.android.application" + +import com.android.build.OutputFile + +/** + * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets + * and bundleReleaseJsAndAssets). + * These basically call `react-native bundle` with the correct arguments during the Android build + * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the + * bundle directly from the development server. Below you can see all the possible configurations + * and their defaults. If you decide to add a configuration block, make sure to add it before the + * `apply from: "../../node_modules/react-native/react.gradle"` line. + * + * project.ext.react = [ + * // the name of the generated asset file containing your JS bundle + * bundleAssetName: "index.android.bundle", + * + * // the entry file for bundle generation + * entryFile: "index.android.js", + * + * // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format + * bundleCommand: "ram-bundle", + * + * // whether to bundle JS and assets in debug mode + * bundleInDebug: false, + * + * // whether to bundle JS and assets in release mode + * bundleInRelease: true, + * + * // whether to bundle JS and assets in another build variant (if configured). + * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants + * // The configuration property can be in the following formats + * // 'bundleIn${productFlavor}${buildType}' + * // 'bundleIn${buildType}' + * // bundleInFreeDebug: true, + * // bundleInPaidRelease: true, + * // bundleInBeta: true, + * + * // whether to disable dev mode in custom build variants (by default only disabled in release) + * // for AgoraExample: to disable dev mode in the staging build type (if configured) + * devDisabledInStaging: true, + * // The configuration property can be in the following formats + * // 'devDisabledIn${productFlavor}${buildType}' + * // 'devDisabledIn${buildType}' + * + * // the root of your project, i.e. where "package.json" lives + * root: "../../", + * + * // where to put the JS bundle asset in debug mode + * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", + * + * // where to put the JS bundle asset in release mode + * jsBundleDirRelease: "$buildDir/intermediates/assets/release", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in debug mode + * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in release mode + * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", + * + * // by default the gradle tasks are skipped if none of the JS files or assets change; this means + * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to + * // date; if you have any other folders that you want to ignore for performance reasons (gradle + * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ + * // for AgoraExample, you might want to remove it from here. + * inputExcludes: ["android/**", "ios/**"], + * + * // override which node gets called and with what additional arguments + * nodeExecutableAndArgs: ["node"], + * + * // supply additional arguments to the packager + * extraPackagerArgs: [] + * ] + */ + +project.ext.react = [ + enableHermes: false, // clean and rebuild if changing +] + +apply from: "../../node_modules/react-native/react.gradle" + +/** + * Set this to true to create two separate APKs instead of one: + * - An APK that only works on ARM devices + * - An APK that only works on x86 devices + * The advantage is the size of the APK is reduced by about 4MB. + * Upload all the APKs to the Play Store and people will download + * the correct one based on the CPU architecture of their device. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Run Proguard to shrink the Java bytecode in release builds. + */ +def enableProguardInReleaseBuilds = false + +/** + * The preferred build flavor of JavaScriptCore. + * + * For AgoraExample, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ +def jscFlavor = 'org.webkit:android-jsc:+' + +/** + * Whether to enable the Hermes VM. + * + * This should be set on project.ext.react and mirrored here. If it is not set + * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode + * and the benefits of using Hermes will therefore be sharply reduced. + */ +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" + } + 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' + } + } + 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 + } + + } + } + + 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') +} + +// 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' +} + +apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/example/android/app/debug.keystore b/example/android/app/debug.keystore new file mode 100644 index 0000000000000000000000000000000000000000..364e105ed39fbfd62001429a68140672b06ec0de GIT binary patch literal 2257 zcmchYXEfYt8;7T1^dLH$VOTZ%2NOdOH5j5LYLtZ0q7x-V8_6gU5)#7dkq{HTmsfNq zB3ZqcAxeY^G10@?efK?Q&)M(qInVv!xjx+IKEL}p*K@LYvIzo#AZG>st5|P)KF1_Z;y){W{<7K{nl!CPuE z_^(!C(Ol0n8 zK13*rzAtW>(wULKPRYLd7G18F8#1P`V*9`(Poj26eOXYyBVZPno~Cvvhx7vPjAuZo zF?VD!zB~QG(!zbw#qsxT8%BSpqMZ4f70ZPn-3y$L8{EVbbN9$H`B&Z1quk9tgp5FM zuxp3pJ0b8u|3+#5bkJ4SRnCF2l7#DyLYXYY8*?OuAwK4E6J{0N=O3QNVzQ$L#FKkR zi-c@&!nDvezOV$i$Lr}iF$XEcwnybQ6WZrMKuw8gCL^U#D;q3t&HpTbqyD%vG=TeDlzCT~MXUPC|Leb-Uk+ z=vnMd(|>ld?Fh>V8poP;q;;nc@en$|rnP0ytzD&fFkCeUE^kG9Kx4wUh!!rpjwKDP zyw_e|a^x_w3E zP}}@$g>*LLJ4i0`Gx)qltL}@;mDv}D*xR^oeWcWdPkW@Uu)B^X&4W1$p6}ze!zudJ zyiLg@uggoMIArBr*27EZV7djDg@W1MaL+rcZ-lrANJQ%%>u8)ZMWU@R2qtnmG(acP z0d_^!t>}5W zpT`*2NR+0+SpTHb+6Js4b;%LJB;B_-ChhnU5py}iJtku*hm5F0!iql8Hrpcy1aYbT z1*dKC5ua6pMX@@iONI?Hpr%h;&YaXp9n!ND7-=a%BD7v&g zOO41M6EbE24mJ#S$Ui0-brR5ML%@|ndz^)YLMMV1atna{Fw<;TF@>d&F|!Z>8eg>>hkFrV)W+uv=`^F9^e zzzM2*oOjT9%gLoub%(R57p-`TXFe#oh1_{&N-YN z<}artH|m=d8TQuKSWE)Z%puU|g|^^NFwC#N=@dPhasyYjoy(fdEVfKR@cXKHZV-`06HsP`|Ftx;8(YD$fFXumLWbGnu$GMqRncXYY9mwz9$ap zQtfZB^_BeNYITh^hA7+(XNFox5WMeG_LtJ%*Q}$8VKDI_p8^pqX)}NMb`0e|wgF7D zuQACY_Ua<1ri{;Jwt@_1sW9zzdgnyh_O#8y+C;LcZq6=4e^cs6KvmK@$vVpKFGbQ= z$)Eux5C|Fx;Gtmv9^#Y-g@7Rt7*eLp5n!gJmn7&B_L$G?NCN`AP>cXQEz}%F%K;vUs{+l4Q{}eWW;ATe2 zqvXzxoIDy(u;F2q1JH7Sf;{jy_j})F+cKlIOmNfjBGHoG^CN zM|Ho&&X|L-36f}Q-obEACz`sI%2f&k>z5c$2TyTSj~vmO)BW~+N^kt`Jt@R|s!){H ze1_eCrlNaPkJQhL$WG&iRvF*YG=gXd1IyYQ9ew|iYn7r~g!wOnw;@n42>enAxBv*A zEmV*N#sxdicyNM=A4|yaOC5MByts}s_Hpfj|y<6G=o=!3S@eIFKDdpR7|FY>L&Wat&oW&cm&X~ z5Bt>Fcq(fgnvlvLSYg&o6>&fY`ODg4`V^lWWD=%oJ#Kbad2u~! zLECFS*??>|vDsNR&pH=Ze0Eo`sC_G`OjoEKVHY|wmwlX&(XBE<@sx3Hd^gtd-fNwUHsylg06p`U2y_={u}Bc + + + + + + diff --git a/example/android/app/src/debug/java/com/example/reactnativeagora/ReactNativeFlipper.java b/example/android/app/src/debug/java/com/example/reactnativeagora/ReactNativeFlipper.java new file mode 100644 index 000000000..533f5e00b --- /dev/null +++ b/example/android/app/src/debug/java/com/example/reactnativeagora/ReactNativeFlipper.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.example.reactnativeagora; + +import android.content.Context; +import com.facebook.flipper.android.AndroidFlipperClient; +import com.facebook.flipper.android.utils.FlipperUtils; +import com.facebook.flipper.core.FlipperClient; +import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; +import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; +import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; +import com.facebook.flipper.plugins.inspector.DescriptorMapping; +import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; +import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; +import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; +import com.facebook.flipper.plugins.react.ReactFlipperPlugin; +import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.modules.network.NetworkingModule; +import okhttp3.OkHttpClient; + +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + if (FlipperUtils.shouldEnableFlipper(context)) { + final FlipperClient client = AndroidFlipperClient.getInstance(context); + client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); + client.addPlugin(new ReactFlipperPlugin()); + client.addPlugin(new DatabasesFlipperPlugin(context)); + client.addPlugin(new SharedPreferencesFlipperPlugin(context)); + client.addPlugin(CrashReporterPlugin.getInstance()); + NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); + NetworkingModule.setCustomClientBuilder( + new NetworkingModule.CustomClientBuilder() { + @Override + public void apply(OkHttpClient.Builder builder) { + builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); + } + }); + client.addPlugin(networkFlipperPlugin); + client.start(); + // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized + // Hence we run if after all native modules have been initialized + ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); + if (reactContext == null) { + reactInstanceManager.addReactInstanceEventListener( + new ReactInstanceManager.ReactInstanceEventListener() { + @Override + public void onReactContextInitialized(ReactContext reactContext) { + reactInstanceManager.removeReactInstanceEventListener(this); + reactContext.runOnNativeModulesQueueThread( + new Runnable() { + @Override + public void run() { + client.addPlugin(new FrescoFlipperPlugin()); + } + }); + } + }); + } else { + client.addPlugin(new FrescoFlipperPlugin()); + } + } + } +} diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..52950f2da --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + diff --git a/example/android/app/src/main/java/com/example/reactnativeagora/MainActivity.java b/example/android/app/src/main/java/com/example/reactnativeagora/MainActivity.java new file mode 100644 index 000000000..f37ad495f --- /dev/null +++ b/example/android/app/src/main/java/com/example/reactnativeagora/MainActivity.java @@ -0,0 +1,15 @@ +package com.example.reactnativeagora; + +import com.facebook.react.ReactActivity; + +public class MainActivity extends ReactActivity { + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + @Override + protected String getMainComponentName() { + return "AgoraExample"; + } +} diff --git a/example/android/app/src/main/java/com/example/reactnativeagora/MainApplication.java b/example/android/app/src/main/java/com/example/reactnativeagora/MainApplication.java new file mode 100644 index 000000000..fc1670b32 --- /dev/null +++ b/example/android/app/src/main/java/com/example/reactnativeagora/MainApplication.java @@ -0,0 +1,81 @@ +package com.example.reactnativeagora; + +import android.app.Application; +import android.content.Context; +import com.facebook.react.PackageList; +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.ReactInstanceManager; +import com.facebook.soloader.SoLoader; +import java.lang.reflect.InvocationTargetException; +import java.util.List; + +import io.agora.rtc.react.RCTAgoraRtcPackage; + +public class MainApplication extends Application implements ReactApplication { + + private final ReactNativeHost mReactNativeHost = + new ReactNativeHost(this) { + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + @Override + protected List getPackages() { + @SuppressWarnings("UnnecessaryLocalVariable") + List packages = new PackageList(this).getPackages(); + // Packages that cannot be autolinked yet can be added manually here, for AgoraExample: + // packages.add(new MyReactNativePackage()); + packages.add(new RCTAgoraRtcPackage()); + + return packages; + } + + @Override + protected String getJSMainModuleName() { + return "index"; + } + }; + + @Override + public ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } + + @Override + public void onCreate() { + super.onCreate(); + SoLoader.init(this, /* native exopackage */ false); + initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); // Remove this line if you don't want Flipper enabled + } + + /** + * Loads Flipper in React Native templates. + * + * @param context + */ + private static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + if (BuildConfig.DEBUG) { + try { + /* + We use reflection here to pick up the class that initializes Flipper, + since Flipper library is not available in release mode + */ + Class aClass = Class.forName("com.reactnativeagoraExample.ReactNativeFlipper"); + aClass + .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) + .invoke(null, context, reactInstanceManager); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + } +} diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f5908281d070150700378b64a84c7db1f97aa1 GIT binary patch literal 3056 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 axPAxe%7rDusX+w*00006jj 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⁣ zwiG+x#%j}{0gU~J8;<|!B1@-XaB@{KORFwrYg_8rOv({b0EO#DbeQRm;B6_9=mXGf z-x|VL{zd`)#@yN}HkCSJbjbNlE|zL3Wm9Q8HY`sV)}3%pgN>cL^67{Z;PPL(*wT8N zUjXU{@|*hvm}({wsAC=x0^ok0%UAz0;sogW{B!nDqk|JJ5x~4NfTDgP49^zeu`csl?5mY@JdQdISc zFs!E{^grmkLnUk9 zny~m)1vws@5BFI<-0Tuo2JWX(0v`W|t(wg;s--L47WTvTMz-8l#TL^=OJNRS2?_Qj z3AKT+gvbyBi#H*-tJ%tWD|>EV3wy|8qxfzS!5RW;Jpl5*zo&^UBU=fG#2}UvRyNkK zA06Dy9;K1ca@r2T>yThYgI!ont$(G{6q#2QT+00r_x0(b)gsE`lBB?2gr55gq^D3Fi&p%E(p9>U%bv zkg1Jco(RbyTX7FDHOnl7-O@ zI$AaIl?9NJKPm(WiBP`1-#CB1QzU>&hKm)fpa5DKE{2$X0hGz-0uZ?cyTk(YC!Y&| zL=1VrNERSA5NA2jq7FACfX4JfPyj5XXl1yv0>~s;eF7L2$>&oMqeTFT2m$y7FlkON z_yurD1yIOvA;5C6016pyxBznGUt0kJ&k5r#;&>Jow`r)sp9R~PmK~lz$3xH%LT*1U zJdOyABZ3!FvNoR*vN$5ykHS8f`jA4zV+|L}i1C4`B2c{R0;UdYxaU|H)2avz@ z=mEYc|2S<+(B2Tj+FkX+2D+yFI!k9lWMA61DJ{)e;lum$(;O87?vGJJe!KtK04+N_ zI*P~t@dUb>9Xh{dbyl{-ZQ(UMgz7$|QfL5XSPkskt^NgctYC#;4WcZB1@%@wy@2t3 z2z0DI7&%b$*Aw~abe?GxE`ez@+6hOh-6*8fHRV{1os$EL@}uUZeG4h1&Be`98q*7j z=3-v+lhIjfWVo12!<>%V^a6lTgW3+_#W6n|p*~==zOH7z$0{LSZk(Tpd7EaD04hnA zL;#fxS0aD{`5^&D`}>0Uq?byDD-l2=!wm_bLcUl4gc(% za1p|itVANvFF>hghAS07Im1;IK;|b*W)}VDyI;BIp2=K*yu2a)j?B|f<44NI$NbmJ z#dE0>jI$fMr&@>4kN8MLFb4&2O9fEKaQg%(QO$4_1rVQywG^CmBLh#}_7gKW3vd?| z2?1^&KWq8}8I^_S0|)MowU_pw$q@nl@Nkn$z>BQq_KA^9yaR`(R3u{{Ig;cwt z@AJ^{ODQCm^neroM9nKNUAXi9RCK`OsP_LuR0PUR(YZCCX5dNF6VzcoK&=b^r`W?ltt|*F zpkoae%ZT{C1h~EcFui~b7fF`vb<<~j_VquuUA$}QqIKYELPp#;{u?q8Dz}WAG-(3; zjrm$i%7UbyZMM(Y{>!uJ#vNB?R~B{6Htp=>e*<{fQQ5W7V(1coCWlOON!MzZxhum| ztZBQpGR z;~#ur^&PockKdV{Q6R>o`Pl{0x!DEbpZ7y9Y;*ZvE!*gU`V1W3znva{f=?WO5I&>B z&hw6}tjECtaghm5z|C#%M;Yf_*pI^};h}Vl=^r9EN=tVDj86D;C$jIJ?K7VP+00000NkvXXu0mjf D5i!M* literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..459ca609d3ae0d3943ab44cdc27feef9256dc6d7 GIT binary patch literal 7098 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 literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca12fe024be86e868d14e91120a6902f8e88ac6 GIT binary patch literal 6464 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 B0*L?s literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..8e19b410a1b15ff180f3dacac19395fe3046cdec GIT binary patch literal 10676 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 literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..4c19a13c239cb67b8a2134ddd5f325db1d2d5bee GIT binary patch literal 15523 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 BIP(Ai literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/values/strings.xml b/example/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..e8e419ef0 --- /dev/null +++ b/example/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Agora Example + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..62fe59fa4 --- /dev/null +++ b/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle new file mode 100644 index 000000000..5d5d188b3 --- /dev/null +++ b/example/android/build.gradle @@ -0,0 +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") + + // 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' } + } +} diff --git a/example/android/gradle.properties b/example/android/gradle.properties new file mode 100644 index 000000000..d09f17e0e --- /dev/null +++ b/example/android/gradle.properties @@ -0,0 +1,22 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +android.useAndroidX=true +android.enableJetifier=true +FLIPPER_VERSION=0.33.1 diff --git a/example/android/gradle/wrapper/gradle-wrapper.jar b/example/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..5c2d1cf016b3885f6930543d57b744ea8c220a1a GIT binary patch literal 55616 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/example/android/gradlew.bat b/example/android/gradlew.bat new file mode 100644 index 000000000..9991c5032 --- /dev/null +++ b/example/android/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/example/android/settings.gradle b/example/android/settings.gradle new file mode 100644 index 000000000..ed8ccdd9a --- /dev/null +++ b/example/android/settings.gradle @@ -0,0 +1,6 @@ +rootProject.name = 'AgoraExample' +apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) +include ':app' + +include ':react-native-agora' +project(':react-native-agora').projectDir = new File(rootProject.projectDir, '../../android') diff --git a/example/app.json b/example/app.json new file mode 100644 index 000000000..e53420e6d --- /dev/null +++ b/example/app.json @@ -0,0 +1,4 @@ +{ + "name": "AgoraExample", + "displayName": "Agora Example" +} diff --git a/example/babel.config.js b/example/babel.config.js new file mode 100644 index 000000000..db64a007b --- /dev/null +++ b/example/babel.config.js @@ -0,0 +1,16 @@ +const path = require('path'); +const pak = require('../package.json'); + +module.exports = { + presets: ['module:metro-react-native-babel-preset'], + plugins: [ + [ + 'module-resolver', + { + alias: { + [pak.name]: path.join(__dirname, '..', pak.source), + }, + }, + ], + ], +}; diff --git a/example/index.tsx b/example/index.tsx new file mode 100644 index 000000000..117ddcae4 --- /dev/null +++ b/example/index.tsx @@ -0,0 +1,5 @@ +import { AppRegistry } from 'react-native'; +import App from './src/App'; +import { name as appName } from './app.json'; + +AppRegistry.registerComponent(appName, () => App); diff --git a/example/ios/AgoraExample-Bridging-Header.h b/example/ios/AgoraExample-Bridging-Header.h new file mode 100644 index 000000000..e11d920b1 --- /dev/null +++ b/example/ios/AgoraExample-Bridging-Header.h @@ -0,0 +1,3 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// diff --git a/example/ios/AgoraExample.xcodeproj/project.pbxproj b/example/ios/AgoraExample.xcodeproj/project.pbxproj new file mode 100644 index 000000000..c816ad72e --- /dev/null +++ b/example/ios/AgoraExample.xcodeproj/project.pbxproj @@ -0,0 +1,462 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0D1336C0461A88D01186E375 /* libPods-AgoraExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BCEA90A70F4BEAD7E9FA28B2 /* libPods-AgoraExample.a */; }; + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 20F357B024636CDF00C146DC /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20F357AF24636CDF00C146DC /* File.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* AgoraExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AgoraExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = AgoraExample/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = AgoraExample/AppDelegate.m; sourceTree = ""; }; + 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = AgoraExample/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = AgoraExample/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = AgoraExample/main.m; sourceTree = ""; }; + 20F357AD24636CDE00C146DC /* AgoraExample-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AgoraExample-Bridging-Header.h"; sourceTree = ""; }; + 20F357AE24636CDF00C146DC /* AgoraExample-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AgoraExample-Bridging-Header.h"; sourceTree = ""; }; + 20F357AF24636CDF00C146DC /* File.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; }; + 4D7192F03A36A017E887435B /* Pods-AgoraExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AgoraExample.release.xcconfig"; path = "Target Support Files/Pods-AgoraExample/Pods-AgoraExample.release.xcconfig"; sourceTree = ""; }; + 871719007ECC5EAD276C345C /* Pods-AgoraExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AgoraExample.debug.xcconfig"; path = "Target Support Files/Pods-AgoraExample/Pods-AgoraExample.debug.xcconfig"; sourceTree = ""; }; + BCEA90A70F4BEAD7E9FA28B2 /* libPods-AgoraExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AgoraExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0D1336C0461A88D01186E375 /* libPods-AgoraExample.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 13B07FAE1A68108700A75B9A /* AgoraExample */ = { + isa = PBXGroup; + children = ( + 008F07F21AC5B25A0029DE68 /* main.jsbundle */, + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.m */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = AgoraExample; + sourceTree = ""; + }; + 1CFFDEF7170271C97B8B7E5A /* Pods */ = { + isa = PBXGroup; + children = ( + 871719007ECC5EAD276C345C /* Pods-AgoraExample.debug.xcconfig */, + 4D7192F03A36A017E887435B /* Pods-AgoraExample.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ED297162215061F000B7C4FE /* JavaScriptCore.framework */, + BCEA90A70F4BEAD7E9FA28B2 /* libPods-AgoraExample.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = Libraries; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 20F357AF24636CDF00C146DC /* File.swift */, + 20F357AE24636CDF00C146DC /* AgoraExample-Bridging-Header.h */, + 13B07FAE1A68108700A75B9A /* AgoraExample */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 83CBBA001A601CBA00E9B192 /* Products */, + 2D16E6871FA4F8E400B85C8A /* Frameworks */, + 1CFFDEF7170271C97B8B7E5A /* Pods */, + 20F357AD24636CDE00C146DC /* AgoraExample-Bridging-Header.h */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* AgoraExample.app */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 13B07F861A680F5B00A75B9A /* AgoraExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "AgoraExample" */; + buildPhases = ( + CCCC07BCAFDEF1FCADC0D0C9 /* [CP] Check Pods Manifest.lock */, + FD10A7F022414F080027D42C /* Start Packager */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 784B7493D27387E7554188B3 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AgoraExample; + productName = AgoraExample; + productReference = 13B07F961A680F5B00A75B9A /* AgoraExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0940; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 13B07F861A680F5B00A75B9A = { + LastSwiftMigration = 1110; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "AgoraExample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* AgoraExample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; + }; + 784B7493D27387E7554188B3 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + 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", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AgoraRtcKit.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AgoraRtcCryptoLoader.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AgoraExample/Pods-AgoraExample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + CCCC07BCAFDEF1FCADC0D0C9 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-AgoraExample-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + FD10A7F022414F080027D42C /* Start Packager */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Start Packager"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + 20F357B024636CDF00C146DC /* File.swift in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 13B07FB21A68108700A75B9A /* Base */, + ); + name = LaunchScreen.xib; + path = AgoraExample; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 871719007ECC5EAD276C345C /* Pods-AgoraExample.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = NO; + INFOPLIST_FILE = AgoraExample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_CFLAGS = ( + "$(inherited)", + "-DFB_SONARKIT_ENABLED=1", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.AgoraExample.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = AgoraExample; + SWIFT_OBJC_BRIDGING_HEADER = "AgoraExample-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4D7192F03A36A017E887435B /* Pods-AgoraExample.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + INFOPLIST_FILE = AgoraExample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_CFLAGS = ( + "$(inherited)", + "-DFB_SONARKIT_ENABLED=1", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.AgoraExample.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = AgoraExample; + SWIFT_OBJC_BRIDGING_HEADER = "AgoraExample-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "AgoraExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "AgoraExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/example/ios/AgoraExample.xcodeproj/xcshareddata/xcschemes/AgoraExample.xcscheme b/example/ios/AgoraExample.xcodeproj/xcshareddata/xcschemes/AgoraExample.xcscheme new file mode 100644 index 000000000..ecfd19fe0 --- /dev/null +++ b/example/ios/AgoraExample.xcodeproj/xcshareddata/xcschemes/AgoraExample.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/AgoraExample.xcworkspace/contents.xcworkspacedata b/example/ios/AgoraExample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..59283523c --- /dev/null +++ b/example/ios/AgoraExample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/ios/AgoraExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/AgoraExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/example/ios/AgoraExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/AgoraExample/AppDelegate.h b/example/ios/AgoraExample/AppDelegate.h new file mode 100644 index 000000000..2726d5e13 --- /dev/null +++ b/example/ios/AgoraExample/AppDelegate.h @@ -0,0 +1,15 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import + +@interface AppDelegate : UIResponder + +@property (nonatomic, strong) UIWindow *window; + +@end diff --git a/example/ios/AgoraExample/AppDelegate.m b/example/ios/AgoraExample/AppDelegate.m new file mode 100644 index 000000000..76882f3d3 --- /dev/null +++ b/example/ios/AgoraExample/AppDelegate.m @@ -0,0 +1,63 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "AppDelegate.h" + +#import +#import +#import + +#if DEBUG +#import +#import +#import +#import +#import +#import +static void InitializeFlipper(UIApplication *application) { + FlipperClient *client = [FlipperClient sharedClient]; + SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; + [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; + [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; + [client addPlugin:[FlipperKitReactPlugin new]]; + [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; + [client start]; +} +#endif + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + #if DEBUG + InitializeFlipper(application); + #endif + RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge + moduleName:@"AgoraExample" + initialProperties:nil]; + + rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; + + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + UIViewController *rootViewController = [UIViewController new]; + rootViewController.view = rootView; + self.window.rootViewController = rootViewController; + [self.window makeKeyAndVisible]; + return YES; +} + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ +#if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; +#else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; +#endif +} + +@end diff --git a/example/ios/AgoraExample/Base.lproj/LaunchScreen.xib b/example/ios/AgoraExample/Base.lproj/LaunchScreen.xib new file mode 100644 index 000000000..88d0c4dbd --- /dev/null +++ b/example/ios/AgoraExample/Base.lproj/LaunchScreen.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/AgoraExample/Images.xcassets/AppIcon.appiconset/Contents.json b/example/ios/AgoraExample/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..118c98f74 --- /dev/null +++ b/example/ios/AgoraExample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/example/ios/AgoraExample/Images.xcassets/Contents.json b/example/ios/AgoraExample/Images.xcassets/Contents.json new file mode 100644 index 000000000..2d92bd53f --- /dev/null +++ b/example/ios/AgoraExample/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/AgoraExample/Info.plist b/example/ios/AgoraExample/Info.plist new file mode 100644 index 000000000..41790beb9 --- /dev/null +++ b/example/ios/AgoraExample/Info.plist @@ -0,0 +1,57 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Agora Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSExceptionDomains + + localhost + + NSExceptionAllowsInsecureHTTPLoads + + + + + NSLocationWhenInUseUsageDescription + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/example/ios/AgoraExample/main.m b/example/ios/AgoraExample/main.m new file mode 100644 index 000000000..c316cf816 --- /dev/null +++ b/example/ios/AgoraExample/main.m @@ -0,0 +1,16 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/example/ios/File.swift b/example/ios/File.swift new file mode 100644 index 000000000..aae0fbc1a --- /dev/null +++ b/example/ios/File.swift @@ -0,0 +1,6 @@ +// +// File.swift +// AgoraExample +// + +import Foundation diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 000000000..73def3ff0 --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,68 @@ +platform :ios, '9.0' +require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' + +def add_flipper_pods! + version = '~> 0.33.1' + pod 'FlipperKit', version, :configuration => 'Debug' + pod 'FlipperKit/FlipperKitLayoutPlugin', version, :configuration => 'Debug' + pod 'FlipperKit/SKIOSNetworkPlugin', version, :configuration => 'Debug' + pod 'FlipperKit/FlipperKitUserDefaultsPlugin', version, :configuration => 'Debug' + pod 'FlipperKit/FlipperKitReactPlugin', version, :configuration => 'Debug' +end +# Post Install processing for Flipper +def flipper_post_install(installer) + installer.pods_project.targets.each do |target| + if target.name == 'YogaKit' + target.build_configurations.each do |config| + config.build_settings['SWIFT_VERSION'] = '4.1' + end + end + end +end + +target 'AgoraExample' do + # Pods for AgoraExample + pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" + pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" + pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" + pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" + pod 'React', :path => '../node_modules/react-native/' + pod 'React-Core', :path => '../node_modules/react-native/' + pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' + pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' + pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' + pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' + pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' + pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' + pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' + pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' + pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' + pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' + pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' + pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/' + + pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' + pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' + pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' + pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' + pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon" + pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" + pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => true + + pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' + pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' + pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' + + pod 'react-native-agora', :path => '../..' + + use_native_modules! + + # Enables Flipper. + # + # Note that if you have use_frameworks! enabled, Flipper will not work and + # you should disable these next few lines. + add_flipper_pods! + post_install do |installer| + flipper_post_install(installer) + end +end diff --git a/example/metro.config.js b/example/metro.config.js new file mode 100644 index 000000000..d1f468ab0 --- /dev/null +++ b/example/metro.config.js @@ -0,0 +1,40 @@ +const path = require('path'); +const blacklist = require('metro-config/src/defaults/blacklist'); +const escape = require('escape-string-regexp'); +const pak = require('../package.json'); + +const root = path.resolve(__dirname, '..'); + +const modules = Object.keys({ + ...pak.peerDependencies, +}); + +module.exports = { + projectRoot: __dirname, + watchFolders: [root], + + // We need to make sure that only one version is loaded for peerDependencies + // So we blacklist them at the root, and alias them to the versions in example's node_modules + resolver: { + blacklistRE: blacklist( + modules.map( + (m) => + new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) + ) + ), + + extraNodeModules: modules.reduce((acc, name) => { + acc[name] = path.join(__dirname, 'node_modules', name); + return acc; + }, {}), + }, + + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }), + }, +}; diff --git a/example/package.json b/example/package.json new file mode 100644 index 000000000..44659bd31 --- /dev/null +++ b/example/package.json @@ -0,0 +1,21 @@ +{ + "name": "react-native-agora-example", + "description": "Example app for react-native-agora", + "version": "0.0.1", + "private": true, + "scripts": { + "android": "react-native run-android", + "ios": "react-native run-ios", + "start": "react-native start" + }, + "dependencies": { + "react": "16.11.0", + "react-native": "0.62.2" + }, + "devDependencies": { + "@babel/core": "^7.9.6", + "@babel/runtime": "^7.9.6", + "babel-plugin-module-resolver": "^4.0.0", + "metro-react-native-babel-preset": "^0.59.0" + } +} diff --git a/example/src/App.tsx b/example/src/App.tsx new file mode 100644 index 000000000..1e12c57c9 --- /dev/null +++ b/example/src/App.tsx @@ -0,0 +1,31 @@ +import * as React from 'react'; +import { StyleSheet, View, Text } from 'react-native'; +import RtcEngine, { RtcChannel } from 'react-native-agora'; + +export default function App() { + const [result, setResult] = React.useState(); + + React.useEffect(() => { + RtcEngine.create('2b4b76e458cf439aa7cd313b9504f0a4').then(() => { + RtcChannel.create('xxx').then((channel: RtcChannel) => { + setResult(channel.channelId); + }); + }); + }, []); + + return ( + + Result: {result} + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + }, + text: { + textAlign: 'center', + }, +}); diff --git a/example/yarn.lock b/example/yarn.lock new file mode 100644 index 000000000..54e6e94c2 --- /dev/null +++ b/example/yarn.lock @@ -0,0 +1,4473 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/core@^7.0.0", "@babel/core@^7.9.6": + version "7.12.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.3.tgz#1b436884e1e3bff6fb1328dc02b208759de92ad8" + integrity sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.1" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.1" + "@babel/parser" "^7.12.3" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.12.1", "@babel/generator@^7.5.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.1.tgz#0d70be32bdaa03d7c51c8597dda76e0df1f15468" + integrity sha512-DB+6rafIdc9o72Yc3/Ph5h+6hUjeOp66pF0naQBgUFFuPqzQwIlPTm3xZR7YNvduIMtkDIj2t21LSQwnbCrXvg== + dependencies: + "@babel/types" "^7.12.1" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" + integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" + integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-builder-react-jsx-experimental@^7.12.1": + version "7.12.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.12.4.tgz#55fc1ead5242caa0ca2875dcb8eed6d311e50f48" + integrity sha512-AjEa0jrQqNk7eDQOo0pTfUOwQBMF+xVqrausQwT9/rTKy0g04ggFNaJpaE09IQMn9yExluigWMJcj0WC7bq+Og== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-module-imports" "^7.12.1" + "@babel/types" "^7.12.1" + +"@babel/helper-builder-react-jsx@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.4.tgz#8095cddbff858e6fa9c326daee54a2f2732c1d5d" + integrity sha512-5nPcIZ7+KKDxT1427oBivl9V9YTal7qk0diccnh7RrcgrT/pGFOjgGw1dgryyx1GvHEpXVfoDF6Ak3rTiWh8Rg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-create-class-features-plugin@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz#3c45998f431edd4a9214c5f1d3ad1448a6137f6e" + integrity sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-member-expression-to-functions" "^7.12.1" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-replace-supers" "^7.12.1" + "@babel/helper-split-export-declaration" "^7.10.4" + +"@babel/helper-create-regexp-features-plugin@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.1.tgz#18b1302d4677f9dc4740fe8c9ed96680e29d37e8" + integrity sha512-rsZ4LGvFTZnzdNZR5HZdmJVuXK8834R5QkF3WvcnBhrlVtF0HSIUC6zbreL9MgjTywhKokn8RIYRiq99+DLAxA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-regex" "^7.10.4" + regexpu-core "^4.7.1" + +"@babel/helper-define-map@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30" + integrity sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/types" "^7.10.5" + lodash "^4.17.19" + +"@babel/helper-explode-assignable-expression@^7.10.4": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz#8006a466695c4ad86a2a5f2fb15b5f2c31ad5633" + integrity sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" + integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== + dependencies: + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-get-function-arity@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" + integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-member-expression-to-functions@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz#fba0f2fcff3fba00e6ecb664bb5e6e26e2d6165c" + integrity sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-module-imports@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.1.tgz#1644c01591a15a2f084dd6d092d9430eb1d1216c" + integrity sha512-ZeC1TlMSvikvJNy1v/wPIazCu3NdOwgYZLIkmIyAsGhqkNpiDoQQRmaCK8YP4Pq3GPTLPV9WXaPCJKvx06JxKA== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-module-transforms@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c" + integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w== + dependencies: + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-replace-supers" "^7.12.1" + "@babel/helper-simple-access" "^7.12.1" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/helper-validator-identifier" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + lodash "^4.17.19" + +"@babel/helper-optimise-call-expression@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" + integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + +"@babel/helper-regex@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" + integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== + dependencies: + lodash "^4.17.19" + +"@babel/helper-remap-async-to-generator@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz#8c4dbbf916314f6047dc05e6a2217074238347fd" + integrity sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-wrap-function" "^7.10.4" + "@babel/types" "^7.12.1" + +"@babel/helper-replace-supers@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.1.tgz#f15c9cc897439281891e11d5ce12562ac0cf3fa9" + integrity sha512-zJjTvtNJnCFsCXVi5rUInstLd/EIVNmIKA1Q9ynESmMBWPWd+7sdR+G4/wdu+Mppfep0XLyG2m7EBPvjCeFyrw== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.12.1" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + +"@babel/helper-simple-access@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz#32427e5aa61547d38eb1e6eaf5fd1426fdad9136" + integrity sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-skip-transparent-expression-wrappers@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf" + integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" + integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== + dependencies: + "@babel/types" "^7.11.0" + +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== + +"@babel/helper-wrap-function@^7.10.4": + version "7.12.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz#3332339fc4d1fbbf1c27d7958c27d34708e990d9" + integrity sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helpers@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.1.tgz#8a8261c1d438ec18cb890434df4ec768734c1e79" + integrity sha512-9JoDSBGoWtmbay98efmT2+mySkwjzeFeAL9BuWNoVQpkPFQF8SIIFUfY5os9u8wVzglzoiPRSW7cuJmBDUt43g== + dependencies: + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.0.0", "@babel/parser@^7.10.4", "@babel/parser@^7.12.1", "@babel/parser@^7.12.3": + version "7.12.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.3.tgz#a305415ebe7a6c7023b40b5122a0662d928334cd" + integrity sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw== + +"@babel/plugin-external-helpers@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.12.1.tgz#df474775860b3b8bdfeaedd45596cd2c7f36a2be" + integrity sha512-5VBqan0daXhDSRjrq2miABuELRwWJWFdM42Jvs/CDuhp+Es+fW+ISA5l+co8d+9oN3WLz/N3VvzyeseL3AvjxA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-proposal-class-properties@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz#a082ff541f2a29a4821065b8add9346c0c16e5de" + integrity sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-proposal-export-default-from@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.12.1.tgz#c6e62d668a8abcfe0d28b82f560395fecb611c5a" + integrity sha512-z5Q4Ke7j0AexQRfgUvnD+BdCSgpTEKnqQ3kskk2jWtOBulxICzd1X9BGt7kmWftxZ2W3++OZdt5gtmC8KLxdRQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-export-default-from" "^7.12.1" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz#3ed4fff31c015e7f3f1467f190dbe545cd7b046c" + integrity sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-object-rest-spread@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz#def9bd03cea0f9b72283dac0ec22d289c7691069" + integrity sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-transform-parameters" "^7.12.1" + +"@babel/plugin-proposal-optional-catch-binding@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz#ccc2421af64d3aae50b558a71cede929a5ab2942" + integrity sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + +"@babel/plugin-proposal-optional-chaining@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.1.tgz#cce122203fc8a32794296fc377c6dedaf4363797" + integrity sha512-c2uRpY6WzaVDzynVY9liyykS+kVU+WRZPMPYpkelXH8KBt1oXoI89kPbZKKG/jDT5UK92FTW2fZkZaJhdiBabw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz#bcb297c5366e79bebadef509549cd93b04f19978" + integrity sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-dynamic-import@^7.0.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-default-from@^7.0.0", "@babel/plugin-syntax-export-default-from@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.12.1.tgz#a9eb31881f4f9a1115a3d2c6d64ac3f6016b5a9d" + integrity sha512-dP5eGg6tHEkhnRD2/vRG/KJKRSg8gtxu2i+P/8/yFPJn/CfPU5G0/7Gks2i3M6IOVAPQekmsLN9LPsmXFFL4Uw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.12.1", "@babel/plugin-syntax-flow@^7.2.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.12.1.tgz#a77670d9abe6d63e8acadf4c31bb1eb5a506bbdd" + integrity sha512-1lBLLmtxrwpm4VKmtVFselI/P3pX+G63fAtUUt6b2Nzgao77KNDwyuRt90Mj2/9pKobtt68FdvjfqohZjg/FCA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz#9d9d357cc818aa7ae7935917c1257f67677a0926" + integrity sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.0.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.0.0", "@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-typescript@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.1.tgz#460ba9d77077653803c3dd2e673f76d66b4029e5" + integrity sha512-UZNEcCY+4Dp9yYRCAHrHDU+9ZXLYaY9MgBXSRLkB9WjYFRR6quJBumfVrEkUxrePPBwFcpWfNKXqVRQQtm7mMA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-arrow-functions@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz#8083ffc86ac8e777fbe24b5967c4b2521f3cb2b3" + integrity sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-async-to-generator@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz#3849a49cc2a22e9743cbd6b52926d30337229af1" + integrity sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A== + dependencies: + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.12.1" + +"@babel/plugin-transform-block-scoped-functions@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz#f2a1a365bde2b7112e0a6ded9067fdd7c07905d9" + integrity sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-block-scoping@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz#f0ee727874b42a208a48a586b84c3d222c2bbef1" + integrity sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-classes@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz#65e650fcaddd3d88ddce67c0f834a3d436a32db6" + integrity sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-define-map" "^7.10.4" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.12.1" + "@babel/helper-split-export-declaration" "^7.10.4" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz#d68cf6c9b7f838a8a4144badbe97541ea0904852" + integrity sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-destructuring@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz#b9a570fe0d0a8d460116413cb4f97e8e08b2f847" + integrity sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-exponentiation-operator@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz#b0f2ed356ba1be1428ecaf128ff8a24f02830ae0" + integrity sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-flow-strip-types@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.1.tgz#8430decfa7eb2aea5414ed4a3fa6e1652b7d77c4" + integrity sha512-8hAtkmsQb36yMmEtk2JZ9JnVyDSnDOdlB+0nEGzIDLuK4yR3JcEjfuFPYkdEPSh8Id+rAMeBEn+X0iVEyho6Hg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-flow" "^7.12.1" + +"@babel/plugin-transform-for-of@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz#07640f28867ed16f9511c99c888291f560921cfa" + integrity sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-function-name@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz#2ec76258c70fe08c6d7da154003a480620eba667" + integrity sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-literals@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz#d73b803a26b37017ddf9d3bb8f4dc58bfb806f57" + integrity sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz#496038602daf1514a64d43d8e17cbb2755e0c3ad" + integrity sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-modules-commonjs@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz#fa403124542636c786cf9b460a0ffbb48a86e648" + integrity sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag== + dependencies: + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-simple-access" "^7.12.1" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-object-assign@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.12.1.tgz#9102b06625f60a5443cc292d32b565373665e1e4" + integrity sha512-geUHn4XwHznRAFiuROTy0Hr7bKbpijJCmr1Svt/VNGhpxmp0OrdxURNpWbOAf94nUbL+xj6gbxRVPHWIbRpRoA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-object-super@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz#4ea08696b8d2e65841d0c7706482b048bed1066e" + integrity sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.12.1" + +"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz#d2e963b038771650c922eff593799c96d853255d" + integrity sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-property-literals@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz#41bc81200d730abb4456ab8b3fbd5537b59adecd" + integrity sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-react-display-name@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz#1cbcd0c3b1d6648c55374a22fc9b6b7e5341c00d" + integrity sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-react-jsx-self@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.12.1.tgz#ef43cbca2a14f1bd17807dbe4376ff89d714cf28" + integrity sha512-FbpL0ieNWiiBB5tCldX17EtXgmzeEZjFrix72rQYeq9X6nUK38HCaxexzVQrZWXanxKJPKVVIU37gFjEQYkPkA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-react-jsx-source@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.12.1.tgz#d07de6863f468da0809edcf79a1aa8ce2a82a26b" + integrity sha512-keQ5kBfjJNRc6zZN1/nVHCd6LLIHq4aUKcVnvE/2l+ZZROSbqoiGFRtT5t3Is89XJxBQaP7NLZX2jgGHdZvvFQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-react-jsx@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.1.tgz#c2d96c77c2b0e4362cc4e77a43ce7c2539d478cb" + integrity sha512-RmKejwnT0T0QzQUzcbP5p1VWlpnP8QHtdhEtLG55ZDQnJNalbF3eeDyu3dnGKvGzFIQiBzFhBYTwvv435p9Xpw== + dependencies: + "@babel/helper-builder-react-jsx" "^7.10.4" + "@babel/helper-builder-react-jsx-experimental" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.12.1" + +"@babel/plugin-transform-regenerator@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz#5f0a28d842f6462281f06a964e88ba8d7ab49753" + integrity sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-runtime@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.1.tgz#04b792057eb460389ff6a4198e377614ea1e7ba5" + integrity sha512-Ac/H6G9FEIkS2tXsZjL4RAdS3L3WHxci0usAnz7laPWUmFiGtj7tIASChqKZMHTSQTQY6xDbOq+V1/vIq3QrWg== + dependencies: + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + resolve "^1.8.1" + semver "^5.5.1" + +"@babel/plugin-transform-shorthand-properties@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz#0bf9cac5550fce0cfdf043420f661d645fdc75e3" + integrity sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-spread@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz#527f9f311be4ec7fdc2b79bb89f7bf884b3e1e1e" + integrity sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + +"@babel/plugin-transform-sticky-regex@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.1.tgz#5c24cf50de396d30e99afc8d1c700e8bce0f5caf" + integrity sha512-CiUgKQ3AGVk7kveIaPEET1jNDhZZEl1RPMWdTBE1799bdz++SwqDHStmxfCtDfBhQgCl38YRiSnrMuUMZIWSUQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-regex" "^7.10.4" + +"@babel/plugin-transform-template-literals@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz#b43ece6ed9a79c0c71119f576d299ef09d942843" + integrity sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-typescript@^7.5.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.12.1.tgz#d92cc0af504d510e26a754a7dbc2e5c8cd9c7ab4" + integrity sha512-VrsBByqAIntM+EYMqSm59SiMEf7qkmI9dqMt6RbD/wlwueWmYcI0FFK5Fj47pP6DRZm+3teXjosKlwcZJ5lIMw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-typescript" "^7.12.1" + +"@babel/plugin-transform-unicode-regex@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz#cc9661f61390db5c65e3febaccefd5c6ac3faecb" + integrity sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/register@^7.0.0": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.12.1.tgz#cdb087bdfc4f7241c03231f22e15d211acf21438" + integrity sha512-XWcmseMIncOjoydKZnWvWi0/5CUCD+ZYKhRwgYlWOrA8fGZ/FjuLRpqtIhLOVD/fvR1b9DQHtZPn68VvhpYf+Q== + dependencies: + find-cache-dir "^2.0.0" + lodash "^4.17.19" + make-dir "^2.1.0" + pirates "^4.0.0" + source-map-support "^0.5.16" + +"@babel/runtime@^7.0.0", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.6": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740" + integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.0.0", "@babel/template@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" + integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/parser" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/traverse@^7.0.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.1.tgz#941395e0c5cc86d5d3e75caa095d3924526f0c1e" + integrity sha512-MA3WPoRt1ZHo2ZmoGKNqi20YnPt0B1S0GTZEPhhd+hw2KGUzBlHuVunj6K4sNuK+reEvyiPwtp0cpaqLzJDmAw== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.1" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/parser" "^7.12.1" + "@babel/types" "^7.12.1" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.1.tgz#e109d9ab99a8de735be287ee3d6a9947a190c4ae" + integrity sha512-BzSY3NJBKM4kyatSOWh3D/JJ2O3CVzBybHWxtgxnggaxEuaSTTDqeiSb/xk9lrkw2Tbqyivw5ZU4rT+EfznQsA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + +"@cnakazawa/watch@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== + dependencies: + exec-sh "^0.3.2" + minimist "^1.2.0" + +"@hapi/address@2.x.x": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" + integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== + +"@hapi/bourne@1.x.x": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a" + integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== + +"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": + version "8.5.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" + integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== + +"@hapi/joi@^15.0.3": + version "15.1.1" + resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7" + integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== + dependencies: + "@hapi/address" "2.x.x" + "@hapi/bourne" "1.x.x" + "@hapi/hoek" "8.x.x" + "@hapi/topo" "3.x.x" + +"@hapi/topo@3.x.x": + version "3.1.6" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" + integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== + dependencies: + "@hapi/hoek" "^8.3.0" + +"@jest/console@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0" + integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== + dependencies: + "@jest/source-map" "^24.9.0" + chalk "^2.0.1" + slash "^2.0.0" + +"@jest/fake-timers@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.9.0.tgz#ba3e6bf0eecd09a636049896434d306636540c93" + integrity sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A== + dependencies: + "@jest/types" "^24.9.0" + jest-message-util "^24.9.0" + jest-mock "^24.9.0" + +"@jest/source-map@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" + integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.1.15" + source-map "^0.6.0" + +"@jest/test-result@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca" + integrity sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA== + dependencies: + "@jest/console" "^24.9.0" + "@jest/types" "^24.9.0" + "@types/istanbul-lib-coverage" "^2.0.0" + +"@jest/types@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" + integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^13.0.0" + +"@jest/types@^25.5.0": + version "25.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" + integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + +"@react-native-community/cli-debugger-ui@^4.9.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-4.9.0.tgz#4177764ba69243c97aa26829d59d9501acb2bd71" + integrity sha512-fBFGamHm4VUrDqkBGnsrwQL8OC6Om7K6EBQb4xj0nWekpXt1HSa3ScylYHTTWwYcpRf9htGMRGiv4dQDY/odAw== + dependencies: + serve-static "^1.13.1" + +"@react-native-community/cli-hermes@^4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-hermes/-/cli-hermes-4.13.0.tgz#6243ed9c709dad5e523f1ccd7d21066b32f2899d" + integrity sha512-oG+w0Uby6rSGsUkJGLvMQctZ5eVRLLfhf84lLyz942OEDxFRa9U19YJxOe9FmgCKtotbYiM3P/XhK+SVCuerPQ== + dependencies: + "@react-native-community/cli-platform-android" "^4.13.0" + "@react-native-community/cli-tools" "^4.13.0" + chalk "^3.0.0" + hermes-profile-transformer "^0.0.6" + ip "^1.1.5" + +"@react-native-community/cli-platform-android@^4.13.0", "@react-native-community/cli-platform-android@^4.5.1": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-4.13.0.tgz#922681ec82ee1aadd993598b814df1152118be02" + integrity sha512-3i8sX8GklEytUZwPnojuoFbCjIRzMugCdzDIdZ9UNmi/OhD4/8mLGO0dgXfT4sMWjZwu3qjy45sFfk2zOAgHbA== + dependencies: + "@react-native-community/cli-tools" "^4.13.0" + chalk "^3.0.0" + execa "^1.0.0" + fs-extra "^8.1.0" + glob "^7.1.3" + jetifier "^1.6.2" + lodash "^4.17.15" + logkitty "^0.7.1" + slash "^3.0.0" + xmldoc "^1.1.2" + +"@react-native-community/cli-platform-ios@^4.5.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-4.13.0.tgz#a738915c68cac86df54e578b59a1311ea62b1aef" + integrity sha512-6THlTu8zp62efkzimfGr3VIuQJ2514o+vScZERJCV1xgEi8XtV7mb/ZKt9o6Y9WGxKKkc0E0b/aVAtgy+L27CA== + dependencies: + "@react-native-community/cli-tools" "^4.13.0" + chalk "^3.0.0" + glob "^7.1.3" + js-yaml "^3.13.1" + lodash "^4.17.15" + plist "^3.0.1" + xcode "^2.0.0" + +"@react-native-community/cli-server-api@^4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-4.13.0.tgz#ef0e53fe0edc7356d62bca725ca47cb368f748a5" + integrity sha512-ER138ChLc1YYX7j9yE6fDm4DdNdsHThr+pla/B6iZoKje1r7TwymDdKaUvOsYalG7sWG9glW3bofcCq+Yh0Dvw== + dependencies: + "@react-native-community/cli-debugger-ui" "^4.9.0" + "@react-native-community/cli-tools" "^4.13.0" + compression "^1.7.1" + connect "^3.6.5" + errorhandler "^1.5.0" + pretty-format "^25.1.0" + serve-static "^1.13.1" + ws "^1.1.0" + +"@react-native-community/cli-tools@^4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-4.13.0.tgz#b406463d33af16cedc4305a9a9257ed32845cf1b" + integrity sha512-s4f489h5+EJksn4CfheLgv5PGOM0CDmK1UEBLw2t/ncWs3cW2VI7vXzndcd/WJHTv3GntJhXDcJMuL+Z2IAOgg== + dependencies: + chalk "^3.0.0" + lodash "^4.17.15" + mime "^2.4.1" + node-fetch "^2.6.0" + open "^6.2.0" + shell-quote "1.6.1" + +"@react-native-community/cli-types@^4.10.1": + version "4.10.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-4.10.1.tgz#d68a2dcd1649d3b3774823c64e5e9ce55bfbe1c9" + integrity sha512-ael2f1onoPF3vF7YqHGWy7NnafzGu+yp88BbFbP0ydoCP2xGSUzmZVw0zakPTC040Id+JQ9WeFczujMkDy6jYQ== + +"@react-native-community/cli@^4.5.1": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-4.13.0.tgz#04d5032f9b2b423c61ceef6be83b1bcc8a37db75" + integrity sha512-R+1VehIQ6VTLf+e7YOwzJk0F9tstfeSC4xy7oT6GSgB3FnXbTJGHFUp4siyO68Ae/gzGqt8SiUO145teWkP+ZA== + dependencies: + "@hapi/joi" "^15.0.3" + "@react-native-community/cli-debugger-ui" "^4.9.0" + "@react-native-community/cli-hermes" "^4.13.0" + "@react-native-community/cli-server-api" "^4.13.0" + "@react-native-community/cli-tools" "^4.13.0" + "@react-native-community/cli-types" "^4.10.1" + chalk "^3.0.0" + command-exists "^1.2.8" + commander "^2.19.0" + cosmiconfig "^5.1.0" + deepmerge "^3.2.0" + envinfo "^7.7.2" + execa "^1.0.0" + find-up "^4.1.0" + fs-extra "^8.1.0" + glob "^7.1.3" + graceful-fs "^4.1.3" + inquirer "^3.0.6" + leven "^3.1.0" + lodash "^4.17.15" + metro "^0.58.0" + metro-config "^0.58.0" + metro-core "^0.58.0" + metro-react-native-babel-transformer "^0.58.0" + metro-resolver "^0.58.0" + minimist "^1.2.0" + mkdirp "^0.5.1" + node-stream-zip "^1.9.1" + ora "^3.4.0" + pretty-format "^25.2.0" + semver "^6.3.0" + serve-static "^1.13.1" + strip-ansi "^5.2.0" + sudo-prompt "^9.0.0" + wcwidth "^1.0.1" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" + integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== + dependencies: + "@types/istanbul-lib-coverage" "*" + "@types/istanbul-lib-report" "*" + +"@types/stack-utils@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" + integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== + +"@types/yargs-parser@*": + version "15.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" + integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== + +"@types/yargs@^13.0.0": + version "13.0.11" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.11.tgz#def2f0c93e4bdf2c61d7e34899b17e34be28d3b1" + integrity sha512-NRqD6T4gktUrDi1o1wLH3EKC1o2caCr7/wR87ODcbVITQF106OM3sFN92ysZ++wqelOd1CTzatnOBRDYYG6wGQ== + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^15.0.0": + version "15.0.9" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.9.tgz#524cd7998fe810cdb02f26101b699cccd156ff19" + integrity sha512-HmU8SeIRhZCWcnRskCs36Q1Q00KBV6Cqh/ora8WN1+22dY07AZdn6Gel8QZ3t26XYPImtcL8WV/eqjhVmMEw4g== + dependencies: + "@types/yargs-parser" "*" + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +absolute-path@^0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/absolute-path/-/absolute-path-0.0.0.tgz#a78762fbdadfb5297be99b15d35a785b2f095bf7" + integrity sha1-p4di+9rftSl76ZsV01p4Wy8JW/c= + +accepts@~1.3.5, accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +anser@^1.4.9: + version "1.4.10" + resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.10.tgz#befa3eddf282684bd03b63dcda3927aef8c2e35b" + integrity sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww== + +ansi-colors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" + integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA== + dependencies: + ansi-wrap "^0.1.0" + +ansi-cyan@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" + integrity sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM= + dependencies: + ansi-wrap "0.1.0" + +ansi-escapes@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-fragments@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ansi-fragments/-/ansi-fragments-0.2.1.tgz#24409c56c4cc37817c3d7caa99d8969e2de5a05e" + integrity sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w== + dependencies: + colorette "^1.0.7" + slice-ansi "^2.0.0" + strip-ansi "^5.0.0" + +ansi-gray@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" + integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= + dependencies: + ansi-wrap "0.1.0" + +ansi-red@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" + integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw= + dependencies: + ansi-wrap "0.1.0" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.0.0, ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-wrap@0.1.0, ansi-wrap@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" + integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a" + integrity sha1-aHwydYFjWI/vfeezb6vklesaOZo= + dependencies: + arr-flatten "^1.0.1" + array-slice "^0.2.3" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" + integrity sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0= + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-filter@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" + integrity sha1-fajPLiZijtcygDWB/SH2fKzS7uw= + +array-map@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" + integrity sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI= + +array-reduce@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" + integrity sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys= + +array-slice@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" + integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async@^2.4.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-module-resolver@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.0.0.tgz#8f3a3d9d48287dc1d3b0d5595113adabd36a847f" + integrity sha512-3pdEq3PXALilSJ6dnC4wMWr0AZixHRM4utpdpBR9g5QG7B7JwWyukQv7a9hVxkbGFl+nQbrHDqqQOIBtTXTP/Q== + dependencies: + find-babel-config "^1.2.0" + glob "^7.1.6" + pkg-up "^3.1.0" + reselect "^4.0.0" + resolve "^1.13.1" + +babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: + version "7.0.0-beta.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" + integrity sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ== + +babel-preset-fbjs@^3.2.0, babel-preset-fbjs@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.3.0.tgz#a6024764ea86c8e06a22d794ca8b69534d263541" + integrity sha512-7QTLTCd2gwB2qGoi5epSULMHugSVgpcVt5YAeiFO9ABLrutDQzKfGwzxgZHLpugq8qMdg/DhRZDZ5CLKxBkEbw== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-syntax-class-properties" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-block-scoped-functions" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-for-of" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-member-expression-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-object-super" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-property-literals" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-js@^1.1.2, base64-js@^1.2.3: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +big-integer@^1.6.44: + version "1.6.48" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e" + integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bplist-creator@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/bplist-creator/-/bplist-creator-0.0.8.tgz#56b2a6e79e9aec3fc33bf831d09347d73794e79c" + integrity sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA== + dependencies: + stream-buffers "~2.2.0" + +bplist-parser@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e" + integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== + dependencies: + big-integer "^1.6.44" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-crc32@^0.2.13: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= + dependencies: + callsites "^2.0.0" + +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= + dependencies: + caller-callsite "^2.0.0" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== + dependencies: + rsvp "^4.8.4" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-spinners@^2.0.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.5.0.tgz#12763e47251bf951cb75c201dfa58ff1bcb2d047" + integrity sha512-PC+AmIuK04E6aeSs/pUccSujsTzBhu4HzC2dL+CfJB/Jcc2qTRbEwZQDfIUpt2Xl8BodYBEq8w4fc0kU2I9DjQ== + +cli-width@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +colorette@^1.0.7: + version "1.2.1" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" + integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== + +command-exists@^1.2.8: + version "1.2.9" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" + integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== + +commander@^2.19.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@~2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.1: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +connect@^3.6.5: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js@^2.2.2, core-js@^2.4.1: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^5.0.5, cosmiconfig@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" + integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.13.1" + parse-json "^4.0.0" + +create-react-class@^15.6.3: + version "15.7.0" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.7.0.tgz#7499d7ca2e69bb51d13faf59bd04f0c65a1d6c1e" + integrity sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng== + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + +cross-spawn@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +dayjs@^1.8.15: + version "1.9.3" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.9.3.tgz#b7f94b22ad2a136a4ca02a01ab68ae893fe1a268" + integrity sha512-V+1SyIvkS+HmNbN1G7A9+ERbFTV9KTXu6Oor98v2xHmzzpp52OIJhQuJSTywWuBY5pyAEmlwbCi1Me87n/SLOw== + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" + integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== + dependencies: + ms "2.1.2" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deepmerge@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.3.0.tgz#d3c47fd6f3a93d517b14426b0628a17b0125f5f7" + integrity sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA== + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +denodeify@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/denodeify/-/denodeify-1.2.1.tgz#3a36287f5034e699e7577901052c2e6c94251631" + integrity sha1-OjYof1A05pnnV3kBBSwubJQlFjE= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +encoding@^0.1.11: + version "0.1.13" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +envinfo@^7.7.2: + version "7.7.3" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.7.3.tgz#4b2d8622e3e7366afb8091b23ed95569ea0208cc" + integrity sha512-46+j5QxbPWza0PB1i15nZx0xQ4I/EfQxg9J8Had3b408SV63nEtor2e+oiY63amTo9KTuh2a3XLObNwduxYwwA== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +errorhandler@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/errorhandler/-/errorhandler-1.5.1.tgz#b9ba5d17cf90744cd1e851357a6e75bf806a9a91" + integrity sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A== + dependencies: + accepts "~1.3.7" + escape-html "~1.0.3" + +es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1: + version "1.18.0-next.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" + integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.2" + is-negative-zero "^2.0.0" + is-regex "^1.1.1" + object-inspect "^1.8.0" + object-keys "^1.1.1" + object.assign "^4.1.1" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-plugin-relay@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-relay/-/eslint-plugin-relay-1.4.1.tgz#5af2ac13e24bd01ad17b6a4014204918d65021cd" + integrity sha512-yb+p+4AxZTi2gXN7cZRfXMBFlRa5j6TtiVeq3yHXyy+tlgYNpxi/dDrP1+tcUTNP9vdaJovnfGZ5jp6kMiH9eg== + dependencies: + graphql "^14.0.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +event-target-shim@^5.0.0, event-target-shim@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +eventemitter3@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + +exec-sh@^0.3.2: + version "0.3.4" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" + integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extend-shallow@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" + integrity sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE= + dependencies: + kind-of "^1.1.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +external-editor@^2.0.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fancy-log@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7" + integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw== + dependencies: + ansi-gray "^0.1.1" + color-support "^1.1.3" + parse-node-version "^1.0.0" + time-stamp "^1.0.0" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +fbjs-css-vars@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" + integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== + +fbjs-scripts@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fbjs-scripts/-/fbjs-scripts-1.2.0.tgz#069a0c0634242d10031c6460ef1fccefcdae8b27" + integrity sha512-5krZ8T0Bf8uky0abPoCLrfa7Orxd8UH4Qq8hRUF2RZYNMu+FmEOrBc7Ib3YVONmxTXTlLAvyrrdrVmksDb2OqQ== + dependencies: + "@babel/core" "^7.0.0" + ansi-colors "^1.0.1" + babel-preset-fbjs "^3.2.0" + core-js "^2.4.1" + cross-spawn "^5.1.0" + fancy-log "^1.3.2" + object-assign "^4.0.1" + plugin-error "^0.1.2" + semver "^5.1.0" + through2 "^2.0.0" + +fbjs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-1.0.0.tgz#52c215e0883a3c86af2a7a776ed51525ae8e0a5a" + integrity sha512-MUgcMEJaFhCaF1QtWGnmq9ZDRAzECTCRAF7O6UZIlAlkTs1SasiX9aP0Iw7wfD2mJ7wDTNfg2w7u5fSCwJk1OA== + dependencies: + core-js "^2.4.1" + fbjs-css-vars "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-babel-config@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2" + integrity sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA== + dependencies: + json5 "^0.5.1" + path-exists "^3.0.0" + +find-cache-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-extra@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" + integrity sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA= + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +glob@^7.1.3, glob@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +graphql@^14.0.0: + version "14.7.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.7.0.tgz#7fa79a80a69be4a31c27dda824dc04dac2035a72" + integrity sha512-l0xWZpoPKpppFzMfvVyFmp9vLN7w/ZZJPefUicMCepfJeQ8sMcztloGYY9DfjVPo6tIUDzU5Hw3MUbIjj9AVVA== + dependencies: + iterall "^1.2.2" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hermes-engine@~0.4.0: + version "0.4.3" + resolved "https://registry.yarnpkg.com/hermes-engine/-/hermes-engine-0.4.3.tgz#1754932f989daddd149172600f01e69cb8f27298" + integrity sha512-qkk85ezG+w70C3tQ4iDs22B8talvByGeJQ1VIb2KG5+rMZWVizRq6r+NYptOC/HWAFxkdYb6F3OPca7RxvjYew== + +hermes-profile-transformer@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz#bd0f5ecceda80dd0ddaae443469ab26fb38fc27b" + integrity sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ== + dependencies: + source-map "^0.7.3" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +iconv-lite@^0.4.17: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" + integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +image-size@^0.6.0: + version "0.6.3" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.6.3.tgz#e7e5c65bb534bd7cdcedd6cb5166272a85f75fb2" + integrity sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA== + +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4, is-callable@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" + integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-core-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.0.0.tgz#58531b70aed1db7c0e8d4eb1a0a2d1ddd64bd12d" + integrity sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-negative-zero@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" + integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" + integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== + dependencies: + has-symbols "^1.0.1" + +is-stream@^1.0.1, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + +iterall@^1.2.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" + integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== + +jest-get-type@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" + integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== + +jest-haste-map@^24.7.1: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" + integrity sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ== + dependencies: + "@jest/types" "^24.9.0" + anymatch "^2.0.0" + fb-watchman "^2.0.0" + graceful-fs "^4.1.15" + invariant "^2.2.4" + jest-serializer "^24.9.0" + jest-util "^24.9.0" + jest-worker "^24.9.0" + micromatch "^3.1.10" + sane "^4.0.3" + walker "^1.0.7" + optionalDependencies: + fsevents "^1.2.7" + +jest-message-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" + integrity sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" + "@types/stack-utils" "^1.0.1" + chalk "^2.0.1" + micromatch "^3.1.10" + slash "^2.0.0" + stack-utils "^1.0.1" + +jest-mock@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6" + integrity sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w== + dependencies: + "@jest/types" "^24.9.0" + +jest-serializer@^24.4.0, jest-serializer@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" + integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ== + +jest-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162" + integrity sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg== + dependencies: + "@jest/console" "^24.9.0" + "@jest/fake-timers" "^24.9.0" + "@jest/source-map" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" + callsites "^3.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.15" + is-ci "^2.0.0" + mkdirp "^0.5.1" + slash "^2.0.0" + source-map "^0.6.0" + +jest-validate@^24.7.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" + integrity sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ== + dependencies: + "@jest/types" "^24.9.0" + camelcase "^5.3.1" + chalk "^2.0.1" + jest-get-type "^24.9.0" + leven "^3.1.0" + pretty-format "^24.9.0" + +jest-worker@^24.6.0, jest-worker@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" + integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== + dependencies: + merge-stream "^2.0.0" + supports-color "^6.1.0" + +jetifier@^1.6.2: + version "1.6.6" + resolved "https://registry.yarnpkg.com/jetifier/-/jetifier-1.6.6.tgz#fec8bff76121444c12dc38d2dad6767c421dab68" + integrity sha512-JNAkmPeB/GS2tCRqUzRPsTOHpGDah7xP18vGJfIjZC+W2sxEHbxgJxetIjIqhjQ3yYbYNEELkM/spKLtwoOSUQ== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" + integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsc-android@^245459.0.0: + version "245459.0.0" + resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-245459.0.0.tgz#e584258dd0b04c9159a27fb104cd5d491fd202c9" + integrity sha512-wkjURqwaB1daNkDi2OYYbsLnIdC/lUM2nPXQKRs5pqEU9chDg435bjvo+LSaHotDENygHQDHe+ntUkkw2gwMtg== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= + dependencies: + jsonify "~0.0.0" + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= + +json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= + +kind-of@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" + integrity sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ= + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= + optionalDependencies: + graceful-fs "^4.1.9" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= + +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.3.0: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== + dependencies: + chalk "^2.0.1" + +logkitty@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/logkitty/-/logkitty-0.7.1.tgz#8e8d62f4085a826e8d38987722570234e33c6aa7" + integrity sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ== + dependencies: + ansi-fragments "^0.2.1" + dayjs "^1.8.15" + yargs "^15.1.0" + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +make-dir@^2.0.0, make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +merge-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= + dependencies: + readable-stream "^2.0.1" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +metro-babel-register@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-babel-register/-/metro-babel-register-0.58.0.tgz#5c44786d49a044048df56cf476a2263491d4f53a" + integrity sha512-P5+G3ufhSYL6cA3a7xkbSJzzFBvtivj/PhWvGXFXnuFssDlMAX1CTktff+0gpka5Cd6B6QLt0UAMWulUAAE4Eg== + dependencies: + "@babel/core" "^7.0.0" + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" + "@babel/plugin-proposal-optional-chaining" "^7.0.0" + "@babel/plugin-transform-async-to-generator" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/register" "^7.0.0" + core-js "^2.2.2" + escape-string-regexp "^1.0.5" + +metro-babel-transformer@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.58.0.tgz#317c83b863cceb0573943815f1711fbcbe69b106" + integrity sha512-yBX3BkRhw2TCNPhe+pmLSgsAEA3huMvnX08UwjFqSXXI1aiqzRQobn92uKd1U5MM1Vx8EtXVomlJb95ZHNAv6A== + dependencies: + "@babel/core" "^7.0.0" + metro-source-map "0.58.0" + +metro-cache@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.58.0.tgz#630ea0a4626dfb9591c71fdb85dce14b5e9a04ec" + integrity sha512-jjW9zCTKxhgKcVkyQ6LHyna9Zdf4TK/45vvT1fPyyTk1RY82ZYjU1qs+84ycKEd08Ka4YcK9xcUew9SIDJYI8Q== + dependencies: + jest-serializer "^24.4.0" + metro-core "0.58.0" + mkdirp "^0.5.1" + rimraf "^2.5.4" + +metro-config@0.58.0, metro-config@^0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.58.0.tgz#1e24b43a5a00971d75662b1a0d3c04a13d4a1746" + integrity sha512-4vgBliXwL56vjUlYplvGMVSNrJJpkHuLcD+O20trV3FvPxKg4ZsvuOcNSxqDSMU26FCtIEJ15ojcuCbRL7KY0w== + dependencies: + cosmiconfig "^5.0.5" + jest-validate "^24.7.0" + metro "0.58.0" + metro-cache "0.58.0" + metro-core "0.58.0" + pretty-format "^24.7.0" + +metro-core@0.58.0, metro-core@^0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.58.0.tgz#ad9f6645a2b439a3fbce7ce4e19b01b00375768a" + integrity sha512-RzXUjGFmCLOyzUqcKDvr91AldGtIOxnzNZrWUIiG8uC3kerVLo0mQp4YH3+XVm6fMNiLMg6iER7HLqD+MbpUjQ== + dependencies: + jest-haste-map "^24.7.1" + lodash.throttle "^4.1.1" + metro-resolver "0.58.0" + wordwrap "^1.0.0" + +metro-inspector-proxy@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.58.0.tgz#6fefb0cdf25655919d56c82ebe09cd26eb00e636" + integrity sha512-oFqTyNTJdCdvcw1Ha6SKE7ITbSaoTbO4xpYownIoJR+WZ0ZfxbWpp225JkHuBJm9UcBAnG9c0CME924m3uBbaw== + dependencies: + connect "^3.6.5" + debug "^2.2.0" + rxjs "^5.4.3" + ws "^1.1.5" + yargs "^14.2.0" + +metro-minify-uglify@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.58.0.tgz#7e1066954bfd4f767ba6aca7feef676ca44c68b8" + integrity sha512-vRHsA7bCi7eCn3LXLm20EfY2NoWDyYOnmWaq/N8LB0OxL2L5DXRqMYAQK+prWGJ5S1yvVnDuuNVP+peQ9851TA== + dependencies: + uglify-es "^3.1.9" + +metro-react-native-babel-preset@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.58.0.tgz#18f48d33fe124280ffabc000ab8b42c488d762a2" + integrity sha512-MRriNW+fF6jxABsgPphocUY6mIhmCm8idcrQZ58fT3Iti2vCdtkaK32TyCGUNUptzhUe2/cbE57j4aC+eaodAA== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-export-default-from" "^7.0.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" + "@babel/plugin-proposal-optional-chaining" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.0.0" + "@babel/plugin-syntax-export-default-from" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.2.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-exponentiation-operator" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-for-of" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-object-assign" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-react-jsx-source" "^7.0.0" + "@babel/plugin-transform-regenerator" "^7.0.0" + "@babel/plugin-transform-runtime" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-sticky-regex" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.5.0" + "@babel/plugin-transform-unicode-regex" "^7.0.0" + "@babel/template" "^7.0.0" + react-refresh "^0.4.0" + +metro-react-native-babel-preset@^0.59.0: + version "0.59.0" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.59.0.tgz#20e020bc6ac9849e1477de1333d303ed42aba225" + integrity sha512-BoO6ncPfceIDReIH8pQ5tQptcGo5yRWQXJGVXfANbiKLq4tfgdZB1C1e2rMUJ6iypmeJU9dzl+EhPmIFKtgREg== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-export-default-from" "^7.0.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" + "@babel/plugin-proposal-optional-chaining" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.0.0" + "@babel/plugin-syntax-export-default-from" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.2.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-syntax-optional-chaining" "^7.0.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-exponentiation-operator" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-for-of" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-object-assign" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-react-jsx-self" "^7.0.0" + "@babel/plugin-transform-react-jsx-source" "^7.0.0" + "@babel/plugin-transform-regenerator" "^7.0.0" + "@babel/plugin-transform-runtime" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-sticky-regex" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.5.0" + "@babel/plugin-transform-unicode-regex" "^7.0.0" + "@babel/template" "^7.0.0" + react-refresh "^0.4.0" + +metro-react-native-babel-transformer@0.58.0, metro-react-native-babel-transformer@^0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.58.0.tgz#5da0e5a1b83c01d11626905fa59f34fda53a21a5" + integrity sha512-3A73+cRq1eUPQ8g+hPNGgMUMCGmtQjwqHfoG1DwinAoJ/kr4WOXWWbGZo0xHJNBe/zdHGl0uHcDCp2knPglTdQ== + dependencies: + "@babel/core" "^7.0.0" + babel-preset-fbjs "^3.3.0" + metro-babel-transformer "0.58.0" + metro-react-native-babel-preset "0.58.0" + metro-source-map "0.58.0" + +metro-resolver@0.58.0, metro-resolver@^0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.58.0.tgz#4d03edc52e2e25d45f16688adf3b3f268ea60df9" + integrity sha512-XFbAKvCHN2iWqKeiRARzEXn69eTDdJVJC7lu16S4dPQJ+Dy82dZBr5Es12iN+NmbJuFgrAuIHbpWrdnA9tOf6Q== + dependencies: + absolute-path "^0.0.0" + +metro-source-map@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.58.0.tgz#e951b99f4c653239ce9323bb08339c6f1978a112" + integrity sha512-yvN1YPmejmgiiS7T1aKBiiUTHPw2Vcm3r2TZ+DY92z/9PR4alysIywrCs/fTHs8rbDcKM5VfPCKGLpkBrbKeOw== + dependencies: + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + invariant "^2.2.4" + metro-symbolicate "0.58.0" + ob1 "0.58.0" + source-map "^0.5.6" + vlq "^1.0.0" + +metro-symbolicate@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.58.0.tgz#ba9fd52549c41fc1b656adaad7c8875726dd5abe" + integrity sha512-uIVxUQC1E26qOMj13dKROhwAa2FmZk5eR0NcBqej/aXmQhpr8LjJg2sondkoLKUp827Tf/Fm9+pS4icb5XiqCw== + dependencies: + invariant "^2.2.4" + metro-source-map "0.58.0" + source-map "^0.5.6" + through2 "^2.0.1" + vlq "^1.0.0" + +metro@0.58.0, metro@^0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro/-/metro-0.58.0.tgz#c037318c112f80dc96199780c8b401ab72cfd142" + integrity sha512-yi/REXX+/s4r7RjzXht+E+qE6nzvFIrEXO5Q61h+70Q7RODMU8EnlpXx04JYk7DevHuMhFaX+NWhCtRINzR4zA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/core" "^7.0.0" + "@babel/generator" "^7.5.0" + "@babel/parser" "^7.0.0" + "@babel/plugin-external-helpers" "^7.0.0" + "@babel/template" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + absolute-path "^0.0.0" + async "^2.4.0" + babel-preset-fbjs "^3.3.0" + buffer-crc32 "^0.2.13" + chalk "^2.4.1" + ci-info "^2.0.0" + concat-stream "^1.6.0" + connect "^3.6.5" + debug "^2.2.0" + denodeify "^1.2.1" + eventemitter3 "^3.0.0" + fbjs "^1.0.0" + fs-extra "^1.0.0" + graceful-fs "^4.1.3" + image-size "^0.6.0" + invariant "^2.2.4" + jest-haste-map "^24.7.1" + jest-worker "^24.6.0" + json-stable-stringify "^1.0.1" + lodash.throttle "^4.1.1" + merge-stream "^1.0.1" + metro-babel-register "0.58.0" + metro-babel-transformer "0.58.0" + metro-cache "0.58.0" + metro-config "0.58.0" + metro-core "0.58.0" + metro-inspector-proxy "0.58.0" + metro-minify-uglify "0.58.0" + metro-react-native-babel-preset "0.58.0" + metro-resolver "0.58.0" + metro-source-map "0.58.0" + metro-symbolicate "0.58.0" + mime-types "2.1.11" + mkdirp "^0.5.1" + node-fetch "^2.2.0" + nullthrows "^1.1.1" + resolve "^1.5.0" + rimraf "^2.5.4" + serialize-error "^2.1.0" + source-map "^0.5.6" + strip-ansi "^4.0.0" + temp "0.8.3" + throat "^4.1.0" + wordwrap "^1.0.0" + write-file-atomic "^1.2.0" + ws "^1.1.5" + xpipe "^1.0.5" + yargs "^14.2.0" + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== + +"mime-db@>= 1.43.0 < 2": + version "1.45.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" + integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== + +mime-db@~1.23.0: + version "1.23.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.23.0.tgz#a31b4070adaea27d732ea333740a64d0ec9a6659" + integrity sha1-oxtAcK2uon1zLqMzdApk0OyaZlk= + +mime-types@2.1.11: + version "2.1.11" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.11.tgz#c259c471bda808a85d6cd193b430a5fae4473b3c" + integrity sha1-wlnEcb2oCKhdbNGTtDCl+uRHOzw= + dependencies: + mime-db "~1.23.0" + +mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + dependencies: + mime-db "1.44.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.1: + version "2.4.6" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1" + integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + +nan@^2.12.1: + version "2.14.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-fetch@^2.2.0, node-fetch@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-stream-zip@^1.9.1: + version "1.11.3" + resolved "https://registry.yarnpkg.com/node-stream-zip/-/node-stream-zip-1.11.3.tgz#223892620b4889bce9782b256a76682631c507be" + integrity sha512-GY+9LxkQuIT3O7K8BTdHVGKFcBYBy2vAVcTBtkKpu+OlBef/NSb6VuIWSyLiVDfmLMkggHeRJZN0F3W0GWU/uw== + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +nullthrows@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" + integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== + +ob1@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.58.0.tgz#484a1e9a63a8b79d9ea6f3a83b2a42110faac973" + integrity sha512-uZP44cbowAfHafP1k4skpWItk5iHCoRevMfrnUvYCfyNNPPJd3rfDCyj0exklWi2gDXvjlj2ObsfiqP/bs/J7Q== + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" + integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0, object.assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd" + integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.18.0-next.0" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +open@^6.2.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" + integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== + dependencies: + is-wsl "^1.1.0" + +options@>=0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + integrity sha1-7CLTEoBrtT5zF3Pnza788cZDEo8= + +ora@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" + integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg== + dependencies: + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-spinners "^2.0.0" + log-symbols "^2.2.0" + strip-ansi "^5.2.0" + wcwidth "^1.0.1" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-node-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" + integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pirates@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + +plist@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.1.tgz#a9b931d17c304e8912ef0ba3bdd6182baf2e1f8c" + integrity sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ== + dependencies: + base64-js "^1.2.3" + xmlbuilder "^9.0.7" + xmldom "0.1.x" + +plugin-error@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" + integrity sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4= + dependencies: + ansi-cyan "^0.1.1" + ansi-red "^0.1.1" + arr-diff "^1.0.1" + arr-union "^2.0.1" + extend-shallow "^1.1.2" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +pretty-format@^24.7.0, pretty-format@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" + integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== + dependencies: + "@jest/types" "^24.9.0" + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + react-is "^16.8.4" + +pretty-format@^25.1.0, pretty-format@^25.2.0: + version "25.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" + integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== + dependencies: + "@jest/types" "^25.5.0" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + +prop-types@^15.6.2, prop-types@^15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +react-devtools-core@^4.0.6: + version "4.9.0" + resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.9.0.tgz#39cc4589b4c6fbcb6a18e529ce745a1af3e63ae5" + integrity sha512-3NyHXW1ClqxEXdHunawAytDxiIxs620oP3wB8DHsbx1fkGgqjMkwlyHVf0zmES/b4ffqzJySowRwSYds/uAHzw== + dependencies: + shell-quote "^1.6.1" + ws "^7" + +react-is@^16.12.0, react-is@^16.8.1, react-is@^16.8.4: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-native@0.62.2: + version "0.62.2" + resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.62.2.tgz#d831e11a3178705449142df19a70ac2ca16bad10" + integrity sha512-gADZZ3jcm2WFTjh8CCBCbl5wRSbdxqZGd+8UpNwLQFgrkp/uHorwAhLNqcd4+fHmADgPBltNL0uR1Vhv47zcOw== + dependencies: + "@babel/runtime" "^7.0.0" + "@react-native-community/cli" "^4.5.1" + "@react-native-community/cli-platform-android" "^4.5.1" + "@react-native-community/cli-platform-ios" "^4.5.0" + abort-controller "^3.0.0" + anser "^1.4.9" + base64-js "^1.1.2" + connect "^3.6.5" + create-react-class "^15.6.3" + escape-string-regexp "^1.0.5" + eslint-plugin-relay "1.4.1" + event-target-shim "^5.0.1" + fbjs "^1.0.0" + fbjs-scripts "^1.1.0" + hermes-engine "~0.4.0" + invariant "^2.2.4" + jsc-android "^245459.0.0" + metro-babel-register "0.58.0" + metro-react-native-babel-transformer "0.58.0" + metro-source-map "0.58.0" + nullthrows "^1.1.1" + pretty-format "^24.7.0" + promise "^7.1.1" + prop-types "^15.7.2" + react-devtools-core "^4.0.6" + react-refresh "^0.4.0" + regenerator-runtime "^0.13.2" + scheduler "0.17.0" + stacktrace-parser "^0.1.3" + use-subscription "^1.0.0" + whatwg-fetch "^3.0.0" + +react-refresh@^0.4.0: + version "0.4.3" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.4.3.tgz#966f1750c191672e76e16c2efa569150cc73ab53" + integrity sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA== + +react@16.11.0: + version "16.11.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.11.0.tgz#d294545fe62299ccee83363599bf904e4a07fdbb" + integrity sha512-M5Y8yITaLmU0ynd0r1Yvfq98Rmll6q8AxaEe88c8e7LxO8fZ2cNgmFt0aGAS9wzf1Ao32NKXtCl+/tVVtkxq6g== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + +readable-stream@^2.0.1, readable-stream@^2.2.2, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" + integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== + +regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpu-core@^4.7.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" + integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.2.0" + +regjsgen@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +reselect@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" + integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA== + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.13.1, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.8.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130" + integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA== + dependencies: + is-core-module "^2.0.0" + path-parse "^1.0.6" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rimraf@^2.5.4: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@~2.2.6: + version "2.2.8" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI= + +rsvp@^4.8.4: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + +run-async@^2.2.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= + +rxjs@^5.4.3: + version "5.5.12" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc" + integrity sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw== + dependencies: + symbol-observable "1.0.1" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sane@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== + dependencies: + "@cnakazawa/watch" "^1.0.3" + anymatch "^2.0.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + +sax@^1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +scheduler@0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.17.0.tgz#7c9c673e4ec781fac853927916d1c426b6f3ddfe" + integrity sha512-7rro8Io3tnCPuY4la/NuI5F2yfESpnfZyT6TtkXnSWVkcu0BCDJ+8gk5ozUaFaxpIyNuWAPXrH0yFcSi28fnDA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +semver@^5.1.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serialize-error@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a" + integrity sha1-ULZ51WNc34Rme9yOWa9OW4HV9go= + +serve-static@^1.13.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shell-quote@1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" + integrity sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c= + dependencies: + array-filter "~0.0.0" + array-map "~0.0.0" + array-reduce "~0.0.0" + jsonify "~0.0.0" + +shell-quote@^1.6.1: + version "1.7.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +simple-plist@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/simple-plist/-/simple-plist-1.1.1.tgz#54367ca28bc5996a982c325c1c4a4c1a05f4047c" + integrity sha512-pKMCVKvZbZTsqYR6RKgLfBHkh2cV89GXcA/0CVPje3sOiNOnXA8+rp/ciAMZ7JRaUdLzlEM6JFfUn+fS6Nt3hg== + dependencies: + bplist-creator "0.0.8" + bplist-parser "0.2.0" + plist "^3.0.1" + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +slide@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.5.16: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +stack-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" + integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== + +stacktrace-parser@^0.1.3: + version "0.1.10" + resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" + integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== + dependencies: + type-fest "^0.7.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +stream-buffers@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4" + integrity sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ= + +string-width@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimend@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz#6ddd9a8796bc714b489a3ae22246a208f37bfa46" + integrity sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + +string.prototype.trimstart@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz#22d45da81015309cd0cdd79787e8919fc5c613e7" + integrity sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +sudo-prompt@^9.0.0: + version "9.2.1" + resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.2.1.tgz#77efb84309c9ca489527a4e749f287e6bdd52afd" + integrity sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= + +temp@0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + integrity sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k= + dependencies: + os-tmpdir "^1.0.0" + rimraf "~2.2.6" + +throat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= + +through2@^2.0.0, through2@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +time-stamp@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" + integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +type-fest@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" + integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +ua-parser-js@^0.7.18: + version "0.7.22" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.22.tgz#960df60a5f911ea8f1c818f3747b99c6e177eae3" + integrity sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q== + +uglify-es@^3.1.9: + version "3.3.9" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" + integrity sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ== + dependencies: + commander "~2.13.0" + source-map "~0.6.1" + +ultron@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +use-subscription@^1.0.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.0.tgz#0df66fdf97b9a340147ad72f76fac1db6f56d240" + integrity sha512-/FVRiB2I7NDjzWoNBYPt6YkkvleMm/lFtxj1hH6nX2TVrJ/5UTbovw9OE1efv2Zl0HoAYuTjM7zHd9OsABn5sg== + dependencies: + object-assign "^4.1.1" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vlq@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vlq/-/vlq-1.0.1.tgz#c003f6e7c0b4c1edd623fd6ee50bbc0d6a1de468" + integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w== + +walker@^1.0.7, walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz#e5f871572d6879663fa5674c8f833f15a8425ab3" + integrity sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ== + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^1.2.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" + integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8= + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + +ws@^1.1.0, ws@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" + integrity sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w== + dependencies: + options ">=0.0.5" + ultron "1.0.x" + +ws@^7: + version "7.3.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" + integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== + +xcode@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/xcode/-/xcode-2.1.0.tgz#bab64a7e954bb50ca8d19da7e09531c65a43ecfe" + integrity sha512-uCrmPITrqTEzhn0TtT57fJaNaw8YJs1aCzs+P/QqxsDbvPZSv7XMPPwXrKvHtD6pLjBM/NaVwraWJm8q83Y4iQ== + dependencies: + simple-plist "^1.0.0" + uuid "^3.3.2" + +xmlbuilder@^9.0.7: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= + +xmldoc@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/xmldoc/-/xmldoc-1.1.2.tgz#6666e029fe25470d599cd30e23ff0d1ed50466d7" + integrity sha512-ruPC/fyPNck2BD1dpz0AZZyrEwMOrWTO5lDdIXS91rs3wtm4j+T8Rp2o+zoOYkkAxJTZRPOSnOGei1egoRmKMQ== + dependencies: + sax "^1.2.1" + +xmldom@0.1.x: + version "0.1.31" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff" + integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ== + +xpipe@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf" + integrity sha1-jdi/Rfw/f1Xw4FS4ePQ6YmFNr98= + +xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yargs-parser@^15.0.1: + version "15.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-15.0.1.tgz#54786af40b820dcb2fb8025b11b4d659d76323b3" + integrity sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^14.2.0: + version "14.2.3" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.3.tgz#1a1c3edced1afb2a2fea33604bc6d1d8d688a414" + integrity sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg== + dependencies: + cliui "^5.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^15.0.1" + +yargs@^15.1.0: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" diff --git a/package.json b/package.json index ede146e01..39438fe78 100644 --- a/package.json +++ b/package.json @@ -1,70 +1,138 @@ { "name": "react-native-agora", "version": "3.1.3", - "description": "React Native around the Agora RTC SDKs for Android and iOS agora", - "summary": "agora native sdk for react-native", - "main": "lib/index.js", - "types": "lib/index.d.ts", + "description": "Agora RTC SDK For React Native", + "main": "lib/commonjs/index", + "module": "lib/module/index", + "types": "lib/typescript/src/index.d.ts", + "react-native": "src/index", + "source": "src/index", + "files": [ + "src", + "lib", + "android", + "ios", + "cpp", + "react-native-agora.podspec", + "!lib/typescript/example", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__" + ], "scripts": { - "build": "rm -rf lib && tsc", - "doc": "typedoc ./src", "test": "jest", - "lint": "eslint . --ext .js,.jsx,.ts,.tsx", - "prepublish": "npm run build" - }, - "repository": { - "type": "git", - "url": "https://github.com/syanbo/react-native-agora.git" + "typescript": "tsc --noEmit", + "lint": "eslint \"**/*.{js,ts,tsx}\"", + "prepare": "bob build", + "release": "release-it", + "example": "yarn --cwd example", + "pods": "cd example && pod-install --quiet", + "bootstrap": "yarn example && yarn && yarn pods" }, "keywords": [ - "agora", "react-native", - "react-native-agora", - "live", - "react", - "Agora", + "agora", + "audio", "video", - "react-native-video" - ], - "author": "luxuhui", - "authors": [ - "https://github.com/syanbo/react-native-agora/graphs/contributors" + "chat", + "live" ], + "repository": "https://github.com/AgoraIO-Community/react-native-agora", + "author": "HUI (https://github.com/LichKing-2234)", "license": "MIT", "bugs": { - "url": "https://github.com/syanbo/react-native-agora/issues" - }, - "homepage": "https://github.com/syanbo/react-native-agora#readme", - "peerDependencies": { - "react": ">=16.8.3", - "react-native": ">=0.59.9" + "url": "https://github.com/AgoraIO-Community/react-native-agora/issues" }, + "homepage": "https://github.com/AgoraIO-Community/react-native-agora#readme", "devDependencies": { - "@babel/core": "^7.6.2", - "@babel/runtime": "^7.6.2", - "@react-native-community/eslint-config": "^0.0.5", - "@types/jest": "^24.0.24", - "@types/react-native": "^0.60.25", - "@types/react-test-renderer": "16.9.1", - "@typescript-eslint/eslint-plugin": "^2.12.0", - "@typescript-eslint/parser": "^2.12.0", - "babel-jest": "^24.9.0", - "eslint": "^6.5.1", - "jest": "^24.9.0", - "metro-react-native-babel-preset": "^0.56.0", - "react-test-renderer": "16.9.0", - "typedoc-plugin-no-inherit": "^1.1.10", - "typescript": "^4.0.2" + "@commitlint/config-conventional": "^8.3.4", + "@react-native-community/bob": "^0.16.2", + "@react-native-community/eslint-config": "^2.0.0", + "@release-it/conventional-changelog": "^1.1.4", + "@types/jest": "^26.0.0", + "@types/react": "^16.9.19", + "@types/react-native": "0.62.13", + "commitlint": "^8.3.5", + "eslint": "^7.2.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-prettier": "^3.1.3", + "husky": "^4.2.5", + "jest": "^26.0.1", + "pod-install": "^0.1.0", + "prettier": "^2.0.5", + "react": "16.11.0", + "react-native": "0.62.2", + "release-it": "^13.5.8", + "typescript": "^3.8.3" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" }, "jest": { "preset": "react-native", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" + "modulePathIgnorePatterns": [ + "/example/node_modules", + "/lib/" + ] + }, + "husky": { + "hooks": { + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS", + "pre-commit": "yarn lint && yarn typescript" + } + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" ] + }, + "release-it": { + "git": { + "commitMessage": "chore: release ${version}", + "tagName": "v${version}" + }, + "npm": { + "publish": true + }, + "github": { + "release": true + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": "angular" + } + } + }, + "eslintConfig": { + "extends": [ + "@react-native-community", + "prettier" + ], + "rules": { + "prettier/prettier": [ + "error", + { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + } + ] + } + }, + "eslintIgnore": ["node_modules/", "lib/"], + "prettier": { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + }, + "@react-native-community/bob": { + "source": "src", + "output": "lib", + "targets": ["commonjs", "module", "typescript"] } } diff --git a/react-native-agora.podspec b/react-native-agora.podspec index 681dac8af..4e605735b 100644 --- a/react-native-agora.podspec +++ b/react-native-agora.podspec @@ -1,21 +1,24 @@ -require 'json' +require "json" -package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) Pod::Spec.new do |s| - s.name = "react-native-agora" - s.version = package["version"] - s.summary = package["description"] - s.homepage = package['homepage'] - s.license = package['license'] - s.authors = package["authors"] - s.platform = :ios, "9.0" - s.static_framework = true - s.swift_version = "4.0" + s.name = "react-native-agora" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] - s.source = { :git => package["repository"]["url"] } - s.source_files = 'ios/RCTAgora/**/*.{h,m,swift}' + s.platforms = { :ios => "9.0" } + s.source = { :git => "https://github.com/AgoraIO-Community/react-native-agora.git", :tag => "#{s.version}" } - s.dependency 'React' - s.dependency "AgoraRtcEngine_iOS_Crypto", "3.1.2" + + s.source_files = "ios/**/*.{h,m,mm,swift}" + + s.static_framework = true + s.swift_version = "4.0" + + s.dependency "React" + s.dependency "AgoraRtcEngine_iOS_Crypto", "3.1.2" end diff --git a/samples/README.md b/samples/README.md deleted file mode 100644 index 602febc41..000000000 --- a/samples/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# react native agora samples - -| name | description | -| :-------------: | :-------------: | -| [Agora-RN-QuickStart](https://github.com/AgoraIO-Community/Agora-RN-Quickstart) | react-native-agora demo for beginner | diff --git a/src/RtcLocalView.tsx b/src/RtcLocalView.tsx index 5b4c69949..a7c9366d1 100644 --- a/src/RtcLocalView.tsx +++ b/src/RtcLocalView.tsx @@ -1,7 +1,12 @@ -import React, {Component} from "react" -import {Platform, ViewProps} from "react-native" +import React, { Component } from 'react'; +import { Platform, ViewProps } from 'react-native'; -import {RtcSurfaceView, RtcSurfaceViewProps, RtcTextureView, RtcTextureViewProps} from "./src/RtcRenderView.native" +import { + RtcSurfaceView, + RtcSurfaceViewProps, + RtcTextureView, + RtcTextureViewProps, +} from './common/RtcRenderView.native'; /** * The SurfaceView class. @@ -13,13 +18,9 @@ import {RtcSurfaceView, RtcSurfaceViewProps, RtcTextureView, RtcTextureViewProps * @noInheritDoc */ class SurfaceView extends Component { - render() { - return ( - - ) - } + render() { + return ; + } } /** @@ -31,21 +32,17 @@ class SurfaceView extends Component { * @noInheritDoc */ class TextureView extends Component { - render() { - if (Platform.OS === 'ios') - throw new Error('TextureView not support for iOS') - return ( - - ) - } + render() { + if (Platform.OS === 'ios') + throw new Error('TextureView not support for iOS'); + return ; + } } /** * View for previewing local video. */ export default { - SurfaceView, - TextureView -} + SurfaceView, + TextureView, +}; diff --git a/src/RtcRemoteView.tsx b/src/RtcRemoteView.tsx index 9ccdf3698..ec4e65c97 100644 --- a/src/RtcRemoteView.tsx +++ b/src/RtcRemoteView.tsx @@ -1,13 +1,13 @@ -import React, {Component} from "react" -import {Platform, ViewProps} from "react-native" +import React, { Component } from 'react'; +import { Platform, ViewProps } from 'react-native'; import { - RtcSurfaceView, - RtcSurfaceViewProps, - RtcTextureView, - RtcTextureViewProps, - RtcUidProps -} from "./src/RtcRenderView.native" + RtcSurfaceView, + RtcSurfaceViewProps, + RtcTextureView, + RtcTextureViewProps, + RtcUidProps, +} from './common/RtcRenderView.native'; /** * The SurfaceView class. @@ -18,12 +18,13 @@ import { * * @noInheritDoc */ -class SurfaceView extends Component { - render() { - return ( - - ) - } +class SurfaceView extends Component< + ViewProps & RtcSurfaceViewProps & RtcUidProps, + {} +> { + render() { + return ; + } } /** @@ -34,20 +35,21 @@ class SurfaceView extends Component { - render() { - if (Platform.OS === 'ios') - throw new Error('TextureView not support for iOS') - return ( - - ) - } +class TextureView extends Component< + ViewProps & RtcTextureViewProps & RtcUidProps, + {} +> { + render() { + if (Platform.OS === 'ios') + throw new Error('TextureView not support for iOS'); + return ; + } } /** * View for rendering remote video. */ export default { - SurfaceView, - TextureView -} + SurfaceView, + TextureView, +}; diff --git a/src/Types.ts b/src/Types.ts index a306920d9..1c71509cd 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -1,2 +1,2 @@ -export * from './src/Classes' -export * from './src/Enums' +export * from './common/Classes'; +export * from './common/Enums'; diff --git a/src/common/Classes.ts b/src/common/Classes.ts new file mode 100644 index 000000000..3370eeba5 --- /dev/null +++ b/src/common/Classes.ts @@ -0,0 +1,1350 @@ +import type { + AudioChannel, + AudioCodecProfileType, + AudioSampleRateType, + CameraCaptureOutputPreference, + CameraDirection, + DegradationPreference, + EncryptionMode, + LastmileProbeResultState, + LighteningContrastLevel, + NetworkQuality, + VideoCodecProfileType, + VideoCodecType, + VideoFrameRate, + VideoMirrorMode, + VideoOutputOrientationMode, + VideoQualityAdaptIndication, + VideoStreamType, +} from './Enums'; + +/** + * The user information, including the user ID and user account. + */ +export interface UserInfo { + /** + * The user ID of a user. + */ + uid: number; + /** + * The user account of a user. + */ + userAccount: string; +} + +/** + * The video resolution. + */ +export class VideoDimensions { + /** + * The video resolution on the horizontal axis. + */ + width: number; + /** + * The video resolution on the vertical axis. + */ + height: number; + + constructor(width: number, height: number) { + this.width = width; + this.height = height; + } +} + +/** + * Definition of VideoEncoderConfiguration. + */ +export class VideoEncoderConfiguration { + /** + * The video frame dimensions (px), which is used to specify the video quality and measured by the total number of pixels along a + * frame's width and height. The default value is 640 × 360. + * You can customize the dimension, or select from the following list: + *

+ * + * **Note** + *
    + *
  • The value of the dimension does not indicate the orientation mode of the output ratio. For how to set the video orientation, see [VideoOutputOrientationMode]{@link VideoOutputOrientationMode}.
  • + *
  • Whether 720p+ can be supported depends on the device. If the device cannot support 720p, the frame rate will be lower than the one listed in the table.
  • + *
+ * + */ + dimensions?: VideoDimensions; + /** + * The video frame rate (fps). The default value is 15. Users can either set the frame rate manually or choose from the following options. + * We do not recommend setting this to a value greater than 30. + */ + frameRate?: VideoFrameRate; + /** + * The minimum video encoder frame rate (fps). The default value is Min(-1) (the SDK uses the lowest encoder frame rate). + */ + minFrameRate?: VideoFrameRate; + /** + * Bitrate of the video (Kbps). Refer to the table below and set your bitrate. If you set a bitrate beyond the proper range, the SDK automatically adjusts it to a value within the range. + * You can also choose from the following options: + * - [`Standard`]{@link BitRate.Standard}: (Recommended) The standard bitrate mode. In this mode, the bitrates differ between the `LiveBroadcasting` and `Communication` profiles: + * - In the `Communication` profile, the video bitrate is the same as the base bitrate. + * - In the `LiveBroadcasting` profile, the video bitrate is twice the base bitrate. + * - [`Compatible`]{@link BitRate.Compatible}: The compatible bitrate mode. In this mode, the bitrate stays the same regardless of the profile. If you choose this mode for the `LiveBroadcasting` profile, the video frame rate may be lower than the set value. + * + * Agora uses different video codecs for different profiles to optimize the user experience. For example, the Communication profile prioritizes the smoothness while the `LiveBroadcasting` profile prioritizes the video quality (a higher bitrate). Therefore, We recommend setting this parameter as [`Standard`]{@link BitRate.Standard}. + * + * **Video Bitrate Table** + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
ResolutionFrame rate

(fps)

Base Bitrate

(Kbps, for Communication)

Live Bitrate

(Kbps, for Live Broadcasting)

160*1201565130
120*1201550100
320*18015140280
180*18015100200
240*18015120240
320*24015200400
240*24015140280
424*24015220440
640*36015400800
360*36015260520
640*360306001200
360*36030400800
480*36015320640
480*36030490980
640*480155001000
480*48015400800
640*480307501500
480*480306001200
848*480156101220
848*480309301860
640*48010400800
1280*7201511302260
1280*7203017103420
960*720159101820
960*7203013802760
+ * + * **Note** + * + * The base bitrate in this table applies to the Communication profile. + * The `LiveBroadcasting` profile generally requires a higher bitrate for better video quality. + * We recommend setting the bitrate mode as [`Standard`]{@link BitRate.Standard}. You can also set the bitrate as the base bitrate value × 2. + */ + bitrate?: number; + /** + * The minimum encoding bitrate (Kbps). The Agora SDK automatically adjusts the encoding bitrate to adapt to the network conditions. Using a value greater than the default value forces the video encoder to output high-quality images but may cause more packet loss and hence sacrifice the smoothness of the video transmission. That said, unless you have special requirements for image quality, + * Agora does not recommend changing this value. + */ + minBitrate?: number; + /** + * The orientation mode. + */ + orientationMode?: VideoOutputOrientationMode; + /** + * The video encoding degradation preference under limited bandwidth. + */ + degradationPrefer?: DegradationPreference; + /** + * Sets the mirror mode of the published local video stream. + */ + mirrorMode?: VideoMirrorMode; + + constructor(params?: { + dimensions?: VideoDimensions; + frameRate?: VideoFrameRate; + minFrameRate?: VideoFrameRate; + bitrate?: number; + minBitrate?: number; + orientationMode?: VideoOutputOrientationMode; + 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; + } +} + +/** + * Sets the image enhancement options. + */ +export class BeautyOptions { + /** + * The lightening contrast level. + */ + lighteningContrastLevel?: LighteningContrastLevel; + /** + * The brightness level. The value ranges between 0.0 (original) and 1.0. The default value is 0.7. + */ + lighteningLevel?: number; + /** + * The sharpness level. The value ranges between 0.0 (original) and 1.0. + * The default value is 0.5. This parameter is usually used to remove blemishes. + */ + smoothnessLevel?: number; + /** + * The redness level. The value ranges between 0.0 (original) and 1.0. + * The default value is 0.1. This parameter adjusts the red saturation level. + */ + rednessLevel?: number; + + constructor(params?: { + lighteningContrastLevel?: LighteningContrastLevel; + lighteningLevel?: number; + smoothnessLevel?: number; + rednessLevel?: number; + }) { + this.lighteningContrastLevel = params?.lighteningContrastLevel; + this.lighteningLevel = params?.lighteningLevel; + this.smoothnessLevel = params?.smoothnessLevel; + this.rednessLevel = params?.rednessLevel; + } +} + +/** + * Agora image properties. A class for setting the properties of the watermark and background images. + */ +export class AgoraImage { + /** + * HTTP/HTTPS URL address of the image on the broadcasting video. The maximum length of this parameter is 1024 bytes. + */ + url: string; + /** + * Position of the image on the upper left of the broadcasting video on the horizontal axis. + */ + x: number; + /** + * Position of the image on the upper left of the broadcasting video on the vertical axis. + */ + y: number; + /** + * Width of the image on the broadcasting video. + */ + width: number; + /** + * Height of the image on the broadcasting video. + */ + height: number; + + constructor( + url: string, + x: number, + y: number, + width: number, + height: number + ) { + this.url = url; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } +} + +/** + * The transcodingUser class, which defines the audio and video properties in the CDN live. Agora supports a maximum of 17 transcoding users in a CDN live streaming channel. + */ +export class TranscodingUser { + /** + * ID of the user in the CDN live streaming. + */ + uid: number; + /** + * Horizontal position of the video frame of the user from the top left corner of the CDN live streaming. + */ + x: number; + /** + * Vertical position of the video frame of the user from the top left corner of the CDN live streaming. + */ + y: number; + /** + * Width of the video frame of the user on the CDN live streaming. The default value is 360. + */ + width?: number; + /** + * Height of the video frame of the user on the CDN live streaming. The default value is 640. + */ + height?: number; + /** + * Layer position of video frame of the user on the CDN live streaming. The value ranges between 0 and 100. From v2.3.0, Agora SDK supports setting zOrder as 0. The smallest value is 0 (default value), which means that the video frame is at the bottom layer. The biggest value is 100, which means that the video frame is at the top layer. + */ + zOrder?: number; + /** + * The transparency of the video frame of the user in the CDN live streaming that ranges between 0.0 and 1.0. 0.0 means that the video frame is completely transparent and 1.0 means opaque. The default value is 1.0. + */ + alpha?: number; + /** + * The audio channel ranging between 0 and 5. The default value is 0. + * + * - 0: (default) Supports dual channels. Depends on the upstream of the broadcaster. + * - 1: The audio stream of the broadcaster uses the FL audio channel. If the broadcaster’s upstream uses multiple audio channels, these channels are mixed into mono first. + * - 2: The audio stream of the broadcaster uses the FC audio channel. If the broadcaster’s upstream uses multiple audio channels, these channels are mixed into mono first. + * - 3: The audio stream of the broadcaster uses the FR audio channel. If the broadcaster’s upstream uses multiple audio channels, these channels are mixed into mono first. + * - 4: The audio stream of the broadcaster uses the BL audio channel. If the broadcaster’s upstream uses multiple audio channels, these channels are mixed into mono first. + * - 5: The audio stream of the broadcaster uses the BR audio channel. If the broadcaster’s upstream uses multiple audio channels, these channels are mixed into mono first. + * + * **Note** + * + * Special players are needed if `audioChannel` is not set as 0. + */ + audioChannel?: AudioChannel; + + constructor( + uid: number, + x: number, + y: number, + params?: { + width?: number; + height?: number; + zOrder?: number; + alpha?: number; + audioChannel?: AudioChannel; + } + ) { + 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; + } +} + +/** + * Color. + */ +export class Color { + /** + * Red. + */ + red: number; + /** + * Green. + */ + green: number; + /** + * Blue. + */ + blue: number; + + constructor(red: number, green: number, blue: number) { + this.red = red; + this.green = green; + this.blue = blue; + } +} + +/** + * A class for managing user-specific CDN live audio/video transcoding settings. + */ +export class LiveTranscoding { + /** + * Width (pixel) of the video. The default value is 360. If you push video streams to the CDN, set the value of width × height to at least 64 × 64, or the SDK adjusts it to 64 x 64. + * If you push audio streams to the CDN, set the value of width × height to 0 × 0. + */ + width?: number; + /** + * Height (pixel) of the video. The default value is 640. If you push video streams to the CDN, set the value of width × height to at least 64 × 64, or the SDK adjusts it to 64 x 64. + * If you push audio streams to the CDN, set the value of width × height to 0 × 0. + */ + height?: number; + /** + * Bitrate (Kbps) of the CDN live output video stream. The default value is 400. Set this parameter according to the Video Bitrate Table. If you set a bitrate beyond the proper range, + * the SDK automatically adapts it to a value within the range. + */ + videoBitrate?: number; + /** + * Frame rate (fps) of the CDN live output video stream. + * The value range is [0,30]. The default value is 15. Agora adjusts all values over 30 to 30. + */ + videoFramerate?: VideoFrameRate; + /** + * @deprecated + * - `true`: Low latency with unassured quality. + * - `false`: (Default) High latency with assured quality. + */ + lowLatency?: boolean; + /** + * Gop of the video frames in the CDN live stream. The default value is 30 fps. + */ + videoGop?: number; + /** + * The watermark image added to the CDN live publishing stream. Ensure that the format of the image is PNG. Once a watermark image is added, + * the audience of the CDN live publishing stream can see it. + */ + watermark?: AgoraImage; + /** + * The background image added to the CDN live publishing stream. Once a background image is added, + * the audience of the CDN live publishing stream can see it. + */ + backgroundImage?: AgoraImage; + /** + * Self-defined audio-sample rate: AudioSampleRateType. + */ + audioSampleRate?: AudioSampleRateType; + /** + * Bitrate (Kbps) of the CDN live audio output stream. The default value is 48 and the highest value is 128. + */ + audioBitrate?: number; + /** + * The number of audio channels for the CDN live stream. + * + * Agora recommends choosing 1 (mono), or 2 (stereo) audio channels. Special players are required if you choose 3, 4, or 5. + * - 1: (Default) Mono + * - 2: Stereo + * - 3: Three audio channels + * - 4: Four audio channels + * - 5: Five audio channels + */ + audioChannels?: AudioChannel; + /** + * Audio codec profile type: AudioCodecProfileType. Set it as LC-AAC or HE-AAC. The default value is LC-AAC. + */ + audioCodecProfile?: AudioCodecProfileType; + /** + * Video codec profile type: VideoCodecProfileType. Set it as BASELINE, MAIN, or HIGH (default). If you set this parameter to other values, Agora adjusts it to the default value HIGH. + */ + videoCodecProfile?: VideoCodecProfileType; + /** + * Sets the background color. + */ + backgroundColor?: Color; + /** + * Reserved property. Extra user-defined information to send the Supplemental Enhancement Information (SEI) for the H.264/H.265 video stream to the CDN live client. Maximum length: 4096 Bytes. + */ + userConfigExtraInfo?: string; + /** + * An TranscodingUser object managing the user layout configuration in the CDN live stream. Agora supports a maximum of 17 transcoding users in a CDN live stream channel. + */ + transcodingUsers: TranscodingUser[]; + + constructor( + transcodingUsers: TranscodingUser[], + params?: { + width?: number; + height?: number; + videoBitrate?: number; + videoFramerate?: VideoFrameRate; + lowLatency?: boolean; + videoGop?: number; + watermark?: AgoraImage; + backgroundImage?: AgoraImage; + audioSampleRate?: AudioSampleRateType; + audioBitrate?: number; + audioChannels?: AudioChannel; + audioCodecProfile?: AudioCodecProfileType; + videoCodecProfile?: VideoCodecProfileType; + backgroundColor?: Color; + 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; + this.transcodingUsers = transcodingUsers; + } +} + +/** + * The ChannelMediaInfo class. + */ +export class ChannelMediaInfo { + /** + * The channel name. + */ + channelName?: string; + /** + * The token that enables the user to join the channel. + */ + token?: string; + /** + * The user ID. + */ + uid: number; + + constructor(uid: number, params?: { channelName?: string; token?: string }) { + this.channelName = params?.channelName; + this.token = params?.token; + this.uid = uid; + } +} + +/** + * The ChannelMediaRelayConfiguration class. + */ +export class ChannelMediaRelayConfiguration { + /** + * The information of the source channel: [`ChannelMediaInfo`]{@link ChannelMediaInfo}. It contains the following members: + * - `channelName`: The name of the source channel. The default value is null, which means the SDK applies the name of the current channel. + * - `uid`: ID of the host whose media stream you want to relay. The default value is 0, which means the SDK generates a random UID. You must set it as 0. + * - `token`: The token for joining the source channel. It is generated with the `channelName` and `uid` you set in `srcInfo`. + * - If you have not enabled the App Certificate, set this parameter as the default value null, which means the SDK applies the App ID. + * - If you have enabled the App Certificate, you must use the token generated with the `channelName` and `uid`, and the `uid` must be set as 0. + */ + srcInfo: ChannelMediaInfo; + /** + * The information of the destination channel: [`ChannelMediaInfo`]{@link ChannelMediaInfo}. It contains the following members: + * - `channelName`: The name of the destination channel. + * - `uid`: ID of the host in the destination channel. The value ranges from 0 to (232-1). To avoid UID conflicts, this uid must be different from any other UIDs in the destination channel. The default value is 0, which means the SDK generates a random UID. + * - `token`: The token for joining the source channel. It is generated with the `channelName` and `uid` you set in `destInfo`. + * - If you have not enabled the App Certificate, set this parameter as the default value null, which means the SDK applies the App ID. + * - If you have enabled the App Certificate, you must use the token generated with the `channelName` and `uid`, and the `uid` must be set as 0. + */ + destInfos: ChannelMediaInfo[]; + + constructor(srcInfo: ChannelMediaInfo, destInfos: ChannelMediaInfo[]) { + this.srcInfo = srcInfo; + this.destInfos = destInfos; + } +} + +/** + * Lastmile probe configuration. + */ +export class LastmileProbeConfig { + /** + * Whether to probe uplink of lastmile. i.e., audience don't need probe uplink bandwidth. + */ + probeUplink: boolean; + /** + * Whether to probe downlink of lastmile. + */ + probeDownlink: boolean; + /** + * The expected maximum sending bitrate in bps in range of [100000,5000000]. It is recommended to set this value according to the required bitrate of selected video profile. + */ + expectedUplinkBitrate: number; + /** + * The expected maximum receive bitrate in bps in range of [100000,5000000]. + */ + expectedDownlinkBitrate: number; + + constructor( + probeUplink: boolean, + probeDownlink: boolean, + expectedUplinkBitrate: number, + expectedDownlinkBitrate: number + ) { + this.probeUplink = probeUplink; + this.probeDownlink = probeDownlink; + this.expectedUplinkBitrate = expectedUplinkBitrate; + this.expectedDownlinkBitrate = expectedDownlinkBitrate; + } +} + +/** + * The position and size of the watermark image. + */ +export class Rectangle { + /** + * The horizontal offset from the top-left corner. + */ + x: number; + /** + * The vertical offset from the top-left corner. + */ + y: number; + /** + * The width (pixels) of the watermark image. + */ + width: number; + /** + * The height (pixels) of the watermark image. + */ + height: number; + + constructor(x: number, y: number, width: number, height: number) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } +} + +/** + * Agora watermark options. A class for setting the properties of watermark. + */ +export class WatermarkOptions { + /** + * Sets whether or not the watermark image is visible in the local video preview: + * - `true`: (Default) The watermark image is visible in preview. + * - `false`: The watermark image is not visible in preview. + */ + visibleInPreview?: boolean; + /** + * The watermark position in the landscape mode. + */ + positionInLandscapeMode: Rectangle; + /** + * The watermark position in the portrait mode. + */ + positionInPortraitMode: Rectangle; + + constructor( + positionInLandscapeMode: Rectangle, + positionInPortraitMode: Rectangle, + visibleInPreview?: boolean + ) { + this.visibleInPreview = visibleInPreview; + this.positionInLandscapeMode = positionInLandscapeMode; + this.positionInPortraitMode = positionInPortraitMode; + } +} + +/** + * Configuration of the imported live interactive voice or video stream. + */ +export class LiveInjectStreamConfig { + /** + * Width (pixels) of the added stream to the live interactive streaming. The default value is 0, which is the same width as the original stream. + */ + width?: number; + /** + * Height (pixels) of the added stream to the live interactive streaming. The default value is 0, which is the same height as the original stream. + */ + height?: number; + /** + * Video GOP of the added stream to the live interactive streaming. The default value is 30 frames. + */ + videoGop?: number; + /** + * Video frame rate of the added stream to the live interactive streaming. The default value is 15 fps. + */ + videoFramerate?: VideoFrameRate; + /** + * Video bitrate of the added stream to the live interactive streaming. The default value is 400 Kbps. + * + * **Note** + * + * The setting of the video bitrate is closely linked to the resolution. If you set the video bitrate beyond a reasonable range, the SDK sets it within a reasonable range instead. + */ + videoBitrate?: number; + /** + * Audio sample rate of the added stream to the live interactive streaming. The default value is 44100 Hz. + * + * **Note** + * + * We recommend you use the default value and not reset it. + */ + audioSampleRate?: AudioSampleRateType; + /** + * Audio bitrate of the added stream to the live interactive streaming. The default value is 48 Kbps. + * + * **Note** + * + * We recommend you use the default value and not reset it. + */ + audioBitrate?: number; + /** + * Audio channels to add into the live streaming. The value ranges between 1 and 2. The default value is 1. + * + * **Note** + * + * We recommend you use the default value and not reset it. + */ + audioChannels?: AudioChannel; + + constructor(params?: { + width?: number; + height?: number; + videoGop?: number; + videoFramerate?: VideoFrameRate; + videoBitrate?: number; + audioSampleRate?: AudioSampleRateType; + 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; + } +} + +/** + * The definition of CameraCapturerConfiguration. + */ +export class CameraCapturerConfiguration { + /** + * The camera capturer configuration. + */ + preference: CameraCaptureOutputPreference; + /** + * The camera direction. + */ + cameraDirection: CameraDirection; + + constructor( + preference: CameraCaptureOutputPreference, + cameraDirection: CameraDirection + ) { + this.preference = preference; + this.cameraDirection = cameraDirection; + } +} + +/** + * The channel media options. + */ +export class ChannelMediaOptions { + /** + * Determines whether to subscribe to audio streams when the user joins the channel. + * - `true`: (Default) Subscribe. + * - `false`: Do not subscribe. + * + * This member serves a similar function to the [`muteAllRemoteAudioStreams`]{@link RtcEngine.muteAllRemoteAudioStreams} method. After joining the channel, you can call the `muteAllRemoteAudioStreams` method to set whether to subscribe to audio streams in the channel. + */ + autoSubscribeAudio: boolean; + /** + * Determines whether to subscribe to video streams when the user joins the channel. + * - `true`: (Default) Subscribe. + * - `false`: Do not subscribe. + * + * This member serves a similar function to the [`muteAllRemoteVideoStreams`]{@link RtcEngine.muteAllRemoteVideoStreams} method. After joining the channel, you can call the `muteAllRemoteVideoStreams` method to set whether to subscribe to audio streams in the channel. + */ + autoSubscribeVideo: boolean; + + constructor(autoSubscribeAudio: boolean, autoSubscribeVideo: boolean) { + this.autoSubscribeAudio = autoSubscribeAudio; + this.autoSubscribeVideo = autoSubscribeVideo; + } +} + +/** + * Definition of `EncryptionConfig`. + * + * @since v3.1.2. + */ +export class EncryptionConfig { + /** + * Encryption mode. The default encryption mode is `AES128XTS`. See [`EncryptionMode`]{@link EncryptionMode}. + */ + encryptionMode: EncryptionMode; + /** + * Encryption key in string type. + * + * **Note** + * + * If you do not set an encryption key or set it as null, you cannot use the built-in encryption, and the SDK returns [`InvalidArgument(2)`]{@link ErrorCode.InvalidArgument}. + */ + encryptionKey: string; + + constructor(encryptionMode: EncryptionMode, encryptionKey: string) { + this.encryptionMode = encryptionMode; + this.encryptionKey = encryptionKey; + } +} + +/** + * Statistics of the call. + */ +export interface RtcStats { + /** + * Call duration in seconds, represented by an aggregate value. + */ + totalDuration: number; + /** + * Total number of bytes transmitted, represented by an aggregate value. + */ + txBytes: number; + /** + * Total number of bytes received, represented by an aggregate value. + */ + rxBytes: number; + /** + * Total number of audio bytes sent (bytes), represented by an aggregate value. + */ + txAudioBytes: number; + /** + * Total number of video bytes sent (bytes), represented by an aggregate value. + */ + txVideoBytes: number; + /** + * Total number of audio bytes received (bytes), represented by an aggregate value. + */ + rxAudioBytes: number; + /** + * Total number of video bytes received (bytes), represented by an aggregate value. + */ + rxVideoBytes: number; + /** + * Transmission bitrate in Kbps, represented by an instantaneous value. + */ + txKBitRate: number; + /** + * Receive bitrate (Kbps), represented by an instantaneous value. + */ + rxKBitRate: number; + /** + * The transmission bitrate of the audio packet (Kbps), represented by an instantaneous value. + */ + txAudioKBitRate: number; + /** + * Audio receive bitrate (Kbps), represented by an instantaneous value. + */ + rxAudioKBitRate: number; + /** + * Video transmission bitrate (Kbps), represented by an instantaneous value. + */ + txVideoKBitRate: number; + /** + * Video receive bitrate (Kbps), represented by an instantaneous value. + */ + rxVideoKBitRate: number; + /** + * The number of users in the channel. + * - `COMMUNICATION` profile: The number of users in the channel. + * - `LiveBroadcasting` profile: + * - If the local user is an audience member: The number of users in the channel = The number of hosts in the channel + 1. + * - If the local user is a host: The number of users in the channel = The number of hosts in the channel. + */ + users: number; + /** + * Client-server latency. + */ + lastmileDelay: number; + /** + * The packet loss rate (%) from the local client to Agora's edge server, before network countermeasures. + */ + txPacketLossRate: number; + /** + * The packet loss rate (%) from Agora's edge server to the local client, before network countermeasures. + */ + rxPacketLossRate: number; + /** + * System CPU usage (%). + */ + cpuTotalUsage: number; + /** + * Application CPU usage (%). + */ + cpuAppUsage: number; + /** + * The round-trip time delay from the client to the local router. + * + * **Note** + * (iOS only) Since v3.1.2, this parameter is disabled by default. See [FAQ](https://docs.agora.io/en/faq/local_network_privacy) for details. If you need to enable this parameter, contact support@agora.io. + */ + gatewayRtt: number; + /** + * The memory usage ratio of the app (%). + * + * **Note** + * + * This value is for reference only. Due to system limitations, you may not get the value of this member. + */ + memoryAppUsageRatio: number; + /** + * The memory usage ratio of the system (%). + * + * **Note** + * + * This value is for reference only. Due to system limitations, you may not get the value of this member. + */ + memoryTotalUsageRatio: number; + /** + * The memory usage of the app (KB). + * + * **Note** + * + * This value is for reference only. Due to system limitations, you may not get the value of this member. + */ + memoryAppUsageInKbytes: number; +} + +/** + * Properties of the audio volume information. An array containing the user ID and volume information for each speaker. + */ +export interface AudioVolumeInfo { + /** + * The user ID of the speaker. The uid of the local user is 0. + */ + uid: number; + /** + * The sum of the voice volume and audio-mixing volume of the speaker. The value ranges between 0 (lowest volume) and 255 (highest volume). + */ + volume: number; + /** + * Voice activity status of the local user. + * - 0: The local user is not speaking. + * - 1: The local user is speaking. + * + * **Note** + * - The `vad` parameter cannot report the voice activity status of the remote users. In the remote users' callback, `vad` = 0. + * - Ensure that you set `report_vad(true)` in the [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication} method to enable the voice activity detection of the local user. + */ + vad: number; + /** + * The channel ID, which indicates which channel the speaker is in. + */ + channelId: string; +} + +/** + * The rectangular area. + */ +export interface Rect { + /** + * The horizontal coordinate of the left side of the rectangular area. + */ + left: number; + /** + * The vertical coordinate of the upper side of the rectangular area. + */ + top: number; + /** + * The horizontal coordinate of the right side of the rectangular area. + */ + right: number; + /** + * The vertical coordinate of the bottom side of the rectangular area. + */ + bottom: number; +} + +/** + * The one-way last-mile probe result. + */ +export interface LastmileProbeOneWayResult { + /** + * The packet loss rate (%). + */ + packetLossRate: number; + /** + * The network jitter (ms). + */ + jitter: number; + /** + * The estimated available bandwidth (bps). + */ + availableBandwidth: number; +} + +/** + * Statistics of the lastmile probe. + */ +export interface LastmileProbeResult { + /** + * The state of the probe test. + */ + state: LastmileProbeResultState; + /** + * The round-trip delay time (ms). + */ + rtt: number; + /** + * The uplink last-mile network report. + */ + uplinkReport: LastmileProbeOneWayResult; + /** + * The downlink last-mile network report. + */ + downlinkReport: LastmileProbeOneWayResult; +} + +/** + * Statistics of the local audio stream. + */ +export interface LocalAudioStats { + /** + * The number of channels. + */ + numChannels: number; + /** + * The sample rate (Hz). + */ + sentSampleRate: number; + /** + * The average sending bitrate (Kbps). + */ + sentBitrate: number; + /** + * The video packet loss rate (%) from the local client to the Agora edge server before applying the anti-packet loss strategies. + * + * @since v3.1.2. + */ + txPacketLossRate: number; +} + +/** + * Statistics of the local video. + */ +export interface LocalVideoStats { + /** + * Bitrate (Kbps) sent in the reported interval, which does not include the bitrate of the re-transmission video after the packet loss. + */ + sentBitrate: number; + /** + * Frame rate (fps) sent in the reported interval, which does not include the frame rate of the re-transmission video after the packet loss. + */ + sentFrameRate: number; + /** + * The encoder output frame rate (fps) of the local video. + */ + encoderOutputFrameRate: number; + /** + * The renderer output frame rate (fps) of the local video. + */ + rendererOutputFrameRate: number; + /** + * The target bitrate (Kbps) of the current encoder. This value is estimated by the SDK based on the current network conditions. + */ + targetBitrate: number; + /** + * The target frame rate (fps) of the current encoder. + */ + targetFrameRate: number; + /** + * Quality change of the local video in terms of target frame rate and target bit rate since last count. + */ + qualityAdaptIndication: VideoQualityAdaptIndication; + /** + * The encoding bitrate (Kbps), which does not include the bitrate of the re-transmission video after packet loss. + */ + encodedBitrate: number; + /** + * The width of the encoding frame (px). + */ + encodedFrameWidth: number; + /** + * The height of the encoding frame (px). + */ + encodedFrameHeight: number; + /** + * The value of the sent frame rate, represented by an aggregate value. + */ + encodedFrameCount: number; + /** + * The codec type of the local video. + */ + codecType: VideoCodecType; + /** + * The video packet loss rate (%) from the local client to the Agora edge server before applying the anti-packet loss strategies. + * + * @since v3.1.2. + */ + txPacketLossRate: number; + /** + * The capture frame rate (fps) of the local video. + * + * @since v3.1.2. + */ + captureFrameRate: number; +} + +/** + * Statistics of the remote audio. + */ +export interface RemoteAudioStats { + /** + * User ID of the user sending the audio streams. + */ + uid: number; + /** + * Audio quality received by the user. + */ + quality: NetworkQuality; + /** + * Network delay (ms) from the sender to the receiver. + */ + networkTransportDelay: number; + /** + * Network delay (ms) from the receiver to the jitter buffer. + */ + jitterBufferDelay: number; + /** + * Packet loss rate in the reported interval. + */ + audioLossRate: number; + /** + * The number of channels. + */ + numChannels: number; + /** + * The sample rate (Hz) of the received audio stream in the reported interval. + */ + receivedSampleRate: number; + /** + * The average bitrate (Kbps) of the received audio stream in the reported interval. + */ + receivedBitrate: number; + /** + * The total freeze time (ms) of the remote audio stream after the remote user joins the channel. In the reported interval, audio freeze occurs when the audio frame loss rate reaches 4%. totalFrozenTime = The audio freeze time × 2 × 1000 (ms). + */ + totalFrozenTime: number; + /** + * The total audio freeze time as a percentage (%) of the total time when the audio is available. + */ + frozenRate: number; + /** + * The total time (ms) when the remote user in the `Communication` profile or the remote broadcaster in the `LiveBroadcasting` profile neither stops sending the audio stream nor disables the audio module after joining the channel. + */ + totalActiveTime: number; + /** + * The total active time (ms) of the remote audio stream after the remote user publish the audio stream. + * + * @since v3.1.2. + * + */ + publishDuration: number; +} + +/** + * Statistics of the remote video. + */ +export interface RemoteVideoStats { + /** + * User ID of the user sending the video streams. + */ + uid: number; + /** + * @deprecated + * + * Time delay (ms). In scenarios where audio and video is synchronized, you can use the value + * of `networkTransportDelay` and `jitterBufferDelay` + * in [`RemoteAudioStats`]{@link RemoteAudioStats} to know the delay statistics of the remote video. + */ + delay: number; + /** + * Width (pixels) of the remote video. + */ + width: number; + /** + * Height (pixels) of the remote video. + */ + height: number; + /** + * Bitrate (Kbps) received in the reported interval. + */ + receivedBitrate: number; + /** + * The decoder output frame rate (fps) of the remote video. + */ + decoderOutputFrameRate: number; + /** + * The renderer output frame rate (fps) of the remote video. + */ + rendererOutputFrameRate: number; + /** + * Packet loss rate (%) of the remote video stream after network countermeasures. + */ + packetLossRate: number; + /** + * Video stream type (high-stream or low-stream). + */ + rxStreamType: VideoStreamType; + /** + * The total freeze time (ms) of the remote video stream after the remote user joins the channel. + * + * In a video session where the frame rate is set to no less than 5 fps, video freeze occurs when the time interval between two adjacent + * renderable video frames is more than 500 ms. + */ + totalFrozenTime: number; + /** + * The total video freeze time (`totalFrozenTime`) as a percentage (%) of the total active time of the remote video stream (`totalActiveTime`). + */ + frozenRate: number; + /** + * The total time (ms) when the remote user in the Communication profile or the remote broadcaster in the Live-broadcast profile neither stops sending the video stream nor disables the video module after joining the channel. + */ + totalActiveTime: number; + /** + * The total publish duration (ms) of the remote video stream. + * + * @since v3.1.2. + * + */ + publishDuration: number; +} + +/** + * The information of the detected human face. + */ +export interface FacePositionInfo { + /** + * The x coordinate (px) of the human face in the local video. Taking the top left corner of the captured video as the origin, + * the x coordinate represents the relative lateral displacement of the top left corner of the human face to the origin. + */ + x: number; + /** + * The y coordinate (px) of the human face in the local video. Taking the top left corner of the captured video as the origin, + * the y coordinate represents the relative longitudinal displacement of the top left corner of the human face to the origin. + */ + y: number; + /** + * The width (px) of the human face in the captured video. + */ + width: number; + /** + * The height (px) of the human face in the captured video. + */ + height: number; + /** + * The distance (cm) between the human face and the screen. + */ + distance: number; +} diff --git a/src/common/Enums.ts b/src/common/Enums.ts new file mode 100644 index 000000000..40bb33011 --- /dev/null +++ b/src/common/Enums.ts @@ -0,0 +1,2367 @@ +/** + * Regions for connection. + */ +export enum AreaCode { + /** + * Mainland China + */ + CN = 0x00000001, + /** + * North America + */ + NA = 0x00000002, + /** + * Europe + */ + EU = 0x00000004, + /** + * Asia, excluding Mainland China + */ + AS = 0x00000008, + /** + * Japan + */ + JP = 0x00000010, + /** + * India + */ + IN = 0x00000020, + /** + * (Default) Global + */ + GLOB = -1, +} + +/** + * Audio codec profile. + */ +export enum AudioCodecProfileType { + /** + * 0: (Default) LC-AAC, which is the low-complexity audio codec profile. + */ + LCAAC = 0, + /** + * 1: HE-AAC, which is the high-efficiency audio codec profile. + */ + HEAAC = 1, +} + +/** + * Audio equalization band frequency. + */ +export enum AudioEqualizationBandFrequency { + /** + * 0: 31 Hz. + */ + Band31 = 0, + /** + * 1: 62 Hz. + */ + Band62 = 1, + /** + * 2: 125 Hz. + */ + Band125 = 2, + /** + * 3: 250 Hz. + */ + Band250 = 3, + /** + * 4: 500 Hz. + */ + Band500 = 4, + /** + * 5: 1 kHz. + */ + Band1K = 5, + /** + * 6: 2 kHz. + */ + Band2K = 6, + /** + * 7: 4 kHz. + */ + Band4K = 7, + /** + * 8: 8 kHz. + */ + Band8K = 8, + /** + * 9: 16 kHz. + */ + Band16K = 9, +} + +/** + * The error information of the local audio. + */ +export enum AudioLocalError { + /** + * 0: The local audio is normal. + */ + Ok = 0, + /** + * 1: No specified reason for the local audio failure. + */ + Failure = 1, + /** + * 2: No permission to use the local audio device. + */ + DeviceNoPermission = 2, + /** + * 3: The microphone is in use. + */ + DeviceBusy = 3, + /** + * 4: The local audio recording fails. Check whether the recording device is working properly. + */ + RecordFailure = 4, + /** + * 5: The local audio encoding fails. + */ + EncodeFailure = 5, +} + +/** + * The state of the local audio. + */ +export enum AudioLocalState { + /** + * 0: The local audio is in the initial state. + */ + Stopped = 0, + /** + * 1: The recording device starts successfully. + */ + Recording = 1, + /** + * 2: The first audio frame encodes successfully. + */ + Encoding = 2, + /** + * 3: The local audio fails to start. + */ + Failed = 3, +} + +/** + * The error code of the audio mixing file. + */ +export enum AudioMixingErrorCode { + /** + * 701: The SDK cannot open the audio mixing file. + */ + CanNotOpen = 701, + /** + * 702: The SDK opens the audio mixing file too frequently. + */ + TooFrequentCall = 702, + /** + * 703: The opening of the audio mixing file is interrupted. + */ + InterruptedEOF = 703, + /** + * 0: No error. + */ + OK = 0, +} + +/** + * The state of the audio mixing file. + */ +export enum AudioMixingStateCode { + /** + * 710: The audio mixing file is playing. + */ + Playing = 710, + /** + * 711: The audio mixing file pauses playing. + */ + Paused = 711, + /** + * 713: The audio mixing file stops playing. + */ + Stopped = 713, + /** + * 714: An exception occurs when playing the audio mixing file. + */ + Failed = 714, +} + +/** + * Audio output routing. + */ +export enum AudioOutputRouting { + /** + * -1: Default. + */ + Default = -1, + /** + * 0: Headset. + */ + Headset = 0, + /** + * 1: Earpiece. + */ + Earpiece = 1, + /** + * 2: Headset with no microphone. + */ + HeadsetNoMic = 2, + /** + * 3: Speakerphone. + */ + Speakerphone = 3, + /** + * 4: Loudspeaker. + */ + Loudspeaker = 4, + /** + * 5: Bluetooth headset. + */ + HeadsetBluetooth = 5, +} + +/** + * Audio profile. + */ +export enum AudioProfile { + /** + * 0: Default audio profile. + * - In the `Communication` profile: A sample rate of 32 KHz, audio encoding, mono, and a bitrate of up to 18 Kbps. + * - In the `LiveBroadcasting` profile: A sample rate of 48 KHz, music encoding, mono, and a bitrate of up to 64 Kbps. + */ + Default = 0, + /** + * 1: A sample rate of 32 KHz, audio encoding, mono, and a bitrate of up to 18 Kbps. + */ + SpeechStandard = 1, + /** + * 2: A sample rate of 48 KHz, music encoding, mono, and a bitrate of up to 64 Kbps. + */ + MusicStandard = 2, + /** + * 3: A sample rate of 48 KHz, music encoding, stereo, and a bitrate of up to 80 Kbps. + */ + MusicStandardStereo = 3, + /** + * 4: A sample rate of 48 KHz, music encoding, mono, and a bitrate of up to 96 Kbps. + */ + MusicHighQuality = 4, + /** + * 5: A sample rate of 48 KHz, music encoding, stereo, and a bitrate of up to 128 Kbps. + */ + MusicHighQualityStereo = 5, +} + +/** + * Audio recording quality. + */ +export enum AudioRecordingQuality { + /** + * 0: The sample rate is 32 KHz, and the file size is around 1.2 MB after 10 minutes of recording. + */ + Low = 0, + /** + * 1: The sample rate is 32 KHz, and the file size is around 2 MB after 10 minutes of recording. + */ + Medium = 1, + /** + * 2: The sample rate is 32 KHz, and the file size is around 3.75 MB after 10 minutes of recording. + */ + High = 2, +} + +/** + * The state of the remote audio. + */ +export enum AudioRemoteState { + /** + * 0: The remote audio is in the default state, probably due to: + * - [`LocalMuted`]{@link AudioRemoteStateReason.LocalMuted} + * - [`RemoteMuted`]{@link AudioRemoteStateReason.RemoteMuted} + * - [`RemoteOffline`]{@link AudioRemoteStateReason.RemoteOffline} + */ + Stopped = 0, + /** + * 1: The first remote audio packet is received. + */ + Starting = 1, + /** + * 2: The remote audio stream is decoded and plays normally, probably due to: + * - [`NetworkRecovery`]{@link AudioRemoteStateReason.NetworkRecovery} + * - [`LocalUnmuted`]{@link AudioRemoteStateReason.LocalUnmuted} + * - [`RemoteUnmuted`]{@link AudioRemoteStateReason.RemoteUnmuted} + */ + Decoding = 2, + /** + * 3: The remote audio is frozen, probably due to: + * [`NetworkCongestion`]{@link AudioRemoteStateReason.NetworkCongestion} + */ + Frozen = 3, + /** + * 4: The remote audio fails to start, probably due to: + * [`Internal`]{@link AudioRemoteStateReason.Internal} + */ + Failed = 4, +} + +/** + * The reason of the remote audio state change. + */ +export enum AudioRemoteStateReason { + /** + * 0: Internal reasons. + */ + Internal = 0, + /** + * 1: Network congestion. + */ + NetworkCongestion = 1, + /** + * 2: Network recovery. + */ + NetworkRecovery = 2, + /** + * 3: The local user stops receiving the remote audio stream or disables the audio module. + */ + LocalMuted = 3, + /** + * 4: The local user resumes receiving the remote audio stream or enables the audio module. + */ + LocalUnmuted = 4, + /** + * 5: The remote user stops sending the audio stream or disables the audio module. + */ + RemoteMuted = 5, + /** + * 6: The remote user resumes sending the audio stream or enables the audio module. + */ + RemoteUnmuted = 6, + /** + * 7: The remote user leaves the channel. + */ + RemoteOffline = 7, +} + +/** + * The preset local voice reverberation option. + */ +export enum AudioReverbPreset { + /** + * The original voice (no local voice reverberation). + */ + Off = 0x00000000, + /** + * Pop music. + */ + Popular = 0x00000001, + /** + * R&B. + */ + RnB = 0x00000002, + /** + * Rock music. + */ + Rock = 0x00000003, + /** + * Hip-hop music. + */ + HipHop = 0x00000004, + /** + * Pop concert. + */ + VocalConcert = 0x00000005, + /** + * Karaoke. + */ + KTV = 0x00000006, + /** + * Recording studio. + */ + Studio = 0x00000007, + /** + * The reverberation style typical of a KTV venue (enhanced). + */ + FX_KTV = 0x00100001, + /** + * The reverberation style typical of a concert hall (enhanced). + */ + FX_VOCAL_CONCERT = 0x00100002, + /** + * The reverberation style typical of an uncle’s voice. + */ + FX_UNCLE = 0x00100003, + /** + * The reverberation style typical of a sister’s voice. + */ + FX_SISTER = 0x00100004, + /** + * The reverberation style typical of a recording studio (enhanced). + */ + FX_STUDIO = 0x00100005, + /** + * The reverberation style typical of popular music (enhanced). + */ + FX_POPULAR = 0x00100006, + /** + * The reverberation style typical of R&B music (enhanced). + */ + FX_RNB = 0x00100007, + /** + * The reverberation style typical of the vintage phonograph. + */ + FX_PHONOGRAPH = 0x00100008, + /** + * The reverberation of the virtual stereo. The virtual stereo is an effect that renders + * the monophonic audio as the stereo audio, so that all users in the channel can hear the stereo voice effect. + * To achieve better virtual stereo reverberation, Agora recommends setting the profile + * parameter in [`RtcEngine#setAudioProfile`]{@link RtcEngine#setAudioProfile} as [`MusicHighQualityStereo(5)`]{@link AudioProfile.MusicHighQualityStereo}. + */ + VIRTUAL_STEREO = 0x00200001, +} + +/** + * Audio reverberation type. + */ +export enum AudioReverbType { + /** + * 0: The level of the dry signal (dB). The value ranges between -20 and 10. + */ + DryLevel = 0, + /** + * 1: The level of the early reflection signal (wet signal) in dB. The value ranges between -20 and 10. + */ + WetLevel = 1, + /** + * 2: The room size of the reverberation. A larger room size means a stronger reverberation. The value ranges between 0 and 100. + */ + RoomSize = 2, + /** + * 3: The length of the initial delay of the wet signal (ms). The value ranges between 0 and 200. + */ + WetDelay = 3, + /** + * 4: The reverberation strength. The value ranges between 0 and 100. + */ + Strength = 4, +} + +/** + * Audio sample rate. + */ +export enum AudioSampleRateType { + /** + * 32000: 32 kHz. + */ + Type32000 = 32000, + /** + * 44100: 44.1 kHz. + */ + Type44100 = 44100, + /** + * 48000: 48 kHz. + */ + Type48000 = 48000, +} + +/** + * Audio scenario. + */ +export enum AudioScenario { + /** + * 0: Default. + */ + Default = 0, + /** + * 1: Entertainment scenario, supporting voice during gameplay. + */ + ChatRoomEntertainment = 1, + /** + * 2: Education scenario, prioritizing fluency 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. + */ + GameStreaming = 3, + /** + * 4: Showroom scenario, optimizing the audio quality with external professional equipment. + */ + ShowRoom = 4, + /** + * 5: Gaming scenario. + */ + ChatRoomGaming = 5, +} + +/** + * The preset audio voice configuration used to change the voice effect. + */ +export enum AudioVoiceChanger { + /** + * The original voice (no local voice change). + */ + Off = 0x00000000, + /** + * An old man’s voice. + */ + OldMan = 0x00000001, + /** + * A little boy’s voice. + */ + BabyBoy = 0x00000002, + /** + * A little girl’s voice. + */ + BabyGirl = 0x00000003, + /** + * The voice of a growling bear. + */ + ZhuBaJie = 0x00000004, + /** + * Ethereal vocal effects. + */ + Ethereal = 0x00000005, + /** + * Hulk’s voice. + */ + Hulk = 0x00000006, + /** + * A more vigorous voice. + */ + BEAUTY_VIGOROUS = 0x00100001, + /** + * A deeper voice. + */ + BEAUTY_DEEP = 0x00100002, + /** + * A mellower voice. + */ + BEAUTY_MELLOW = 0x00100003, + /** + * Falsetto. + */ + BEAUTY_FALSETTO = 0x00100004, + /** + * A fuller voice. + */ + BEAUTY_FULL = 0x00100005, + /** + * A clearer voice. + */ + BEAUTY_CLEAR = 0x00100006, + /** + * A more resounding voice. + */ + BEAUTY_RESOUNDING = 0x00100007, + /** + * A more ringing voice. + */ + BEAUTY_RINGING = 0x00100008, + /** + * A more spatially resonant voice. + */ + BEAUTY_SPACIAL = 0x00100009, + /** + * (For male only) A more magnetic voice. Do not use it when the speaker is a female; otherwise, voice distortion occurs. + */ + GENERAL_BEAUTY_VOICE_MALE_MAGNETIC = 0x00200001, + /** + * (For female only) A fresher voice. Do not use it when the speaker is a male; otherwise, voice distortion occurs. + */ + GENERAL_BEAUTY_VOICE_FEMALE_FRESH = 0x00200002, + /** + * (For female only) A more vital voice. Do not use it when the speaker is a male; otherwise, voice distortion occurs. + */ + GENERAL_BEAUTY_VOICE_FEMALE_VITALITY = 0x00200003, +} + +/** + * The camera capturer configuration. + */ +export enum CameraCaptureOutputPreference { + /** + * 0: (default) Self-adapts the camera output parameters to the system performance and network conditions to balance CPU consumption and video preview quality. + */ + Auto = 0, + /** + * 1: Prioritizes the system performance. The SDK chooses the dimension and frame rate of the local camera capture closest to those set by [`setVideoEncoderConfiguration`]{@link RtcEngine.setVideoEncoderConfiguration}. + */ + Performance = 1, + /** + * 2: Prioritizes the local preview quality. The SDK chooses higher camera output parameters to improve the local video preview quality. This option requires extra CPU and RAM usage for video pre-processing. + */ + Preview = 2, + /** + * 3: Internal use only + */ + Unkown = 3, +} + +/** + * The camera direction. + */ +export enum CameraDirection { + /** + * 0: The rear camera. + */ + Rear = 0, + /** + * 1: The front camera. + */ + Front = 1, +} + +/** + * The error code in AgoraChannelMediaRelayError. + */ +export enum ChannelMediaRelayError { + /** + * 0: The state is normal. + */ + None = 0, + /** + * 1: An error occurs in the server response. + */ + ServerErrorResponse = 1, + /** + * 2: No server response. You can call the leaveChannel method to leave the channel. + * [`leaveChannel`]{@link RtcEngine.leaveChannel} + */ + ServerNoResponse = 2, + /** + * 3: The SDK fails to access the service, probably due to limited resources of the server. + */ + NoResourceAvailable = 3, + /** + * 4: Fails to send the relay request. + */ + FailedJoinSourceChannel = 4, + /** + * 5: Fails to accept the relay request. + */ + FailedJoinDestinationChannel = 5, + /** + * 6: The server fails to receive the media stream. + */ + FailedPacketReceivedFromSource = 6, + /** + * 7: The server fails to send the media stream. + */ + FailedPacketSentToDestination = 7, + /** + * 8: The SDK disconnects from the server due to poor network connections. You can call [`leaveChannel`]{@link RtcEngine.leaveChannel} to leave the channel. + */ + ServerConnectionLost = 8, + /** + * 9: An internal error occurs in the server. + */ + InternalError = 9, + /** + * 10: The token of the source channel has expired. + */ + SourceTokenExpired = 10, + /** + * 11: The token of the destination channel has expired. + */ + DestinationTokenExpired = 11, +} + +/** + * The event code in `ChannelMediaRelayEvent`. + */ +export enum ChannelMediaRelayEvent { + /** + * 0: The user disconnects from the server due to poor network connections. + */ + Disconnect = 0, + /** + * 1: The network reconnects. + */ + Connected = 1, + /** + * 2: The user joins the source channel. + */ + JoinedSourceChannel = 2, + /** + * 3: The user joins the destination channel. + */ + JoinedDestinationChannel = 3, + /** + * 4: The SDK starts relaying the media stream to the destination channel. + */ + SentToDestinationChannel = 4, + /** + * 5: The server receives the video stream from the source channel. + */ + ReceivedVideoPacketFromSource = 5, + /** + * 6: The server receives the audio stream from the source channel. + */ + ReceivedAudioPacketFromSource = 6, + /** + * 7: The destination channel is updated. + */ + UpdateDestinationChannel = 7, + /** + * 8: The destination channel update fails due to internal reasons. + */ + UpdateDestinationChannelRefused = 8, + /** + * 9: The destination channel does not change, which means that the destination channel fails to be updated. + */ + UpdateDestinationChannelNotChange = 9, + /** + * 10: The destination channel name is null. + */ + UpdateDestinationChannelIsNil = 10, + /** + * 11: The video profile is sent to the server. + */ + VideoProfileUpdate = 11, +} + +/** + * The state code in [`ChannelMediaRelayState`]{@link ChannelMediaRelayState}. + */ +export enum ChannelMediaRelayState { + /** + * 0: The SDK is initializing. + */ + Idle = 0, + /** + * 1: The SDK tries to relay the media stream to the destination channel. + */ + Connecting = 1, + /** + * 2: The SDK successfully relays the media stream to the destination channel. + */ + Running = 2, + /** + * 3: A failure occurs. See the details in error. + */ + Failure = 3, +} + +/** + * Channel profile. + */ +export enum ChannelProfile { + /** + * 0: (Default) The Communication profile. + * Use this profile in one-on-one calls or group calls, where all users can talk freely. + */ + Communication = 0, + /** + * 1: The Live-Broadcast profile. + * Users in a live-broadcast channel have a role as either host or audience. A host can both send and receive streams; an audience can only receive streams. + */ + LiveBroadcasting = 1, + /** + * 2: The Gaming profile. + * This profile uses a codec with a lower bitrate and consumes less power. Applies to the gaming scenario, where all game players can talk freely. + */ + Game = 2, +} + +/** + * Client role in the `LiveBroadcasting` profile. + */ +export enum ClientRole { + /** + * 1: A host can both send and receive streams. + */ + Broadcaster = 1, + /** + * 2: The default role. An audience can only receive streams. + */ + Audience = 2, +} + +/** + * Reasons for the connection state change. + */ +export enum ConnectionChangedReason { + /** + * 0: The SDK is connecting to Agora’s edge server. + */ + Connecting = 0, + /** + * 1: The SDK has joined the channel successfully. + */ + JoinSuccess = 1, + /** + * 2: The connection between the SDK and Agora’s edge server is interrupted. + */ + Interrupted = 2, + /** + * 3: The connection between the SDK and Agora’s edge server is banned by Agora’s edge server. + */ + BannedByServer = 3, + /** + * 4: The SDK fails to join the channel for more than 20 minutes and stops reconnecting to the channel. + */ + JoinFailed = 4, + /** + * 5: The SDK has left the channel. + */ + LeaveChannel = 5, + /** + * 6: The specified App ID is invalid. Try to rejoin the channel with a valid App ID. + */ + InvalidAppId = 6, + /** + * 7: The specified channel name is invalid. Try to rejoin the channel with a valid channel name. + */ + InvalidChannelName = 7, + /** + * 8: The generated token is invalid probably due to the following reasons: + * - The App Certificate for the project is enabled in Console, but you do not use Token when joining the channel. If you enable the App Certificate, you must use a token to join the channel. + * - The uid that you specify in the [`joinChannel`]{@link RtcEngine.joinChannel} method is different from the uid that you pass for generating the token. + */ + InvalidToken = 8, + /** + * 9: The token has expired. Generate a new token from your server. + */ + TokenExpired = 9, + /** + * 10: The user is banned by the server. + */ + RejectedByServer = 10, + /** + * 11: The SDK tries to reconnect after setting a proxy server. + */ + SettingProxyServer = 11, + /** + * 12: The token renews. + */ + RenewToken = 12, + /** + * 13: The client IP address has changed, probably due to a change of the network type, IP address, or network port. + */ + ClientIpAddressChanged = 13, + /** + * 14: Timeout for the keep-alive of the connection between the SDK and Agora’s edge server. The connection state changes to: + * [`Reconnecting`]{@link ConnectionStateType.Reconnecting} + */ + KeepAliveTimeout = 14, +} + +/** + * Connection states. + */ +export enum ConnectionStateType { + /** + * 1: The SDK is disconnected from Agora's edge server. + * - This is the initial state before [`joinChannel`]{@link RtcEngine.joinChannel}. + * - The SDK also enters this state when the app calls [`leaveChannel`]{@link RtcEngine.leaveChannel}. + */ + Disconnected = 1, + /** + * 2: The SDK is connecting to Agora's edge server. + * - When the app calls [`joinChannel`]{@link RtcEngine.joinChannel}, the SDK starts to establish a connection to the specified channel, triggers the [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callback, and switches to the [`Connecting`]{@link ConnectionStateType.Connecting} state. + * - When the SDK successfully joins the channel, the SDK triggers the [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callback and switches to the [`Connected`]{@link ConnectionStateType.Connected} state. + * - After the SDK joins the channel and when it finishes initializing the media engine, the SDK triggers the [`JoinChannelSuccess`]{@link RtcEngineEvents.JoinChannelSuccess} callback. + */ + Connecting = 2, + /** + * 3: The SDK is connected to Agora's edge server and joins a channel. You can now publish or subscribe to a media stream in the channel. + * If the connection to the channel is lost because, for example, the network is down or switched, the SDK automatically tries to reconnect and triggers: + * - The [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callback, and switches to the [`Reconnecting`]{@link ConnectionStateType.Reconnecting} state. + */ + Connected = 3, + /** + * 4: The SDK keeps rejoining the channel after being disconnected from a joined channel because of network issues. + * - If the SDK cannot rejoin the channel within 10 seconds after being disconnected from Agora’s edge server, the SDK triggers the [`ConnectionLost`]{@link RtcEngineEvents.ConnectionLost} callback, stays in the [`Reconnecting`]{@link ConnectionStateType.Reconnecting} state, and keeps rejoining the channel. + * + * - If the SDK fails to rejoin the channel 20 minutes after being disconnected from Agora’s edge server, the SDK triggers the [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callback, switches to the [`Failed`]{@link ConnectionStateType.Failed} state, and stops rejoining the channel. + * [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} + */ + Reconnecting = 4, + /** + * 5: The SDK fails to connect to Agora's edge server or join the channel. + * You must call [`leaveChannel`]{@link RtcEngine.leaveChannel} to leave this state, and call [`joinChannel`]{@link RtcEngine.joinChannel} again to rejoin the channel. + * + * If the SDK is banned from joining the channel by Agora’s edge server (through the RESTful API), the SDK triggers the [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callbacks. + */ + Failed = 5, +} + +/** + * The video encoding degradation preference under limited bandwidth. + */ +export enum DegradationPreference { + /** + * 0: (Default) Degrades the frame rate to guarantee the video quality. + */ + MaintainQuality = 0, + /** + * 1: Degrades the video quality to guarantee the frame rate. + */ + MaintainFramerate = 1, + /** + * 2: Reserved for future use. + */ + Balanced = 2, +} + +/** + * Encryption mode. + */ +export enum EncryptionMode { + /** + * @deprecated + * 0: This mode is deprecated. + */ + None = 0, + /** + * 1: (Default) 128-bit AES encryption, XTS mode. + */ + AES128XTS = 1, + /** + * 2: 128-bit AES encryption, ECB mode. + */ + AES128ECB = 2, + /** + * 3: 256-bit AES encryption, XTS mode. + */ + AES256XTS = 3, + /** + * 4: 128-bit SM4 encryption, ECB mode. + * + * @since v3.1.2. + */ + SM4128ECB = 4, +} + +/** + * Error codes occur when the SDK encounters an error that cannot be recovered automatically without any app intervention. + */ +export enum ErrorCode { + /** + * 0: No error occurs. + */ + NoError = 0, + /** + * 1: A general error occurs (no specified reason). + */ + Failed = 1, + /** + * 2: An invalid parameter is used. For example, the specific channel name includes illegal characters. + */ + InvalidArgument = 2, + /** + * 3: The SDK module is not ready. + * Possible solutions: + * - Check the audio device. + * - Check the completeness of the app. + * - Re-initialize the SDK. + */ + NotReady = 3, + /** + * 4: The current state of the SDK does not support this function. + */ + NotSupported = 4, + /** + * 5: The request is rejected. This is for internal SDK use only, and is not returned to the app through any method or callback. + */ + Refused = 5, + /** + * 6: The buffer size is not big enough to store the returned data. + */ + BufferTooSmall = 6, + /** + * 7: The SDK is not initialized before calling this method. + */ + NotInitialized = 7, + /** + * 9: No permission exists. Check if the user has granted access to the audio or video device. + */ + NoPermission = 9, + /** + * 10: An API method timeout occurs. Some API methods require the SDK to return the execution result, and this error occurs if the request takes too long (over 10 seconds) for the SDK to process. + */ + TimedOut = 10, + /** + * 11: The request is canceled. This is for internal SDK use only, and is not returned to the app through any method or callback. + */ + Canceled = 11, + /** + * 12: The method is called too often. This is for internal SDK use only, and is not returned to the app through any method or callback. + */ + TooOften = 12, + /** + * 13: The SDK fails to bind to the network socket. This is for internal SDK use only, and is not returned to the app through any method or callback. + */ + BindSocket = 13, + /** + * 14: The network is unavailable. This is for internal SDK use only, and is not returned to the app through any method or callback. + */ + NetDown = 14, + /** + * 15: No network buffers are available. This is for internal SDK use only, and is not returned to the app through any method or callback. + */ + NoBufs = 15, + /** + * 17: The request to join the channel is rejected. + * Possible reasons are: + * - The user is already in the channel, and still calls the API method to join the channel, for example, [`joinChannel`]{@link RtcEngine.joinChannel} + * - The user tries joining the channel during the echo test. Please join the channel after the echo test ends. + */ + JoinChannelRejected = 17, + /** + * 18: The request to leave the channel is rejected. + * Possible reasons are: + * - The user left the channel and still calls the API method to leave the channel, for example, [`leaveChannel`]{@link RtcEngine.leaveChannel}. + * - The user has not joined the channel and calls the API method to leave the channel. + */ + LeaveChannelRejected = 18, + /** + * 19: The resources are occupied and cannot be used. + */ + AlreadyInUse = 19, + /** + * 20: The SDK gave up the request due to too many requests. + */ + Abort = 20, + /** + * 21: In Windows, specific firewall settings cause the SDK to fail to initialize and crash. + */ + InitNetEngine = 21, + /** + * 22: The app uses too much of the system resources and the SDK fails to allocate the resources. + */ + ResourceLimited = 22, + /** + * 101: The specified App ID is invalid. Please try to rejoin the channel with a valid App ID. + */ + InvalidAppId = 101, + /** + * 102: The specified channel name is invalid. Please try to rejoin the channel with a valid channel name. + */ + InvalidChannelId = 102, + /** + * 103: Fails to get server resources in the specified region. Please try to specify another region. + * + * @since v3.1.2. + */ + NoServerResources = 103, + /** + * 109: The token expired. + * @deprecated Use [`TokenExpired`]{@link ConnectionChangedReason.TokenExpired} in the reason parameter of [`onConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged}. + * + * Possible reasons are: + * - Authorized Timestamp expired: The timestamp is represented by the number of seconds elapsed since 1/1/1970. The user can use the token to access the Agora service within five minutes after the token is generated. If the user does not access the Agora service after five minutes, this token is no longer valid. + * - Call Expiration Timestamp expired: The timestamp is the exact time when a user can no longer use the Agora service (for example, when a user is forced to leave an ongoing call). When a value is set for the Call Expiration Timestamp, it does not mean that the token will expire, but that the user will be banned from the channel. + */ + TokenExpired = 109, + /** + * 110: The token is invalid. + * @deprecated Use [`InvalidToken`]{@link ConnectionChangedReason.InvalidToken} in the reason parameter of [`onConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged}. + * + * Possible reasons are: + * - The App Certificate for the project is enabled in Console, but the user is using the App ID. Once the App Certificate is enabled, the user must use a token. + * - The uid is mandatory, and users must set the same uid as the one set in the [`joinChannel`]{@link RtcEngine.joinChannel} method. + */ + InvalidToken = 110, + /** + * 111: The Internet connection is interrupted. This applies to the Agora Web SDK only. + */ + ConnectionInterrupted = 111, + /** + * 112: The Internet connection is lost. This applies to the Agora Web SDK only. + */ + ConnectionLost = 112, + /** + * 113: The user is not in the channel when calling the [`sendStreamMessage`]{@link RtcEngine.sendStreamMessage} or [`getUserInfoByUserAccount`]{@link RtcEngine.getUserInfoByUserAccount} method. + */ + NotInChannel = 113, + /** + * 114: The size of the sent data is over 1024 bytes when the user calls the [`sendStreamMessage`]{@link RtcEngine.sendStreamMessage} method. + */ + SizeTooLarge = 114, + /** + * 115: The bitrate of the sent data exceeds the limit of 6 Kbps when the user calls the [`sendStreamMessage`]{@link RtcEngine.sendStreamMessage} method. + */ + BitrateLimit = 115, + /** + * 116: Too many data streams (over five streams) are created when the user calls the [`createDataStream`]{@link RtcEngine.createDataStream} method. + */ + TooManyDataStreams = 116, + /** + * 120: Decryption fails. The user may have used a different encryption password to join the channel. Check your settings or try rejoining the channel. + */ + DecryptionFailed = 120, + /** + * 123: The client is banned by the server. + */ + ClientIsBannedByServer = 123, + /** + * 124: Incorrect watermark file parameter. + */ + WatermarkParam = 124, + /** + * 125: Incorrect watermark file path. + */ + WatermarkPath = 125, + /** + * 126: Incorrect watermark file format. + */ + WatermarkPng = 126, + /** + * 127: Incorrect watermark file information. + */ + WatermarkInfo = 127, + /** + * 128: Incorrect watermark file data format. + */ + WatermarkAGRB = 128, + /** + * 129: An error occurs in reading the watermark file. + */ + WatermarkRead = 129, + /** + * 130: The encrypted stream is not allowed to publish. + */ + EncryptedStreamNotAllowedPublish = 130, + /** + * 134: The user account is invalid. + */ + InvalidUserAccount = 134, + /** + * 151: CDN related errors. Remove the original URL address and add a new one by calling the [`removePublishStreamUrl`]{@link RtcEngine.removePublishStreamUrl} and [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} methods. + */ + PublishStreamCDNError = 151, + /** + * 152: The host publishes more than 10 URLs. Delete the unnecessary URLs before adding new ones. + */ + PublishStreamNumReachLimit = 152, + /** + * 153: The host manipulates other hosts' URLs. Check your app logic. + */ + PublishStreamNotAuthorized = 153, + /** + * 154: An error occurs in Agora’s streaming server. Call the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method to publish the stream again. + */ + PublishStreamInternalServerError = 154, + /** + * 155: The server fails to find the stream. + */ + PublishStreamNotFound = 155, + /** + * 156: The format of the RTMP stream URL is not supported. Check whether the URL format is correct. + */ + PublishStreamFormatNotSuppported = 156, + /** + * 1001: Fails to load the media engine. + */ + LoadMediaEngine = 1001, + /** + * 1002: Fails to start the call after enabling the media engine. + */ + StartCall = 1002, + /** + * 1003: Fails to start the camera. + * + * @deprecated Use [`CaptureFailure`]{@link LocalVideoStreamError.CaptureFailure} in the error parameter of [`LocalVideoStateChanged`]{@link RtcEngineEvents.LocalVideoStateChanged}. + */ + StartCamera = 1003, + /** + * 1004: Fails to start the video rendering module. + */ + StartVideoRender = 1004, + /** + * 1005: Audio Device Module: A general error occurs in the Audio Device Module (the reason is not classified specifically). Check if the audio device is used by another app, or try rejoining the channel. + */ + AdmGeneralError = 1005, + /** + * 1006: Audio Device Module: An error occurs in using the Java resources. + */ + AdmJavaResource = 1006, + /** + * 1007: Audio Device Module: An error occurs in setting the sampling frequency. + */ + AdmSampleRate = 1007, + /** + * 1008: Audio Device Module: An error occurs in initializing the playback device. + */ + AdmInitPlayout = 1008, + /** + * 1009: Audio Device Module: An error occurs in starting the playback device. + */ + AdmStartPlayout = 1009, + /** + * 1010: Audio Device Module: An error occurs in stopping the playback device. + */ + AdmStopPlayout = 1010, + /** + * 1011: Audio Device Module: An error occurs in initializing the recording device. + */ + AdmInitRecording = 1011, + /** + * 1012: Audio Device Module: An error occurs in starting the recording device. + */ + AdmStartRecording = 1012, + /** + * 1013: Audio Device Module: An error occurs in stopping the recording device. + */ + AdmStopRecording = 1013, + /** + * 1015: Audio Device Module: A playback error occurs. Check your playback device, or try rejoining the channel. + */ + AdmRuntimePlayoutError = 1015, + /** + * 1017: Audio Device Module: A recording error occurs. + */ + AdmRuntimeRecordingError = 1017, + /** + * 1018: Audio Device Module: Fails to record. + */ + AdmRecordAudioFailed = 1018, + /** + * 1020: Audio device module: The audio playback frequency is abnormal, which may cause audio freezes. This abnormality is caused by high CPU usage. Agora recommends stopping other apps. + */ + AdmPlayAbnormalFrequency = 1020, + /** + * 1021: Audio device module: The audio recording frequency is abnormal, which may cause audio freezes. This abnormality is caused by high CPU usage. Agora recommends stopping other apps. + */ + AdmRecordAbnormalFrequency = 1021, + /** + * 1022: Audio Device Module: An error occurs in initializing the loopback device. + */ + AdmInitLoopback = 1022, + /** + * 1023: Audio Device Module: An error occurs in starting the loopback device. + */ + AdmStartLoopback = 1023, + /** + * 1027: Audio Device Module: No recording permission. + */ + AdmNoPermission = 1027, + /** + * 1030: Audio Routing: Fails to route the audio to the connected Bluetooth device. The default route is used. + */ + AudioBtScoFailed = 1030, + /** + * 1359: Audio Device Module: No recording device exists. + */ + AdmNoRecordingDevice = 1359, + /** + * 1360: No playback device exists. + */ + AdmNoPlayoutDevice = 1360, + /** + * 1501: Video Device Module: The camera is unauthorized. + */ + VdmCameraNotAuthorized = 1501, + /** + * 1600: Video Device Module: An unknown error occurs. + */ + VcmUnknownError = 1600, + /** + * 1601: Video Device Module: An error occurs in initializing the video encoder. + */ + VcmEncoderInitError = 1601, + /** + * 1602: Video Device Module: An error occurs in video encoding. + */ + VcmEncoderEncodeError = 1602, + /** + * 1603: Video Device Module: An error occurs in setting the video encoder. + * + * @deprecated + * This error code is deprecated. + */ + VcmEncoderSetError = 1603, +} + +/** + * State of importing an external video stream in a live broadcast. + */ +export enum InjectStreamStatus { + /** + * 0: The external video stream imported successfully. + */ + StartSuccess = 0, + /** + * 1: The external video stream already exists. + */ + StartAlreadyExists = 1, + /** + * 2: The external video stream import is unauthorized. + */ + StartUnauthorized = 2, + /** + * 3: Import external video stream timeout. + */ + StartTimedout = 3, + /** + * 4: The external video stream failed to import. + */ + StartFailed = 4, + /** + * 5: The external video stream stops importing successfully. + */ + StopSuccess = 5, + /** + * 6: No external video stream is found. + */ + StopNotFound = 6, + /** + * 7: The external video stream to be stopped importing is unauthorized. + */ + StopUnauthorized = 7, + /** + * 8: Stopping importing the external video stream timed out. + */ + StopTimedout = 8, + /** + * 9: Stopping Importing the external video stream failed. + */ + StopFailed = 9, + /** + * 10: The external video stream import is corrupted. + */ + Broken = 10, +} + +/** + * The state of the probe test result. + */ +export enum LastmileProbeResultState { + /** + * 1: the last-mile network probe test is complete. + */ + Complete = 1, + /** + * 2: the last-mile network probe test is incomplete and the bandwidth estimation is not available, probably due to limited test resources. + */ + IncompleteNoBwe = 2, + /** + * 3: The last-mile network probe test is not carried out, probably due to poor network conditions. + */ + Unavailable = 3, +} + +/** + * The lightening contrast level. + */ +export enum LighteningContrastLevel { + /** + * 0: Low contrast level. + */ + Low = 0, + /** + * 1: (Default) Normal contrast level. + */ + Normal = 1, + /** + * 2: High contrast level. + */ + High = 2, +} + +/** + * The detailed error information of the local video. + */ +export enum LocalVideoStreamError { + /** + * 0: The local video is normal. + */ + OK = 0, + /** + * 1: No specified reason for the local video failure. + */ + Failure = 1, + /** + * 2: No permission to use the local video device. + */ + DeviceNoPermission = 2, + /** + * 3: The local video capturer is in use. + */ + DeviceBusy = 3, + /** + * 4: The local video capture fails. Check whether the capturer is working properly. + */ + CaptureFailure = 4, + /** + * 5: The local video encoding fails. + */ + EncodeFailure = 5, +} + +/** + * The state of the local video stream. + */ +export enum LocalVideoStreamState { + /** + * 0: The local video is in the initial state. + */ + Stopped = 0, + /** + * 1: The local video capturer starts successfully. + */ + Capturing = 1, + /** + * 2: The first local video frame encodes successfully. + */ + Encoding = 2, + /** + * 3: The local video fails to start. + */ + Failed = 3, +} + +/** + * Output log filter level. + */ +export enum LogFilter { + /** + * 0: Do not output any log information. + */ + Off = 0, + /** + * 0x080f: Output all log information. Set your log filter as debug if you want to get the most complete log file. + */ + Debug = 0x080f, + /** + * 0x000f: Output CRITICAL, ERROR, WARNING, and INFO level log information. We recommend setting your log filter as this level. + */ + Info = 0x000f, + /** + * 0x000e: Outputs CRITICAL, ERROR, and WARNING level log information. + */ + Warning = 0x000e, + /** + * 0x000c: Outputs CRITICAL and ERROR level log information. + */ + Error = 0x000c, + /** + * 0x0008: Outputs CRITICAL level log information. + */ + Critical = 0x0008, +} + +/** + * Network quality. + */ +export enum NetworkQuality { + /** + * 0: The network quality is unknown. + */ + Unknown = 0, + /** + * 1: The network quality is excellent. + */ + Excellent = 1, + /** + * 2: The network quality is quite good, but the bitrate may be slightly lower than excellent. + */ + Good = 2, + /** + * 3: Users can feel the communication slightly impaired. + */ + Poor = 3, + /** + * 4: Users can communicate only not very smoothly. + */ + Bad = 4, + /** + * 5: The network quality is so bad that users can hardly communicate. + */ + VBad = 5, + /** + * 6: The network is disconnected and users cannot communicate at all. + */ + Down = 6, + /** + * 7: Users cannot detect the network quality. (Not in use.) + */ + Unsupported = 7, + /** + * 8: Detecting the network quality. + */ + Detecting = 8, +} + +/** + * Network type. + */ +export enum NetworkType { + /** + * -1: The network type is unknown. + */ + Unknown = -1, + /** + * 0: The SDK disconnects from the network. + */ + Disconnected = 0, + /** + * 1: The network type is LAN. + */ + LAN = 1, + /** + * 2: The network type is Wi-Fi (including hotspots). + */ + WIFI = 2, + /** + * 3: The network type is mobile 2G. + */ + Mobile2G = 3, + /** + * 4: The network type is mobile 3G. + */ + Mobile3G = 4, + /** + * 5: The network type is mobile 4G. + */ + Mobile4G = 5, +} + +/** + * The detailed error information for streaming. + */ +export enum RtmpStreamingErrorCode { + /** + * 0: The RTMP streaming publishes successfully. + */ + OK = 0, + /** + * 1: Invalid argument used. If, for example, you do not call the [`setLiveTranscoding`]{@link RtcEngine.setLiveTranscoding} method to configure + * the `LiveTranscoding` parameters before calling the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method, the SDK returns this error. + * Check whether you set the parameters in the [`setLiveTranscoding`]{@link RtcEngine.setLiveTranscoding} method properly. + */ + InvalidParameters = 1, + /** + * 2: The RTMP 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. + */ + ConnectionTimeout = 3, + /** + * 4: An error occurs in Agora’s streaming server. Call the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method to publish the streaming again. + */ + InternalServerError = 4, + /** + * 5: An error occurs in the RTMP server. + */ + RtmpServerError = 5, + /** + * 6: The RTMP streaming publishes too frequently. + */ + TooOften = 6, + /** + * 7: The host publishes more than 10 URLs. Delete the unnecessary URLs before adding new ones. + */ + ReachLimit = 7, + /** + * 8: The host manipulates other hosts' URLs. Check your app logic. + */ + NotAuthorized = 8, + /** + * 9: Agora’s server fails to find the RTMP streaming. + */ + StreamNotFound = 9, + /** + * 10: The format of the RTMP streaming URL is not supported. Check whether the URL format is correct. + */ + FormatNotSupported = 10, +} + +/** + * The RTMP 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}. + */ + Idle = 0, + /** + * 1: The SDK is connecting to Agora’s streaming server and the RTMP 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. + */ + 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. + * + * - 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, + * [`Failure`]{@link RtmpStreamingState.Failure} returns. + * + * You can also reconnect to the server by calling the [`removePublishStreamUrl`]{@link RtcEngine.removePublishStreamUrl} and [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} methods. + */ + 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. + */ + Failure = 4, +} + +/** + * Stream fallback option. + */ +export enum StreamFallbackOptions { + /** + * 0: No fallback behavior for the local/remote video stream when the uplink/downlink network condition is unreliable. The quality of the stream is not guaranteed. + */ + Disabled = 0, + /** + * 1: Under unreliable downlink network conditions, the remote video stream falls back to the + * low-stream (low resolution and low bitrate) video. You can only set this option + * in the [`setRemoteSubscribeFallbackOption`]{@link RtcEngine.setRemoteSubscribeFallbackOption} method. + * Nothing happens when you set this in the [`setLocalPublishFallbackOption`]{@link RtcEngine.setLocalPublishFallbackOption} method. + */ + VideoStreamLow = 1, + /** + * 2: Under unreliable uplink network conditions, the published video stream falls back to audio only. Under unreliable downlink network conditions, the remote video stream first falls back to the low-stream (low resolution and low bitrate) video; and then to an audio-only stream if the network condition deteriorates. + */ + AudioOnly = 2, +} + +/** + * Reason for the user being offline. + */ +export enum UserOfflineReason { + /** + * 0: The user left the current channel. + */ + Quit = 0, + /** + * 1: The SDK timed out and the user dropped offline because no data packet is received within a certain period of time. If a user quits the call and the message is not passed to the SDK (due to an unreliable channel), the SDK assumes the user dropped offline. + */ + Dropped = 1, + /** + * 2: (Live broadcast only.) The client role switched from the host to the audience. + */ + BecomeAudience = 2, +} + +/** + * The priority of the remote user. + */ +export enum UserPriority { + /** + * 50: The user’s priority is high. + */ + High = 50, + /** + * 100: (Default) The user’s priority is normal. + */ + Normal = 100, +} + +/** + * Self-defined video codec profile. + */ +export enum VideoCodecProfileType { + /** + * 66: Baseline video codec profile. Generally used in video calls on mobile phones. + */ + BaseLine = 66, + /** + * 77: Main video codec profile. Generally used in mainstream electronics, such as MP4 players, portable video players, PSP, and iPads. + */ + Main = 77, + /** + * 100: (Default) High video codec profile. Generally used in high-resolution broadcasts or television. + */ + High = 100, +} + +/** + * Video frame rate. + */ +export enum VideoFrameRate { + /** + * -1: The minimum frame rate of the video. + */ + Min = -1, + /** + * 1: 1 fps. + */ + Fps1 = 1, + /** + * 7: 7 fps. + */ + Fps7 = 7, + /** + * 10: 10 fps. + */ + Fps10 = 10, + /** + * 15: 15 fps. + */ + Fps15 = 15, + /** + * 24: 24 fps. + */ + Fps24 = 24, + /** + * 30: 30 fps. + */ + Fps30 = 30, + /** + * 60: 60 fps (macOS only). + */ + Fps60 = 60, +} + +/** + * Bitrate of the video (Kbps). Refer to the table below and set your bitrate. + * If you set a bitrate beyond the proper range, the SDK automatically adjusts it to a value within the range. + * + * **Video Bitrate Table** + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
ResolutionFrame rate

(fps)

Base Bitrate

(Kbps, for Communication)

Live Bitrate

(Kbps, for Live Broadcasting)

160*1201565130
120*1201550100
320*18015140280
180*18015100200
240*18015120240
320*24015200400
240*24015140280
424*24015220440
640*36015400800
360*36015260520
640*360306001200
360*36030400800
480*36015320640
480*36030490980
640*480155001000
480*48015400800
640*480307501500
480*480306001200
848*480156101220
848*480309301860
640*48010400800
1280*7201511302260
1280*7203017103420
960*720159101820
960*7203013802760
+ * + * Agora uses different video codecs for different profiles to optimize the user experience. For example, + * the Communication profile prioritizes the smoothness while the LIVE_BROADCASTING profile prioritizes the + * video quality (a higher bitrate). Therefore, We recommend setting this parameter as STANDARD_BITRATE = 0. + */ +export enum BitRate { + /** + * 0: (Recommended) the standard bitrate mode. In this mode, the bitrates differ between the Live-broadcast and Communication profiles: + * - Communication profile: the video bitrate is the same as the base bitrate. + * - Live-broadcast profile: the video bitrate is twice the base bitrate. + */ + Standard = 0, + /** + * -1: The compatible bitrate mode. In this mode, the bitrate stays the same regardless of the profile. In the Live-broadcast profile, + * if you choose this mode, the video frame rate may be lower than the set value. + */ + Compatible = -1, +} + +/** + * Video mirror mode. + */ +export enum VideoMirrorMode { + /** + * 0: (Default) The SDK determines the mirror mode. + */ + Auto = 0, + /** + * 1: Enables mirror mode. + */ + Enabled = 1, + /** + * 2: Disables mirror mode. + */ + Disabled = 2, +} + +/** + * Video output orientation mode. + */ +export enum VideoOutputOrientationMode { + /** + * 0: Adaptive mode (Default). + * + * The video encoder adapts to the orientation mode of the video input device. When you use a custom video source, the output video from the encoder inherits the orientation of the original video. + * - If the width of the captured video from the SDK is greater than the height, the encoder sends the video in landscape mode. The encoder also sends the rotational information of the video, and the receiver uses the rotational information to rotate the received video. + * - If the original video is in portrait mode, the output video from the encoder is also in portrait mode. The encoder also sends the rotational information of the video to the receiver. + */ + Adaptative = 0, + /** + * 1: Landscape mode. + * + * The video encoder always sends the video in landscape mode. The video encoder rotates the original video before sending it and the rotational information is 0. This mode applies to scenarios involving CDN live streaming. + */ + FixedLandscape = 1, + /** + * 2: Portrait mode. + * + * The video encoder always sends the video in portrait mode. The video encoder rotates the original video before sending it and the rotational information is 0. This mode applies to scenarios involving CDN live streaming. + */ + FixedPortrait = 2, +} + +/** + * Quality change of the local video in terms of target frame rate and target bit rate since last count. + */ +export enum VideoQualityAdaptIndication { + /** + * 0: The quality of the local video stays the same. + */ + AdaptNone = 0, + /** + * 1: The quality improves because the network bandwidth increases. + */ + AdaptUpBandwidth = 1, + /** + * 2: The quality worsens because the network bandwidth decreases. + */ + AdaptDownBandwidth = 2, +} + +/** + * The state of the remote video. + */ +export enum VideoRemoteState { + /** + * 0: The remote video is in the default state, probably due to: + * - [`LocalMuted`]{@link VideoRemoteStateReason.LocalMuted} + * - [`RemoteMuted`]{@link VideoRemoteStateReason.RemoteMuted} + * - [`RemoteOffline`]{@link VideoRemoteStateReason.RemoteOffline} + */ + Stopped = 0, + /** + * 1: The first remote video packet is received. + */ + Starting = 1, + /** + * 2: The remote video stream is decoded and plays normally, probably due to: + * - [`NetworkRecovery`]{@link VideoRemoteStateReason.NetworkRecovery} + * - [`LocalUnmuted`]{@link VideoRemoteStateReason.LocalUnmuted} + * - [`RemoteUnmuted`]{@link VideoRemoteStateReason.RemoteUnmuted} + * - [`AudioFallbackRecovery`]{@link VideoRemoteStateReason.AudioFallbackRecovery} + */ + Decoding = 2, + /** + * 3: The remote video is frozen, probably due to: + * - [`NetworkCongestion`]{@link VideoRemoteStateReason.NetworkCongestion} + * - [`AudioFallback`]{@link VideoRemoteStateReason.AudioFallback} + */ + Frozen = 3, + /** + * 4: The remote video fails to start, probably due to: [`Internal`]{@link VideoRemoteStateReason.Internal} + */ + Failed = 4, +} + +/** + * The reason of the remote video state change. + */ +export enum VideoRemoteStateReason { + /** + * 0: Internal reasons. + */ + Internal = 0, + /** + * 1: Network congestion. + */ + NetworkCongestion = 1, + /** + * 2: Network recovery. + */ + NetworkRecovery = 2, + /** + * 3: The local user stops receiving the remote video stream or disables the video module. + */ + LocalMuted = 3, + /** + * 4: The local user resumes receiving the remote video stream or disables the video module. + */ + LocalUnmuted = 4, + /** + * 5: The remote user stops sending the video stream or disables the video module. + */ + RemoteMuted = 5, + /** + * 6: The remote user resumes sending the video stream or enables the video module. + */ + RemoteUnmuted = 6, + /** + * 7: The remote user leaves the channel. + */ + RemoteOffline = 7, + /** + * 8: The remote media stream falls back to the audio-only stream due to poor network conditions. + */ + AudioFallback = 8, + /** + * 9: The remote media stream switches back to the video stream after the network conditions improve. + */ + AudioFallbackRecovery = 9, +} + +/** + * Video display mode. + */ +export enum VideoRenderMode { + /** + * 1: Uniformly scale the video until it fills the visible boundaries (cropped). One dimension of the video may have clipped contents. + */ + Hidden = 1, + /** + * 2: Uniformly scale the video until one of its dimension fits the boundary (zoomed to fit). Areas that are not filled due to the disparity in the aspect ratio are filled with black. + */ + Fit = 2, + /** + * @deprecated + * 3: This mode is deprecated. + */ + Adaptive = 3, + /** + * 4: The fill mode. In this mode, the SDK stretches or zooms the video to fill the display window. + */ + FILL = 4, +} + +/** + * Video stream type. + */ +export enum VideoStreamType { + /** + * 0: High-bitrate, high-resolution video stream. + */ + High = 0, + /** + * 1: Low-bitrate, low-resolution video stream. + */ + Low = 1, +} + +/** + * Warning codes occur when the SDK encounters an error that may be recovered automatically. + * These are only notifications, and can generally be ignored. For example, when the SDK loses connection to the server, + * the SDK reports the [`OpenChannelTimeout(106)`]{@link WarningCode.OpenChannelTimeout} warning and tries to reconnect automatically. + */ +export enum WarningCode { + /** + * 8: The specified view is invalid. Specify a view when using the video call function. + */ + InvalidView = 8, + /** + * 16: Failed to initialize the video function, possibly caused by a lack of resources. The users cannot see the video while the voice communication is not affected. + */ + InitVideo = 16, + /** + * 20: The request is pending, usually due to some module not being ready, and the SDK postpones processing the request. + */ + Pending = 20, + /** + * 103: No channel resources are available. Maybe because the server cannot allocate any channel resource. + */ + NoAvailableChannel = 103, + /** + * 104: A timeout occurs when looking up the channel. When joining a channel, the SDK looks up the specified channel. The warning usually occurs when the network condition is too poor for the SDK to connect to the server. + */ + LookupChannelTimeout = 104, + /** + * 105: The server rejects the request to look up the channel. + * The server cannot process this request or the request is illegal. + * @deprecated + * + * Use [`RejectedByServer(10)`]{@link ConnectionChangedReason.RejectedByServer} in the reason parameter + * of [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged}. + */ + LookupChannelRejected = 105, + /** + * 106: The server rejects the request to look up the channel. The server cannot process this request + * or the request is illegal. + */ + OpenChannelTimeout = 106, + /** + * 107: The server rejects the request to open the channel. The server cannot process this request or the request is illegal. + */ + OpenChannelRejected = 107, + /** + * 111: A timeout occurs when switching to the live video. + */ + SwitchLiveVideoTimeout = 111, + /** + * 118: A timeout occurs when setting the client role in the live broadcast profile. + */ + SetClientRoleTimeout = 118, + /** + * 119: The client role is unauthorized. + */ + SetClientRoleNotAuthorized = 119, + /** + * 121: The ticket to open the channel is invalid. + */ + OpenChannelInvalidTicket = 121, + /** + * 122: Try connecting to another server. + */ + OpenChannelTryNextVos = 122, + /** + * 701: An error occurs in opening the audio mixing file. + */ + AudioMixingOpenError = 701, + /** + * 1014: Audio Device Module: a warning occurs in the playback device. + */ + AdmRuntimePlayoutWarning = 1014, + /** + * 1016: Audio Device Module: a warning occurs in the recording device. + */ + AdmRuntimeRecordingWarning = 1016, + /** + * 1019: Audio Device Module: no valid audio data is collected. + */ + AdmRecordAudioSilence = 1019, + /** + * 1020: Audio Device Module: a playback device fails. + */ + AdmPlaybackMalfunction = 1020, + /** + * 1021: Audio Device Module: a recording device fails. + */ + AdmRecordMalfunction = 1021, + /** + * 1025: Audio Device Module: call is interrupted by system events such as phone call or siri etc. + */ + AdmInterruption = 1025, + /** + * 1029: During a call, `AudioSessionCategory` should be set to `AVAudioSessionCategoryPlayAndRecord`, and the SDK monitors this value. If the `AudioSessionCategory` is set to other values, this warning code is triggered and the SDK will forcefully set it back to `AVAudioSessionCategoryPlayAndRecord`. + * + * @since v3.1.2. + */ + AdmCategoryNotPlayAndRecord = 1029, + /** + * 1031: Audio Device Module: the recorded audio is too low. + */ + AdmRecordAudioLowlevel = 1031, + /** + * 1032: Audio Device Module: the playback audio is too low. + */ + AdmPlayoutAudioLowlevel = 1032, + /** + * 1033: Audio Device Module: The recording device is busy. + */ + AdmRecordIsOccupied = 1033, + /** + * 1040: Audio device module: An error occurs in the audio driver. Solutions: + * - Restart your audio device. + * - Restart your device where the app runs. + * - Upgrade the sound card drive. + * + * @since v3.1.2. + */ + AdmNoDataReadyCallback = 1040, + /** + * 1042: Audio device module: The audio recording device is different from the audio playback device, which may cause echoes problem. Agora recommends using the same audio device to record and playback audio. + * + * @since v3.1.2. + */ + AdmInconsistentDevices = 1042, + /** + * 1051: Audio Device Module: howling is detected. + */ + ApmHowling = 1051, + /** + * 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, +} + +/** + * The audio channel of the sound. + */ +export enum AudioChannel { + /** + * 0: (Default) Supports dual channels. Depends on the upstream of the host. + */ + Channel0 = 0, + /** + * 1: The audio stream of the host uses the FL audio channel. If the upstream of the host uses multiple audio channels, these channels will be mixed into mono first. + */ + Channel1 = 1, + /** + * 2: The audio stream of the host uses the FC audio channel. If the upstream of the host uses multiple audio channels, these channels will be mixed into mono first. + */ + Channel2 = 2, + /** + * 3: The audio stream of the host uses the FR audio channel. If the upstream of the host uses multiple audio channels, these channels will be mixed into mono first. + */ + Channel3 = 3, + /** + * 4: The audio stream of the host uses the BL audio channel. If the upstream of the host uses multiple audio channels, these channels will be mixed into mono first. + */ + Channel4 = 4, + /** + * 5: The audio stream of the host uses the BR audio channel. If the upstream of the host uses multiple audio channels, these channels will be mixed into mono first. + */ + Channel5 = 5, +} + +/** + * Video codec types. + */ +export enum VideoCodecType { + /** + * 1: Standard VP8. + */ + VP8 = 1, + /** + * 2: Standard H264. + */ + H264 = 2, + /** + * 3: Enhanced VP8. + */ + EVP = 3, + /** + * 4: Enhanced H264. + */ + E264 = 4, +} + +/** + * The publishing state. + * + * @since v3.1.2. + */ +export enum StreamPublishState { + /** + * 0: The initial publishing state after joining the channel. + */ + Idle = 0, + /** + * 1: Fails to publish the local stream. Possible reasons: + * - The local user calls [`muteLocalAudioStream(true)`]{@link RtcEngine.muteLocalAudioStream} or [`muteLocalVideoStream(true)`]{@link RtcEngine.muteLocalVideoStream} to stop sending local streams. + * - The local user calls [`disableAudio`]{@link RtcEngine.disableAudio} or [`disableVideo`]{@link RtcEngine.disableVideo} to disable the entire audio or video module. + * - The local user calls [`enableLocalAudio(false)`]{@link RtcEngine.enableLocalAudio} or [`enableLocalVideo(false)`]{@link enableLocalVideo} to disable the local audio sampling or video capturing. + * - The role of the local user is `Audience`. + */ + NoPublished = 1, + /** + * 2: Publishing. + */ + Publishing = 2, + /** + * 3: Publishes successfully. + */ + Published = 3, +} + +/** + * The subscribing state. + * + * @since v3.1.2. + */ +export enum StreamSubscribeState { + /** + * 0: The initial subscribing state after joining the channel. + */ + Idle = 0, + /** + * 1: Fails to subscribe to the remote stream. Possible reasons: + * - The remote user: + * - Calls [`muteLocalAudioStream(true)`]{@link RtcEngine.muteLocalAudioStream} or [`muteLocalVideoStream(true)`]{@link RtcEngine.muteLocalVideoStream} to stop sending local streams. + * - The local user calls [`disableAudio`]{@link RtcEngine.disableAudio} or [`disableVideo`]{@link RtcEngine.disableVideo} to disable the entire audio or video module. + * - The local user calls [`enableLocalAudio(false)`]{@link RtcEngine.enableLocalAudio} or [`enableLocalVideo(false)`]{@link enableLocalVideo} to disable the local audio sampling or video capturing. + * - The role of the local user is `Audience`. + * - The local user calls the following methods to stop receiving remote streams: + * - Calls [`muteRemoteAudioStream(true)`]{@link RtcEngine.muteRemoteAudioStream}, [`muteAllRemoteAudioStreams(true)`]{@link RtcEngine.muteAllRemoteAudioStreams}, or [`setDefaultMuteAllRemoteAudioStreams(true)`]{@link RtcEngine.setDefaultMuteAllRemoteAudioStreams} to stop receiving remote audio streams. + * - Calls [`muteRemoteVideoStream(true)`]{@link RtcEngine.muteRemoteVideoStream}, [`muteAllRemoteVideoStreams(true)`]{@link RtcEngine.muteAllRemoteVideoStreams}, or [`setDefaultMuteAllRemoteVideoStreams(true)`]{@link RtcEngine.setDefaultMuteAllRemoteVideoStreams} to stop receiving remote video streams. + */ + NoSubscribed = 1, + /** + * 2: Subscribing. + */ + Subscribing = 2, + /** + * 3: Subscribes to and receives the remote stream successfully. + */ + Subscribed = 3, +} + +/** + * Events during the RTMP streaming. + */ +export enum RtmpStreamingEvent { + /** + * 1: An error occurs when you add a background image or a watermark image to the RTMP stream. + */ + FailedLoadImage = 1, +} + +/** + * Audio session restriction. + */ +export enum AudioSessionOperationRestriction { + /** + * No restriction, the SDK has full control of the audio session operations. + */ + None = 0, + /** + * The SDK does not change the audio session category. + */ + SetCategory = 1, + /** + * The SDK does not change any setting of the audio session (category, mode, categoryOptions). + */ + ConfigureSession = 1 << 1, + /** + * The SDK keeps the audio session active when leaving a channel. + */ + DeactivateSession = 1 << 2, + /** + * The SDK does not configure the audio session anymore. + */ + All = 1 << 7, +} diff --git a/src/common/RtcChannel.native.ts b/src/common/RtcChannel.native.ts new file mode 100644 index 000000000..c2911f4a0 --- /dev/null +++ b/src/common/RtcChannel.native.ts @@ -0,0 +1,977 @@ +import { NativeEventEmitter, NativeModules } from 'react-native'; + +import type { + ChannelMediaOptions, + ChannelMediaRelayConfiguration, + ClientRole, + ConnectionStateType, + EncryptionConfig, + EncryptionMode, + LiveInjectStreamConfig, + LiveTranscoding, + UserPriority, + VideoStreamType, +} from '../Types'; +import type { Listener, RtcChannelEvents, Subscription } from './RtcEvents'; + +const { + /** + * @ignore + */ + AgoraRtcChannelModule, +} = NativeModules; +/** + * @ignore + */ +const Prefix = AgoraRtcChannelModule.prefix; +/** + * @ignore + */ +const RtcChannelEvent = new NativeEventEmitter(AgoraRtcChannelModule); + +/** + * @ignore + */ +const channels = new Map(); + +/** + * The {@link RtcChannel} class. + */ +export default class RtcChannel implements RtcChannelInterface { + /** + * The ID of RtcChannel + */ + public readonly channelId: string; + /** + * @ignore + */ + private _listeners = new Map>(); + + /** + * @ignore + */ + private constructor(channelId: string) { + this.channelId = channelId; + } + + /** + * @ignore + */ + private _callMethod(method: string, args?: {}): Promise { + return AgoraRtcChannelModule.callMethod( + method, + args === undefined + ? { channelId: this.channelId } + : { channelId: this.channelId, ...args } + ); + } + + /** + * Creates and gets an [`RtcChannel`]{@link RtcChannel} instance. + * + * To join more than one channel, call this method multiple times to create as many `RtcChannel` instances as needed, + * and call the [`joinChannel`]{@link RtcChannel.joinChannel} method of each created `RtcChannel` object. + * + * After joining multiple channels, you can simultaneously subscribe to streams of all the channels, but publish a stream in only one channel at one time. + * @param channelId The unique channel name for the Agora RTC session in the string format. + * The string length must be less than 64 bytes. + * Supported character scopes are: + * - All lowercase English letters: a to z. + * - All uppercase English letters: A to Z. + * - All numeric characters: 0 to 9. + * - The space character. + * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + * + * **Note** + * - This parameter does not have a default value. You must set it. + * - Do not set it as the empty string "". Otherwise, the SDK returns [`Refused(-5)`]{@link ErrorCode.Refused}. + * + * @returns + * - An `RtcChannel` instance, if the method call succeeds. + * - Null, if the method call fails. + * - [`Refused(-5)`]{@link ErrorCode.Refused}, if you set channelId as the empty string "". + */ + static async create(channelId: string): Promise { + if (channels.get(channelId)) return channels.get(channelId) as RtcChannel; + await AgoraRtcChannelModule.callMethod('create', { channelId }); + channels.set(channelId, new RtcChannel(channelId)); + return channels.get(channelId) as RtcChannel; + } + + /** + * Destroys all [`RtcChannel`]{@link RtcChannel} instances. + */ + static destroyAll() { + channels.forEach(async (value) => { + await value.destroy(); + }); + channels.clear(); + } + + /** + * Destroys the [`RtcChannel`]{@link RtcChannel} instance. + */ + destroy(): Promise { + this.removeAllListeners(); + channels.delete(this.channelId); + return this._callMethod('destroy'); + } + + /** + * Adds the [`RtcChannelEvents`]{@link RtcChannelEvents} handler. + * + * After setting the [`RtcChannelEvents`]{@link RtcChannelEvents} handler, you can listen for channel events and receive the statistics of the corresponding [`RtcChannel`]{@link RtcChannel} instance. + * @param event The event type. + * @param listener The [`RtcChannelEvents`]{@link RtcChannelEvents} handler. + */ + addListener( + event: EventType, + listener: RtcChannelEvents[EventType] + ): Subscription { + const callback = (res: any) => { + const { channelId, data } = res; + if (channelId === this.channelId) { + // @ts-ignore + listener(...data); + } + }; + let map = this._listeners.get(event); + if (map === undefined) { + map = new Map(); + this._listeners.set(event, map); + } + RtcChannelEvent.addListener(Prefix + event, callback); + map.set(listener, callback); + return { + remove: () => { + this.removeListener(event, listener); + }, + }; + } + + /** + * Removes the [`RtcChannelEvents`]{@link RtcChannelEvents} handler. + * + * For callback events that you only want to listen for once, call this method to remove the specific [`RtcEngineEvents`]{@link RtcEngineEvents} objects after you have received them. + * @param event The event type. + * @param listener The [`RtcChannelEvents`]{@link RtcChannelEvents} handler. + */ + removeListener( + event: EventType, + listener: RtcChannelEvents[EventType] + ) { + const map = this._listeners.get(event); + if (map === undefined) return; + RtcChannelEvent.removeListener( + Prefix + event, + map.get(listener) as Listener + ); + map.delete(listener); + } + + /** + * Removes all the [`RtcChannelEvents`]{@link RtcChannelEvents} handlers. + * @param event The event type. + */ + removeAllListeners( + event?: EventType + ) { + if (event === undefined) { + this._listeners.forEach((_, key) => { + RtcChannelEvent.removeAllListeners(Prefix + key); + }); + this._listeners.clear(); + return; + } + RtcChannelEvent.removeAllListeners(Prefix + event); + this._listeners.delete(event as string); + } + + /** + * Sets the role of a user. + * + * 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: + * - 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. + */ + setClientRole(role: ClientRole): Promise { + return this._callMethod('setClientRole', { role }); + } + + /** + * Joins the channel with a user ID. + * + * **Note** + * - If you are already in a channel, you cannot rejoin it with the same UID. + * - We recommend using different UIDs for different channels. + * - 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. + * + * @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. + */ + joinChannel( + token: string | null, + optionalInfo: string | null, + optionalUid: number, + options: ChannelMediaOptions + ): Promise { + return this._callMethod('joinChannel', { + token, + optionalInfo, + optionalUid, + options, + }); + } + + /** + * Joins a channel with the user account. + * + * **Note** + * - If you are already in a channel, you cannot rejoin it with the same user account. + * - We recommend using different user accounts for different channels. + * - 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. + * + * @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 userAccount The user account. The maximum length of this parameter is 255 bytes. Ensure that you set this parameter and do not set it as null. + * - All lowercase English letters: a to z. + * - All uppercase English letters: A to Z. + * - All numeric characters: 0 to 9. + * - The space character. + * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + * @param options The channel media options. + */ + joinChannelWithUserAccount( + token: string | null, + userAccount: string, + options: ChannelMediaOptions + ): Promise { + return this._callMethod('joinChannelWithUserAccount', { + token, + userAccount, + options, + }); + } + + /** + * Leaves the current channel. + * + * 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. + */ + leaveChannel(): Promise { + return this._callMethod('leaveChannel'); + } + + /** + * Renews the token when the current token expires. + * + * In the following situations, the SDK decides that the current token has expired: + * - The SDK triggers the [`TokenPrivilegeWillExpire`]{@link RtcChannelEvents.TokenPrivilegeWillExpire} callback, or + * - The [`ConnectionStateChanged`]{@link RtcChannelEvents.ConnectionStateChanged} callback reports the [`TokenExpired(9)`]{@link ConnectionChangedReason.TokenExpired} error. + * + * 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. + */ + renewToken(token: string): Promise { + return this._callMethod('renewToken', { token }); + } + + /** + * Gets the network connection state of the SDK. + */ + getConnectionState(): Promise { + return this._callMethod('getConnectionState'); + } + + /** + * Publishes the local stream to the channel. + * You must keep the following restrictions in mind when calling this method. + * Otherwise, the SDK returns the [`Refused(-5)`]{@link ErrorCode.Refused}: + * - This method publishes one stream only to the channel corresponding to the current [`RtcChannel`]{@link RtcChannel} instance. + * - In a `LiveBroadcasting` channel, only a host can call this method. To switch the client role, call [`setClientRole`]{@link RtcChannel.setClientRole} of the current [`RtcChannel`]{@link RtcChannel} instance. + * - You can publish a stream to only one channel at a time. For details, see the advanced guide *Join Multiple Channels*. + */ + publish(): Promise { + return this._callMethod('publish'); + } + + /** + * Stops publishing a stream to the channel. + * + * If you call this method in a channel where you are not publishing streams, the SDK returns [`Refused(-5)`]{@link ErrorCode.Refused}. + */ + unpublish(): Promise { + return this._callMethod('unpublish'); + } + + /** + * Gets the current call ID. + * + * @returns + * - The current call ID, if the method call succeeds. + * - The empty string "", if the method call fails. + */ + getCallId(): Promise { + return this._callMethod('getCallId'); + } + + /** + * Adjusts the playback volume of a specified remote user. + * + * You can call this method as many times as necessary to adjust the playback volume of different remote + * users, or to repeatedly adjust the playback volume of the same remote user. + * + * **Note** + * - Call this method after joining a channel. + * - The playback volume here refers to the mixed volume of a specified remote user. + * - This method can only adjust the playback volume of one specified remote user at a time. + * To adjust the playback volume of different remote users, call the method as many times, once for each remote user. + * + * @param uid ID of the remote user. + * @param volume The playback volume of the specified remote user. The value ranges from 0 to 100: + * - 0: Mute. + * - 100: The original volume. + */ + adjustUserPlaybackSignalVolume(uid: number, volume: number): Promise { + return this._callMethod('adjustUserPlaybackSignalVolume', { uid, volume }); + } + + /** + * Stops/Resumes receiving the audio stream of the specified user. + * + * @param uid ID of the remote user whose audio stream you want to mute. + * @param muted Determines whether to receive/stop receiving the audio stream of the specified user: + * - `true`: Stop receiving the audio stream of the user. + * - `false`: (Default) Receive the audio stream of the user. + */ + muteRemoteAudioStream(uid: number, muted: boolean): Promise { + return this._callMethod('muteRemoteAudioStream', { uid, muted }); + } + + /** + * Stops/Resumes receiving all remote audio streams. + * + * @param muted Determines whether to receive/stop receiving all remote audio streams: + * - `true`: Stop receiving all remote audio streams. + * - `false`: (Default) Receive all remote audio streams. + */ + muteAllRemoteAudioStreams(muted: boolean): Promise { + return this._callMethod('muteAllRemoteAudioStreams', { muted }); + } + + /** + * Sets whether to receive all remote audio streams by default. + * + * @param muted Determines whether to receive/stop receiving all remote audio streams by default: + * - `true`: Stop receiving all remote audio streams by default. + * - `false`: (Default) Receive all remote audio streams by default. + */ + setDefaultMuteAllRemoteAudioStreams(muted: boolean): Promise { + return this._callMethod('setDefaultMuteAllRemoteAudioStreams', { muted }); + } + + /** + * Stops/Resumes receiving all remote video streams. + * + * @param muted Determines whether to receive/stop receiving all remote video streams: + * - `true`: Stop receiving all remote video streams. + * - `false`: (Default) Receive all remote video streams. + */ + muteAllRemoteVideoStreams(muted: boolean): Promise { + return this._callMethod('muteAllRemoteVideoStreams', { muted }); + } + + /** + * Stops/Resumes receiving the video stream of the specified user. + * + * @param uid ID of the remote user whose video stream you want to mute. + * @param muted Determines whether to receive/stop receiving the video stream of the specified user: + * - `true`: Stop receiving the video stream of the user. + * - `false`: (Default) Receive the video stream of the user. + */ + muteRemoteVideoStream(uid: number, muted: boolean): Promise { + return this._callMethod('muteRemoteVideoStream', { uid, muted }); + } + + /** + * Sets whether to receive all remote video streams by default. + * + * @param muted Determines whether to receive/stop receiving all remote video streams by default: + * - `true`: Stop receiving all remote video streams by default. + * - `false`: (Default) Receive all remote video streams by default. + */ + setDefaultMuteAllRemoteVideoStreams(muted: boolean): Promise { + return this._callMethod('setDefaultMuteAllRemoteVideoStreams', { muted }); + } + + /** + * Sets the sound position of a remote user. + * + * When the local user calls this method to set the sound position of a remote user, the sound difference between the left and right channels allows the local user to track the real-time position of the remote user, creating a real sense of space. This method applies to massively multiplayer online games, such as Battle Royale games. + * + * **Note** + * - For this method to work, enable stereo panning for remote users by calling the [`enableSoundPositionIndication`]{@link RtcEngine.enableSoundPositionIndication} method before joining a channel. + * - This method requires hardware support. For the best sound positioning, we recommend using a stereo headset. + * + * @param uid The ID of the remote user. + * @param pan The sound position of the remote user. The value ranges from -1.0 to 1.0: + * - 0.0: (default) The remote sound comes from the front. + * - -1.0: The remote sound comes from the left. + * - 1.0: The remote sound comes from the right. + * @param gain Gain of the remote user. The value ranges from 0.0 to 100.0. The default value is 100.0 (the original gain of the remote user). The smaller the value, the less the gain. + */ + setRemoteVoicePosition( + uid: number, + pan: number, + gain: number + ): Promise { + return this._callMethod('setRemoteVoicePosition', { uid, pan, gain }); + } + + /** + * Publishes the local stream 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. + * + * **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 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. + * + * @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, + * 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. + */ + addPublishStreamUrl(url: string, transcodingEnabled: boolean): Promise { + return this._callMethod('addPublishStreamUrl', { url, transcodingEnabled }); + } + + /** + * Removes an RTMP stream from the CDN. + * + * This method removes the RTMP URL address (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. + * + * @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, + * such as Chinese language characters. + */ + removePublishStreamUrl(url: string): Promise { + return this._callMethod('removePublishStreamUrl', { url }); + } + + /** + * Sets the video layout and audio settings for CDN live. + * + * The SDK triggers the [`TranscodingUpdated`]{@link RtcChannelEvents.TranscodingUpdated} callback when you + * call this method to update the [`LiveTranscoding`]{@link LiveTranscoding} class. If you call this method to set the [`LiveTranscoding`]{@link LiveTranscoding} + * class for the first time, the SDK does not trigger the [`TranscodingUpdated`]{@link RtcChannelEvents.TranscodingUpdated} 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 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. + * + * @param transcoding Sets the CDN live audio/video transcoding settings. + */ + setLiveTranscoding(transcoding: LiveTranscoding): Promise { + return this._callMethod('setLiveTranscoding', { transcoding }); + } + + /** + * Starts to relay media streams across channels. + * + * After a successful method call, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcChannelEvents.ChannelMediaRelayStateChanged} and [`ChannelMediaRelayEvent`]{@link RtcChannelEvents.ChannelMediaRelayEvent} callbacks, + * and these callbacks report the state and events of the media stream relay. + * + * - If the [`ChannelMediaRelayStateChanged`]{@link RtcChannelEvents.ChannelMediaRelayStateChanged} callback reports [`Running(2)`]{@link ChannelMediaRelayState.Running} and [`None(0)`]{@link ChannelMediaRelayError.None}, and + * the [`ChannelMediaRelayEvent`]{@link RtcChannelEvents.ChannelMediaRelayEvent} callback + * reports [`SentToDestinationChannel(4)`]{@link ChannelMediaRelayEvent.SentToDestinationChannel}, the SDK starts relaying media streams between the original and the destination channel. + * + * - If the [`ChannelMediaRelayStateChanged`]{@link RtcChannelEvents.ChannelMediaRelayStateChanged} callback returns [`Failure(3)`]{@link ChannelMediaRelayState.Failure}, an exception occurs during the media stream relay. + * + * **Note** + * - Contact support@agora.io before implementing this function. + * - We do not support string user accounts in this API. + * - Call this method after joining the channel. + * - This method can only be called by a host in a `LiveBroadcasting` channel. + * - After a successful method call, if you want to call this method again, ensure that you call the [`stopChannelMediaRelay`]{@link RtcChannel.stopChannelMediaRelay} method to quit the current relay. + * + * @param channelMediaRelayConfiguration The configuration of the media stream relay. + */ + startChannelMediaRelay( + channelMediaRelayConfiguration: ChannelMediaRelayConfiguration + ): Promise { + return this._callMethod('startChannelMediaRelay', { + channelMediaRelayConfiguration, + }); + } + + /** + * Stops the media stream relay. + * + * Once the relay stops, the host quits all the destination channels. + * After a successful method call, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcChannelEvents.ChannelMediaRelayStateChanged} callback. If the callback reports [`Idle(0)`]{@link ChannelMediaRelayState.Idle} and + * [`None(0)`]{@link ChannelMediaRelayError.None}, the host successfully stops the relay. + * + * **Note** + * - If the method call fails, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcChannelEvents.ChannelMediaRelayStateChanged} callback with + * the [`ServerNoResponse(2)`]{@link ChannelMediaRelayError.ServerNoResponse} or [`ServerConnectionLost(8)`]{@link ChannelMediaRelayError.ServerConnectionLost} state code. + * You can leave the channel using [`leaveChannel`]{@link RtcChannel.leaveChannel}, and the media stream relay automatically stops. + */ + stopChannelMediaRelay(): Promise { + return this._callMethod('stopChannelMediaRelay'); + } + + /** + * Updates the channels for media relay. + * + * After the channel media relay starts, if you want to relay the media stream to more channels, or leave the current relay channel, you can call this method. + * After a successful method call, the SDK triggers the [`ChannelMediaRelayEvent`]{@link RtcChannelEvents.ChannelMediaRelayEvent} callback with + * the [`UpdateDestinationChannel(7)`]{@link ChannelMediaRelayEvent.UpdateDestinationChannel} state code. + * + * **Note** + * - Call this method after the [`startChannelMediaRelay`]{@link RtcChannel.startChannelMediaRelay} method to update the destination channel. + * - This method supports adding at most four destination channels in the relay. + * + * @param channelMediaRelayConfiguration The media stream relay configuration. + */ + updateChannelMediaRelay( + channelMediaRelayConfiguration: ChannelMediaRelayConfiguration + ): Promise { + return this._callMethod('updateChannelMediaRelay', { + channelMediaRelayConfiguration, + }); + } + + /** + * Sets the default video-stream type of the remote video stream when the remote user sends dual streams. + * + * @param streamType Sets the default video-stream type. + */ + setRemoteDefaultVideoStreamType(streamType: VideoStreamType): Promise { + return this._callMethod('setRemoteDefaultVideoStreamType', { streamType }); + } + + /** + * Sets the video stream type of the remote video stream when the remote user sends dual streams. + * This method allows the app to adjust the corresponding video-stream type based on the size of the + * video window to reduce the bandwidth and resources. + * - If the remote user enables the dual-stream mode by calling the [`enableDualStreamMode`]{@link RtcEngine.enableDualStreamMode} method, + * the SDK receives the high-video stream by default. You can use this method to switch to the low-video stream. + * - If dual-stream mode is not enabled, the SDK receives the high-stream video by default. + * By default, the aspect ratio of the low-video stream is the same as the high-video stream. Once the resolution of the high-video stream is set, + * the system automatically sets the resolution, frame rate, and bitrate of the low-video stream. + * + * @param uid ID of the remote user sending the video stream. + * @param streamType Sets the video-stream type. + */ + setRemoteVideoStreamType( + uid: number, + streamType: VideoStreamType + ): Promise { + return this._callMethod('setRemoteVideoStreamType', { uid, streamType }); + } + + /** + * Sets the priority of a remote user's media stream. + * + * Use this method with the [`setRemoteSubscribeFallbackOption`]{@link RtcEngine.setRemoteSubscribeFallbackOption} method. + * If a remote video stream experiences the fallback, the SDK ensures the high-priority user gets the best possible stream quality. + * + * **Note** + * The Agora SDK supports setting userPriority as high for one user only. + * + * @param uid The ID of the remote user. + * @param userPriority The priority of the remote user. + */ + setRemoteUserPriority( + uid: number, + userPriority: UserPriority + ): Promise { + return this._callMethod('setRemoteUserPriority', { uid, userPriority }); + } + + /** + * Registers the metadata observer. + * + * A successful call of this method triggers the [`setMaxMetadataSize`]{@link RtcChannel.setMaxMetadataSize} method. + * + * This method enables you to add synchronized metadata in the video stream for more diversified live streaming interactions, + * such as sending shopping links, digital coupons, and online quizzes. + * + * **Note** + * - Call this method before the [`joinChannel`]{@link RtcChannel.joinChannel} method. + * - This method applies to the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile only. + */ + registerMediaMetadataObserver(): Promise { + return this._callMethod('registerMediaMetadataObserver'); + } + + /** + * Sends the metadata. + * + * @param metadata The metadata to be sent. + */ + sendMetadata(metadata: string): Promise { + return this._callMethod('sendMetadata', { metadata }); + } + + /** + * Sets the maximum size of the metadata. + * + * @param size Buffer size of the sent or received metadata. + */ + setMaxMetadataSize(size: number): Promise { + return this._callMethod('setMaxMetadataSize', { size }); + } + + /** + * Unregisters the metadata observer. + */ + unregisterMediaMetadataObserver(): Promise { + return this._callMethod('unregisterMediaMetadataObserver'); + } + + /** + * Enables/Disables the built-in encryption. + * + * @since v3.1.2. + * + * In scenarios requiring high security, Agora recommends calling `enableEncryption` to enable the built-in encryption before joining a channel. + * + * 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. + * - 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*. + * + * + * @param enabled Whether to enable the built-in encryption. + * - `true`: Enable the built-in encryption. + * - `false`: Disable the built-in encryption. + * @param config Configurations of built-in encryption schemas. See [`EncryptionConfig`]{@link EncryptionConfig}. + */ + enableEncryption(enabled: boolean, config: EncryptionConfig): Promise { + return this._callMethod('enableEncryption', { enabled, config }); + } + + /** + * Sets the built-in encryption mode. + * + * @deprecated + * Deprecated as of v3.1.2. Use [`enableEncryption`]{@link enableEncryption} instead. + * + * The Agora SDK supports built-in encryption, which is set to aes-128-xts mode by default. + * Call this method to set the encryption mode to use other encryption modes. + * All users in the same channel must use the same encryption mode and password. + * Refer to the information related to the AES encryption algorithm on the differences between the encryption modes. + * + * **Note** + * - Do not use this method for CDN streaming. + * - Before calling this method, ensure that you have called [`setEncryptionSecret`]{@link RtcChannel.setEncryptionSecret} to enable encryption. + * + * @param encryptionMode Sets the encryption mode. + */ + setEncryptionMode(encryptionMode: EncryptionMode): Promise { + return this._callMethod('setEncryptionMode', { encryptionMode }); + } + + /** + * Enables built-in encryption with an encryption password before joining a channel. + * + * @deprecated + * Deprecated as of v3.1.2. Use [`enableEncryption`]{@link enableEncryption} instead. + * + * All users in a channel must set the same encryption password. + * The encryption password is automatically cleared once a user leaves the channel. + * If the encryption password is not specified or set to empty, the encryption functionality is disabled. + * + * **Note** + * - For optimal transmission, ensure that the encrypted data size does not exceed the original data size + 16 bytes. 16 bytes is the maximum padding size for AES encryption. + * - Do not use this method for CDN live streaming. + * + * @param secret The encryption password. + */ + setEncryptionSecret(secret: string): Promise { + return this._callMethod('setEncryptionSecret', { secret }); + } + + /** + * Injects an online media stream to live interactive streaming. + * + * If this method call succeeds, the server pulls the voice or video stream and injects it into a live channel. This applies to scenarios where all audience members in the channel can watch a live show and interact with each other. + * + * Calling this method triggers the following callbacks: + * - The local client: + * - [`StreamInjectedStatus`]{@link RtcChannelEvents.StreamInjectedStatus}, with the state of injecting the media stream. + * - [`UserJoined`]{@link RtcChannelEvents.UserJoined}(uid: 666), if the method call succeeds and the online + * media stream is injected into the channel. + * - The remote client: + * - [`UserJoined`]{@link RtcChannelEvents.UserJoined}(uid: 666), if the method call succeeds and the online + * media stream is injected into the channel. + * + * **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. + * + * @param url The URL address to be added to the ongoing live interactive streaming. Valid protocols are RTMP, HLS, and FLV. + * - 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. + */ + addInjectStreamUrl( + url: string, + config: LiveInjectStreamConfig + ): Promise { + return this._callMethod('addInjectStreamUrl', { url, config }); + } + + /** + * Removes the injected online media stream from a `LiveBroadcasting` channel. + * + * This method removes the URL address added by [`addInjectStreamUrl`]{@link RtcChannel.addInjectStreamUrl}. + * + * If you successfully remove the URL address from the live interactive streaming, the SDK triggers the + * [`UserJoined`]{@link RtcChannelEvents.UserJoined} callback, with the stream uid of 666. + * + * @param url The URL address to be removed. + */ + removeInjectStreamUrl(url: string): Promise { + return this._callMethod('removeInjectStreamUrl', { url }); + } + + /** + * Creates a data stream. + * + * Each user can create up to five data streams during the life cycle of the [`RtcChannel`]{@link RtcChannel} instance. + * + * **Note** + * + * Set both the `reliable` and `ordered` parameters to `true` or `false`. Do not set one as `true` + * and the other as `false`. + * @param reliable Sets whether the recipients are guaranteed to receive the data stream from the + * sender within five seconds. + * - `true`: The recipients receive the data from the sender within five seconds. If the recipient does + * not receive the data within five seconds, the SDK triggers the [`StreamMessageError`]{@link RtcChannelEvents.StreamMessageError} callback and returns an error code. + * - `false`: There is no guarantee that the recipients receive the data stream within five seconds and no error message is reported for any delay or missing data stream. + * @param ordered Determines whether the recipients receive the data stream in the sent order. + * - `true`: The recipients receive the data in the sent order. + * - `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}. + */ + createDataStream(reliable: boolean, ordered: boolean): Promise { + return this._callMethod('createDataStream', { reliable, ordered }); + } + + /** + * Sends the data stream message. + * + * The SDK has the following restrictions on this method: + * - Up to 30 packets can be sent per second in a channel with each packet having a maximum size of 1 KB. + * - Each client can send up to 6 KB of data per second. + * - Each user can have up to five data channels simultaneously. + * + * A successful call of this method triggers the [`StreamMessage`]{@link RtcChannelEvents.StreamMessage} callback on the remote client, from which the remote user gets the stream message. + * + * A failed call of this method triggers the [`StreamMessageError`]{@link RtcChannelEvents.StreamMessageError} callback on the remote client. + * + * @param streamId ID of the sent data stream returned by the [`createDataStream`]{@link RtcChannel.createDataStream} method. + * + * @param message The message data. + */ + sendStreamMessage(streamId: number, message: string): Promise { + return this._callMethod('sendStreamMessage', { streamId, message }); + } +} + +/** + * @ignore + */ +interface RtcChannelInterface + extends RtcAudioInterface, + RtcVideoInterface, + RtcVoicePositionInterface, + RtcPublishStreamInterface, + RtcMediaRelayInterface, + RtcDualStreamInterface, + RtcFallbackInterface, + RtcMediaMetadataInterface, + RtcEncryptionInterface, + RtcInjectStreamInterface, + RtcStreamMessageInterface { + destroy(): Promise; + + setClientRole(role: ClientRole): Promise; + + joinChannel( + token: string | null, + optionalInfo: string | null, + optionalUid: number, + options: ChannelMediaOptions + ): Promise; + + joinChannelWithUserAccount( + token: string | null, + userAccount: string, + options: ChannelMediaOptions + ): Promise; + + leaveChannel(): Promise; + + renewToken(token: string): Promise; + + getConnectionState(): Promise; + + publish(): Promise; + + unpublish(): Promise; + + getCallId(): Promise; +} + +/** + * @ignore + */ +interface RtcAudioInterface { + adjustUserPlaybackSignalVolume(uid: number, volume: number): Promise; + + muteRemoteAudioStream(uid: number, muted: boolean): Promise; + + muteAllRemoteAudioStreams(muted: boolean): Promise; + + setDefaultMuteAllRemoteAudioStreams(muted: boolean): Promise; +} + +/** + * @ignore + */ +interface RtcVideoInterface { + muteRemoteVideoStream(uid: number, muted: boolean): Promise; + + muteAllRemoteVideoStreams(muted: boolean): Promise; + + setDefaultMuteAllRemoteVideoStreams(muted: boolean): Promise; +} + +/** + * @ignore + */ +interface RtcVoicePositionInterface { + setRemoteVoicePosition(uid: number, pan: number, gain: number): Promise; +} + +/** + * @ignore + */ +interface RtcPublishStreamInterface { + setLiveTranscoding(transcoding: LiveTranscoding): Promise; + + addPublishStreamUrl(url: string, transcodingEnabled: boolean): Promise; + + removePublishStreamUrl(url: string): Promise; +} + +/** + * @ignore + */ +interface RtcMediaRelayInterface { + startChannelMediaRelay( + channelMediaRelayConfiguration: ChannelMediaRelayConfiguration + ): Promise; + + updateChannelMediaRelay( + channelMediaRelayConfiguration: ChannelMediaRelayConfiguration + ): Promise; + + stopChannelMediaRelay(): Promise; +} + +/** + * @ignore + */ +interface RtcDualStreamInterface { + setRemoteVideoStreamType( + uid: number, + streamType: VideoStreamType + ): Promise; + + setRemoteDefaultVideoStreamType(streamType: VideoStreamType): Promise; +} + +/** + * @ignore + */ +interface RtcFallbackInterface { + setRemoteUserPriority(uid: number, userPriority: UserPriority): Promise; +} + +/** + * @ignore + */ +interface RtcMediaMetadataInterface { + registerMediaMetadataObserver(): Promise; + + unregisterMediaMetadataObserver(): Promise; + + setMaxMetadataSize(size: number): Promise; + + sendMetadata(metadata: string): Promise; +} + +/** + * @ignore + */ +interface RtcEncryptionInterface { + setEncryptionSecret(secret: string): Promise; + + setEncryptionMode(encryptionMode: EncryptionMode): Promise; + + enableEncryption(enabled: boolean, config: EncryptionConfig): Promise; +} + +/** + * @ignore + */ +interface RtcInjectStreamInterface { + addInjectStreamUrl( + url: string, + config: LiveInjectStreamConfig + ): Promise; + + removeInjectStreamUrl(url: string): Promise; +} + +/** + * @ignore + */ +interface RtcStreamMessageInterface { + createDataStream(reliable: boolean, ordered: boolean): Promise; + + sendStreamMessage(streamId: number, message: string): Promise; +} diff --git a/src/common/RtcEngine.native.ts b/src/common/RtcEngine.native.ts new file mode 100644 index 000000000..3319d09f8 --- /dev/null +++ b/src/common/RtcEngine.native.ts @@ -0,0 +1,2947 @@ +import { NativeEventEmitter, NativeModules } from 'react-native'; + +import { + AreaCode, + AudioEqualizationBandFrequency, + AudioProfile, + AudioRecordingQuality, + AudioReverbPreset, + AudioReverbType, + AudioSampleRateType, + AudioScenario, + AudioSessionOperationRestriction, + AudioVoiceChanger, + BeautyOptions, + CameraCapturerConfiguration, + ChannelMediaRelayConfiguration, + ChannelProfile, + ClientRole, + ConnectionStateType, + EncryptionConfig, + EncryptionMode, + LastmileProbeConfig, + LiveInjectStreamConfig, + LiveTranscoding, + LogFilter, + StreamFallbackOptions, + UserInfo, + UserPriority, + VideoEncoderConfiguration, + VideoStreamType, + WatermarkOptions, +} from '../Types'; +import type { Listener, RtcEngineEvents, Subscription } from './RtcEvents'; +import RtcChannel from './RtcChannel.native'; + +/** + * @ignore + */ +type Rate = 1 | 2 | 3 | 4 | 5; + +const { + /** + * @ignore + */ + AgoraRtcEngineModule, +} = NativeModules; +/** + * @ignore + */ +const Prefix = AgoraRtcEngineModule.prefix; +/** + * @ignore + */ +const RtcEngineEvent = new NativeEventEmitter(AgoraRtcEngineModule); + +/** + * @ignore + */ +let engine: RtcEngine | undefined; + +/** + * [`RtcEngine`]{@link RtcEngine} is the main class of the Agora SDK. + */ +export default class RtcEngine implements RtcEngineInterface { + /** + * @ignore + */ + private _listeners = new Map>(); + + /** + * @ignore + */ + private static _callMethod(method: string, args?: {}): Promise { + return AgoraRtcEngineModule.callMethod(method, args); + } + + /** + * Gets a created [`RtcEngine`]{@link RtcEngine} instance. + * + * **Note** + * + * Ensure that you have created an `RtcEngine`. Otherwise, the method call fails and the SDK returns an error message. + * @returns + * - The `RtcEngine` instance, if the method call succeeds. + * - Returns an error when it fails to get an `RtcEngine`. + */ + static instance(): RtcEngine { + if (engine) { + return engine as RtcEngine; + } else { + throw new Error('please create RtcEngine first'); + } + } + + /** + * Creates an [`RtcEngine`]{@link RtcEngine} instance. + * + * Unless otherwise specified, all the methods provided by the [`RtcEngine`]{@link RtcEngine} class are executed asynchronously. Agora recommends calling these methods in the same thread. + * + * **Note** + * - You must create an [`RtcEngine`]{@link RtcEngine} instance before calling any other method. + * - You can create an [`RtcEngine`]{@link RtcEngine} instance either by calling this method or by calling [`createWithAreaCode`]{@link createWithAreaCode}. The difference between [`createWithAreaCode`]{@link createWithAreaCode} and this method is that [`createWithAreaCode`]{@link createWithAreaCode} enables you to specify the connection area. + * - The Agora React Native SDK supports creating only one [`RtcEngine`]{@link RtcEngine} instance for an app. + * @param appId The App ID issued to you by Agora. See [How to get the App ID](https://docs.agora.io/en/Agora%20Platform/token#get-an-app-id). + * Only users in apps with the same App ID can join the same channel and communicate with each other. + * Use an App ID to create only one [`RtcEngine`]{@link RtcEngine} instance. To change your App ID, call [`destroy`]{@link destroy} to destroy the current [`RtcEngine`]{@link RtcEngine} instance, and after [`destroy`]{@link destroy} returns `0`, + * call `create` to create an [`RtcEngine`]{@link RtcEngine} instance with the new App ID. + * @returns + * - The `RtcEngine` instance, if the method call succeeds. + * - The error code, if the method call fails. + */ + static async create(appId: string): Promise { + return RtcEngine.createWithAreaCode(appId, AreaCode.GLOB); + } + + /** + * Creates an [`RtcEngine`]{@link RtcEngine} instance. + * + * Unless otherwise specified, all the methods provided by the [`RtcEngine`]{@link RtcEngine} class are executed asynchronously. Agora recommends calling these methods in the same thread. + * + * **Note** + * + * - You must create an [`RtcEngine`]{@link RtcEngine} instance before calling any other method. + * - You can create an [`RtcEngine`]{@link RtcEngine} instance either by calling this method or by calling [`create`]{@link create}. The difference between [`create`]{@link create} and this method is that this method enables you to specify the connection area. + * - The Agora React Native SDK supports creating only one [`RtcEngine`]{@link RtcEngine} instance for an app. + * @param appId The App ID issued to you by Agora. See [How to get the App ID](https://docs.agora.io/en/Agora%20Platform/token#get-an-app-id). + * Only users in apps with the same App ID can join the same channel and communicate with each other. Use an App ID to create only one [`RtcEngine`]{@link RtcEngine} instance. + * To change your App ID, call [`destroy`]{@link destroy} to destroy the current [`RtcEngine`]{@link RtcEngine} instance and after [`destroy`]{@link destroy} returns `0`, call [`create`]{@link create} to create an [`RtcEngine`]{@link RtcEngine} instance with the new App ID. + * @param areaCode The area of connection. This advanced feature applies to scenarios that have regional restrictions. + * For details, see {@link AreaCode}. + * + * After specifying the region, the app that integrates the Agora SDK connects to the Agora servers within that region. + * + * @returns + * - The `RtcEngine` instance, if the method call succeeds. + * - The error code, if the method call fails. + */ + static async createWithAreaCode( + appId: string, + areaCode: AreaCode + ): Promise { + if (engine) return engine; + await RtcEngine._callMethod('create', { appId, areaCode, appType: 8 }); + engine = new RtcEngine(); + return engine; + } + + /** + * Destroys the [`RtcEngine`]{@link RtcEngine} instance and releases all resources used by the Agora SDK. + * + * Use this method for apps in which users occasionally make voice or video calls. When users do not make calls, you can free up resources for other operations. + * Once you call this method to destroy the created [`RtcEngine`]{@link RtcEngine} instance, you cannot use any method or callback in the SDK any more. + * If you want to use the real-time communication functions again, you must call `create` to create a new [`RtcEngine`]{@link RtcEngine} instance. + * + * **Note** + * + * - Because [`destroy`]{@link destroy} is a synchronous method and the app cannot move on to another task until the execution completes, + * Agora suggests calling this method in a sub-thread to avoid congestion in the main thread. + * Besides, you cannot call [`destroy`]{@link destroy} in any method or callback of the SDK. + * Otherwise, the SDK cannot release the resources occupied by the [`RtcEngine`]{@link RtcEngine} instance until the callbacks return results, which may result in a deadlock. + * - If you want to create a new [`RtcEngine`]{@link RtcEngine} instance after destroying the current one, ensure that you wait till the [`destroy`]{@link destroy} method completes executing. + */ + destroy(): Promise { + RtcChannel.destroyAll(); + this.removeAllListeners(); + engine = undefined; + return RtcEngine._callMethod('destroy'); + } + + /** + * Adds the [`RtcEngineEvents`]{@link RtcEngineEvents} handler. + * + * After setting the [`RtcEngineEvents`]{@link RtcEngineEvents} handler, you can listen for `RtcEngine` events and receive the statistics of the corresponding RtcEngine instance. + * @param event The event type. + * @param listener The [`RtcEngineEvents`]{@link RtcEngineEvents} handler. + */ + addListener( + event: EventType, + listener: RtcEngineEvents[EventType] + ): Subscription { + const callback = (res: any) => { + const { channelId, data } = res; + if (channelId === undefined) { + // @ts-ignore + listener(...data); + } + }; + let map = this._listeners.get(event); + if (map === undefined) { + map = new Map(); + this._listeners.set(event, map); + } + RtcEngineEvent.addListener(Prefix + event, callback); + map.set(listener, callback); + return { + remove: () => { + this.removeListener(event, listener); + }, + }; + } + + /** + * Removes the [`RtcEngineEvents`]{@link RtcEngineEvents} handler. + * + * For callback events that you only want to listen for once, call this method to remove the specific [`RtcEngineEvents`]{@link RtcEngineEvents} objects after you have received them. + * @param event The event type. + * @param listener The [`RtcEngineEvents`]{@link RtcEngineEvents} handler. + */ + removeListener( + event: EventType, + listener: RtcEngineEvents[EventType] + ) { + const map = this._listeners.get(event); + if (map === undefined) return; + RtcEngineEvent.removeListener( + Prefix + event, + map.get(listener) as Listener + ); + map.delete(listener); + } + + /** + * Removes all the [`RtcEngineEvents`]{@link RtcEngineEvents} handlers. + * @param event The event type. + */ + removeAllListeners( + event?: EventType + ) { + if (event === undefined) { + this._listeners.forEach((_, key) => { + RtcEngineEvent.removeAllListeners(Prefix + key); + }); + this._listeners.clear(); + return; + } + RtcEngineEvent.removeAllListeners(Prefix + event); + this._listeners.delete(event as string); + } + + /** + * Sets the channel profile of the Agora [`RtcEngine`]{@link RtcEngine}. + * + * 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}. + */ + 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. + * + * 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: + * - 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. + */ + setClientRole(role: ClientRole): Promise { + return RtcEngine._callMethod('setClientRole', { role }); + } + + /** + * Allows a user to join a channel. + * + * Users in the same channel can talk to each other, and multiple users in the same channel can start a group chat. Users with different App IDs cannot call each other. + * You must call [`leaveChannel`]{@link leaveChannel} to exit the current call before joining another channel. + * + * A successful call of this method triggers the following callbacks: + * + * - The local client: [`JoinChannelSuccess`]{@link RtcEngineEvents.JoinChannelSuccess}. + * + * - The remote client: [`UserJoined`]{@link RtcEngineEvents.UserJoined}, 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. + * + * 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. + * + * **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. + * + * **Warning** + * + * Ensure that the App ID used for creating the token is the same App ID used in the `create` method for creating an [`RtcEngine`]{@link RtcEngine} object. Otherwise, CDN live streaming may fail. + * + * @param token The token for authentication: + * - 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 channelName The unique channel name for the AgoraRTC session in the string format. The string length must be less than 64 bytes. Supported character scopes are: + * - All lowercase English letters: a to z. + * - All uppercase English letters: A to Z. + * - All numeric characters: 0 to 9. + * - The space character. + * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + * @param optionalInfo Additional information about the channel. This parameter can be set as null or contain channel related information. Other users in the channel do not receive this message. + * @param optionalUid (Optional) User ID. A 32-bit unsigned integer with a value ranging from 1 to (2^32-1). `optionalUid` must be unique. If `optionalUid` is not assigned (or set to `0`), the SDK assigns and returns `uid` in the [`JoinChannelSuccess`]{@link RtcEngineEvents.JoinChannelSuccess} callback. + * Your app must record and maintain the returned uid since the SDK does not do so. + * + * 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”. + */ + joinChannel( + token: string | null, + channelName: string, + optionalInfo: string | null, + optionalUid: number + ): Promise { + return RtcEngine._callMethod('joinChannel', { + token, + channelName, + optionalInfo, + optionalUid, + }); + } + + /** + * Switches to a different channel. + * + * This method allows the audience of a [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} channel to switch to a different channel. + * + * 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. + * + * **Note** + * + * This method applies to the [`Audience`]{@link ClientRole.Audience} role in a [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} channel only. + * + * @param token The token for authentication: + * - 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 channelName Unique channel name for the AgoraRTC session in the string format. The string length must be less than 64 bytes. Supported character scopes are: + * - All lowercase English letters: a to z. + * - All uppercase English letters: A to Z. + * - All numeric characters: 0 to 9. + * - The space character. + * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + */ + switchChannel(token: string | null, channelName: string): Promise { + return RtcEngine._callMethod('switchChannel', { token, channelName }); + } + + /** + * Allows a user to leave a channel. + * + * After joining a channel, the user must call this method to end the call before joining another channel. + * This method returns `0` if the user leaves the channel and releases all resources related to the call. + * + * This method call is asynchronous, and the user has not exited the channel when the method call returns. + * Once the user leaves the channel, the SDK triggers the [`LeaveChannel`]{@link RtcEngineEvents.LeaveChannel} callback. + * A successful [`leaveChannel`]{@link leaveChannel} method call triggers the following callbacks: + * - The local client: [`LeaveChannel`]{@link RtcEngineEvents.LeaveChannel}. + * + * - The remote client: [`UserOffline`]{@link RtcEngineEvents.UserOffline}, if the user leaving the channel is in the [`Communication`]{@link ChannelProfile.Communication} channel, or is a [`Broadcaster`]{@link ClientRole.Broadcaster} + * in the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile. + * + * **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. + */ + leaveChannel(): Promise { + return RtcEngine._callMethod('leaveChannel'); + } + + /** + * Renews the token when the current token expires. + * + * The token expires after a period of time once the token schema is enabled when: + * - The SDK triggers the [`TokenPrivilegeWillExpire`]{@link RtcEngineEvents.TokenPrivilegeWillExpire} callback, or + * + * - The [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callback reports the [`TokenExpired(9)`]{@link ConnectionChangedReason.TokenExpired} error. + * + * 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. + */ + renewToken(token: string): Promise { + return RtcEngine._callMethod('renewToken', { token }); + } + + /** + * Enables interoperability with the Agora Web SDK ([`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} only). + * + * @deprecated This method is deprecated. The Agora Native SDK automatically enables interoperability with the Web SDK, so you no longer need to call this method. + * + * If the channel has Web SDK users, ensure that you call this method, or the video of the Native user will be a black screen for the Web user. + * Use this method when the channel profile is [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting}. Interoperability with the Agora Web SDK is enabled by default when the channel profile is [`Communication`]{@link ChannelProfile.Communication}. + * @param enabled Sets whether to enable/disable interoperability with the Agora Web SDK: + * - `true`: Enable. + * - `false`: (Default) Disable. + */ + enableWebSdkInteroperability(enabled: boolean): Promise { + return RtcEngine._callMethod('enableWebSdkInteroperability', { enabled }); + } + + /** + * Gets the connection state of the SDK. + */ + getConnectionState(): Promise { + return RtcEngine._callMethod('getConnectionState'); + } + + /** + * Gets the current call ID. + * + * When a user joins a channel on a client, a call ID is generated to identify the call from the client. + * Feedback methods, such as [`rate`]{@link rate} and [`complain`]{@link complain}, must be called after the call ends to submit feedback to the SDK. + * + * The [`rate`]{@link rate} and [`complain`]{@link complain} methods require the `callId` parameter retrieved from the [`getCallId`]{@link getCallId} method during a call. + * `callId` is passed as an argument into the [`rate`]{@link rate} and [`complain`]{@link complain} methods after the call ends. + * + * @returns + * Current call ID. + */ + getCallId(): Promise { + return RtcEngine._callMethod('getCallId'); + } + + /** + * Allows the user to rate a call after the call ends. + * + * @param callId ID of the call retrieved from the [`getCallId`]{@link getCallId} method. + * @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. + */ + rate(callId: string, rating: Rate, description?: string): Promise { + return RtcEngine._callMethod('rate', { callId, rating, description }); + } + + /** + * Allows a user to complain about the call quality after a call ends. + * + * @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. + */ + complain(callId: string, description: string): Promise { + return RtcEngine._callMethod('complain', { callId, description }); + } + + /** + * Sets the log files that the SDK outputs. + * + * By default, the SDK outputs five log files, `agorasdk.log`, `agorasdk_1.log`, `agorasdk_2.log`, `agorasdk_3.log`, `agorasdk_4.log`, each with a default size of 1024 KB. + * These log files are encoded in UTF-8. The SDK writes the latest logs in `agorasdk.log`. When `agorasdk.log` is full, the SDK deletes the log file with the + * earliest modification time among the other four, renames `agorasdk.log` to the name of the deleted log file, and creates a new `agorasdk.log` to record latest logs. + * The log file records all log data for the SDK’s operation. Ensure that the directory for the log file exists and is writable. + * + * **Note** + * + * Ensure that you call this method immediately after calling the `create` method, otherwise the output log may not be complete. + * + * @param filePath File path of the log file. The string of the log file is in UTF-8. The default file path is `/storage/emulated/0/Android/data/="">/files/agorasdk.log`. + */ + setLogFile(filePath: string): Promise { + return RtcEngine._callMethod('setLogFile', { filePath }); + } + + /** + * Sets the output log level of the SDK. + * + * You can use one or a combination of the filters. The log level follows the sequence of `Off`, `Critical`, `Error`, `Warning`, `Info`, and `Debug`. + * Choose a level to see the logs preceding that level. For example, if you set the log level to `Warning`, you see the logs within levels `Critical`, `Error`, and `Warning`. + * + * @param filter Sets the log filter level. + */ + setLogFilter(filter: LogFilter): Promise { + return RtcEngine._callMethod('setLogFilter', { filter }); + } + + /** + * Sets the size (KB) of a log file that the SDK outputs. + * + * By default, the SDK outputs five log files, `agorasdk.log`, `agorasdk_1.log`, `agorasdk_2.log`, `agorasdk_3.log`, `agorasdk_4.log`, each with a default size of 1024 KB. These log files are encoded in UTF-8. The SDK writes the latest logs in `agorasdk.log`. + * When `agorasdk.log` is full, the SDK deletes the log file with the earliest modification time among the other four, renames `agorasdk.log` to the name of the deleted log file, and create a new `agorasdk.log` to record latest logs. + * @param fileSizeInKBytes The size (KB) of a log file. The default value is 1024 KB. If you set `fileSizeInKByte` to 1024 KB, the SDK outputs + * at most 5 MB log files; if you set it to less than 1024 KB, the maximum size of a log file is still 1024 KB. + */ + setLogFileSize(fileSizeInKBytes: number): Promise { + return RtcEngine._callMethod('setLogFileSize', { fileSizeInKBytes }); + } + + /** + * @ignore + * Provides technical preview functionalities or special customizations by configuring the SDK with JSON options. + * + * The JSON options are not public by default. Agora is working on making commonly used JSON options public in a standard way. + * @param parameters Sets the parameter as a JSON string in the specified format. + */ + setParameters(parameters: string): Promise { + return RtcEngine._callMethod('setParameters', { parameters }); + } + + /** + * Gets the user information by passing in the user ID. + * + * After a remote user joins the channel, the SDK gets the user ID and user account of the remote user, caches them in a mapping table object ([`UserInfo`]{@link UserInfo}), and triggers the [`UserInfoUpdated`]{@link RtcEngineEvents.UserInfoUpdated} callback on the local client. + * + * After receiving the [`UserInfoUpdated`]{@link RtcEngineEvents.UserInfoUpdated} callback, you can call this method to get the user ID of the remote user from the [`UserInfo`]{@link UserInfo} object by passing in the user account. + * @param uid The user ID of the user. Ensure that you set this parameter. + */ + getUserInfoByUid(uid: number): Promise { + return RtcEngine._callMethod('getUserInfoByUid', { uid }); + } + + /** + * Gets the user information by passing in the user account. + * + * After a remote user joins the channel, the SDK gets the user ID and user account of the remote user, caches them in a mapping table object ([`UserInfo`]{@link UserInfo}), and triggers the [`UserInfoUpdated`]{@link RtcEngineEvents.UserInfoUpdated} callback on the local client. + * + * After receiving the [`UserInfoUpdated`]{@link RtcEngineEvents.UserInfoUpdated} callback, you can call this method to get the user ID of the remote user from the [`UserInfo`]{@link UserInfo} object by passing in the user account. + * @param userAccount The user account of the user. Ensure that you set this parameter. + */ + getUserInfoByUserAccount(userAccount: string): Promise { + return RtcEngine._callMethod('getUserInfoByUserAccount', { userAccount }); + } + + /** + * Joins the channel with a user account. + * + * After the user successfully joins the channel, the SDK triggers the following callbacks: + * - The local client: [`LocalUserRegistered`]{@link RtcEngineEvents.LocalUserRegistered} and [`JoinChannelSuccess`]{@link RtcEngineEvents.JoinChannelSuccess}. + * + * - 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. + * + * **Note** + * + * To ensure smooth communication, use the same parameter type to identify the user. + * For example, if a user joins the channel with a user ID, then ensure all the other users use the user ID too. The same applies to the user account. + * If a user joins the channel with the Agora Web SDK, ensure that the uid of the user is set to the same parameter type. + * @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 channelName The channel name. The maximum length of this parameter is 64 bytes. Supported character scopes are: + * - All lowercase English letters: a to z. + * - All uppercase English letters: A to Z. + * - All numeric characters: 0 to 9. + * - The space character. + * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + * @param userAccount The user account. The maximum length of this parameter is 255 bytes. + * Ensure that you set this parameter and do not set it as null. + * - All lowercase English letters: a to z. + * - All uppercase English letters: A to Z. + * - All numeric characters: 0 to 9. + * - The space character. + * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + */ + joinChannelWithUserAccount( + token: string | null, + channelName: string, + userAccount: string + ): Promise { + return RtcEngine._callMethod('joinChannelWithUserAccount', { + token, + channelName, + userAccount, + }); + } + + /** + * Registers a user account. + * + * Once registered, the user account can be used to identify the local user when the user joins the channel. + * After the user successfully registers a user account, the SDK triggers the [`LocalUserRegistered`]{@link RtcEngineEvents.LocalUserRegistered} callback on the local client, reporting the user ID and user account of the local user. + * + * To join a channel with a user account, you can choose either of the following: + * - Call this method to create a user account, and then [`joinChannelWithUserAccount`]{@link joinChannelWithUserAccount} to join the channel. + * + * - Call [`joinChannelWithUserAccount`]{@link joinChannelWithUserAccount} to join the channel. + * + * The difference between the two is that for the former, the time elapsed between calling the [`joinChannelWithUserAccount`]{@link joinChannelWithUserAccount} method and joining the channel is shorter than the latter. + * + * **Note** + * + * - Ensure that you set the `userAccount` parameter. Otherwise, this method does not take effect. + * - Ensure that the value of the `userAccount` parameter is unique in the channel. + * - To ensure smooth communication, use the same parameter type to identify the user. + * For example, if a user joins the channel with a user ID, then ensure all the other users use the user ID too. + * The same applies to the user account. If a user joins the channel with the Agora Web SDK, ensure that the uid of the user is set to the same parameter type. + * @param appId The App ID of your project. + * @param userAccount The user account. The maximum length of this parameter is 255 bytes. + * Ensure that you set this parameter and do not set it as null. Supported character scopes are: + * - All lowercase English letters: a to z. + * - All uppercase English letters: A to Z. + * - All numeric characters: 0 to 9. + * - The space character. + * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + */ + registerLocalUserAccount(appId: string, userAccount: string): Promise { + return RtcEngine._callMethod('registerLocalUserAccount', { + appId, + userAccount, + }); + } + + /** + * Adjusts the playback volume of all remote users. + * + * **Note** + * + * - This method adjusts the playback volume which is mixed volume of all remote users. + * - To mute the local audio playback, call both this method and [`adjustAudioMixingVolume`]{@link adjustAudioMixingVolume}, and set `volume` as `0`. + * + * @param volume The playback volume of all remote users. The value ranges from 0 to 400: + * - 0: Mute. + * - 100: The original volume. + * - 400: (Maximum) Four times the original volume with signal clipping protection. To avoid echoes and improve call quality, + * Agora recommends setting the value of volume between 0 and 100. If you need to set the value higher than 100, contact support@agora.io first. + */ + adjustPlaybackSignalVolume(volume: number): Promise { + return RtcEngine._callMethod('adjustPlaybackSignalVolume', { volume }); + } + + /** + * Adjusts the recording volume. + * + * @param volume Recording volume. The value ranges between 0 and 400: + * - 0: Mute. + * - 100: Original volume. + * - 400: (Maximum) Four times the original volume with signal-clipping protection. To avoid echoes and improve call quality, Agora recommends setting the value of volume between 0 and 100. + * If you need to set the value higher than 100, contact support@agora.io first. + */ + adjustRecordingSignalVolume(volume: number): Promise { + return RtcEngine._callMethod('adjustRecordingSignalVolume', { volume }); + } + + /** + * Adjusts the playback volume of a specified remote user. + * + * You can call this method as many times as necessary to adjust the playback volume of different remote users, or to repeatedly adjust the playback volume of the same remote user. + * + * **Note** + * - Call this method after joining a channel. + * - The playback volume here refers to the mixed volume of a specified remote user. + * - This method can only adjust the playback volume of one specified remote user at a time. To adjust the playback volume of different remote users, call the method as many times, once for each remote user. + * @param uid ID of the remote user. + * @param volume The playback volume of the specified remote user. The value ranges from 0 to 100: + * - 0: Mute. + * - 100: The original volume. + */ + adjustUserPlaybackSignalVolume(uid: number, volume: number): Promise { + return RtcEngine._callMethod('adjustUserPlaybackSignalVolume', { + uid, + volume, + }); + } + + /** + * Disables the audio module. + * + * **Note** + * + * - This method affects the internal engine 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: + * + * - [`enableLocalAudio`]{@link enableLocalAudio}: Whether to enable the microphone to create the local audio stream. + * + * - [`muteLocalAudioStream`]{@link muteLocalAudioStream}: Whether to publish the local audio stream. + * + * - [`muteRemoteAudioStream`]{@link muteRemoteAudioStream}: Whether to subscribe to and play the remote audio stream. + * + * - [`muteAllRemoteAudioStreams`]{@link muteAllRemoteAudioStreams}: Whether to subscribe to and play all remote audio streams. + */ + disableAudio(): Promise { + return RtcEngine._callMethod('disableAudio'); + } + + /** + * Enables the audio module. + * + * The audio module is enabled by default. + * + * **Note** + * + * - This method affects the internal engine 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: + * + * - [`enableLocalAudio`]{@link enableLocalAudio}: Whether to enable the microphone to create the local audio stream. + * + * - [`muteLocalAudioStream`]{@link muteLocalAudioStream}: Whether to publish the local audio stream. + * + * - [`muteRemoteAudioStream`]{@link muteRemoteAudioStream}: Whether to subscribe to and play the remote audio stream. + * + * - [`muteAllRemoteAudioStreams`]{@link muteAllRemoteAudioStreams}: Whether to subscribe to and play all remote audio streams. + */ + enableAudio(): Promise { + return RtcEngine._callMethod('enableAudio'); + } + + /** + * Enables the [`AudioVolumeIndication`]{@link RtcEngineEvents.AudioVolumeIndication} callback at a set time interval to + * report on which users are speaking and the speakers' volume. + * + * Once this method is enabled, the SDK returns the volume indication in the [`AudioVolumeIndication`]{@link RtcEngineEvents.AudioVolumeIndication} callback at the set time interval, + * regardless of whether any user is speaking in the channel. + * @param interval Sets the time interval between two consecutive volume indications: + * - ≤ 0: Disables the volume indication. + * - > 0: Time interval (ms) between two consecutive volume indications. Agora recommends setting interval ≥ 200 ms. + * @param smooth The smoothing factor sets the sensitivity of the audio volume indicator. The value ranges between 0 and 10. The greater the value, the more sensitive the indicator. + * 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, + * except for scenarios where the engine automatically detects the voice activity of the local user. + */ + enableAudioVolumeIndication( + interval: number, + smooth: number, + report_vad: boolean + ): Promise { + return RtcEngine._callMethod('enableAudioVolumeIndication', { + interval, + smooth, + report_vad, + }); + } + + /** + * Enables/Disables the local audio capture. + * + * The audio function is enabled by default. This method disables/re-enables the local audio function, that is, + * to stop or restart local audio capture and processing. + * + * This method does not affect receiving or playing the remote audio streams, and `enableLocalAudio(false)` is applicable to scenarios + * where the user wants to receive remote audio streams without sending any audio stream to other users in the channel. + * + * Once the local audio function is disabled or re-enabled, the SDK triggers the [`LocalAudioStateChanged`]{@link RtcEngineEvents.LocalAudioStateChanged} callback, which reports [`Stopped`]{@link AudioLocalState.Stopped} or [`Recording`]{@link AudioLocalState.Recording}. + * The SDK triggers the [`LocalAudioStateChanged`]{@link RtcEngineEvents.LocalAudioStateChanged} callback once the local audio function is disabled or re-enabled. + * + * **Note** + * + * - 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. + * + * - [`muteLocalAudioStream`]{@link muteLocalAudioStream}: Stops/Continues sending the local audio streams. + * + * @param enabled Sets whether to disable/re-enable the local audio function: + * - `true`: (Default) Re-enable the local audio function, that is, to start local audio capture and processing. + * - `false`: Disable the local audio function, that is, to stop local audio capture and processing. + */ + enableLocalAudio(enabled: boolean): Promise { + return RtcEngine._callMethod('enableLocalAudio', { enabled }); + } + + /** + * Stops/Resumes receiving all remote audio streams. + * + * @param muted Sets whether to receive/stop receiving all remote audio streams: + * - `true`: Stop receiving all remote audio streams. + * - `false`: (Default) Receive all remote audio streams. + */ + muteAllRemoteAudioStreams(muted: boolean): Promise { + return RtcEngine._callMethod('muteAllRemoteAudioStreams', { muted }); + } + + /** + * Stops/Resumes sending the local audio stream. + * A successful [`muteLocalAudioStream`]{@link muteLocalAudioStream} method call triggers the [`UserMuteAudio`]{@link RtcEngineEvents.UserMuteAudio} callback on the remote client. + * + * **Note** + * + * - When `muted` is set as ``true``, this method does not disable the microphone and thus does not affect any ongoing recording. + * - If you call [`setChannelProfile`]{@link setChannelProfile} after this method, the SDK resets whether to mute the local audio according to the channel profile and user role. + * Therefore, we recommend calling this method after the [`setChannelProfile`]{@link setChannelProfile} method. + * + * @param muted Sets whether to send/stop sending the local audio stream: + * - `true`: Stop sending the local audio stream. + * - `false`: (Default) Send the local audio stream. + */ + muteLocalAudioStream(muted: boolean): Promise { + return RtcEngine._callMethod('muteLocalAudioStream', { muted }); + } + + /** + * Stops/Resumes receiving a specified audio stream. + * + * **Note** + * + * - If you called [`muteAllRemoteAudioStreams`]{@link muteAllRemoteAudioStreams} and set `muted` as `true` to stop receiving all remote video streams, + * ensure that the [`muteAllRemoteAudioStreams`]{@link muteAllRemoteAudioStreams} method is called and set `muted` as `false` before calling this method. + * The [`muteAllRemoteAudioStreams`]{@link muteAllRemoteAudioStreams} method sets all remote audio streams, while the [`muteRemoteAudioStream`]{@link muteRemoteAudioStream} method sets a specified remote user's audio stream. + * + * @param uid ID of the specified remote user. + * @param muted Sets whether to receive/stop receiving the specified remote user's audio stream: + * - `true`: Stop receiving the specified remote user’s audio stream. + * - `false`: (Default) Receive the specified remote user’s audio stream. + */ + muteRemoteAudioStream(uid: number, muted: boolean): Promise { + return RtcEngine._callMethod('muteRemoteAudioStream', { uid, muted }); + } + + /** + * Sets the audio parameters and application scenarios. + * + * **Note** + * + * - 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. + * + * @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. + */ + setAudioProfile( + profile: AudioProfile, + scenario: AudioScenario + ): Promise { + return RtcEngine._callMethod('setAudioProfile', { profile, scenario }); + } + + /** + * Sets whether to receive all remote audio streams by default. + * + * You can call this method either before or after joining a channel. + * If you call `setDefaultMuteAllRemoteAudioStreams(true)` after joining a channel, you will not receive the audio streams of any subsequent user. + * + * **Note** + * + * If you want to resume receiving audio streams, call [`muteRemoteAudioStream(false)`]{@link muteRemoteAudioStream}, and specify the ID of the remote user that you want to subscribe to. + * To resume audio streams of multiple users, call [`muteRemoteAudioStream`]{@link muteRemoteAudioStream} as many times. + * Calling `setDefaultMuteAllRemoteAudioStreams(false)` resumes receiving audio streams of the subsequent users only. + * + * @param muted Sets whether to receive/stop receiving the remote audio streams by default: + * - `true`: Stop receiving any audio stream by default. + * - `false`: (Default) Receive all remote audio streams by default. + */ + setDefaultMuteAllRemoteAudioStreams(muted: boolean): Promise { + return RtcEngine._callMethod('setDefaultMuteAllRemoteAudioStreams', { + muted, + }); + } + + /** + * Disables the video module. + * + * You can call this method before joining a channel or during a call: + * + * - If you call this method before joining a channel, the service starts in audio mode. + * - If you call this method during a video call, the video mode switches to the audio mode. + * + * A successful call of this method triggers the [`UserEnableVideo(false)`]{@link RtcEngineEvents.UserEnableVideo} callback on the remote client. + * + * To enable the video mode, call [`enableVideo`]{@link enableVideo}. + * + * **Note** + * + * - This method affects the internal engine 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 video engine modules separately: + * + * - [`enableLocalVideo`]{@link enableLocalVideo}: Whether to enable the camera to create the local video stream. + * + * - [`muteLocalVideoStream`]{@link muteLocalVideoStream}: Whether to publish the local video stream. + * + * - [`muteRemoteVideoStream`]{@link muteRemoteVideoStream}: Whether to subscribe to and play the remote video stream. + * + * - [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams}: Whether to subscribe to and play all remote video streams. + */ + disableVideo(): Promise { + return RtcEngine._callMethod('disableVideo'); + } + + /** + * Disables/Re-enables the local video capture. + * + * This method disables or re-enables the local video capturer, and does not affect receiving the remote video stream. + * + * After you call [`enableVideo`]{@link enableVideo}, the local video capturer is enabled by default. + * You can call `enableLocalVideo(false)` to disable the local video capturer. If you want to re-enable it, + * call `enableLocalVideo(true)`. + * + * After the local video capturer is successfully disabled or re-enabled, the SDK triggers the [`UserEnableLocalVideo`]{@link RtcEngineEvents.UserEnableLocalVideo} callback on the remote client. + * + * **Note** + * + * - This method affects the internal engine and can be called after calling [`leaveChannel`]{@link leaveChannel}. + * @param enabled Sets whether to disable/re-enable the local video, including the capturer, renderer, and sender: + * - `true`: (Default) Re-enable the local video. + * - `false`: Disable the local video. Once the local video is disabled, the remote users can no longer receive the video stream of this user, while this user can still receive the video streams of other remote users. + * When you set `enabled` as `false`, this method does not require a local camera. + */ + enableLocalVideo(enabled: boolean): Promise { + return RtcEngine._callMethod('enableLocalVideo', { enabled }); + } + + /** + * Enables the video module. + * + * You can call this method either before joining a channel or during a call: + * + * - If you call this method before joining a channel, + * the service starts in the video mode. + * - If you call this method during an audio call, the audio mode switches to the video mode. + * + * A successful call of this method triggers the [`UserEnableVideo(true)`]{@link RtcEngineEvents.UserEnableVideo} callback on the remote client. + * + * To disable the video, call the [`disableVideo`]{@link disableVideo} method. + * + * **Note** + * + * - This method affects the internal engine and can be called after calling the [`leaveChannel`]{@link leaveChannel} method. 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 video engine modules separately: + * + * - [`enableLocalVideo`]{@link enableLocalVideo}: Whether to enable the camera to create the local video stream. + * + * - [`muteLocalVideoStream`]{@link muteLocalVideoStream}: Whether to publish the local video stream. + * + * - [`muteRemoteVideoStream`]{@link muteRemoteVideoStream}: Whether to subscribe to and play the remote video stream. + * + * - [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams}: Whether to subscribe to and play all remote video streams. + */ + enableVideo(): Promise { + return RtcEngine._callMethod('enableVideo'); + } + + /** + * Stops/Resumes receiving all remote video streams. + * + * @param muted Sets whether to receive/stop receiving all remote video streams: + * - `true`: Stop receiving all remote video streams. + * - `false`: (Default) Receive all remote video streams. + */ + muteAllRemoteVideoStreams(muted: boolean): Promise { + return RtcEngine._callMethod('muteAllRemoteVideoStreams', { muted }); + } + + /** + * Stops/Resumes sending the local video stream. + * + * A successful [`muteLocalVideoStream`]{@link muteLocalVideoStream} method call triggers the [`UserMuteVideo`]{@link RtcEngineEvents.UserMuteVideo} callback on the remote client. + * + * **Note** + * + * - When you set `muted` as `true`, this method does not disable the camera and thus does not affect the retrieval of the local video streams. + * This method responds faster than calling [`enableLocalVideo`]{@link enableLocalVideo} and set `muted` as `false`, which controls sending the local video stream. + * + * - If you call [`setChannelProfile`]{@link setChannelProfile} after this method, the SDK resets whether to mute the local video according to the channel profile and user role. + * Therefore, we recommend calling this method after the [`setChannelProfile`]{@link setChannelProfile} method. + * + * @param muted Sets whether to send/stop sending the local video stream: + * - `true`: Stop sending the local video stream. + * - `false`: (Default) Send the local video stream. + */ + muteLocalVideoStream(muted: boolean): Promise { + return RtcEngine._callMethod('muteLocalVideoStream', { muted }); + } + + /** + * Stops/Resumes receiving a specified remote user's video stream. + * + * **Note** + * + * If you call [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams} and set `muted` as `true` to stop receiving all remote video streams, + * ensure that the [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams} method is called and set `muted` as `false` before calling this method. The [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams} method sets all remote streams, while this method sets a specified remote user's stream. + * + * @param uid User ID of the specified remote user. + * @param muted Sets whether to receive/stop receiving a specified remote user's video stream: + * - `true`: Stop receiving a specified remote user’s video stream. + * - `false`: (Default) Receive a specified remote user’s video stream. + */ + muteRemoteVideoStream(uid: number, muted: boolean): Promise { + return RtcEngine._callMethod('muteRemoteVideoStream', { uid, muted }); + } + + /** + * Enables/Disables image enhancement and sets the options. + * + * **Note** + * + * - Call this method after calling [`enableVideo`]{@link enableVideo}. + * - On Android,this method applies to Android 4.4 or later. + * + * @param enabled Sets whether to enable image enhancement: + * - `true`: Enable image enhancement. + * - `false`: Disable image enhancement. + * @param options The image enhancement options. + */ + setBeautyEffectOptions( + enabled: boolean, + options: BeautyOptions + ): Promise { + return RtcEngine._callMethod('setBeautyEffectOptions', { + enabled, + options, + }); + } + + /** + * Sets whether to receive all remote video streams by default. + * + * You can call this method either before or after joining a channel. + * If you call `setDefaultMuteAllRemoteVideoStreams(true)` after joining a channel, you will not receive the video stream of any subsequent user. + * + * **Note** + * + * If you want to resume receiving video streams, call [`muteRemoteVideoStream(false)`]{@link muteRemoteVideoStream}, and specify the ID of the remote user that you want to subscribe to. + * To resume receiving video streams of multiple users, call [`muteRemoteVideoStream`]{@link muteRemoteVideoStream} as many times. Calling `setDefaultMuteAllRemoteVideoStreams(false)` resumes receiving video streams of the subsequent users only. + * + * @param muted Sets whether to receive/stop receiving all remote video streams by default: + * - `true`: Stop receiving any remote video stream by default. + * - `false`: (Default) Receive all remote video streams by default. + */ + setDefaultMuteAllRemoteVideoStreams(muted: boolean): Promise { + return RtcEngine._callMethod('setDefaultMuteAllRemoteVideoStreams', { + muted, + }); + } + + /** + * Sets the video encoder configuration. + * + * Each video encoder configuration corresponds to a set of video parameters, including the resolution, frame rate, bitrate, and video orientation. + * The parameters specified in this method are the maximum values under ideal network conditions. + * If the video engine cannot render the video using the specified parameters due to poor network conditions, the parameters further down the list are considered until a successful configuration is found. + * If you do not set the video encoder configuration after joining the channel, you can call this method before calling [`enableVideo`]{@link enableVideo} to reduce the render time of the first video frame. + * + * @param config The local video encoder configuration. + */ + setVideoEncoderConfiguration( + config: VideoEncoderConfiguration + ): Promise { + return RtcEngine._callMethod('setVideoEncoderConfiguration', { config }); + } + + /** + * Starts the local video preview before joining a channel. + * + * Before calling this method, you must call the [`enableVideo`]{@link enableVideo} method to enable the video. + * + * **Note** + * + * - By default, the local preview enables the mirror mode. + * - Once you call this method to start the local video preview, if you leave the channel by calling [`leaveChannel`]{@link leaveChannel}, + * the local video preview remains until you call [`stopPreview`]{@link stopPreview} to disable it. + */ + startPreview(): Promise { + return RtcEngine._callMethod('startPreview'); + } + + /** + * Stops the local video preview and the video. + */ + stopPreview(): Promise { + return RtcEngine._callMethod('stopPreview'); + } + + /** + * Adjusts the volume of audio mixing for local playback. + * + * **Note** + * + * Call this method when you are in a channel. + * + * @param volume Audio mixing volume for local playback. The value ranges between 0 and 100 (default). + */ + adjustAudioMixingPlayoutVolume(volume: number): Promise { + return RtcEngine._callMethod('adjustAudioMixingPlayoutVolume', { volume }); + } + + /** + * Adjusts the volume of audio mixing for publishing (sending to other users). + * + * **Note** + * + * Call this method when you are in a channel. + * + * @param volume Audio mixing volume for publishing. The value ranges between 0 and 100 (default). + */ + adjustAudioMixingPublishVolume(volume: number): Promise { + return RtcEngine._callMethod('adjustAudioMixingPublishVolume', { volume }); + } + + /** + * Adjusts the volume of audio mixing. + * + * **Note** + * + * - Call this method when you are in a channel. + * + * - Calling this method does not affect the volume of the audio effect file playback invoked by the [`playEffect`]{@link playEffect} method. + * + * @param volume Audio mixing volume. The value ranges between 0 and 100 (default). + */ + adjustAudioMixingVolume(volume: number): Promise { + return RtcEngine._callMethod('adjustAudioMixingVolume', { volume }); + } + + /** + * Gets the playback position (ms) of the music file. + * + * **Note** + * + * Call this method when you are in a channel. + * + * @returns + * - Returns the current playback position of the audio mixing, if the method call is successful. + * - < 0: Failure. + */ + getAudioMixingCurrentPosition(): Promise { + return RtcEngine._callMethod('getAudioMixingCurrentPosition'); + } + + /** + * Gets the duration (ms) of the music file. + * + * **Note** + * + * Call this method when you are in a channel. + * + * @returns + * - Returns the audio mixing duration, if the method call is successful. + * - < 0: Failure. + */ + getAudioMixingDuration(): Promise { + return RtcEngine._callMethod('getAudioMixingDuration'); + } + + /** + * Gets the audio mixing volume for local playback. + * + * This method helps troubleshoot audio volume related issues. + * + * @returns + * - Returns the audio mixing volume for local playback, if the method call is successful. The value range is [0,100]. + * - < 0: Failure. + */ + getAudioMixingPlayoutVolume(): Promise { + return RtcEngine._callMethod('getAudioMixingPlayoutVolume'); + } + + /** + * Gets the audio mixing volume for publishing. + * + * This method helps troubleshoot audio volume related issues. + * + * @returns + * - Returns the audio mixing volume for publishing, if the method call is successful. The value range is [0,100]. + * - < 0: Failure. + */ + getAudioMixingPublishVolume(): Promise { + return RtcEngine._callMethod('getAudioMixingPublishVolume'); + } + + /** + * Pauses playing and mixing the music file. + * + * Call this method when you are in a channel. + */ + pauseAudioMixing(): Promise { + return RtcEngine._callMethod('pauseAudioMixing'); + } + + /** + * Resumes playing and mixing the music file. + * + * Call this method when you are in a channel. + */ + resumeAudioMixing(): Promise { + return RtcEngine._callMethod('resumeAudioMixing'); + } + + /** + * Sets the pitch of the local music file. + * + * When a local music file is mixed with a local human voice, call this method to + * set the pitch of the local music file only. + * + * **Note** + * + * Call this method after calling [`startAudioMixing`]{@link startAudioMixing}. + * + * @param pitch Sets the pitch of the local music file by chromatic scale. + * The default value is 0, which means keep the original pitch. + * The value ranges from -12 to 12, and the pitch value between consecutive values is a chromatic value. + * The greater the absolute value of this parameter, the higher or lower the pitch of the local music file. + */ + setAudioMixingPitch(pitch: number): Promise { + return RtcEngine._callMethod('setAudioMixingPitch', { pitch }); + } + + /** + * Sets the playback position (ms) of the music file to a different starting position (the default plays from the beginning). + * @param pos The playback starting position (ms) of the audio mixing file. + */ + setAudioMixingPosition(pos: number): Promise { + return RtcEngine._callMethod('setAudioMixingPosition', { pos }); + } + + /** + * Starts playing and mixing the music file. + * + * This method mixes the specified local or online audio file with the audio stream from the microphone, + * or replaces the microphone’s audio stream with the specified local or remote audio file. + * You can choose whether the other user can hear the local audio playback and specify the number of playback loops. + * When the audio mixing file playback finishes after calling this method, the SDK triggers the [`AudioMixingFinished`]{@link RtcEngineEvents.AudioMixingFinished} callback. + * + * A successful call of this method triggers the [`AudioMixingStateChanged`]{@link RtcEngineEvents.AudioMixingStateChanged} callback and reports [`Playing`]{@link AudioMixingStateCode.Playing} on the local client. + * + * When the audio mixing file playback finishes, the SDK triggers the [`AudioMixingStateChanged`]{@link RtcEngineEvents.AudioMixingStateChanged} callback and reports [`Stopped`]{@link AudioMixingStateCode.Stopped} on the local client. + * + * **Note** + * + * - To use this method on Android, ensure that the Android device is v4.2 or later, and the API version is v16 or later. + * + * - Call this method when you are in the channel, otherwise it may cause issues. + * + * - If you want to play an online music file, ensure that the time interval between calling this method is more than 100 ms, or the [`TooFrequentCall(702)`]{@link AudioMixingErrorCode.TooFrequentCall} error occurs. + * + * - If you want to play an online music file, Agora does not recommend using the redirected URL address. Some Android devices may fail to open a redirected URL address. + * + * - If the local audio mixing file does not exist, or if the SDK does not support the file format or cannot access the music file URL, the SDK returns [`CanNotOpen(701)`]{@link AudioMixingErrorCode.CanNotOpen}. + * + * - If you call this method on an emulator, only the MP3 file format is supported. + * + * @param filePath Specifies the absolute path (including the suffixes of the filename) of the local or online audio file to be mixed. For example, `/sdcard/emulated/0/audio.mp4`. + * Supported audio formats: mp3, mp4, m4a, aac, 3gp, mkv, and wav. + * - If the path begins with /assets/, the audio file is in the /assets/ directory. + * - Otherwise, the audio file is in the absolute path. + * @param loopback Sets which user can hear the audio mixing: + * - `true`: Only the local user can hear the audio mixing. + * - `false`: Both users can hear the audio mixing. + * @param replace Sets the audio mixing content: + * - `true`: Only publish the specified audio file; the audio stream from the microphone is not published. + * - `false`: The local audio file is mixed with the audio stream from the microphone. + * @param cycle Sets the number of playback loops: + * - Positive integer: Number of playback loops. + * - -1: Infinite playback loops. + */ + startAudioMixing( + filePath: string, + loopback: boolean, + replace: boolean, + cycle: number + ): Promise { + return RtcEngine._callMethod('startAudioMixing', { + filePath, + loopback, + replace, + cycle, + }); + } + + /** + * Stops playing or mixing the music file. + * + * Call this method when you are in a channel. + */ + stopAudioMixing(): Promise { + return RtcEngine._callMethod('stopAudioMixing'); + } + + /** + * Gets the volume of the audio effects. + * + * The value ranges between 0.0 and 100.0. + * + * @returns + * - Returns the volume, if the method call is successful. + * - < 0: Failure. + */ + getEffectsVolume(): Promise { + return RtcEngine._callMethod('getEffectsVolume'); + } + + /** + * Pauses all audio effects. + */ + pauseAllEffects(): Promise { + return RtcEngine._callMethod('pauseAllEffects'); + } + + /** + * Pauses a specified audio effect. + * @param soundId ID of the audio effect. Each audio effect has a unique ID. + */ + pauseEffect(soundId: number): Promise { + return RtcEngine._callMethod('pauseEffect', { soundId }); + } + + /** + * Plays a specified local or online audio effect file. + * + * With this method, you can set the loop count, pitch, pan, and gain of the audio effect file and whether the remote user can hear the audio effect. + * To play multiple audio effect files simultaneously, call this method multiple times with different `soundId` and `filePath`. + * We recommend playing no more than three audio effect files at the same time. + * When the audio effect file playback is finished, the SDK triggers the [`AudioEffectFinished`]{@link RtcEngineEvents.AudioEffectFinished} callback. + * + * @param soundId ID of the specified audio effect. Each audio effect has a unique ID. If you preloaded the audio effect into the memory + * through the [`preloadEffect`]{@link preloadEffect} method, ensure that the `soundID` value is set to the same value as in the [`preloadEffect`]{@link preloadEffect} method. + * + * @param filePath The absolute file path (including the suffixes of the filename) of the audio effect file or + * the URL of the online audio effect file. For example, `/sdcard/emulated/0/audio.mp4`. + * + * Supported audio formats: mp3, mp4, m4a, aac. 3gp, mkv, and wav. + * @param loopCount Sets the number of times the audio effect loops: + * - 0: Plays the audio effect once. + * - 1: Plays the audio effect twice. + * - -1: Plays the audio effect in a loop indefinitely, until you call the [`stopEffect`]{@link stopEffect} or [`stopAllEffects`]{@link stopAllEffects} method. + * @param pitch Sets the pitch of the audio effect. The value ranges between 0.5 and 2. + * The default value is 1 (no change to the pitch). The lower the value, the lower the pitch. + * @param pan Sets the spatial position of the audio effect. The value ranges between -1.0 and 1.0. + * - 0.0: The audio effect shows ahead. + * - 1.0: The audio effect shows on the right. + * - -1.0: The audio effect shows on the left. + * @param gain Sets the volume of the audio effect. The value ranges between 0.0 and 100,0. + * The default value is 100.0. The lower the value, the lower the volume of the audio effect. + * @param publish Set whether to publish the specified audio effect to the remote stream: + * - `true`: The locally played audio effect is published to the Agora Cloud and the remote users can hear it. + * - `false`: The locally played audio effect is not published to the Agora Cloud and the remote users cannot hear it. + */ + playEffect( + soundId: number, + filePath: string, + loopCount: number, + pitch: number, + pan: number, + gain: number, + publish: Boolean + ): Promise { + return RtcEngine._callMethod('playEffect', { + soundId, + filePath, + loopCount, + pitch, + pan, + gain, + publish, + }); + } + + /** + * Preloads a specified audio effect file into the memory. + * + * Supported audio formats: mp3, aac, m4a, 3gp, wav. + * + * **Note** + * - This method does not support online audio effect files. + * + * - To ensure smooth communication, limit the size of the audio effect file. + * We recommend using this method to preload the audio effect before calling [`joinChannel`]{@link joinChannel}. + * + * @param soundId ID of the audio effect. Each audio effect has a unique ID. + * @param filePath Absolute path of the audio effect file. + */ + preloadEffect(soundId: number, filePath: string): Promise { + return RtcEngine._callMethod('preloadEffect', { soundId, filePath }); + } + + /** + * Resumes playing all audio effects. + */ + resumeAllEffects(): Promise { + return RtcEngine._callMethod('resumeAllEffects'); + } + + /** + * Resumes playing a specified audio effect. + * @param soundId ID of the audio effect. Each audio effect has a unique ID. + */ + resumeEffect(soundId: number): Promise { + return RtcEngine._callMethod('resumeEffect', { soundId }); + } + + /** + * Sets the volume of the audio effects. + * @param volume Volume of the audio effects. The value ranges between 0.0 and 100.0 (default). + */ + setEffectsVolume(volume: number): Promise { + return RtcEngine._callMethod('setEffectsVolume', { volume }); + } + + /** + * Sets the volume of a specified audio effect. + * @param soundId ID of the audio effect. Each audio effect has a unique ID. + * @param volume Volume of the audio effect. The value ranges between 0.0 and 100.0 (default). + */ + setVolumeOfEffect(soundId: number, volume: number): Promise { + return RtcEngine._callMethod('setVolumeOfEffect', { soundId, volume }); + } + + /** + * Stops playing all audio effects. + */ + stopAllEffects(): Promise { + return RtcEngine._callMethod('stopAllEffects'); + } + + /** + * Stops playing a specified audio effect. + * + * **Note** + * + * If you preloaded the audio effect into the memory through the [`preloadEffect`]{@link preloadEffect} method, + * ensure that the `soundID` value is set to the same value as in the [`preloadEffect`]{@link preloadEffect} method. + * + * @param soundId ID of the specified audio effect. Each audio effect has a unique ID. + */ + stopEffect(soundId: number): Promise { + return RtcEngine._callMethod('stopEffect', { soundId }); + } + + /** + * Releases a specified preloaded audio effect from the memory. + * @param soundId ID of the audio effect. Each audio effect has a unique ID. + */ + unloadEffect(soundId: number): Promise { + return RtcEngine._callMethod('unloadEffect', { soundId }); + } + + /** + * Sets the local voice changer option. + * + * **Note** + * + * Do not use this method together with [`setLocalVoiceReverbPreset`]{@link setLocalVoiceReverbPreset}, or the method called earlier does not take effect. + * + * @param voiceChanger The local voice changer option. + */ + setLocalVoiceChanger(voiceChanger: AudioVoiceChanger): Promise { + return RtcEngine._callMethod('setLocalVoiceChanger', { voiceChanger }); + } + + /** + * Sets the local voice equalization effect. + * + * @param bandFrequency Sets the band frequency. The value ranges between 0 and 9; representing the respective 10-band center frequencies of the voice effects, including 31, 62, 125, 500, 1k, 2k, 4k, 8k, and 16k Hz. + * + * @param bandGain Sets the gain of each band (dB). The value ranges between -15 and 15. The default value is 0. + */ + setLocalVoiceEqualization( + bandFrequency: AudioEqualizationBandFrequency, + bandGain: number + ): Promise { + return RtcEngine._callMethod('setLocalVoiceEqualization', { + bandFrequency, + bandGain, + }); + } + + /** + * Changes the voice pitch of the local speaker. + * @param pitch Sets the voice pitch. The value ranges between 0.5 and 2.0. + * The lower the value, the lower the voice pitch. The default value is 1.0 (no change to the local voice pitch). + */ + setLocalVoicePitch(pitch: number): Promise { + return RtcEngine._callMethod('setLocalVoicePitch', { pitch }); + } + + /** + * Sets the local voice reverberation. + * + * **Note** + * + * Adds the [`setLocalVoiceReverbPreset`]{@link setLocalVoiceReverbPreset} method, a more user-friendly method for setting the + * local voice reverberation. You can use this method to set the local reverberation effect, + * such as Popular, R&B, Rock, Hip-hop, and more. + * + * @param reverbKey The reverberation key: [`AudioReverbType`]{@link AudioReverbType} + * + * @param value The local voice reverberation value. + */ + setLocalVoiceReverb( + reverbKey: AudioReverbType, + value: number + ): Promise { + return RtcEngine._callMethod('setLocalVoiceReverb', { reverbKey, value }); + } + + /** + * Sets the preset local voice reverberation effect. + * + * **Note** + * + * - Do not use this method together with [`setLocalVoiceReverb`]{@link setLocalVoiceReverb}. + * + * - Do not use this method together with [`setLocalVoiceChanger`]{@link setLocalVoiceChanger}, or the method called earlier does not take effect. + * + * @param preset The local voice reverberation preset. + */ + setLocalVoiceReverbPreset(preset: AudioReverbPreset): Promise { + return RtcEngine._callMethod('setLocalVoiceReverbPreset', { preset }); + } + + /** + * Enables/Disables stereo panning for remote users. + * + * Ensure that you call this method before calling [`joinChannel`]{@link joinChannel} to enable stereo panning for remote users so that + * the local user can track the position of a remote user by calling [`setRemoteVoicePosition`]{@link setRemoteVoicePosition}. + * + * @param enabled Sets whether to enable stereo panning for remote users: + * - `true`: Enable stereo panning. + * - `false`: Disable stereo panning. + */ + enableSoundPositionIndication(enabled: boolean): Promise { + return RtcEngine._callMethod('enableSoundPositionIndication', { enabled }); + } + + /** + * Sets the sound position of a remote user. + * + * When the local user calls this method to set the sound position of a remote user, + * the sound difference between the left and right channels allows the local user to track the real-time + * position of the remote user, creating a real sense of space. + * This method applies to massively multiplayer online games, such as Battle Royale games. + * + * **Note** + * + * - For this method to work, enable stereo panning for remote users by calling the [`enableSoundPositionIndication`]{@link enableSoundPositionIndication} method before joining a channel. + * + * - This method requires hardware support. For the best sound positioning, we recommend using a stereo headset. + * + * @param uid The ID of the remote user. + * @param pan The sound position of the remote user. + * The value ranges from -1.0 to 1.0: + * - 0.0: The remote sound comes from the front. + * - -1.0: The remote sound comes from the left. + * - 1.0: The remote sound comes from the right. + * @param gain Gain of the remote user. The value ranges from 0.0 to 100.0. + * The default value is 100.0 (the original gain of the remote user). The smaller the value, the less the gain. + */ + setRemoteVoicePosition( + uid: number, + pan: number, + gain: number + ): Promise { + return RtcEngine._callMethod('setRemoteVoicePosition', { uid, pan, gain }); + } + + /** + * Publishes the local stream to the CDN. + * + * 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. + * + * **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. + * 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`, 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. + */ + addPublishStreamUrl(url: string, transcodingEnabled: boolean): Promise { + return RtcEngine._callMethod('addPublishStreamUrl', { + url, + transcodingEnabled, + }); + } + + /** + * Removes an RTMP stream from the CDN. + * + * This method removes the RTMP URL address (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. + * The URL address must not contain special characters, such as Chinese language characters. + */ + removePublishStreamUrl(url: string): Promise { + return RtcEngine._callMethod('removePublishStreamUrl', { url }); + } + + /** + * Sets the video layout and audio settings for CDN live. + * + * The SDK triggers the [`TranscodingUpdated`]{@link RtcEngineEvents.TranscodingUpdated} callback when you call this method to update the [`LiveTranscoding`]{@link LiveTranscoding} class. + * If you call this method to set the [`LiveTranscoding`]{@link LiveTranscoding} class for the first time, + * the SDK does not trigger the [`TranscodingUpdated`]{@link RtcEngineEvents.TranscodingUpdated} callback. + * + * **Note** + * + * - This method applies to [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} only. + * - 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}. + * + * @param transcoding Sets the CDN live audio/video transcoding settings. + */ + setLiveTranscoding(transcoding: LiveTranscoding): Promise { + return RtcEngine._callMethod('setLiveTranscoding', { transcoding }); + } + + /** + * Starts to relay media streams across channels. + * + * After a successful method call, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcEngineEvents.ChannelMediaRelayStateChanged} and [`ChannelMediaRelayEvent`]{@link RtcEngineEvents.ChannelMediaRelayEvent} callbacks, and these + * callbacks return the state and events of the media stream relay. + * + * If the [`ChannelMediaRelayStateChanged`]{@link RtcEngineEvents.ChannelMediaRelayStateChanged} callback returns [`Running(2)`]{@link ChannelMediaRelayState.Running} and [`None(0)`]{@link ChannelMediaRelayError.None}, + * and the [`ChannelMediaRelayEvent`]{@link RtcEngineEvents.ChannelMediaRelayEvent} callback returns [`SentToDestinationChannel(4)`]{@link ChannelMediaRelayEvent.SentToDestinationChannel}, the SDK starts relaying media streams between the original and the destination channel. + * + * If the [`ChannelMediaRelayStateChanged`]{@link RtcEngineEvents.ChannelMediaRelayStateChanged} callback returns [`Failure(3)`]{@link ChannelMediaRelayState.Failure}, an exception occurs during the media stream relay. + * + * **Note** + * + * - Contact sales-us@agora.io before implementing this function. + * - We do not support string user accounts in this API. + * - Call this method after the [`joinChannel`]{@link joinChannel} method. + * - This method takes effect only when you are a [`Broadcaster`]{@link ClientRole.Broadcaster} + * in a [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} channel. + * - After a successful method call, if you want to call this method again, ensure that you call [`stopChannelMediaRelay`]{@link stopChannelMediaRelay} to quit the current relay. + * + * @param channelMediaRelayConfiguration The configuration of the media stream relay. + */ + startChannelMediaRelay( + channelMediaRelayConfiguration: ChannelMediaRelayConfiguration + ): Promise { + return RtcEngine._callMethod('startChannelMediaRelay', { + channelMediaRelayConfiguration, + }); + } + + /** + * Stops the media stream relay. + * + * Once the relay stops, the host quits all the destination channels. + * After a successful method call, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcEngineEvents.ChannelMediaRelayStateChanged} callback. + * If the callback returns [`Idle(0)`]{@link ChannelMediaRelayState.Idle} and [`None(0)`]{@link ChannelMediaRelayError.None}, the host successfully stops the relay. + * + * **Note** + * + * If the method call fails, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcEngineEvents.ChannelMediaRelayStateChanged} callback with the [`ServerNoResponse(2)`]{@link ChannelMediaRelayError.ServerNoResponse} + * or [`ServerConnectionLost(8)`]{@link ChannelMediaRelayError.ServerConnectionLost} state code. + * You can leave the channel by calling [`leaveChannel`]{@link leaveChannel}, and the media stream relay automatically stops. + */ + stopChannelMediaRelay(): Promise { + return RtcEngine._callMethod('stopChannelMediaRelay'); + } + + /** + * Updates the channels for media relay. + * + * After the channel media relay starts, if you want to relay the media stream to more channels, + * or leave the current relay channel, you can call [`updateChannelMediaRelay`]{@link updateChannelMediaRelay}. + * + * After a successful method call, the SDK triggers the [`ChannelMediaRelayEvent`]{@link RtcEngineEvents.ChannelMediaRelayEvent} callback with the [`UpdateDestinationChannel(7)`]{@link ChannelMediaRelayEvent.UpdateDestinationChannel} state code. + * + * **Note** + * + * - Call this method after the [`startChannelMediaRelay`]{@link startChannelMediaRelay} method to update the destination channel. + * + * - This method supports adding at most four destination channels in the relay. If there are already four destination channels in the relay. + * @param channelMediaRelayConfiguration The media stream relay configuration + */ + updateChannelMediaRelay( + channelMediaRelayConfiguration: ChannelMediaRelayConfiguration + ): Promise { + return RtcEngine._callMethod('updateChannelMediaRelay', { + channelMediaRelayConfiguration, + }); + } + + /** + * Checks whether the speakerphone is enabled. + * + * @returns + * - `true`: The speakerphone is enabled, and the audio plays from the speakerphone. + * - `false`: The speakerphone is not enabled, and the audio plays from devices other than the speakerphone. For example, the headset or earpiece. + */ + isSpeakerphoneEnabled(): Promise { + return RtcEngine._callMethod('isSpeakerphoneEnabled'); + } + + /** + * Sets the default audio playback route. + * + * This method sets whether the received audio is routed to the earpiece or speakerphone + * by default before joining a channel. If a user does not call this method, + * the audio is routed to the earpiece by default. If you need to change the default audio route after + * joining a channel, call [`setEnableSpeakerphone`]{@link setEnableSpeakerphone}. + * + * The default audio route for each scenario: + * - In the [`Communication`]{@link ChannelProfile.Communication} profile: + * + * - For a voice call, the default audio route is the earpiece. + * - For a video call, the default audio route is the speaker. If the user disables the video + * using [`disableVideo`]{@link disableVideo}, or [`muteLocalVideoStream`]{@link muteLocalVideoStream} and [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams}, the default audio route automatically switches back to the earpiece. + * + * - In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile: The default audio route is the speaker. + * + * **Note** + * + * - This method applies to the [`Communication`]{@link ChannelProfile.Communication} profile only. + * - Call this method before the user joins a channel. + * @param defaultToSpeaker Sets the default audio route: + * - `true`: Route the audio to the speaker. If the playback device connects to the earpiece or Bluetooth, the audio cannot be routed to the earpiece. + * - `false`: (Default) Route the audio to the earpiece. If a headset is plugged in, the audio is routed to the headset. + */ + setDefaultAudioRoutetoSpeakerphone(defaultToSpeaker: boolean): Promise { + return RtcEngine._callMethod('setDefaultAudioRoutetoSpeakerphone', { + defaultToSpeaker, + }); + } + + /** + * Enables/Disables the audio playback route to the speakerphone. + * + * This method sets whether the audio is routed to the speakerphone or earpiece. + * After calling this method, the SDK returns the [`AudioRouteChanged`]{@link RtcEngineEvents.AudioRouteChanged} callback to indicate the changes. + * + * **Note** + * + * - Ensure that you have successfully called [`joinChannel`]{@link joinChannel} before calling this method. + * + * - This method is invalid for audience users in the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile. + * + * @param enabled Sets whether to route the audio to the speakerphone or earpiece: + * - `true`: Route the audio 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 { + return RtcEngine._callMethod('setEnableSpeakerphone', { enabled }); + } + + /** + * Enables in-ear monitoring. + * @param enabled Sets whether to enable/disable in-ear monitoring: + * - `true`: Enable. + * - `false`: (Default) Disable. + */ + enableInEarMonitoring(enabled: boolean): Promise { + return RtcEngine._callMethod('enableInEarMonitoring', { enabled }); + } + + /** + * Sets the volume of the in-ear monitor. + * @param volume Sets the volume of the in-ear monitor. The value ranges between 0 and 100 (default). + */ + setInEarMonitoringVolume(volume: number): Promise { + return RtcEngine._callMethod('setInEarMonitoringVolume', { volume }); + } + + /** + * Enables/Disables the dual video stream mode. + * + * If dual-stream mode is enabled, the receiver can choose to receive the high stream (high-resolution high-bitrate video stream) or + * low stream (low-resolution low-bitrate video stream) video. + * + * @param enabled Sets the stream mode: + * - `true`: Dual-stream mode. + * - `false`: (Default) Single-stream mode. + */ + enableDualStreamMode(enabled: boolean): Promise { + return RtcEngine._callMethod('enableDualStreamMode', { enabled }); + } + + /** + * Sets the default video-stream type of the remotely subscribed video stream + * when the remote user sends dual streams. + * + * @param streamType Sets the default video-stream type. + */ + setRemoteDefaultVideoStreamType(streamType: VideoStreamType): Promise { + return RtcEngine._callMethod('setRemoteDefaultVideoStreamType', { + streamType, + }); + } + + /** + * Sets the stream type of the remote video. + * + * Under limited network conditions, if the publisher has not disabled the + * dual-stream mode using [`enableDualStreamMode(false)`]{@link RtcEngine.enableDualStreamMode}, the receiver can choose to receive + * either the high-video stream (the high resolution, and high bitrate video stream) or the low-video stream (the low resolution, and low bitrate video stream). + * + * By default, users receive the high-video stream. Call this method if you want to switch to the low-video stream. This method allows the app to adjust the corresponding video stream type + * based on the size of the video window to reduce the bandwidth and resources. + * + * The aspect ratio of the low-video stream is the same as the high-video stream. Once the resolution of the high-video stream is set, + * the system automatically sets the resolution, frame rate, and bitrate of the low-video stream. + * + * The SDK reports the result of calling this method in the [`ApiCallExecuted`]{@link RtcEngineEvents.ApiCallExecuted} callback. + * + * @param uid ID of the remote user sending the video stream. + * @param streamType Sets the video-stream type. + */ + setRemoteVideoStreamType( + uid: number, + streamType: VideoStreamType + ): Promise { + return RtcEngine._callMethod('setRemoteVideoStreamType', { + uid, + streamType, + }); + } + + /** + * Sets the fallback option for the locally published video stream based on the network conditions. + * + * If `option` is set as [`AudioOnly(2)`]{@link StreamFallbackOptions.AudioOnly}, the SDK will: + * + * - Disable the upstream video but enable audio only when the network conditions deteriorate and cannot support both video and audio. + * + * - Re-enable the video when the network conditions improve. + * + * When the locally published video stream falls back to audio only or when the audio-only stream + * switches back to the video, the SDK triggers the [`LocalPublishFallbackToAudioOnly`]{@link RtcEngineEvents.LocalPublishFallbackToAudioOnly}. + * + * **Note** + * + * Agora does not recommend using this method for CDN live streaming, because the remote CDN live user will have a noticeable lag when the locally published video stream falls back to audio only. + * @param option Sets the fallback option for the locally published video stream. + */ + setLocalPublishFallbackOption(option: StreamFallbackOptions): Promise { + return RtcEngine._callMethod('setLocalPublishFallbackOption', { option }); + } + + /** + * Sets the fallback option for the remotely subscribed video stream based on the network conditions. + * + * If `option` is set as [`AudioOnly(2)`]{@link StreamFallbackOptions.AudioOnly}, the SDK automatically switches + * the video from a high-stream to a low-stream, or disables the video when the downlink network condition cannot support + * both audio and video to guarantee the quality of the audio. + * The SDK monitors the network quality and restores the video stream when the network conditions improve. + * When the remotely subscribed video stream falls back to audio only, or the audio-only stream switches back to the video, + * the SDK triggers the [`RemoteSubscribeFallbackToAudioOnly`]{@link RtcEngineEvents.RemoteSubscribeFallbackToAudioOnly} callback. + * + * @param option Sets the fallback option for the remotely subscribed video stream. + */ + setRemoteSubscribeFallbackOption( + option: StreamFallbackOptions + ): Promise { + return RtcEngine._callMethod('setRemoteSubscribeFallbackOption', { + option, + }); + } + + /** + * Sets the priority of a remote user's media stream. + * + * Use this method with the [`setRemoteSubscribeFallbackOption`]{@link setRemoteSubscribeFallbackOption} method. + * If the fallback function is enabled for a subscribed stream, the SDK ensures the high-priority user gets the best possible stream quality. + * + * **Note** + * + * The Agora SDK supports setting `userPriority` as high for one user only. + * + * @param uid The ID of the remote user. + * @param userPriority The priority of the remote user. + */ + setRemoteUserPriority( + uid: number, + userPriority: UserPriority + ): Promise { + return RtcEngine._callMethod('setRemoteUserPriority', { + uid, + userPriority, + }); + } + + /** + * Disables the network connection quality test. + */ + disableLastmileTest(): Promise { + return RtcEngine._callMethod('disableLastmileTest'); + } + + /** + * Enables the network connection quality test. + * + * This method tests the quality of the users' network connections and is disabled by default. + * + * Before users join a channel or before an audience switches to a host, call this method to check the + * uplink network quality. This method consumes additional network traffic, which may affect the communication quality. + * Call [`disableLastmileTest`]{@link disableLastmileTest} to disable this test after receiving the [`LastmileQuality`]{@link RtcEngineEvents.LastmileQuality} callback, + * and before the user joins a channel or switches the user role. + * + * **Note** + * + * - Do not use this method with the [`startLastmileProbeTest`]{@link startLastmileProbeTest} method. + * + * - Do not call any other methods before receiving the [`LastmileQuality`]{@link RtcEngineEvents.LastmileQuality} callback. Otherwise, the callback may be interrupted by other methods and may not execute. + * + * - In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile, a host should not call this method after joining a channel. + * - If you call this method to test the last-mile quality, the SDK consumes the bandwidth of a video stream, whose bitrate corresponds to the bitrate you set in the [`setVideoEncoderConfiguration`]{@link setVideoEncoderConfiguration} method. + * After you join the channel, whether you have called [`disableLastmileTest`]{@link disableLastmileTest} or not, the SDK automatically stops consuming the bandwidth. + */ + enableLastmileTest(): Promise { + return RtcEngine._callMethod('enableLastmileTest'); + } + + /** + * Starts an audio call test. + * + * In the audio call test, you record your voice. If the recording plays back within the set time interval, the audio devices and the network connection are working properly. + * + * **Note** + * + * - Call this method before joining a channel. + * + * - After calling this method, call [`stopEchoTest`]{@link stopEchoTest} to end the test. + * Otherwise, the app cannot run the next echo test, or call [`joinChannel`]{@link joinChannel}. + * + * - In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile, only a host can call this method. + * @param intervalInSeconds The time interval (s) between when you speak and when the recording plays back. + */ + startEchoTest(intervalInSeconds: number): Promise { + return RtcEngine._callMethod('startEchoTest', { intervalInSeconds }); + } + + /** + * Starts the last-mile network probe test before joining a channel to get the uplink and downlink last-mile network statistics, + * including the bandwidth, packet loss, jitter, and round-trip time (RTT). + * + * Once this method is enabled, the SDK returns the following callbacks: + * - [`LastmileQuality`]{@link RtcEngineEvents.LastmileQuality}: the SDK triggers this callback within two seconds depending on the network conditions. + * This callback rates the network conditions with a score and is more closely linked to the user experience. + * + * - [`LastmileProbeResult`]{@link RtcEngineEvents.LastmileProbeResult}: the SDK triggers this callback within 30 seconds depending on the network conditions. + * This callback returns the real-time statistics of the network conditions and is more objective. + * + * Call this method to check the uplink network quality before users join a channel or before an audience switches to a host. + * + * **Note** + * + * - This method consumes extra network traffic and may affect communication quality. We do not recommend calling this method together with [`enableLastmileTest`]{@link enableLastmileTest}. + * - Do not call other methods before receiving the [`LastmileQuality`]{@link RtcEngineEvents.LastmileQuality} and [`LastmileProbeResult`]{@link RtcEngineEvents.LastmileProbeResult} callbacks. Otherwise, the callbacks may be interrupted by other methods. + * - In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile, a host should not call this method after joining a channel. + * + * @param config The configurations of the last-mile network probe test. + */ + startLastmileProbeTest(config: LastmileProbeConfig): Promise { + return RtcEngine._callMethod('startLastmileProbeTest', { config }); + } + + /** + * Stops the audio call test. + */ + stopEchoTest(): Promise { + return RtcEngine._callMethod('stopEchoTest'); + } + + /** + * Stops the last-mile network probe test. + */ + stopLastmileProbeTest(): Promise { + return RtcEngine._callMethod('stopLastmileProbeTest'); + } + + /** + * Registers the metadata observer. + * + * This method enables you to add synchronized metadata in the video stream for more diversified live streaming interactions, + * such as sending shopping links, digital coupons, and online quizzes. + * + * **Note** + * + * Call this method before the [`joinChannel`]{@link joinChannel} method. + */ + registerMediaMetadataObserver(): Promise { + return RtcEngine._callMethod('registerMediaMetadataObserver'); + } + + /** + * Sends the metadata. + * + * @param metadata The metadata to be sent. + */ + sendMetadata(metadata: string): Promise { + return RtcEngine._callMethod('sendMetadata', { metadata }); + } + + /** + * Sets the maximum size of the metadata. + * + * @param size Buffer size of the sent or received metadata. + */ + setMaxMetadataSize(size: number): Promise { + return RtcEngine._callMethod('setMaxMetadataSize', { size }); + } + + /** + * Unregisters the metadata observer. + */ + unregisterMediaMetadataObserver(): Promise { + return RtcEngine._callMethod('unregisterMediaMetadataObserver'); + } + + /** + * Adds a watermark image to the local video. + * + * This method adds a PNG watermark image to the local video stream in a live interactive streaming. + * Once the watermark image is added, all the audience in the channel (CDN audience included), and the recording device can see and capture it. + * + * Agora supports adding only one watermark image onto the local video, and the newly-added watermark image replaces the previous one. + * The watermark position depends on the settings in the [`setVideoEncoderConfiguration`]{@link setVideoEncoderConfiguration} method: + * + * - If the orientation mode of the encoding video is [`FixedLandscape`]{@link VideoOutputOrientationMode.FixedLandscape}, or the landscape mode in [`Adaptative`]{@link VideoOutputOrientationMode.Adaptative}, the watermark uses the landscape orientation. + * + * - If the orientation mode of the encoding video is [`FixedPortrait`]{@link VideoOutputOrientationMode.FixedPortrait}, or the portrait mode in [`Adaptative`]{@link VideoOutputOrientationMode.Adaptative}, the watermark uses the portrait orientation. + * + * - When setting the watermark position, the region must be less than the dimensions set in the [`setVideoEncoderConfiguration`]{@link setVideoEncoderConfiguration} method. + * Otherwise, the watermark image will be cropped. + * + * **Note** + * + * - Ensure that you have called [`enableVideo`]{@link enableVideo} to enable the video module before calling this method. + * + * - If you only want to add a watermark image to the local video for the audience in the CDN live interactive streaming channel to see and capture, you can call this method or the [`setLiveTranscoding`]{@link setLiveTranscoding} method. + * + * - This method supports adding a watermark image in the PNG file format only. Supported pixel formats of the PNG image are RGBA, RGB, Palette, Gray, and Alpha_gray. + * + * - If the dimensions of the PNG image differ from your settings in this method, the image will be cropped or zoomed to conform to your settings. + * + * - If you have enabled the local video preview by calling [`startPreview`]{@link startPreview}, you can use the `visibleInPreview` member in the [`WatermarkOptions`]{@link WatermarkOptions} class to set whether the watermark is visible in preview. + * + * - If you have enabled the mirror mode for the local video, the watermark on the local video is also mirrored. To avoid mirroring the watermark, Agora recommends that you do not use the mirror and watermark functions for the local video at the same time. + * You can implement the watermark function in your application layer. + * @param watermarkUrl The local file path of the watermark image to be added. This method supports adding a watermark image from either the local file path or the assets file path. If you use the assets file path, you need to start with `/assets/` when filling in this parameter. + * @param options The options of the watermark image to be added. + */ + addVideoWatermark( + watermarkUrl: string, + options: WatermarkOptions + ): Promise { + return RtcEngine._callMethod('addVideoWatermark', { + watermarkUrl, + options, + }); + } + + /** + * Removes the watermark image from the video stream added by [`addVideoWatermark`]{@link addVideoWatermark}. + */ + clearVideoWatermarks(): Promise { + return RtcEngine._callMethod('clearVideoWatermarks'); + } + + /** + * Enables/Disables the built-in encryption. + * + * @since v3.1.2. + * + * In scenarios requiring high security, Agora recommends calling `enableEncryption` to enable the built-in encryption before joining a channel. + * + * 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. + * - 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*. + * + * + * @param enabled Whether to enable the built-in encryption. + * - `true`: Enable the built-in encryption. + * - `false`: Disable the built-in encryption. + * @param config Configurations of built-in encryption schemas. See [`EncryptionConfig`]{@link EncryptionConfig}. + */ + enableEncryption(enabled: boolean, config: EncryptionConfig): Promise { + return RtcEngine._callMethod('enableEncryption', { enabled, config }); + } + + /** + * Sets the built-in encryption mode. + * + * @deprecated + * Deprecated as of v3.1.2. Use [`enableEncryption`]{@link enableEncryption} instead. + * + * The Agora SDK supports built-in encryption, which is set to `AES128XTS` mode by default. + * Call this method to set the encryption mode to use other encryption modes. + * All users in the same channel must use the same encryption mode and password. + * + * Refer to the information related to the AES encryption algorithm on the differences between the encryption modes. + * + * **Note** + * + * Call [`setEncryptionSecret`]{@link setEncryptionSecret} before calling this method. + * + * @param encryptionMode Sets the encryption mode. + */ + setEncryptionMode(encryptionMode: EncryptionMode): Promise { + return RtcEngine._callMethod('setEncryptionMode', { encryptionMode }); + } + + /** + * Enables built-in encryption with an encryption password before joining a channel. + * + * @deprecated + * Deprecated as of v3.1.2. Use [`enableEncryption`]{@link enableEncryption} instead. + * + * All users in a channel must set the same encryption password. + * The encryption password is automatically cleared once a user leaves the channel. + * If the encryption password is not specified or set to empty, the encryption functionality is disabled. + * + * **Note** + * + * - For optimal transmission, ensure that the encrypted data size does not exceed the original data size + 16 bytes. 16 bytes is the maximum padding size for AES encryption. + * - Do not use this method for CDN live streaming. + * @param secret The encryption password. + */ + setEncryptionSecret(secret: string): Promise { + return RtcEngine._callMethod('setEncryptionSecret', { secret }); + } + + /** + * Starts an audio recording on the client. + * + * The SDK allows recording during a call. After successfully calling this method, + * you can record the audio of all the users in the channel and get an audio recording file. + * + * Supported formats of the recording file are as follows: + * - .wav: Large file size with high fidelity. + * - .aac: Small file size with low fidelity. + * + * **Note** + * + * - Ensure that the directory to save the recording file exists and is writable. + * - This method is usually called after calling [`joinChannel`]{@link joinChannel}. The recording automatically stops when you call [`leaveChannel`]{@link leaveChannel}. + * - For better recording effects, set quality as [`Medium`]{@link AudioRecordingQuality.Medium} or [`High`]{@link AudioRecordingQuality.High} when sampleRate is 44.1 kHz or 48 kHz. + * + * @param filePath Absolute file path (including the suffixes of the filename) of the recording file. The string of the file name is in UTF-8. For example, `/sdcard/emulated/0/audio/aac`. + * @param sampleRate Sample rate (Hz) of the recording file. + * @param quality The audio recording quality. + */ + startAudioRecording( + filePath: string, + sampleRate: AudioSampleRateType, + quality: AudioRecordingQuality + ): Promise { + return RtcEngine._callMethod('startAudioRecording', { + filePath, + sampleRate, + quality, + }); + } + + /** + * Stops the audio recording on the client. + * + * **Note** + * + * You can call this method before calling [`leaveChannel`]{@link leaveChannel}; + * else, the recording automatically stops when you call [`leaveChannel`]{@link leaveChannel}. + */ + stopAudioRecording(): Promise { + return RtcEngine._callMethod('stopAudioRecording'); + } + + /** + * Injects an online media stream to live interactive streaming. + * + * If this method call is successful, the server pulls the voice or video stream and injects it into + * a live channel. This is applicable to scenarios where all audience members in the channel can watch a live show and interact with each other. + * + * This method call triggers the following callbacks: + * - The local client: + * - [`StreamInjectedStatus`]{@link RtcEngineEvents.StreamInjectedStatus}, with the state of the injecting the online stream. + * + * - [`UserJoined`]{@link RtcEngineEvents.UserJoined}(uid: 666), if the method call is successful and the online media stream is injected into the channel. + * + * - The remote client: + * - [`UserJoined`]{@link RtcEngineEvents.UserJoined}(uid: 666), if the method call is successful and the online media stream is injected into the channel. + * + * **Note** + * + * - This method applies to the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile only. + * - Ensure that you enable the RTMP Converter service before using this function. See Prerequisites in *Push Streams to CDN*. + * - You can inject only one media stream into the channel at the same time. + * + * @param url The URL address to be added to the ongoing live interactive streaming. Valid protocols are RTMP, HLS, and HTTP-FLV. + * - 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. + */ + addInjectStreamUrl( + url: string, + config: LiveInjectStreamConfig + ): Promise { + return RtcEngine._callMethod('addInjectStreamUrl', { url, config }); + } + + /** + * Removes the injected online media stream from live interactive streaming. + * + * This method removes the URL address (added by [`addInjectStreamUrl`]{@link addInjectStreamUrl}) from interactive streaming. + * + * If this method call is successful, the SDK triggers the [`UserOffline`]{@link RtcEngineEvents.UserOffline} callback and returns a stream uid of 666. + * + * @param url HTTP/HTTPS URL address of the added stream to be removed. + */ + removeInjectStreamUrl(url: string): Promise { + return RtcEngine._callMethod('removeInjectStreamUrl', { url }); + } + + /** + * Enables/Disables face detection for the local user. + * + * Once face detection is enabled, the SDK triggers the [`FacePositionChanged`]{@link RtcEngineEvents.FacePositionChanged} callback to report the face information of the local user, which includes the following aspects: + * + * - The width and height of the local video. + * - The position of the human face in the local video. + * - The distance between the human face and the device screen. + * + * @param enable Determines whether to enable the face detection function for the local user: + * - `true`: Enable face detection. + * - `false`: (Default) Disable face detection. + */ + enableFaceDetection(enable: boolean): Promise { + return RtcEngine._callMethod('enableFaceDetection', { enable }); + } + + /** + * Gets the maximum zoom ratio supported by the camera. + * + * @returns The maximum camera zoom factor. + */ + getCameraMaxZoomFactor(): Promise { + return RtcEngine._callMethod('getCameraMaxZoomFactor'); + } + + /** + * Checks whether the camera auto-face focus function is supported. + * + * @returns + * + * - `true`: The device supports the camera auto-face focus function. + * - `false`: The device does not support the camera auto-face focus function. + */ + isCameraAutoFocusFaceModeSupported(): Promise { + return RtcEngine._callMethod('isCameraAutoFocusFaceModeSupported'); + } + + /** + * Checks whether the camera exposure function is supported. + * + * @returns + * + * - `true`: The device supports the camera exposure function. + * - `false`: The device does not support the camera exposure function. + */ + isCameraExposurePositionSupported(): Promise { + return RtcEngine._callMethod('isCameraExposurePositionSupported'); + } + + /** + * Checks whether the camera manual focus function is supported. + * + * @returns + * + * - `true`: The device supports the camera manual focus function. + * - `false`: The device does not support the camera manual focus function. + */ + isCameraFocusSupported(): Promise { + return RtcEngine._callMethod('isCameraFocusSupported'); + } + + /** + * Checks whether the camera flash function is supported. + * + * @returns + * + * - `true`: The device supports the camera flash function. + * - `false`: The device does not the support camera flash function. + */ + isCameraTorchSupported(): Promise { + return RtcEngine._callMethod('isCameraTorchSupported'); + } + + /** + * Checks whether the camera zoom function is supported. + * + * @returns + * + * - `true`: The device supports the camera zoom function. + * - `false`: The device does not support the camera zoom function. + */ + isCameraZoomSupported(): Promise { + return RtcEngine._callMethod('isCameraZoomSupported'); + } + + /** + * Enables the camera auto-face focus function. + * + * @param enabled Sets whether to enable/disable the camera auto-face focus function: + * - `true`: Enable the camera auto-face focus function. + * - `false`: (Default) Disable the camera auto-face focus function. + */ + setCameraAutoFocusFaceModeEnabled(enabled: boolean): Promise { + return RtcEngine._callMethod('setCameraAutoFocusFaceModeEnabled', { + enabled, + }); + } + + /** + * Sets the camera capturer configuration. + * + * For a video call or live interactive video streaming, generally the SDK controls the camera output parameters. + * When the default camera capture settings do not meet special requirements or cause performance problems, + * we recommend using this method to set the camera capturer configuration: + * + * - If the resolution or frame rate of the captured raw video data are higher than those set by [`setVideoEncoderConfiguration`]{@link setVideoEncoderConfiguration}, processing video frames requires extra CPU and RAM usage and degrades performance. + * We recommend setting `config` as [`Performance(1)`]{@link CameraCaptureOutputPreference.Performance} to avoid such problems. + * + * - If you do not need local video preview or are willing to sacrifice preview quality, we recommend setting `config` as [`Performance(1)`]{@link CameraCaptureOutputPreference.Performance} to optimize CPU and RAM usage. + * + * - If you want better quality for the local video preview, we recommend setting `config` as [`Preview(2)`]{@link CameraCaptureOutputPreference.Preview}. + * + * **Note** + * + * Call this method before enabling the local camera. That said, you can call this method before calling [`joinChannel`]{@link joinChannel}, [`enableVideo`]{@link enableVideo}, or [`enableLocalVideo`]{@link enableLocalVideo}, depending on which method you use to turn on your local camera. + * + * @param config The camera capturer configuration. + */ + setCameraCapturerConfiguration( + config: CameraCapturerConfiguration + ): Promise { + return RtcEngine._callMethod('setCameraCapturerConfiguration', { config }); + } + + /** + * Sets the camera exposure position. + * + * A successful [`setCameraExposurePosition`]{@link setCameraExposurePosition} method call triggers the [`CameraExposureAreaChanged`]{@link RtcEngineEvents.CameraExposureAreaChanged} callback on the local client. + * + * @param positionXinView The horizontal coordinate of the touch point in the view. + * @param positionYinView The vertical coordinate of the touch point in the view. + */ + setCameraExposurePosition( + positionXinView: number, + positionYinView: number + ): Promise { + return RtcEngine._callMethod('setCameraExposurePosition', { + positionXinView, + positionYinView, + }); + } + + /** + * Sets the camera manual focus position. + * + * A successful [`setCameraFocusPositionInPreview`]{@link setCameraFocusPositionInPreview} method call triggers the [`CameraFocusAreaChanged`]{@link RtcEngineEvents.CameraFocusAreaChanged} callback on the local client. + * + * @param positionX The horizontal coordinate of the touch point in the view. + * @param positionY The vertical coordinate of the touch point in the view. + */ + setCameraFocusPositionInPreview( + positionX: number, + positionY: number + ): Promise { + return RtcEngine._callMethod('setCameraFocusPositionInPreview', { + positionX, + positionY, + }); + } + + /** + * Enables the camera flash function. + * @param isOn Sets whether to enable/disable the camera flash function: + * - `true`: Enable the camera flash function. + * - `false`: Disable the camera flash function. + */ + setCameraTorchOn(isOn: boolean): Promise { + return RtcEngine._callMethod('setCameraTorchOn', { isOn }); + } + + /** + * Sets the camera zoom ratio. + * @param factor Sets the camera zoom factor. The value ranges between 1.0 and the maximum zoom supported by the device. + */ + setCameraZoomFactor(factor: number): Promise { + return RtcEngine._callMethod('setCameraZoomFactor', { factor }); + } + + /** + * Switches between front and rear cameras. + */ + switchCamera(): Promise { + return RtcEngine._callMethod('switchCamera'); + } + + /** + * Creates a data stream. + * + * Each user can create up to five data streams during the lifecycle of the [`RtcEngine`]{@link RtcEngine}. + * + * **Note** + * + * Set both the `reliable` and `ordered` parameters to `true` or `false`. Do not set one as `true` and the other as `false`. + * @param reliable Sets whether the recipients are guaranteed to receive the data stream from the sender within five seconds: + * - `true`: The recipients receive the data from the sender within five seconds. + * If the recipient does not receive the data within five seconds, the SDK triggers the [`StreamMessageError`]{@link RtcEngineEvents.StreamMessageError} callback and returns an error code. + * + * - `false`: There is no guarantee that the recipients receive the data stream within five seconds and no error message is reported for any delay or missing data stream. + * @param ordered Sets whether the recipients receive the data stream in the sent order: + * - `true`: The recipients receive the data in the sent order. + * - `false`: The recipients do not receive the data in the sent order. + * + * @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}. + */ + createDataStream(reliable: boolean, ordered: boolean): Promise { + return RtcEngine._callMethod('createDataStream', { reliable, ordered }); + } + + /** + * Sends data stream messages. + * + * The SDK has the following restrictions on this method: + * + * - Up to 30 packets can be sent per second in a channel with each packet having a maximum size of 1 kB. + * - Each client can send up to 6 kB of data per second. + * - Each user can have up to five data channels simultaneously. + * + * A successful [`sendStreamMessage`]{@link sendStreamMessage} method call triggers the [`StreamMessage`]{@link RtcEngineEvents.StreamMessage} callback on the remote client, from which the remote user gets the stream message. + * + * A failed [`sendStreamMessage`]{@link sendStreamMessage} method call triggers the [`StreamMessageError`]{@link RtcEngineEvents.StreamMessageError} callback on the remote client. + * + * **Note** + * + * - Ensure that you have created the data stream using [`createDataStream`]{@link createDataStream} before calling this method. + * + * - This method applies only to the [`Communication`]{@link ChannelProfile.Communication} profile or to hosts in the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile. + * @param streamId ID of the sent data stream returned by the [`createDataStream`]{@link createDataStream} method. + * @param message Sent data. + */ + sendStreamMessage(streamId: number, message: string): Promise { + return RtcEngine._callMethod('sendStreamMessage', { streamId, message }); + } + + /** + * This function is in the beta stage with a free trial. The ability provided in its beta test version is reporting a maximum of 10 message pieces within 6 seconds, with each message piece not exceeding 256 bytes and each string not exceeding 100 bytes. To try out this function, contact support@agora.io and discuss the format of customized messages with us. + * @param id + * @param category + * @param event + * @param label + * @param value + */ + sendCustomReportMessage( + id: string, + category: string, + event: string, + label: string, + value: number + ): Promise { + return RtcEngine._callMethod('sendCustomReportMessage', { + id, + category, + event, + label, + value, + }); + } + + /** + * 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. + * + * **Note** + * - This method restricts the SDK’s manipulation of the audio session. Any operation to the audio session relies solely on the app, other apps, or third-party components. + * + * @param restriction The operational restriction (bit mask) of the SDK on the audio session. See [`AudioSessionOperationRestriction`]{@link AudioSessionOperationRestriction}. + */ + setAudioSessionOperationRestriction( + restriction: AudioSessionOperationRestriction + ): Promise { + return RtcEngine._callMethod('setAudioSessionOperationRestriction', { + restriction, + }); + } +} + +/** + * @ignore + */ +interface RtcEngineInterface + extends RtcUserInfoInterface, + RtcAudioInterface, + RtcVideoInterface, + RtcAudioMixingInterface, + RtcAudioEffectInterface, + RtcVoiceChangerInterface, + RtcVoicePositionInterface, + RtcPublishStreamInterface, + RtcMediaRelayInterface, + RtcAudioRouteInterface, + RtcEarMonitoringInterface, + RtcDualStreamInterface, + RtcFallbackInterface, + RtcTestInterface, + RtcMediaMetadataInterface, + RtcWatermarkInterface, + RtcEncryptionInterface, + RtcAudioRecorderInterface, + RtcInjectStreamInterface, + RtcCameraInterface, + RtcStreamMessageInterface { + destroy(): Promise; + + setChannelProfile(profile: ChannelProfile): Promise; + + setClientRole(role: ClientRole): Promise; + + joinChannel( + token: string | null, + channelName: string, + optionalInfo: string | null, + optionalUid: number + ): Promise; + + switchChannel(token: string | null, channelName: string): Promise; + + leaveChannel(): Promise; + + renewToken(token: string): Promise; + + enableWebSdkInteroperability(enabled: boolean): Promise; + + getConnectionState(): Promise; + + sendCustomReportMessage( + id: string, + category: string, + event: string, + label: string, + value: number + ): Promise; + + getCallId(): Promise; + + rate(callId: string, rating: Rate, description?: string): Promise; + + complain(callId: string, description: string): Promise; + + setLogFile(filePath: string): Promise; + + setLogFilter(filter: LogFilter): Promise; + + setLogFileSize(fileSizeInKBytes: number): Promise; + + setParameters(parameters: string): Promise; +} + +/** + * @ignore + */ +interface RtcUserInfoInterface { + registerLocalUserAccount(appId: string, userAccount: string): Promise; + + joinChannelWithUserAccount( + token: string, + channelName: string, + userAccount: string + ): Promise; + + getUserInfoByUserAccount(userAccount: string): Promise; + + getUserInfoByUid(uid: number): Promise; +} + +/** + * @ignore + */ +interface RtcAudioInterface { + enableAudio(): Promise; + + disableAudio(): Promise; + + setAudioProfile( + profile: AudioProfile, + scenario: AudioScenario + ): Promise; + + adjustRecordingSignalVolume(volume: number): Promise; + + adjustUserPlaybackSignalVolume(uid: number, volume: number): Promise; + + adjustPlaybackSignalVolume(volume: number): Promise; + + enableLocalAudio(enabled: boolean): Promise; + + muteLocalAudioStream(muted: boolean): Promise; + + muteRemoteAudioStream(uid: number, muted: boolean): Promise; + + muteAllRemoteAudioStreams(muted: boolean): Promise; + + setDefaultMuteAllRemoteAudioStreams(muted: boolean): Promise; + + enableAudioVolumeIndication( + interval: number, + smooth: number, + report_vad: boolean + ): Promise; +} + +/** + * @ignore + */ +interface RtcVideoInterface { + enableVideo(): Promise; + + disableVideo(): Promise; + + setVideoEncoderConfiguration( + config: VideoEncoderConfiguration + ): Promise; + + startPreview(): Promise; + + stopPreview(): Promise; + + enableLocalVideo(enabled: boolean): Promise; + + muteLocalVideoStream(muted: boolean): Promise; + + muteRemoteVideoStream(uid: number, muted: boolean): Promise; + + muteAllRemoteVideoStreams(muted: boolean): Promise; + + setDefaultMuteAllRemoteVideoStreams(muted: boolean): Promise; + + setBeautyEffectOptions( + enabled: boolean, + options: BeautyOptions + ): Promise; +} + +/** + * @ignore + */ +interface RtcAudioMixingInterface { + startAudioMixing( + filePath: string, + loopback: boolean, + replace: boolean, + cycle: number + ): Promise; + + stopAudioMixing(): Promise; + + pauseAudioMixing(): Promise; + + resumeAudioMixing(): Promise; + + adjustAudioMixingVolume(volume: number): Promise; + + adjustAudioMixingPlayoutVolume(volume: number): Promise; + + adjustAudioMixingPublishVolume(volume: number): Promise; + + getAudioMixingPlayoutVolume(): Promise; + + getAudioMixingPublishVolume(): Promise; + + getAudioMixingDuration(): Promise; + + getAudioMixingCurrentPosition(): Promise; + + setAudioMixingPosition(pos: number): Promise; + + setAudioMixingPitch(pitch: number): Promise; +} + +/** + * @ignore + */ +interface RtcAudioEffectInterface { + getEffectsVolume(): Promise; + + setEffectsVolume(volume: number): Promise; + + setVolumeOfEffect(soundId: number, volume: number): Promise; + + playEffect( + soundId: number, + filePath: string, + loopCount: number, + pitch: number, + pan: number, + gain: number, + publish: Boolean + ): Promise; + + stopEffect(soundId: number): Promise; + + stopAllEffects(): Promise; + + preloadEffect(soundId: number, filePath: string): Promise; + + unloadEffect(soundId: number): Promise; + + pauseEffect(soundId: number): Promise; + + pauseAllEffects(): Promise; + + resumeEffect(soundId: number): Promise; + + resumeAllEffects(): Promise; + + setAudioSessionOperationRestriction( + restriction: AudioSessionOperationRestriction + ): Promise; +} + +/** + * @ignore + */ +interface RtcVoiceChangerInterface { + setLocalVoiceChanger(voiceChanger: AudioVoiceChanger): Promise; + + setLocalVoiceReverbPreset(preset: AudioReverbPreset): Promise; + + setLocalVoicePitch(pitch: number): Promise; + + setLocalVoiceEqualization( + bandFrequency: AudioEqualizationBandFrequency, + bandGain: number + ): Promise; + + setLocalVoiceReverb(reverbKey: AudioReverbType, value: number): Promise; +} + +/** + * @ignore + */ +interface RtcVoicePositionInterface { + enableSoundPositionIndication(enabled: boolean): Promise; + + setRemoteVoicePosition(uid: number, pan: number, gain: number): Promise; +} + +/** + * @ignore + */ +interface RtcPublishStreamInterface { + setLiveTranscoding(transcoding: LiveTranscoding): Promise; + + addPublishStreamUrl(url: string, transcodingEnabled: boolean): Promise; + + removePublishStreamUrl(url: string): Promise; +} + +/** + * @ignore + */ +interface RtcMediaRelayInterface { + startChannelMediaRelay( + channelMediaRelayConfiguration: ChannelMediaRelayConfiguration + ): Promise; + + updateChannelMediaRelay( + channelMediaRelayConfiguration: ChannelMediaRelayConfiguration + ): Promise; + + stopChannelMediaRelay(): Promise; +} + +/** + * @ignore + */ +interface RtcAudioRouteInterface { + setDefaultAudioRoutetoSpeakerphone(defaultToSpeaker: boolean): Promise; + + setEnableSpeakerphone(enabled: boolean): Promise; + + isSpeakerphoneEnabled(): Promise; +} + +/** + * @ignore + */ +interface RtcEarMonitoringInterface { + enableInEarMonitoring(enabled: boolean): Promise; + + setInEarMonitoringVolume(volume: number): Promise; +} + +/** + * @ignore + */ +interface RtcDualStreamInterface { + enableDualStreamMode(enabled: boolean): Promise; + + setRemoteVideoStreamType( + uid: number, + streamType: VideoStreamType + ): Promise; + + setRemoteDefaultVideoStreamType(streamType: VideoStreamType): Promise; +} + +/** + * @ignore + */ +interface RtcFallbackInterface { + setLocalPublishFallbackOption(option: StreamFallbackOptions): Promise; + + setRemoteSubscribeFallbackOption( + option: StreamFallbackOptions + ): Promise; + + setRemoteUserPriority(uid: number, userPriority: UserPriority): Promise; +} + +/** + * @ignore + */ +interface RtcTestInterface { + startEchoTest(intervalInSeconds: number): Promise; + + stopEchoTest(): Promise; + + enableLastmileTest(): Promise; + + disableLastmileTest(): Promise; + + startLastmileProbeTest(config: LastmileProbeConfig): Promise; + + stopLastmileProbeTest(): Promise; +} + +/** + * @ignore + */ +interface RtcMediaMetadataInterface { + registerMediaMetadataObserver(): Promise; + + unregisterMediaMetadataObserver(): Promise; + + setMaxMetadataSize(size: number): Promise; + + sendMetadata(metadata: string): Promise; +} + +/** + * @ignore + */ +interface RtcWatermarkInterface { + addVideoWatermark( + watermarkUrl: string, + options: WatermarkOptions + ): Promise; + + clearVideoWatermarks(): Promise; +} + +/** + * @ignore + */ +interface RtcEncryptionInterface { + setEncryptionSecret(secret: string): Promise; + + setEncryptionMode(encryptionMode: EncryptionMode): Promise; + + enableEncryption(enabled: boolean, config: EncryptionConfig): Promise; +} + +/** + * @ignore + */ +interface RtcAudioRecorderInterface { + startAudioRecording( + filePath: string, + sampleRate: AudioSampleRateType, + quality: AudioRecordingQuality + ): Promise; + + stopAudioRecording(): Promise; +} + +/** + * @ignore + */ +interface RtcInjectStreamInterface { + addInjectStreamUrl( + url: string, + config: LiveInjectStreamConfig + ): Promise; + + removeInjectStreamUrl(url: string): Promise; +} + +/** + * @ignore + */ +interface RtcCameraInterface { + switchCamera(): Promise; + + isCameraZoomSupported(): Promise; + + isCameraTorchSupported(): Promise; + + isCameraFocusSupported(): Promise; + + isCameraExposurePositionSupported(): Promise; + + isCameraAutoFocusFaceModeSupported(): Promise; + + setCameraZoomFactor(factor: number): Promise; + + getCameraMaxZoomFactor(): Promise; + + setCameraFocusPositionInPreview( + positionX: number, + positionY: number + ): Promise; + + setCameraExposurePosition( + positionXinView: number, + positionYinView: number + ): Promise; + + enableFaceDetection(enable: boolean): Promise; + + setCameraTorchOn(isOn: boolean): Promise; + + setCameraAutoFocusFaceModeEnabled(enabled: boolean): Promise; + + setCameraCapturerConfiguration( + config: CameraCapturerConfiguration + ): Promise; +} + +/** + * @ignore + */ +interface RtcStreamMessageInterface { + createDataStream(reliable: boolean, ordered: boolean): Promise; + + sendStreamMessage(streamId: number, message: string): Promise; +} diff --git a/src/common/RtcEvents.ts b/src/common/RtcEvents.ts new file mode 100644 index 000000000..79757b926 --- /dev/null +++ b/src/common/RtcEvents.ts @@ -0,0 +1,1712 @@ +import type { + AudioLocalError, + AudioLocalState, + AudioMixingErrorCode, + AudioMixingStateCode, + AudioOutputRouting, + AudioRemoteState, + AudioRemoteStateReason, + AudioVolumeInfo, + ChannelMediaRelayError, + ChannelMediaRelayEvent, + ChannelMediaRelayState, + ClientRole, + 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'; + +/** + * @internal + * @ignore + */ + +export type Listener = (...args: any[]) => any; + +/** + * @internal + * @ignore + */ +export interface Subscription { + remove(): void; +} + +export type EmptyCallback = () => void; +export type WarningCallback = + /** + * @param warn Warning code. + */ + (warn: WarningCode) => void; +export type ErrorCallback = + /** + * @param err Error code. + */ + (err: ErrorCode) => void; +export type ApiCallCallback = + /** + * @param error [Error Code]{@link ErrorCode} that the SDK returns when the method call fails. + * @param api The method executed by the SDK. + * @param result The result of the method call. + */ + (error: ErrorCode, api: string, result: string) => void; +export type UidWithElapsedAndChannelCallback = + /** + * @param channel Channel name. + * @param uid User ID. + * @param elapsed Time elapsed (ms) from the user calling [`joinChannel`]{@link RtcEngine.joinChannel} until + * this callback is triggered. + */ + (channel: string, uid: number, elapsed: number) => void; +export type RtcStatsCallback = + /** + * @param stats Statistics of the call. + */ + (stats: RtcStats) => void; +export type UserAccountCallback = + /** + * @param uid The ID of the local user. + * @param userAccount The user account of the local user. + */ + (uid: number, userAccount: string) => void; +export type UserInfoCallback = + /** + * @param uid The ID of the remote user. + * @param userInfo The `UserInfo` object that contains the user ID and user account of the remote user. + */ + (uid: number, userInfo: UserInfo) => void; +export type ClientRoleCallback = + /** + * @param oldRole Role that the user switches from. + * @param newRole Role that the user switches to. + */ + (oldRole: ClientRole, newRole: ClientRole) => void; +export type UidWithElapsedCallback = + /** + * @param uid This parameter has the following definitions in different events: + * - [`UserJoined`]{@link RtcEngineEvents.UserJoined}: ID of the user or host who joins the channel. + * - [`FirstRemoteAudioFrame`]{@link RtcEngineEvents.FirstRemoteAudioFrame}: User ID of the remote user. + * - [`FirstRemoteAudioDecoded`]{@link RtcEngineEvents.FirstRemoteAudioDecoded}: User ID of the remote user sending the audio stream. + * - [`JoinChannelSuccess`]{@link RtcChannelEvents.JoinChannelSuccess}: User ID. + * - [`RejoinChannelSuccess`]{@link RtcChannelEvents.RejoinChannelSuccess}: User ID. + * @param elapsed This parameter has the following definitions in different events: + * - [`UserJoined`]{@link RtcEngineEvents.UserJoined}: Time delay (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} or [`setClientRole`]{@link RtcEngine.setClientRole} + * until this callback is triggered. + * - [`FirstRemoteAudioFrame`]{@link RtcEngineEvents.FirstRemoteAudioFrame}: Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until this callback is triggered. + * - [`FirstRemoteAudioDecoded`]{@link RtcEngineEvents.FirstRemoteAudioDecoded}: Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until the SDK triggers this callback. + * - [`JoinChannelSuccess`]{@link RtcChannelEvents.JoinChannelSuccess}: Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcChannel.joinChannel} until this callback is triggered. + * - [`RejoinChannelSuccess`]{@link RtcChannelEvents.RejoinChannelSuccess}: Time elapsed (ms) from the local user starting to reconnect until this callback is triggered. + * + */ + (uid: number, elapsed: number) => void; +export type UserOfflineCallback = + /** + * @param uid ID of the user or host who leaves the channel or goes offline. + * @param reason Reason why the user goes offline. + */ + (uid: number, reason: UserOfflineReason) => void; +export type ConnectionStateCallback = + /** + * @param state The current network connection state. + * @param reason The reason causing the change of the connection state. + */ + (state: ConnectionStateType, reason: ConnectionChangedReason) => void; +export type NetworkTypeCallback = + /** + * @param type The network type. + */ + (type: NetworkType) => void; +export type TokenCallback = + /** + * @param token The token that will expire in 30 seconds. + */ + (token: string) => void; +export type AudioVolumeCallback = + /** + * @param speakers An array containing the user ID and volume information for each speaker. + * + * In the local user’s callback, this array contains the following members: + * - `uid` = 0, + * - `volume` = `totalVolume`, which reports the sum of the voice volume and audio-mixing volume of the local user, and + * - `vad`, which reports the voice activity status of the local user. + * + * In the remote speakers' callback, this array contains the following members: + * - `uid` of each remote speaker, + * - `volume`, which reports the sum of the voice volume and audio-mixing volume of each remote speaker, and + * - `vad` = 0. + * + * An empty `speakers` array in the callback indicates that no remote user is speaking at the moment. + * + * @param totalVolume Total volume after audio mixing. The value ranges between 0 (lowest volume) and 255 (highest volume). + * - In the local user’s callback, `totalVolume` is the sum of the voice volume and audio-mixing volume of the local user. + * - In the remote speakers' callback, `totalVolume` is the sum of the voice volume and audio-mixing + * volume of all remote speakers. + */ + (speakers: AudioVolumeInfo[], totalVolume: number) => void; +export type UidCallback = + /** + * @param uid User ID of the active speaker. A `uid` of 0 represents the local user. + */ + (uid: number) => void; +export type ElapsedCallback = + /** + * @param elapsed Time elapsed (ms) from the local user calling the [`joinChannel`]{@link RtcEngine.joinChannel} until + * this callback is triggered. + */ + (elapsed: number) => void; +export type VideoFrameCallback = + /** + * @param width Width (pixels) of the first local video frame. + * @param height Height (pixels) of the first local video frame. + * @param elapsed Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until this + * callback is triggered. + * If [`startPreview`]{@link RtcEngine.startPreview} is called before [`joinChannel`]{@link RtcEngine.joinChannel}, elapsed is the + * time elapsed (ms) from the local user calling [`startPreview`]{@link RtcEngine.startPreview} until this callback is triggered. + */ + (width: number, height: number, elapsed: number) => void; +export type UidWithMutedCallback = + /** + * @param uid ID of the remote user. + * @param muted Whether the remote user's video stream playback pauses/resumes: + * + * - `true`: Pause. + * - `false`: Resume. + */ + (uid: number, muted: boolean) => void; +export type VideoSizeCallback = + /** + * @param uid User ID of the remote user or local user (0) whose video size or rotation changes. + * @param width New width (pixels) of the video. + * @param height New height (pixels) of the video. + * @param rotation New rotation of the video [0 to 360). + */ + (uid: number, width: number, height: number, rotation: number) => void; +export type RemoteVideoStateCallback = + /** + * @param uid ID of the remote user whose video state changes. + * @param state State of the remote video. + * @param reason The reason of the remote video state change. + * @param elapsed Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until the SDK + * triggers this callback. + */ + ( + uid: number, + state: VideoRemoteState, + reason: VideoRemoteStateReason, + elapsed: number + ) => void; +export type LocalVideoStateCallback = + /** + * @param localVideoState The local video state. + * @param error The detailed error information of the local video. + */ + ( + localVideoState: LocalVideoStreamState, + error: LocalVideoStreamError + ) => void; +export type RemoteAudioStateCallback = + /** + * @param uid ID of the user whose audio state changes. + * @param state State of the remote audio. + * @param reason The reason of the remote audio state change. + * @param elapsed Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until the + * SDK triggers this callback. + */ + ( + uid: number, + state: AudioRemoteState, + reason: AudioRemoteStateReason, + elapsed: number + ) => void; +export type LocalAudioStateCallback = + /** + * @param state State of the local audio. + * @param error The error information of the local audio. + */ + (state: AudioLocalState, error: AudioLocalError) => void; +export type FallbackCallback = + /** + * @param isFallbackOrRecover Whether the published stream fell back to audio-only or switched back to the video: + * + * - `true`: The published stream fell back to audio-only due to poor network conditions. + * - `false`: The published stream switched back to the video after the network conditions improved. + */ + (isFallbackOrRecover: boolean) => void; +export type FallbackWithUidCallback = + /** + * @param uid ID of the remote user sending the stream. + * @param isFallbackOrRecover Whether the remote media stream fell back to audio-only or + * switched back to the video: + * + * - `true`: The remote media stream fell back to audio-only due to poor network conditions. + * - `false`: The remote media stream switched back to the video stream after the network conditions improved. + */ + (uid: number, isFallbackOrRecover: boolean) => void; +export type AudioRouteCallback = + /** + * @param routing Audio output routing. + */ + (routing: AudioOutputRouting) => void; +export type RectCallback = + /** + * @param rect Rectangular area in the camera zoom specifying the focus area. + */ + + (rect: Rect) => void; +export type NetworkQualityCallback = + /** + * @param quality The last mile network quality based on the uplink and downlink packet loss rate and jitter. + */ + (quality: NetworkQuality) => void; +export type NetworkQualityWithUidCallback = + /** + * @param uid User ID. The network quality of the user with this uid is reported. + * @param txQuality Uplink transmission quality of the user in terms of the transmission bitrate, packet loss rate, average RTT (Round-Trip Time) + * and jitter of the uplink network. `txQuality` is a quality rating helping you understand how well the current uplink + * network conditions can support the selected VideoEncoderConfiguration. + * For example, a 1000 Kbps uplink network may be adequate for video frames with a resolution + * of 680 × 480 and a frame rate of 30 fps, but may be inadequate for resolutions higher than 1280 × 720. + * @param rxQuality Downlink network quality rating of the user in terms of packet loss rate, average RTT, and + * jitter of the downlink network. + */ + (uid: number, txQuality: NetworkQuality, rxQuality: NetworkQuality) => void; +export type LastmileProbeCallback = + /** + * @param result The uplink and downlink last-mile network probe test result. + */ + (result: LastmileProbeResult) => void; +export type LocalVideoStatsCallback = + /** + * @param stats The statistics of the local video stream. + */ + (stats: LocalVideoStats) => void; +export type LocalAudioStatsCallback = + /** + * @param stats The statistics of the local audio stream. + */ + (stats: LocalAudioStats) => void; +export type RemoteVideoStatsCallback = + /** + * @param stats Statistics of the received remote video streams. + */ + (stats: RemoteVideoStats) => void; +export type RemoteAudioStatsCallback = + /** + * @param stats Statistics of the received remote audio streams. + */ + (stats: RemoteAudioStats) => void; +export type AudioMixingStateCallback = + /** + * @param state The state code. + * @param errorCode The error code. + */ + (state: AudioMixingStateCode, errorCode: AudioMixingErrorCode) => void; +export type SoundIdCallback = + /** + * @param soundId ID of the local audio effect. Each local audio effect has a unique ID. + */ + (soundId: number) => void; +export type RtmpStreamingStateCallback = + /** + * @param url The RTMP URL address. + * @param state The RTMP streaming state. + * @param errCode The detailed error information for streaming. + */ + ( + url: string, + state: RtmpStreamingState, + errCode: RtmpStreamingErrorCode + ) => void; +export type StreamInjectedStatusCallback = + /** + * @param url The URL address of the externally injected stream. + * @param uid User ID. + * @param status State of the externally injected stream. + */ + (url: string, uid: number, status: InjectStreamStatus) => void; +export type StreamMessageCallback = + /** + * @param uid User ID of the remote user sending the data stream. + * @param streamId Stream ID. + * @param data Data received by the local user. + */ + (uid: number, streamId: number, data: string) => void; +export type StreamMessageErrorCallback = + /** + * @param uid User ID of the remote user sending the data stream. + * @param streamId Stream ID. + * @param error Error code. + * @param missed The number of lost messages. + * @param cached The number of incoming cached messages when the data stream is interrupted. + */ + ( + uid: number, + streamId: number, + error: ErrorCode, + missed: number, + cached: number + ) => void; +export type MediaRelayStateCallback = + /** + * @param state The state code. + * @param code The error code. + */ + (state: ChannelMediaRelayState, code: ChannelMediaRelayError) => void; +export type MediaRelayEventCallback = + /** + * @param code The event code for media stream relay. + */ + (code: ChannelMediaRelayEvent) => void; +export type VideoFrameWithUidCallback = + /** + * @param uid User ID of the remote user sending the video streams. + * @param width Width (pixels) of the video stream. + * @param height Height (pixels) of the video stream. + * @param elapsed Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until this + * callback is triggered. + */ + (uid: number, width: number, height: number, elapsed: number) => void; +export type UrlWithErrorCallback = + /** + * @param url The RTMP streaming URL. + * @param error The detailed error information. + */ + (url: string, error: ErrorCode) => void; +export type UrlCallback = + /** + * @param url The RTMP URL address. + */ + (url: string) => void; +export type TransportStatsCallback = + /** + * @param uid User ID of the remote user sending the audio packet/video packet. + * @param delay Network time delay (ms) from the remote user sending the audio packet/video packet to the local user. + * @param lost Packet loss rate (%) of the audio packet/video packet sent from the remote user. + * @param rxKBitRate Received bitrate (Kbps) of the audio packet/video packet sent from the remote user. + */ + (uid: number, delay: number, lost: number, rxKBitRate: number) => void; +export type UidWithEnabledCallback = + /** + * @param uid User ID of the remote user. + * @param enabled Whether the specific remote user enables/disables the video module: + * + * - `true`: Enabled. The remote user can enter a video session. + * - `false`: Disabled. The remote user can only enter a voice session, and cannot send or receive + * any video stream. + */ + (uid: number, enabled: boolean) => void; +export type EnabledCallback = + /** + * @param enabled Whether the microphone is enabled/disabled: + * - `true`: Enabled. + * - `false`: Disabled. + */ + (enabled: boolean) => void; +export type AudioQualityCallback = + /** + * @param uid User ID of the speaker. + * @param quality Audio quality of the user. + * @param delay Time delay (ms) of the audio packet from the sender to the receiver, including the time delay + * from audio sampling pre-processing, transmission, and the jitter buffer. + * @param lost Packet loss rate (%) of the audio packet sent from the sender to the receiver. + */ + (uid: number, quality: number, delay: number, lost: number) => void; +export type MetadataCallback = + /** + * @param buffer The received metadata. + * @param uid The ID of the user who sent the metadata. + * @param timeStampMs The timestamp (ms) of the received metadata. + */ + (buffer: string, uid: number, timeStampMs: number) => void; +export type FacePositionCallback = + /** + * @param imageWidth The width (px) of the local video. + * @param imageHeight The height (px) of the local video. + * @param faces The information of the detected human face. For details, see [`FacePositionInfo`]{@link FacePositionInfo}. + * The number of the `FacePositionInfo` array depends on the number of human faces detected. + * If the array length is 0, it means that no human face is detected. + */ + (imageWidth: number, imageHeight: number, faces: FacePositionInfo[]) => void; +export type StreamPublishStateCallback = + /** + * @param channel The channel name. + * @param oldState The previous publishing state. See [`StreamPublishState`]{@link StreamPublishState}. + * @param newState The current publishing state. See [`StreamPublishState`]{@link StreamPublishState}. + * @param elapseSinceLastState The time elapsed (ms) from the previous state to the current state. + */ + ( + channel: string, + oldState: StreamPublishState, + newState: StreamPublishState, + elapseSinceLastState: number + ) => void; +export type StreamSubscribeStateCallback = + /** + * @param channel The channel name. + * @param oldState The previous publishing state. See [`StreamPublishState`]{@link StreamPublishState}. + * @param newState The current publishing state. See [`StreamPublishState`]{@link StreamPublishState}. + * @param elapseSinceLastState The time elapsed (ms) from the previous state to the current state. + */ + ( + channel: string, + oldState: StreamSubscribeState, + newState: StreamSubscribeState, + elapseSinceLastState: number + ) => void; +export type RtmpStreamingEventCallback = + /** + * @param url The RTMP streaming URL. + * @param eventCode The event code. See [`RtmpStreamingEvent`]{@link RtmpStreamingEvent}. + */ + (url: string, eventCode: RtmpStreamingEvent) => void; + +/** + * Callbacks. + * + * The SDK uses the [`RtcEngineEvents`]{@link RtcEngineEvents} interface class to send callbacks to the application, and the application inherits the methods of this interface class to retrieve these callbacks. + * All methods in this interface class have their (empty) default implementations, and the application can inherit only some of the required events instead of all of them. + * In the callbacks, the application should avoid time-consuming tasks or call blocking APIs (such as SendMessage), otherwise, the SDK may not work properly. + */ +export interface RtcEngineEvents { + /** + * Reports a warning during SDK runtime. + * + * In most cases, the app can ignore the warning reported by the SDK because the SDK can usually fix the issue and resume running. + * + * For instance, the SDK may report a [`LookupChannelTimeout`]{@link WarningCode.LookupChannelTimeout} warning upon disconnection with the server and tries to reconnect. For detailed warning codes, see [`WarningCode`]{@link WarningCode}. + * + * @event Warning + */ + Warning: WarningCallback; + + /** + * Reports an error during SDK runtime. + * + * In most cases, the SDK cannot fix the issue and resume running. The SDK requires the app to take action or informs the user about the issue. + * + * For example, the SDK reports a [`StartCall`]{@link ErrorCode.StartCall} error when failing to initialize a call. The app informs the user that the call initialization failed and invokes the [`leaveChannel`]{@link RtcEngine.leaveChannel} method to leave the channel. For detailed error codes, see {@link ErrorCode}. + * + * @event Error + */ + Error: ErrorCallback; + + /** + * Occurs when an API method is executed. + * + * @event ApiCallExecuted + */ + ApiCallExecuted: ApiCallCallback; + + /** + * Occurs when the local user joins a specified channel. + * + * The channel name assignment is based on channelName specified in the joinChannel method. + * + * If the uid is not specified when [`joinChannel`]{@link RtcEngine.joinChannel} is called, the server automatically assigns a uid. + * + * @event JoinChannelSuccess + */ + JoinChannelSuccess: UidWithElapsedAndChannelCallback; + + /** + * Occurs when a user rejoins the channel after being disconnected due to network problems. + * + * When a user loses connection with the server because of network problems, the SDK automatically tries to reconnect and triggers this callback upon reconnection. + * + * @event RejoinChannelSuccess + */ + RejoinChannelSuccess: UidWithElapsedAndChannelCallback; + + /** + * Occurs when a user leaves the channel. + * + * When the app calls the [`leaveChannel`]{@link RtcEngine.leaveChannel} method, the SDK uses this callback to notify the app when the user leaves the channel. + * + * With this callback, the application retrieves the channel information, such as the call duration and statistics. + * + * @event LeaveChannel + */ + LeaveChannel: RtcStatsCallback; + + /** + * Occurs when the local user registers a user account. + * + * This callback is triggered when the local user successfully registers a user account by calling [`registerLocalUserAccount`]{@link RtcEngine.registerLocalUserAccount}, or joins a channel by calling [`joinChannelWithUserAccount`]{@link RtcEngine.joinChannelWithUserAccount}. + * This callback reports the user ID and user account of the local user. + * + * @event LocalUserRegistered + */ + LocalUserRegistered: UserAccountCallback; + + /** + * Occurs when the SDK gets the user ID and user account of the remote user. + * + * After a remote user joins the channel, the SDK gets the UID and user account of the remote user, caches them in a mapping table object ([`UserInfo`]{@link UserInfo}), and triggers this callback on the local client. + * + * @event UserInfoUpdated + */ + UserInfoUpdated: UserInfoCallback; + + /** + * Occurs when the user role switches in live interactive streaming. For example, from a host to an audience or vice versa. + * + * The SDK triggers this callback when the local user switches the user role by calling [`setClientRole`]{@link RtcEngine.setClientRole} after joining the channel. + * + * @event ClientRoleChanged + */ + ClientRoleChanged: ClientRoleCallback; + + /** + * Occurs when a remote user ([`Communication`]{@link ChannelProfile.Communication})/host ([`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting}) joins the channel. + * - [`Communication`]{@link ChannelProfile.Communication} profile: This callback notifies the app when another user joins the channel. If other users are already in the channel, the SDK also reports to the app on the existing users. + * - [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile: This callback notifies the app when the host joins the channel. If other hosts are already in the channel, the SDK also reports to the app on the existing hosts. We recommend having at most 17 hosts in a channel. + * + * The SDK triggers this callback under one of the following circumstances: + * - A remote user/host joins the channel by calling [`joinChannel`]{@link RtcEngine.joinChannel}. + * - A remote user switches the user role to the host by calling [`setClientRole`]{@link RtcEngine.setClientRole} after joining the channel. + * - A remote user/host rejoins the channel after a network interruption. + * - The host injects an online media stream into the channel by calling [`addInjectStreamUrl`]{@link RtcEngine.addInjectStreamUrl}. + * + * **Note** + * In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile: + * - The host receives the [`UserJoined`]{@link UserJoined} callback when another host joins the channel. + * - The audience in the channel receives the [`UserJoined`]{@link UserJoined} callback when a new host joins the channel. + * - When a web application joins the channel, the [`UserJoined`]{@link UserJoined} callback is triggered as long as the web application publishes streams. + * + * @event UserJoined + */ + UserJoined: UidWithElapsedCallback; + + /** + * Occurs when a remote user ([`Communication`]{@link ChannelProfile.Communication})/host ([`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting}) leaves the channel. + * + * There are two reasons for users to become offline: + * - Leave the channel: When the user/host leaves the channel, the user/host sends a goodbye message. When this message is received, the SDK determines that the user/host leaves the channel. + * - Drop offline: When no data packet of the user or host is received for a certain period of time (20 seconds for the [`Communication`]{@link ChannelProfile.Communication} profile, and more for the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile), the SDK assumes that the user/host drops offline. A poor network connection may lead to false detections, so we recommend using the Agora RTM SDK for reliable offline detection. + * + * @event UserOffline + */ + UserOffline: UserOfflineCallback; + + /** + * Occurs when the network connection state changes. + * + * The Agora SDK returns this callback to report on the current network connection state when it changes, and the reason to such change. + * + * @event ConnectionStateChanged + */ + ConnectionStateChanged: ConnectionStateCallback; + + /** + * Occurs when the network type changes. + * + * The SDK returns the current network type in this callback. When the network connection is interrupted, this callback indicates whether the interruption is caused by a network type change or poor network conditions. + * + * @event NetworkTypeChanged + */ + NetworkTypeChanged: NetworkTypeCallback; + + /** + * Occurs when the SDK cannot reconnect to Agora's edge server 10 seconds after its connection to the server is interrupted. + * + * The SDK triggers this callback when it cannot connect to the server 10 seconds after calling [`joinChannel`]{@link RtcEngine.joinChannel}, regardless of whether it is in the channel or not. + * + * If the SDK fails to rejoin the channel 20 minutes after being disconnected from Agora's edge server, the SDK stops rejoining the channel. + * + * @event ConnectionLost + */ + ConnectionLost: EmptyCallback; + + /** + * Occurs when the token expires in 30 seconds. + * + * The user becomes offline if the token used when joining the channel expires. This callback is triggered 30 seconds before the token expires to remind the app to get a new token. Upon receiving this callback, you need to generate a new token on the server and call [`renewToken`]{@link RtcEngine.renewToken} to pass the new token to the SDK. + * + * @event TokenPrivilegeWillExpire + */ + TokenPrivilegeWillExpire: TokenCallback; + + /** + * Occurs when the token has expired. + * + * After a token is specified when joining the channel, the token expires after a certain period of time, + * and a new token is required to reconnect to the server. This callback notifies the app to generate a + * new token and call [`joinChannel`]{@link RtcEngine.joinChannel} to rejoin the channel with the new token. + * + * @event RequestToken + */ + RequestToken: EmptyCallback; + + /** + * Reports which users are speaking and the speakers' volume, and whether the local user is speaking. + * + * This callback reports the IDs and volumes of the loudest speakers (at most 3) at the moment in the channel, and whether the local user is speaking. + * + * By default, this callback is disabled. You can enable it by calling [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication}. Once enabled, this callback is triggered at the set interval, regardless of whether a user speaks or not. + * + * The SDK triggers two independent `AudioVolumeIndication` callbacks at one time, which separately report the volume information of the local user and all the remote speakers. For more information, see the detailed parameter descriptions. + * + * **Note** + * - To enable the voice activity detection of the local user, ensure that you set `report_vad(true)` in the [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication} method. + * - Calling [`muteLocalAudioStream`]{@link RtcEngine.muteLocalAudioStream} affects the SDK's behavior. + * - If the local user calls [`muteLocalAudioStream`]{@link RtcEngine.muteLocalAudioStream}, the SDK stops triggering the local user's callback. + * - 20 seconds after a remote speaker calls [`muteLocalAudioStream`]{@link RtcEngine.muteLocalAudioStream}, the remote speakers' callback does not include information of this remote user; 20 seconds after all remote users call the the [`muteLocalAudioStream`]{@link muteLocalAudioStream} method, the SDK stops triggering the remote speakers' callback. + * + * @event AudioVolumeIndication + */ + AudioVolumeIndication: AudioVolumeCallback; + + /** + * Reports which user is the loudest speaker. + * + * This callback reports the speaker with the highest accumulative volume during a certain period. If the user enables the audio volume indication by + * calling [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication}, this callback returns the uid of the active speaker whose voice is detected by the audio volume detection module of the SDK. + * + * **Note** + * - To receive this callback, you need to call [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication}. + * - This callback returns the user ID of the user with the highest voice volume during a period of time, instead of at the moment. + * + * @event ActiveSpeaker + */ + ActiveSpeaker: UidCallback; + + /** + * Occurs when the first local audio frame is sent. + * + * @deprecated Deprecated as of v3.1.2. Use [`FirstLocalAudioFramePublished`]{@link RtcEngineEvents.FirstLocalAudioFramePublished} instead. + * + * @event FirstLocalAudioFrame + */ + FirstLocalAudioFrame: ElapsedCallback; + + /** + * Occurs when the first local video frame is rendered. + * + * This callback is triggered after the first local video frame is rendered on the local video window. + * + * @event FirstLocalVideoFrame + */ + FirstLocalVideoFrame: VideoFrameCallback; + + /** + * Occurs when a remote user stops/resumes sending the video stream. + * + * @deprecated + * + * This callback is deprecated. Use the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback with the following parameters for the same function: + * - [`Stopped`]{@link VideoRemoteState.Stopped} and [`RemoteMuted`]{@link VideoRemoteStateReason.RemoteMuted}. + * - [`Decoding`]{@link VideoRemoteState.Decoding} and [`RemoteUnmuted`]{@link VideoRemoteStateReason.RemoteUnmuted}. + * + * The SDK triggers this callback when the remote user stops or resumes sending the video stream by calling the [`muteLocalVideoStream`]{@link RtcEngine.muteLocalVideoStream} method. + * + * **Note** + * + * This callback is invalid when the number of users or hosts in the channel exceeds 17. + * + * @event UserMuteVideo + */ + UserMuteVideo: UidWithMutedCallback; + + /** + * Occurs when the video size or rotation information of a remote user changes. + * + * @event VideoSizeChanged + */ + VideoSizeChanged: VideoSizeCallback; + + /** + * Occurs when the remote video state changes. + * + * @event RemoteVideoStateChanged + */ + RemoteVideoStateChanged: RemoteVideoStateCallback; + + /** + * Occurs when the local video state changes. + * + * The SDK returns the current video state in this callback. + * This callback indicates the state of the local video stream, including camera capturing and video encoding, and allows you to troubleshoot issues when exceptions occur. + * When the state is [`Failed`]{@link LocalVideoStreamState.Failed}, see the error parameter for details. + * + * @event LocalVideoStateChanged + */ + LocalVideoStateChanged: LocalVideoStateCallback; + + /** + * Occurs when the remote audio state changes. + * + * This callback indicates the state change of the remote audio stream. + * + * **Note** + * + * This callback does not work properly when the number of users (in the [`Communication`] profile) or hosts (in the [`LiveBroadcasting`] profile) in the channel exceeds 17. + * + * @event RemoteAudioStateChanged + */ + RemoteAudioStateChanged: RemoteAudioStateCallback; + + /** + * Occurs when the local audio stream state changes. + * + * This callback indicates the state change of the local audio stream, including the state of the audio recording and encoding, and allows you to troubleshoot issues when exceptions occur. + * + * **Note** + * + * When the state is [`Failed`]{@link AudioLocalState.Failed}, see the error parameter for details. + * + * @event LocalAudioStateChanged + */ + LocalAudioStateChanged: LocalAudioStateCallback; + + /** + * Occurs when the published media stream falls back to an audio-only stream due to poor network conditions + * or switches back to video stream after the network conditions improve. + * + * If you call [`setLocalPublishFallbackOption`]{@link RtcEngine.setLocalPublishFallbackOption} and set option as [`AudioOnly`]{@link StreamFallbackOptions.AudioOnly}, + * this callback is triggered when the locally published stream falls back to audio-only mode due to poor uplink conditions, + * or when the audio stream switches back to the video after the uplink network condition improves. Once the published stream falls back to audio only, + * the remote app receives the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback. + * + * @event LocalPublishFallbackToAudioOnly + */ + LocalPublishFallbackToAudioOnly: FallbackCallback; + + /** + * Occurs when the remote media stream falls back to audio-only stream due to poor network conditions or switches back to video stream after the network conditions improve. + * + * If you call [`setRemoteSubscribeFallbackOption`]{@link RtcEngine.setRemoteSubscribeFallbackOption} and set + * option as [`AudioOnly`]{@link StreamFallbackOptions.AudioOnly}, + * this callback is triggered when the remotely subscribed media stream falls back to audio-only mode due + * to poor uplink conditions, or when the remotely subscribed media stream switches back to the video after + * the uplink network condition improves. + * + * @event RemoteSubscribeFallbackToAudioOnly + */ + RemoteSubscribeFallbackToAudioOnly: FallbackWithUidCallback; + + /** + * Occurs when the local audio playback route changes. + * + * This callback returns that the audio route switched to an earpiece, speakerphone, headset, or Bluetooth device. + * + * The definition of the routing is listed in [`AudioOutputRouting`]{@link AudioOutputRouting}. + * + * @event AudioRouteChanged + */ + AudioRouteChanged: AudioRouteCallback; + + /** + * Occurs when the camera focus area is changed. + * + * The SDK triggers this callback when the local user changes the camera focus position by + * calling [`setCameraFocusPositionInPreview`]{@link RtcEngine.setCameraFocusPositionInPreview}. + * + * @event CameraFocusAreaChanged + */ + CameraFocusAreaChanged: RectCallback; + + /** + * The camera exposure area has changed. + * + * The SDK triggers this callback when the local user changes the camera exposure position by calling [`setCameraExposurePosition`]{@link RtcEngine.setCameraExposurePosition}. + * + * @event CameraExposureAreaChanged + */ + CameraExposureAreaChanged: RectCallback; + + /** + * Reports the face detection result of the local user. + * + * Once you enable face detection by calling [`enableFaceDetection`]{@link RtcEngine.enableFaceDetection}, you can get the following information on the local user in real-time: + * - The width and height of the local video. + * - The position of the human face in the local video. + * - The distance between the human face and the device screen. This value is based on the fitting calculation of the local video size and the position of the human face. + * + * **Note** + * - If the SDK does not detect a face, it reduces the frequency of this callback to reduce power consumption on the local device. + * - The SDK stops triggering this callback when a human face is in close proximity to the screen. + * - On Android, the distance value reported in this callback may be slightly different from the actual distance. Therefore, Agora does not recommend using it for accurate calculation. + * + * @event FacePositionChanged + */ + FacePositionChanged: FacePositionCallback; + + /** + * Reports the statistics of the [`RtcEngine`]{@link RtcEngine} once every two seconds. + * + * @event RtcStats + */ + RtcStats: RtcStatsCallback; + + /** + * Reports the last mile network quality of the local user once every two seconds before the user joins the channel. + * Last mile refers to the connection between the local device and Agora's edge server. After the application calls the [`enableLastmileTest`]{@link RtcEngine.enableLastmileTest} method, + * this callback reports once every two seconds the uplink and downlink last mile network conditions of the local user before the user joins the channel. + * + * @event LastmileQuality + */ + LastmileQuality: NetworkQualityCallback; + + /** + * Reports the last mile network quality of each user in the channel once every two seconds. + * + * Last mile refers to the connection between the local device and Agora's edge server. This callback reports once every two seconds the last mile network conditions of each user in the channel. If a channel includes multiple users, then this callback will be triggered as many times. + * + * @event NetworkQuality + */ + NetworkQuality: NetworkQualityWithUidCallback; + + /** + * Reports the last-mile network probe result. + * + * The SDK triggers this callback within 30 seconds after the app calls [`startLastmileProbeTest`]{@link RtcEngine.startLastmileProbeTest}. + * + * @event LastmileProbeResult + */ + LastmileProbeResult: LastmileProbeCallback; + + /** + * Reports the statistics of the local video streams. + * + * The SDK triggers this callback once every two seconds for each user/host. If there are multiple users/hosts in the channel, the SDK triggers this callback as many times. + * + * @event LocalVideoStats + */ + LocalVideoStats: LocalVideoStatsCallback; + + /** + * Reports the statistics of the local audio stream. + * + * @event LocalAudioStats + */ + LocalAudioStats: LocalAudioStatsCallback; + + /** + * Reports the statistics of the video stream from each remote user/host. The SDK triggers this callback once every two seconds for each remote user/host. If a channel includes multiple remote users, the SDK triggers this callback as many times. + * + * @event RemoteVideoStats + */ + RemoteVideoStats: RemoteVideoStatsCallback; + + /** + * Reports the statistics of the audio stream from each remote user/host. + * + * The SDK triggers this callback once every two seconds for each remote user/host. If a channel includes multiple remote users, the SDK triggers this callback as many times. + * + * Schemes such as FEC (Forward Error Correction) or retransmission counter the frame loss rate. Hence, users may find the overall audio quality acceptable even when the packet loss rate is high. + * + * @event RemoteAudioStats + */ + RemoteAudioStats: RemoteAudioStatsCallback; + + /** + * Occurs when the audio mixing file playback finishes. + * + * @deprecated + * + * This callback is deprecated. + * Use [`AudioMixingStateChanged`]{@link AudioMixingStateChanged} instead. + * + * You can start an audio mixing file playback by calling [`startAudioMixing`]{@link RtcEngine.startAudioMixing}. This callback is triggered when the audio mixing file playback finishes. + * + * If the [`startAudioMixing`]{@link RtcEngine.startAudioMixing} method call fails, an [`AudioMixingOpenError`]{@link WarningCode.AudioMixingOpenError} warning returns in the [`Warning`]{@link Warning} callback. + * + * @event AudioMixingFinished + */ + AudioMixingFinished: EmptyCallback; + + /** + * Occurs when the state of the local user's audio mixing file changes. + * + * When you call [`startAudioMixing`]{@link RtcEngine.startAudioMixing} and the state of audio mixing file changes, the Agora SDK triggers this callback. + * - When the audio mixing file plays, pauses playing, or stops playing, this callback returns `710`, `711`, or `713` in state, and `0` in errorCode. + * - When exceptions occur during playback, this callback returns `714` in state and an error in errorCode. + * - If the local audio mixing file does not exist, or if the SDK does not support the file format or cannot access the music file URL, the SDK returns [`AudioMixingOpenError`]{@link WarningCode.AudioMixingOpenError}. + * + * @event AudioMixingStateChanged + */ + AudioMixingStateChanged: AudioMixingStateCallback; + + /** + * Occurs when the audio effect file playback finishes. + * + * You can start a local audio effect playback by calling [`playEffect`]{@link RtcEngine.playEffect}. This callback is triggered when the local audio effect file playback finishes. + * + * @event AudioEffectFinished + */ + AudioEffectFinished: SoundIdCallback; + + /** + * Occurs when the state of the RTMP 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. + * + * @event RtmpStreamingStateChanged + */ + RtmpStreamingStateChanged: RtmpStreamingStateCallback; + + /** + * Occurs when the publisher's transcoding settings are updated. + * + * When the `LiveTranscoding` class in the [`setLiveTranscoding`]{@link RtcEngine.setLiveTranscoding} method updates, the SDK triggers this callback to report the update information. + * + * **Note** + * - If you call [`setLiveTranscoding`]{@link RtcEngine.setLiveTranscoding} to set the `LiveTranscoding` class for the first time, the SDK does not trigger this callback. + * + * @event TranscodingUpdated + */ + TranscodingUpdated: EmptyCallback; + + /** + * Reports the status of injecting the online media stream. + * + * @event StreamInjectedStatus + */ + StreamInjectedStatus: StreamInjectedStatusCallback; + + /** + * Occurs when the local user receives a remote data stream. + * + * The SDK triggers this callback when the local user receives the stream message that the remote user sends + * by calling the [`sendStreamMessage`]{@link RtcEngine.sendStreamMessage} method. + * + * @event StreamMessage + */ + StreamMessage: StreamMessageCallback; + + /** + * Occurs when the local user fails to receive a remote data stream. + * + * The SDK triggers this callback when the local user fails to receive the stream message that the remote + * user sends by calling the [`sendStreamMessage`]{@link RtcEngine.sendStreamMessage} method. + * + * @event StreamMessageError + */ + StreamMessageError: StreamMessageErrorCallback; + + /** + * Occurs when the media engine is loaded. + * + * @event MediaEngineLoadSuccess + */ + MediaEngineLoadSuccess: EmptyCallback; + + /** + * Occurs when the media engine starts. + * + * @event MediaEngineStartCallSuccess + */ + MediaEngineStartCallSuccess: EmptyCallback; + + /** + * Occurs when the state of the media stream relay changes. + * + * The SDK reports the state of the current media relay and possible error messages in this callback. + * + * @event ChannelMediaRelayStateChanged + */ + ChannelMediaRelayStateChanged: MediaRelayStateCallback; + + /** + * Reports events during the media stream relay. + * + * @event ChannelMediaRelayEvent + */ + ChannelMediaRelayEvent: MediaRelayEventCallback; + + /** + * Occurs when the first remote video frame is rendered. + * + * @deprecated + * + * Use [`Starting`]{@link VideoRemoteState.Starting} or [`Decoding`]{@link VideoRemoteState.Decoding} in the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback instead. + * + * This callback is triggered after the first frame of the remote video is rendered on the video window. The application can retrieve the data of the time elapsed from the user joining the channel until the first video frame is displayed. + * + * @event FirstRemoteVideoFrame + */ + FirstRemoteVideoFrame: VideoFrameWithUidCallback; + + /** + * Occurs when the first remote audio frame is received. + * + * @deprecated + * + * Use [`Starting`]{@link AudioRemoteState.Starting} in [`RemoteAudioStateChanged`]{@link RemoteAudioStateChanged} instead. + * + * @event FirstRemoteAudioFrame + */ + FirstRemoteAudioFrame: UidWithElapsedCallback; + + /** + * Occurs when the engine receives the first audio frame from a specified remote user. + * + * @deprecated + * + * Use [`Decoding`]{@link VideoRemoteState.Decoding} in [`RemoteAudioStateChanged`]{@link RemoteAudioStateChanged} instead. + * + * This callback is triggered in either of the following scenarios: + * - The remote user joins the channel and sends the audio stream. + * - The remote user stops sending the audio stream and re-sends it after 15 seconds. Possible reasons include: + * - The remote user leaves channel. + * - The remote user drops offline. + * - The remote user calls [`muteLocalAudioStream`]{@link RtcEngine.muteLocalAudioStream}. + * - The remote user calls [`disableAudio`]{@link RtcEngine.disableAudio}. + * + * @event FirstRemoteAudioDecoded + */ + FirstRemoteAudioDecoded: UidWithElapsedCallback; + + /** + * Occurs when a remote user stops/resumes sending the audio stream. + * + * @deprecated + * Use the [`RemoteAudioStateChanged`]{@link RemoteAudioStateChanged} callback with the following parameters instead: + * - [`Stopped`]{@link VideoRemoteState.Stopped} and [`RemoteMuted`]{@link VideoRemoteStateReason.RemoteMuted}. + * - [`Decoding`]{@link VideoRemoteState.Decoding} and [`RemoteUnmuted`]{@link VideoRemoteStateReason.RemoteUnmuted}. + * + * The SDK triggers this callback when the remote user stops or resumes sending the audio stream by calling the [`muteLocalAudioStream`]{@link RtcEngine.muteLocalAudioStream} method. + * + * **Note** + * + * This callback is invalid when the number of users or hosts in the channel exceeds 17. + * + * @event UserMuteAudio + */ + UserMuteAudio: UidWithMutedCallback; + + /** + * Reports the result of calling [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl}. + * + * @deprecated + * + * Use [`RtmpStreamingStateChanged`]{@link RtmpStreamingStateChanged} instead. + * + * This callback indicates whether you have successfully added an RTMP stream to the CDN. + * + * @event StreamPublished + */ + StreamPublished: UrlWithErrorCallback; + + /** + * Reports the result of calling [`removePublishStreamUrl`]{@link RtcEngine.removePublishStreamUrl}. + * + * @deprecated + * + * Use [`RtmpStreamingStateChanged`]{@link RtmpStreamingStateChanged} instead. + * + * This callback indicates whether you have successfully removed an RTMP stream from the CDN. + * + * @event StreamUnpublished + */ + StreamUnpublished: UrlCallback; + + /** + * Reports the transport-layer statistics of each remote audio stream. + * + * @deprecated + * + * This callback is deprecated. Use [`RemoteAudioStats`]{@link RemoteAudioStats} instead. + * + * This callback reports the transport-layer statistics, such as the packet loss rate and time delay, + * once every two seconds after the local user receives an audio packet from a remote user. + * + * @event RemoteAudioTransportStats + */ + RemoteAudioTransportStats: TransportStatsCallback; + + /** + * Reports the transport-layer statistics of each remote video stream. + * + * @deprecated + * + * This callback is deprecated. Use [`RemoteVideoStats`]{@link RemoteVideoStats} instead. + * + * This callback reports the transport-layer statistics, such as the packet loss rate and time delay, + * once every two seconds after the local user receives the video packet from a remote user. + * + * @event RemoteVideoTransportStats + */ + RemoteVideoTransportStats: TransportStatsCallback; + + /** + * Occurs when a remote user enables/disables the video module. + * + * @deprecated + * This callback is deprecated and replaced by the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback with the following parameters: + * - [`Stopped`]{@link VideoRemoteState.Stopped} and [`RemoteMuted`]{@link VideoRemoteStateReason.RemoteMuted}. + * - [`Decoding`]{@link VideoRemoteState.Decoding} and [`RemoteUnmuted`]{@link VideoRemoteStateReason.RemoteUnmuted}. + * + * Once the video module is disabled, the remote user can only use a voice call. The remote user cannot send or receive any video from other users. + * + * The SDK triggers this callback when the remote user enables or disables the video module by calling the [`enableVideo`]{@link RtcEngine.enableVideo} or [`disableVideo`]{@link RtcEngine.disableVideo} method. + * + * **Note** + * + * This callback is invalid when the number of users or hosts in the channel exceeds 17. + * + * @event UserEnableVideo + */ + UserEnableVideo: UidWithEnabledCallback; + + /** + * Occurs when a remote user enables/disables the local video capture function. + * + * @deprecated + * + * This callback is deprecated and replaced by the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback with the following parameters: + * - [`Stopped`]{@link VideoRemoteState.Stopped} and [`RemoteMuted`]{@link VideoRemoteStateReason.RemoteMuted}. + * - [`Decoding`]{@link VideoRemoteState.Decoding} and [`RemoteUnmuted`]{@link VideoRemoteStateReason.RemoteUnmuted}. + * + * The SDK triggers this callback when the remote user resumes or stops capturing the video stream by + * calling [`enableLocalVideo`]{@link RtcEngine.enableLocalVideo}. + * + * This callback is only applicable to the scenario when the remote user only wants to watch the remote video without sending any video stream to the other user. + * + * @event UserEnableLocalVideo + */ + UserEnableLocalVideo: UidWithEnabledCallback; + + /** + * Occurs when the first remote video frame is received and decoded. + * + * @deprecated + * + * This callback is deprecated. Use [`Starting`]{@link VideoRemoteState.Starting} or [`Decoding`]{@link VideoRemoteState.Decoding} in the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback instead. + * + * This callback is triggered in either of the following scenarios: + * - The remote user joins the channel and sends the video stream. + * - The remote user stops sending the video stream and re-sends it after 15 seconds. Possible reasons include: + * - The remote user leaves channel. + * - The remote user drops offline. + * - The remote user calls [`muteLocalVideoStream`]{@link RtcEngine.muteLocalVideoStream}. + * - The remote user calls [`disableVideo`]{@link RtcEngine.disableVideo}. + * + * @event FirstRemoteVideoDecoded + */ + FirstRemoteVideoDecoded: VideoFrameWithUidCallback; + + /** + * Occurs when the microphone is enabled/disabled. + * + * @deprecated + * + * This callback is deprecated. Use [`Stopped`]{@link AudioLocalState.Stopped} or [`Recording`]{@link AudioLocalState.Recording} in the [`LocalAudioStateChanged`]{@link LocalAudioStateChanged} callback instead. + * + * The SDK triggers this callback when the local user resumes or stops capturing the local audio stream by calling [`enableLocalAudio`]{@link RtcEngine.enableLocalAudio}. + * + * @event MicrophoneEnabled + */ + MicrophoneEnabled: EnabledCallback; + + /** + * Occurs when the connection between the SDK and the server is interrupted. + * + * @deprecated + * + * Use {@link ConnectionStateChanged} instead. + * + * The SDK triggers this callback when it loses connection to the server for more than four seconds after + * the connection is established. After triggering this callback, the SDK tries to reconnect to the server. + * You can use this callback to implement pop-up reminders. This callback is different from [`ConnectionLost`]{@link ConnectionLost}: + * - The SDK triggers the [`ConnectionInterrupted`]{@link ConnectionInterrupted} callback when the SDK loses + * connection with the server for more than four seconds after it joins the channel. + * - The SDK triggers the [`ConnectionLost`]{@link ConnectionLost} callback when it loses connection with + * the server for more than 10 seconds, regardless of whether it joins the channel or not. + * + * If the SDK fails to rejoin the channel 20 minutes after being disconnected from Agora's edge server, the SDK stops rejoining the channel. + * + * @event ConnectionInterrupted + */ + ConnectionInterrupted: EmptyCallback; + + /** + * Occurs when your connection is banned by the Agora Server. + * + * @deprecated + * + * Use [`ConnectionStateChanged`]{@link ConnectionStateChanged} instead. + * + * @event ConnectionBanned + */ + ConnectionBanned: EmptyCallback; + + /** + * Reports the statistics of the audio stream from each remote user/host. + * + * @deprecated + * + * Use [`RemoteAudioStats`]{@link RemoteAudioStats} instead. + * + * The SDK triggers this callback once every two seconds to report the audio quality of each remote user/host sending an audio stream. If a channel has multiple remote users/hosts sending audio streams, the SDK trggers this callback as many times. + * + * @event AudioQuality + */ + AudioQuality: AudioQualityCallback; + + /** + * Occurs when the camera is turned on and ready to capture video. + * + * @deprecated + * + * Use [`Capturing`]{@link LocalVideoStreamState.Capturing} in the [`LocalVideoStateChanged`]{@link LocalVideoStateChanged} callback instead. + * If the camera fails to turn on, fix the error reported in the [`Error`]{@link Error} callback. + * + * @event CameraReady + */ + CameraReady: EmptyCallback; + + /** + * Occurs when the video stops playing. + * + * @deprecated + * + * Use [`Stopped`]{@link LocalVideoStreamState.Stopped} in the [`LocalVideoStateChanged`]{@link LocalVideoStateChanged} callback instead. + * The application can use this callback to change the configuration of the view (for example, displaying other pictures in the view) + * after the video stops playing. + * + * @event VideoStopped + */ + VideoStopped: EmptyCallback; + + /** + * Occurs when the local user receives the metadata. + * + * @event MetadataReceived + */ + MetadataReceived: MetadataCallback; + + /** + * Occurs when the first audio frame is published. + * + * @since v3.1.2. + * + * The SDK triggers this callback under one of the following circumstances: + * - The local client enables the audio module and calls [`joinChannel`]{@link joinChannel} successfully. + * - The local client calls [`muteLocalAudioStream(true)`]{@link RtcEngine.muteLocalAudioStream} and [`muteLocalAudioStream(false)`]{@link RtcEngine.muteLocalAudioStream} in sequence. + * - The local client calls [`disableAudio`]{@link RtcEngine.disableAudio} and [`enableAudio`]{@link RtcEngine.enableAudio} in sequence. + */ + FirstLocalAudioFramePublished: ElapsedCallback; + + /** + * Occurs when the first video frame is published. + * + * @since v3.1.2. + * + * The SDK triggers this callback under one of the following circumstances: + * - The local client enables the video module and calls [`joinChannel`]{@link joinChannel} successfully. + * - The local client calls [`muteLocalVideoStream(true)`]{@link RtcEngine.muteLocalVideoStream} and [`muteLocalVideoStream(false)`]{@link RtcEngine.muteLocalVideoStream} in sequence. + * - The local client calls [`disableVideo`]{@link RtcEngine.disableVideo} and [`enableVideo`]{@link RtcEngine.enableVideo} in sequence. + */ + FirstLocalVideoFramePublished: ElapsedCallback; + + /** + * Occurs when the audio publishing state changes. + * + * @since v3.1.2. + * + * This callback indicates the publishing state change of the local audio stream. + */ + AudioPublishStateChanged: StreamPublishStateCallback; + + /** + * Occurs when the video publishing state changes. + * + * @since v3.1.2. + * + * This callback indicates the publishing state change of the local video stream. + */ + VideoPublishStateChanged: StreamPublishStateCallback; + + /** + * Occurs when the audio subscribing state changes. + * + * @since v3.1.2. + * + * This callback indicates the subscribing state change of a remote audio stream. + */ + AudioSubscribeStateChanged: StreamSubscribeStateCallback; + + /** + * Occurs when the video subscribing state changes. + * + * @since v3.1.2. + * + * This callback indicates the subscribing state change of a remote video stream. + */ + VideoSubscribeStateChanged: StreamSubscribeStateCallback; + + /** + * Reports events during the RTMP streaming. + * + * @since v3.1.2. + */ + RtmpStreamingEvent: RtmpStreamingEventCallback; +} + +/** + * The [`RtcChannelEvents`]{@link RtcChannelEvents} interface. + */ +export interface RtcChannelEvents { + /** + * Reports the warning code of the [`RtcChannel`]{@link RtcChannel} instance. + * + * @event Warning + */ + Warning: WarningCallback; + + /** + * Reports the error code of the [`RtcChannel`]{@link RtcChannel} instance. + * + * @event Error + */ + Error: ErrorCallback; + + /** + * Occurs when the local user joins a specified channel. + * + * If the uid is not specified when calling [`joinChannel`]{@link RtcChannel.joinChannel}, the + * server automatically assigns a uid. + * + * @event JoinChannelSuccess + */ + JoinChannelSuccess: UidWithElapsedCallback; + + /** + * Occurs when a user rejoins the channel after being disconnected due to network problems. + * + * When a user loses connection with the server because of network problems, the SDK automatically tries + * to reconnect and triggers this callback upon reconnection. + * + * @event RejoinChannelSuccess + */ + RejoinChannelSuccess: UidWithElapsedCallback; + + /** + * Occurs when a user leaves the channel. + * + * When a user leaves the channel by using the [`leaveChannel`]{@link RtcChannel.leaveChannel} method, the SDK uses this callback to notify the app when the user leaves the channel. + * + * With this callback, the app retrieves the channel information, such as the call duration and statistics. + * + * @event LeaveChannel + */ + LeaveChannel: RtcStatsCallback; + + /** + * Occurs when the user role switches in a live interactive streaming channel. For example, from a host to an audience member or vice versa. + * + * The SDK triggers this callback when the local user switches the user role by calling the [`setClientRole`]{@link RtcChannel.setClientRole} method after joining the channel. + * + * @event ClientRoleChanged + */ + ClientRoleChanged: ClientRoleCallback; + + /** + * Occurs when a remote user (`Communication`) or a host (`LiveBroadcasting`) joins the channel. + * - `Communication` profile: This callback notifies the app when another user joins the channel. If other users are already in the channel, the SDK also reports to the app on the existing users. + * - `LiveBroadcasting` profile: This callback notifies the app when the host joins the channel. If other hosts are already in the channel, the SDK also reports to the app on the existing hosts. We recommend having at most 17 hosts in a channel. + * + * The SDK triggers this callback under one of the following circumstances: + * - A remote user/host joins the channel by calling [`joinChannel`]{@link RtcChannel.joinChannel}. + * - A remote user switches the user role to the host by calling [`setClientRole`]{@link RtcChannel.setClientRole} after joining the channel. + * - A remote user/host rejoins the channel after a network interruption. + * - The host injects an online media stream into the channel by calling [`addInjectStreamUrl`]{@link RtcChannel.addInjectStreamUrl}. + * + * **Note** + * - In the `LiveBroadcasting` profile: + * - The host receives this callback when another host joins the channel. + * - The audience in the channel receives this callback when a new host joins the channel. + * - When a web app joins the channel, this callback is triggered as long as the web app publishes streams. + * + * @event UserJoined + */ + UserJoined: UidWithElapsedCallback; + + /** + * Occurs when a remote user (`Communication`) or a host (`LiveBroadcasting`) leaves the channel. + * + * There are two reasons for users to become offline: + * - Leave the channel: When the user/host leaves the channel, the user/host sends a goodbye message. When this message is received, the SDK determines that the user/host leaves the channel. + * - Go offline: When no data packet of the user or host is received for a certain period of time (around 20 seconds), the SDK assumes that the user/host drops offline. A poor network connection may lead to false detections, so we recommend using the Agora RTM SDK for reliable offline detection. + * + * @event UserOffline + */ + UserOffline: UserOfflineCallback; + + /** + * Occurs when the network connection state changes. + * + * The Agora SDK triggers this callback to report on the current network connection state when it changes, + * and the reason to such change. + * + * @event ConnectionStateChanged + */ + ConnectionStateChanged: ConnectionStateCallback; + + /** + * Occurs when the SDK cannot reconnect to Agora's edge server 10 seconds after its connection to the server is interrupted. + * + * The SDK also triggers this callback when it cannot connect to the server 10 seconds after calling [`joinChannel`]{@link RtcChannel.joinChannel}, regardless of whether it is in the channel or not. + * + * If the SDK fails to rejoin the channel 20 minutes after being disconnected from Agora's edge server, the SDK stops rejoining the channel. + * + * @event ConnectionLost + */ + ConnectionLost: EmptyCallback; + + /** + * Occurs when the token expires in 30 seconds. + * + * The user becomes offline if the token used when joining the channel expires. This callback is + * triggered 30 seconds before the token expires, to remind the app to get a new token. Upon receiving this callback, + * you need to generate a new token on the server and call [`renewToken`]{@link RtcChannel.renewToken} to pass the new token to the SDK. + * + * @event TokenPrivilegeWillExpire + */ + TokenPrivilegeWillExpire: TokenCallback; + + /** + * Occurs when the token has expired. + * + * After a token is specified when joining the channel, the token expires after a certain period of time, + * and a new token is required to reconnect to the server. + * This callback notifies the app to generate a new token and call [`renewToken`]{@link RtcChannel.renewToken} to renew the token. + * + * @event RequestToken + */ + RequestToken: EmptyCallback; + + /** + * Reports which user is the loudest speaker. + * + * This callback reports the speaker with the highest accumulative volume during a certain period. If the user enables the audio volume indication by calling [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication}, this callback returns the uid of the active speaker whose voice is detected by the audio volume detection module of the SDK. + * + * **Note** + * - To receive this callback, you need to call [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication}. + * - This callback reports the ID of the user with the highest voice volume during a period of time, instead of at the moment. + * + * @event ActiveSpeaker + */ + ActiveSpeaker: UidCallback; + + /** + * Occurs when the video size or rotation information of a remote user changes. + * + * @event VideoSizeChanged + */ + VideoSizeChanged: VideoSizeCallback; + + /** + * Occurs when the remote video state changes. + * + * @event RemoteVideoStateChanged + */ + RemoteVideoStateChanged: RemoteVideoStateCallback; + + /** + * Occurs when the remote audio state changes. + * + * This callback indicates the state change of the remote audio stream. + * + * @event RemoteAudioStateChanged + */ + RemoteAudioStateChanged: RemoteAudioStateCallback; + + /** + * Occurs when the published media stream falls back to an audio-only stream due to poor network conditions or switches back to video stream after the network conditions improve. + * + * If you call [`setLocalPublishFallbackOption`]{@link RtcEngine.setLocalPublishFallbackOption} and set `option` as [`AudioOnly`]{@link StreamFallbackOptions.AudioOnly}, this callback is triggered when the locally published stream falls back to audio-only mode due to poor uplink conditions, or when the audio stream switches back to the video after the uplink network condition improves. + * + * @event LocalPublishFallbackToAudioOnly + */ + LocalPublishFallbackToAudioOnly: FallbackCallback; + + /** + * Occurs when the remote media stream falls back to audio-only stream due to poor network conditions or switches back to video stream after the network conditions improve. + * + * If you call [`setRemoteSubscribeFallbackOption`]{@link RtcEngine.setRemoteSubscribeFallbackOption} and set option as [`AudioOnly`]{@link StreamFallbackOptions.AudioOnly}, this callback is triggered when the remote media stream falls back to audio-only mode due to poor uplink conditions, or when the remote media stream switches back to the video after the uplink network condition improves. + * + * **Note** + * + * Once the remote media stream is switched to the low stream due to poor network conditions, + * you can monitor the stream switch between a high and low stream in the [`RemoteVideoStats`]{@link RemoteVideoStats} callback. + * + * @event RemoteSubscribeFallbackToAudioOnly + */ + RemoteSubscribeFallbackToAudioOnly: FallbackWithUidCallback; + + /** + * Reports the statistics of the [`RtcEngine`]{@link RtcEngine} once every two seconds. + * + * @event RtcStats + */ + RtcStats: RtcStatsCallback; + + /** + * Reports the last mile network quality of each user in the channel once every two seconds. + * + * Last mile refers to the connection between the local device and Agora's edge server. This callback reports once every two seconds the last mile network conditions of each user in the channel. If a channel includes multiple users, then this callback will be triggered as many times. + * + * @event NetworkQuality + */ + NetworkQuality: NetworkQualityWithUidCallback; + + /** + * Reports the statistics of the video stream from each remote user/host. The SDK triggers this callback once every two seconds for each remote user/broadcaster. If a channel includes multiple remote users, the SDK triggers this callback as many times. + * + * @event RemoteVideoStats + */ + RemoteVideoStats: RemoteVideoStatsCallback; + + /** + * Reports the statistics of the audio stream from each remote user/host. + * + * The SDK triggers this callback once every two seconds for each remote user/host. If a channel includes multiple remote users, the SDK triggers this callback as many times. + * + * Schemes such as FEC (Forward Error Correction) or retransmission counter the frame loss rate. Hence, users may find the overall audio quality acceptable even when the packet loss rate is high. + * + * @event RemoteAudioStats + */ + RemoteAudioStats: RemoteAudioStatsCallback; + + /** + * Occurs when the state of the RTMP 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. + * + * @event RtmpStreamingStateChanged + */ + RtmpStreamingStateChanged: RtmpStreamingStateCallback; + + /** + * Occurs when the publisher's transcoding settings are updated. + * + * When the `LiveTranscoding` class in the [`setLiveTranscoding`]{@link RtcChannel.setLiveTranscoding} method updates, the SDK triggers this callback to report the update information. + * + * **Note** + * + * If you call [`setLiveTranscoding`]{@link RtcChannel.setLiveTranscoding} to set the `LiveTranscoding` class for the first time, the SDK does not trigger this callback. + * + * @event TranscodingUpdated + */ + TranscodingUpdated: EmptyCallback; + + /** + * Reports the status of injecting the online media stream. + * + * @event StreamInjectedStatus + */ + StreamInjectedStatus: StreamInjectedStatusCallback; + + /** + * Occurs when the local user receives a remote data stream. + * + * The SDK triggers this callback when the local user receives the stream message that the remote user sends by calling the [`sendStreamMessage`]{@link RtcChannel.sendStreamMessage} method. + * + * @event StreamMessage + */ + StreamMessage: StreamMessageCallback; + + /** + * Occurs when the local user fails to receive a remote data stream. + * + * The SDK triggers this callback when the local user fails to receive the stream message that the remote user sends by calling the [`sendStreamMessage`]{@link RtcChannel.sendStreamMessage} method. + * + * @event StreamMessageError + */ + StreamMessageError: StreamMessageErrorCallback; + + /** + * Occurs when the state of the media stream relay changes. + * + * The SDK reports the state of the current media relay and possible error messages in this callback. + * + * @event ChannelMediaRelayStateChanged + */ + ChannelMediaRelayStateChanged: MediaRelayStateCallback; + + /** + * Reports events during the media stream relay. + * + * @event ChannelMediaRelayEvent + */ + ChannelMediaRelayEvent: MediaRelayEventCallback; + + /** + * Occurs when the local user receives the metadata. + * + * @event MetadataReceived + */ + MetadataReceived: MetadataCallback; + + /** + * Occurs when the audio publishing state changes. + * + * @since v3.1.2. + * + * This callback indicates the publishing state change of the local audio stream. + */ + AudioPublishStateChanged: StreamPublishStateCallback; + + /** + * Occurs when the video publishing state changes. + * + * @since v3.1.2. + * + * This callback indicates the publishing state change of the local video stream. + */ + VideoPublishStateChanged: StreamPublishStateCallback; + + /** + * Occurs when the audio subscribing state changes. + * + * @since v3.1.2. + * + * This callback indicates the subscribing state change of a remote audio stream. + */ + AudioSubscribeStateChanged: StreamSubscribeStateCallback; + + /** + * Occurs when the video subscribing state changes. + * + * @since v3.1.2. + * + * This callback indicates the subscribing state change of a remote video stream. + */ + VideoSubscribeStateChanged: StreamSubscribeStateCallback; + + /** + * Reports events during the RTMP streaming. + * + * @since v3.1.2. + */ + RtmpStreamingEvent: RtmpStreamingEventCallback; +} diff --git a/src/common/RtcRenderView.native.tsx b/src/common/RtcRenderView.native.tsx new file mode 100644 index 000000000..e539923ae --- /dev/null +++ b/src/common/RtcRenderView.native.tsx @@ -0,0 +1,129 @@ +import React, { Component } from 'react'; +import { requireNativeComponent, ViewProps } from 'react-native'; + +import type { VideoMirrorMode, VideoRenderMode } from './Enums'; + +/** + * Properties of the uid. + */ +export interface RtcUidProps { + /** User ID. */ + uid: number; +} + +/** + * Properties of the SurfaceView. + */ +export interface RtcSurfaceViewProps { + /** + * Controls whether the SurfaceView's surface is placed on top of another + * regular surface view in the window (but still behind the window itself). + */ + zOrderMediaOverlay?: boolean; + /** + * Controls whether the SurfaceView's surface is placed on top of its window. + */ + zOrderOnTop?: boolean; + /** + * The rendering mode of the video view. + */ + renderMode?: VideoRenderMode; + /** + * The unique channel name for the AgoraRTC session in the string format. + * The string length must be less than 64 bytes. Supported character scopes are: + * - All lowercase English letters: a to z. + * - All uppercase English letters: A to Z. + * - All numeric characters: 0 to 9. + * - The space character. + * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + * + * **Note** + * - The default value is the empty string "". Use the default value if the user joins the channel using the [`joinChannel`]{@link RtcEngine.joinChannel} method in the `RtcEngine` class. + * - If the user joins the channel using the [`joinChannel`]{@link RtcChannel.joinChannel} method in the `RtcChannel` class, set this parameter as the `channelId` of the `RtcChannel` object. + */ + channelId?: string; + /** The video mirror mode. */ + mirrorMode?: VideoMirrorMode; +} + +/** + * Properties of the TextureView. + */ +export interface RtcTextureViewProps { + /** + * The rendering mode of the video view. + */ + renderMode?: VideoRenderMode; + /** + * The unique channel name for the AgoraRTC session in the string format. + * The string length must be less than 64 bytes. Supported character scopes are: + * - All lowercase English letters: a to z. + * - All uppercase English letters: A to Z. + * - All numeric characters: 0 to 9. + * - The space character. + * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". + * + * **Note** + * - The default value is the empty string "". Use the default value if the user joins the channel using the [`joinChannel`]{@link RtcEngine.joinChannel} method in the `RtcEngine` class. + * - If the user joins the channel using the [`joinChannel`]{@link RtcChannel.joinChannel} method in the `RtcChannel` class, set this parameter as the `channelId` of the `RtcChannel` object. + */ + channelId?: string; + /** The video mirror mode. */ + mirrorMode?: VideoMirrorMode; +} + +interface RtcRenderViewProps { + data: { channelId?: string; uid: number }; +} + +/** + * @ignore + */ +const RCTRtcSurfaceView = requireNativeComponent( + 'RCTAgoraRtcSurfaceView' +); + +/** + * @ignore + */ +export class RtcSurfaceView extends Component< + ViewProps & RtcSurfaceViewProps & RtcUidProps, + {} +> { + render() { + const { channelId = undefined, uid, ...others } = this.props; + return ( + + ); + } +} + +/** + * @ignore + */ +const RCTRtcTextureView = requireNativeComponent( + 'RCTAgoraRtcTextureView' +); + +/** + * @ignore + */ +export class RtcTextureView extends Component< + ViewProps & RtcTextureViewProps & RtcUidProps, + {} +> { + render() { + const { channelId = undefined, uid, ...others } = this.props; + return ( + + ); + } +} diff --git a/src/index.ts b/src/index.ts index 55ff6a171..0b9329276 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,9 @@ -import RtcEngine from './src/RtcEngine.native' -import RtcChannel from './src/RtcChannel.native' -import RtcLocalView from './RtcLocalView' -import RtcRemoteView from './RtcRemoteView' +import RtcEngine from './common/RtcEngine.native'; +import RtcChannel from './common/RtcChannel.native'; +import RtcLocalView from './RtcLocalView'; +import RtcRemoteView from './RtcRemoteView'; -export * from './Types' +export * from './Types'; -export default RtcEngine -export { - RtcChannel, - RtcLocalView, - RtcRemoteView -} +export default RtcEngine; +export { RtcChannel, RtcLocalView, RtcRemoteView }; diff --git a/src/src/Classes.ts b/src/src/Classes.ts deleted file mode 100644 index 06a9afb04..000000000 --- a/src/src/Classes.ts +++ /dev/null @@ -1,1280 +0,0 @@ -import { - AudioChannel, - AudioCodecProfileType, - AudioSampleRateType, - CameraCaptureOutputPreference, - CameraDirection, - DegradationPreference, - EncryptionMode, - LastmileProbeResultState, - LighteningContrastLevel, - NetworkQuality, - VideoCodecProfileType, - VideoCodecType, - VideoFrameRate, - VideoMirrorMode, - VideoOutputOrientationMode, - VideoQualityAdaptIndication, - VideoStreamType -} from "./Enums" - -/** - * The user information, including the user ID and user account. - */ -export interface UserInfo { - /** - * The user ID of a user. - */ - uid: number - /** - * The user account of a user. - */ - userAccount: string -} - -/** - * The video resolution. - */ -export class VideoDimensions { - /** - * The video resolution on the horizontal axis. - */ - width: number - /** - * The video resolution on the vertical axis. - */ - height: number - - constructor(width: number, height: number) { - this.width = width - this.height = height - } -} - -/** - * Definition of VideoEncoderConfiguration. - */ -export class VideoEncoderConfiguration { - /** - * The video frame dimensions (px), which is used to specify the video quality and measured by the total number of pixels along a - * frame's width and height. The default value is 640 × 360. - * You can customize the dimension, or select from the following list: - *
    - *
  • 120x120
  • - *
  • 160x120
  • - *
  • 180x180
  • - *
  • 240x180
  • - *
  • 320x180
  • - *
  • 240x240
  • - *
  • 320x240
  • - *
  • 424x240
  • - *
  • 360x360
  • - *
  • 480x360
  • - *
  • 640x360
  • - *
  • 480x480
  • - *
  • 640x480
  • - *
  • 840x480
  • - *
  • 960x720
  • - *
  • 1280x720
  • - *
- * - * **Note** - *
    - *
  • The value of the dimension does not indicate the orientation mode of the output ratio. For how to set the video orientation, see [VideoOutputOrientationMode]{@link VideoOutputOrientationMode}.
  • - *
  • Whether 720p+ can be supported depends on the device. If the device cannot support 720p, the frame rate will be lower than the one listed in the table.
  • - *
- * - */ - dimensions?: VideoDimensions - /** - * The video frame rate (fps). The default value is 15. Users can either set the frame rate manually or choose from the following options. - * We do not recommend setting this to a value greater than 30. - */ - frameRate?: VideoFrameRate - /** - * The minimum video encoder frame rate (fps). The default value is Min(-1) (the SDK uses the lowest encoder frame rate). - */ - minFrameRate?: VideoFrameRate - /** - * Bitrate of the video (Kbps). Refer to the table below and set your bitrate. If you set a bitrate beyond the proper range, the SDK automatically adjusts it to a value within the range. - * You can also choose from the following options: - * - [`Standard`]{@link BitRate.Standard}: (Recommended) The standard bitrate mode. In this mode, the bitrates differ between the `LiveBroadcasting` and `Communication` profiles: - * - In the `Communication` profile, the video bitrate is the same as the base bitrate. - * - In the `LiveBroadcasting` profile, the video bitrate is twice the base bitrate. - * - [`Compatible`]{@link BitRate.Compatible}: The compatible bitrate mode. In this mode, the bitrate stays the same regardless of the profile. If you choose this mode for the `LiveBroadcasting` profile, the video frame rate may be lower than the set value. - * - * Agora uses different video codecs for different profiles to optimize the user experience. For example, the Communication profile prioritizes the smoothness while the `LiveBroadcasting` profile prioritizes the video quality (a higher bitrate). Therefore, We recommend setting this parameter as [`Standard`]{@link BitRate.Standard}. - * - * **Video Bitrate Table** - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
ResolutionFrame rate

(fps)

Base Bitrate

(Kbps, for Communication)

Live Bitrate

(Kbps, for Live Broadcasting)

160*1201565130
120*1201550100
320*18015140280
180*18015100200
240*18015120240
320*24015200400
240*24015140280
424*24015220440
640*36015400800
360*36015260520
640*360306001200
360*36030400800
480*36015320640
480*36030490980
640*480155001000
480*48015400800
640*480307501500
480*480306001200
848*480156101220
848*480309301860
640*48010400800
1280*7201511302260
1280*7203017103420
960*720159101820
960*7203013802760
- * - * **Note** - * - * The base bitrate in this table applies to the Communication profile. - * The `LiveBroadcasting` profile generally requires a higher bitrate for better video quality. - * We recommend setting the bitrate mode as [`Standard`]{@link BitRate.Standard}. You can also set the bitrate as the base bitrate value × 2. - */ - bitrate?: number - /** - * The minimum encoding bitrate (Kbps). The Agora SDK automatically adjusts the encoding bitrate to adapt to the network conditions. Using a value greater than the default value forces the video encoder to output high-quality images but may cause more packet loss and hence sacrifice the smoothness of the video transmission. That said, unless you have special requirements for image quality, - * Agora does not recommend changing this value. - */ - minBitrate?: number - /** - * The orientation mode. - */ - orientationMode?: VideoOutputOrientationMode - /** - * The video encoding degradation preference under limited bandwidth. - */ - degradationPrefer?: DegradationPreference - /** - * Sets the mirror mode of the published local video stream. - */ - mirrorMode?: VideoMirrorMode - - constructor(params?: { dimensions?: VideoDimensions, frameRate?: VideoFrameRate, minFrameRate?: VideoFrameRate, bitrate?: number, minBitrate?: number, orientationMode?: VideoOutputOrientationMode, 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 - } -} - -/** - * Sets the image enhancement options. - */ -export class BeautyOptions { - /** - * The lightening contrast level. - */ - lighteningContrastLevel?: LighteningContrastLevel - /** - * The brightness level. The value ranges between 0.0 (original) and 1.0. The default value is 0.7. - */ - lighteningLevel?: number - /** - * The sharpness level. The value ranges between 0.0 (original) and 1.0. - * The default value is 0.5. This parameter is usually used to remove blemishes. - */ - smoothnessLevel?: number - /** - * The redness level. The value ranges between 0.0 (original) and 1.0. - * The default value is 0.1. This parameter adjusts the red saturation level. - */ - rednessLevel?: number - - constructor(params?: { lighteningContrastLevel?: LighteningContrastLevel, lighteningLevel?: number, smoothnessLevel?: number, rednessLevel?: number }) { - this.lighteningContrastLevel = params?.lighteningContrastLevel - this.lighteningLevel = params?.lighteningLevel - this.smoothnessLevel = params?.smoothnessLevel - this.rednessLevel = params?.rednessLevel - } -} - -/** - * Agora image properties. A class for setting the properties of the watermark and background images. - */ -export class AgoraImage { - /** - * HTTP/HTTPS URL address of the image on the broadcasting video. The maximum length of this parameter is 1024 bytes. - */ - url: string - /** - * Position of the image on the upper left of the broadcasting video on the horizontal axis. - */ - x: number - /** - * Position of the image on the upper left of the broadcasting video on the vertical axis. - */ - y: number - /** - * Width of the image on the broadcasting video. - */ - width: number - /** - * Height of the image on the broadcasting video. - */ - height: number - - constructor(url: string, x: number, y: number, width: number, height: number) { - this.url = url - this.x = x - this.y = y - this.width = width - this.height = height - } -} - -/** - * The transcodingUser class, which defines the audio and video properties in the CDN live. Agora supports a maximum of 17 transcoding users in a CDN live streaming channel. - */ -export class TranscodingUser { - /** - * ID of the user in the CDN live streaming. - */ - uid: number - /** - * Horizontal position of the video frame of the user from the top left corner of the CDN live streaming. - */ - x: number - /** - * Vertical position of the video frame of the user from the top left corner of the CDN live streaming. - */ - y: number - /** - * Width of the video frame of the user on the CDN live streaming. The default value is 360. - */ - width?: number - /** - * Height of the video frame of the user on the CDN live streaming. The default value is 640. - */ - height?: number - /** - * Layer position of video frame of the user on the CDN live streaming. The value ranges between 0 and 100. From v2.3.0, Agora SDK supports setting zOrder as 0. The smallest value is 0 (default value), which means that the video frame is at the bottom layer. The biggest value is 100, which means that the video frame is at the top layer. - */ - zOrder?: number - /** - * The transparency of the video frame of the user in the CDN live streaming that ranges between 0.0 and 1.0. 0.0 means that the video frame is completely transparent and 1.0 means opaque. The default value is 1.0. - */ - alpha?: number - /** - * The audio channel ranging between 0 and 5. The default value is 0. - * - * - 0: (default) Supports dual channels. Depends on the upstream of the broadcaster. - * - 1: The audio stream of the broadcaster uses the FL audio channel. If the broadcaster’s upstream uses multiple audio channels, these channels are mixed into mono first. - * - 2: The audio stream of the broadcaster uses the FC audio channel. If the broadcaster’s upstream uses multiple audio channels, these channels are mixed into mono first. - * - 3: The audio stream of the broadcaster uses the FR audio channel. If the broadcaster’s upstream uses multiple audio channels, these channels are mixed into mono first. - * - 4: The audio stream of the broadcaster uses the BL audio channel. If the broadcaster’s upstream uses multiple audio channels, these channels are mixed into mono first. - * - 5: The audio stream of the broadcaster uses the BR audio channel. If the broadcaster’s upstream uses multiple audio channels, these channels are mixed into mono first. - * - * **Note** - * - * Special players are needed if `audioChannel` is not set as 0. - */ - audioChannel?: AudioChannel - - constructor(uid: number, x: number, y: number, params?: { width?: number, height?: number, zOrder?: number, alpha?: number, audioChannel?: AudioChannel }) { - 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 - } -} - -/** - * Color. - */ -export class Color { - /** - * Red. - */ - red: number - /** - * Green. - */ - green: number - /** - * Blue. - */ - blue: number - - constructor(red: number, green: number, blue: number) { - this.red = red - this.green = green - this.blue = blue - } -} - -/** - * A class for managing user-specific CDN live audio/video transcoding settings. - */ -export class LiveTranscoding { - /** - * Width (pixel) of the video. The default value is 360. If you push video streams to the CDN, set the value of width × height to at least 64 × 64, or the SDK adjusts it to 64 x 64. - * If you push audio streams to the CDN, set the value of width × height to 0 × 0. - */ - width?: number - /** - * Height (pixel) of the video. The default value is 640. If you push video streams to the CDN, set the value of width × height to at least 64 × 64, or the SDK adjusts it to 64 x 64. - * If you push audio streams to the CDN, set the value of width × height to 0 × 0. - */ - height?: number - /** - * Bitrate (Kbps) of the CDN live output video stream. The default value is 400. Set this parameter according to the Video Bitrate Table. If you set a bitrate beyond the proper range, - * the SDK automatically adapts it to a value within the range. - */ - videoBitrate?: number - /** - * Frame rate (fps) of the CDN live output video stream. - * The value range is [0,30]. The default value is 15. Agora adjusts all values over 30 to 30. - */ - videoFramerate?: VideoFrameRate - /** - * @deprecated - * - `true`: Low latency with unassured quality. - * - `false`: (Default) High latency with assured quality. - */ - lowLatency?: boolean - /** - * Gop of the video frames in the CDN live stream. The default value is 30 fps. - */ - videoGop?: number - /** - * The watermark image added to the CDN live publishing stream. Ensure that the format of the image is PNG. Once a watermark image is added, - * the audience of the CDN live publishing stream can see it. - */ - watermark?: AgoraImage - /** - * The background image added to the CDN live publishing stream. Once a background image is added, - * the audience of the CDN live publishing stream can see it. - */ - backgroundImage?: AgoraImage - /** - * Self-defined audio-sample rate: AudioSampleRateType. - */ - audioSampleRate?: AudioSampleRateType - /** - * Bitrate (Kbps) of the CDN live audio output stream. The default value is 48 and the highest value is 128. - */ - audioBitrate?: number - /** - * The number of audio channels for the CDN live stream. - * - * Agora recommends choosing 1 (mono), or 2 (stereo) audio channels. Special players are required if you choose 3, 4, or 5. - * - 1: (Default) Mono - * - 2: Stereo - * - 3: Three audio channels - * - 4: Four audio channels - * - 5: Five audio channels - */ - audioChannels?: AudioChannel - /** - * Audio codec profile type: AudioCodecProfileType. Set it as LC-AAC or HE-AAC. The default value is LC-AAC. - */ - audioCodecProfile?: AudioCodecProfileType - /** - * Video codec profile type: VideoCodecProfileType. Set it as BASELINE, MAIN, or HIGH (default). If you set this parameter to other values, Agora adjusts it to the default value HIGH. - */ - videoCodecProfile?: VideoCodecProfileType - /** - * Sets the background color. - */ - backgroundColor?: Color - /** - * Reserved property. Extra user-defined information to send the Supplemental Enhancement Information (SEI) for the H.264/H.265 video stream to the CDN live client. Maximum length: 4096 Bytes. - */ - userConfigExtraInfo?: string - /** - * An TranscodingUser object managing the user layout configuration in the CDN live stream. Agora supports a maximum of 17 transcoding users in a CDN live stream channel. - */ - transcodingUsers: TranscodingUser[] - - constructor(transcodingUsers: TranscodingUser[], params?: { width?: number, height?: number, videoBitrate?: number, videoFramerate?: VideoFrameRate, lowLatency?: boolean, videoGop?: number, watermark?: AgoraImage, backgroundImage?: AgoraImage, audioSampleRate?: AudioSampleRateType, audioBitrate?: number, audioChannels?: AudioChannel, audioCodecProfile?: AudioCodecProfileType, videoCodecProfile?: VideoCodecProfileType, backgroundColor?: Color, 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 - this.transcodingUsers = transcodingUsers - } -} - -/** - * The ChannelMediaInfo class. - */ -export class ChannelMediaInfo { - /** - * The channel name. - */ - channelName?: string - /** - * The token that enables the user to join the channel. - */ - token?: string - /** - * The user ID. - */ - uid: number - - constructor(uid: number, params?: { channelName?: string, token?: string }) { - this.channelName = params?.channelName - this.token = params?.token - this.uid = uid - } -} - -/** - * The ChannelMediaRelayConfiguration class. - */ -export class ChannelMediaRelayConfiguration { - /** - * The information of the source channel: [`ChannelMediaInfo`]{@link ChannelMediaInfo}. It contains the following members: - * - `channelName`: The name of the source channel. The default value is null, which means the SDK applies the name of the current channel. - * - `uid`: ID of the host whose media stream you want to relay. The default value is 0, which means the SDK generates a random UID. You must set it as 0. - * - `token`: The token for joining the source channel. It is generated with the `channelName` and `uid` you set in `srcInfo`. - * - If you have not enabled the App Certificate, set this parameter as the default value null, which means the SDK applies the App ID. - * - If you have enabled the App Certificate, you must use the token generated with the `channelName` and `uid`, and the `uid` must be set as 0. - */ - srcInfo: ChannelMediaInfo - /** - * The information of the destination channel: [`ChannelMediaInfo`]{@link ChannelMediaInfo}. It contains the following members: - * - `channelName`: The name of the destination channel. - * - `uid`: ID of the host in the destination channel. The value ranges from 0 to (232-1). To avoid UID conflicts, this uid must be different from any other UIDs in the destination channel. The default value is 0, which means the SDK generates a random UID. - * - `token`: The token for joining the source channel. It is generated with the `channelName` and `uid` you set in `destInfo`. - * - If you have not enabled the App Certificate, set this parameter as the default value null, which means the SDK applies the App ID. - * - If you have enabled the App Certificate, you must use the token generated with the `channelName` and `uid`, and the `uid` must be set as 0. - */ - destInfos: ChannelMediaInfo[] - - constructor(srcInfo: ChannelMediaInfo, destInfos: ChannelMediaInfo[]) { - this.srcInfo = srcInfo - this.destInfos = destInfos - } -} - -/** - * Lastmile probe configuration. - */ -export class LastmileProbeConfig { - /** - * Whether to probe uplink of lastmile. i.e., audience don't need probe uplink bandwidth. - */ - probeUplink: boolean - /** - * Whether to probe downlink of lastmile. - */ - probeDownlink: boolean - /** - * The expected maximum sending bitrate in bps in range of [100000,5000000]. It is recommended to set this value according to the required bitrate of selected video profile. - */ - expectedUplinkBitrate: number - /** - * The expected maximum receive bitrate in bps in range of [100000,5000000]. - */ - expectedDownlinkBitrate: number - - constructor(probeUplink: boolean, probeDownlink: boolean, expectedUplinkBitrate: number, expectedDownlinkBitrate: number) { - this.probeUplink = probeUplink - this.probeDownlink = probeDownlink - this.expectedUplinkBitrate = expectedUplinkBitrate - this.expectedDownlinkBitrate = expectedDownlinkBitrate - } -} - -/** - * The position and size of the watermark image. - */ -export class Rectangle { - /** - * The horizontal offset from the top-left corner. - */ - x: number - /** - * The vertical offset from the top-left corner. - */ - y: number - /** - * The width (pixels) of the watermark image. - */ - width: number - /** - * The height (pixels) of the watermark image. - */ - height: number - - constructor(x: number, y: number, width: number, height: number) { - this.x = x - this.y = y - this.width = width - this.height = height - } -} - -/** - * Agora watermark options. A class for setting the properties of watermark. - */ -export class WatermarkOptions { - /** - * Sets whether or not the watermark image is visible in the local video preview: - * - `true`: (Default) The watermark image is visible in preview. - * - `false`: The watermark image is not visible in preview. - */ - visibleInPreview?: boolean - /** - * The watermark position in the landscape mode. - */ - positionInLandscapeMode: Rectangle - /** - * The watermark position in the portrait mode. - */ - positionInPortraitMode: Rectangle - - constructor(positionInLandscapeMode: Rectangle, positionInPortraitMode: Rectangle, visibleInPreview?: boolean) { - this.visibleInPreview = visibleInPreview - this.positionInLandscapeMode = positionInLandscapeMode - this.positionInPortraitMode = positionInPortraitMode - } -} - -/** - * Configuration of the imported live interactive voice or video stream. - */ -export class LiveInjectStreamConfig { - /** - * Width (pixels) of the added stream to the live interactive streaming. The default value is 0, which is the same width as the original stream. - */ - width?: number - /** - * Height (pixels) of the added stream to the live interactive streaming. The default value is 0, which is the same height as the original stream. - */ - height?: number - /** - * Video GOP of the added stream to the live interactive streaming. The default value is 30 frames. - */ - videoGop?: number - /** - * Video frame rate of the added stream to the live interactive streaming. The default value is 15 fps. - */ - videoFramerate?: VideoFrameRate - /** - * Video bitrate of the added stream to the live interactive streaming. The default value is 400 Kbps. - * - * **Note** - * - * The setting of the video bitrate is closely linked to the resolution. If you set the video bitrate beyond a reasonable range, the SDK sets it within a reasonable range instead. - */ - videoBitrate?: number - /** - * Audio sample rate of the added stream to the live interactive streaming. The default value is 44100 Hz. - * - * **Note** - * - * We recommend you use the default value and not reset it. - */ - audioSampleRate?: AudioSampleRateType - /** - * Audio bitrate of the added stream to the live interactive streaming. The default value is 48 Kbps. - * - * **Note** - * - * We recommend you use the default value and not reset it. - */ - audioBitrate?: number - /** - * Audio channels to add into the live streaming. The value ranges between 1 and 2. The default value is 1. - * - * **Note** - * - * We recommend you use the default value and not reset it. - */ - audioChannels?: AudioChannel - - constructor(params?: { width?: number, height?: number, videoGop?: number, videoFramerate?: VideoFrameRate, videoBitrate?: number, audioSampleRate?: AudioSampleRateType, 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 - } -} - -/** - * The definition of CameraCapturerConfiguration. - */ -export class CameraCapturerConfiguration { - /** - * The camera capturer configuration. - */ - preference: CameraCaptureOutputPreference - /** - * The camera direction. - */ - cameraDirection: CameraDirection - - constructor(preference: CameraCaptureOutputPreference, cameraDirection: CameraDirection) { - this.preference = preference - this.cameraDirection = cameraDirection - } -} - -/** - * The channel media options. - */ -export class ChannelMediaOptions { - /** - * Determines whether to subscribe to audio streams when the user joins the channel. - * - `true`: (Default) Subscribe. - * - `false`: Do not subscribe. - * - * This member serves a similar function to the [`muteAllRemoteAudioStreams`]{@link RtcEngine.muteAllRemoteAudioStreams} method. After joining the channel, you can call the `muteAllRemoteAudioStreams` method to set whether to subscribe to audio streams in the channel. - */ - autoSubscribeAudio: boolean - /** - * Determines whether to subscribe to video streams when the user joins the channel. - * - `true`: (Default) Subscribe. - * - `false`: Do not subscribe. - * - * This member serves a similar function to the [`muteAllRemoteVideoStreams`]{@link RtcEngine.muteAllRemoteVideoStreams} method. After joining the channel, you can call the `muteAllRemoteVideoStreams` method to set whether to subscribe to audio streams in the channel. - */ - autoSubscribeVideo: boolean - - constructor(autoSubscribeAudio: boolean, autoSubscribeVideo: boolean) { - this.autoSubscribeAudio = autoSubscribeAudio - this.autoSubscribeVideo = autoSubscribeVideo - } -} - -/** - * Definition of `EncryptionConfig`. - * - * @since v3.1.2. - */ -export class EncryptionConfig { - /** - * Encryption mode. The default encryption mode is `AES128XTS`. See [`EncryptionMode`]{@link EncryptionMode}. - */ - encryptionMode: EncryptionMode - /** - * Encryption key in string type. - * - * **Note** - * - * If you do not set an encryption key or set it as null, you cannot use the built-in encryption, and the SDK returns [`InvalidArgument(2)`]{@link ErrorCode.InvalidArgument}. - */ - encryptionKey: string - - constructor(encryptionMode: EncryptionMode, encryptionKey: string) { - this.encryptionMode = encryptionMode - this.encryptionKey = encryptionKey - } -} - -/** - * Statistics of the call. - */ -export interface RtcStats { - /** - * Call duration in seconds, represented by an aggregate value. - */ - totalDuration: number - /** - * Total number of bytes transmitted, represented by an aggregate value. - */ - txBytes: number - /** - * Total number of bytes received, represented by an aggregate value. - */ - rxBytes: number - /** - * Total number of audio bytes sent (bytes), represented by an aggregate value. - */ - txAudioBytes: number - /** - * Total number of video bytes sent (bytes), represented by an aggregate value. - */ - txVideoBytes: number - /** - * Total number of audio bytes received (bytes), represented by an aggregate value. - */ - rxAudioBytes: number - /** - * Total number of video bytes received (bytes), represented by an aggregate value. - */ - rxVideoBytes: number - /** - * Transmission bitrate in Kbps, represented by an instantaneous value. - */ - txKBitRate: number - /** - * Receive bitrate (Kbps), represented by an instantaneous value. - */ - rxKBitRate: number - /** - * The transmission bitrate of the audio packet (Kbps), represented by an instantaneous value. - */ - txAudioKBitRate: number - /** - * Audio receive bitrate (Kbps), represented by an instantaneous value. - */ - rxAudioKBitRate: number - /** - * Video transmission bitrate (Kbps), represented by an instantaneous value. - */ - txVideoKBitRate: number - /** - * Video receive bitrate (Kbps), represented by an instantaneous value. - */ - rxVideoKBitRate: number - /** - * The number of users in the channel. - * - `COMMUNICATION` profile: The number of users in the channel. - * - `LiveBroadcasting` profile: - * - If the local user is an audience member: The number of users in the channel = The number of hosts in the channel + 1. - * - If the local user is a host: The number of users in the channel = The number of hosts in the channel. - */ - users: number - /** - * Client-server latency. - */ - lastmileDelay: number - /** - * The packet loss rate (%) from the local client to Agora's edge server, before network countermeasures. - */ - txPacketLossRate: number - /** - * The packet loss rate (%) from Agora's edge server to the local client, before network countermeasures. - */ - rxPacketLossRate: number - /** - * System CPU usage (%). - */ - cpuTotalUsage: number - /** - * Application CPU usage (%). - */ - cpuAppUsage: number - /** - * The round-trip time delay from the client to the local router. - * - * **Note** - * (iOS only) Since v3.1.2, this parameter is disabled by default. See [FAQ](https://docs.agora.io/en/faq/local_network_privacy) for details. If you need to enable this parameter, contact support@agora.io. - */ - gatewayRtt: number - /** - * The memory usage ratio of the app (%). - * - * **Note** - * - * This value is for reference only. Due to system limitations, you may not get the value of this member. - */ - memoryAppUsageRatio: number - /** - * The memory usage ratio of the system (%). - * - * **Note** - * - * This value is for reference only. Due to system limitations, you may not get the value of this member. - */ - memoryTotalUsageRatio: number - /** - * The memory usage of the app (KB). - * - * **Note** - * - * This value is for reference only. Due to system limitations, you may not get the value of this member. - */ - memoryAppUsageInKbytes: number -} - -/** - * Properties of the audio volume information. An array containing the user ID and volume information for each speaker. - */ -export interface AudioVolumeInfo { - /** - * The user ID of the speaker. The uid of the local user is 0. - */ - uid: number - /** - * The sum of the voice volume and audio-mixing volume of the speaker. The value ranges between 0 (lowest volume) and 255 (highest volume). - */ - volume: number - /** - * Voice activity status of the local user. - * - 0: The local user is not speaking. - * - 1: The local user is speaking. - * - * **Note** - * - The `vad` parameter cannot report the voice activity status of the remote users. In the remote users' callback, `vad` = 0. - * - Ensure that you set `report_vad(true)` in the [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication} method to enable the voice activity detection of the local user. - */ - vad: number - /** - * The channel ID, which indicates which channel the speaker is in. - */ - channelId: string -} - -/** - * The rectangular area. - */ -export interface Rect { - /** - * The horizontal coordinate of the left side of the rectangular area. - */ - left: number - /** - * The vertical coordinate of the upper side of the rectangular area. - */ - top: number - /** - * The horizontal coordinate of the right side of the rectangular area. - */ - right: number - /** - * The vertical coordinate of the bottom side of the rectangular area. - */ - bottom: number -} - -/** - * The one-way last-mile probe result. - */ -export interface LastmileProbeOneWayResult { - /** - * The packet loss rate (%). - */ - packetLossRate: number - /** - * The network jitter (ms). - */ - jitter: number - /** - * The estimated available bandwidth (bps). - */ - availableBandwidth: number -} - -/** - * Statistics of the lastmile probe. - */ -export interface LastmileProbeResult { - /** - * The state of the probe test. - */ - state: LastmileProbeResultState - /** - * The round-trip delay time (ms). - */ - rtt: number - /** - * The uplink last-mile network report. - */ - uplinkReport: LastmileProbeOneWayResult - /** - * The downlink last-mile network report. - */ - downlinkReport: LastmileProbeOneWayResult -} - -/** - * Statistics of the local audio stream. - */ -export interface LocalAudioStats { - /** - * The number of channels. - */ - numChannels: number - /** - * The sample rate (Hz). - */ - sentSampleRate: number - /** - * The average sending bitrate (Kbps). - */ - sentBitrate: number - /** - * The video packet loss rate (%) from the local client to the Agora edge server before applying the anti-packet loss strategies. - * - * @since v3.1.2. - */ - txPacketLossRate: number -} - -/** - * Statistics of the local video. - */ -export interface LocalVideoStats { - /** - * Bitrate (Kbps) sent in the reported interval, which does not include the bitrate of the re-transmission video after the packet loss. - */ - sentBitrate: number - /** - * Frame rate (fps) sent in the reported interval, which does not include the frame rate of the re-transmission video after the packet loss. - */ - sentFrameRate: number - /** - * The encoder output frame rate (fps) of the local video. - */ - encoderOutputFrameRate: number - /** - * The renderer output frame rate (fps) of the local video. - */ - rendererOutputFrameRate: number - /** - * The target bitrate (Kbps) of the current encoder. This value is estimated by the SDK based on the current network conditions. - */ - targetBitrate: number - /** - * The target frame rate (fps) of the current encoder. - */ - targetFrameRate: number - /** - * Quality change of the local video in terms of target frame rate and target bit rate since last count. - */ - qualityAdaptIndication: VideoQualityAdaptIndication - /** - * The encoding bitrate (Kbps), which does not include the bitrate of the re-transmission video after packet loss. - */ - encodedBitrate: number - /** - * The width of the encoding frame (px). - */ - encodedFrameWidth: number - /** - * The height of the encoding frame (px). - */ - encodedFrameHeight: number - /** - * The value of the sent frame rate, represented by an aggregate value. - */ - encodedFrameCount: number - /** - * The codec type of the local video. - */ - codecType: VideoCodecType - /** - * The video packet loss rate (%) from the local client to the Agora edge server before applying the anti-packet loss strategies. - * - * @since v3.1.2. - */ - txPacketLossRate: number, - /** - * The capture frame rate (fps) of the local video. - * - * @since v3.1.2. - */ - captureFrameRate: number, -} - -/** - * Statistics of the remote audio. - */ -export interface RemoteAudioStats { - /** - * User ID of the user sending the audio streams. - */ - uid: number - /** - * Audio quality received by the user. - */ - quality: NetworkQuality - /** - * Network delay (ms) from the sender to the receiver. - */ - networkTransportDelay: number - /** - * Network delay (ms) from the receiver to the jitter buffer. - */ - jitterBufferDelay: number - /** - * Packet loss rate in the reported interval. - */ - audioLossRate: number - /** - * The number of channels. - */ - numChannels: number - /** - * The sample rate (Hz) of the received audio stream in the reported interval. - */ - receivedSampleRate: number - /** - * The average bitrate (Kbps) of the received audio stream in the reported interval. - */ - receivedBitrate: number - /** - * The total freeze time (ms) of the remote audio stream after the remote user joins the channel. In the reported interval, audio freeze occurs when the audio frame loss rate reaches 4%. totalFrozenTime = The audio freeze time × 2 × 1000 (ms). - */ - totalFrozenTime: number - /** - * The total audio freeze time as a percentage (%) of the total time when the audio is available. - */ - frozenRate: number - /** - * The total time (ms) when the remote user in the `Communication` profile or the remote broadcaster in the `LiveBroadcasting` profile neither stops sending the audio stream nor disables the audio module after joining the channel. - */ - totalActiveTime: number - /** - * The total active time (ms) of the remote audio stream after the remote user publish the audio stream. - * - * @since v3.1.2. - * - */ - publishDuration: number -} - -/** - * Statistics of the remote video. - */ -export interface RemoteVideoStats { - - /** - * User ID of the user sending the video streams. - */ - uid: number - /** - * @deprecated - * - * Time delay (ms). In scenarios where audio and video is synchronized, you can use the value - * of `networkTransportDelay` and `jitterBufferDelay` - * in [`RemoteAudioStats`]{@link RemoteAudioStats} to know the delay statistics of the remote video. - */ - delay: number - /** - * Width (pixels) of the remote video. - */ - width: number - /** - * Height (pixels) of the remote video. - */ - height: number - /** - * Bitrate (Kbps) received in the reported interval. - */ - receivedBitrate: number - /** - * The decoder output frame rate (fps) of the remote video. - */ - decoderOutputFrameRate: number - /** - * The renderer output frame rate (fps) of the remote video. - */ - rendererOutputFrameRate: number - /** - * Packet loss rate (%) of the remote video stream after network countermeasures. - */ - packetLossRate: number - /** - * Video stream type (high-stream or low-stream). - */ - rxStreamType: VideoStreamType - /** - * The total freeze time (ms) of the remote video stream after the remote user joins the channel. - * - * In a video session where the frame rate is set to no less than 5 fps, video freeze occurs when the time interval between two adjacent - * renderable video frames is more than 500 ms. - */ - totalFrozenTime: number - /** - * The total video freeze time (`totalFrozenTime`) as a percentage (%) of the total active time of the remote video stream (`totalActiveTime`). - */ - frozenRate: number - /** - * The total time (ms) when the remote user in the Communication profile or the remote broadcaster in the Live-broadcast profile neither stops sending the video stream nor disables the video module after joining the channel. - */ - totalActiveTime: number - /** - * The total publish duration (ms) of the remote video stream. - * - * @since v3.1.2. - * - */ - publishDuration: number -} - -/** - * The information of the detected human face. - */ -export interface FacePositionInfo { - /** - * The x coordinate (px) of the human face in the local video. Taking the top left corner of the captured video as the origin, - * the x coordinate represents the relative lateral displacement of the top left corner of the human face to the origin. - */ - x: number - /** - * The y coordinate (px) of the human face in the local video. Taking the top left corner of the captured video as the origin, - * the y coordinate represents the relative longitudinal displacement of the top left corner of the human face to the origin. - */ - y: number - /** - * The width (px) of the human face in the captured video. - */ - width: number - /** - * The height (px) of the human face in the captured video. - */ - height: number - /** - * The distance (cm) between the human face and the screen. - */ - distance: number -} diff --git a/src/src/Enums.ts b/src/src/Enums.ts deleted file mode 100644 index 302a592ff..000000000 --- a/src/src/Enums.ts +++ /dev/null @@ -1,2367 +0,0 @@ -/** - * Regions for connection. - */ -export enum AreaCode { - /** - * Mainland China - */ - CN = 0x00000001, - /** - * North America - */ - NA = 0x00000002, - /** - * Europe - */ - EU = 0x00000004, - /** - * Asia, excluding Mainland China - */ - AS = 0x00000008, - /** - * Japan - */ - JP = 0x00000010, - /** - * India - */ - IN = 0x00000020, - /** - * (Default) Global - */ - GLOB = -1, -} - -/** - * Audio codec profile. - */ -export enum AudioCodecProfileType { - /** - * 0: (Default) LC-AAC, which is the low-complexity audio codec profile. - */ - LCAAC = 0, - /** - * 1: HE-AAC, which is the high-efficiency audio codec profile. - */ - HEAAC = 1, -} - -/** - * Audio equalization band frequency. - */ -export enum AudioEqualizationBandFrequency { - /** - * 0: 31 Hz. - */ - Band31 = 0, - /** - * 1: 62 Hz. - */ - Band62 = 1, - /** - * 2: 125 Hz. - */ - Band125 = 2, - /** - * 3: 250 Hz. - */ - Band250 = 3, - /** - * 4: 500 Hz. - */ - Band500 = 4, - /** - * 5: 1 kHz. - */ - Band1K = 5, - /** - * 6: 2 kHz. - */ - Band2K = 6, - /** - * 7: 4 kHz. - */ - Band4K = 7, - /** - * 8: 8 kHz. - */ - Band8K = 8, - /** - * 9: 16 kHz. - */ - Band16K = 9, -} - -/** - * The error information of the local audio. - */ -export enum AudioLocalError { - /** - * 0: The local audio is normal. - */ - Ok = 0, - /** - * 1: No specified reason for the local audio failure. - */ - Failure = 1, - /** - * 2: No permission to use the local audio device. - */ - DeviceNoPermission = 2, - /** - * 3: The microphone is in use. - */ - DeviceBusy = 3, - /** - * 4: The local audio recording fails. Check whether the recording device is working properly. - */ - RecordFailure = 4, - /** - * 5: The local audio encoding fails. - */ - EncodeFailure = 5, -} - -/** - * The state of the local audio. - */ -export enum AudioLocalState { - /** - * 0: The local audio is in the initial state. - */ - Stopped = 0, - /** - * 1: The recording device starts successfully. - */ - Recording = 1, - /** - * 2: The first audio frame encodes successfully. - */ - Encoding = 2, - /** - * 3: The local audio fails to start. - */ - Failed = 3, -} - -/** - * The error code of the audio mixing file. - */ -export enum AudioMixingErrorCode { - /** - * 701: The SDK cannot open the audio mixing file. - */ - CanNotOpen = 701, - /** - * 702: The SDK opens the audio mixing file too frequently. - */ - TooFrequentCall = 702, - /** - * 703: The opening of the audio mixing file is interrupted. - */ - InterruptedEOF = 703, - /** - * 0: No error. - */ - OK = 0, -} - -/** - * The state of the audio mixing file. - */ -export enum AudioMixingStateCode { - /** - * 710: The audio mixing file is playing. - */ - Playing = 710, - /** - * 711: The audio mixing file pauses playing. - */ - Paused = 711, - /** - * 713: The audio mixing file stops playing. - */ - Stopped = 713, - /** - * 714: An exception occurs when playing the audio mixing file. - */ - Failed = 714, -} - -/** - * Audio output routing. - */ -export enum AudioOutputRouting { - /** - * -1: Default. - */ - Default = -1, - /** - * 0: Headset. - */ - Headset = 0, - /** - * 1: Earpiece. - */ - Earpiece = 1, - /** - * 2: Headset with no microphone. - */ - HeadsetNoMic = 2, - /** - * 3: Speakerphone. - */ - Speakerphone = 3, - /** - * 4: Loudspeaker. - */ - Loudspeaker = 4, - /** - * 5: Bluetooth headset. - */ - HeadsetBluetooth = 5, -} - -/** - * Audio profile. - */ -export enum AudioProfile { - /** - * 0: Default audio profile. - * - In the `Communication` profile: A sample rate of 32 KHz, audio encoding, mono, and a bitrate of up to 18 Kbps. - * - In the `LiveBroadcasting` profile: A sample rate of 48 KHz, music encoding, mono, and a bitrate of up to 64 Kbps. - */ - Default = 0, - /** - * 1: A sample rate of 32 KHz, audio encoding, mono, and a bitrate of up to 18 Kbps. - */ - SpeechStandard = 1, - /** - * 2: A sample rate of 48 KHz, music encoding, mono, and a bitrate of up to 64 Kbps. - */ - MusicStandard = 2, - /** - * 3: A sample rate of 48 KHz, music encoding, stereo, and a bitrate of up to 80 Kbps. - */ - MusicStandardStereo = 3, - /** - * 4: A sample rate of 48 KHz, music encoding, mono, and a bitrate of up to 96 Kbps. - */ - MusicHighQuality = 4, - /** - * 5: A sample rate of 48 KHz, music encoding, stereo, and a bitrate of up to 128 Kbps. - */ - MusicHighQualityStereo = 5, -} - -/** - * Audio recording quality. - */ -export enum AudioRecordingQuality { - /** - * 0: The sample rate is 32 KHz, and the file size is around 1.2 MB after 10 minutes of recording. - */ - Low = 0, - /** - * 1: The sample rate is 32 KHz, and the file size is around 2 MB after 10 minutes of recording. - */ - Medium = 1, - /** - * 2: The sample rate is 32 KHz, and the file size is around 3.75 MB after 10 minutes of recording. - */ - High = 2, -} - -/** - * The state of the remote audio. - */ -export enum AudioRemoteState { - /** - * 0: The remote audio is in the default state, probably due to: - * - [`LocalMuted`]{@link AudioRemoteStateReason.LocalMuted} - * - [`RemoteMuted`]{@link AudioRemoteStateReason.RemoteMuted} - * - [`RemoteOffline`]{@link AudioRemoteStateReason.RemoteOffline} - */ - Stopped = 0, - /** - * 1: The first remote audio packet is received. - */ - Starting = 1, - /** - * 2: The remote audio stream is decoded and plays normally, probably due to: - * - [`NetworkRecovery`]{@link AudioRemoteStateReason.NetworkRecovery} - * - [`LocalUnmuted`]{@link AudioRemoteStateReason.LocalUnmuted} - * - [`RemoteUnmuted`]{@link AudioRemoteStateReason.RemoteUnmuted} - */ - Decoding = 2, - /** - * 3: The remote audio is frozen, probably due to: - * [`NetworkCongestion`]{@link AudioRemoteStateReason.NetworkCongestion} - */ - Frozen = 3, - /** - * 4: The remote audio fails to start, probably due to: - * [`Internal`]{@link AudioRemoteStateReason.Internal} - */ - Failed = 4, -} - -/** - * The reason of the remote audio state change. - */ -export enum AudioRemoteStateReason { - /** - * 0: Internal reasons. - */ - Internal = 0, - /** - * 1: Network congestion. - */ - NetworkCongestion = 1, - /** - * 2: Network recovery. - */ - NetworkRecovery = 2, - /** - * 3: The local user stops receiving the remote audio stream or disables the audio module. - */ - LocalMuted = 3, - /** - * 4: The local user resumes receiving the remote audio stream or enables the audio module. - */ - LocalUnmuted = 4, - /** - * 5: The remote user stops sending the audio stream or disables the audio module. - */ - RemoteMuted = 5, - /** - * 6: The remote user resumes sending the audio stream or enables the audio module. - */ - RemoteUnmuted = 6, - /** - * 7: The remote user leaves the channel. - */ - RemoteOffline = 7, -} - -/** - * The preset local voice reverberation option. - */ -export enum AudioReverbPreset { - /** - * The original voice (no local voice reverberation). - */ - Off = 0x00000000, - /** - * Pop music. - */ - Popular = 0x00000001, - /** - * R&B. - */ - RnB = 0x00000002, - /** - * Rock music. - */ - Rock = 0x00000003, - /** - * Hip-hop music. - */ - HipHop = 0x00000004, - /** - * Pop concert. - */ - VocalConcert = 0x00000005, - /** - * Karaoke. - */ - KTV = 0x00000006, - /** - * Recording studio. - */ - Studio = 0x00000007, - /** - * The reverberation style typical of a KTV venue (enhanced). - */ - FX_KTV = 0x00100001, - /** - * The reverberation style typical of a concert hall (enhanced). - */ - FX_VOCAL_CONCERT = 0x00100002, - /** - * The reverberation style typical of an uncle’s voice. - */ - FX_UNCLE = 0x00100003, - /** - * The reverberation style typical of a sister’s voice. - */ - FX_SISTER = 0x00100004, - /** - * The reverberation style typical of a recording studio (enhanced). - */ - FX_STUDIO = 0x00100005, - /** - * The reverberation style typical of popular music (enhanced). - */ - FX_POPULAR = 0x00100006, - /** - * The reverberation style typical of R&B music (enhanced). - */ - FX_RNB = 0x00100007, - /** - * The reverberation style typical of the vintage phonograph. - */ - FX_PHONOGRAPH = 0x00100008, - /** - * The reverberation of the virtual stereo. The virtual stereo is an effect that renders - * the monophonic audio as the stereo audio, so that all users in the channel can hear the stereo voice effect. - * To achieve better virtual stereo reverberation, Agora recommends setting the profile - * parameter in [`RtcEngine#setAudioProfile`]{@link RtcEngine#setAudioProfile} as [`MusicHighQualityStereo(5)`]{@link AudioProfile.MusicHighQualityStereo}. - */ - VIRTUAL_STEREO = 0x00200001, -} - -/** - * Audio reverberation type. - */ -export enum AudioReverbType { - /** - * 0: The level of the dry signal (dB). The value ranges between -20 and 10. - */ - DryLevel = 0, - /** - * 1: The level of the early reflection signal (wet signal) in dB. The value ranges between -20 and 10. - */ - WetLevel = 1, - /** - * 2: The room size of the reverberation. A larger room size means a stronger reverberation. The value ranges between 0 and 100. - */ - RoomSize = 2, - /** - * 3: The length of the initial delay of the wet signal (ms). The value ranges between 0 and 200. - */ - WetDelay = 3, - /** - * 4: The reverberation strength. The value ranges between 0 and 100. - */ - Strength = 4, -} - -/** - * Audio sample rate. - */ -export enum AudioSampleRateType { - /** - * 32000: 32 kHz. - */ - Type32000 = 32000, - /** - * 44100: 44.1 kHz. - */ - Type44100 = 44100, - /** - * 48000: 48 kHz. - */ - Type48000 = 48000, -} - -/** - * Audio scenario. - */ -export enum AudioScenario { - /** - * 0: Default. - */ - Default = 0, - /** - * 1: Entertainment scenario, supporting voice during gameplay. - */ - ChatRoomEntertainment = 1, - /** - * 2: Education scenario, prioritizing fluency 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. - */ - GameStreaming = 3, - /** - * 4: Showroom scenario, optimizing the audio quality with external professional equipment. - */ - ShowRoom = 4, - /** - * 5: Gaming scenario. - */ - ChatRoomGaming = 5, -} - -/** - * The preset audio voice configuration used to change the voice effect. - */ -export enum AudioVoiceChanger { - /** - * The original voice (no local voice change). - */ - Off = 0x00000000, - /** - * An old man’s voice. - */ - OldMan = 0x00000001, - /** - * A little boy’s voice. - */ - BabyBoy = 0x00000002, - /** - * A little girl’s voice. - */ - BabyGirl = 0x00000003, - /** - * The voice of a growling bear. - */ - ZhuBaJie = 0x00000004, - /** - * Ethereal vocal effects. - */ - Ethereal = 0x00000005, - /** - * Hulk’s voice. - */ - Hulk = 0x00000006, - /** - * A more vigorous voice. - */ - BEAUTY_VIGOROUS = 0x00100001, - /** - * A deeper voice. - */ - BEAUTY_DEEP = 0x00100002, - /** - * A mellower voice. - */ - BEAUTY_MELLOW = 0x00100003, - /** - * Falsetto. - */ - BEAUTY_FALSETTO = 0x00100004, - /** - * A fuller voice. - */ - BEAUTY_FULL = 0x00100005, - /** - * A clearer voice. - */ - BEAUTY_CLEAR = 0x00100006, - /** - * A more resounding voice. - */ - BEAUTY_RESOUNDING = 0x00100007, - /** - * A more ringing voice. - */ - BEAUTY_RINGING = 0x00100008, - /** - * A more spatially resonant voice. - */ - BEAUTY_SPACIAL = 0x00100009, - /** - * (For male only) A more magnetic voice. Do not use it when the speaker is a female; otherwise, voice distortion occurs. - */ - GENERAL_BEAUTY_VOICE_MALE_MAGNETIC = 0x00200001, - /** - * (For female only) A fresher voice. Do not use it when the speaker is a male; otherwise, voice distortion occurs. - */ - GENERAL_BEAUTY_VOICE_FEMALE_FRESH = 0x00200002, - /** - * (For female only) A more vital voice. Do not use it when the speaker is a male; otherwise, voice distortion occurs. - */ - GENERAL_BEAUTY_VOICE_FEMALE_VITALITY = 0x00200003, -} - -/** - * The camera capturer configuration. - */ -export enum CameraCaptureOutputPreference { - /** - * 0: (default) Self-adapts the camera output parameters to the system performance and network conditions to balance CPU consumption and video preview quality. - */ - Auto = 0, - /** - * 1: Prioritizes the system performance. The SDK chooses the dimension and frame rate of the local camera capture closest to those set by [`setVideoEncoderConfiguration`]{@link RtcEngine.setVideoEncoderConfiguration}. - */ - Performance = 1, - /** - * 2: Prioritizes the local preview quality. The SDK chooses higher camera output parameters to improve the local video preview quality. This option requires extra CPU and RAM usage for video pre-processing. - */ - Preview = 2, - /** - * 3: Internal use only - */ - Unkown = 3, -} - -/** - * The camera direction. - */ -export enum CameraDirection { - /** - * 0: The rear camera. - */ - Rear = 0, - /** - * 1: The front camera. - */ - Front = 1, -} - -/** - * The error code in AgoraChannelMediaRelayError. - */ -export enum ChannelMediaRelayError { - /** - * 0: The state is normal. - */ - None = 0, - /** - * 1: An error occurs in the server response. - */ - ServerErrorResponse = 1, - /** - * 2: No server response. You can call the leaveChannel method to leave the channel. - * [`leaveChannel`]{@link RtcEngine.leaveChannel} - */ - ServerNoResponse = 2, - /** - * 3: The SDK fails to access the service, probably due to limited resources of the server. - */ - NoResourceAvailable = 3, - /** - * 4: Fails to send the relay request. - */ - FailedJoinSourceChannel = 4, - /** - * 5: Fails to accept the relay request. - */ - FailedJoinDestinationChannel = 5, - /** - * 6: The server fails to receive the media stream. - */ - FailedPacketReceivedFromSource = 6, - /** - * 7: The server fails to send the media stream. - */ - FailedPacketSentToDestination = 7, - /** - * 8: The SDK disconnects from the server due to poor network connections. You can call [`leaveChannel`]{@link RtcEngine.leaveChannel} to leave the channel. - */ - ServerConnectionLost = 8, - /** - * 9: An internal error occurs in the server. - */ - InternalError = 9, - /** - * 10: The token of the source channel has expired. - */ - SourceTokenExpired = 10, - /** - * 11: The token of the destination channel has expired. - */ - DestinationTokenExpired = 11, -} - -/** - * The event code in `ChannelMediaRelayEvent`. - */ -export enum ChannelMediaRelayEvent { - /** - * 0: The user disconnects from the server due to poor network connections. - */ - Disconnect = 0, - /** - * 1: The network reconnects. - */ - Connected = 1, - /** - * 2: The user joins the source channel. - */ - JoinedSourceChannel = 2, - /** - * 3: The user joins the destination channel. - */ - JoinedDestinationChannel = 3, - /** - * 4: The SDK starts relaying the media stream to the destination channel. - */ - SentToDestinationChannel = 4, - /** - * 5: The server receives the video stream from the source channel. - */ - ReceivedVideoPacketFromSource = 5, - /** - * 6: The server receives the audio stream from the source channel. - */ - ReceivedAudioPacketFromSource = 6, - /** - * 7: The destination channel is updated. - */ - UpdateDestinationChannel = 7, - /** - * 8: The destination channel update fails due to internal reasons. - */ - UpdateDestinationChannelRefused = 8, - /** - * 9: The destination channel does not change, which means that the destination channel fails to be updated. - */ - UpdateDestinationChannelNotChange = 9, - /** - * 10: The destination channel name is null. - */ - UpdateDestinationChannelIsNil = 10, - /** - * 11: The video profile is sent to the server. - */ - VideoProfileUpdate = 11, -} - -/** - * The state code in [`ChannelMediaRelayState`]{@link ChannelMediaRelayState}. - */ -export enum ChannelMediaRelayState { - /** - * 0: The SDK is initializing. - */ - Idle = 0, - /** - * 1: The SDK tries to relay the media stream to the destination channel. - */ - Connecting = 1, - /** - * 2: The SDK successfully relays the media stream to the destination channel. - */ - Running = 2, - /** - * 3: A failure occurs. See the details in error. - */ - Failure = 3, -} - -/** - * Channel profile. - */ -export enum ChannelProfile { - /** - * 0: (Default) The Communication profile. - * Use this profile in one-on-one calls or group calls, where all users can talk freely. - */ - Communication = 0, - /** - * 1: The Live-Broadcast profile. - * Users in a live-broadcast channel have a role as either host or audience. A host can both send and receive streams; an audience can only receive streams. - */ - LiveBroadcasting = 1, - /** - * 2: The Gaming profile. - * This profile uses a codec with a lower bitrate and consumes less power. Applies to the gaming scenario, where all game players can talk freely. - */ - Game = 2, -} - -/** - * Client role in the `LiveBroadcasting` profile. - */ -export enum ClientRole { - /** - * 1: A host can both send and receive streams. - */ - Broadcaster = 1, - /** - * 2: The default role. An audience can only receive streams. - */ - Audience = 2, -} - -/** - * Reasons for the connection state change. - */ -export enum ConnectionChangedReason { - /** - * 0: The SDK is connecting to Agora’s edge server. - */ - Connecting = 0, - /** - * 1: The SDK has joined the channel successfully. - */ - JoinSuccess = 1, - /** - * 2: The connection between the SDK and Agora’s edge server is interrupted. - */ - Interrupted = 2, - /** - * 3: The connection between the SDK and Agora’s edge server is banned by Agora’s edge server. - */ - BannedByServer = 3, - /** - * 4: The SDK fails to join the channel for more than 20 minutes and stops reconnecting to the channel. - */ - JoinFailed = 4, - /** - * 5: The SDK has left the channel. - */ - LeaveChannel = 5, - /** - * 6: The specified App ID is invalid. Try to rejoin the channel with a valid App ID. - */ - InvalidAppId = 6, - /** - * 7: The specified channel name is invalid. Try to rejoin the channel with a valid channel name. - */ - InvalidChannelName = 7, - /** - * 8: The generated token is invalid probably due to the following reasons: - * - The App Certificate for the project is enabled in Console, but you do not use Token when joining the channel. If you enable the App Certificate, you must use a token to join the channel. - * - The uid that you specify in the [`joinChannel`]{@link RtcEngine.joinChannel} method is different from the uid that you pass for generating the token. - */ - InvalidToken = 8, - /** - * 9: The token has expired. Generate a new token from your server. - */ - TokenExpired = 9, - /** - * 10: The user is banned by the server. - */ - RejectedByServer = 10, - /** - * 11: The SDK tries to reconnect after setting a proxy server. - */ - SettingProxyServer = 11, - /** - * 12: The token renews. - */ - RenewToken = 12, - /** - * 13: The client IP address has changed, probably due to a change of the network type, IP address, or network port. - */ - ClientIpAddressChanged = 13, - /** - * 14: Timeout for the keep-alive of the connection between the SDK and Agora’s edge server. The connection state changes to: - * [`Reconnecting`]{@link ConnectionStateType.Reconnecting} - */ - KeepAliveTimeout = 14, -} - -/** - * Connection states. - */ -export enum ConnectionStateType { - /** - * 1: The SDK is disconnected from Agora's edge server. - * - This is the initial state before [`joinChannel`]{@link RtcEngine.joinChannel}. - * - The SDK also enters this state when the app calls [`leaveChannel`]{@link RtcEngine.leaveChannel}. - */ - Disconnected = 1, - /** - * 2: The SDK is connecting to Agora's edge server. - * - When the app calls [`joinChannel`]{@link RtcEngine.joinChannel}, the SDK starts to establish a connection to the specified channel, triggers the [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callback, and switches to the [`Connecting`]{@link ConnectionStateType.Connecting} state. - * - When the SDK successfully joins the channel, the SDK triggers the [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callback and switches to the [`Connected`]{@link ConnectionStateType.Connected} state. - * - After the SDK joins the channel and when it finishes initializing the media engine, the SDK triggers the [`JoinChannelSuccess`]{@link RtcEngineEvents.JoinChannelSuccess} callback. - */ - Connecting = 2, - /** - * 3: The SDK is connected to Agora's edge server and joins a channel. You can now publish or subscribe to a media stream in the channel. - * If the connection to the channel is lost because, for example, the network is down or switched, the SDK automatically tries to reconnect and triggers: - * - The [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callback, and switches to the [`Reconnecting`]{@link ConnectionStateType.Reconnecting} state. - */ - Connected = 3, - /** - * 4: The SDK keeps rejoining the channel after being disconnected from a joined channel because of network issues. - * - If the SDK cannot rejoin the channel within 10 seconds after being disconnected from Agora’s edge server, the SDK triggers the [`ConnectionLost`]{@link RtcEngineEvents.ConnectionLost} callback, stays in the [`Reconnecting`]{@link ConnectionStateType.Reconnecting} state, and keeps rejoining the channel. - * - * - If the SDK fails to rejoin the channel 20 minutes after being disconnected from Agora’s edge server, the SDK triggers the [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callback, switches to the [`Failed`]{@link ConnectionStateType.Failed} state, and stops rejoining the channel. - * [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} - */ - Reconnecting = 4, - /** - * 5: The SDK fails to connect to Agora's edge server or join the channel. - * You must call [`leaveChannel`]{@link RtcEngine.leaveChannel} to leave this state, and call [`joinChannel`]{@link RtcEngine.joinChannel} again to rejoin the channel. - * - * If the SDK is banned from joining the channel by Agora’s edge server (through the RESTful API), the SDK triggers the [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callbacks. - */ - Failed = 5, -} - -/** - * The video encoding degradation preference under limited bandwidth. - */ -export enum DegradationPreference { - /** - * 0: (Default) Degrades the frame rate to guarantee the video quality. - */ - MaintainQuality = 0, - /** - * 1: Degrades the video quality to guarantee the frame rate. - */ - MaintainFramerate = 1, - /** - * 2: Reserved for future use. - */ - Balanced = 2, -} - -/** - * Encryption mode. - */ -export enum EncryptionMode { - /** - * @deprecated - * 0: This mode is deprecated. - */ - None = 0, - /** - * 1: (Default) 128-bit AES encryption, XTS mode. - */ - AES128XTS = 1, - /** - * 2: 128-bit AES encryption, ECB mode. - */ - AES128ECB = 2, - /** - * 3: 256-bit AES encryption, XTS mode. - */ - AES256XTS = 3, - /** - * 4: 128-bit SM4 encryption, ECB mode. - * - * @since v3.1.2. - */ - SM4128ECB = 4, -} - -/** - * Error codes occur when the SDK encounters an error that cannot be recovered automatically without any app intervention. - */ -export enum ErrorCode { - /** - * 0: No error occurs. - */ - NoError = 0, - /** - * 1: A general error occurs (no specified reason). - */ - Failed = 1, - /** - * 2: An invalid parameter is used. For example, the specific channel name includes illegal characters. - */ - InvalidArgument = 2, - /** - * 3: The SDK module is not ready. - * Possible solutions: - * - Check the audio device. - * - Check the completeness of the app. - * - Re-initialize the SDK. - */ - NotReady = 3, - /** - * 4: The current state of the SDK does not support this function. - */ - NotSupported = 4, - /** - * 5: The request is rejected. This is for internal SDK use only, and is not returned to the app through any method or callback. - */ - Refused = 5, - /** - * 6: The buffer size is not big enough to store the returned data. - */ - BufferTooSmall = 6, - /** - * 7: The SDK is not initialized before calling this method. - */ - NotInitialized = 7, - /** - * 9: No permission exists. Check if the user has granted access to the audio or video device. - */ - NoPermission = 9, - /** - * 10: An API method timeout occurs. Some API methods require the SDK to return the execution result, and this error occurs if the request takes too long (over 10 seconds) for the SDK to process. - */ - TimedOut = 10, - /** - * 11: The request is canceled. This is for internal SDK use only, and is not returned to the app through any method or callback. - */ - Canceled = 11, - /** - * 12: The method is called too often. This is for internal SDK use only, and is not returned to the app through any method or callback. - */ - TooOften = 12, - /** - * 13: The SDK fails to bind to the network socket. This is for internal SDK use only, and is not returned to the app through any method or callback. - */ - BindSocket = 13, - /** - * 14: The network is unavailable. This is for internal SDK use only, and is not returned to the app through any method or callback. - */ - NetDown = 14, - /** - * 15: No network buffers are available. This is for internal SDK use only, and is not returned to the app through any method or callback. - */ - NoBufs = 15, - /** - * 17: The request to join the channel is rejected. - * Possible reasons are: - * - The user is already in the channel, and still calls the API method to join the channel, for example, [`joinChannel`]{@link RtcEngine.joinChannel} - * - The user tries joining the channel during the echo test. Please join the channel after the echo test ends. - */ - JoinChannelRejected = 17, - /** - * 18: The request to leave the channel is rejected. - * Possible reasons are: - * - The user left the channel and still calls the API method to leave the channel, for example, [`leaveChannel`]{@link RtcEngine.leaveChannel}. - * - The user has not joined the channel and calls the API method to leave the channel. - */ - LeaveChannelRejected = 18, - /** - * 19: The resources are occupied and cannot be used. - */ - AlreadyInUse = 19, - /** - * 20: The SDK gave up the request due to too many requests. - */ - Abort = 20, - /** - * 21: In Windows, specific firewall settings cause the SDK to fail to initialize and crash. - */ - InitNetEngine = 21, - /** - * 22: The app uses too much of the system resources and the SDK fails to allocate the resources. - */ - ResourceLimited = 22, - /** - * 101: The specified App ID is invalid. Please try to rejoin the channel with a valid App ID. - */ - InvalidAppId = 101, - /** - * 102: The specified channel name is invalid. Please try to rejoin the channel with a valid channel name. - */ - InvalidChannelId = 102, - /** - * 103: Fails to get server resources in the specified region. Please try to specify another region. - * - * @since v3.1.2. - */ - NoServerResources = 103, - /** - * 109: The token expired. - * @deprecated Use [`TokenExpired`]{@link ConnectionChangedReason.TokenExpired} in the reason parameter of [`onConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged}. - * - * Possible reasons are: - * - Authorized Timestamp expired: The timestamp is represented by the number of seconds elapsed since 1/1/1970. The user can use the token to access the Agora service within five minutes after the token is generated. If the user does not access the Agora service after five minutes, this token is no longer valid. - * - Call Expiration Timestamp expired: The timestamp is the exact time when a user can no longer use the Agora service (for example, when a user is forced to leave an ongoing call). When a value is set for the Call Expiration Timestamp, it does not mean that the token will expire, but that the user will be banned from the channel. - */ - TokenExpired = 109, - /** - * 110: The token is invalid. - * @deprecated Use [`InvalidToken`]{@link ConnectionChangedReason.InvalidToken} in the reason parameter of [`onConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged}. - * - * Possible reasons are: - * - The App Certificate for the project is enabled in Console, but the user is using the App ID. Once the App Certificate is enabled, the user must use a token. - * - The uid is mandatory, and users must set the same uid as the one set in the [`joinChannel`]{@link RtcEngine.joinChannel} method. - */ - InvalidToken = 110, - /** - * 111: The Internet connection is interrupted. This applies to the Agora Web SDK only. - */ - ConnectionInterrupted = 111, - /** - * 112: The Internet connection is lost. This applies to the Agora Web SDK only. - */ - ConnectionLost = 112, - /** - * 113: The user is not in the channel when calling the [`sendStreamMessage`]{@link RtcEngine.sendStreamMessage} or [`getUserInfoByUserAccount`]{@link RtcEngine.getUserInfoByUserAccount} method. - */ - NotInChannel = 113, - /** - * 114: The size of the sent data is over 1024 bytes when the user calls the [`sendStreamMessage`]{@link RtcEngine.sendStreamMessage} method. - */ - SizeTooLarge = 114, - /** - * 115: The bitrate of the sent data exceeds the limit of 6 Kbps when the user calls the [`sendStreamMessage`]{@link RtcEngine.sendStreamMessage} method. - */ - BitrateLimit = 115, - /** - * 116: Too many data streams (over five streams) are created when the user calls the [`createDataStream`]{@link RtcEngine.createDataStream} method. - */ - TooManyDataStreams = 116, - /** - * 120: Decryption fails. The user may have used a different encryption password to join the channel. Check your settings or try rejoining the channel. - */ - DecryptionFailed = 120, - /** - * 123: The client is banned by the server. - */ - ClientIsBannedByServer = 123, - /** - * 124: Incorrect watermark file parameter. - */ - WatermarkParam = 124, - /** - * 125: Incorrect watermark file path. - */ - WatermarkPath = 125, - /** - * 126: Incorrect watermark file format. - */ - WatermarkPng = 126, - /** - * 127: Incorrect watermark file information. - */ - WatermarkInfo = 127, - /** - * 128: Incorrect watermark file data format. - */ - WatermarkAGRB = 128, - /** - * 129: An error occurs in reading the watermark file. - */ - WatermarkRead = 129, - /** - * 130: The encrypted stream is not allowed to publish. - */ - EncryptedStreamNotAllowedPublish = 130, - /** - * 134: The user account is invalid. - */ - InvalidUserAccount = 134, - /** - * 151: CDN related errors. Remove the original URL address and add a new one by calling the [`removePublishStreamUrl`]{@link RtcEngine.removePublishStreamUrl} and [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} methods. - */ - PublishStreamCDNError = 151, - /** - * 152: The host publishes more than 10 URLs. Delete the unnecessary URLs before adding new ones. - */ - PublishStreamNumReachLimit = 152, - /** - * 153: The host manipulates other hosts' URLs. Check your app logic. - */ - PublishStreamNotAuthorized = 153, - /** - * 154: An error occurs in Agora’s streaming server. Call the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method to publish the stream again. - */ - PublishStreamInternalServerError = 154, - /** - * 155: The server fails to find the stream. - */ - PublishStreamNotFound = 155, - /** - * 156: The format of the RTMP stream URL is not supported. Check whether the URL format is correct. - */ - PublishStreamFormatNotSuppported = 156, - /** - * 1001: Fails to load the media engine. - */ - LoadMediaEngine = 1001, - /** - * 1002: Fails to start the call after enabling the media engine. - */ - StartCall = 1002, - /** - * 1003: Fails to start the camera. - * - * @deprecated Use [`CaptureFailure`]{@link LocalVideoStreamError.CaptureFailure} in the error parameter of [`LocalVideoStateChanged`]{@link RtcEngineEvents.LocalVideoStateChanged}. - */ - StartCamera = 1003, - /** - * 1004: Fails to start the video rendering module. - */ - StartVideoRender = 1004, - /** - * 1005: Audio Device Module: A general error occurs in the Audio Device Module (the reason is not classified specifically). Check if the audio device is used by another app, or try rejoining the channel. - */ - AdmGeneralError = 1005, - /** - * 1006: Audio Device Module: An error occurs in using the Java resources. - */ - AdmJavaResource = 1006, - /** - * 1007: Audio Device Module: An error occurs in setting the sampling frequency. - */ - AdmSampleRate = 1007, - /** - * 1008: Audio Device Module: An error occurs in initializing the playback device. - */ - AdmInitPlayout = 1008, - /** - * 1009: Audio Device Module: An error occurs in starting the playback device. - */ - AdmStartPlayout = 1009, - /** - * 1010: Audio Device Module: An error occurs in stopping the playback device. - */ - AdmStopPlayout = 1010, - /** - * 1011: Audio Device Module: An error occurs in initializing the recording device. - */ - AdmInitRecording = 1011, - /** - * 1012: Audio Device Module: An error occurs in starting the recording device. - */ - AdmStartRecording = 1012, - /** - * 1013: Audio Device Module: An error occurs in stopping the recording device. - */ - AdmStopRecording = 1013, - /** - * 1015: Audio Device Module: A playback error occurs. Check your playback device, or try rejoining the channel. - */ - AdmRuntimePlayoutError = 1015, - /** - * 1017: Audio Device Module: A recording error occurs. - */ - AdmRuntimeRecordingError = 1017, - /** - * 1018: Audio Device Module: Fails to record. - */ - AdmRecordAudioFailed = 1018, - /** - * 1020: Audio device module: The audio playback frequency is abnormal, which may cause audio freezes. This abnormality is caused by high CPU usage. Agora recommends stopping other apps. - */ - AdmPlayAbnormalFrequency = 1020, - /** - * 1021: Audio device module: The audio recording frequency is abnormal, which may cause audio freezes. This abnormality is caused by high CPU usage. Agora recommends stopping other apps. - */ - AdmRecordAbnormalFrequency = 1021, - /** - * 1022: Audio Device Module: An error occurs in initializing the loopback device. - */ - AdmInitLoopback = 1022, - /** - * 1023: Audio Device Module: An error occurs in starting the loopback device. - */ - AdmStartLoopback = 1023, - /** - * 1027: Audio Device Module: No recording permission. - */ - AdmNoPermission = 1027, - /** - * 1030: Audio Routing: Fails to route the audio to the connected Bluetooth device. The default route is used. - */ - AudioBtScoFailed = 1030, - /** - * 1359: Audio Device Module: No recording device exists. - */ - AdmNoRecordingDevice = 1359, - /** - * 1360: No playback device exists. - */ - AdmNoPlayoutDevice = 1360, - /** - * 1501: Video Device Module: The camera is unauthorized. - */ - VdmCameraNotAuthorized = 1501, - /** - * 1600: Video Device Module: An unknown error occurs. - */ - VcmUnknownError = 1600, - /** - * 1601: Video Device Module: An error occurs in initializing the video encoder. - */ - VcmEncoderInitError = 1601, - /** - * 1602: Video Device Module: An error occurs in video encoding. - */ - VcmEncoderEncodeError = 1602, - /** - * 1603: Video Device Module: An error occurs in setting the video encoder. - * - * @deprecated - * This error code is deprecated. - */ - VcmEncoderSetError = 1603, -} - -/** - * State of importing an external video stream in a live broadcast. - */ -export enum InjectStreamStatus { - /** - * 0: The external video stream imported successfully. - */ - StartSuccess = 0, - /** - * 1: The external video stream already exists. - */ - StartAlreadyExists = 1, - /** - * 2: The external video stream import is unauthorized. - */ - StartUnauthorized = 2, - /** - * 3: Import external video stream timeout. - */ - StartTimedout = 3, - /** - * 4: The external video stream failed to import. - */ - StartFailed = 4, - /** - * 5: The external video stream stops importing successfully. - */ - StopSuccess = 5, - /** - * 6: No external video stream is found. - */ - StopNotFound = 6, - /** - * 7: The external video stream to be stopped importing is unauthorized. - */ - StopUnauthorized = 7, - /** - * 8: Stopping importing the external video stream timed out. - */ - StopTimedout = 8, - /** - * 9: Stopping Importing the external video stream failed. - */ - StopFailed = 9, - /** - * 10: The external video stream import is corrupted. - */ - Broken = 10, -} - -/** - * The state of the probe test result. - */ -export enum LastmileProbeResultState { - /** - * 1: the last-mile network probe test is complete. - */ - Complete = 1, - /** - * 2: the last-mile network probe test is incomplete and the bandwidth estimation is not available, probably due to limited test resources. - */ - IncompleteNoBwe = 2, - /** - * 3: The last-mile network probe test is not carried out, probably due to poor network conditions. - */ - Unavailable = 3, -} - -/** - * The lightening contrast level. - */ -export enum LighteningContrastLevel { - /** - * 0: Low contrast level. - */ - Low = 0, - /** - * 1: (Default) Normal contrast level. - */ - Normal = 1, - /** - * 2: High contrast level. - */ - High = 2, -} - -/** - * The detailed error information of the local video. - */ -export enum LocalVideoStreamError { - /** - * 0: The local video is normal. - */ - OK = 0, - /** - * 1: No specified reason for the local video failure. - */ - Failure = 1, - /** - * 2: No permission to use the local video device. - */ - DeviceNoPermission = 2, - /** - * 3: The local video capturer is in use. - */ - DeviceBusy = 3, - /** - * 4: The local video capture fails. Check whether the capturer is working properly. - */ - CaptureFailure = 4, - /** - * 5: The local video encoding fails. - */ - EncodeFailure = 5, -} - -/** - * The state of the local video stream. - */ -export enum LocalVideoStreamState { - /** - * 0: The local video is in the initial state. - */ - Stopped = 0, - /** - * 1: The local video capturer starts successfully. - */ - Capturing = 1, - /** - * 2: The first local video frame encodes successfully. - */ - Encoding = 2, - /** - * 3: The local video fails to start. - */ - Failed = 3, -} - -/** - * Output log filter level. - */ -export enum LogFilter { - /** - * 0: Do not output any log information. - */ - Off = 0, - /** - * 0x080f: Output all log information. Set your log filter as debug if you want to get the most complete log file. - */ - Debug = 0x080f, - /** - * 0x000f: Output CRITICAL, ERROR, WARNING, and INFO level log information. We recommend setting your log filter as this level. - */ - Info = 0x000f, - /** - * 0x000e: Outputs CRITICAL, ERROR, and WARNING level log information. - */ - Warning = 0x000e, - /** - * 0x000c: Outputs CRITICAL and ERROR level log information. - */ - Error = 0x000c, - /** - * 0x0008: Outputs CRITICAL level log information. - */ - Critical = 0x0008, -} - -/** - * Network quality. - */ -export enum NetworkQuality { - /** - * 0: The network quality is unknown. - */ - Unknown = 0, - /** - * 1: The network quality is excellent. - */ - Excellent = 1, - /** - * 2: The network quality is quite good, but the bitrate may be slightly lower than excellent. - */ - Good = 2, - /** - * 3: Users can feel the communication slightly impaired. - */ - Poor = 3, - /** - * 4: Users can communicate only not very smoothly. - */ - Bad = 4, - /** - * 5: The network quality is so bad that users can hardly communicate. - */ - VBad = 5, - /** - * 6: The network is disconnected and users cannot communicate at all. - */ - Down = 6, - /** - * 7: Users cannot detect the network quality. (Not in use.) - */ - Unsupported = 7, - /** - * 8: Detecting the network quality. - */ - Detecting = 8, -} - -/** - * Network type. - */ -export enum NetworkType { - /** - * -1: The network type is unknown. - */ - Unknown = -1, - /** - * 0: The SDK disconnects from the network. - */ - Disconnected = 0, - /** - * 1: The network type is LAN. - */ - LAN = 1, - /** - * 2: The network type is Wi-Fi (including hotspots). - */ - WIFI = 2, - /** - * 3: The network type is mobile 2G. - */ - Mobile2G = 3, - /** - * 4: The network type is mobile 3G. - */ - Mobile3G = 4, - /** - * 5: The network type is mobile 4G. - */ - Mobile4G = 5, -} - -/** - * The detailed error information for streaming. - */ -export enum RtmpStreamingErrorCode { - /** - * 0: The RTMP streaming publishes successfully. - */ - OK = 0, - /** - * 1: Invalid argument used. If, for example, you do not call the [`setLiveTranscoding`]{@link RtcEngine.setLiveTranscoding} method to configure - * the `LiveTranscoding` parameters before calling the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method, the SDK returns this error. - * Check whether you set the parameters in the [`setLiveTranscoding`]{@link RtcEngine.setLiveTranscoding} method properly. - */ - InvalidParameters = 1, - /** - * 2: The RTMP 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. - */ - ConnectionTimeout = 3, - /** - * 4: An error occurs in Agora’s streaming server. Call the [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} method to publish the streaming again. - */ - InternalServerError = 4, - /** - * 5: An error occurs in the RTMP server. - */ - RtmpServerError = 5, - /** - * 6: The RTMP streaming publishes too frequently. - */ - TooOften = 6, - /** - * 7: The host publishes more than 10 URLs. Delete the unnecessary URLs before adding new ones. - */ - ReachLimit = 7, - /** - * 8: The host manipulates other hosts' URLs. Check your app logic. - */ - NotAuthorized = 8, - /** - * 9: Agora’s server fails to find the RTMP streaming. - */ - StreamNotFound = 9, - /** - * 10: The format of the RTMP streaming URL is not supported. Check whether the URL format is correct. - */ - FormatNotSupported = 10, -} - -/** - * The RTMP 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}. - */ - Idle = 0, - /** - * 1: The SDK is connecting to Agora’s streaming server and the RTMP 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. - */ - 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. - * - * - 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, - * [`Failure`]{@link RtmpStreamingState.Failure} returns. - * - * You can also reconnect to the server by calling the [`removePublishStreamUrl`]{@link RtcEngine.removePublishStreamUrl} and [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl} methods. - */ - 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. - */ - Failure = 4, -} - -/** - * Stream fallback option. - */ -export enum StreamFallbackOptions { - /** - * 0: No fallback behavior for the local/remote video stream when the uplink/downlink network condition is unreliable. The quality of the stream is not guaranteed. - */ - Disabled = 0, - /** - * 1: Under unreliable downlink network conditions, the remote video stream falls back to the - * low-stream (low resolution and low bitrate) video. You can only set this option - * in the [`setRemoteSubscribeFallbackOption`]{@link RtcEngine.setRemoteSubscribeFallbackOption} method. - * Nothing happens when you set this in the [`setLocalPublishFallbackOption`]{@link RtcEngine.setLocalPublishFallbackOption} method. - */ - VideoStreamLow = 1, - /** - * 2: Under unreliable uplink network conditions, the published video stream falls back to audio only. Under unreliable downlink network conditions, the remote video stream first falls back to the low-stream (low resolution and low bitrate) video; and then to an audio-only stream if the network condition deteriorates. - */ - AudioOnly = 2, -} - -/** - * Reason for the user being offline. - */ -export enum UserOfflineReason { - /** - * 0: The user left the current channel. - */ - Quit = 0, - /** - * 1: The SDK timed out and the user dropped offline because no data packet is received within a certain period of time. If a user quits the call and the message is not passed to the SDK (due to an unreliable channel), the SDK assumes the user dropped offline. - */ - Dropped = 1, - /** - * 2: (Live broadcast only.) The client role switched from the host to the audience. - */ - BecomeAudience = 2, -} - -/** - * The priority of the remote user. - */ -export enum UserPriority { - /** - * 50: The user’s priority is high. - */ - High = 50, - /** - * 100: (Default) The user’s priority is normal. - */ - Normal = 100, -} - -/** - * Self-defined video codec profile. - */ -export enum VideoCodecProfileType { - /** - * 66: Baseline video codec profile. Generally used in video calls on mobile phones. - */ - BaseLine = 66, - /** - * 77: Main video codec profile. Generally used in mainstream electronics, such as MP4 players, portable video players, PSP, and iPads. - */ - Main = 77, - /** - * 100: (Default) High video codec profile. Generally used in high-resolution broadcasts or television. - */ - High = 100, -} - -/** - * Video frame rate. - */ -export enum VideoFrameRate { - /** - * -1: The minimum frame rate of the video. - */ - Min = -1, - /** - * 1: 1 fps. - */ - Fps1 = 1, - /** - * 7: 7 fps. - */ - Fps7 = 7, - /** - * 10: 10 fps. - */ - Fps10 = 10, - /** - * 15: 15 fps. - */ - Fps15 = 15, - /** - * 24: 24 fps. - */ - Fps24 = 24, - /** - * 30: 30 fps. - */ - Fps30 = 30, - /** - * 60: 60 fps (macOS only). - */ - Fps60 = 60, -} - -/** - * Bitrate of the video (Kbps). Refer to the table below and set your bitrate. - * If you set a bitrate beyond the proper range, the SDK automatically adjusts it to a value within the range. - * - * **Video Bitrate Table** - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
ResolutionFrame rate

(fps)

Base Bitrate

(Kbps, for Communication)

Live Bitrate

(Kbps, for Live Broadcasting)

160*1201565130
120*1201550100
320*18015140280
180*18015100200
240*18015120240
320*24015200400
240*24015140280
424*24015220440
640*36015400800
360*36015260520
640*360306001200
360*36030400800
480*36015320640
480*36030490980
640*480155001000
480*48015400800
640*480307501500
480*480306001200
848*480156101220
848*480309301860
640*48010400800
1280*7201511302260
1280*7203017103420
960*720159101820
960*7203013802760
- * - * Agora uses different video codecs for different profiles to optimize the user experience. For example, - * the Communication profile prioritizes the smoothness while the LIVE_BROADCASTING profile prioritizes the - * video quality (a higher bitrate). Therefore, We recommend setting this parameter as STANDARD_BITRATE = 0. - */ -export enum BitRate { - /** - * 0: (Recommended) the standard bitrate mode. In this mode, the bitrates differ between the Live-broadcast and Communication profiles: - * - Communication profile: the video bitrate is the same as the base bitrate. - * - Live-broadcast profile: the video bitrate is twice the base bitrate. - */ - Standard = 0, - /** - * -1: The compatible bitrate mode. In this mode, the bitrate stays the same regardless of the profile. In the Live-broadcast profile, - * if you choose this mode, the video frame rate may be lower than the set value. - */ - Compatible = -1, -} - -/** - * Video mirror mode. - */ -export enum VideoMirrorMode { - /** - * 0: (Default) The SDK determines the mirror mode. - */ - Auto = 0, - /** - * 1: Enables mirror mode. - */ - Enabled = 1, - /** - * 2: Disables mirror mode. - */ - Disabled = 2, -} - -/** - * Video output orientation mode. - */ -export enum VideoOutputOrientationMode { - /** - * 0: Adaptive mode (Default). - * - * The video encoder adapts to the orientation mode of the video input device. When you use a custom video source, the output video from the encoder inherits the orientation of the original video. - * - If the width of the captured video from the SDK is greater than the height, the encoder sends the video in landscape mode. The encoder also sends the rotational information of the video, and the receiver uses the rotational information to rotate the received video. - * - If the original video is in portrait mode, the output video from the encoder is also in portrait mode. The encoder also sends the rotational information of the video to the receiver. - */ - Adaptative = 0, - /** - * 1: Landscape mode. - * - * The video encoder always sends the video in landscape mode. The video encoder rotates the original video before sending it and the rotational information is 0. This mode applies to scenarios involving CDN live streaming. - */ - FixedLandscape = 1, - /** - * 2: Portrait mode. - * - * The video encoder always sends the video in portrait mode. The video encoder rotates the original video before sending it and the rotational information is 0. This mode applies to scenarios involving CDN live streaming. - */ - FixedPortrait = 2, -} - -/** - * Quality change of the local video in terms of target frame rate and target bit rate since last count. - */ -export enum VideoQualityAdaptIndication { - /** - * 0: The quality of the local video stays the same. - */ - AdaptNone = 0, - /** - * 1: The quality improves because the network bandwidth increases. - */ - AdaptUpBandwidth = 1, - /** - * 2: The quality worsens because the network bandwidth decreases. - */ - AdaptDownBandwidth = 2, -} - -/** - * The state of the remote video. - */ -export enum VideoRemoteState { - /** - * 0: The remote video is in the default state, probably due to: - * - [`LocalMuted`]{@link VideoRemoteStateReason.LocalMuted} - * - [`RemoteMuted`]{@link VideoRemoteStateReason.RemoteMuted} - * - [`RemoteOffline`]{@link VideoRemoteStateReason.RemoteOffline} - */ - Stopped = 0, - /** - * 1: The first remote video packet is received. - */ - Starting = 1, - /** - * 2: The remote video stream is decoded and plays normally, probably due to: - * - [`NetworkRecovery`]{@link VideoRemoteStateReason.NetworkRecovery} - * - [`LocalUnmuted`]{@link VideoRemoteStateReason.LocalUnmuted} - * - [`RemoteUnmuted`]{@link VideoRemoteStateReason.RemoteUnmuted} - * - [`AudioFallbackRecovery`]{@link VideoRemoteStateReason.AudioFallbackRecovery} - */ - Decoding = 2, - /** - * 3: The remote video is frozen, probably due to: - * - [`NetworkCongestion`]{@link VideoRemoteStateReason.NetworkCongestion} - * - [`AudioFallback`]{@link VideoRemoteStateReason.AudioFallback} - */ - Frozen = 3, - /** - * 4: The remote video fails to start, probably due to: [`Internal`]{@link VideoRemoteStateReason.Internal} - */ - Failed = 4, -} - -/** - * The reason of the remote video state change. - */ -export enum VideoRemoteStateReason { - /** - * 0: Internal reasons. - */ - Internal = 0, - /** - * 1: Network congestion. - */ - NetworkCongestion = 1, - /** - * 2: Network recovery. - */ - NetworkRecovery = 2, - /** - * 3: The local user stops receiving the remote video stream or disables the video module. - */ - LocalMuted = 3, - /** - * 4: The local user resumes receiving the remote video stream or disables the video module. - */ - LocalUnmuted = 4, - /** - * 5: The remote user stops sending the video stream or disables the video module. - */ - RemoteMuted = 5, - /** - * 6: The remote user resumes sending the video stream or enables the video module. - */ - RemoteUnmuted = 6, - /** - * 7: The remote user leaves the channel. - */ - RemoteOffline = 7, - /** - * 8: The remote media stream falls back to the audio-only stream due to poor network conditions. - */ - AudioFallback = 8, - /** - * 9: The remote media stream switches back to the video stream after the network conditions improve. - */ - AudioFallbackRecovery = 9, -} - -/** - * Video display mode. - */ -export enum VideoRenderMode { - /** - * 1: Uniformly scale the video until it fills the visible boundaries (cropped). One dimension of the video may have clipped contents. - */ - Hidden = 1, - /** - * 2: Uniformly scale the video until one of its dimension fits the boundary (zoomed to fit). Areas that are not filled due to the disparity in the aspect ratio are filled with black. - */ - Fit = 2, - /** - * @deprecated - * 3: This mode is deprecated. - */ - Adaptive = 3, - /** - * 4: The fill mode. In this mode, the SDK stretches or zooms the video to fill the display window. - */ - FILL = 4, -} - -/** - * Video stream type. - */ -export enum VideoStreamType { - /** - * 0: High-bitrate, high-resolution video stream. - */ - High = 0, - /** - * 1: Low-bitrate, low-resolution video stream. - */ - Low = 1, -} - -/** - * Warning codes occur when the SDK encounters an error that may be recovered automatically. - * These are only notifications, and can generally be ignored. For example, when the SDK loses connection to the server, - * the SDK reports the [`OpenChannelTimeout(106)`]{@link WarningCode.OpenChannelTimeout} warning and tries to reconnect automatically. - */ -export enum WarningCode { - /** - * 8: The specified view is invalid. Specify a view when using the video call function. - */ - InvalidView = 8, - /** - * 16: Failed to initialize the video function, possibly caused by a lack of resources. The users cannot see the video while the voice communication is not affected. - */ - InitVideo = 16, - /** - * 20: The request is pending, usually due to some module not being ready, and the SDK postpones processing the request. - */ - Pending = 20, - /** - * 103: No channel resources are available. Maybe because the server cannot allocate any channel resource. - */ - NoAvailableChannel = 103, - /** - * 104: A timeout occurs when looking up the channel. When joining a channel, the SDK looks up the specified channel. The warning usually occurs when the network condition is too poor for the SDK to connect to the server. - */ - LookupChannelTimeout = 104, - /** - * 105: The server rejects the request to look up the channel. - * The server cannot process this request or the request is illegal. - * @deprecated - * - * Use [`RejectedByServer(10)`]{@link ConnectionChangedReason.RejectedByServer} in the reason parameter - * of [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged}. - */ - LookupChannelRejected = 105, - /** - * 106: The server rejects the request to look up the channel. The server cannot process this request - * or the request is illegal. - */ - OpenChannelTimeout = 106, - /** - * 107: The server rejects the request to open the channel. The server cannot process this request or the request is illegal. - */ - OpenChannelRejected = 107, - /** - * 111: A timeout occurs when switching to the live video. - */ - SwitchLiveVideoTimeout = 111, - /** - * 118: A timeout occurs when setting the client role in the live broadcast profile. - */ - SetClientRoleTimeout = 118, - /** - * 119: The client role is unauthorized. - */ - SetClientRoleNotAuthorized = 119, - /** - * 121: The ticket to open the channel is invalid. - */ - OpenChannelInvalidTicket = 121, - /** - * 122: Try connecting to another server. - */ - OpenChannelTryNextVos = 122, - /** - * 701: An error occurs in opening the audio mixing file. - */ - AudioMixingOpenError = 701, - /** - * 1014: Audio Device Module: a warning occurs in the playback device. - */ - AdmRuntimePlayoutWarning = 1014, - /** - * 1016: Audio Device Module: a warning occurs in the recording device. - */ - AdmRuntimeRecordingWarning = 1016, - /** - * 1019: Audio Device Module: no valid audio data is collected. - */ - AdmRecordAudioSilence = 1019, - /** - * 1020: Audio Device Module: a playback device fails. - */ - AdmPlaybackMalfunction = 1020, - /** - * 1021: Audio Device Module: a recording device fails. - */ - AdmRecordMalfunction = 1021, - /** - * 1025: Audio Device Module: call is interrupted by system events such as phone call or siri etc. - */ - AdmInterruption = 1025, - /** - * 1029: During a call, `AudioSessionCategory` should be set to `AVAudioSessionCategoryPlayAndRecord`, and the SDK monitors this value. If the `AudioSessionCategory` is set to other values, this warning code is triggered and the SDK will forcefully set it back to `AVAudioSessionCategoryPlayAndRecord`. - * - * @since v3.1.2. - */ - AdmCategoryNotPlayAndRecord = 1029, - /** - * 1031: Audio Device Module: the recorded audio is too low. - */ - AdmRecordAudioLowlevel = 1031, - /** - * 1032: Audio Device Module: the playback audio is too low. - */ - AdmPlayoutAudioLowlevel = 1032, - /** - * 1033: Audio Device Module: The recording device is busy. - */ - AdmRecordIsOccupied = 1033, - /** - * 1040: Audio device module: An error occurs in the audio driver. Solutions: - * - Restart your audio device. - * - Restart your device where the app runs. - * - Upgrade the sound card drive. - * - * @since v3.1.2. - */ - AdmNoDataReadyCallback = 1040, - /** - * 1042: Audio device module: The audio recording device is different from the audio playback device, which may cause echoes problem. Agora recommends using the same audio device to record and playback audio. - * - * @since v3.1.2. - */ - AdmInconsistentDevices = 1042, - /** - * 1051: Audio Device Module: howling is detected. - */ - ApmHowling = 1051, - /** - * 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, -} - -/** - * The audio channel of the sound. - */ -export enum AudioChannel { - /** - * 0: (Default) Supports dual channels. Depends on the upstream of the host. - */ - Channel0 = 0, - /** - * 1: The audio stream of the host uses the FL audio channel. If the upstream of the host uses multiple audio channels, these channels will be mixed into mono first. - */ - Channel1 = 1, - /** - * 2: The audio stream of the host uses the FC audio channel. If the upstream of the host uses multiple audio channels, these channels will be mixed into mono first. - */ - Channel2 = 2, - /** - * 3: The audio stream of the host uses the FR audio channel. If the upstream of the host uses multiple audio channels, these channels will be mixed into mono first. - */ - Channel3 = 3, - /** - * 4: The audio stream of the host uses the BL audio channel. If the upstream of the host uses multiple audio channels, these channels will be mixed into mono first. - */ - Channel4 = 4, - /** - * 5: The audio stream of the host uses the BR audio channel. If the upstream of the host uses multiple audio channels, these channels will be mixed into mono first. - */ - Channel5 = 5, -} - -/** - * Video codec types. - */ -export enum VideoCodecType { - /** - * 1: Standard VP8. - */ - VP8 = 1, - /** - * 2: Standard H264. - */ - H264 = 2, - /** - * 3: Enhanced VP8. - */ - EVP = 3, - /** - * 4: Enhanced H264. - */ - E264 = 4, -} - -/** - * The publishing state. - * - * @since v3.1.2. - */ -export enum StreamPublishState { - /** - * 0: The initial publishing state after joining the channel. - */ - Idle = 0, - /** - * 1: Fails to publish the local stream. Possible reasons: - * - The local user calls [`muteLocalAudioStream(true)`]{@link RtcEngine.muteLocalAudioStream} or [`muteLocalVideoStream(true)`]{@link RtcEngine.muteLocalVideoStream} to stop sending local streams. - * - The local user calls [`disableAudio`]{@link RtcEngine.disableAudio} or [`disableVideo`]{@link RtcEngine.disableVideo} to disable the entire audio or video module. - * - The local user calls [`enableLocalAudio(false)`]{@link RtcEngine.enableLocalAudio} or [`enableLocalVideo(false)`]{@link enableLocalVideo} to disable the local audio sampling or video capturing. - * - The role of the local user is `Audience`. - */ - NoPublished = 1, - /** - * 2: Publishing. - */ - Publishing = 2, - /** - * 3: Publishes successfully. - */ - Published = 3, -} - -/** - * The subscribing state. - * - * @since v3.1.2. - */ -export enum StreamSubscribeState { - /** - * 0: The initial subscribing state after joining the channel. - */ - Idle = 0, - /** - * 1: Fails to subscribe to the remote stream. Possible reasons: - * - The remote user: - * - Calls [`muteLocalAudioStream(true)`]{@link RtcEngine.muteLocalAudioStream} or [`muteLocalVideoStream(true)`]{@link RtcEngine.muteLocalVideoStream} to stop sending local streams. - * - The local user calls [`disableAudio`]{@link RtcEngine.disableAudio} or [`disableVideo`]{@link RtcEngine.disableVideo} to disable the entire audio or video module. - * - The local user calls [`enableLocalAudio(false)`]{@link RtcEngine.enableLocalAudio} or [`enableLocalVideo(false)`]{@link enableLocalVideo} to disable the local audio sampling or video capturing. - * - The role of the local user is `Audience`. - * - The local user calls the following methods to stop receiving remote streams: - * - Calls [`muteRemoteAudioStream(true)`]{@link RtcEngine.muteRemoteAudioStream}, [`muteAllRemoteAudioStreams(true)`]{@link RtcEngine.muteAllRemoteAudioStreams}, or [`setDefaultMuteAllRemoteAudioStreams(true)`]{@link RtcEngine.setDefaultMuteAllRemoteAudioStreams} to stop receiving remote audio streams. - * - Calls [`muteRemoteVideoStream(true)`]{@link RtcEngine.muteRemoteVideoStream}, [`muteAllRemoteVideoStreams(true)`]{@link RtcEngine.muteAllRemoteVideoStreams}, or [`setDefaultMuteAllRemoteVideoStreams(true)`]{@link RtcEngine.setDefaultMuteAllRemoteVideoStreams} to stop receiving remote video streams. - */ - NoSubscribed = 1, - /** - * 2: Subscribing. - */ - Subscribing = 2, - /** - * 3: Subscribes to and receives the remote stream successfully. - */ - Subscribed = 3, -} - -/** - * Events during the RTMP streaming. - */ -export enum RtmpStreamingEvent { - /** - * 1: An error occurs when you add a background image or a watermark image to the RTMP stream. - */ - FailedLoadImage = 1, -} - -/** - * Audio session restriction. - */ -export enum AudioSessionOperationRestriction { - /** - * No restriction, the SDK has full control of the audio session operations. - */ - None = 0, - /** - * The SDK does not change the audio session category. - */ - SetCategory = 1, - /** - * The SDK does not change any setting of the audio session (category, mode, categoryOptions). - */ - ConfigureSession = 1 << 1, - /** - * The SDK keeps the audio session active when leaving a channel. - */ - DeactivateSession = 1 << 2, - /** - * The SDK does not configure the audio session anymore. - */ - All = 1 << 7, -} diff --git a/src/src/RtcChannel.native.ts b/src/src/RtcChannel.native.ts deleted file mode 100644 index 1fad8102c..000000000 --- a/src/src/RtcChannel.native.ts +++ /dev/null @@ -1,894 +0,0 @@ -import {NativeEventEmitter, NativeModules} from "react-native" - -import { - ChannelMediaOptions, - ChannelMediaRelayConfiguration, - ClientRole, - ConnectionStateType, - EncryptionConfig, - EncryptionMode, - LiveInjectStreamConfig, - LiveTranscoding, - UserPriority, - VideoStreamType -} from "../Types" -import {Listener, RtcChannelEvents, Subscription} from "./RtcEvents" - -const { - /** - * @ignore - */ - AgoraRtcChannelModule -} = NativeModules -/** - * @ignore - */ -const Prefix = AgoraRtcChannelModule.prefix -/** - * @ignore - */ -const RtcChannelEvent = new NativeEventEmitter(AgoraRtcChannelModule) - -/** - * @ignore - */ -const channels = new Map() - -/** - * The {@link RtcChannel} class. - */ -export default class RtcChannel implements RtcChannelInterface { - /** - * The ID of RtcChannel - */ - public readonly channelId: string - /** - * @ignore - */ - private _listeners = new Map>() - - /** - * @ignore - */ - private constructor(channelId: string) { - this.channelId = channelId - } - - /** - * @ignore - */ - private _callMethod(method: string, args?: {}): Promise { - return AgoraRtcChannelModule.callMethod(method, args === undefined ? {channelId: this.channelId} : {channelId: this.channelId, ...args}); - } - - /** - * Creates and gets an [`RtcChannel`]{@link RtcChannel} instance. - * - * To join more than one channel, call this method multiple times to create as many `RtcChannel` instances as needed, - * and call the [`joinChannel`]{@link RtcChannel.joinChannel} method of each created `RtcChannel` object. - * - * After joining multiple channels, you can simultaneously subscribe to streams of all the channels, but publish a stream in only one channel at one time. - * @param channelId The unique channel name for the Agora RTC session in the string format. - * The string length must be less than 64 bytes. - * Supported character scopes are: - * - All lowercase English letters: a to z. - * - All uppercase English letters: A to Z. - * - All numeric characters: 0 to 9. - * - The space character. - * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". - * - * **Note** - * - This parameter does not have a default value. You must set it. - * - Do not set it as the empty string "". Otherwise, the SDK returns [`Refused(-5)`]{@link ErrorCode.Refused}. - * - * @returns - * - An `RtcChannel` instance, if the method call succeeds. - * - Null, if the method call fails. - * - [`Refused(-5)`]{@link ErrorCode.Refused}, if you set channelId as the empty string "". - */ - static async create(channelId: string): Promise { - if (channels.get(channelId)) return channels.get(channelId) as RtcChannel - await AgoraRtcChannelModule.callMethod('create', {channelId}) - channels.set(channelId, new RtcChannel(channelId)) - return channels.get(channelId) as RtcChannel - } - - /** - * Destroys all [`RtcChannel`]{@link RtcChannel} instances. - */ - static destroyAll() { - channels.forEach(async (value) => { - await value.destroy() - }) - channels.clear() - } - - /** - * Destroys the [`RtcChannel`]{@link RtcChannel} instance. - */ - destroy(): Promise { - this.removeAllListeners() - channels.delete(this.channelId) - return this._callMethod('destroy') - } - - /** - * Adds the [`RtcChannelEvents`]{@link RtcChannelEvents} handler. - * - * After setting the [`RtcChannelEvents`]{@link RtcChannelEvents} handler, you can listen for channel events and receive the statistics of the corresponding [`RtcChannel`]{@link RtcChannel} instance. - * @param event The event type. - * @param listener The [`RtcChannelEvents`]{@link RtcChannelEvents} handler. - */ - addListener(event: EventType, listener: RtcChannelEvents[EventType]): Subscription { - const callback = (res: any) => { - const {channelId, data} = res - if (channelId === this.channelId) { - // @ts-ignore - listener(...data) - } - } - let map = this._listeners.get(event) - if (map === undefined) { - map = new Map() - this._listeners.set(event, map) - } - RtcChannelEvent.addListener(Prefix + event, callback) - map.set(listener, callback) - return { - remove: () => { - this.removeListener(event, listener) - } - } - } - - /** - * Removes the [`RtcChannelEvents`]{@link RtcChannelEvents} handler. - * - * For callback events that you only want to listen for once, call this method to remove the specific [`RtcEngineEvents`]{@link RtcEngineEvents} objects after you have received them. - * @param event The event type. - * @param listener The [`RtcChannelEvents`]{@link RtcChannelEvents} handler. - */ - removeListener(event: EventType, listener: RtcChannelEvents[EventType]) { - const map = this._listeners.get(event) - if (map === undefined) return - RtcChannelEvent.removeListener(Prefix + event, map.get(listener) as Listener) - map.delete(listener) - } - - /** - * Removes all the [`RtcChannelEvents`]{@link RtcChannelEvents} handlers. - * @param event The event type. - */ - removeAllListeners(event?: EventType) { - if (event === undefined) { - this._listeners.forEach((value, key) => { - RtcChannelEvent.removeAllListeners(Prefix + key) - }) - this._listeners.clear() - return - } - RtcChannelEvent.removeAllListeners(Prefix + event) - this._listeners.delete(event as string) - } - - /** - * Sets the role of a user. - * - * 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: - * - 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. - */ - setClientRole(role: ClientRole): Promise { - return this._callMethod('setClientRole', {role}) - } - - /** - * Joins the channel with a user ID. - * - * **Note** - * - If you are already in a channel, you cannot rejoin it with the same UID. - * - We recommend using different UIDs for different channels. - * - 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. - * - * @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. - */ - joinChannel(token: string | null, optionalInfo: string | null, optionalUid: number, options: ChannelMediaOptions): Promise { - return this._callMethod('joinChannel', {token, optionalInfo, optionalUid, options}) - } - - /** - * Joins a channel with the user account. - * - * **Note** - * - If you are already in a channel, you cannot rejoin it with the same user account. - * - We recommend using different user accounts for different channels. - * - 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. - * - * @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 userAccount The user account. The maximum length of this parameter is 255 bytes. Ensure that you set this parameter and do not set it as null. - * - All lowercase English letters: a to z. - * - All uppercase English letters: A to Z. - * - All numeric characters: 0 to 9. - * - The space character. - * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". - * @param options The channel media options. - */ - joinChannelWithUserAccount(token: string | null, userAccount: string, options: ChannelMediaOptions): Promise { - return this._callMethod('joinChannelWithUserAccount', {token, userAccount, options}) - } - - /** - * Leaves the current channel. - * - * 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. - */ - leaveChannel(): Promise { - return this._callMethod('leaveChannel') - } - - /** - * Renews the token when the current token expires. - * - * In the following situations, the SDK decides that the current token has expired: - * - The SDK triggers the [`TokenPrivilegeWillExpire`]{@link RtcChannelEvents.TokenPrivilegeWillExpire} callback, or - * - The [`ConnectionStateChanged`]{@link RtcChannelEvents.ConnectionStateChanged} callback reports the [`TokenExpired(9)`]{@link ConnectionChangedReason.TokenExpired} error. - * - * 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. - */ - renewToken(token: string): Promise { - return this._callMethod('renewToken', {token}) - } - - /** - * Gets the network connection state of the SDK. - */ - getConnectionState(): Promise { - return this._callMethod('getConnectionState') - } - - /** - * Publishes the local stream to the channel. - * You must keep the following restrictions in mind when calling this method. - * Otherwise, the SDK returns the [`Refused(-5)`]{@link ErrorCode.Refused}: - * - This method publishes one stream only to the channel corresponding to the current [`RtcChannel`]{@link RtcChannel} instance. - * - In a `LiveBroadcasting` channel, only a host can call this method. To switch the client role, call [`setClientRole`]{@link RtcChannel.setClientRole} of the current [`RtcChannel`]{@link RtcChannel} instance. - * - You can publish a stream to only one channel at a time. For details, see the advanced guide *Join Multiple Channels*. - */ - publish(): Promise { - return this._callMethod('publish') - } - - /** - * Stops publishing a stream to the channel. - * - * If you call this method in a channel where you are not publishing streams, the SDK returns [`Refused(-5)`]{@link ErrorCode.Refused}. - */ - unpublish(): Promise { - return this._callMethod('unpublish') - } - - /** - * Gets the current call ID. - * - * @returns - * - The current call ID, if the method call succeeds. - * - The empty string "", if the method call fails. - */ - getCallId(): Promise { - return this._callMethod('getCallId') - } - - /** - * Adjusts the playback volume of a specified remote user. - * - * You can call this method as many times as necessary to adjust the playback volume of different remote - * users, or to repeatedly adjust the playback volume of the same remote user. - * - * **Note** - * - Call this method after joining a channel. - * - The playback volume here refers to the mixed volume of a specified remote user. - * - This method can only adjust the playback volume of one specified remote user at a time. - * To adjust the playback volume of different remote users, call the method as many times, once for each remote user. - * - * @param uid ID of the remote user. - * @param volume The playback volume of the specified remote user. The value ranges from 0 to 100: - * - 0: Mute. - * - 100: The original volume. - */ - adjustUserPlaybackSignalVolume(uid: number, volume: number): Promise { - return this._callMethod('adjustUserPlaybackSignalVolume', {uid, volume}) - } - - /** - * Stops/Resumes receiving the audio stream of the specified user. - * - * @param uid ID of the remote user whose audio stream you want to mute. - * @param muted Determines whether to receive/stop receiving the audio stream of the specified user: - * - `true`: Stop receiving the audio stream of the user. - * - `false`: (Default) Receive the audio stream of the user. - */ - muteRemoteAudioStream(uid: number, muted: boolean): Promise { - return this._callMethod('muteRemoteAudioStream', {uid, muted}) - } - - /** - * Stops/Resumes receiving all remote audio streams. - * - * @param muted Determines whether to receive/stop receiving all remote audio streams: - * - `true`: Stop receiving all remote audio streams. - * - `false`: (Default) Receive all remote audio streams. - */ - muteAllRemoteAudioStreams(muted: boolean): Promise { - return this._callMethod('muteAllRemoteAudioStreams', {muted}) - } - - /** - * Sets whether to receive all remote audio streams by default. - * - * @param muted Determines whether to receive/stop receiving all remote audio streams by default: - * - `true`: Stop receiving all remote audio streams by default. - * - `false`: (Default) Receive all remote audio streams by default. - */ - setDefaultMuteAllRemoteAudioStreams(muted: boolean): Promise { - return this._callMethod('setDefaultMuteAllRemoteAudioStreams', {muted}) - } - - /** - * Stops/Resumes receiving all remote video streams. - * - * @param muted Determines whether to receive/stop receiving all remote video streams: - * - `true`: Stop receiving all remote video streams. - * - `false`: (Default) Receive all remote video streams. - */ - muteAllRemoteVideoStreams(muted: boolean): Promise { - return this._callMethod('muteAllRemoteVideoStreams', {muted}) - } - - /** - * Stops/Resumes receiving the video stream of the specified user. - * - * @param uid ID of the remote user whose video stream you want to mute. - * @param muted Determines whether to receive/stop receiving the video stream of the specified user: - * - `true`: Stop receiving the video stream of the user. - * - `false`: (Default) Receive the video stream of the user. - */ - muteRemoteVideoStream(uid: number, muted: boolean): Promise { - return this._callMethod('muteRemoteVideoStream', {uid, muted}) - } - - /** - * Sets whether to receive all remote video streams by default. - * - * @param muted Determines whether to receive/stop receiving all remote video streams by default: - * - `true`: Stop receiving all remote video streams by default. - * - `false`: (Default) Receive all remote video streams by default. - */ - setDefaultMuteAllRemoteVideoStreams(muted: boolean): Promise { - return this._callMethod('setDefaultMuteAllRemoteVideoStreams', {muted}) - } - - /** - * Sets the sound position of a remote user. - * - * When the local user calls this method to set the sound position of a remote user, the sound difference between the left and right channels allows the local user to track the real-time position of the remote user, creating a real sense of space. This method applies to massively multiplayer online games, such as Battle Royale games. - * - * **Note** - * - For this method to work, enable stereo panning for remote users by calling the [`enableSoundPositionIndication`]{@link RtcEngine.enableSoundPositionIndication} method before joining a channel. - * - This method requires hardware support. For the best sound positioning, we recommend using a stereo headset. - * - * @param uid The ID of the remote user. - * @param pan The sound position of the remote user. The value ranges from -1.0 to 1.0: - * - 0.0: (default) The remote sound comes from the front. - * - -1.0: The remote sound comes from the left. - * - 1.0: The remote sound comes from the right. - * @param gain Gain of the remote user. The value ranges from 0.0 to 100.0. The default value is 100.0 (the original gain of the remote user). The smaller the value, the less the gain. - */ - setRemoteVoicePosition(uid: number, pan: number, gain: number): Promise { - return this._callMethod('setRemoteVoicePosition', {uid, pan, gain}) - } - - /** - * Publishes the local stream 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. - * - * **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 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. - * - * @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, - * 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. - */ - addPublishStreamUrl(url: string, transcodingEnabled: boolean): Promise { - return this._callMethod('addPublishStreamUrl', {url, transcodingEnabled}) - } - - /** - * Removes an RTMP stream from the CDN. - * - * This method removes the RTMP URL address (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. - * - * @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, - * such as Chinese language characters. - */ - removePublishStreamUrl(url: string): Promise { - return this._callMethod('removePublishStreamUrl', {url}) - } - - /** - * Sets the video layout and audio settings for CDN live. - * - * The SDK triggers the [`TranscodingUpdated`]{@link RtcChannelEvents.TranscodingUpdated} callback when you - * call this method to update the [`LiveTranscoding`]{@link LiveTranscoding} class. If you call this method to set the [`LiveTranscoding`]{@link LiveTranscoding} - * class for the first time, the SDK does not trigger the [`TranscodingUpdated`]{@link RtcChannelEvents.TranscodingUpdated} 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 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. - * - * @param transcoding Sets the CDN live audio/video transcoding settings. - */ - setLiveTranscoding(transcoding: LiveTranscoding): Promise { - return this._callMethod('setLiveTranscoding', {transcoding}) - } - - /** - * Starts to relay media streams across channels. - * - * After a successful method call, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcChannelEvents.ChannelMediaRelayStateChanged} and [`ChannelMediaRelayEvent`]{@link RtcChannelEvents.ChannelMediaRelayEvent} callbacks, - * and these callbacks report the state and events of the media stream relay. - * - * - If the [`ChannelMediaRelayStateChanged`]{@link RtcChannelEvents.ChannelMediaRelayStateChanged} callback reports [`Running(2)`]{@link ChannelMediaRelayState.Running} and [`None(0)`]{@link ChannelMediaRelayError.None}, and - * the [`ChannelMediaRelayEvent`]{@link RtcChannelEvents.ChannelMediaRelayEvent} callback - * reports [`SentToDestinationChannel(4)`]{@link ChannelMediaRelayEvent.SentToDestinationChannel}, the SDK starts relaying media streams between the original and the destination channel. - * - * - If the [`ChannelMediaRelayStateChanged`]{@link RtcChannelEvents.ChannelMediaRelayStateChanged} callback returns [`Failure(3)`]{@link ChannelMediaRelayState.Failure}, an exception occurs during the media stream relay. - * - * **Note** - * - Contact support@agora.io before implementing this function. - * - We do not support string user accounts in this API. - * - Call this method after joining the channel. - * - This method can only be called by a host in a `LiveBroadcasting` channel. - * - After a successful method call, if you want to call this method again, ensure that you call the [`stopChannelMediaRelay`]{@link RtcChannel.stopChannelMediaRelay} method to quit the current relay. - * - * @param channelMediaRelayConfiguration The configuration of the media stream relay. - */ - startChannelMediaRelay(channelMediaRelayConfiguration: ChannelMediaRelayConfiguration): Promise { - return this._callMethod('startChannelMediaRelay', {channelMediaRelayConfiguration}) - } - - /** - * Stops the media stream relay. - * - * Once the relay stops, the host quits all the destination channels. - * After a successful method call, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcChannelEvents.ChannelMediaRelayStateChanged} callback. If the callback reports [`Idle(0)`]{@link ChannelMediaRelayState.Idle} and - * [`None(0)`]{@link ChannelMediaRelayError.None}, the host successfully stops the relay. - * - * **Note** - * - If the method call fails, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcChannelEvents.ChannelMediaRelayStateChanged} callback with - * the [`ServerNoResponse(2)`]{@link ChannelMediaRelayError.ServerNoResponse} or [`ServerConnectionLost(8)`]{@link ChannelMediaRelayError.ServerConnectionLost} state code. - * You can leave the channel using [`leaveChannel`]{@link RtcChannel.leaveChannel}, and the media stream relay automatically stops. - */ - stopChannelMediaRelay(): Promise { - return this._callMethod('stopChannelMediaRelay') - } - - /** - * Updates the channels for media relay. - * - * After the channel media relay starts, if you want to relay the media stream to more channels, or leave the current relay channel, you can call this method. - * After a successful method call, the SDK triggers the [`ChannelMediaRelayEvent`]{@link RtcChannelEvents.ChannelMediaRelayEvent} callback with - * the [`UpdateDestinationChannel(7)`]{@link ChannelMediaRelayEvent.UpdateDestinationChannel} state code. - * - * **Note** - * - Call this method after the [`startChannelMediaRelay`]{@link RtcChannel.startChannelMediaRelay} method to update the destination channel. - * - This method supports adding at most four destination channels in the relay. - * - * @param channelMediaRelayConfiguration The media stream relay configuration. - */ - updateChannelMediaRelay(channelMediaRelayConfiguration: ChannelMediaRelayConfiguration): Promise { - return this._callMethod('updateChannelMediaRelay', {channelMediaRelayConfiguration}) - } - - /** - * Sets the default video-stream type of the remote video stream when the remote user sends dual streams. - * - * @param streamType Sets the default video-stream type. - */ - setRemoteDefaultVideoStreamType(streamType: VideoStreamType): Promise { - return this._callMethod('setRemoteDefaultVideoStreamType', {streamType}) - } - - /** - * Sets the video stream type of the remote video stream when the remote user sends dual streams. - * This method allows the app to adjust the corresponding video-stream type based on the size of the - * video window to reduce the bandwidth and resources. - * - If the remote user enables the dual-stream mode by calling the [`enableDualStreamMode`]{@link RtcEngine.enableDualStreamMode} method, - * the SDK receives the high-video stream by default. You can use this method to switch to the low-video stream. - * - If dual-stream mode is not enabled, the SDK receives the high-stream video by default. - * By default, the aspect ratio of the low-video stream is the same as the high-video stream. Once the resolution of the high-video stream is set, - * the system automatically sets the resolution, frame rate, and bitrate of the low-video stream. - * - * @param uid ID of the remote user sending the video stream. - * @param streamType Sets the video-stream type. - */ - setRemoteVideoStreamType(uid: number, streamType: VideoStreamType): Promise { - return this._callMethod('setRemoteVideoStreamType', {uid, streamType}) - } - - /** - * Sets the priority of a remote user's media stream. - * - * Use this method with the [`setRemoteSubscribeFallbackOption`]{@link RtcEngine.setRemoteSubscribeFallbackOption} method. - * If a remote video stream experiences the fallback, the SDK ensures the high-priority user gets the best possible stream quality. - * - * **Note** - * The Agora SDK supports setting userPriority as high for one user only. - * - * @param uid The ID of the remote user. - * @param userPriority The priority of the remote user. - */ - setRemoteUserPriority(uid: number, userPriority: UserPriority): Promise { - return this._callMethod('setRemoteUserPriority', {uid, userPriority}) - } - - /** - * Registers the metadata observer. - * - * A successful call of this method triggers the [`setMaxMetadataSize`]{@link RtcChannel.setMaxMetadataSize} method. - * - * This method enables you to add synchronized metadata in the video stream for more diversified live streaming interactions, - * such as sending shopping links, digital coupons, and online quizzes. - * - * **Note** - * - Call this method before the [`joinChannel`]{@link RtcChannel.joinChannel} method. - * - This method applies to the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile only. - */ - registerMediaMetadataObserver(): Promise { - return this._callMethod('registerMediaMetadataObserver') - } - - /** - * Sends the metadata. - * - * @param metadata The metadata to be sent. - */ - sendMetadata(metadata: string): Promise { - return this._callMethod('sendMetadata', {metadata}) - } - - /** - * Sets the maximum size of the metadata. - * - * @param size Buffer size of the sent or received metadata. - */ - setMaxMetadataSize(size: number): Promise { - return this._callMethod('setMaxMetadataSize', {size}) - } - - /** - * Unregisters the metadata observer. - */ - unregisterMediaMetadataObserver(): Promise { - return this._callMethod('unregisterMediaMetadataObserver') - } - - /** - * Enables/Disables the built-in encryption. - * - * @since v3.1.2. - * - * In scenarios requiring high security, Agora recommends calling `enableEncryption` to enable the built-in encryption before joining a channel. - * - * 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. - * - 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*. - * - * - * @param enabled Whether to enable the built-in encryption. - * - `true`: Enable the built-in encryption. - * - `false`: Disable the built-in encryption. - * @param config Configurations of built-in encryption schemas. See [`EncryptionConfig`]{@link EncryptionConfig}. - */ - enableEncryption(enabled: boolean, config: EncryptionConfig): Promise { - return this._callMethod('enableEncryption', {enabled, config}); - } - - /** - * Sets the built-in encryption mode. - * - * @deprecated - * Deprecated as of v3.1.2. Use [`enableEncryption`]{@link enableEncryption} instead. - * - * The Agora SDK supports built-in encryption, which is set to aes-128-xts mode by default. - * Call this method to set the encryption mode to use other encryption modes. - * All users in the same channel must use the same encryption mode and password. - * Refer to the information related to the AES encryption algorithm on the differences between the encryption modes. - * - * **Note** - * - Do not use this method for CDN streaming. - * - Before calling this method, ensure that you have called [`setEncryptionSecret`]{@link RtcChannel.setEncryptionSecret} to enable encryption. - * - * @param encryptionMode Sets the encryption mode. - */ - setEncryptionMode(encryptionMode: EncryptionMode): Promise { - return this._callMethod('setEncryptionMode', {encryptionMode}) - } - - /** - * Enables built-in encryption with an encryption password before joining a channel. - * - * @deprecated - * Deprecated as of v3.1.2. Use [`enableEncryption`]{@link enableEncryption} instead. - * - * All users in a channel must set the same encryption password. - * The encryption password is automatically cleared once a user leaves the channel. - * If the encryption password is not specified or set to empty, the encryption functionality is disabled. - * - * **Note** - * - For optimal transmission, ensure that the encrypted data size does not exceed the original data size + 16 bytes. 16 bytes is the maximum padding size for AES encryption. - * - Do not use this method for CDN live streaming. - * - * @param secret The encryption password. - */ - setEncryptionSecret(secret: string): Promise { - return this._callMethod('setEncryptionSecret', {secret}) - } - - /** - * Injects an online media stream to live interactive streaming. - * - * If this method call succeeds, the server pulls the voice or video stream and injects it into a live channel. This applies to scenarios where all audience members in the channel can watch a live show and interact with each other. - * - * Calling this method triggers the following callbacks: - * - The local client: - * - [`StreamInjectedStatus`]{@link RtcChannelEvents.StreamInjectedStatus}, with the state of injecting the media stream. - * - [`UserJoined`]{@link RtcChannelEvents.UserJoined}(uid: 666), if the method call succeeds and the online - * media stream is injected into the channel. - * - The remote client: - * - [`UserJoined`]{@link RtcChannelEvents.UserJoined}(uid: 666), if the method call succeeds and the online - * media stream is injected into the channel. - * - * **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. - * - * @param url The URL address to be added to the ongoing live interactive streaming. Valid protocols are RTMP, HLS, and FLV. - * - 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. - */ - addInjectStreamUrl(url: string, config: LiveInjectStreamConfig): Promise { - return this._callMethod('addInjectStreamUrl', {url, config}) - } - - /** - * Removes the injected online media stream from a `LiveBroadcasting` channel. - * - * This method removes the URL address added by [`addInjectStreamUrl`]{@link RtcChannel.addInjectStreamUrl}. - * - * If you successfully remove the URL address from the live interactive streaming, the SDK triggers the - * [`UserJoined`]{@link RtcChannelEvents.UserJoined} callback, with the stream uid of 666. - * - * @param url The URL address to be removed. - */ - removeInjectStreamUrl(url: string): Promise { - return this._callMethod('removeInjectStreamUrl', {url}) - } - - /** - * Creates a data stream. - * - * Each user can create up to five data streams during the life cycle of the [`RtcChannel`]{@link RtcChannel} instance. - * - * **Note** - * - * Set both the `reliable` and `ordered` parameters to `true` or `false`. Do not set one as `true` - * and the other as `false`. - * @param reliable Sets whether the recipients are guaranteed to receive the data stream from the - * sender within five seconds. - * - `true`: The recipients receive the data from the sender within five seconds. If the recipient does - * not receive the data within five seconds, the SDK triggers the [`StreamMessageError`]{@link RtcChannelEvents.StreamMessageError} callback and returns an error code. - * - `false`: There is no guarantee that the recipients receive the data stream within five seconds and no error message is reported for any delay or missing data stream. - * @param ordered Determines whether the recipients receive the data stream in the sent order. - * - `true`: The recipients receive the data in the sent order. - * - `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}. - */ - createDataStream(reliable: boolean, ordered: boolean): Promise { - return this._callMethod('createDataStream', {reliable, ordered}) - } - - /** - * Sends the data stream message. - * - * The SDK has the following restrictions on this method: - * - Up to 30 packets can be sent per second in a channel with each packet having a maximum size of 1 KB. - * - Each client can send up to 6 KB of data per second. - * - Each user can have up to five data channels simultaneously. - * - * A successful call of this method triggers the [`StreamMessage`]{@link RtcChannelEvents.StreamMessage} callback on the remote client, from which the remote user gets the stream message. - * - * A failed call of this method triggers the [`StreamMessageError`]{@link RtcChannelEvents.StreamMessageError} callback on the remote client. - * - * @param streamId ID of the sent data stream returned by the [`createDataStream`]{@link RtcChannel.createDataStream} method. - * - * @param message The message data. - */ - sendStreamMessage(streamId: number, message: string): Promise { - return this._callMethod('sendStreamMessage', {streamId, message}) - } -} - -/** - * @ignore - */ -interface RtcChannelInterface extends RtcAudioInterface, RtcVideoInterface, RtcVoicePositionInterface, - RtcPublishStreamInterface, RtcMediaRelayInterface, RtcDualStreamInterface, RtcFallbackInterface, - RtcMediaMetadataInterface, RtcEncryptionInterface, RtcInjectStreamInterface, RtcStreamMessageInterface { - destroy(): Promise - - setClientRole(role: ClientRole): Promise - - joinChannel(token: string | null, optionalInfo: string | null, optionalUid: number, options: ChannelMediaOptions): Promise - - joinChannelWithUserAccount(token: string | null, userAccount: string, options: ChannelMediaOptions): Promise - - leaveChannel(): Promise - - renewToken(token: string): Promise - - getConnectionState(): Promise - - publish(): Promise - - unpublish(): Promise - - getCallId(): Promise -} - -/** - * @ignore - */ -interface RtcAudioInterface { - adjustUserPlaybackSignalVolume(uid: number, volume: number): Promise - - muteRemoteAudioStream(uid: number, muted: boolean): Promise - - muteAllRemoteAudioStreams(muted: boolean): Promise - - setDefaultMuteAllRemoteAudioStreams(muted: boolean): Promise -} - -/** - * @ignore - */ -interface RtcVideoInterface { - muteRemoteVideoStream(uid: number, muted: boolean): Promise - - muteAllRemoteVideoStreams(muted: boolean): Promise - - setDefaultMuteAllRemoteVideoStreams(muted: boolean): Promise -} - -/** - * @ignore - */ -interface RtcVoicePositionInterface { - setRemoteVoicePosition(uid: number, pan: number, gain: number): Promise -} - -/** - * @ignore - */ -interface RtcPublishStreamInterface { - setLiveTranscoding(transcoding: LiveTranscoding): Promise - - addPublishStreamUrl(url: string, transcodingEnabled: boolean): Promise - - removePublishStreamUrl(url: string): Promise -} - -/** - * @ignore - */ -interface RtcMediaRelayInterface { - startChannelMediaRelay(channelMediaRelayConfiguration: ChannelMediaRelayConfiguration): Promise - - updateChannelMediaRelay(channelMediaRelayConfiguration: ChannelMediaRelayConfiguration): Promise - - stopChannelMediaRelay(): Promise -} - -/** - * @ignore - */ -interface RtcDualStreamInterface { - setRemoteVideoStreamType(uid: number, streamType: VideoStreamType): Promise - - setRemoteDefaultVideoStreamType(streamType: VideoStreamType): Promise -} - -/** - * @ignore - */ -interface RtcFallbackInterface { - setRemoteUserPriority(uid: number, userPriority: UserPriority): Promise -} - -/** - * @ignore - */ -interface RtcMediaMetadataInterface { - registerMediaMetadataObserver(): Promise - - unregisterMediaMetadataObserver(): Promise - - setMaxMetadataSize(size: number): Promise - - sendMetadata(metadata: string): Promise -} - -/** - * @ignore - */ -interface RtcEncryptionInterface { - setEncryptionSecret(secret: string): Promise - - setEncryptionMode(encryptionMode: EncryptionMode): Promise - - enableEncryption(enabled: boolean, config: EncryptionConfig): Promise -} - -/** - * @ignore - */ -interface RtcInjectStreamInterface { - addInjectStreamUrl(url: string, config: LiveInjectStreamConfig): Promise - - removeInjectStreamUrl(url: string): Promise -} - -/** - * @ignore - */ -interface RtcStreamMessageInterface { - createDataStream(reliable: boolean, ordered: boolean): Promise - - sendStreamMessage(streamId: number, message: string): Promise -} diff --git a/src/src/RtcEngine.native.ts b/src/src/RtcEngine.native.ts deleted file mode 100644 index f05fa5d44..000000000 --- a/src/src/RtcEngine.native.ts +++ /dev/null @@ -1,2678 +0,0 @@ -import {NativeEventEmitter, NativeModules} from "react-native" - -import { - AreaCode, - AudioEqualizationBandFrequency, - AudioProfile, - AudioRecordingQuality, - AudioReverbPreset, - AudioReverbType, - AudioSampleRateType, - AudioScenario, - AudioSessionOperationRestriction, - AudioVoiceChanger, - BeautyOptions, - CameraCapturerConfiguration, - ChannelMediaRelayConfiguration, - ChannelProfile, - ClientRole, - ConnectionStateType, - EncryptionConfig, - EncryptionMode, - LastmileProbeConfig, - LiveInjectStreamConfig, - LiveTranscoding, - LogFilter, - StreamFallbackOptions, - UserInfo, - UserPriority, - VideoEncoderConfiguration, - VideoStreamType, - WatermarkOptions -} from "../Types" -import {Listener, RtcEngineEvents, Subscription} from "./RtcEvents" -import RtcChannel from "./RtcChannel.native" - -/** - * @ignore - */ -type Rate = 1 | 2 | 3 | 4 | 5 - -const { - /** - * @ignore - */ - AgoraRtcEngineModule -} = NativeModules -/** - * @ignore - */ -const Prefix = AgoraRtcEngineModule.prefix -/** - * @ignore - */ -const RtcEngineEvent = new NativeEventEmitter(AgoraRtcEngineModule) - -/** - * @ignore - */ -let engine: RtcEngine | undefined - -/** - * [`RtcEngine`]{@link RtcEngine} is the main class of the Agora SDK. - */ -export default class RtcEngine implements RtcEngineInterface { - /** - * @ignore - */ - private _listeners = new Map>() - - /** - * @ignore - */ - private static _callMethod(method: string, args?: {}): Promise { - return AgoraRtcEngineModule.callMethod(method, args); - } - - /** - * Gets a created [`RtcEngine`]{@link RtcEngine} instance. - * - * **Note** - * - * Ensure that you have created an `RtcEngine`. Otherwise, the method call fails and the SDK returns an error message. - * @returns - * - The `RtcEngine` instance, if the method call succeeds. - * - Returns an error when it fails to get an `RtcEngine`. - */ - static instance(): RtcEngine { - if (engine) { - return engine as RtcEngine - } else { - throw new Error('please create RtcEngine first') - } - } - - /** - * Creates an [`RtcEngine`]{@link RtcEngine} instance. - * - * Unless otherwise specified, all the methods provided by the [`RtcEngine`]{@link RtcEngine} class are executed asynchronously. Agora recommends calling these methods in the same thread. - * - * **Note** - * - You must create an [`RtcEngine`]{@link RtcEngine} instance before calling any other method. - * - You can create an [`RtcEngine`]{@link RtcEngine} instance either by calling this method or by calling [`createWithAreaCode`]{@link createWithAreaCode}. The difference between [`createWithAreaCode`]{@link createWithAreaCode} and this method is that [`createWithAreaCode`]{@link createWithAreaCode} enables you to specify the connection area. - * - The Agora React Native SDK supports creating only one [`RtcEngine`]{@link RtcEngine} instance for an app. - * @param appId The App ID issued to you by Agora. See [How to get the App ID](https://docs.agora.io/en/Agora%20Platform/token#get-an-app-id). - * Only users in apps with the same App ID can join the same channel and communicate with each other. - * Use an App ID to create only one [`RtcEngine`]{@link RtcEngine} instance. To change your App ID, call [`destroy`]{@link destroy} to destroy the current [`RtcEngine`]{@link RtcEngine} instance, and after [`destroy`]{@link destroy} returns `0`, - * call `create` to create an [`RtcEngine`]{@link RtcEngine} instance with the new App ID. - * @returns - * - The `RtcEngine` instance, if the method call succeeds. - * - The error code, if the method call fails. - */ - static async create(appId: string): Promise { - return RtcEngine.createWithAreaCode(appId, AreaCode.GLOB) - } - - /** - * Creates an [`RtcEngine`]{@link RtcEngine} instance. - * - * Unless otherwise specified, all the methods provided by the [`RtcEngine`]{@link RtcEngine} class are executed asynchronously. Agora recommends calling these methods in the same thread. - * - * **Note** - * - * - You must create an [`RtcEngine`]{@link RtcEngine} instance before calling any other method. - * - You can create an [`RtcEngine`]{@link RtcEngine} instance either by calling this method or by calling [`create`]{@link create}. The difference between [`create`]{@link create} and this method is that this method enables you to specify the connection area. - * - The Agora React Native SDK supports creating only one [`RtcEngine`]{@link RtcEngine} instance for an app. - * @param appId The App ID issued to you by Agora. See [How to get the App ID](https://docs.agora.io/en/Agora%20Platform/token#get-an-app-id). - * Only users in apps with the same App ID can join the same channel and communicate with each other. Use an App ID to create only one [`RtcEngine`]{@link RtcEngine} instance. - * To change your App ID, call [`destroy`]{@link destroy} to destroy the current [`RtcEngine`]{@link RtcEngine} instance and after [`destroy`]{@link destroy} returns `0`, call [`create`]{@link create} to create an [`RtcEngine`]{@link RtcEngine} instance with the new App ID. - * @param areaCode The area of connection. This advanced feature applies to scenarios that have regional restrictions. - * For details, see {@link AreaCode}. - * - * After specifying the region, the app that integrates the Agora SDK connects to the Agora servers within that region. - * - * @returns - * - The `RtcEngine` instance, if the method call succeeds. - * - The error code, if the method call fails. - */ - static async createWithAreaCode(appId: string, areaCode: AreaCode): Promise { - if (engine) return engine - await RtcEngine._callMethod('create', {appId, areaCode, appType: 8}) - engine = new RtcEngine() - return engine - } - - /** - * Destroys the [`RtcEngine`]{@link RtcEngine} instance and releases all resources used by the Agora SDK. - * - * Use this method for apps in which users occasionally make voice or video calls. When users do not make calls, you can free up resources for other operations. - * Once you call this method to destroy the created [`RtcEngine`]{@link RtcEngine} instance, you cannot use any method or callback in the SDK any more. - * If you want to use the real-time communication functions again, you must call `create` to create a new [`RtcEngine`]{@link RtcEngine} instance. - * - * **Note** - * - * - Because [`destroy`]{@link destroy} is a synchronous method and the app cannot move on to another task until the execution completes, - * Agora suggests calling this method in a sub-thread to avoid congestion in the main thread. - * Besides, you cannot call [`destroy`]{@link destroy} in any method or callback of the SDK. - * Otherwise, the SDK cannot release the resources occupied by the [`RtcEngine`]{@link RtcEngine} instance until the callbacks return results, which may result in a deadlock. - * - If you want to create a new [`RtcEngine`]{@link RtcEngine} instance after destroying the current one, ensure that you wait till the [`destroy`]{@link destroy} method completes executing. - */ - destroy(): Promise { - RtcChannel.destroyAll() - this.removeAllListeners() - engine = undefined - return RtcEngine._callMethod('destroy') - } - - /** - * Adds the [`RtcEngineEvents`]{@link RtcEngineEvents} handler. - * - * After setting the [`RtcEngineEvents`]{@link RtcEngineEvents} handler, you can listen for `RtcEngine` events and receive the statistics of the corresponding RtcEngine instance. - * @param event The event type. - * @param listener The [`RtcEngineEvents`]{@link RtcEngineEvents} handler. - */ - addListener(event: EventType, listener: RtcEngineEvents[EventType]): Subscription { - const callback = (res: any) => { - const {channelId, data} = res - if (channelId === undefined) { - // @ts-ignore - listener(...data) - } - } - let map = this._listeners.get(event) - if (map === undefined) { - map = new Map() - this._listeners.set(event, map) - } - RtcEngineEvent.addListener(Prefix + event, callback) - map.set(listener, callback) - return { - remove: () => { - this.removeListener(event, listener) - } - } - } - - /** - * Removes the [`RtcEngineEvents`]{@link RtcEngineEvents} handler. - * - * For callback events that you only want to listen for once, call this method to remove the specific [`RtcEngineEvents`]{@link RtcEngineEvents} objects after you have received them. - * @param event The event type. - * @param listener The [`RtcEngineEvents`]{@link RtcEngineEvents} handler. - */ - removeListener(event: EventType, listener: RtcEngineEvents[EventType]) { - const map = this._listeners.get(event) - if (map === undefined) return - RtcEngineEvent.removeListener(Prefix + event, map.get(listener) as Listener) - map.delete(listener) - } - - /** - * Removes all the [`RtcEngineEvents`]{@link RtcEngineEvents} handlers. - * @param event The event type. - */ - removeAllListeners(event?: EventType) { - if (event === undefined) { - this._listeners.forEach((value, key) => { - RtcEngineEvent.removeAllListeners(Prefix + key) - }) - this._listeners.clear() - return - } - RtcEngineEvent.removeAllListeners(Prefix + event) - this._listeners.delete(event as string) - } - - /** - * Sets the channel profile of the Agora [`RtcEngine`]{@link RtcEngine}. - * - * 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}. - */ - 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. - * - * 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: - * - 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. - */ - setClientRole(role: ClientRole): Promise { - return RtcEngine._callMethod('setClientRole', {role}) - } - - /** - * Allows a user to join a channel. - * - * Users in the same channel can talk to each other, and multiple users in the same channel can start a group chat. Users with different App IDs cannot call each other. - * You must call [`leaveChannel`]{@link leaveChannel} to exit the current call before joining another channel. - * - * A successful call of this method triggers the following callbacks: - * - * - The local client: [`JoinChannelSuccess`]{@link RtcEngineEvents.JoinChannelSuccess}. - * - * - The remote client: [`UserJoined`]{@link RtcEngineEvents.UserJoined}, 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. - * - * 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. - * - * **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. - * - * **Warning** - * - * Ensure that the App ID used for creating the token is the same App ID used in the `create` method for creating an [`RtcEngine`]{@link RtcEngine} object. Otherwise, CDN live streaming may fail. - * - * @param token The token for authentication: - * - 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 channelName The unique channel name for the AgoraRTC session in the string format. The string length must be less than 64 bytes. Supported character scopes are: - * - All lowercase English letters: a to z. - * - All uppercase English letters: A to Z. - * - All numeric characters: 0 to 9. - * - The space character. - * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". - * @param optionalInfo Additional information about the channel. This parameter can be set as null or contain channel related information. Other users in the channel do not receive this message. - * @param optionalUid (Optional) User ID. A 32-bit unsigned integer with a value ranging from 1 to (2^32-1). `optionalUid` must be unique. If `optionalUid` is not assigned (or set to `0`), the SDK assigns and returns `uid` in the [`JoinChannelSuccess`]{@link RtcEngineEvents.JoinChannelSuccess} callback. - * Your app must record and maintain the returned uid since the SDK does not do so. - * - * 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”. - */ - joinChannel(token: string | null, channelName: string, optionalInfo: string | null, optionalUid: number): Promise { - return RtcEngine._callMethod('joinChannel', {token, channelName, optionalInfo, optionalUid}) - } - - /** - * Switches to a different channel. - * - * This method allows the audience of a [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} channel to switch to a different channel. - * - * 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. - * - * **Note** - * - * This method applies to the [`Audience`]{@link ClientRole.Audience} role in a [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} channel only. - * - * @param token The token for authentication: - * - 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 channelName Unique channel name for the AgoraRTC session in the string format. The string length must be less than 64 bytes. Supported character scopes are: - * - All lowercase English letters: a to z. - * - All uppercase English letters: A to Z. - * - All numeric characters: 0 to 9. - * - The space character. - * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". - */ - switchChannel(token: string | null, channelName: string): Promise { - return RtcEngine._callMethod('switchChannel', {token, channelName}) - } - - /** - * Allows a user to leave a channel. - * - * After joining a channel, the user must call this method to end the call before joining another channel. - * This method returns `0` if the user leaves the channel and releases all resources related to the call. - * - * This method call is asynchronous, and the user has not exited the channel when the method call returns. - * Once the user leaves the channel, the SDK triggers the [`LeaveChannel`]{@link RtcEngineEvents.LeaveChannel} callback. - * A successful [`leaveChannel`]{@link leaveChannel} method call triggers the following callbacks: - * - The local client: [`LeaveChannel`]{@link RtcEngineEvents.LeaveChannel}. - * - * - The remote client: [`UserOffline`]{@link RtcEngineEvents.UserOffline}, if the user leaving the channel is in the [`Communication`]{@link ChannelProfile.Communication} channel, or is a [`Broadcaster`]{@link ClientRole.Broadcaster} - * in the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile. - * - * **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. - */ - leaveChannel(): Promise { - return RtcEngine._callMethod('leaveChannel') - } - - /** - * Renews the token when the current token expires. - * - * The token expires after a period of time once the token schema is enabled when: - * - The SDK triggers the [`TokenPrivilegeWillExpire`]{@link RtcEngineEvents.TokenPrivilegeWillExpire} callback, or - * - * - The [`ConnectionStateChanged`]{@link RtcEngineEvents.ConnectionStateChanged} callback reports the [`TokenExpired(9)`]{@link ConnectionChangedReason.TokenExpired} error. - * - * 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. - */ - renewToken(token: string): Promise { - return RtcEngine._callMethod('renewToken', {token}) - } - - /** - * Enables interoperability with the Agora Web SDK ([`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} only). - * - * @deprecated This method is deprecated. The Agora Native SDK automatically enables interoperability with the Web SDK, so you no longer need to call this method. - * - * If the channel has Web SDK users, ensure that you call this method, or the video of the Native user will be a black screen for the Web user. - * Use this method when the channel profile is [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting}. Interoperability with the Agora Web SDK is enabled by default when the channel profile is [`Communication`]{@link ChannelProfile.Communication}. - * @param enabled Sets whether to enable/disable interoperability with the Agora Web SDK: - * - `true`: Enable. - * - `false`: (Default) Disable. - */ - enableWebSdkInteroperability(enabled: boolean): Promise { - return RtcEngine._callMethod('enableWebSdkInteroperability', {enabled}) - } - - /** - * Gets the connection state of the SDK. - */ - getConnectionState(): Promise { - return RtcEngine._callMethod('getConnectionState') - } - - /** - * Gets the current call ID. - * - * When a user joins a channel on a client, a call ID is generated to identify the call from the client. - * Feedback methods, such as [`rate`]{@link rate} and [`complain`]{@link complain}, must be called after the call ends to submit feedback to the SDK. - * - * The [`rate`]{@link rate} and [`complain`]{@link complain} methods require the `callId` parameter retrieved from the [`getCallId`]{@link getCallId} method during a call. - * `callId` is passed as an argument into the [`rate`]{@link rate} and [`complain`]{@link complain} methods after the call ends. - * - * @returns - * Current call ID. - */ - getCallId(): Promise { - return RtcEngine._callMethod('getCallId') - } - - /** - * Allows the user to rate a call after the call ends. - * - * @param callId ID of the call retrieved from the [`getCallId`]{@link getCallId} method. - * @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. - */ - rate(callId: string, rating: Rate, description?: string): Promise { - return RtcEngine._callMethod('rate', {callId, rating, description}) - } - - /** - * Allows a user to complain about the call quality after a call ends. - * - * @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. - */ - complain(callId: string, description: string): Promise { - return RtcEngine._callMethod('complain', {callId, description}) - } - - /** - * Sets the log files that the SDK outputs. - * - * By default, the SDK outputs five log files, `agorasdk.log`, `agorasdk_1.log`, `agorasdk_2.log`, `agorasdk_3.log`, `agorasdk_4.log`, each with a default size of 1024 KB. - * These log files are encoded in UTF-8. The SDK writes the latest logs in `agorasdk.log`. When `agorasdk.log` is full, the SDK deletes the log file with the - * earliest modification time among the other four, renames `agorasdk.log` to the name of the deleted log file, and creates a new `agorasdk.log` to record latest logs. - * The log file records all log data for the SDK’s operation. Ensure that the directory for the log file exists and is writable. - * - * **Note** - * - * Ensure that you call this method immediately after calling the `create` method, otherwise the output log may not be complete. - * - * @param filePath File path of the log file. The string of the log file is in UTF-8. The default file path is `/storage/emulated/0/Android/data/="">/files/agorasdk.log`. - */ - setLogFile(filePath: string): Promise { - return RtcEngine._callMethod('setLogFile', {filePath}) - } - - /** - * Sets the output log level of the SDK. - * - * You can use one or a combination of the filters. The log level follows the sequence of `Off`, `Critical`, `Error`, `Warning`, `Info`, and `Debug`. - * Choose a level to see the logs preceding that level. For example, if you set the log level to `Warning`, you see the logs within levels `Critical`, `Error`, and `Warning`. - * - * @param filter Sets the log filter level. - */ - setLogFilter(filter: LogFilter): Promise { - return RtcEngine._callMethod('setLogFilter', {filter}) - } - - /** - * Sets the size (KB) of a log file that the SDK outputs. - * - * By default, the SDK outputs five log files, `agorasdk.log`, `agorasdk_1.log`, `agorasdk_2.log`, `agorasdk_3.log`, `agorasdk_4.log`, each with a default size of 1024 KB. These log files are encoded in UTF-8. The SDK writes the latest logs in `agorasdk.log`. - * When `agorasdk.log` is full, the SDK deletes the log file with the earliest modification time among the other four, renames `agorasdk.log` to the name of the deleted log file, and create a new `agorasdk.log` to record latest logs. - * @param fileSizeInKBytes The size (KB) of a log file. The default value is 1024 KB. If you set `fileSizeInKByte` to 1024 KB, the SDK outputs - * at most 5 MB log files; if you set it to less than 1024 KB, the maximum size of a log file is still 1024 KB. - */ - setLogFileSize(fileSizeInKBytes: number): Promise { - return RtcEngine._callMethod('setLogFileSize', {fileSizeInKBytes}) - } - - /** - * @ignore - * Provides technical preview functionalities or special customizations by configuring the SDK with JSON options. - * - * The JSON options are not public by default. Agora is working on making commonly used JSON options public in a standard way. - * @param parameters Sets the parameter as a JSON string in the specified format. - */ - setParameters(parameters: string): Promise { - return RtcEngine._callMethod('setParameters', {parameters}) - } - - /** - * Gets the user information by passing in the user ID. - * - * After a remote user joins the channel, the SDK gets the user ID and user account of the remote user, caches them in a mapping table object ([`UserInfo`]{@link UserInfo}), and triggers the [`UserInfoUpdated`]{@link RtcEngineEvents.UserInfoUpdated} callback on the local client. - * - * After receiving the [`UserInfoUpdated`]{@link RtcEngineEvents.UserInfoUpdated} callback, you can call this method to get the user ID of the remote user from the [`UserInfo`]{@link UserInfo} object by passing in the user account. - * @param uid The user ID of the user. Ensure that you set this parameter. - */ - getUserInfoByUid(uid: number): Promise { - return RtcEngine._callMethod('getUserInfoByUid', {uid}) - } - - /** - * Gets the user information by passing in the user account. - * - * After a remote user joins the channel, the SDK gets the user ID and user account of the remote user, caches them in a mapping table object ([`UserInfo`]{@link UserInfo}), and triggers the [`UserInfoUpdated`]{@link RtcEngineEvents.UserInfoUpdated} callback on the local client. - * - * After receiving the [`UserInfoUpdated`]{@link RtcEngineEvents.UserInfoUpdated} callback, you can call this method to get the user ID of the remote user from the [`UserInfo`]{@link UserInfo} object by passing in the user account. - * @param userAccount The user account of the user. Ensure that you set this parameter. - */ - getUserInfoByUserAccount(userAccount: string): Promise { - return RtcEngine._callMethod('getUserInfoByUserAccount', {userAccount}) - } - - /** - * Joins the channel with a user account. - * - * After the user successfully joins the channel, the SDK triggers the following callbacks: - * - The local client: [`LocalUserRegistered`]{@link RtcEngineEvents.LocalUserRegistered} and [`JoinChannelSuccess`]{@link RtcEngineEvents.JoinChannelSuccess}. - * - * - 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. - * - * **Note** - * - * To ensure smooth communication, use the same parameter type to identify the user. - * For example, if a user joins the channel with a user ID, then ensure all the other users use the user ID too. The same applies to the user account. - * If a user joins the channel with the Agora Web SDK, ensure that the uid of the user is set to the same parameter type. - * @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 channelName The channel name. The maximum length of this parameter is 64 bytes. Supported character scopes are: - * - All lowercase English letters: a to z. - * - All uppercase English letters: A to Z. - * - All numeric characters: 0 to 9. - * - The space character. - * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". - * @param userAccount The user account. The maximum length of this parameter is 255 bytes. - * Ensure that you set this parameter and do not set it as null. - * - All lowercase English letters: a to z. - * - All uppercase English letters: A to Z. - * - All numeric characters: 0 to 9. - * - The space character. - * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". - */ - joinChannelWithUserAccount(token: string | null, channelName: string, userAccount: string): Promise { - return RtcEngine._callMethod('joinChannelWithUserAccount', {token, channelName, userAccount}) - } - - /** - * Registers a user account. - * - * Once registered, the user account can be used to identify the local user when the user joins the channel. - * After the user successfully registers a user account, the SDK triggers the [`LocalUserRegistered`]{@link RtcEngineEvents.LocalUserRegistered} callback on the local client, reporting the user ID and user account of the local user. - * - * To join a channel with a user account, you can choose either of the following: - * - Call this method to create a user account, and then [`joinChannelWithUserAccount`]{@link joinChannelWithUserAccount} to join the channel. - * - * - Call [`joinChannelWithUserAccount`]{@link joinChannelWithUserAccount} to join the channel. - * - * The difference between the two is that for the former, the time elapsed between calling the [`joinChannelWithUserAccount`]{@link joinChannelWithUserAccount} method and joining the channel is shorter than the latter. - * - * **Note** - * - * - Ensure that you set the `userAccount` parameter. Otherwise, this method does not take effect. - * - Ensure that the value of the `userAccount` parameter is unique in the channel. - * - To ensure smooth communication, use the same parameter type to identify the user. - * For example, if a user joins the channel with a user ID, then ensure all the other users use the user ID too. - * The same applies to the user account. If a user joins the channel with the Agora Web SDK, ensure that the uid of the user is set to the same parameter type. - * @param appId The App ID of your project. - * @param userAccount The user account. The maximum length of this parameter is 255 bytes. - * Ensure that you set this parameter and do not set it as null. Supported character scopes are: - * - All lowercase English letters: a to z. - * - All uppercase English letters: A to Z. - * - All numeric characters: 0 to 9. - * - The space character. - * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". - */ - registerLocalUserAccount(appId: string, userAccount: string): Promise { - return RtcEngine._callMethod('registerLocalUserAccount', {appId, userAccount}) - } - - /** - * Adjusts the playback volume of all remote users. - * - * **Note** - * - * - This method adjusts the playback volume which is mixed volume of all remote users. - * - To mute the local audio playback, call both this method and [`adjustAudioMixingVolume`]{@link adjustAudioMixingVolume}, and set `volume` as `0`. - * - * @param volume The playback volume of all remote users. The value ranges from 0 to 400: - * - 0: Mute. - * - 100: The original volume. - * - 400: (Maximum) Four times the original volume with signal clipping protection. To avoid echoes and improve call quality, - * Agora recommends setting the value of volume between 0 and 100. If you need to set the value higher than 100, contact support@agora.io first. - */ - adjustPlaybackSignalVolume(volume: number): Promise { - return RtcEngine._callMethod('adjustPlaybackSignalVolume', {volume}) - } - - /** - * Adjusts the recording volume. - * - * @param volume Recording volume. The value ranges between 0 and 400: - * - 0: Mute. - * - 100: Original volume. - * - 400: (Maximum) Four times the original volume with signal-clipping protection. To avoid echoes and improve call quality, Agora recommends setting the value of volume between 0 and 100. - * If you need to set the value higher than 100, contact support@agora.io first. - */ - adjustRecordingSignalVolume(volume: number): Promise { - return RtcEngine._callMethod('adjustRecordingSignalVolume', {volume}) - } - - /** - * Adjusts the playback volume of a specified remote user. - * - * You can call this method as many times as necessary to adjust the playback volume of different remote users, or to repeatedly adjust the playback volume of the same remote user. - * - * **Note** - * - Call this method after joining a channel. - * - The playback volume here refers to the mixed volume of a specified remote user. - * - This method can only adjust the playback volume of one specified remote user at a time. To adjust the playback volume of different remote users, call the method as many times, once for each remote user. - * @param uid ID of the remote user. - * @param volume The playback volume of the specified remote user. The value ranges from 0 to 100: - * - 0: Mute. - * - 100: The original volume. - */ - adjustUserPlaybackSignalVolume(uid: number, volume: number): Promise { - return RtcEngine._callMethod('adjustUserPlaybackSignalVolume', {uid, volume}) - } - - /** - * Disables the audio module. - * - * **Note** - * - * - This method affects the internal engine 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: - * - * - [`enableLocalAudio`]{@link enableLocalAudio}: Whether to enable the microphone to create the local audio stream. - * - * - [`muteLocalAudioStream`]{@link muteLocalAudioStream}: Whether to publish the local audio stream. - * - * - [`muteRemoteAudioStream`]{@link muteRemoteAudioStream}: Whether to subscribe to and play the remote audio stream. - * - * - [`muteAllRemoteAudioStreams`]{@link muteAllRemoteAudioStreams}: Whether to subscribe to and play all remote audio streams. - */ - disableAudio(): Promise { - return RtcEngine._callMethod('disableAudio') - } - - /** - * Enables the audio module. - * - * The audio module is enabled by default. - * - * **Note** - * - * - This method affects the internal engine 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: - * - * - [`enableLocalAudio`]{@link enableLocalAudio}: Whether to enable the microphone to create the local audio stream. - * - * - [`muteLocalAudioStream`]{@link muteLocalAudioStream}: Whether to publish the local audio stream. - * - * - [`muteRemoteAudioStream`]{@link muteRemoteAudioStream}: Whether to subscribe to and play the remote audio stream. - * - * - [`muteAllRemoteAudioStreams`]{@link muteAllRemoteAudioStreams}: Whether to subscribe to and play all remote audio streams. - */ - enableAudio(): Promise { - return RtcEngine._callMethod('enableAudio') - } - - /** - * Enables the [`AudioVolumeIndication`]{@link RtcEngineEvents.AudioVolumeIndication} callback at a set time interval to - * report on which users are speaking and the speakers' volume. - * - * Once this method is enabled, the SDK returns the volume indication in the [`AudioVolumeIndication`]{@link RtcEngineEvents.AudioVolumeIndication} callback at the set time interval, - * regardless of whether any user is speaking in the channel. - * @param interval Sets the time interval between two consecutive volume indications: - * - ≤ 0: Disables the volume indication. - * - > 0: Time interval (ms) between two consecutive volume indications. Agora recommends setting interval ≥ 200 ms. - * @param smooth The smoothing factor sets the sensitivity of the audio volume indicator. The value ranges between 0 and 10. The greater the value, the more sensitive the indicator. - * 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, - * except for scenarios where the engine automatically detects the voice activity of the local user. - */ - enableAudioVolumeIndication(interval: number, smooth: number, report_vad: boolean): Promise { - return RtcEngine._callMethod('enableAudioVolumeIndication', {interval, smooth, report_vad}) - } - - /** - * Enables/Disables the local audio capture. - * - * The audio function is enabled by default. This method disables/re-enables the local audio function, that is, - * to stop or restart local audio capture and processing. - * - * This method does not affect receiving or playing the remote audio streams, and `enableLocalAudio(false)` is applicable to scenarios - * where the user wants to receive remote audio streams without sending any audio stream to other users in the channel. - * - * Once the local audio function is disabled or re-enabled, the SDK triggers the [`LocalAudioStateChanged`]{@link RtcEngineEvents.LocalAudioStateChanged} callback, which reports [`Stopped`]{@link AudioLocalState.Stopped} or [`Recording`]{@link AudioLocalState.Recording}. - * The SDK triggers the [`LocalAudioStateChanged`]{@link RtcEngineEvents.LocalAudioStateChanged} callback once the local audio function is disabled or re-enabled. - * - * **Note** - * - * - 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. - * - * - [`muteLocalAudioStream`]{@link muteLocalAudioStream}: Stops/Continues sending the local audio streams. - * - * @param enabled Sets whether to disable/re-enable the local audio function: - * - `true`: (Default) Re-enable the local audio function, that is, to start local audio capture and processing. - * - `false`: Disable the local audio function, that is, to stop local audio capture and processing. - */ - enableLocalAudio(enabled: boolean): Promise { - return RtcEngine._callMethod('enableLocalAudio', {enabled}) - } - - /** - * Stops/Resumes receiving all remote audio streams. - * - * @param muted Sets whether to receive/stop receiving all remote audio streams: - * - `true`: Stop receiving all remote audio streams. - * - `false`: (Default) Receive all remote audio streams. - */ - muteAllRemoteAudioStreams(muted: boolean): Promise { - return RtcEngine._callMethod('muteAllRemoteAudioStreams', {muted}) - } - - /** - * Stops/Resumes sending the local audio stream. - * A successful [`muteLocalAudioStream`]{@link muteLocalAudioStream} method call triggers the [`UserMuteAudio`]{@link RtcEngineEvents.UserMuteAudio} callback on the remote client. - * - * **Note** - * - * - When `muted` is set as ``true``, this method does not disable the microphone and thus does not affect any ongoing recording. - * - If you call [`setChannelProfile`]{@link setChannelProfile} after this method, the SDK resets whether to mute the local audio according to the channel profile and user role. - * Therefore, we recommend calling this method after the [`setChannelProfile`]{@link setChannelProfile} method. - * - * @param muted Sets whether to send/stop sending the local audio stream: - * - `true`: Stop sending the local audio stream. - * - `false`: (Default) Send the local audio stream. - */ - muteLocalAudioStream(muted: boolean): Promise { - return RtcEngine._callMethod('muteLocalAudioStream', {muted}) - } - - /** - * Stops/Resumes receiving a specified audio stream. - * - * **Note** - * - * - If you called [`muteAllRemoteAudioStreams`]{@link muteAllRemoteAudioStreams} and set `muted` as `true` to stop receiving all remote video streams, - * ensure that the [`muteAllRemoteAudioStreams`]{@link muteAllRemoteAudioStreams} method is called and set `muted` as `false` before calling this method. - * The [`muteAllRemoteAudioStreams`]{@link muteAllRemoteAudioStreams} method sets all remote audio streams, while the [`muteRemoteAudioStream`]{@link muteRemoteAudioStream} method sets a specified remote user's audio stream. - * - * @param uid ID of the specified remote user. - * @param muted Sets whether to receive/stop receiving the specified remote user's audio stream: - * - `true`: Stop receiving the specified remote user’s audio stream. - * - `false`: (Default) Receive the specified remote user’s audio stream. - */ - muteRemoteAudioStream(uid: number, muted: boolean): Promise { - return RtcEngine._callMethod('muteRemoteAudioStream', {uid, muted}) - } - - /** - * Sets the audio parameters and application scenarios. - * - * **Note** - * - * - 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. - * - * @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. - */ - setAudioProfile(profile: AudioProfile, scenario: AudioScenario): Promise { - return RtcEngine._callMethod('setAudioProfile', {profile, scenario}) - } - - /** - * Sets whether to receive all remote audio streams by default. - * - * You can call this method either before or after joining a channel. - * If you call `setDefaultMuteAllRemoteAudioStreams(true)` after joining a channel, you will not receive the audio streams of any subsequent user. - * - * **Note** - * - * If you want to resume receiving audio streams, call [`muteRemoteAudioStream(false)`]{@link muteRemoteAudioStream}, and specify the ID of the remote user that you want to subscribe to. - * To resume audio streams of multiple users, call [`muteRemoteAudioStream`]{@link muteRemoteAudioStream} as many times. - * Calling `setDefaultMuteAllRemoteAudioStreams(false)` resumes receiving audio streams of the subsequent users only. - * - * @param muted Sets whether to receive/stop receiving the remote audio streams by default: - * - `true`: Stop receiving any audio stream by default. - * - `false`: (Default) Receive all remote audio streams by default. - */ - setDefaultMuteAllRemoteAudioStreams(muted: boolean): Promise { - return RtcEngine._callMethod('setDefaultMuteAllRemoteAudioStreams', {muted}) - } - - /** - * Disables the video module. - * - * You can call this method before joining a channel or during a call: - * - * - If you call this method before joining a channel, the service starts in audio mode. - * - If you call this method during a video call, the video mode switches to the audio mode. - * - * A successful call of this method triggers the [`UserEnableVideo(false)`]{@link RtcEngineEvents.UserEnableVideo} callback on the remote client. - * - * To enable the video mode, call [`enableVideo`]{@link enableVideo}. - * - * **Note** - * - * - This method affects the internal engine 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 video engine modules separately: - * - * - [`enableLocalVideo`]{@link enableLocalVideo}: Whether to enable the camera to create the local video stream. - * - * - [`muteLocalVideoStream`]{@link muteLocalVideoStream}: Whether to publish the local video stream. - * - * - [`muteRemoteVideoStream`]{@link muteRemoteVideoStream}: Whether to subscribe to and play the remote video stream. - * - * - [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams}: Whether to subscribe to and play all remote video streams. - */ - disableVideo(): Promise { - return RtcEngine._callMethod('disableVideo') - } - - /** - * Disables/Re-enables the local video capture. - * - * This method disables or re-enables the local video capturer, and does not affect receiving the remote video stream. - * - * After you call [`enableVideo`]{@link enableVideo}, the local video capturer is enabled by default. - * You can call `enableLocalVideo(false)` to disable the local video capturer. If you want to re-enable it, - * call `enableLocalVideo(true)`. - * - * After the local video capturer is successfully disabled or re-enabled, the SDK triggers the [`UserEnableLocalVideo`]{@link RtcEngineEvents.UserEnableLocalVideo} callback on the remote client. - * - * **Note** - * - * - This method affects the internal engine and can be called after calling [`leaveChannel`]{@link leaveChannel}. - * @param enabled Sets whether to disable/re-enable the local video, including the capturer, renderer, and sender: - * - `true`: (Default) Re-enable the local video. - * - `false`: Disable the local video. Once the local video is disabled, the remote users can no longer receive the video stream of this user, while this user can still receive the video streams of other remote users. - * When you set `enabled` as `false`, this method does not require a local camera. - */ - enableLocalVideo(enabled: boolean): Promise { - return RtcEngine._callMethod('enableLocalVideo', {enabled}) - } - - /** - * Enables the video module. - * - * You can call this method either before joining a channel or during a call: - * - * - If you call this method before joining a channel, - * the service starts in the video mode. - * - If you call this method during an audio call, the audio mode switches to the video mode. - * - * A successful call of this method triggers the [`UserEnableVideo(true)`]{@link RtcEngineEvents.UserEnableVideo} callback on the remote client. - * - * To disable the video, call the [`disableVideo`]{@link disableVideo} method. - * - * **Note** - * - * - This method affects the internal engine and can be called after calling the [`leaveChannel`]{@link leaveChannel} method. 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 video engine modules separately: - * - * - [`enableLocalVideo`]{@link enableLocalVideo}: Whether to enable the camera to create the local video stream. - * - * - [`muteLocalVideoStream`]{@link muteLocalVideoStream}: Whether to publish the local video stream. - * - * - [`muteRemoteVideoStream`]{@link muteRemoteVideoStream}: Whether to subscribe to and play the remote video stream. - * - * - [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams}: Whether to subscribe to and play all remote video streams. - */ - enableVideo(): Promise { - return RtcEngine._callMethod('enableVideo') - } - - /** - * Stops/Resumes receiving all remote video streams. - * - * @param muted Sets whether to receive/stop receiving all remote video streams: - * - `true`: Stop receiving all remote video streams. - * - `false`: (Default) Receive all remote video streams. - */ - muteAllRemoteVideoStreams(muted: boolean): Promise { - return RtcEngine._callMethod('muteAllRemoteVideoStreams', {muted}) - } - - /** - * Stops/Resumes sending the local video stream. - * - * A successful [`muteLocalVideoStream`]{@link muteLocalVideoStream} method call triggers the [`UserMuteVideo`]{@link RtcEngineEvents.UserMuteVideo} callback on the remote client. - * - * **Note** - * - * - When you set `muted` as `true`, this method does not disable the camera and thus does not affect the retrieval of the local video streams. - * This method responds faster than calling [`enableLocalVideo`]{@link enableLocalVideo} and set `muted` as `false`, which controls sending the local video stream. - * - * - If you call [`setChannelProfile`]{@link setChannelProfile} after this method, the SDK resets whether to mute the local video according to the channel profile and user role. - * Therefore, we recommend calling this method after the [`setChannelProfile`]{@link setChannelProfile} method. - * - * @param muted Sets whether to send/stop sending the local video stream: - * - `true`: Stop sending the local video stream. - * - `false`: (Default) Send the local video stream. - */ - muteLocalVideoStream(muted: boolean): Promise { - return RtcEngine._callMethod('muteLocalVideoStream', {muted}) - } - - /** - * Stops/Resumes receiving a specified remote user's video stream. - * - * **Note** - * - * If you call [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams} and set `muted` as `true` to stop receiving all remote video streams, - * ensure that the [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams} method is called and set `muted` as `false` before calling this method. The [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams} method sets all remote streams, while this method sets a specified remote user's stream. - * - * @param uid User ID of the specified remote user. - * @param muted Sets whether to receive/stop receiving a specified remote user's video stream: - * - `true`: Stop receiving a specified remote user’s video stream. - * - `false`: (Default) Receive a specified remote user’s video stream. - */ - muteRemoteVideoStream(uid: number, muted: boolean): Promise { - return RtcEngine._callMethod('muteRemoteVideoStream', {uid, muted}) - } - - /** - * Enables/Disables image enhancement and sets the options. - * - * **Note** - * - * - Call this method after calling [`enableVideo`]{@link enableVideo}. - * - On Android,this method applies to Android 4.4 or later. - * - * @param enabled Sets whether to enable image enhancement: - * - `true`: Enable image enhancement. - * - `false`: Disable image enhancement. - * @param options The image enhancement options. - */ - setBeautyEffectOptions(enabled: boolean, options: BeautyOptions): Promise { - return RtcEngine._callMethod('setBeautyEffectOptions', {enabled, options}) - } - - /** - * Sets whether to receive all remote video streams by default. - * - * You can call this method either before or after joining a channel. - * If you call `setDefaultMuteAllRemoteVideoStreams(true)` after joining a channel, you will not receive the video stream of any subsequent user. - * - * **Note** - * - * If you want to resume receiving video streams, call [`muteRemoteVideoStream(false)`]{@link muteRemoteVideoStream}, and specify the ID of the remote user that you want to subscribe to. - * To resume receiving video streams of multiple users, call [`muteRemoteVideoStream`]{@link muteRemoteVideoStream} as many times. Calling `setDefaultMuteAllRemoteVideoStreams(false)` resumes receiving video streams of the subsequent users only. - * - * @param muted Sets whether to receive/stop receiving all remote video streams by default: - * - `true`: Stop receiving any remote video stream by default. - * - `false`: (Default) Receive all remote video streams by default. - */ - setDefaultMuteAllRemoteVideoStreams(muted: boolean): Promise { - return RtcEngine._callMethod('setDefaultMuteAllRemoteVideoStreams', {muted}) - } - - /** - * Sets the video encoder configuration. - * - * Each video encoder configuration corresponds to a set of video parameters, including the resolution, frame rate, bitrate, and video orientation. - * The parameters specified in this method are the maximum values under ideal network conditions. - * If the video engine cannot render the video using the specified parameters due to poor network conditions, the parameters further down the list are considered until a successful configuration is found. - * If you do not set the video encoder configuration after joining the channel, you can call this method before calling [`enableVideo`]{@link enableVideo} to reduce the render time of the first video frame. - * - * @param config The local video encoder configuration. - */ - setVideoEncoderConfiguration(config: VideoEncoderConfiguration): Promise { - return RtcEngine._callMethod('setVideoEncoderConfiguration', {config}) - } - - /** - * Starts the local video preview before joining a channel. - * - * Before calling this method, you must call the [`enableVideo`]{@link enableVideo} method to enable the video. - * - * **Note** - * - * - By default, the local preview enables the mirror mode. - * - Once you call this method to start the local video preview, if you leave the channel by calling [`leaveChannel`]{@link leaveChannel}, - * the local video preview remains until you call [`stopPreview`]{@link stopPreview} to disable it. - */ - startPreview(): Promise { - return RtcEngine._callMethod('startPreview') - } - - /** - * Stops the local video preview and the video. - */ - stopPreview(): Promise { - return RtcEngine._callMethod('stopPreview') - } - - /** - * Adjusts the volume of audio mixing for local playback. - * - * **Note** - * - * Call this method when you are in a channel. - * - * @param volume Audio mixing volume for local playback. The value ranges between 0 and 100 (default). - */ - adjustAudioMixingPlayoutVolume(volume: number): Promise { - return RtcEngine._callMethod('adjustAudioMixingPlayoutVolume', {volume}) - } - - /** - * Adjusts the volume of audio mixing for publishing (sending to other users). - * - * **Note** - * - * Call this method when you are in a channel. - * - * @param volume Audio mixing volume for publishing. The value ranges between 0 and 100 (default). - */ - adjustAudioMixingPublishVolume(volume: number): Promise { - return RtcEngine._callMethod('adjustAudioMixingPublishVolume', {volume}) - } - - /** - * Adjusts the volume of audio mixing. - * - * **Note** - * - * - Call this method when you are in a channel. - * - * - Calling this method does not affect the volume of the audio effect file playback invoked by the [`playEffect`]{@link playEffect} method. - * - * @param volume Audio mixing volume. The value ranges between 0 and 100 (default). - */ - adjustAudioMixingVolume(volume: number): Promise { - return RtcEngine._callMethod('adjustAudioMixingVolume', {volume}) - } - - /** - * Gets the playback position (ms) of the music file. - * - * **Note** - * - * Call this method when you are in a channel. - * - * @returns - * - Returns the current playback position of the audio mixing, if the method call is successful. - * - < 0: Failure. - */ - getAudioMixingCurrentPosition(): Promise { - return RtcEngine._callMethod('getAudioMixingCurrentPosition') - } - - /** - * Gets the duration (ms) of the music file. - * - * **Note** - * - * Call this method when you are in a channel. - * - * @returns - * - Returns the audio mixing duration, if the method call is successful. - * - < 0: Failure. - */ - getAudioMixingDuration(): Promise { - return RtcEngine._callMethod('getAudioMixingDuration') - } - - /** - * Gets the audio mixing volume for local playback. - * - * This method helps troubleshoot audio volume related issues. - * - * @returns - * - Returns the audio mixing volume for local playback, if the method call is successful. The value range is [0,100]. - * - < 0: Failure. - */ - getAudioMixingPlayoutVolume(): Promise { - return RtcEngine._callMethod('getAudioMixingPlayoutVolume') - } - - /** - * Gets the audio mixing volume for publishing. - * - * This method helps troubleshoot audio volume related issues. - * - * @returns - * - Returns the audio mixing volume for publishing, if the method call is successful. The value range is [0,100]. - * - < 0: Failure. - */ - getAudioMixingPublishVolume(): Promise { - return RtcEngine._callMethod('getAudioMixingPublishVolume') - } - - /** - * Pauses playing and mixing the music file. - * - * Call this method when you are in a channel. - */ - pauseAudioMixing(): Promise { - return RtcEngine._callMethod('pauseAudioMixing') - } - - /** - * Resumes playing and mixing the music file. - * - * Call this method when you are in a channel. - */ - resumeAudioMixing(): Promise { - return RtcEngine._callMethod('resumeAudioMixing') - } - - /** - * Sets the pitch of the local music file. - * - * When a local music file is mixed with a local human voice, call this method to - * set the pitch of the local music file only. - * - * **Note** - * - * Call this method after calling [`startAudioMixing`]{@link startAudioMixing}. - * - * @param pitch Sets the pitch of the local music file by chromatic scale. - * The default value is 0, which means keep the original pitch. - * The value ranges from -12 to 12, and the pitch value between consecutive values is a chromatic value. - * The greater the absolute value of this parameter, the higher or lower the pitch of the local music file. - */ - setAudioMixingPitch(pitch: number): Promise { - return RtcEngine._callMethod('setAudioMixingPitch', {pitch}) - } - - /** - * Sets the playback position (ms) of the music file to a different starting position (the default plays from the beginning). - * @param pos The playback starting position (ms) of the audio mixing file. - */ - setAudioMixingPosition(pos: number): Promise { - return RtcEngine._callMethod('setAudioMixingPosition', {pos}) - } - - /** - * Starts playing and mixing the music file. - * - * This method mixes the specified local or online audio file with the audio stream from the microphone, - * or replaces the microphone’s audio stream with the specified local or remote audio file. - * You can choose whether the other user can hear the local audio playback and specify the number of playback loops. - * When the audio mixing file playback finishes after calling this method, the SDK triggers the [`AudioMixingFinished`]{@link RtcEngineEvents.AudioMixingFinished} callback. - * - * A successful call of this method triggers the [`AudioMixingStateChanged`]{@link RtcEngineEvents.AudioMixingStateChanged} callback and reports [`Playing`]{@link AudioMixingStateCode.Playing} on the local client. - * - * When the audio mixing file playback finishes, the SDK triggers the [`AudioMixingStateChanged`]{@link RtcEngineEvents.AudioMixingStateChanged} callback and reports [`Stopped`]{@link AudioMixingStateCode.Stopped} on the local client. - * - * **Note** - * - * - To use this method on Android, ensure that the Android device is v4.2 or later, and the API version is v16 or later. - * - * - Call this method when you are in the channel, otherwise it may cause issues. - * - * - If you want to play an online music file, ensure that the time interval between calling this method is more than 100 ms, or the [`TooFrequentCall(702)`]{@link AudioMixingErrorCode.TooFrequentCall} error occurs. - * - * - If you want to play an online music file, Agora does not recommend using the redirected URL address. Some Android devices may fail to open a redirected URL address. - * - * - If the local audio mixing file does not exist, or if the SDK does not support the file format or cannot access the music file URL, the SDK returns [`CanNotOpen(701)`]{@link AudioMixingErrorCode.CanNotOpen}. - * - * - If you call this method on an emulator, only the MP3 file format is supported. - * - * @param filePath Specifies the absolute path (including the suffixes of the filename) of the local or online audio file to be mixed. For example, `/sdcard/emulated/0/audio.mp4`. - * Supported audio formats: mp3, mp4, m4a, aac, 3gp, mkv, and wav. - * - If the path begins with /assets/, the audio file is in the /assets/ directory. - * - Otherwise, the audio file is in the absolute path. - * @param loopback Sets which user can hear the audio mixing: - * - `true`: Only the local user can hear the audio mixing. - * - `false`: Both users can hear the audio mixing. - * @param replace Sets the audio mixing content: - * - `true`: Only publish the specified audio file; the audio stream from the microphone is not published. - * - `false`: The local audio file is mixed with the audio stream from the microphone. - * @param cycle Sets the number of playback loops: - * - Positive integer: Number of playback loops. - * - -1: Infinite playback loops. - */ - startAudioMixing(filePath: string, loopback: boolean, replace: boolean, cycle: number): Promise { - return RtcEngine._callMethod('startAudioMixing', {filePath, loopback, replace, cycle}) - } - - /** - * Stops playing or mixing the music file. - * - * Call this method when you are in a channel. - */ - stopAudioMixing(): Promise { - return RtcEngine._callMethod('stopAudioMixing') - } - - /** - * Gets the volume of the audio effects. - * - * The value ranges between 0.0 and 100.0. - * - * @returns - * - Returns the volume, if the method call is successful. - * - < 0: Failure. - */ - getEffectsVolume(): Promise { - return RtcEngine._callMethod('getEffectsVolume') - } - - /** - * Pauses all audio effects. - */ - pauseAllEffects(): Promise { - return RtcEngine._callMethod('pauseAllEffects') - } - - /** - * Pauses a specified audio effect. - * @param soundId ID of the audio effect. Each audio effect has a unique ID. - */ - pauseEffect(soundId: number): Promise { - return RtcEngine._callMethod('pauseEffect', {soundId}) - } - - /** - * Plays a specified local or online audio effect file. - * - * With this method, you can set the loop count, pitch, pan, and gain of the audio effect file and whether the remote user can hear the audio effect. - * To play multiple audio effect files simultaneously, call this method multiple times with different `soundId` and `filePath`. - * We recommend playing no more than three audio effect files at the same time. - * When the audio effect file playback is finished, the SDK triggers the [`AudioEffectFinished`]{@link RtcEngineEvents.AudioEffectFinished} callback. - * - * @param soundId ID of the specified audio effect. Each audio effect has a unique ID. If you preloaded the audio effect into the memory - * through the [`preloadEffect`]{@link preloadEffect} method, ensure that the `soundID` value is set to the same value as in the [`preloadEffect`]{@link preloadEffect} method. - * - * @param filePath The absolute file path (including the suffixes of the filename) of the audio effect file or - * the URL of the online audio effect file. For example, `/sdcard/emulated/0/audio.mp4`. - * - * Supported audio formats: mp3, mp4, m4a, aac. 3gp, mkv, and wav. - * @param loopCount Sets the number of times the audio effect loops: - * - 0: Plays the audio effect once. - * - 1: Plays the audio effect twice. - * - -1: Plays the audio effect in a loop indefinitely, until you call the [`stopEffect`]{@link stopEffect} or [`stopAllEffects`]{@link stopAllEffects} method. - * @param pitch Sets the pitch of the audio effect. The value ranges between 0.5 and 2. - * The default value is 1 (no change to the pitch). The lower the value, the lower the pitch. - * @param pan Sets the spatial position of the audio effect. The value ranges between -1.0 and 1.0. - * - 0.0: The audio effect shows ahead. - * - 1.0: The audio effect shows on the right. - * - -1.0: The audio effect shows on the left. - * @param gain Sets the volume of the audio effect. The value ranges between 0.0 and 100,0. - * The default value is 100.0. The lower the value, the lower the volume of the audio effect. - * @param publish Set whether to publish the specified audio effect to the remote stream: - * - `true`: The locally played audio effect is published to the Agora Cloud and the remote users can hear it. - * - `false`: The locally played audio effect is not published to the Agora Cloud and the remote users cannot hear it. - */ - playEffect(soundId: number, filePath: string, loopCount: number, pitch: number, pan: number, gain: number, publish: Boolean): Promise { - return RtcEngine._callMethod('playEffect', {soundId, filePath, loopCount, pitch, pan, gain, publish}) - } - - /** - * Preloads a specified audio effect file into the memory. - * - * Supported audio formats: mp3, aac, m4a, 3gp, wav. - * - * **Note** - * - This method does not support online audio effect files. - * - * - To ensure smooth communication, limit the size of the audio effect file. - * We recommend using this method to preload the audio effect before calling [`joinChannel`]{@link joinChannel}. - * - * @param soundId ID of the audio effect. Each audio effect has a unique ID. - * @param filePath Absolute path of the audio effect file. - */ - preloadEffect(soundId: number, filePath: string): Promise { - return RtcEngine._callMethod('preloadEffect', {soundId, filePath}) - } - - /** - * Resumes playing all audio effects. - */ - resumeAllEffects(): Promise { - return RtcEngine._callMethod('resumeAllEffects') - } - - /** - * Resumes playing a specified audio effect. - * @param soundId ID of the audio effect. Each audio effect has a unique ID. - */ - resumeEffect(soundId: number): Promise { - return RtcEngine._callMethod('resumeEffect', {soundId}) - } - - /** - * Sets the volume of the audio effects. - * @param volume Volume of the audio effects. The value ranges between 0.0 and 100.0 (default). - */ - setEffectsVolume(volume: number): Promise { - return RtcEngine._callMethod('setEffectsVolume', {volume}) - } - - /** - * Sets the volume of a specified audio effect. - * @param soundId ID of the audio effect. Each audio effect has a unique ID. - * @param volume Volume of the audio effect. The value ranges between 0.0 and 100.0 (default). - */ - setVolumeOfEffect(soundId: number, volume: number): Promise { - return RtcEngine._callMethod('setVolumeOfEffect', {soundId, volume}) - } - - /** - * Stops playing all audio effects. - */ - stopAllEffects(): Promise { - return RtcEngine._callMethod('stopAllEffects') - } - - /** - * Stops playing a specified audio effect. - * - * **Note** - * - * If you preloaded the audio effect into the memory through the [`preloadEffect`]{@link preloadEffect} method, - * ensure that the `soundID` value is set to the same value as in the [`preloadEffect`]{@link preloadEffect} method. - * - * @param soundId ID of the specified audio effect. Each audio effect has a unique ID. - */ - stopEffect(soundId: number): Promise { - return RtcEngine._callMethod('stopEffect', {soundId}) - } - - /** - * Releases a specified preloaded audio effect from the memory. - * @param soundId ID of the audio effect. Each audio effect has a unique ID. - */ - unloadEffect(soundId: number): Promise { - return RtcEngine._callMethod('unloadEffect', {soundId}) - } - - /** - * Sets the local voice changer option. - * - * **Note** - * - * Do not use this method together with [`setLocalVoiceReverbPreset`]{@link setLocalVoiceReverbPreset}, or the method called earlier does not take effect. - * - * @param voiceChanger The local voice changer option. - */ - setLocalVoiceChanger(voiceChanger: AudioVoiceChanger): Promise { - return RtcEngine._callMethod('setLocalVoiceChanger', {voiceChanger}) - } - - /** - * Sets the local voice equalization effect. - * - * @param bandFrequency Sets the band frequency. The value ranges between 0 and 9; representing the respective 10-band center frequencies of the voice effects, including 31, 62, 125, 500, 1k, 2k, 4k, 8k, and 16k Hz. - * - * @param bandGain Sets the gain of each band (dB). The value ranges between -15 and 15. The default value is 0. - */ - setLocalVoiceEqualization(bandFrequency: AudioEqualizationBandFrequency, bandGain: number): Promise { - return RtcEngine._callMethod('setLocalVoiceEqualization', {bandFrequency, bandGain}) - } - - /** - * Changes the voice pitch of the local speaker. - * @param pitch Sets the voice pitch. The value ranges between 0.5 and 2.0. - * The lower the value, the lower the voice pitch. The default value is 1.0 (no change to the local voice pitch). - */ - setLocalVoicePitch(pitch: number): Promise { - return RtcEngine._callMethod('setLocalVoicePitch', {pitch}) - } - - /** - * Sets the local voice reverberation. - * - * **Note** - * - * Adds the [`setLocalVoiceReverbPreset`]{@link setLocalVoiceReverbPreset} method, a more user-friendly method for setting the - * local voice reverberation. You can use this method to set the local reverberation effect, - * such as Popular, R&B, Rock, Hip-hop, and more. - * - * @param reverbKey The reverberation key: [`AudioReverbType`]{@link AudioReverbType} - * - * @param value The local voice reverberation value. - */ - setLocalVoiceReverb(reverbKey: AudioReverbType, value: number): Promise { - return RtcEngine._callMethod('setLocalVoiceReverb', {reverbKey, value}) - } - - /** - * Sets the preset local voice reverberation effect. - * - * **Note** - * - * - Do not use this method together with [`setLocalVoiceReverb`]{@link setLocalVoiceReverb}. - * - * - Do not use this method together with [`setLocalVoiceChanger`]{@link setLocalVoiceChanger}, or the method called earlier does not take effect. - * - * @param preset The local voice reverberation preset. - */ - setLocalVoiceReverbPreset(preset: AudioReverbPreset): Promise { - return RtcEngine._callMethod('setLocalVoiceReverbPreset', {preset}) - } - - /** - * Enables/Disables stereo panning for remote users. - * - * Ensure that you call this method before calling [`joinChannel`]{@link joinChannel} to enable stereo panning for remote users so that - * the local user can track the position of a remote user by calling [`setRemoteVoicePosition`]{@link setRemoteVoicePosition}. - * - * @param enabled Sets whether to enable stereo panning for remote users: - * - `true`: Enable stereo panning. - * - `false`: Disable stereo panning. - */ - enableSoundPositionIndication(enabled: boolean): Promise { - return RtcEngine._callMethod('enableSoundPositionIndication', {enabled}) - } - - /** - * Sets the sound position of a remote user. - * - * When the local user calls this method to set the sound position of a remote user, - * the sound difference between the left and right channels allows the local user to track the real-time - * position of the remote user, creating a real sense of space. - * This method applies to massively multiplayer online games, such as Battle Royale games. - * - * **Note** - * - * - For this method to work, enable stereo panning for remote users by calling the [`enableSoundPositionIndication`]{@link enableSoundPositionIndication} method before joining a channel. - * - * - This method requires hardware support. For the best sound positioning, we recommend using a stereo headset. - * - * @param uid The ID of the remote user. - * @param pan The sound position of the remote user. - * The value ranges from -1.0 to 1.0: - * - 0.0: The remote sound comes from the front. - * - -1.0: The remote sound comes from the left. - * - 1.0: The remote sound comes from the right. - * @param gain Gain of the remote user. The value ranges from 0.0 to 100.0. - * The default value is 100.0 (the original gain of the remote user). The smaller the value, the less the gain. - */ - setRemoteVoicePosition(uid: number, pan: number, gain: number): Promise { - return RtcEngine._callMethod('setRemoteVoicePosition', {uid, pan, gain}) - } - - /** - * Publishes the local stream to the CDN. - * - * 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. - * - * **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. - * 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`, 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. - */ - addPublishStreamUrl(url: string, transcodingEnabled: boolean): Promise { - return RtcEngine._callMethod('addPublishStreamUrl', {url, transcodingEnabled}) - } - - /** - * Removes an RTMP stream from the CDN. - * - * This method removes the RTMP URL address (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. - * The URL address must not contain special characters, such as Chinese language characters. - */ - removePublishStreamUrl(url: string): Promise { - return RtcEngine._callMethod('removePublishStreamUrl', {url}) - } - - /** - * Sets the video layout and audio settings for CDN live. - * - * The SDK triggers the [`TranscodingUpdated`]{@link RtcEngineEvents.TranscodingUpdated} callback when you call this method to update the [`LiveTranscoding`]{@link LiveTranscoding} class. - * If you call this method to set the [`LiveTranscoding`]{@link LiveTranscoding} class for the first time, - * the SDK does not trigger the [`TranscodingUpdated`]{@link RtcEngineEvents.TranscodingUpdated} callback. - * - * **Note** - * - * - This method applies to [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} only. - * - 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}. - * - * @param transcoding Sets the CDN live audio/video transcoding settings. - */ - setLiveTranscoding(transcoding: LiveTranscoding): Promise { - return RtcEngine._callMethod('setLiveTranscoding', {transcoding}) - } - - /** - * Starts to relay media streams across channels. - * - * After a successful method call, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcEngineEvents.ChannelMediaRelayStateChanged} and [`ChannelMediaRelayEvent`]{@link RtcEngineEvents.ChannelMediaRelayEvent} callbacks, and these - * callbacks return the state and events of the media stream relay. - * - * If the [`ChannelMediaRelayStateChanged`]{@link RtcEngineEvents.ChannelMediaRelayStateChanged} callback returns [`Running(2)`]{@link ChannelMediaRelayState.Running} and [`None(0)`]{@link ChannelMediaRelayError.None}, - * and the [`ChannelMediaRelayEvent`]{@link RtcEngineEvents.ChannelMediaRelayEvent} callback returns [`SentToDestinationChannel(4)`]{@link ChannelMediaRelayEvent.SentToDestinationChannel}, the SDK starts relaying media streams between the original and the destination channel. - * - * If the [`ChannelMediaRelayStateChanged`]{@link RtcEngineEvents.ChannelMediaRelayStateChanged} callback returns [`Failure(3)`]{@link ChannelMediaRelayState.Failure}, an exception occurs during the media stream relay. - * - * **Note** - * - * - Contact sales-us@agora.io before implementing this function. - * - We do not support string user accounts in this API. - * - Call this method after the [`joinChannel`]{@link joinChannel} method. - * - This method takes effect only when you are a [`Broadcaster`]{@link ClientRole.Broadcaster} - * in a [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} channel. - * - After a successful method call, if you want to call this method again, ensure that you call [`stopChannelMediaRelay`]{@link stopChannelMediaRelay} to quit the current relay. - * - * @param channelMediaRelayConfiguration The configuration of the media stream relay. - */ - startChannelMediaRelay(channelMediaRelayConfiguration: ChannelMediaRelayConfiguration): Promise { - return RtcEngine._callMethod('startChannelMediaRelay', {channelMediaRelayConfiguration}) - } - - /** - * Stops the media stream relay. - * - * Once the relay stops, the host quits all the destination channels. - * After a successful method call, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcEngineEvents.ChannelMediaRelayStateChanged} callback. - * If the callback returns [`Idle(0)`]{@link ChannelMediaRelayState.Idle} and [`None(0)`]{@link ChannelMediaRelayError.None}, the host successfully stops the relay. - * - * **Note** - * - * If the method call fails, the SDK triggers the [`ChannelMediaRelayStateChanged`]{@link RtcEngineEvents.ChannelMediaRelayStateChanged} callback with the [`ServerNoResponse(2)`]{@link ChannelMediaRelayError.ServerNoResponse} - * or [`ServerConnectionLost(8)`]{@link ChannelMediaRelayError.ServerConnectionLost} state code. - * You can leave the channel by calling [`leaveChannel`]{@link leaveChannel}, and the media stream relay automatically stops. - */ - stopChannelMediaRelay(): Promise { - return RtcEngine._callMethod('stopChannelMediaRelay') - } - - /** - * Updates the channels for media relay. - * - * After the channel media relay starts, if you want to relay the media stream to more channels, - * or leave the current relay channel, you can call [`updateChannelMediaRelay`]{@link updateChannelMediaRelay}. - * - * After a successful method call, the SDK triggers the [`ChannelMediaRelayEvent`]{@link RtcEngineEvents.ChannelMediaRelayEvent} callback with the [`UpdateDestinationChannel(7)`]{@link ChannelMediaRelayEvent.UpdateDestinationChannel} state code. - * - * **Note** - * - * - Call this method after the [`startChannelMediaRelay`]{@link startChannelMediaRelay} method to update the destination channel. - * - * - This method supports adding at most four destination channels in the relay. If there are already four destination channels in the relay. - * @param channelMediaRelayConfiguration The media stream relay configuration - */ - updateChannelMediaRelay(channelMediaRelayConfiguration: ChannelMediaRelayConfiguration): Promise { - return RtcEngine._callMethod('updateChannelMediaRelay', {channelMediaRelayConfiguration}) - } - - /** - * Checks whether the speakerphone is enabled. - * - * @returns - * - `true`: The speakerphone is enabled, and the audio plays from the speakerphone. - * - `false`: The speakerphone is not enabled, and the audio plays from devices other than the speakerphone. For example, the headset or earpiece. - */ - isSpeakerphoneEnabled(): Promise { - return RtcEngine._callMethod('isSpeakerphoneEnabled') - } - - /** - * Sets the default audio playback route. - * - * This method sets whether the received audio is routed to the earpiece or speakerphone - * by default before joining a channel. If a user does not call this method, - * the audio is routed to the earpiece by default. If you need to change the default audio route after - * joining a channel, call [`setEnableSpeakerphone`]{@link setEnableSpeakerphone}. - * - * The default audio route for each scenario: - * - In the [`Communication`]{@link ChannelProfile.Communication} profile: - * - * - For a voice call, the default audio route is the earpiece. - * - For a video call, the default audio route is the speaker. If the user disables the video - * using [`disableVideo`]{@link disableVideo}, or [`muteLocalVideoStream`]{@link muteLocalVideoStream} and [`muteAllRemoteVideoStreams`]{@link muteAllRemoteVideoStreams}, the default audio route automatically switches back to the earpiece. - * - * - In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile: The default audio route is the speaker. - * - * **Note** - * - * - This method applies to the [`Communication`]{@link ChannelProfile.Communication} profile only. - * - Call this method before the user joins a channel. - * @param defaultToSpeaker Sets the default audio route: - * - `true`: Route the audio to the speaker. If the playback device connects to the earpiece or Bluetooth, the audio cannot be routed to the earpiece. - * - `false`: (Default) Route the audio to the earpiece. If a headset is plugged in, the audio is routed to the headset. - */ - setDefaultAudioRoutetoSpeakerphone(defaultToSpeaker: boolean): Promise { - return RtcEngine._callMethod('setDefaultAudioRoutetoSpeakerphone', {defaultToSpeaker}) - } - - /** - * Enables/Disables the audio playback route to the speakerphone. - * - * This method sets whether the audio is routed to the speakerphone or earpiece. - * After calling this method, the SDK returns the [`AudioRouteChanged`]{@link RtcEngineEvents.AudioRouteChanged} callback to indicate the changes. - * - * **Note** - * - * - Ensure that you have successfully called [`joinChannel`]{@link joinChannel} before calling this method. - * - * - This method is invalid for audience users in the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile. - * - * @param enabled Sets whether to route the audio to the speakerphone or earpiece: - * - `true`: Route the audio 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 { - return RtcEngine._callMethod('setEnableSpeakerphone', {enabled}) - } - - /** - * Enables in-ear monitoring. - * @param enabled Sets whether to enable/disable in-ear monitoring: - * - `true`: Enable. - * - `false`: (Default) Disable. - */ - enableInEarMonitoring(enabled: boolean): Promise { - return RtcEngine._callMethod('enableInEarMonitoring', {enabled}) - } - - /** - * Sets the volume of the in-ear monitor. - * @param volume Sets the volume of the in-ear monitor. The value ranges between 0 and 100 (default). - */ - setInEarMonitoringVolume(volume: number): Promise { - return RtcEngine._callMethod('setInEarMonitoringVolume', {volume}) - } - - /** - * Enables/Disables the dual video stream mode. - * - * If dual-stream mode is enabled, the receiver can choose to receive the high stream (high-resolution high-bitrate video stream) or - * low stream (low-resolution low-bitrate video stream) video. - * - * @param enabled Sets the stream mode: - * - `true`: Dual-stream mode. - * - `false`: (Default) Single-stream mode. - */ - enableDualStreamMode(enabled: boolean): Promise { - return RtcEngine._callMethod('enableDualStreamMode', {enabled}) - } - - /** - * Sets the default video-stream type of the remotely subscribed video stream - * when the remote user sends dual streams. - * - * @param streamType Sets the default video-stream type. - */ - setRemoteDefaultVideoStreamType(streamType: VideoStreamType): Promise { - return RtcEngine._callMethod('setRemoteDefaultVideoStreamType', {streamType}) - } - - /** - * Sets the stream type of the remote video. - * - * Under limited network conditions, if the publisher has not disabled the - * dual-stream mode using [`enableDualStreamMode(false)`]{@link RtcEngine.enableDualStreamMode}, the receiver can choose to receive - * either the high-video stream (the high resolution, and high bitrate video stream) or the low-video stream (the low resolution, and low bitrate video stream). - * - * By default, users receive the high-video stream. Call this method if you want to switch to the low-video stream. This method allows the app to adjust the corresponding video stream type - * based on the size of the video window to reduce the bandwidth and resources. - * - * The aspect ratio of the low-video stream is the same as the high-video stream. Once the resolution of the high-video stream is set, - * the system automatically sets the resolution, frame rate, and bitrate of the low-video stream. - * - * The SDK reports the result of calling this method in the [`ApiCallExecuted`]{@link RtcEngineEvents.ApiCallExecuted} callback. - * - * @param uid ID of the remote user sending the video stream. - * @param streamType Sets the video-stream type. - */ - setRemoteVideoStreamType(uid: number, streamType: VideoStreamType): Promise { - return RtcEngine._callMethod('setRemoteVideoStreamType', {uid, streamType}) - } - - /** - * Sets the fallback option for the locally published video stream based on the network conditions. - * - * If `option` is set as [`AudioOnly(2)`]{@link StreamFallbackOptions.AudioOnly}, the SDK will: - * - * - Disable the upstream video but enable audio only when the network conditions deteriorate and cannot support both video and audio. - * - * - Re-enable the video when the network conditions improve. - * - * When the locally published video stream falls back to audio only or when the audio-only stream - * switches back to the video, the SDK triggers the [`LocalPublishFallbackToAudioOnly`]{@link RtcEngineEvents.LocalPublishFallbackToAudioOnly}. - * - * **Note** - * - * Agora does not recommend using this method for CDN live streaming, because the remote CDN live user will have a noticeable lag when the locally published video stream falls back to audio only. - * @param option Sets the fallback option for the locally published video stream. - */ - setLocalPublishFallbackOption(option: StreamFallbackOptions): Promise { - return RtcEngine._callMethod('setLocalPublishFallbackOption', {option}) - } - - /** - * Sets the fallback option for the remotely subscribed video stream based on the network conditions. - * - * If `option` is set as [`AudioOnly(2)`]{@link StreamFallbackOptions.AudioOnly}, the SDK automatically switches - * the video from a high-stream to a low-stream, or disables the video when the downlink network condition cannot support - * both audio and video to guarantee the quality of the audio. - * The SDK monitors the network quality and restores the video stream when the network conditions improve. - * When the remotely subscribed video stream falls back to audio only, or the audio-only stream switches back to the video, - * the SDK triggers the [`RemoteSubscribeFallbackToAudioOnly`]{@link RtcEngineEvents.RemoteSubscribeFallbackToAudioOnly} callback. - * - * @param option Sets the fallback option for the remotely subscribed video stream. - */ - setRemoteSubscribeFallbackOption(option: StreamFallbackOptions): Promise { - return RtcEngine._callMethod('setRemoteSubscribeFallbackOption', {option}) - } - - /** - * Sets the priority of a remote user's media stream. - * - * Use this method with the [`setRemoteSubscribeFallbackOption`]{@link setRemoteSubscribeFallbackOption} method. - * If the fallback function is enabled for a subscribed stream, the SDK ensures the high-priority user gets the best possible stream quality. - * - * **Note** - * - * The Agora SDK supports setting `userPriority` as high for one user only. - * - * @param uid The ID of the remote user. - * @param userPriority The priority of the remote user. - */ - setRemoteUserPriority(uid: number, userPriority: UserPriority): Promise { - return RtcEngine._callMethod('setRemoteUserPriority', {uid, userPriority}) - } - - /** - * Disables the network connection quality test. - */ - disableLastmileTest(): Promise { - return RtcEngine._callMethod('disableLastmileTest') - } - - /** - * Enables the network connection quality test. - * - * This method tests the quality of the users' network connections and is disabled by default. - * - * Before users join a channel or before an audience switches to a host, call this method to check the - * uplink network quality. This method consumes additional network traffic, which may affect the communication quality. - * Call [`disableLastmileTest`]{@link disableLastmileTest} to disable this test after receiving the [`LastmileQuality`]{@link RtcEngineEvents.LastmileQuality} callback, - * and before the user joins a channel or switches the user role. - * - * **Note** - * - * - Do not use this method with the [`startLastmileProbeTest`]{@link startLastmileProbeTest} method. - * - * - Do not call any other methods before receiving the [`LastmileQuality`]{@link RtcEngineEvents.LastmileQuality} callback. Otherwise, the callback may be interrupted by other methods and may not execute. - * - * - In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile, a host should not call this method after joining a channel. - * - If you call this method to test the last-mile quality, the SDK consumes the bandwidth of a video stream, whose bitrate corresponds to the bitrate you set in the [`setVideoEncoderConfiguration`]{@link setVideoEncoderConfiguration} method. - * After you join the channel, whether you have called [`disableLastmileTest`]{@link disableLastmileTest} or not, the SDK automatically stops consuming the bandwidth. - */ - enableLastmileTest(): Promise { - return RtcEngine._callMethod('enableLastmileTest') - } - - /** - * Starts an audio call test. - * - * In the audio call test, you record your voice. If the recording plays back within the set time interval, the audio devices and the network connection are working properly. - * - * **Note** - * - * - Call this method before joining a channel. - * - * - After calling this method, call [`stopEchoTest`]{@link stopEchoTest} to end the test. - * Otherwise, the app cannot run the next echo test, or call [`joinChannel`]{@link joinChannel}. - * - * - In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile, only a host can call this method. - * @param intervalInSeconds The time interval (s) between when you speak and when the recording plays back. - */ - startEchoTest(intervalInSeconds: number): Promise { - return RtcEngine._callMethod('startEchoTest', {intervalInSeconds}) - } - - /** - * Starts the last-mile network probe test before joining a channel to get the uplink and downlink last-mile network statistics, - * including the bandwidth, packet loss, jitter, and round-trip time (RTT). - * - * Once this method is enabled, the SDK returns the following callbacks: - * - [`LastmileQuality`]{@link RtcEngineEvents.LastmileQuality}: the SDK triggers this callback within two seconds depending on the network conditions. - * This callback rates the network conditions with a score and is more closely linked to the user experience. - * - * - [`LastmileProbeResult`]{@link RtcEngineEvents.LastmileProbeResult}: the SDK triggers this callback within 30 seconds depending on the network conditions. - * This callback returns the real-time statistics of the network conditions and is more objective. - * - * Call this method to check the uplink network quality before users join a channel or before an audience switches to a host. - * - * **Note** - * - * - This method consumes extra network traffic and may affect communication quality. We do not recommend calling this method together with [`enableLastmileTest`]{@link enableLastmileTest}. - * - Do not call other methods before receiving the [`LastmileQuality`]{@link RtcEngineEvents.LastmileQuality} and [`LastmileProbeResult`]{@link RtcEngineEvents.LastmileProbeResult} callbacks. Otherwise, the callbacks may be interrupted by other methods. - * - In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile, a host should not call this method after joining a channel. - * - * @param config The configurations of the last-mile network probe test. - */ - startLastmileProbeTest(config: LastmileProbeConfig): Promise { - return RtcEngine._callMethod('startLastmileProbeTest', {config}) - } - - /** - * Stops the audio call test. - */ - stopEchoTest(): Promise { - return RtcEngine._callMethod('stopEchoTest') - } - - /** - * Stops the last-mile network probe test. - */ - stopLastmileProbeTest(): Promise { - return RtcEngine._callMethod('stopLastmileProbeTest') - } - - /** - * Registers the metadata observer. - * - * This method enables you to add synchronized metadata in the video stream for more diversified live streaming interactions, - * such as sending shopping links, digital coupons, and online quizzes. - * - * **Note** - * - * Call this method before the [`joinChannel`]{@link joinChannel} method. - */ - registerMediaMetadataObserver(): Promise { - return RtcEngine._callMethod('registerMediaMetadataObserver') - } - - /** - * Sends the metadata. - * - * @param metadata The metadata to be sent. - */ - sendMetadata(metadata: string): Promise { - return RtcEngine._callMethod('sendMetadata', {metadata}) - } - - /** - * Sets the maximum size of the metadata. - * - * @param size Buffer size of the sent or received metadata. - */ - setMaxMetadataSize(size: number): Promise { - return RtcEngine._callMethod('setMaxMetadataSize', {size}) - } - - /** - * Unregisters the metadata observer. - */ - unregisterMediaMetadataObserver(): Promise { - return RtcEngine._callMethod('unregisterMediaMetadataObserver') - } - - /** - * Adds a watermark image to the local video. - * - * This method adds a PNG watermark image to the local video stream in a live interactive streaming. - * Once the watermark image is added, all the audience in the channel (CDN audience included), and the recording device can see and capture it. - * - * Agora supports adding only one watermark image onto the local video, and the newly-added watermark image replaces the previous one. - * The watermark position depends on the settings in the [`setVideoEncoderConfiguration`]{@link setVideoEncoderConfiguration} method: - * - * - If the orientation mode of the encoding video is [`FixedLandscape`]{@link VideoOutputOrientationMode.FixedLandscape}, or the landscape mode in [`Adaptative`]{@link VideoOutputOrientationMode.Adaptative}, the watermark uses the landscape orientation. - * - * - If the orientation mode of the encoding video is [`FixedPortrait`]{@link VideoOutputOrientationMode.FixedPortrait}, or the portrait mode in [`Adaptative`]{@link VideoOutputOrientationMode.Adaptative}, the watermark uses the portrait orientation. - * - * - When setting the watermark position, the region must be less than the dimensions set in the [`setVideoEncoderConfiguration`]{@link setVideoEncoderConfiguration} method. - * Otherwise, the watermark image will be cropped. - * - * **Note** - * - * - Ensure that you have called [`enableVideo`]{@link enableVideo} to enable the video module before calling this method. - * - * - If you only want to add a watermark image to the local video for the audience in the CDN live interactive streaming channel to see and capture, you can call this method or the [`setLiveTranscoding`]{@link setLiveTranscoding} method. - * - * - This method supports adding a watermark image in the PNG file format only. Supported pixel formats of the PNG image are RGBA, RGB, Palette, Gray, and Alpha_gray. - * - * - If the dimensions of the PNG image differ from your settings in this method, the image will be cropped or zoomed to conform to your settings. - * - * - If you have enabled the local video preview by calling [`startPreview`]{@link startPreview}, you can use the `visibleInPreview` member in the [`WatermarkOptions`]{@link WatermarkOptions} class to set whether the watermark is visible in preview. - * - * - If you have enabled the mirror mode for the local video, the watermark on the local video is also mirrored. To avoid mirroring the watermark, Agora recommends that you do not use the mirror and watermark functions for the local video at the same time. - * You can implement the watermark function in your application layer. - * @param watermarkUrl The local file path of the watermark image to be added. This method supports adding a watermark image from either the local file path or the assets file path. If you use the assets file path, you need to start with `/assets/` when filling in this parameter. - * @param options The options of the watermark image to be added. - */ - addVideoWatermark(watermarkUrl: string, options: WatermarkOptions): Promise { - return RtcEngine._callMethod('addVideoWatermark', {watermarkUrl, options}) - } - - /** - * Removes the watermark image from the video stream added by [`addVideoWatermark`]{@link addVideoWatermark}. - */ - clearVideoWatermarks(): Promise { - return RtcEngine._callMethod('clearVideoWatermarks') - } - - /** - * Enables/Disables the built-in encryption. - * - * @since v3.1.2. - * - * In scenarios requiring high security, Agora recommends calling `enableEncryption` to enable the built-in encryption before joining a channel. - * - * 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. - * - 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*. - * - * - * @param enabled Whether to enable the built-in encryption. - * - `true`: Enable the built-in encryption. - * - `false`: Disable the built-in encryption. - * @param config Configurations of built-in encryption schemas. See [`EncryptionConfig`]{@link EncryptionConfig}. - */ - enableEncryption(enabled: boolean, config: EncryptionConfig): Promise { - return RtcEngine._callMethod('enableEncryption', {enabled, config}); - } - - /** - * Sets the built-in encryption mode. - * - * @deprecated - * Deprecated as of v3.1.2. Use [`enableEncryption`]{@link enableEncryption} instead. - * - * The Agora SDK supports built-in encryption, which is set to `AES128XTS` mode by default. - * Call this method to set the encryption mode to use other encryption modes. - * All users in the same channel must use the same encryption mode and password. - * - * Refer to the information related to the AES encryption algorithm on the differences between the encryption modes. - * - * **Note** - * - * Call [`setEncryptionSecret`]{@link setEncryptionSecret} before calling this method. - * - * @param encryptionMode Sets the encryption mode. - */ - setEncryptionMode(encryptionMode: EncryptionMode): Promise { - return RtcEngine._callMethod('setEncryptionMode', {encryptionMode}) - } - - /** - * Enables built-in encryption with an encryption password before joining a channel. - * - * @deprecated - * Deprecated as of v3.1.2. Use [`enableEncryption`]{@link enableEncryption} instead. - * - * All users in a channel must set the same encryption password. - * The encryption password is automatically cleared once a user leaves the channel. - * If the encryption password is not specified or set to empty, the encryption functionality is disabled. - * - * **Note** - * - * - For optimal transmission, ensure that the encrypted data size does not exceed the original data size + 16 bytes. 16 bytes is the maximum padding size for AES encryption. - * - Do not use this method for CDN live streaming. - * @param secret The encryption password. - */ - setEncryptionSecret(secret: string): Promise { - return RtcEngine._callMethod('setEncryptionSecret', {secret}) - } - - /** - * Starts an audio recording on the client. - * - * The SDK allows recording during a call. After successfully calling this method, - * you can record the audio of all the users in the channel and get an audio recording file. - * - * Supported formats of the recording file are as follows: - * - .wav: Large file size with high fidelity. - * - .aac: Small file size with low fidelity. - * - * **Note** - * - * - Ensure that the directory to save the recording file exists and is writable. - * - This method is usually called after calling [`joinChannel`]{@link joinChannel}. The recording automatically stops when you call [`leaveChannel`]{@link leaveChannel}. - * - For better recording effects, set quality as [`Medium`]{@link AudioRecordingQuality.Medium} or [`High`]{@link AudioRecordingQuality.High} when sampleRate is 44.1 kHz or 48 kHz. - * - * @param filePath Absolute file path (including the suffixes of the filename) of the recording file. The string of the file name is in UTF-8. For example, `/sdcard/emulated/0/audio/aac`. - * @param sampleRate Sample rate (Hz) of the recording file. - * @param quality The audio recording quality. - */ - startAudioRecording(filePath: string, sampleRate: AudioSampleRateType, quality: AudioRecordingQuality): Promise { - return RtcEngine._callMethod('startAudioRecording', {filePath, sampleRate, quality}) - } - - /** - * Stops the audio recording on the client. - * - * **Note** - * - * You can call this method before calling [`leaveChannel`]{@link leaveChannel}; - * else, the recording automatically stops when you call [`leaveChannel`]{@link leaveChannel}. - */ - stopAudioRecording(): Promise { - return RtcEngine._callMethod('stopAudioRecording') - } - - /** - * Injects an online media stream to live interactive streaming. - * - * If this method call is successful, the server pulls the voice or video stream and injects it into - * a live channel. This is applicable to scenarios where all audience members in the channel can watch a live show and interact with each other. - * - * This method call triggers the following callbacks: - * - The local client: - * - [`StreamInjectedStatus`]{@link RtcEngineEvents.StreamInjectedStatus}, with the state of the injecting the online stream. - * - * - [`UserJoined`]{@link RtcEngineEvents.UserJoined}(uid: 666), if the method call is successful and the online media stream is injected into the channel. - * - * - The remote client: - * - [`UserJoined`]{@link RtcEngineEvents.UserJoined}(uid: 666), if the method call is successful and the online media stream is injected into the channel. - * - * **Note** - * - * - This method applies to the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile only. - * - Ensure that you enable the RTMP Converter service before using this function. See Prerequisites in *Push Streams to CDN*. - * - You can inject only one media stream into the channel at the same time. - * - * @param url The URL address to be added to the ongoing live interactive streaming. Valid protocols are RTMP, HLS, and HTTP-FLV. - * - 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. - */ - addInjectStreamUrl(url: string, config: LiveInjectStreamConfig): Promise { - return RtcEngine._callMethod('addInjectStreamUrl', {url, config}) - } - - /** - * Removes the injected online media stream from live interactive streaming. - * - * This method removes the URL address (added by [`addInjectStreamUrl`]{@link addInjectStreamUrl}) from interactive streaming. - * - * If this method call is successful, the SDK triggers the [`UserOffline`]{@link RtcEngineEvents.UserOffline} callback and returns a stream uid of 666. - * - * @param url HTTP/HTTPS URL address of the added stream to be removed. - */ - removeInjectStreamUrl(url: string): Promise { - return RtcEngine._callMethod('removeInjectStreamUrl', {url}) - } - - /** - * Enables/Disables face detection for the local user. - * - * Once face detection is enabled, the SDK triggers the [`FacePositionChanged`]{@link RtcEngineEvents.FacePositionChanged} callback to report the face information of the local user, which includes the following aspects: - * - * - The width and height of the local video. - * - The position of the human face in the local video. - * - The distance between the human face and the device screen. - * - * @param enable Determines whether to enable the face detection function for the local user: - * - `true`: Enable face detection. - * - `false`: (Default) Disable face detection. - */ - enableFaceDetection(enable: boolean): Promise { - return RtcEngine._callMethod('enableFaceDetection', {enable}) - } - - /** - * Gets the maximum zoom ratio supported by the camera. - * - * @returns The maximum camera zoom factor. - */ - getCameraMaxZoomFactor(): Promise { - return RtcEngine._callMethod('getCameraMaxZoomFactor') - } - - /** - * Checks whether the camera auto-face focus function is supported. - * - * @returns - * - * - `true`: The device supports the camera auto-face focus function. - * - `false`: The device does not support the camera auto-face focus function. - */ - isCameraAutoFocusFaceModeSupported(): Promise { - return RtcEngine._callMethod('isCameraAutoFocusFaceModeSupported') - } - - /** - * Checks whether the camera exposure function is supported. - * - * @returns - * - * - `true`: The device supports the camera exposure function. - * - `false`: The device does not support the camera exposure function. - */ - isCameraExposurePositionSupported(): Promise { - return RtcEngine._callMethod('isCameraExposurePositionSupported') - } - - /** - * Checks whether the camera manual focus function is supported. - * - * @returns - * - * - `true`: The device supports the camera manual focus function. - * - `false`: The device does not support the camera manual focus function. - */ - isCameraFocusSupported(): Promise { - return RtcEngine._callMethod('isCameraFocusSupported') - } - - /** - * Checks whether the camera flash function is supported. - * - * @returns - * - * - `true`: The device supports the camera flash function. - * - `false`: The device does not the support camera flash function. - */ - isCameraTorchSupported(): Promise { - return RtcEngine._callMethod('isCameraTorchSupported') - } - - /** - * Checks whether the camera zoom function is supported. - * - * @returns - * - * - `true`: The device supports the camera zoom function. - * - `false`: The device does not support the camera zoom function. - */ - isCameraZoomSupported(): Promise { - return RtcEngine._callMethod('isCameraZoomSupported') - } - - /** - * Enables the camera auto-face focus function. - * - * @param enabled Sets whether to enable/disable the camera auto-face focus function: - * - `true`: Enable the camera auto-face focus function. - * - `false`: (Default) Disable the camera auto-face focus function. - */ - setCameraAutoFocusFaceModeEnabled(enabled: boolean): Promise { - return RtcEngine._callMethod('setCameraAutoFocusFaceModeEnabled', {enabled}) - } - - /** - * Sets the camera capturer configuration. - * - * For a video call or live interactive video streaming, generally the SDK controls the camera output parameters. - * When the default camera capture settings do not meet special requirements or cause performance problems, - * we recommend using this method to set the camera capturer configuration: - * - * - If the resolution or frame rate of the captured raw video data are higher than those set by [`setVideoEncoderConfiguration`]{@link setVideoEncoderConfiguration}, processing video frames requires extra CPU and RAM usage and degrades performance. - * We recommend setting `config` as [`Performance(1)`]{@link CameraCaptureOutputPreference.Performance} to avoid such problems. - * - * - If you do not need local video preview or are willing to sacrifice preview quality, we recommend setting `config` as [`Performance(1)`]{@link CameraCaptureOutputPreference.Performance} to optimize CPU and RAM usage. - * - * - If you want better quality for the local video preview, we recommend setting `config` as [`Preview(2)`]{@link CameraCaptureOutputPreference.Preview}. - * - * **Note** - * - * Call this method before enabling the local camera. That said, you can call this method before calling [`joinChannel`]{@link joinChannel}, [`enableVideo`]{@link enableVideo}, or [`enableLocalVideo`]{@link enableLocalVideo}, depending on which method you use to turn on your local camera. - * - * @param config The camera capturer configuration. - */ - setCameraCapturerConfiguration(config: CameraCapturerConfiguration): Promise { - return RtcEngine._callMethod('setCameraCapturerConfiguration', {config}) - } - - /** - * Sets the camera exposure position. - * - * A successful [`setCameraExposurePosition`]{@link setCameraExposurePosition} method call triggers the [`CameraExposureAreaChanged`]{@link RtcEngineEvents.CameraExposureAreaChanged} callback on the local client. - * - * @param positionXinView The horizontal coordinate of the touch point in the view. - * @param positionYinView The vertical coordinate of the touch point in the view. - */ - setCameraExposurePosition(positionXinView: number, positionYinView: number): Promise { - return RtcEngine._callMethod('setCameraExposurePosition', {positionXinView, positionYinView}) - } - - /** - * Sets the camera manual focus position. - * - * A successful [`setCameraFocusPositionInPreview`]{@link setCameraFocusPositionInPreview} method call triggers the [`CameraFocusAreaChanged`]{@link RtcEngineEvents.CameraFocusAreaChanged} callback on the local client. - * - * @param positionX The horizontal coordinate of the touch point in the view. - * @param positionY The vertical coordinate of the touch point in the view. - */ - setCameraFocusPositionInPreview(positionX: number, positionY: number): Promise { - return RtcEngine._callMethod('setCameraFocusPositionInPreview', {positionX, positionY}) - } - - /** - * Enables the camera flash function. - * @param isOn Sets whether to enable/disable the camera flash function: - * - `true`: Enable the camera flash function. - * - `false`: Disable the camera flash function. - */ - setCameraTorchOn(isOn: boolean): Promise { - return RtcEngine._callMethod('setCameraTorchOn', {isOn}) - } - - /** - * Sets the camera zoom ratio. - * @param factor Sets the camera zoom factor. The value ranges between 1.0 and the maximum zoom supported by the device. - */ - setCameraZoomFactor(factor: number): Promise { - return RtcEngine._callMethod('setCameraZoomFactor', {factor}) - } - - /** - * Switches between front and rear cameras. - */ - switchCamera(): Promise { - return RtcEngine._callMethod('switchCamera') - } - - /** - * Creates a data stream. - * - * Each user can create up to five data streams during the lifecycle of the [`RtcEngine`]{@link RtcEngine}. - * - * **Note** - * - * Set both the `reliable` and `ordered` parameters to `true` or `false`. Do not set one as `true` and the other as `false`. - * @param reliable Sets whether the recipients are guaranteed to receive the data stream from the sender within five seconds: - * - `true`: The recipients receive the data from the sender within five seconds. - * If the recipient does not receive the data within five seconds, the SDK triggers the [`StreamMessageError`]{@link RtcEngineEvents.StreamMessageError} callback and returns an error code. - * - * - `false`: There is no guarantee that the recipients receive the data stream within five seconds and no error message is reported for any delay or missing data stream. - * @param ordered Sets whether the recipients receive the data stream in the sent order: - * - `true`: The recipients receive the data in the sent order. - * - `false`: The recipients do not receive the data in the sent order. - * - * @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}. - */ - createDataStream(reliable: boolean, ordered: boolean): Promise { - return RtcEngine._callMethod('createDataStream', {reliable, ordered}) - } - - /** - * Sends data stream messages. - * - * The SDK has the following restrictions on this method: - * - * - Up to 30 packets can be sent per second in a channel with each packet having a maximum size of 1 kB. - * - Each client can send up to 6 kB of data per second. - * - Each user can have up to five data channels simultaneously. - * - * A successful [`sendStreamMessage`]{@link sendStreamMessage} method call triggers the [`StreamMessage`]{@link RtcEngineEvents.StreamMessage} callback on the remote client, from which the remote user gets the stream message. - * - * A failed [`sendStreamMessage`]{@link sendStreamMessage} method call triggers the [`StreamMessageError`]{@link RtcEngineEvents.StreamMessageError} callback on the remote client. - * - * **Note** - * - * - Ensure that you have created the data stream using [`createDataStream`]{@link createDataStream} before calling this method. - * - * - This method applies only to the [`Communication`]{@link ChannelProfile.Communication} profile or to hosts in the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile. - * @param streamId ID of the sent data stream returned by the [`createDataStream`]{@link createDataStream} method. - * @param message Sent data. - */ - sendStreamMessage(streamId: number, message: string): Promise { - return RtcEngine._callMethod('sendStreamMessage', {streamId, message}) - } - - /** - * This function is in the beta stage with a free trial. The ability provided in its beta test version is reporting a maximum of 10 message pieces within 6 seconds, with each message piece not exceeding 256 bytes and each string not exceeding 100 bytes. To try out this function, contact support@agora.io and discuss the format of customized messages with us. - * @param id - * @param category - * @param event - * @param label - * @param value - */ - sendCustomReportMessage(id: string, category: string, event: string, label: string, value: number): Promise { - return RtcEngine._callMethod('sendCustomReportMessage', {id, category, event, label, value}) - } - - /** - * 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. - * - * **Note** - * - This method restricts the SDK’s manipulation of the audio session. Any operation to the audio session relies solely on the app, other apps, or third-party components. - * - * @param restriction The operational restriction (bit mask) of the SDK on the audio session. See [`AudioSessionOperationRestriction`]{@link AudioSessionOperationRestriction}. - */ - setAudioSessionOperationRestriction(restriction: AudioSessionOperationRestriction): Promise { - return RtcEngine._callMethod('setAudioSessionOperationRestriction', {restriction}) - } -} - -/** - * @ignore - */ -interface RtcEngineInterface extends RtcUserInfoInterface, RtcAudioInterface, RtcVideoInterface, RtcAudioMixingInterface, - RtcAudioEffectInterface, RtcVoiceChangerInterface, RtcVoicePositionInterface, RtcPublishStreamInterface, - RtcMediaRelayInterface, RtcAudioRouteInterface, RtcEarMonitoringInterface, RtcDualStreamInterface, - RtcFallbackInterface, RtcTestInterface, RtcMediaMetadataInterface, RtcWatermarkInterface, RtcEncryptionInterface, - RtcAudioRecorderInterface, RtcInjectStreamInterface, RtcCameraInterface, RtcStreamMessageInterface { - destroy(): Promise - - setChannelProfile(profile: ChannelProfile): Promise - - setClientRole(role: ClientRole): Promise - - joinChannel(token: string | null, channelName: string, optionalInfo: string | null, optionalUid: number): Promise - - switchChannel(token: string | null, channelName: string): Promise - - leaveChannel(): Promise - - renewToken(token: string): Promise - - enableWebSdkInteroperability(enabled: boolean): Promise - - getConnectionState(): Promise - - sendCustomReportMessage(id: string, category: string, event: string, label: string, value: number): Promise - - getCallId(): Promise - - rate(callId: string, rating: Rate, description?: string): Promise - - complain(callId: string, description: string): Promise - - setLogFile(filePath: string): Promise - - setLogFilter(filter: LogFilter): Promise - - setLogFileSize(fileSizeInKBytes: number): Promise - - setParameters(parameters: string): Promise -} - -/** - * @ignore - */ -interface RtcUserInfoInterface { - registerLocalUserAccount(appId: string, userAccount: string): Promise - - joinChannelWithUserAccount(token: string, channelName: string, userAccount: string): Promise - - getUserInfoByUserAccount(userAccount: string): Promise - - getUserInfoByUid(uid: number): Promise -} - -/** - * @ignore - */ -interface RtcAudioInterface { - enableAudio(): Promise - - disableAudio(): Promise - - setAudioProfile(profile: AudioProfile, scenario: AudioScenario): Promise - - adjustRecordingSignalVolume(volume: number): Promise - - adjustUserPlaybackSignalVolume(uid: number, volume: number): Promise - - adjustPlaybackSignalVolume(volume: number): Promise - - enableLocalAudio(enabled: boolean): Promise - - muteLocalAudioStream(muted: boolean): Promise - - muteRemoteAudioStream(uid: number, muted: boolean): Promise - - muteAllRemoteAudioStreams(muted: boolean): Promise - - setDefaultMuteAllRemoteAudioStreams(muted: boolean): Promise - - enableAudioVolumeIndication(interval: number, smooth: number, report_vad: boolean): Promise -} - -/** - * @ignore - */ -interface RtcVideoInterface { - enableVideo(): Promise - - disableVideo(): Promise - - setVideoEncoderConfiguration(config: VideoEncoderConfiguration): Promise - - startPreview(): Promise - - stopPreview(): Promise - - enableLocalVideo(enabled: boolean): Promise - - muteLocalVideoStream(muted: boolean): Promise - - muteRemoteVideoStream(uid: number, muted: boolean): Promise - - muteAllRemoteVideoStreams(muted: boolean): Promise - - setDefaultMuteAllRemoteVideoStreams(muted: boolean): Promise - - setBeautyEffectOptions(enabled: boolean, options: BeautyOptions): Promise -} - -/** - * @ignore - */ -interface RtcAudioMixingInterface { - startAudioMixing(filePath: string, loopback: boolean, replace: boolean, cycle: number): Promise - - stopAudioMixing(): Promise - - pauseAudioMixing(): Promise - - resumeAudioMixing(): Promise - - adjustAudioMixingVolume(volume: number): Promise - - adjustAudioMixingPlayoutVolume(volume: number): Promise - - adjustAudioMixingPublishVolume(volume: number): Promise - - getAudioMixingPlayoutVolume(): Promise - - getAudioMixingPublishVolume(): Promise - - getAudioMixingDuration(): Promise - - getAudioMixingCurrentPosition(): Promise - - setAudioMixingPosition(pos: number): Promise - - setAudioMixingPitch(pitch: number): Promise -} - -/** - * @ignore - */ -interface RtcAudioEffectInterface { - getEffectsVolume(): Promise - - setEffectsVolume(volume: number): Promise - - setVolumeOfEffect(soundId: number, volume: number): Promise - - playEffect(soundId: number, filePath: string, loopCount: number, pitch: number, pan: number, gain: number, publish: Boolean): Promise - - stopEffect(soundId: number): Promise - - stopAllEffects(): Promise - - preloadEffect(soundId: number, filePath: string): Promise - - unloadEffect(soundId: number): Promise - - pauseEffect(soundId: number): Promise - - pauseAllEffects(): Promise - - resumeEffect(soundId: number): Promise - - resumeAllEffects(): Promise - - setAudioSessionOperationRestriction(restriction: AudioSessionOperationRestriction): Promise -} - -/** - * @ignore - */ -interface RtcVoiceChangerInterface { - setLocalVoiceChanger(voiceChanger: AudioVoiceChanger): Promise - - setLocalVoiceReverbPreset(preset: AudioReverbPreset): Promise - - setLocalVoicePitch(pitch: number): Promise - - setLocalVoiceEqualization(bandFrequency: AudioEqualizationBandFrequency, bandGain: number): Promise - - setLocalVoiceReverb(reverbKey: AudioReverbType, value: number): Promise -} - -/** - * @ignore - */ -interface RtcVoicePositionInterface { - enableSoundPositionIndication(enabled: boolean): Promise - - setRemoteVoicePosition(uid: number, pan: number, gain: number): Promise -} - -/** - * @ignore - */ -interface RtcPublishStreamInterface { - setLiveTranscoding(transcoding: LiveTranscoding): Promise - - addPublishStreamUrl(url: string, transcodingEnabled: boolean): Promise - - removePublishStreamUrl(url: string): Promise -} - -/** - * @ignore - */ -interface RtcMediaRelayInterface { - startChannelMediaRelay(channelMediaRelayConfiguration: ChannelMediaRelayConfiguration): Promise - - updateChannelMediaRelay(channelMediaRelayConfiguration: ChannelMediaRelayConfiguration): Promise - - stopChannelMediaRelay(): Promise -} - -/** - * @ignore - */ -interface RtcAudioRouteInterface { - setDefaultAudioRoutetoSpeakerphone(defaultToSpeaker: boolean): Promise - - setEnableSpeakerphone(enabled: boolean): Promise - - isSpeakerphoneEnabled(): Promise -} - -/** - * @ignore - */ -interface RtcEarMonitoringInterface { - enableInEarMonitoring(enabled: boolean): Promise - - setInEarMonitoringVolume(volume: number): Promise -} - -/** - * @ignore - */ -interface RtcDualStreamInterface { - enableDualStreamMode(enabled: boolean): Promise - - setRemoteVideoStreamType(uid: number, streamType: VideoStreamType): Promise - - setRemoteDefaultVideoStreamType(streamType: VideoStreamType): Promise -} - -/** - * @ignore - */ -interface RtcFallbackInterface { - setLocalPublishFallbackOption(option: StreamFallbackOptions): Promise - - setRemoteSubscribeFallbackOption(option: StreamFallbackOptions): Promise - - setRemoteUserPriority(uid: number, userPriority: UserPriority): Promise -} - -/** - * @ignore - */ -interface RtcTestInterface { - startEchoTest(intervalInSeconds: number): Promise - - stopEchoTest(): Promise - - enableLastmileTest(): Promise - - disableLastmileTest(): Promise - - startLastmileProbeTest(config: LastmileProbeConfig): Promise - - stopLastmileProbeTest(): Promise -} - -/** - * @ignore - */ -interface RtcMediaMetadataInterface { - registerMediaMetadataObserver(): Promise - - unregisterMediaMetadataObserver(): Promise - - setMaxMetadataSize(size: number): Promise - - sendMetadata(metadata: string): Promise -} - -/** - * @ignore - */ -interface RtcWatermarkInterface { - addVideoWatermark(watermarkUrl: string, options: WatermarkOptions): Promise - - clearVideoWatermarks(): Promise -} - -/** - * @ignore - */ -interface RtcEncryptionInterface { - setEncryptionSecret(secret: string): Promise - - setEncryptionMode(encryptionMode: EncryptionMode): Promise - - enableEncryption(enabled: boolean, config: EncryptionConfig): Promise -} - -/** - * @ignore - */ -interface RtcAudioRecorderInterface { - startAudioRecording(filePath: string, sampleRate: AudioSampleRateType, quality: AudioRecordingQuality): Promise - - stopAudioRecording(): Promise -} - -/** - * @ignore - */ -interface RtcInjectStreamInterface { - addInjectStreamUrl(url: string, config: LiveInjectStreamConfig): Promise - - removeInjectStreamUrl(url: string): Promise -} - -/** - * @ignore - */ -interface RtcCameraInterface { - switchCamera(): Promise - - isCameraZoomSupported(): Promise - - isCameraTorchSupported(): Promise - - isCameraFocusSupported(): Promise - - isCameraExposurePositionSupported(): Promise - - isCameraAutoFocusFaceModeSupported(): Promise - - setCameraZoomFactor(factor: number): Promise - - getCameraMaxZoomFactor(): Promise - - setCameraFocusPositionInPreview(positionX: number, positionY: number): Promise - - setCameraExposurePosition(positionXinView: number, positionYinView: number): Promise - - enableFaceDetection(enable: boolean): Promise - - setCameraTorchOn(isOn: boolean): Promise - - setCameraAutoFocusFaceModeEnabled(enabled: boolean): Promise - - setCameraCapturerConfiguration(config: CameraCapturerConfiguration): Promise -} - -/** - * @ignore - */ -interface RtcStreamMessageInterface { - createDataStream(reliable: boolean, ordered: boolean): Promise - - sendStreamMessage(streamId: number, message: string): Promise -} diff --git a/src/src/RtcEvents.ts b/src/src/RtcEvents.ts deleted file mode 100644 index 3cfc4c93b..000000000 --- a/src/src/RtcEvents.ts +++ /dev/null @@ -1,1681 +0,0 @@ -import { - AudioLocalError, - AudioLocalState, - AudioMixingErrorCode, - AudioMixingStateCode, - AudioOutputRouting, - AudioRemoteState, - AudioRemoteStateReason, - AudioVolumeInfo, - ChannelMediaRelayError, - ChannelMediaRelayEvent, - ChannelMediaRelayState, - ClientRole, - 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" - - -/** - * @internal - * @ignore - */ - -export type Listener = (...args: any[]) => any - -/** - * @internal - * @ignore - */ -export interface Subscription { - remove(): void -} - - -export type EmptyCallback = () => void -export type WarningCallback = -/** - * @param warn Warning code. - */ - (warn: WarningCode) => void -export type ErrorCallback = -/** - * @param err Error code. - */ - (err: ErrorCode) => void -export type ApiCallCallback = -/** - * @param error [Error Code]{@link ErrorCode} that the SDK returns when the method call fails. - * @param api The method executed by the SDK. - * @param result The result of the method call. - */ - (error: ErrorCode, api: string, result: string) => void -export type UidWithElapsedAndChannelCallback = -/** - * @param channel Channel name. - * @param uid User ID. - * @param elapsed Time elapsed (ms) from the user calling [`joinChannel`]{@link RtcEngine.joinChannel} until - * this callback is triggered. - */ - (channel: string, uid: number, elapsed: number) => void -export type RtcStatsCallback = -/** - * @param stats Statistics of the call. - */ - (stats: RtcStats) => void -export type UserAccountCallback = -/** - * @param uid The ID of the local user. - * @param userAccount The user account of the local user. - */ - (uid: number, userAccount: string) => void -export type UserInfoCallback = -/** - * @param uid The ID of the remote user. - * @param userInfo The `UserInfo` object that contains the user ID and user account of the remote user. - */ - (uid: number, userInfo: UserInfo) => void -export type ClientRoleCallback = -/** - * @param oldRole Role that the user switches from. - * @param newRole Role that the user switches to. - */ - (oldRole: ClientRole, newRole: ClientRole) => void -export type UidWithElapsedCallback = -/** - * @param uid This parameter has the following definitions in different events: - * - [`UserJoined`]{@link RtcEngineEvents.UserJoined}: ID of the user or host who joins the channel. - * - [`FirstRemoteAudioFrame`]{@link RtcEngineEvents.FirstRemoteAudioFrame}: User ID of the remote user. - * - [`FirstRemoteAudioDecoded`]{@link RtcEngineEvents.FirstRemoteAudioDecoded}: User ID of the remote user sending the audio stream. - * - [`JoinChannelSuccess`]{@link RtcChannelEvents.JoinChannelSuccess}: User ID. - * - [`RejoinChannelSuccess`]{@link RtcChannelEvents.RejoinChannelSuccess}: User ID. - * @param elapsed This parameter has the following definitions in different events: - * - [`UserJoined`]{@link RtcEngineEvents.UserJoined}: Time delay (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} or [`setClientRole`]{@link RtcEngine.setClientRole} - * until this callback is triggered. - * - [`FirstRemoteAudioFrame`]{@link RtcEngineEvents.FirstRemoteAudioFrame}: Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until this callback is triggered. - * - [`FirstRemoteAudioDecoded`]{@link RtcEngineEvents.FirstRemoteAudioDecoded}: Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until the SDK triggers this callback. - * - [`JoinChannelSuccess`]{@link RtcChannelEvents.JoinChannelSuccess}: Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcChannel.joinChannel} until this callback is triggered. - * - [`RejoinChannelSuccess`]{@link RtcChannelEvents.RejoinChannelSuccess}: Time elapsed (ms) from the local user starting to reconnect until this callback is triggered. - * - */ - (uid: number, elapsed: number) => void -export type UserOfflineCallback = -/** - * @param uid ID of the user or host who leaves the channel or goes offline. - * @param reason Reason why the user goes offline. - */ - (uid: number, reason: UserOfflineReason) => void -export type ConnectionStateCallback = -/** - * @param state The current network connection state. - * @param reason The reason causing the change of the connection state. - */ - (state: ConnectionStateType, reason: ConnectionChangedReason) => void -export type NetworkTypeCallback = -/** - * @param type The network type. - */ - (type: NetworkType) => void -export type TokenCallback = -/** - * @param token The token that will expire in 30 seconds. - */ - (token: string) => void -export type AudioVolumeCallback = -/** - * @param speakers An array containing the user ID and volume information for each speaker. - * - * In the local user’s callback, this array contains the following members: - * - `uid` = 0, - * - `volume` = `totalVolume`, which reports the sum of the voice volume and audio-mixing volume of the local user, and - * - `vad`, which reports the voice activity status of the local user. - * - * In the remote speakers' callback, this array contains the following members: - * - `uid` of each remote speaker, - * - `volume`, which reports the sum of the voice volume and audio-mixing volume of each remote speaker, and - * - `vad` = 0. - * - * An empty `speakers` array in the callback indicates that no remote user is speaking at the moment. - * - * @param totalVolume Total volume after audio mixing. The value ranges between 0 (lowest volume) and 255 (highest volume). - * - In the local user’s callback, `totalVolume` is the sum of the voice volume and audio-mixing volume of the local user. - * - In the remote speakers' callback, `totalVolume` is the sum of the voice volume and audio-mixing - * volume of all remote speakers. - */ - (speakers: AudioVolumeInfo[], totalVolume: number) => void -export type UidCallback = -/** - * @param uid User ID of the active speaker. A `uid` of 0 represents the local user. - */ - (uid: number) => void -export type ElapsedCallback = -/** - * @param elapsed Time elapsed (ms) from the local user calling the [`joinChannel`]{@link RtcEngine.joinChannel} until - * this callback is triggered. - */ - (elapsed: number) => void -export type VideoFrameCallback = -/** - * @param width Width (pixels) of the first local video frame. - * @param height Height (pixels) of the first local video frame. - * @param elapsed Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until this - * callback is triggered. - * If [`startPreview`]{@link RtcEngine.startPreview} is called before [`joinChannel`]{@link RtcEngine.joinChannel}, elapsed is the - * time elapsed (ms) from the local user calling [`startPreview`]{@link RtcEngine.startPreview} until this callback is triggered. - */ - (width: number, height: number, elapsed: number) => void -export type UidWithMutedCallback = -/** - * @param uid ID of the remote user. - * @param muted Whether the remote user's video stream playback pauses/resumes: - * - * - `true`: Pause. - * - `false`: Resume. - */ - (uid: number, muted: boolean) => void -export type VideoSizeCallback = -/** - * @param uid User ID of the remote user or local user (0) whose video size or rotation changes. - * @param width New width (pixels) of the video. - * @param height New height (pixels) of the video. - * @param rotation New rotation of the video [0 to 360). - */ - (uid: number, width: number, height: number, rotation: number) => void -export type RemoteVideoStateCallback = -/** - * @param uid ID of the remote user whose video state changes. - * @param state State of the remote video. - * @param reason The reason of the remote video state change. - * @param elapsed Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until the SDK - * triggers this callback. - */ - (uid: number, state: VideoRemoteState, reason: VideoRemoteStateReason, elapsed: number) => void -export type LocalVideoStateCallback = -/** - * @param localVideoState The local video state. - * @param error The detailed error information of the local video. - */ - (localVideoState: LocalVideoStreamState, error: LocalVideoStreamError) => void -export type RemoteAudioStateCallback = -/** - * @param uid ID of the user whose audio state changes. - * @param state State of the remote audio. - * @param reason The reason of the remote audio state change. - * @param elapsed Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until the - * SDK triggers this callback. - */ - (uid: number, state: AudioRemoteState, reason: AudioRemoteStateReason, elapsed: number) => void -export type LocalAudioStateCallback = -/** - * @param state State of the local audio. - * @param error The error information of the local audio. - */ - (state: AudioLocalState, error: AudioLocalError) => void -export type FallbackCallback = -/** - * @param isFallbackOrRecover Whether the published stream fell back to audio-only or switched back to the video: - * - * - `true`: The published stream fell back to audio-only due to poor network conditions. - * - `false`: The published stream switched back to the video after the network conditions improved. - */ - (isFallbackOrRecover: boolean) => void -export type FallbackWithUidCallback = -/** - * @param uid ID of the remote user sending the stream. - * @param isFallbackOrRecover Whether the remote media stream fell back to audio-only or - * switched back to the video: - * - * - `true`: The remote media stream fell back to audio-only due to poor network conditions. - * - `false`: The remote media stream switched back to the video stream after the network conditions improved. - */ - (uid: number, isFallbackOrRecover: boolean) => void -export type AudioRouteCallback = -/** - * @param routing Audio output routing. - */ - (routing: AudioOutputRouting) => void -export type RectCallback = -/** - * @param rect Rectangular area in the camera zoom specifying the focus area. - */ - - (rect: Rect) => void -export type NetworkQualityCallback = -/** - * @param quality The last mile network quality based on the uplink and downlink packet loss rate and jitter. - */ - (quality: NetworkQuality) => void -export type NetworkQualityWithUidCallback = -/** - * @param uid User ID. The network quality of the user with this uid is reported. - * @param txQuality Uplink transmission quality of the user in terms of the transmission bitrate, packet loss rate, average RTT (Round-Trip Time) - * and jitter of the uplink network. `txQuality` is a quality rating helping you understand how well the current uplink - * network conditions can support the selected VideoEncoderConfiguration. - * For example, a 1000 Kbps uplink network may be adequate for video frames with a resolution - * of 680 × 480 and a frame rate of 30 fps, but may be inadequate for resolutions higher than 1280 × 720. - * @param rxQuality Downlink network quality rating of the user in terms of packet loss rate, average RTT, and - * jitter of the downlink network. - */ - (uid: number, txQuality: NetworkQuality, rxQuality: NetworkQuality) => void -export type LastmileProbeCallback = -/** - * @param result The uplink and downlink last-mile network probe test result. - */ - (result: LastmileProbeResult) => void -export type LocalVideoStatsCallback = -/** - * @param stats The statistics of the local video stream. - */ - (stats: LocalVideoStats) => void -export type LocalAudioStatsCallback = -/** - * @param stats The statistics of the local audio stream. - */ - (stats: LocalAudioStats) => void -export type RemoteVideoStatsCallback = -/** - * @param stats Statistics of the received remote video streams. - */ - (stats: RemoteVideoStats) => void -export type RemoteAudioStatsCallback = -/** - * @param stats Statistics of the received remote audio streams. - */ - (stats: RemoteAudioStats) => void -export type AudioMixingStateCallback = -/** - * @param state The state code. - * @param errorCode The error code. - */ - (state: AudioMixingStateCode, errorCode: AudioMixingErrorCode) => void -export type SoundIdCallback = -/** - * @param soundId ID of the local audio effect. Each local audio effect has a unique ID. - */ - (soundId: number) => void -export type RtmpStreamingStateCallback = -/** - * @param url The RTMP URL address. - * @param state The RTMP streaming state. - * @param errCode The detailed error information for streaming. - */ - (url: string, state: RtmpStreamingState, errCode: RtmpStreamingErrorCode) => void -export type StreamInjectedStatusCallback = -/** - * @param url The URL address of the externally injected stream. - * @param uid User ID. - * @param status State of the externally injected stream. - */ - (url: string, uid: number, status: InjectStreamStatus) => void -export type StreamMessageCallback = -/** - * @param uid User ID of the remote user sending the data stream. - * @param streamId Stream ID. - * @param data Data received by the local user. - */ - (uid: number, streamId: number, data: string) => void -export type StreamMessageErrorCallback = -/** - * @param uid User ID of the remote user sending the data stream. - * @param streamId Stream ID. - * @param error Error code. - * @param missed The number of lost messages. - * @param cached The number of incoming cached messages when the data stream is interrupted. - */ - (uid: number, streamId: number, error: ErrorCode, missed: number, cached: number) => void -export type MediaRelayStateCallback = -/** - * @param state The state code. - * @param code The error code. - */ - (state: ChannelMediaRelayState, code: ChannelMediaRelayError) => void -export type MediaRelayEventCallback = -/** - * @param code The event code for media stream relay. - */ - (code: ChannelMediaRelayEvent) => void -export type VideoFrameWithUidCallback = -/** - * @param uid User ID of the remote user sending the video streams. - * @param width Width (pixels) of the video stream. - * @param height Height (pixels) of the video stream. - * @param elapsed Time elapsed (ms) from the local user calling [`joinChannel`]{@link RtcEngine.joinChannel} until this - * callback is triggered. - */ - (uid: number, width: number, height: number, elapsed: number) => void -export type UrlWithErrorCallback = -/** - * @param url The RTMP streaming URL. - * @param error The detailed error information. - */ - (url: string, error: ErrorCode) => void -export type UrlCallback = -/** - * @param url The RTMP URL address. - */ - (url: string) => void -export type TransportStatsCallback = -/** - * @param uid User ID of the remote user sending the audio packet/video packet. - * @param delay Network time delay (ms) from the remote user sending the audio packet/video packet to the local user. - * @param lost Packet loss rate (%) of the audio packet/video packet sent from the remote user. - * @param rxKBitRate Received bitrate (Kbps) of the audio packet/video packet sent from the remote user. - */ - (uid: number, delay: number, lost: number, rxKBitRate: number) => void -export type UidWithEnabledCallback = -/** - * @param uid User ID of the remote user. - * @param enabled Whether the specific remote user enables/disables the video module: - * - * - `true`: Enabled. The remote user can enter a video session. - * - `false`: Disabled. The remote user can only enter a voice session, and cannot send or receive - * any video stream. - */ - (uid: number, enabled: boolean) => void -export type EnabledCallback = -/** - * @param enabled Whether the microphone is enabled/disabled: - * - `true`: Enabled. - * - `false`: Disabled. - */ - (enabled: boolean) => void -export type AudioQualityCallback = -/** - * @param uid User ID of the speaker. - * @param quality Audio quality of the user. - * @param delay Time delay (ms) of the audio packet from the sender to the receiver, including the time delay - * from audio sampling pre-processing, transmission, and the jitter buffer. - * @param lost Packet loss rate (%) of the audio packet sent from the sender to the receiver. - */ - (uid: number, quality: number, delay: number, lost: number) => void -export type MetadataCallback = -/** - * @param buffer The received metadata. - * @param uid The ID of the user who sent the metadata. - * @param timeStampMs The timestamp (ms) of the received metadata. - */ - (buffer: string, uid: number, timeStampMs: number) => void -export type FacePositionCallback = -/** - * @param imageWidth The width (px) of the local video. - * @param imageHeight The height (px) of the local video. - * @param faces The information of the detected human face. For details, see [`FacePositionInfo`]{@link FacePositionInfo}. - * The number of the `FacePositionInfo` array depends on the number of human faces detected. - * If the array length is 0, it means that no human face is detected. - */ - (imageWidth: number, imageHeight: number, faces: FacePositionInfo[]) => void -export type StreamPublishStateCallback = -/** - * @param channel The channel name. - * @param oldState The previous publishing state. See [`StreamPublishState`]{@link StreamPublishState}. - * @param newState The current publishing state. See [`StreamPublishState`]{@link StreamPublishState}. - * @param elapseSinceLastState The time elapsed (ms) from the previous state to the current state. - */ - (channel: string, oldState: StreamPublishState, newState: StreamPublishState, elapseSinceLastState: number) => void -export type StreamSubscribeStateCallback = -/** - * @param channel The channel name. - * @param oldState The previous publishing state. See [`StreamPublishState`]{@link StreamPublishState}. - * @param newState The current publishing state. See [`StreamPublishState`]{@link StreamPublishState}. - * @param elapseSinceLastState The time elapsed (ms) from the previous state to the current state. - */ - (channel: string, oldState: StreamSubscribeState, newState: StreamSubscribeState, elapseSinceLastState: number) => void -export type RtmpStreamingEventCallback = -/** - * @param url The RTMP streaming URL. - * @param eventCode The event code. See [`RtmpStreamingEvent`]{@link RtmpStreamingEvent}. - */ - (url: string, eventCode: RtmpStreamingEvent) => void - -/** - * Callbacks. - * - * The SDK uses the [`RtcEngineEvents`]{@link RtcEngineEvents} interface class to send callbacks to the application, and the application inherits the methods of this interface class to retrieve these callbacks. - * All methods in this interface class have their (empty) default implementations, and the application can inherit only some of the required events instead of all of them. - * In the callbacks, the application should avoid time-consuming tasks or call blocking APIs (such as SendMessage), otherwise, the SDK may not work properly. - */ -export interface RtcEngineEvents { - /** - * Reports a warning during SDK runtime. - * - * In most cases, the app can ignore the warning reported by the SDK because the SDK can usually fix the issue and resume running. - * - * For instance, the SDK may report a [`LookupChannelTimeout`]{@link WarningCode.LookupChannelTimeout} warning upon disconnection with the server and tries to reconnect. For detailed warning codes, see [`WarningCode`]{@link WarningCode}. - * - * @event Warning - */ - Warning: WarningCallback - - /** - * Reports an error during SDK runtime. - * - * In most cases, the SDK cannot fix the issue and resume running. The SDK requires the app to take action or informs the user about the issue. - * - * For example, the SDK reports a [`StartCall`]{@link ErrorCode.StartCall} error when failing to initialize a call. The app informs the user that the call initialization failed and invokes the [`leaveChannel`]{@link RtcEngine.leaveChannel} method to leave the channel. For detailed error codes, see {@link ErrorCode}. - * - * @event Error - */ - Error: ErrorCallback - - /** - * Occurs when an API method is executed. - * - * @event ApiCallExecuted - */ - ApiCallExecuted: ApiCallCallback - - /** - * Occurs when the local user joins a specified channel. - * - * The channel name assignment is based on channelName specified in the joinChannel method. - * - * If the uid is not specified when [`joinChannel`]{@link RtcEngine.joinChannel} is called, the server automatically assigns a uid. - * - * @event JoinChannelSuccess - */ - JoinChannelSuccess: UidWithElapsedAndChannelCallback - - /** - * Occurs when a user rejoins the channel after being disconnected due to network problems. - * - * When a user loses connection with the server because of network problems, the SDK automatically tries to reconnect and triggers this callback upon reconnection. - * - * @event RejoinChannelSuccess - */ - RejoinChannelSuccess: UidWithElapsedAndChannelCallback - - /** - * Occurs when a user leaves the channel. - * - * When the app calls the [`leaveChannel`]{@link RtcEngine.leaveChannel} method, the SDK uses this callback to notify the app when the user leaves the channel. - * - * With this callback, the application retrieves the channel information, such as the call duration and statistics. - * - * @event LeaveChannel - */ - LeaveChannel: RtcStatsCallback - - /** - * Occurs when the local user registers a user account. - * - * This callback is triggered when the local user successfully registers a user account by calling [`registerLocalUserAccount`]{@link RtcEngine.registerLocalUserAccount}, or joins a channel by calling [`joinChannelWithUserAccount`]{@link RtcEngine.joinChannelWithUserAccount}. - * This callback reports the user ID and user account of the local user. - * - * @event LocalUserRegistered - */ - LocalUserRegistered: UserAccountCallback - - /** - * Occurs when the SDK gets the user ID and user account of the remote user. - * - * After a remote user joins the channel, the SDK gets the UID and user account of the remote user, caches them in a mapping table object ([`UserInfo`]{@link UserInfo}), and triggers this callback on the local client. - * - * @event UserInfoUpdated - */ - UserInfoUpdated: UserInfoCallback - - /** - * Occurs when the user role switches in live interactive streaming. For example, from a host to an audience or vice versa. - * - * The SDK triggers this callback when the local user switches the user role by calling [`setClientRole`]{@link RtcEngine.setClientRole} after joining the channel. - * - * @event ClientRoleChanged - */ - ClientRoleChanged: ClientRoleCallback - - /** - * Occurs when a remote user ([`Communication`]{@link ChannelProfile.Communication})/host ([`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting}) joins the channel. - * - [`Communication`]{@link ChannelProfile.Communication} profile: This callback notifies the app when another user joins the channel. If other users are already in the channel, the SDK also reports to the app on the existing users. - * - [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile: This callback notifies the app when the host joins the channel. If other hosts are already in the channel, the SDK also reports to the app on the existing hosts. We recommend having at most 17 hosts in a channel. - * - * The SDK triggers this callback under one of the following circumstances: - * - A remote user/host joins the channel by calling [`joinChannel`]{@link RtcEngine.joinChannel}. - * - A remote user switches the user role to the host by calling [`setClientRole`]{@link RtcEngine.setClientRole} after joining the channel. - * - A remote user/host rejoins the channel after a network interruption. - * - The host injects an online media stream into the channel by calling [`addInjectStreamUrl`]{@link RtcEngine.addInjectStreamUrl}. - * - * **Note** - * In the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile: - * - The host receives the [`UserJoined`]{@link UserJoined} callback when another host joins the channel. - * - The audience in the channel receives the [`UserJoined`]{@link UserJoined} callback when a new host joins the channel. - * - When a web application joins the channel, the [`UserJoined`]{@link UserJoined} callback is triggered as long as the web application publishes streams. - * - * @event UserJoined - */ - UserJoined: UidWithElapsedCallback - - /** - * Occurs when a remote user ([`Communication`]{@link ChannelProfile.Communication})/host ([`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting}) leaves the channel. - * - * There are two reasons for users to become offline: - * - Leave the channel: When the user/host leaves the channel, the user/host sends a goodbye message. When this message is received, the SDK determines that the user/host leaves the channel. - * - Drop offline: When no data packet of the user or host is received for a certain period of time (20 seconds for the [`Communication`]{@link ChannelProfile.Communication} profile, and more for the [`LiveBroadcasting`]{@link ChannelProfile.LiveBroadcasting} profile), the SDK assumes that the user/host drops offline. A poor network connection may lead to false detections, so we recommend using the Agora RTM SDK for reliable offline detection. - * - * @event UserOffline - */ - UserOffline: UserOfflineCallback - - /** - * Occurs when the network connection state changes. - * - * The Agora SDK returns this callback to report on the current network connection state when it changes, and the reason to such change. - * - * @event ConnectionStateChanged - */ - ConnectionStateChanged: ConnectionStateCallback - - /** - * Occurs when the network type changes. - * - * The SDK returns the current network type in this callback. When the network connection is interrupted, this callback indicates whether the interruption is caused by a network type change or poor network conditions. - * - * @event NetworkTypeChanged - */ - NetworkTypeChanged: NetworkTypeCallback - - /** - * Occurs when the SDK cannot reconnect to Agora's edge server 10 seconds after its connection to the server is interrupted. - * - * The SDK triggers this callback when it cannot connect to the server 10 seconds after calling [`joinChannel`]{@link RtcEngine.joinChannel}, regardless of whether it is in the channel or not. - * - * If the SDK fails to rejoin the channel 20 minutes after being disconnected from Agora's edge server, the SDK stops rejoining the channel. - * - * @event ConnectionLost - */ - ConnectionLost: EmptyCallback - - /** - * Occurs when the token expires in 30 seconds. - * - * The user becomes offline if the token used when joining the channel expires. This callback is triggered 30 seconds before the token expires to remind the app to get a new token. Upon receiving this callback, you need to generate a new token on the server and call [`renewToken`]{@link RtcEngine.renewToken} to pass the new token to the SDK. - * - * @event TokenPrivilegeWillExpire - */ - TokenPrivilegeWillExpire: TokenCallback - - /** - * Occurs when the token has expired. - * - * After a token is specified when joining the channel, the token expires after a certain period of time, - * and a new token is required to reconnect to the server. This callback notifies the app to generate a - * new token and call [`joinChannel`]{@link RtcEngine.joinChannel} to rejoin the channel with the new token. - * - * @event RequestToken - */ - RequestToken: EmptyCallback - - /** - * Reports which users are speaking and the speakers' volume, and whether the local user is speaking. - * - * This callback reports the IDs and volumes of the loudest speakers (at most 3) at the moment in the channel, and whether the local user is speaking. - * - * By default, this callback is disabled. You can enable it by calling [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication}. Once enabled, this callback is triggered at the set interval, regardless of whether a user speaks or not. - * - * The SDK triggers two independent `AudioVolumeIndication` callbacks at one time, which separately report the volume information of the local user and all the remote speakers. For more information, see the detailed parameter descriptions. - * - * **Note** - * - To enable the voice activity detection of the local user, ensure that you set `report_vad(true)` in the [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication} method. - * - Calling [`muteLocalAudioStream`]{@link RtcEngine.muteLocalAudioStream} affects the SDK's behavior. - * - If the local user calls [`muteLocalAudioStream`]{@link RtcEngine.muteLocalAudioStream}, the SDK stops triggering the local user's callback. - * - 20 seconds after a remote speaker calls [`muteLocalAudioStream`]{@link RtcEngine.muteLocalAudioStream}, the remote speakers' callback does not include information of this remote user; 20 seconds after all remote users call the the [`muteLocalAudioStream`]{@link muteLocalAudioStream} method, the SDK stops triggering the remote speakers' callback. - * - * @event AudioVolumeIndication - */ - AudioVolumeIndication: AudioVolumeCallback - - /** - * Reports which user is the loudest speaker. - * - * This callback reports the speaker with the highest accumulative volume during a certain period. If the user enables the audio volume indication by - * calling [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication}, this callback returns the uid of the active speaker whose voice is detected by the audio volume detection module of the SDK. - * - * **Note** - * - To receive this callback, you need to call [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication}. - * - This callback returns the user ID of the user with the highest voice volume during a period of time, instead of at the moment. - * - * @event ActiveSpeaker - */ - ActiveSpeaker: UidCallback - - /** - * Occurs when the first local audio frame is sent. - * - * @deprecated Deprecated as of v3.1.2. Use [`FirstLocalAudioFramePublished`]{@link RtcEngineEvents.FirstLocalAudioFramePublished} instead. - * - * @event FirstLocalAudioFrame - */ - FirstLocalAudioFrame: ElapsedCallback - - /** - * Occurs when the first local video frame is rendered. - * - * This callback is triggered after the first local video frame is rendered on the local video window. - * - * @event FirstLocalVideoFrame - */ - FirstLocalVideoFrame: VideoFrameCallback - - /** - * Occurs when a remote user stops/resumes sending the video stream. - * - * @deprecated - * - * This callback is deprecated. Use the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback with the following parameters for the same function: - * - [`Stopped`]{@link VideoRemoteState.Stopped} and [`RemoteMuted`]{@link VideoRemoteStateReason.RemoteMuted}. - * - [`Decoding`]{@link VideoRemoteState.Decoding} and [`RemoteUnmuted`]{@link VideoRemoteStateReason.RemoteUnmuted}. - * - * The SDK triggers this callback when the remote user stops or resumes sending the video stream by calling the [`muteLocalVideoStream`]{@link RtcEngine.muteLocalVideoStream} method. - * - * **Note** - * - * This callback is invalid when the number of users or hosts in the channel exceeds 17. - * - * @event UserMuteVideo - */ - UserMuteVideo: UidWithMutedCallback - - /** - * Occurs when the video size or rotation information of a remote user changes. - * - * @event VideoSizeChanged - */ - VideoSizeChanged: VideoSizeCallback - - /** - * Occurs when the remote video state changes. - * - * @event RemoteVideoStateChanged - */ - RemoteVideoStateChanged: RemoteVideoStateCallback - - /** - * Occurs when the local video state changes. - * - * The SDK returns the current video state in this callback. - * This callback indicates the state of the local video stream, including camera capturing and video encoding, and allows you to troubleshoot issues when exceptions occur. - * When the state is [`Failed`]{@link LocalVideoStreamState.Failed}, see the error parameter for details. - * - * @event LocalVideoStateChanged - */ - LocalVideoStateChanged: LocalVideoStateCallback - - /** - * Occurs when the remote audio state changes. - * - * This callback indicates the state change of the remote audio stream. - * - * **Note** - * - * This callback does not work properly when the number of users (in the [`Communication`] profile) or hosts (in the [`LiveBroadcasting`] profile) in the channel exceeds 17. - * - * @event RemoteAudioStateChanged - */ - RemoteAudioStateChanged: RemoteAudioStateCallback - - /** - * Occurs when the local audio stream state changes. - * - * This callback indicates the state change of the local audio stream, including the state of the audio recording and encoding, and allows you to troubleshoot issues when exceptions occur. - * - * **Note** - * - * When the state is [`Failed`]{@link AudioLocalState.Failed}, see the error parameter for details. - * - * @event LocalAudioStateChanged - */ - LocalAudioStateChanged: LocalAudioStateCallback - - /** - * Occurs when the published media stream falls back to an audio-only stream due to poor network conditions - * or switches back to video stream after the network conditions improve. - * - * If you call [`setLocalPublishFallbackOption`]{@link RtcEngine.setLocalPublishFallbackOption} and set option as [`AudioOnly`]{@link StreamFallbackOptions.AudioOnly}, - * this callback is triggered when the locally published stream falls back to audio-only mode due to poor uplink conditions, - * or when the audio stream switches back to the video after the uplink network condition improves. Once the published stream falls back to audio only, - * the remote app receives the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback. - * - * @event LocalPublishFallbackToAudioOnly - */ - LocalPublishFallbackToAudioOnly: FallbackCallback - - /** - * Occurs when the remote media stream falls back to audio-only stream due to poor network conditions or switches back to video stream after the network conditions improve. - * - * If you call [`setRemoteSubscribeFallbackOption`]{@link RtcEngine.setRemoteSubscribeFallbackOption} and set - * option as [`AudioOnly`]{@link StreamFallbackOptions.AudioOnly}, - * this callback is triggered when the remotely subscribed media stream falls back to audio-only mode due - * to poor uplink conditions, or when the remotely subscribed media stream switches back to the video after - * the uplink network condition improves. - * - * @event RemoteSubscribeFallbackToAudioOnly - */ - RemoteSubscribeFallbackToAudioOnly: FallbackWithUidCallback - - /** - * Occurs when the local audio playback route changes. - * - * This callback returns that the audio route switched to an earpiece, speakerphone, headset, or Bluetooth device. - * - * The definition of the routing is listed in [`AudioOutputRouting`]{@link AudioOutputRouting}. - * - * @event AudioRouteChanged - */ - AudioRouteChanged: AudioRouteCallback - - /** - * Occurs when the camera focus area is changed. - * - * The SDK triggers this callback when the local user changes the camera focus position by - * calling [`setCameraFocusPositionInPreview`]{@link RtcEngine.setCameraFocusPositionInPreview}. - * - * @event CameraFocusAreaChanged - */ - CameraFocusAreaChanged: RectCallback - - /** - * The camera exposure area has changed. - * - * The SDK triggers this callback when the local user changes the camera exposure position by calling [`setCameraExposurePosition`]{@link RtcEngine.setCameraExposurePosition}. - * - * @event CameraExposureAreaChanged - */ - CameraExposureAreaChanged: RectCallback - - /** - * Reports the face detection result of the local user. - * - * Once you enable face detection by calling [`enableFaceDetection`]{@link RtcEngine.enableFaceDetection}, you can get the following information on the local user in real-time: - * - The width and height of the local video. - * - The position of the human face in the local video. - * - The distance between the human face and the device screen. This value is based on the fitting calculation of the local video size and the position of the human face. - * - * **Note** - * - If the SDK does not detect a face, it reduces the frequency of this callback to reduce power consumption on the local device. - * - The SDK stops triggering this callback when a human face is in close proximity to the screen. - * - On Android, the distance value reported in this callback may be slightly different from the actual distance. Therefore, Agora does not recommend using it for accurate calculation. - * - * @event FacePositionChanged - */ - FacePositionChanged: FacePositionCallback - - /** - * Reports the statistics of the [`RtcEngine`]{@link RtcEngine} once every two seconds. - * - * @event RtcStats - */ - RtcStats: RtcStatsCallback - - /** - * Reports the last mile network quality of the local user once every two seconds before the user joins the channel. - * Last mile refers to the connection between the local device and Agora's edge server. After the application calls the [`enableLastmileTest`]{@link RtcEngine.enableLastmileTest} method, - * this callback reports once every two seconds the uplink and downlink last mile network conditions of the local user before the user joins the channel. - * - * @event LastmileQuality - */ - LastmileQuality: NetworkQualityCallback - - /** - * Reports the last mile network quality of each user in the channel once every two seconds. - * - * Last mile refers to the connection between the local device and Agora's edge server. This callback reports once every two seconds the last mile network conditions of each user in the channel. If a channel includes multiple users, then this callback will be triggered as many times. - * - * @event NetworkQuality - */ - NetworkQuality: NetworkQualityWithUidCallback - - /** - * Reports the last-mile network probe result. - * - * The SDK triggers this callback within 30 seconds after the app calls [`startLastmileProbeTest`]{@link RtcEngine.startLastmileProbeTest}. - * - * @event LastmileProbeResult - */ - LastmileProbeResult: LastmileProbeCallback - - /** - * Reports the statistics of the local video streams. - * - * The SDK triggers this callback once every two seconds for each user/host. If there are multiple users/hosts in the channel, the SDK triggers this callback as many times. - * - * @event LocalVideoStats - */ - LocalVideoStats: LocalVideoStatsCallback - - /** - * Reports the statistics of the local audio stream. - * - * @event LocalAudioStats - */ - LocalAudioStats: LocalAudioStatsCallback - - /** - * Reports the statistics of the video stream from each remote user/host. The SDK triggers this callback once every two seconds for each remote user/host. If a channel includes multiple remote users, the SDK triggers this callback as many times. - * - * @event RemoteVideoStats - */ - RemoteVideoStats: RemoteVideoStatsCallback - - /** - * Reports the statistics of the audio stream from each remote user/host. - * - * The SDK triggers this callback once every two seconds for each remote user/host. If a channel includes multiple remote users, the SDK triggers this callback as many times. - * - * Schemes such as FEC (Forward Error Correction) or retransmission counter the frame loss rate. Hence, users may find the overall audio quality acceptable even when the packet loss rate is high. - * - * @event RemoteAudioStats - */ - RemoteAudioStats: RemoteAudioStatsCallback - - /** - * Occurs when the audio mixing file playback finishes. - * - * @deprecated - * - * This callback is deprecated. - * Use [`AudioMixingStateChanged`]{@link AudioMixingStateChanged} instead. - * - * You can start an audio mixing file playback by calling [`startAudioMixing`]{@link RtcEngine.startAudioMixing}. This callback is triggered when the audio mixing file playback finishes. - * - * If the [`startAudioMixing`]{@link RtcEngine.startAudioMixing} method call fails, an [`AudioMixingOpenError`]{@link WarningCode.AudioMixingOpenError} warning returns in the [`Warning`]{@link Warning} callback. - * - * @event AudioMixingFinished - */ - AudioMixingFinished: EmptyCallback - - /** - * Occurs when the state of the local user's audio mixing file changes. - * - * When you call [`startAudioMixing`]{@link RtcEngine.startAudioMixing} and the state of audio mixing file changes, the Agora SDK triggers this callback. - * - When the audio mixing file plays, pauses playing, or stops playing, this callback returns `710`, `711`, or `713` in state, and `0` in errorCode. - * - When exceptions occur during playback, this callback returns `714` in state and an error in errorCode. - * - If the local audio mixing file does not exist, or if the SDK does not support the file format or cannot access the music file URL, the SDK returns [`AudioMixingOpenError`]{@link WarningCode.AudioMixingOpenError}. - * - * @event AudioMixingStateChanged - */ - AudioMixingStateChanged: AudioMixingStateCallback - - /** - * Occurs when the audio effect file playback finishes. - * - * You can start a local audio effect playback by calling [`playEffect`]{@link RtcEngine.playEffect}. This callback is triggered when the local audio effect file playback finishes. - * - * @event AudioEffectFinished - */ - AudioEffectFinished: SoundIdCallback - - /** - * Occurs when the state of the RTMP 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. - * - * @event RtmpStreamingStateChanged - */ - RtmpStreamingStateChanged: RtmpStreamingStateCallback - - /** - * Occurs when the publisher's transcoding settings are updated. - * - * When the `LiveTranscoding` class in the [`setLiveTranscoding`]{@link RtcEngine.setLiveTranscoding} method updates, the SDK triggers this callback to report the update information. - * - * **Note** - * - If you call [`setLiveTranscoding`]{@link RtcEngine.setLiveTranscoding} to set the `LiveTranscoding` class for the first time, the SDK does not trigger this callback. - * - * @event TranscodingUpdated - */ - TranscodingUpdated: EmptyCallback - - /** - * Reports the status of injecting the online media stream. - * - * @event StreamInjectedStatus - */ - StreamInjectedStatus: StreamInjectedStatusCallback - - /** - * Occurs when the local user receives a remote data stream. - * - * The SDK triggers this callback when the local user receives the stream message that the remote user sends - * by calling the [`sendStreamMessage`]{@link RtcEngine.sendStreamMessage} method. - * - * @event StreamMessage - */ - StreamMessage: StreamMessageCallback - - /** - * Occurs when the local user fails to receive a remote data stream. - * - * The SDK triggers this callback when the local user fails to receive the stream message that the remote - * user sends by calling the [`sendStreamMessage`]{@link RtcEngine.sendStreamMessage} method. - * - * @event StreamMessageError - */ - StreamMessageError: StreamMessageErrorCallback - - /** - * Occurs when the media engine is loaded. - * - * @event MediaEngineLoadSuccess - */ - MediaEngineLoadSuccess: EmptyCallback - - /** - * Occurs when the media engine starts. - * - * @event MediaEngineStartCallSuccess - */ - MediaEngineStartCallSuccess: EmptyCallback - - /** - * Occurs when the state of the media stream relay changes. - * - * The SDK reports the state of the current media relay and possible error messages in this callback. - * - * @event ChannelMediaRelayStateChanged - */ - ChannelMediaRelayStateChanged: MediaRelayStateCallback - - /** - * Reports events during the media stream relay. - * - * @event ChannelMediaRelayEvent - */ - ChannelMediaRelayEvent: MediaRelayEventCallback - - /** - * Occurs when the first remote video frame is rendered. - * - * @deprecated - * - * Use [`Starting`]{@link VideoRemoteState.Starting} or [`Decoding`]{@link VideoRemoteState.Decoding} in the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback instead. - * - * This callback is triggered after the first frame of the remote video is rendered on the video window. The application can retrieve the data of the time elapsed from the user joining the channel until the first video frame is displayed. - * - * @event FirstRemoteVideoFrame - */ - FirstRemoteVideoFrame: VideoFrameWithUidCallback - - /** - * Occurs when the first remote audio frame is received. - * - * @deprecated - * - * Use [`Starting`]{@link AudioRemoteState.Starting} in [`RemoteAudioStateChanged`]{@link RemoteAudioStateChanged} instead. - * - * @event FirstRemoteAudioFrame - */ - FirstRemoteAudioFrame: UidWithElapsedCallback - - /** - * Occurs when the engine receives the first audio frame from a specified remote user. - * - * @deprecated - * - * Use [`Decoding`]{@link VideoRemoteState.Decoding} in [`RemoteAudioStateChanged`]{@link RemoteAudioStateChanged} instead. - * - * This callback is triggered in either of the following scenarios: - * - The remote user joins the channel and sends the audio stream. - * - The remote user stops sending the audio stream and re-sends it after 15 seconds. Possible reasons include: - * - The remote user leaves channel. - * - The remote user drops offline. - * - The remote user calls [`muteLocalAudioStream`]{@link RtcEngine.muteLocalAudioStream}. - * - The remote user calls [`disableAudio`]{@link RtcEngine.disableAudio}. - * - * @event FirstRemoteAudioDecoded - */ - FirstRemoteAudioDecoded: UidWithElapsedCallback - - /** - * Occurs when a remote user stops/resumes sending the audio stream. - * - * @deprecated - * Use the [`RemoteAudioStateChanged`]{@link RemoteAudioStateChanged} callback with the following parameters instead: - * - [`Stopped`]{@link VideoRemoteState.Stopped} and [`RemoteMuted`]{@link VideoRemoteStateReason.RemoteMuted}. - * - [`Decoding`]{@link VideoRemoteState.Decoding} and [`RemoteUnmuted`]{@link VideoRemoteStateReason.RemoteUnmuted}. - * - * The SDK triggers this callback when the remote user stops or resumes sending the audio stream by calling the [`muteLocalAudioStream`]{@link RtcEngine.muteLocalAudioStream} method. - * - * **Note** - * - * This callback is invalid when the number of users or hosts in the channel exceeds 17. - * - * @event UserMuteAudio - */ - UserMuteAudio: UidWithMutedCallback - - /** - * Reports the result of calling [`addPublishStreamUrl`]{@link RtcEngine.addPublishStreamUrl}. - * - * @deprecated - * - * Use [`RtmpStreamingStateChanged`]{@link RtmpStreamingStateChanged} instead. - * - * This callback indicates whether you have successfully added an RTMP stream to the CDN. - * - * @event StreamPublished - */ - StreamPublished: UrlWithErrorCallback - - /** - * Reports the result of calling [`removePublishStreamUrl`]{@link RtcEngine.removePublishStreamUrl}. - * - * @deprecated - * - * Use [`RtmpStreamingStateChanged`]{@link RtmpStreamingStateChanged} instead. - * - * This callback indicates whether you have successfully removed an RTMP stream from the CDN. - * - * @event StreamUnpublished - */ - StreamUnpublished: UrlCallback - - /** - * Reports the transport-layer statistics of each remote audio stream. - * - * @deprecated - * - * This callback is deprecated. Use [`RemoteAudioStats`]{@link RemoteAudioStats} instead. - * - * This callback reports the transport-layer statistics, such as the packet loss rate and time delay, - * once every two seconds after the local user receives an audio packet from a remote user. - * - * @event RemoteAudioTransportStats - */ - RemoteAudioTransportStats: TransportStatsCallback - - /** - * Reports the transport-layer statistics of each remote video stream. - * - * @deprecated - * - * This callback is deprecated. Use [`RemoteVideoStats`]{@link RemoteVideoStats} instead. - * - * This callback reports the transport-layer statistics, such as the packet loss rate and time delay, - * once every two seconds after the local user receives the video packet from a remote user. - * - * @event RemoteVideoTransportStats - */ - RemoteVideoTransportStats: TransportStatsCallback - - /** - * Occurs when a remote user enables/disables the video module. - * - * @deprecated - * This callback is deprecated and replaced by the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback with the following parameters: - * - [`Stopped`]{@link VideoRemoteState.Stopped} and [`RemoteMuted`]{@link VideoRemoteStateReason.RemoteMuted}. - * - [`Decoding`]{@link VideoRemoteState.Decoding} and [`RemoteUnmuted`]{@link VideoRemoteStateReason.RemoteUnmuted}. - * - * Once the video module is disabled, the remote user can only use a voice call. The remote user cannot send or receive any video from other users. - * - * The SDK triggers this callback when the remote user enables or disables the video module by calling the [`enableVideo`]{@link RtcEngine.enableVideo} or [`disableVideo`]{@link RtcEngine.disableVideo} method. - * - * **Note** - * - * This callback is invalid when the number of users or hosts in the channel exceeds 17. - * - * @event UserEnableVideo - */ - UserEnableVideo: UidWithEnabledCallback - - /** - * Occurs when a remote user enables/disables the local video capture function. - * - * @deprecated - * - * This callback is deprecated and replaced by the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback with the following parameters: - * - [`Stopped`]{@link VideoRemoteState.Stopped} and [`RemoteMuted`]{@link VideoRemoteStateReason.RemoteMuted}. - * - [`Decoding`]{@link VideoRemoteState.Decoding} and [`RemoteUnmuted`]{@link VideoRemoteStateReason.RemoteUnmuted}. - * - * The SDK triggers this callback when the remote user resumes or stops capturing the video stream by - * calling [`enableLocalVideo`]{@link RtcEngine.enableLocalVideo}. - * - * This callback is only applicable to the scenario when the remote user only wants to watch the remote video without sending any video stream to the other user. - * - * @event UserEnableLocalVideo - */ - UserEnableLocalVideo: UidWithEnabledCallback - - /** - * Occurs when the first remote video frame is received and decoded. - * - * @deprecated - * - * This callback is deprecated. Use [`Starting`]{@link VideoRemoteState.Starting} or [`Decoding`]{@link VideoRemoteState.Decoding} in the [`RemoteVideoStateChanged`]{@link RemoteVideoStateChanged} callback instead. - * - * This callback is triggered in either of the following scenarios: - * - The remote user joins the channel and sends the video stream. - * - The remote user stops sending the video stream and re-sends it after 15 seconds. Possible reasons include: - * - The remote user leaves channel. - * - The remote user drops offline. - * - The remote user calls [`muteLocalVideoStream`]{@link RtcEngine.muteLocalVideoStream}. - * - The remote user calls [`disableVideo`]{@link RtcEngine.disableVideo}. - * - * @event FirstRemoteVideoDecoded - */ - FirstRemoteVideoDecoded: VideoFrameWithUidCallback - - /** - * Occurs when the microphone is enabled/disabled. - * - * @deprecated - * - * This callback is deprecated. Use [`Stopped`]{@link AudioLocalState.Stopped} or [`Recording`]{@link AudioLocalState.Recording} in the [`LocalAudioStateChanged`]{@link LocalAudioStateChanged} callback instead. - * - * The SDK triggers this callback when the local user resumes or stops capturing the local audio stream by calling [`enableLocalAudio`]{@link RtcEngine.enableLocalAudio}. - * - * @event MicrophoneEnabled - */ - MicrophoneEnabled: EnabledCallback - - /** - * Occurs when the connection between the SDK and the server is interrupted. - * - * @deprecated - * - * Use {@link ConnectionStateChanged} instead. - * - * The SDK triggers this callback when it loses connection to the server for more than four seconds after - * the connection is established. After triggering this callback, the SDK tries to reconnect to the server. - * You can use this callback to implement pop-up reminders. This callback is different from [`ConnectionLost`]{@link ConnectionLost}: - * - The SDK triggers the [`ConnectionInterrupted`]{@link ConnectionInterrupted} callback when the SDK loses - * connection with the server for more than four seconds after it joins the channel. - * - The SDK triggers the [`ConnectionLost`]{@link ConnectionLost} callback when it loses connection with - * the server for more than 10 seconds, regardless of whether it joins the channel or not. - * - * If the SDK fails to rejoin the channel 20 minutes after being disconnected from Agora's edge server, the SDK stops rejoining the channel. - * - * @event ConnectionInterrupted - */ - ConnectionInterrupted: EmptyCallback - - /** - * Occurs when your connection is banned by the Agora Server. - * - * @deprecated - * - * Use [`ConnectionStateChanged`]{@link ConnectionStateChanged} instead. - * - * @event ConnectionBanned - */ - ConnectionBanned: EmptyCallback - - /** - * Reports the statistics of the audio stream from each remote user/host. - * - * @deprecated - * - * Use [`RemoteAudioStats`]{@link RemoteAudioStats} instead. - * - * The SDK triggers this callback once every two seconds to report the audio quality of each remote user/host sending an audio stream. If a channel has multiple remote users/hosts sending audio streams, the SDK trggers this callback as many times. - * - * @event AudioQuality - */ - AudioQuality: AudioQualityCallback - - /** - * Occurs when the camera is turned on and ready to capture video. - * - * @deprecated - * - * Use [`Capturing`]{@link LocalVideoStreamState.Capturing} in the [`LocalVideoStateChanged`]{@link LocalVideoStateChanged} callback instead. - * If the camera fails to turn on, fix the error reported in the [`Error`]{@link Error} callback. - * - * @event CameraReady - */ - CameraReady: EmptyCallback - - /** - * Occurs when the video stops playing. - * - * @deprecated - * - * Use [`Stopped`]{@link LocalVideoStreamState.Stopped} in the [`LocalVideoStateChanged`]{@link LocalVideoStateChanged} callback instead. - * The application can use this callback to change the configuration of the view (for example, displaying other pictures in the view) - * after the video stops playing. - * - * @event VideoStopped - */ - VideoStopped: EmptyCallback - - /** - * Occurs when the local user receives the metadata. - * - * @event MetadataReceived - */ - MetadataReceived: MetadataCallback - - /** - * Occurs when the first audio frame is published. - * - * @since v3.1.2. - * - * The SDK triggers this callback under one of the following circumstances: - * - The local client enables the audio module and calls [`joinChannel`]{@link joinChannel} successfully. - * - The local client calls [`muteLocalAudioStream(true)`]{@link RtcEngine.muteLocalAudioStream} and [`muteLocalAudioStream(false)`]{@link RtcEngine.muteLocalAudioStream} in sequence. - * - The local client calls [`disableAudio`]{@link RtcEngine.disableAudio} and [`enableAudio`]{@link RtcEngine.enableAudio} in sequence. - */ - FirstLocalAudioFramePublished: ElapsedCallback - - /** - * Occurs when the first video frame is published. - * - * @since v3.1.2. - * - * The SDK triggers this callback under one of the following circumstances: - * - The local client enables the video module and calls [`joinChannel`]{@link joinChannel} successfully. - * - The local client calls [`muteLocalVideoStream(true)`]{@link RtcEngine.muteLocalVideoStream} and [`muteLocalVideoStream(false)`]{@link RtcEngine.muteLocalVideoStream} in sequence. - * - The local client calls [`disableVideo`]{@link RtcEngine.disableVideo} and [`enableVideo`]{@link RtcEngine.enableVideo} in sequence. - */ - FirstLocalVideoFramePublished: ElapsedCallback - - /** - * Occurs when the audio publishing state changes. - * - * @since v3.1.2. - * - * This callback indicates the publishing state change of the local audio stream. - */ - AudioPublishStateChanged: StreamPublishStateCallback - - /** - * Occurs when the video publishing state changes. - * - * @since v3.1.2. - * - * This callback indicates the publishing state change of the local video stream. - */ - VideoPublishStateChanged: StreamPublishStateCallback - - /** - * Occurs when the audio subscribing state changes. - * - * @since v3.1.2. - * - * This callback indicates the subscribing state change of a remote audio stream. - */ - AudioSubscribeStateChanged: StreamSubscribeStateCallback - - /** - * Occurs when the video subscribing state changes. - * - * @since v3.1.2. - * - * This callback indicates the subscribing state change of a remote video stream. - */ - VideoSubscribeStateChanged: StreamSubscribeStateCallback - - /** - * Reports events during the RTMP streaming. - * - * @since v3.1.2. - */ - RtmpStreamingEvent: RtmpStreamingEventCallback -} - -/** - * The [`RtcChannelEvents`]{@link RtcChannelEvents} interface. - */ -export interface RtcChannelEvents { - /** - * Reports the warning code of the [`RtcChannel`]{@link RtcChannel} instance. - * - * @event Warning - */ - Warning: WarningCallback - - /** - * Reports the error code of the [`RtcChannel`]{@link RtcChannel} instance. - * - * @event Error - */ - Error: ErrorCallback - - /** - * Occurs when the local user joins a specified channel. - * - * If the uid is not specified when calling [`joinChannel`]{@link RtcChannel.joinChannel}, the - * server automatically assigns a uid. - * - * @event JoinChannelSuccess - */ - JoinChannelSuccess: UidWithElapsedCallback - - /** - * Occurs when a user rejoins the channel after being disconnected due to network problems. - * - * When a user loses connection with the server because of network problems, the SDK automatically tries - * to reconnect and triggers this callback upon reconnection. - * - * @event RejoinChannelSuccess - */ - RejoinChannelSuccess: UidWithElapsedCallback - - /** - * Occurs when a user leaves the channel. - * - * When a user leaves the channel by using the [`leaveChannel`]{@link RtcChannel.leaveChannel} method, the SDK uses this callback to notify the app when the user leaves the channel. - * - * With this callback, the app retrieves the channel information, such as the call duration and statistics. - * - * @event LeaveChannel - */ - LeaveChannel: RtcStatsCallback - - /** - * Occurs when the user role switches in a live interactive streaming channel. For example, from a host to an audience member or vice versa. - * - * The SDK triggers this callback when the local user switches the user role by calling the [`setClientRole`]{@link RtcChannel.setClientRole} method after joining the channel. - * - * @event ClientRoleChanged - */ - ClientRoleChanged: ClientRoleCallback - - /** - * Occurs when a remote user (`Communication`) or a host (`LiveBroadcasting`) joins the channel. - * - `Communication` profile: This callback notifies the app when another user joins the channel. If other users are already in the channel, the SDK also reports to the app on the existing users. - * - `LiveBroadcasting` profile: This callback notifies the app when the host joins the channel. If other hosts are already in the channel, the SDK also reports to the app on the existing hosts. We recommend having at most 17 hosts in a channel. - * - * The SDK triggers this callback under one of the following circumstances: - * - A remote user/host joins the channel by calling [`joinChannel`]{@link RtcChannel.joinChannel}. - * - A remote user switches the user role to the host by calling [`setClientRole`]{@link RtcChannel.setClientRole} after joining the channel. - * - A remote user/host rejoins the channel after a network interruption. - * - The host injects an online media stream into the channel by calling [`addInjectStreamUrl`]{@link RtcChannel.addInjectStreamUrl}. - * - * **Note** - * - In the `LiveBroadcasting` profile: - * - The host receives this callback when another host joins the channel. - * - The audience in the channel receives this callback when a new host joins the channel. - * - When a web app joins the channel, this callback is triggered as long as the web app publishes streams. - * - * @event UserJoined - */ - UserJoined: UidWithElapsedCallback - - /** - * Occurs when a remote user (`Communication`) or a host (`LiveBroadcasting`) leaves the channel. - * - * There are two reasons for users to become offline: - * - Leave the channel: When the user/host leaves the channel, the user/host sends a goodbye message. When this message is received, the SDK determines that the user/host leaves the channel. - * - Go offline: When no data packet of the user or host is received for a certain period of time (around 20 seconds), the SDK assumes that the user/host drops offline. A poor network connection may lead to false detections, so we recommend using the Agora RTM SDK for reliable offline detection. - * - * @event UserOffline - */ - UserOffline: UserOfflineCallback - - /** - * Occurs when the network connection state changes. - * - * The Agora SDK triggers this callback to report on the current network connection state when it changes, - * and the reason to such change. - * - * @event ConnectionStateChanged - */ - ConnectionStateChanged: ConnectionStateCallback - - /** - * Occurs when the SDK cannot reconnect to Agora's edge server 10 seconds after its connection to the server is interrupted. - * - * The SDK also triggers this callback when it cannot connect to the server 10 seconds after calling [`joinChannel`]{@link RtcChannel.joinChannel}, regardless of whether it is in the channel or not. - * - * If the SDK fails to rejoin the channel 20 minutes after being disconnected from Agora's edge server, the SDK stops rejoining the channel. - * - * @event ConnectionLost - */ - ConnectionLost: EmptyCallback - - /** - * Occurs when the token expires in 30 seconds. - * - * The user becomes offline if the token used when joining the channel expires. This callback is - * triggered 30 seconds before the token expires, to remind the app to get a new token. Upon receiving this callback, - * you need to generate a new token on the server and call [`renewToken`]{@link RtcChannel.renewToken} to pass the new token to the SDK. - * - * @event TokenPrivilegeWillExpire - */ - TokenPrivilegeWillExpire: TokenCallback - - /** - * Occurs when the token has expired. - * - * After a token is specified when joining the channel, the token expires after a certain period of time, - * and a new token is required to reconnect to the server. - * This callback notifies the app to generate a new token and call [`renewToken`]{@link RtcChannel.renewToken} to renew the token. - * - * @event RequestToken - */ - RequestToken: EmptyCallback - - /** - * Reports which user is the loudest speaker. - * - * This callback reports the speaker with the highest accumulative volume during a certain period. If the user enables the audio volume indication by calling [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication}, this callback returns the uid of the active speaker whose voice is detected by the audio volume detection module of the SDK. - * - * **Note** - * - To receive this callback, you need to call [`enableAudioVolumeIndication`]{@link RtcEngine.enableAudioVolumeIndication}. - * - This callback reports the ID of the user with the highest voice volume during a period of time, instead of at the moment. - * - * @event ActiveSpeaker - */ - ActiveSpeaker: UidCallback - - /** - * Occurs when the video size or rotation information of a remote user changes. - * - * @event VideoSizeChanged - */ - VideoSizeChanged: VideoSizeCallback - - /** - * Occurs when the remote video state changes. - * - * @event RemoteVideoStateChanged - */ - RemoteVideoStateChanged: RemoteVideoStateCallback - - /** - * Occurs when the remote audio state changes. - * - * This callback indicates the state change of the remote audio stream. - * - * @event RemoteAudioStateChanged - */ - RemoteAudioStateChanged: RemoteAudioStateCallback - - /** - * Occurs when the published media stream falls back to an audio-only stream due to poor network conditions or switches back to video stream after the network conditions improve. - * - * If you call [`setLocalPublishFallbackOption`]{@link RtcEngine.setLocalPublishFallbackOption} and set `option` as [`AudioOnly`]{@link StreamFallbackOptions.AudioOnly}, this callback is triggered when the locally published stream falls back to audio-only mode due to poor uplink conditions, or when the audio stream switches back to the video after the uplink network condition improves. - * - * @event LocalPublishFallbackToAudioOnly - */ - LocalPublishFallbackToAudioOnly: FallbackCallback - - /** - * Occurs when the remote media stream falls back to audio-only stream due to poor network conditions or switches back to video stream after the network conditions improve. - * - * If you call [`setRemoteSubscribeFallbackOption`]{@link RtcEngine.setRemoteSubscribeFallbackOption} and set option as [`AudioOnly`]{@link StreamFallbackOptions.AudioOnly}, this callback is triggered when the remote media stream falls back to audio-only mode due to poor uplink conditions, or when the remote media stream switches back to the video after the uplink network condition improves. - * - * **Note** - * - * Once the remote media stream is switched to the low stream due to poor network conditions, - * you can monitor the stream switch between a high and low stream in the [`RemoteVideoStats`]{@link RemoteVideoStats} callback. - * - * @event RemoteSubscribeFallbackToAudioOnly - */ - RemoteSubscribeFallbackToAudioOnly: FallbackWithUidCallback - - /** - * Reports the statistics of the [`RtcEngine`]{@link RtcEngine} once every two seconds. - * - * @event RtcStats - */ - RtcStats: RtcStatsCallback - - /** - * Reports the last mile network quality of each user in the channel once every two seconds. - * - * Last mile refers to the connection between the local device and Agora's edge server. This callback reports once every two seconds the last mile network conditions of each user in the channel. If a channel includes multiple users, then this callback will be triggered as many times. - * - * @event NetworkQuality - */ - NetworkQuality: NetworkQualityWithUidCallback - - /** - * Reports the statistics of the video stream from each remote user/host. The SDK triggers this callback once every two seconds for each remote user/broadcaster. If a channel includes multiple remote users, the SDK triggers this callback as many times. - * - * @event RemoteVideoStats - */ - RemoteVideoStats: RemoteVideoStatsCallback - - /** - * Reports the statistics of the audio stream from each remote user/host. - * - * The SDK triggers this callback once every two seconds for each remote user/host. If a channel includes multiple remote users, the SDK triggers this callback as many times. - * - * Schemes such as FEC (Forward Error Correction) or retransmission counter the frame loss rate. Hence, users may find the overall audio quality acceptable even when the packet loss rate is high. - * - * @event RemoteAudioStats - */ - RemoteAudioStats: RemoteAudioStatsCallback - - /** - * Occurs when the state of the RTMP 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. - * - * @event RtmpStreamingStateChanged - */ - RtmpStreamingStateChanged: RtmpStreamingStateCallback - - /** - * Occurs when the publisher's transcoding settings are updated. - * - * When the `LiveTranscoding` class in the [`setLiveTranscoding`]{@link RtcChannel.setLiveTranscoding} method updates, the SDK triggers this callback to report the update information. - * - * **Note** - * - * If you call [`setLiveTranscoding`]{@link RtcChannel.setLiveTranscoding} to set the `LiveTranscoding` class for the first time, the SDK does not trigger this callback. - * - * @event TranscodingUpdated - */ - TranscodingUpdated: EmptyCallback - - /** - * Reports the status of injecting the online media stream. - * - * @event StreamInjectedStatus - */ - StreamInjectedStatus: StreamInjectedStatusCallback - - /** - * Occurs when the local user receives a remote data stream. - * - * The SDK triggers this callback when the local user receives the stream message that the remote user sends by calling the [`sendStreamMessage`]{@link RtcChannel.sendStreamMessage} method. - * - * @event StreamMessage - */ - StreamMessage: StreamMessageCallback - - /** - * Occurs when the local user fails to receive a remote data stream. - * - * The SDK triggers this callback when the local user fails to receive the stream message that the remote user sends by calling the [`sendStreamMessage`]{@link RtcChannel.sendStreamMessage} method. - * - * @event StreamMessageError - */ - StreamMessageError: StreamMessageErrorCallback - - /** - * Occurs when the state of the media stream relay changes. - * - * The SDK reports the state of the current media relay and possible error messages in this callback. - * - * @event ChannelMediaRelayStateChanged - */ - ChannelMediaRelayStateChanged: MediaRelayStateCallback - - /** - * Reports events during the media stream relay. - * - * @event ChannelMediaRelayEvent - */ - ChannelMediaRelayEvent: MediaRelayEventCallback - - /** - * Occurs when the local user receives the metadata. - * - * @event MetadataReceived - */ - MetadataReceived: MetadataCallback - - /** - * Occurs when the audio publishing state changes. - * - * @since v3.1.2. - * - * This callback indicates the publishing state change of the local audio stream. - */ - AudioPublishStateChanged: StreamPublishStateCallback - - /** - * Occurs when the video publishing state changes. - * - * @since v3.1.2. - * - * This callback indicates the publishing state change of the local video stream. - */ - VideoPublishStateChanged: StreamPublishStateCallback - - /** - * Occurs when the audio subscribing state changes. - * - * @since v3.1.2. - * - * This callback indicates the subscribing state change of a remote audio stream. - */ - AudioSubscribeStateChanged: StreamSubscribeStateCallback - - /** - * Occurs when the video subscribing state changes. - * - * @since v3.1.2. - * - * This callback indicates the subscribing state change of a remote video stream. - */ - VideoSubscribeStateChanged: StreamSubscribeStateCallback - - /** - * Reports events during the RTMP streaming. - * - * @since v3.1.2. - */ - RtmpStreamingEvent: RtmpStreamingEventCallback -} diff --git a/src/src/RtcRenderView.native.tsx b/src/src/RtcRenderView.native.tsx deleted file mode 100644 index 5595aaef8..000000000 --- a/src/src/RtcRenderView.native.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import React, {Component} from "react" -import {requireNativeComponent, ViewProps} from "react-native" - -import {VideoMirrorMode, VideoRenderMode} from "./Enums" - -/** - * Properties of the uid. - */ -export interface RtcUidProps { - /** User ID. */ - uid: number -} - -/** - * Properties of the SurfaceView. - */ -export interface RtcSurfaceViewProps { - /** - * Controls whether the SurfaceView's surface is placed on top of another - * regular surface view in the window (but still behind the window itself). - */ - zOrderMediaOverlay?: boolean - /** - * Controls whether the SurfaceView's surface is placed on top of its window. - */ - zOrderOnTop?: boolean - /** - * The rendering mode of the video view. - */ - renderMode?: VideoRenderMode - /** - * The unique channel name for the AgoraRTC session in the string format. - * The string length must be less than 64 bytes. Supported character scopes are: - * - All lowercase English letters: a to z. - * - All uppercase English letters: A to Z. - * - All numeric characters: 0 to 9. - * - The space character. - * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". - * - * **Note** - * - The default value is the empty string "". Use the default value if the user joins the channel using the [`joinChannel`]{@link RtcEngine.joinChannel} method in the `RtcEngine` class. - * - If the user joins the channel using the [`joinChannel`]{@link RtcChannel.joinChannel} method in the `RtcChannel` class, set this parameter as the `channelId` of the `RtcChannel` object. - */ - channelId?: string - /** The video mirror mode. */ - mirrorMode?: VideoMirrorMode -} - -/** - * Properties of the TextureView. - */ -export interface RtcTextureViewProps { - /** - * The rendering mode of the video view. - */ - renderMode?: VideoRenderMode - /** - * The unique channel name for the AgoraRTC session in the string format. - * The string length must be less than 64 bytes. Supported character scopes are: - * - All lowercase English letters: a to z. - * - All uppercase English letters: A to Z. - * - All numeric characters: 0 to 9. - * - The space character. - * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". - * - * **Note** - * - The default value is the empty string "". Use the default value if the user joins the channel using the [`joinChannel`]{@link RtcEngine.joinChannel} method in the `RtcEngine` class. - * - If the user joins the channel using the [`joinChannel`]{@link RtcChannel.joinChannel} method in the `RtcChannel` class, set this parameter as the `channelId` of the `RtcChannel` object. - */ - channelId?: string - /** The video mirror mode. */ - mirrorMode?: VideoMirrorMode -} - -/** - * @ignore - */ -const RCTRtcSurfaceView = requireNativeComponent('RCTAgoraRtcSurfaceView') - -/** - * @ignore - */ -export class RtcSurfaceView extends Component { - render() { - const {channelId = null, uid, ...others} = this.props - return ( - - ) - } -} - -/** - * @ignore - */ -const RCTRtcTextureView = requireNativeComponent('RCTAgoraRtcTextureView') - -/** - * @ignore - */ -export class RtcTextureView extends Component { - render() { - const {channelId = null, uid, ...others} = this.props - return ( - - ) - } -} diff --git a/tsconfig.json b/tsconfig.json index 55c84cd99..033ce5604 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,65 +1,27 @@ - - { +{ "compilerOptions": { - /* Basic Options */ - "target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ - "module": "esnext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - "lib": ["es6"], /* Specify library files to be included in the compilation. */ - "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - "declaration": true, /* Generates corresponding '.d.ts' file. */ - "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./lib", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - "incremental": true, /* Enable incremental compilation */ - "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - - /* Module Resolution Options */ - "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - - /* Source Map Options */ - // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - }, - "exclude": [ - "node_modules", "babel.config.js", "metro.config.js", "jest.config.js" - ], - "include": [ - "./src" - ] + "baseUrl": ".", + "paths": { + "react-native-agora": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "esModuleInterop": true, + "importsNotUsedAsValues": "error", + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "lib": ["esnext"], + "module": "esnext", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "esnext" + } } From 61110ab173b207306daf21f326667a8eb3f97f04 Mon Sep 17 00:00:00 2001 From: HUI Date: Wed, 21 Oct 2020 20:03:27 +0800 Subject: [PATCH 03/18] docs: add @event --- .gitignore | 4 ++++ .npmignore | 5 +---- src/common/RtcChannel.native.ts | 12 ++++++------ src/common/RtcEngine.native.ts | 20 +++++++++++++------- src/common/RtcEvents.ts | 24 ++++++++++++++++++++++++ typedoc.json | 7 +++++-- 6 files changed, 53 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index e46043a99..c4fdeaf0a 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ node_modules/ npm-debug.log yarn-debug.log yarn-error.log +package-lock.json yarn.lock # BUCK @@ -54,6 +55,9 @@ buck-out/ \.buckd/ android/app/libs android/keystores/debug.keystore +docs/api/ +gitpull.sh +gitpush.sh # Expo .expo/* diff --git a/.npmignore b/.npmignore index c9138b08c..d880c2da3 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,3 @@ -.idea/ docs/ -lib/**/*.map -lib/**/*.tsbuildinfo -samples/ +example/ src/ diff --git a/src/common/RtcChannel.native.ts b/src/common/RtcChannel.native.ts index c2911f4a0..1bce084b3 100644 --- a/src/common/RtcChannel.native.ts +++ b/src/common/RtcChannel.native.ts @@ -220,8 +220,8 @@ export default class RtcChannel implements RtcChannelInterface { * @param options The channel media options. */ joinChannel( - token: string | null, - optionalInfo: string | null, + token: string | undefined | null, + optionalInfo: string | undefined | null, optionalUid: number, options: ChannelMediaOptions ): Promise { @@ -254,7 +254,7 @@ export default class RtcChannel implements RtcChannelInterface { * @param options The channel media options. */ joinChannelWithUserAccount( - token: string | null, + token: string | undefined | null, userAccount: string, options: ChannelMediaOptions ): Promise { @@ -830,14 +830,14 @@ interface RtcChannelInterface setClientRole(role: ClientRole): Promise; joinChannel( - token: string | null, - optionalInfo: string | null, + token: string | undefined | null, + optionalInfo: string | undefined | null, optionalUid: number, options: ChannelMediaOptions ): Promise; joinChannelWithUserAccount( - token: string | null, + token: string | undefined | null, userAccount: string, options: ChannelMediaOptions ): Promise; diff --git a/src/common/RtcEngine.native.ts b/src/common/RtcEngine.native.ts index 3319d09f8..1c0309931 100644 --- a/src/common/RtcEngine.native.ts +++ b/src/common/RtcEngine.native.ts @@ -304,9 +304,9 @@ export default class RtcEngine implements RtcEngineInterface { * If necessary, the uid can be converted to a 64-bit integer through “uid&0xffffffffL”. */ joinChannel( - token: string | null, + token: string | undefined | null, channelName: string, - optionalInfo: string | null, + optionalInfo: string | undefined | null, optionalUid: number ): Promise { return RtcEngine._callMethod('joinChannel', { @@ -339,7 +339,10 @@ export default class RtcEngine implements RtcEngineInterface { * - The space character. * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". */ - switchChannel(token: string | null, channelName: string): Promise { + switchChannel( + token: string | undefined | null, + channelName: string + ): Promise { return RtcEngine._callMethod('switchChannel', { token, channelName }); } @@ -549,7 +552,7 @@ export default class RtcEngine implements RtcEngineInterface { * - Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",". */ joinChannelWithUserAccount( - token: string | null, + token: string | undefined | null, channelName: string, userAccount: string ): Promise { @@ -2517,13 +2520,16 @@ interface RtcEngineInterface setClientRole(role: ClientRole): Promise; joinChannel( - token: string | null, + token: string | undefined | null, channelName: string, - optionalInfo: string | null, + optionalInfo: string | undefined | null, optionalUid: number ): Promise; - switchChannel(token: string | null, channelName: string): Promise; + switchChannel( + token: string | undefined | null, + channelName: string + ): Promise; leaveChannel(): Promise; diff --git a/src/common/RtcEvents.ts b/src/common/RtcEvents.ts index 79757b926..60ead95d2 100644 --- a/src/common/RtcEvents.ts +++ b/src/common/RtcEvents.ts @@ -1310,6 +1310,8 @@ export interface RtcEngineEvents { * - The local client enables the audio module and calls [`joinChannel`]{@link joinChannel} successfully. * - The local client calls [`muteLocalAudioStream(true)`]{@link RtcEngine.muteLocalAudioStream} and [`muteLocalAudioStream(false)`]{@link RtcEngine.muteLocalAudioStream} in sequence. * - The local client calls [`disableAudio`]{@link RtcEngine.disableAudio} and [`enableAudio`]{@link RtcEngine.enableAudio} in sequence. + * + * @event FirstLocalAudioFramePublished */ FirstLocalAudioFramePublished: ElapsedCallback; @@ -1322,6 +1324,8 @@ export interface RtcEngineEvents { * - The local client enables the video module and calls [`joinChannel`]{@link joinChannel} successfully. * - The local client calls [`muteLocalVideoStream(true)`]{@link RtcEngine.muteLocalVideoStream} and [`muteLocalVideoStream(false)`]{@link RtcEngine.muteLocalVideoStream} in sequence. * - The local client calls [`disableVideo`]{@link RtcEngine.disableVideo} and [`enableVideo`]{@link RtcEngine.enableVideo} in sequence. + * + * @event FirstLocalVideoFramePublished */ FirstLocalVideoFramePublished: ElapsedCallback; @@ -1331,6 +1335,8 @@ export interface RtcEngineEvents { * @since v3.1.2. * * This callback indicates the publishing state change of the local audio stream. + * + * @event AudioPublishStateChanged */ AudioPublishStateChanged: StreamPublishStateCallback; @@ -1340,6 +1346,8 @@ export interface RtcEngineEvents { * @since v3.1.2. * * This callback indicates the publishing state change of the local video stream. + * + * @event VideoPublishStateChanged */ VideoPublishStateChanged: StreamPublishStateCallback; @@ -1349,6 +1357,8 @@ export interface RtcEngineEvents { * @since v3.1.2. * * This callback indicates the subscribing state change of a remote audio stream. + * + * @event AudioSubscribeStateChanged */ AudioSubscribeStateChanged: StreamSubscribeStateCallback; @@ -1358,6 +1368,8 @@ export interface RtcEngineEvents { * @since v3.1.2. * * This callback indicates the subscribing state change of a remote video stream. + * + * @event VideoSubscribeStateChanged */ VideoSubscribeStateChanged: StreamSubscribeStateCallback; @@ -1365,6 +1377,8 @@ export interface RtcEngineEvents { * Reports events during the RTMP streaming. * * @since v3.1.2. + * + * @event RtmpStreamingEvent */ RtmpStreamingEvent: RtmpStreamingEventCallback; } @@ -1673,6 +1687,8 @@ export interface RtcChannelEvents { * @since v3.1.2. * * This callback indicates the publishing state change of the local audio stream. + * + * @event AudioPublishStateChanged */ AudioPublishStateChanged: StreamPublishStateCallback; @@ -1682,6 +1698,8 @@ export interface RtcChannelEvents { * @since v3.1.2. * * This callback indicates the publishing state change of the local video stream. + * + * @event VideoPublishStateChanged */ VideoPublishStateChanged: StreamPublishStateCallback; @@ -1691,6 +1709,8 @@ export interface RtcChannelEvents { * @since v3.1.2. * * This callback indicates the subscribing state change of a remote audio stream. + * + * @event AudioSubscribeStateChanged */ AudioSubscribeStateChanged: StreamSubscribeStateCallback; @@ -1700,6 +1720,8 @@ export interface RtcChannelEvents { * @since v3.1.2. * * This callback indicates the subscribing state change of a remote video stream. + * + * @event VideoSubscribeStateChanged */ VideoSubscribeStateChanged: StreamSubscribeStateCallback; @@ -1707,6 +1729,8 @@ export interface RtcChannelEvents { * Reports events during the RTMP streaming. * * @since v3.1.2. + * + * @event RtmpStreamingEvent */ RtmpStreamingEvent: RtmpStreamingEventCallback; } diff --git a/typedoc.json b/typedoc.json index a62ef0078..b0ef83ab3 100644 --- a/typedoc.json +++ b/typedoc.json @@ -1,4 +1,7 @@ { - "mode": "file", - "out": "docs/api" + "inputFiles": ["./lib/typescript/src"], + "mode": "file", + "out": "docs/api", + "includeDeclarations": true, + "excludeExternals": true } From eeb2e24554269c44c0b61ceaa1605007612dce67 Mon Sep 17 00:00:00 2001 From: HUI Date: Wed, 21 Oct 2020 20:17:29 +0800 Subject: [PATCH 04/18] upgrade version --- CHANGELOG.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6226cb94e..c66eb1663 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## THE CHANGELOG +#### 3.1.4.rc-1 + - migrating to @react-native-community/bob + #### 3.1.3 - fix iOS `deinit` `[weak self]` crash - make `RtcChannel.channelId` public diff --git a/package.json b/package.json index 39438fe78..6a978b878 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-agora", - "version": "3.1.3", + "version": "3.1.4-rc.1", "description": "Agora RTC SDK For React Native", "main": "lib/commonjs/index", "module": "lib/module/index", From 25ffbbe02916161fb86d4a3bab93a08c5576fc70 Mon Sep 17 00:00:00 2001 From: HUI Date: Wed, 21 Oct 2020 20:45:02 +0800 Subject: [PATCH 05/18] revert version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6a978b878..39438fe78 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-agora", - "version": "3.1.4-rc.1", + "version": "3.1.3", "description": "Agora RTC SDK For React Native", "main": "lib/commonjs/index", "module": "lib/module/index", From ff7ad0dcc40c30d6f9e4d0d4e2f60e135e163e19 Mon Sep 17 00:00:00 2001 From: HUI Date: Wed, 21 Oct 2020 21:03:49 +0800 Subject: [PATCH 06/18] add infile --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 39438fe78..67ae7d54f 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,8 @@ }, "plugins": { "@release-it/conventional-changelog": { - "preset": "angular" + "preset": "angular", + "infile": "CHANGELOG.md" } } }, From b2bf0ac2dbca8263ff6f432ea8ec573c0085688b Mon Sep 17 00:00:00 2001 From: HUI Date: Wed, 21 Oct 2020 22:46:45 +0800 Subject: [PATCH 07/18] style: optimize CHANGELOG.md --- CHANGELOG.md | 5 ----- package.json | 17 +++++++++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c66eb1663..acf0b7b45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,3 @@ -## THE CHANGELOG - -#### 3.1.4.rc-1 - - migrating to @react-native-community/bob - #### 3.1.3 - fix iOS `deinit` `[weak self]` crash - make `RtcChannel.channelId` public diff --git a/package.json b/package.json index 67ae7d54f..e5055dc8a 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "@types/react": "^16.9.19", "@types/react-native": "0.62.13", "commitlint": "^8.3.5", + "cz-conventional-changelog": "^3.3.0", "eslint": "^7.2.0", "eslint-config-prettier": "^6.11.0", "eslint-plugin-prettier": "^3.1.3", @@ -123,7 +124,10 @@ ] } }, - "eslintIgnore": ["node_modules/", "lib/"], + "eslintIgnore": [ + "node_modules/", + "lib/" + ], "prettier": { "quoteProps": "consistent", "singleQuote": true, @@ -134,6 +138,15 @@ "@react-native-community/bob": { "source": "src", "output": "lib", - "targets": ["commonjs", "module", "typescript"] + "targets": [ + "commonjs", + "module", + "typescript" + ] + }, + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } } } From ba6fbca9113a5b9c4982b201b0add992759673c4 Mon Sep 17 00:00:00 2001 From: HUI Date: Wed, 21 Oct 2020 22:53:03 +0800 Subject: [PATCH 08/18] style: optimize CHANGELOG.md --- CHANGELOG.md | 90 ++++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acf0b7b45..63985ac02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,118 +1,118 @@ -#### 3.1.3 +## 3.1.3 - fix iOS `deinit` `[weak self]` crash - make `RtcChannel.channelId` public - add `setAudioSessionOperationRestriction` and `sendCustomReportMessage` method -#### 3.1.2-rc.2 +## 3.1.2-rc.2 - fix iOS `deinit` `[weak self]` crash - fix `engine()` build error -#### 3.1.2-rc.1 +## 3.1.2-rc.1 - make `RtcChannel.channelId` public -#### 3.1.2 +## 3.1.2 - support 3.1.2 native sdk - fix `RejoinChannelSuccess` bug -#### 3.0.1 +## 3.0.1 - release version -#### 3.0.1-rc.5 +## 3.0.1-rc.5 - fix `Xcode10` `Swift4` compile error -#### 3.0.1-rc.4 +## 3.0.1-rc.4 - fix crash when rendering view without `channelId` property - fix `RtcLocalView` freezes after rendering remote view -#### 3.0.1-rc.3 +## 3.0.1-rc.3 - fix multiple channel render bug - remove `Types` from export, you can import enum or class by `import {} from 'react-native-agora'` - optimize ts code and doc -#### 3.0.1-rc.2 +## 3.0.1-rc.2 - add `startPreview` `stopPreview` -#### 3.0.1-rc.1 +## 3.0.1-rc.1 - prerelease 3.0.1-rc.1 -#### 3.0.1-beta.9 +## 3.0.1-beta.9 - add `constructor` for typescript - fix Android `mapToChannelMediaInfo` crash - fix iOS `switchChannel` `sendMetadata` crash -#### 3.0.1-beta.8 +## 3.0.1-beta.8 - fix iOS event warn - fix ts array declare error -#### 3.0.1-beta.7 +## 3.0.1-beta.7 - fix lib ignore bug -#### 3.0.1-beta.6 +## 3.0.1-beta.6 - support 3.0.1.1 native sdk - fix iOS `RtcChannelEvent` `NetworkQuality` crash -#### 3.0.1-beta.5 +## 3.0.1-beta.5 - fix lib ignore bug -#### 3.0.1-beta.4 +## 3.0.1-beta.4 - fix android `setCameraCapturerConfiguration` bug -#### 3.0.1-beta.3 +## 3.0.1-beta.3 - fix iOS `mirrorMode` bug -#### 3.0.1-beta.2 +## 3.0.1-beta.2 - fix `createWithAreaCode` bug - fix render black screen bug -#### 3.0.1-beta.1 +## 3.0.1-beta.1 - support 3.0.1 native sdk -#### 3.0.0-beta.6 +## 3.0.0-beta.6 - fix iOS link bug -#### 3.0.0-beta.5 +## 3.0.0-beta.5 - optimize doc -#### 3.0.0-beta.4 +## 3.0.0-beta.4 - optimize code -#### 3.0.0-beta.3 +## 3.0.0-beta.3 - optimize doc -#### 3.0.0-beta.2 +## 3.0.0-beta.2 - optimize -#### 3.0.0-beta.1 +## 3.0.0-beta.1 - support 3.0.0 native sdk -#### 2.9.1-alpha.7 +## 2.9.1-alpha.7 - fix `setBeautyEffectOptions` bugs -#### 2.9.1-alpha.6 +## 2.9.1-alpha.6 - fix bugs -#### 2.9.1-alpha.5 +## 2.9.1-alpha.5 - upgrade android sdk to 2.9.4 -#### 2.9.1-alpha.4 +## 2.9.1-alpha.4 - remove `AgoraRtcCryptoLoader` `libcrypto` -#### 2.9.1-alpha.3 +## 2.9.1-alpha.3 - upgrade android sdk to 2.9.4 -#### 2.9.1-alpha.2 +## 2.9.1-alpha.2 - upgrade 2.9.2 fro android -#### 2.9.1-alpha.1 +## 2.9.1-alpha.1 - support 2.9.1 native sdk -#### 2.9.0-alpha.3 +## 2.9.0-alpha.3 - hotfix ios compile error -#### 2.9.0-alpha.2 +## 2.9.0-alpha.2 - fix ios dictionary stringValue type cast -#### 2.9.0-alpha.1 +## 2.9.0-alpha.1 - fix typo: rename `methodisSpeakerphoneEnabled` to `isSpeakerphoneEnabled` - events deprecated & instead: * `microphoneEnabled` instead `localAudioStateChanged` @@ -130,7 +130,7 @@ * `switchChannel` switch to specified channel * `startChannelMediaRelay`, `updateChannelMediaRelay`, `stopChannelMediaRelay`, `removeChannelMediaRelay` relay media streams operation for across channels. -#### 2.8.0-alpha.1 +## 2.8.0-alpha.1 - add `string uid` api support - android: deprecate `lowLatency` member of LiveTranscoding - add methods `getUserInfoByUserAccount`, `getUserInfoByUid`, `joinChannelWithUserAccount`, `registerLocalUserAccount` @@ -140,17 +140,17 @@ - android: upgrade native sdk to 2.8.2 - ios: upgrade native sdk to 2.8.0 -#### 2.4.1-alpha.3 +## 2.4.1-alpha.3 - refactor setLiveTranscoding: rename ios & android native parameters. export enum for javascript/typescript api. - fix negative number case in android platform. - improve api doc. -#### 2.4.1-alpha.2 +## 2.4.1-alpha.2 - deprecated `sendMessage` & `createDataStream` & `removeAllListeners` & `off` - refactor event system - fix `android` enum convert failed. -#### 2.4.1-alpha +## 2.4.1-alpha - support 2.4.1-alpha.1 agora video sdk android-2.4.1 / iOS-2.4.1 1. Deprecate iOS manual link operator, instead using cocoapods resolve compile dependencies. 2. Add methods getAudioMixingPlayoutVolume, getAudioMixingPublishVolume for audio mixing troubleshooting. @@ -165,7 +165,7 @@ 11. Add event `audioMixingStateChanged` and Deprecate event 'localAudioMixingFinish`. 11. Add `firstRemoteAudioDecoded` event you can get more detail [here](https://docs.agora.io/en/Interactive%20Broadcast/release_android_video?platform=Android#v241) -#### 2.4.0-alpha +## 2.4.0-alpha - support 2.4.0-alpha.1 agora video sdk android-2.4.0 / iOS-2.4.0.1 and add sendMessage support in the same channel. Deprecate: startEchoTest and setVideoQualityParameters - support 2.4.0-alpha.2 using 0.55.1 as peerDependency and support typescript - support 2.4.0-alpha.3 bugfix iOS receiveStreamMessage data is null @@ -184,7 +184,7 @@ "AgoraAudioMode" to "AudioMode" ``` -#### 2.3.3-alpha +## 2.3.3-alpha - support agora video sdk 2.3.3 - release 2.3.3-alpha.3 - release 2.3.3-alpha.4 (remove deprecated native api) @@ -193,17 +193,17 @@ - release 2.3.3-alpha.7 (refactor RtcEngine#init method support audio / video mode and switch dualStream) -#### 1.1.2 +## 1.1.2 - add onVideoMute - add onAudioMute -#### 1.1.1 +## 1.1.1 - add createDataStream - add sendStreamMessage - add onStreamMessage -#### 1.0.9 +## 1.0.9 - update to agora sdk version 2.0.2 @@ -215,7 +215,7 @@ - fix bug: Android speaker's volume indication -#### 1.0.8 +## 1.0.8 - update to agora sdk version 1.12 From c08be4d2e7c00749427db2e32641ce9479f15682 Mon Sep 17 00:00:00 2001 From: HUI Date: Wed, 21 Oct 2020 22:53:55 +0800 Subject: [PATCH 09/18] chore: release 3.1.4-rc.0 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63985ac02..fc02cb3c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [3.1.4-rc.0](https://github.com/AgoraIO-Community/react-native-agora/compare/3.1.2-rc.2...v3.1.4-rc.0) (2020-10-21) + + +### Features + +* migrating to @react-native-community/bob ([c72a527](https://github.com/AgoraIO-Community/react-native-agora/commit/c72a5278b2e990081d34e2e765e2e6a26ba792bb)) + ## 3.1.3 - fix iOS `deinit` `[weak self]` crash - make `RtcChannel.channelId` public diff --git a/package.json b/package.json index e5055dc8a..296cff54c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-agora", - "version": "3.1.3", + "version": "3.1.4-rc.0", "description": "Agora RTC SDK For React Native", "main": "lib/commonjs/index", "module": "lib/module/index", From 69a7a96ec35037f5dbcc5a0e67285eb1d4c59c08 Mon Sep 17 00:00:00 2001 From: HUI Date: Thu, 22 Oct 2020 21:22:44 +0800 Subject: [PATCH 10/18] fix: Android setData error --- .../io/agora/rtc/react/RCTAgoraRtcSurfaceViewManager.kt | 6 ++++-- .../io/agora/rtc/react/RCTAgoraRtcTextureViewManager.kt | 6 ++++-- src/common/RtcRenderView.native.tsx | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) 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 af12fad81..9aaed148a 100644 --- a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcSurfaceViewManager.kt +++ b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcSurfaceViewManager.kt @@ -41,8 +41,10 @@ class RCTAgoraRtcSurfaceViewManager : SimpleViewManager() { @ReactProp(name = "data") fun setData(view: RtcSurfaceView, data: ReadableMap) { - val channel = data.getString("channelId")?.let { getChannel(it) } - getEngine()?.let { view.setData(it, channel, data.getInt("uid")) } + 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") 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 c1509c2d2..5e36072e2 100644 --- a/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcTextureViewManager.kt +++ b/android/src/main/java/io/agora/rtc/react/RCTAgoraRtcTextureViewManager.kt @@ -31,8 +31,10 @@ class RCTAgoraRtcTextureViewManager : SimpleViewManager() { @ReactProp(name = "data") fun setData(view: RtcTextureView, data: ReadableMap) { - val channel = data.getString("channelId")?.let { getChannel(it) } - getEngine()?.let { view.setData(it, channel, data.getInt("uid")) } + 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") diff --git a/src/common/RtcRenderView.native.tsx b/src/common/RtcRenderView.native.tsx index e539923ae..846f903d8 100644 --- a/src/common/RtcRenderView.native.tsx +++ b/src/common/RtcRenderView.native.tsx @@ -91,7 +91,7 @@ export class RtcSurfaceView extends Component< {} > { render() { - const { channelId = undefined, uid, ...others } = this.props; + const { channelId, uid, ...others } = this.props; return ( { render() { - const { channelId = undefined, uid, ...others } = this.props; + const { channelId, uid, ...others } = this.props; return ( Date: Thu, 22 Oct 2020 21:23:36 +0800 Subject: [PATCH 11/18] feat: add API example --- example/agora.config.json | 5 + example/android/app/build.gradle | 1 + example/package.json | 9 +- example/src/App.tsx | 99 +- .../src/examples/advanced/MultiChannel.tsx | 255 + example/src/examples/advanced/index.ts | 13 + .../src/examples/basic/JoinChannelAudio.tsx | 158 + .../src/examples/basic/JoinChannelVideo.tsx | 181 + example/src/examples/basic/StringUid.tsx | 137 + example/src/examples/basic/index.ts | 23 + example/yarn.lock | 4473 ----------------- 11 files changed, 861 insertions(+), 4493 deletions(-) create mode 100644 example/agora.config.json create mode 100644 example/src/examples/advanced/MultiChannel.tsx create mode 100644 example/src/examples/advanced/index.ts create mode 100644 example/src/examples/basic/JoinChannelAudio.tsx create mode 100644 example/src/examples/basic/JoinChannelVideo.tsx create mode 100644 example/src/examples/basic/StringUid.tsx create mode 100644 example/src/examples/basic/index.ts delete mode 100644 example/yarn.lock diff --git a/example/agora.config.json b/example/agora.config.json new file mode 100644 index 000000000..f95ac6dcc --- /dev/null +++ b/example/agora.config.json @@ -0,0 +1,5 @@ +{ + "appId": YOUR_APP_ID, + "channelId": "APIExample", + "token": YOUR_TOEKN +} diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index cdc98bab0..e03738298 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -132,6 +132,7 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" + multiDexEnabled true } splits { abi { diff --git a/example/package.json b/example/package.json index 44659bd31..45c1f5394 100644 --- a/example/package.json +++ b/example/package.json @@ -9,8 +9,15 @@ "start": "react-native start" }, "dependencies": { + "@react-native-community/masked-view": "^0.1.10", + "@react-navigation/native": "^5.7.1", + "@react-navigation/stack": "^5.7.1", "react": "16.11.0", - "react-native": "0.62.2" + "react-native": "0.62.2", + "react-native-gesture-handler": "^1.7.0", + "react-native-reanimated": "^1.10.1", + "react-native-safe-area-context": "^3.1.1", + "react-native-screens": "^2.9.0" }, "devDependencies": { "@babel/core": "^7.9.6", diff --git a/example/src/App.tsx b/example/src/App.tsx index 1e12c57c9..d252b2335 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,31 +1,92 @@ -import * as React from 'react'; -import { StyleSheet, View, Text } from 'react-native'; -import RtcEngine, { RtcChannel } from 'react-native-agora'; +/** + * Sample React Native App + * https://github.com/facebook/react-native + * + * Generated with the TypeScript template + * https://github.com/react-native-community/react-native-template-typescript + * + * @format + */ -export default function App() { - const [result, setResult] = React.useState(); +import React from 'react'; +import { + SafeAreaView, + StyleSheet, + SectionList, + Text, + View, + TouchableOpacity, +} from 'react-native'; - React.useEffect(() => { - RtcEngine.create('2b4b76e458cf439aa7cd313b9504f0a4').then(() => { - RtcChannel.create('xxx').then((channel: RtcChannel) => { - setResult(channel.channelId); - }); - }); - }, []); +import { NavigationContainer } from '@react-navigation/native'; +import { createStackNavigator } from '@react-navigation/stack'; +import Basic from './examples/basic'; +import Advanced from './examples/advanced'; + +const Stack = createStackNavigator(); + +const DATA = [Basic, Advanced]; + +const App = () => { + return ( + + + + {DATA.map((value) => + // @ts-ignore + value.data.map(({ name, component }) => ( + + )) + )} + + + ); +}; + +// @ts-ignore +const Home = ({ navigation }) => { return ( - - Result: {result} - + + item.name + index} + renderItem={({ item }) => } + renderSectionHeader={({ section: { title } }) => ( + {title} + )} + /> + ); -} +}; + +// @ts-ignore +const Item = ({ item, navigation }) => ( + + navigation.navigate(item.name)}> + {item.name} + + +); const styles = StyleSheet.create({ container: { flex: 1, - justifyContent: 'center', }, - text: { - textAlign: 'center', + header: { + padding: 10, + fontSize: 24, + color: 'white', + backgroundColor: 'grey', + }, + item: { + padding: 15, + }, + title: { + fontSize: 24, + color: 'black', }, }); + +export default App; diff --git a/example/src/examples/advanced/MultiChannel.tsx b/example/src/examples/advanced/MultiChannel.tsx new file mode 100644 index 000000000..0e6b06efc --- /dev/null +++ b/example/src/examples/advanced/MultiChannel.tsx @@ -0,0 +1,255 @@ +import React, { Component } from 'react'; +import { + View, + PermissionsAndroid, + StyleSheet, + Button, + Platform, +} from 'react-native'; + +import RtcEngine, { + RtcChannel, + RtcLocalView, + RtcRemoteView, + ChannelProfile, + ClientRole, + ChannelMediaOptions, +} from 'react-native-agora'; + +const config = require('../../../agora.config.json'); + +interface State { + renderChannelId: string; + isJoined0: boolean; + isJoined1: boolean; + remoteUid0: number | undefined; + remoteUid1: number | undefined; +} + +const channelId0 = 'channel0'; +const channelId1 = 'channel1'; + +export default class MultiChannel extends Component<{}, State, any> { + _engine: RtcEngine | undefined; + _channel0: RtcChannel | undefined; + _channel1: RtcChannel | undefined; + + constructor(props: {}) { + super(props); + this.state = { + renderChannelId: channelId0, + isJoined0: false, + isJoined1: false, + remoteUid0: undefined, + remoteUid1: undefined, + }; + } + + UNSAFE_componentWillMount() { + this._initEngine(); + } + + componentWillUnmount() { + this._engine?.destroy(); + } + + _initEngine = async () => { + this._engine = await RtcEngine.create(config.appId); + + await this._engine.enableVideo(); + await this._engine.startPreview(); + await this._engine.setChannelProfile(ChannelProfile.LiveBroadcasting); + }; + + _joinChannel0 = async () => { + if (Platform.OS === 'android') { + await PermissionsAndroid.requestMultiple([ + PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, + PermissionsAndroid.PERMISSIONS.CAMERA, + ]); + } + + this._channel0 = await RtcChannel.create(channelId0); + this._addListener(this._channel0, channelId0); + + await this._channel0.setClientRole(ClientRole.Broadcaster); + await this._channel0.joinChannel( + null, + null, + 0, + new ChannelMediaOptions(true, true) + ); + }; + + _joinChannel1 = async () => { + if (Platform.OS === 'android') { + await PermissionsAndroid.requestMultiple([ + PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, + PermissionsAndroid.PERMISSIONS.CAMERA, + ]); + } + + this._channel1 = await RtcChannel.create(channelId1); + this._addListener(this._channel1, channelId1); + + await this._channel1.setClientRole(ClientRole.Broadcaster); + await this._channel1.joinChannel( + null, + null, + 0, + new ChannelMediaOptions(true, true) + ); + }; + + _addListener = (channel: RtcChannel, channelId: string) => { + channel.addListener('JoinChannelSuccess', (uid, elapsed) => { + console.info('JoinChannelSuccess', channelId, uid, elapsed); + if (channelId === channelId0) { + this.setState({ isJoined0: true }); + } else if (channelId === channelId1) { + this.setState({ isJoined1: true }); + } + }); + channel.addListener('UserJoined', (uid, elapsed) => { + console.info('UserJoined', channelId, uid, elapsed); + if (channelId === channelId0) { + this.setState({ remoteUid0: uid }); + } else if (channelId === channelId1) { + this.setState({ remoteUid1: uid }); + } + }); + channel.addListener('UserOffline', (uid, reason) => { + console.info('UserOffline', channelId, uid, reason); + if (channelId === channelId0) { + if (uid === this.state.remoteUid0) { + this.setState({ remoteUid0: undefined }); + } + } else if (channelId === channelId1) { + if (uid === this.state.remoteUid1) { + this.setState({ remoteUid1: undefined }); + } + } + }); + channel.addListener('LeaveChannel', (stats) => { + console.info('LeaveChannel', channelId, stats); + if (channelId === channelId0) { + this.setState({ isJoined0: false, remoteUid0: undefined }); + } else if (channelId === channelId1) { + this.setState({ isJoined1: false, remoteUid1: undefined }); + } + }); + }; + + _publishChannel0 = async () => { + await this._channel1?.unpublish(); + await this._channel0?.publish(); + }; + + _publishChannel1 = async () => { + await this._channel0?.unpublish(); + await this._channel1?.publish(); + }; + + _leaveChannel0 = async () => { + await this._channel0?.leaveChannel(); + }; + + _leaveChannel1 = async () => { + await this._channel1?.leaveChannel(); + }; + + render() { + const { isJoined0, isJoined1 } = this.state; + return ( + + +