├── .gitignore ├── LICENSE ├── README.md ├── demo.png ├── webrtc-flutter-client ├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── android │ ├── .gitignore │ ├── app │ │ ├── appcenter-post-clone.sh │ │ ├── build.gradle │ │ ├── keystores │ │ │ ├── keystore-debug.jks │ │ │ └── keystore-release.jks │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── app │ │ │ │ │ └── nft │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-hdpi │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── drawable-mdpi │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── drawable-xhdpi │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── drawable-xxxhdpi │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ └── ic_launcher.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── assets │ ├── app │ │ ├── fonts │ │ │ └── .gitkeep │ │ └── icons │ │ │ └── .gitkeep │ └── base │ │ ├── fonts │ │ ├── AvenirNextLTPro-Bold.otf │ │ ├── AvenirNextLTPro-Demi.otf │ │ ├── AvenirNextLTPro-Regular.otf │ │ ├── SFProText-Bold.ttf │ │ ├── SFProText-Light.ttf │ │ ├── SFProText-Medium.ttf │ │ ├── SFProText-Regular.ttf │ │ └── SFProText-Semibold.ttf │ │ └── icons │ │ ├── 2.0x │ │ ├── .gitkeep │ │ ├── ic_add.png │ │ ├── ic_add_mail.png │ │ ├── ic_back.png │ │ ├── ic_camera.png │ │ ├── ic_edit.png │ │ ├── ic_empty.png │ │ ├── ic_heart.png │ │ ├── ic_more.png │ │ ├── ic_noti.png │ │ └── ic_search.png │ │ ├── 3.0x │ │ ├── .gitkeep │ │ ├── ic_add.png │ │ ├── ic_add_mail.png │ │ ├── ic_back.png │ │ ├── ic_camera.png │ │ ├── ic_edit.png │ │ ├── ic_empty.png │ │ ├── ic_heart.png │ │ ├── ic_more.png │ │ ├── ic_noti.png │ │ └── ic_search.png │ │ ├── app_icon.png │ │ ├── ic_add.png │ │ ├── ic_add_mail.png │ │ ├── ic_back.png │ │ ├── ic_camera.png │ │ ├── ic_edit.png │ │ ├── ic_empty.png │ │ ├── ic_heart.png │ │ ├── ic_more.png │ │ ├── ic_noti.png │ │ ├── ic_search.png │ │ └── ic_warning.png ├── ios-version.sh ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ ├── Flutter.podspec │ │ └── Release.xcconfig │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ └── LaunchImage.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── README.md │ │ │ │ ├── app_icon@1x.png │ │ │ │ ├── app_icon@2x.png │ │ │ │ └── app_icon@3x.png │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h │ └── appcenter-post-clone.sh ├── lib │ ├── app_config.dart │ ├── main.dart │ ├── my_app.dart │ └── pages │ │ └── webrtc │ │ ├── call_screen.dart │ │ ├── device_info.dart │ │ ├── random_string.dart │ │ ├── signaling.dart │ │ ├── turn.dart │ │ └── websocket.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── widget_test.dart ├── webrtc-nestjs-server ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── nest-cli.json ├── package-lock.json ├── package.json ├── src │ ├── app.controller.spec.ts │ ├── app.controller.ts │ ├── app.module.ts │ ├── app.service.ts │ ├── events │ │ ├── events.gateway.spec.ts │ │ ├── events.gateway.ts │ │ └── events.module.ts │ └── main.ts ├── test │ ├── app.e2e-spec.ts │ └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json └── webrtc-web-client ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── basic_peerconnection ├── css │ └── main.css ├── index.html ├── index.js ├── js │ └── webrtc.js ├── lib │ └── socket.io.js └── logo.svg ├── index.html └── socket_peerconnection ├── css └── main.css ├── index.html ├── js └── webrtc.js ├── lib └── socket.io.js └── logo.svg /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.idea 3 | *node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Nhan Cao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter WebRTC Example 2 | 3 | ![Preview](demo.png) 4 | 5 | # Install 6 | 7 | - NodeJs: https://nodejs.org/en/download/ 8 | - NestJs: https://docs.nestjs.com/first-steps 9 | - Flutter: https://flutter.dev/docs/get-started/install 10 | - Local https server: https://www.npmjs.com/package/local-web-server 11 | 12 | # Runing 13 | 14 | ## Start webrtc server first 15 | 16 | ``` 17 | cd webrtc-nestjs-server 18 | npm i 19 | npm start 20 | ``` 21 | 22 | ## Test with web webrtc client 23 | 24 | ``` 25 | cd webrtc-web-client 26 | ws --http2 27 | ``` 28 | 29 | ## Test with Flutter webrtc client 30 | 31 | ``` 32 | cd webrtc-flutter-client 33 | flutter run 34 | ``` 35 | 36 | 37 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/demo.png -------------------------------------------------------------------------------- /webrtc-flutter-client/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | 32 | # Web related 33 | lib/generated_plugin_registrant.dart 34 | 35 | # Exceptions to above rules. 36 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 37 | .flutter-plugins-dependencies 38 | .last_build_id -------------------------------------------------------------------------------- /webrtc-flutter-client/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b 8 | channel: beta 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /webrtc-flutter-client/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Nhan Cao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /webrtc-flutter-client/README.md: -------------------------------------------------------------------------------- 1 | # nft 2 | Flutter Template 3 | 4 | ## Structure 5 | 6 | ``` 7 | 8 | main.dart 9 | | 10 | +-------|------+ 11 | | login | 12 | +--------------+ 13 | - Login with fake api 14 | | 15 | +-------|------+ 16 | | home | 17 | +--------------+ 18 | - Show repo info 19 | - Navigate to search screen 20 | | 21 | | 22 | +-------|------+ 23 | | search | 24 | +--------------+ 25 | - Search github user 26 | - Show a list of user 27 | - Tap on specific user and navigate to detail screen 28 | | 29 | | 30 | +-------|------+ 31 | | detail | 32 | +--------------+ 33 | - Show detail of github user 34 | 35 | ``` 36 | 37 | ## Update app icon 38 | 39 | ``` 40 | flutter pub get 41 | flutter pub run flutter_launcher_icons:main 42 | ``` -------------------------------------------------------------------------------- /webrtc-flutter-client/android/.gitignore: -------------------------------------------------------------------------------- 1 | /.gradle 2 | /captures/ 3 | /local.properties 4 | GeneratedPluginRegistrant.java 5 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/appcenter-post-clone.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #Place this script in project/android/app/ 3 | 4 | cd .. 5 | 6 | # fail if any command fails 7 | set -e 8 | # debug log 9 | set -x 10 | 11 | cd .. 12 | git clone -b beta https://github.com/flutter/flutter.git 13 | export PATH=`pwd`/flutter/bin:$PATH 14 | 15 | flutter channel stable 16 | flutter doctor 17 | 18 | echo "Installed flutter to `pwd`/flutter" 19 | 20 | # build APK 21 | flutter build apk --release 22 | 23 | # if you need build bundle (AAB) in addition to your APK, uncomment line below and last line of this script. 24 | #flutter build appbundle 25 | 26 | # copy the APK where AppCenter will find it 27 | mkdir -p android/app/build/outputs/apk/; mv build/app/outputs/apk/release/app-release.apk $_ 28 | 29 | # copy the AAB where AppCenter will find it 30 | #mkdir -p android/app/build/outputs/bundle/; mv build/app/outputs/bundle/release/app.aab $_ -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.app.nft" 42 | minSdkVersion 21 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 47 | } 48 | 49 | signingConfigs { 50 | debug { 51 | keyAlias 'androiddebugkey' 52 | keyPassword 'android' 53 | storeFile file("keystores/keystore-debug.jks") 54 | storePassword 'android' 55 | } 56 | release { 57 | keyAlias 'androiddebugkey' 58 | keyPassword 'android' 59 | storeFile file("keystores/keystore-release.jks") 60 | storePassword 'android' 61 | } 62 | } 63 | 64 | buildTypes { 65 | debug { 66 | debuggable true 67 | signingConfig signingConfigs.debug 68 | } 69 | release { 70 | debuggable false 71 | minifyEnabled true 72 | useProguard true 73 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 74 | signingConfig signingConfigs.release 75 | } 76 | } 77 | 78 | compileOptions { 79 | sourceCompatibility JavaVersion.VERSION_1_8 80 | targetCompatibility JavaVersion.VERSION_1_8 81 | } 82 | } 83 | 84 | flutter { 85 | source '../..' 86 | } 87 | 88 | dependencies { 89 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 90 | testImplementation 'junit:junit:4.12' 91 | androidTestImplementation 'androidx.test:runner:1.1.1' 92 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 93 | } 94 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/keystores/keystore-debug.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/keystores/keystore-debug.jks -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/keystores/keystore-release.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/keystores/keystore-release.jks -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | ## Flutter WebRTC 2 | -keep class com.cloudwebrtc.webrtc.** { *; } 3 | -keep class org.webrtc.** { *; } -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 17 | 21 | 28 | 32 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/kotlin/com/app/nft/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.app.nft 2 | 3 | import android.os.Build 4 | import android.os.Bundle 5 | import android.view.ViewTreeObserver 6 | import android.view.WindowManager 7 | 8 | import io.flutter.app.FlutterActivity 9 | import io.flutter.plugins.GeneratedPluginRegistrant 10 | 11 | class MainActivity : FlutterActivity() { 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | //make transparent status bar 15 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 16 | window.statusBarColor = 0x00000000 17 | } 18 | GeneratedPluginRegistrant.registerWith(this) 19 | //Remove full screen flag after load 20 | val vto: ViewTreeObserver = flutterView.viewTreeObserver 21 | vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { 22 | override fun onGlobalLayout() { 23 | // your code here. `this` should work 24 | flutterView.viewTreeObserver.removeOnGlobalLayoutListener(this) 25 | window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) 26 | } 27 | }) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/drawable-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/drawable-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/drawable-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/gradle.properties: -------------------------------------------------------------------------------- 1 | 2 | org.gradle.jvmargs=-Xmx1536M 3 | android.enableR8=true 4 | android.useAndroidX=true 5 | android.enableJetifier=true 6 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /webrtc-flutter-client/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /webrtc-flutter-client/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/app/fonts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/app/fonts/.gitkeep -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/app/icons/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/app/icons/.gitkeep -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/fonts/AvenirNextLTPro-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/fonts/AvenirNextLTPro-Bold.otf -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/fonts/AvenirNextLTPro-Demi.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/fonts/AvenirNextLTPro-Demi.otf -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/fonts/AvenirNextLTPro-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/fonts/AvenirNextLTPro-Regular.otf -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/fonts/SFProText-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/fonts/SFProText-Bold.ttf -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/fonts/SFProText-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/fonts/SFProText-Light.ttf -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/fonts/SFProText-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/fonts/SFProText-Medium.ttf -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/fonts/SFProText-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/fonts/SFProText-Regular.ttf -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/fonts/SFProText-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/fonts/SFProText-Semibold.ttf -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/.gitkeep -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/ic_add.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/ic_add_mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/ic_add_mail.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/ic_back.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/ic_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/ic_camera.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/ic_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/ic_edit.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/ic_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/ic_empty.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/ic_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/ic_heart.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/ic_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/ic_more.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/ic_noti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/ic_noti.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/2.0x/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/2.0x/ic_search.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/.gitkeep -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/ic_add.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/ic_add_mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/ic_add_mail.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/ic_back.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/ic_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/ic_camera.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/ic_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/ic_edit.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/ic_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/ic_empty.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/ic_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/ic_heart.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/ic_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/ic_more.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/ic_noti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/ic_noti.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/3.0x/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/3.0x/ic_search.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/app_icon.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_add.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_add_mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_add_mail.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_back.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_camera.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_edit.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_empty.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_heart.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_more.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_noti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_noti.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_search.png -------------------------------------------------------------------------------- /webrtc-flutter-client/assets/base/icons/ic_warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/assets/base/icons/ic_warning.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios-version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -e 2 | 3 | _INFOPLIST_DIR="ios/Runner/Info.plist" 4 | 5 | _PACKAGE_VERSION=$(cat pubspec.yaml | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[: ']//g'') 6 | 7 | # Set BUILD_NUMBER to the value 1 only if it is unset. 8 | : ${BUILD_NUMBER=$(expr $(git log -1 --pretty=format:%ct) / 3600)} 9 | 10 | # Update plist with new values 11 | 12 | BUNDLE_VERSION=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${_INFOPLIST_DIR}") 13 | if [ "$BUNDLE_VERSION" != "$BUILD_NUMBER" ] 14 | then 15 | /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" "${_INFOPLIST_DIR}" 16 | fi 17 | 18 | /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${_PACKAGE_VERSION#*v}" "${_INFOPLIST_DIR}" 19 | 20 | echo "****************************************" 21 | echo "PACKAGE_VERSION: " $_PACKAGE_VERSION 22 | echo "BUILD_NUMBER: " $BUILD_NUMBER 23 | echo "****************************************" 24 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Generated.xcconfig 20 | Flutter/app.flx 21 | Flutter/app.zip 22 | Flutter/flutter_assets/ 23 | Flutter/flutter_export_environment.sh 24 | ServiceDefinitions.json 25 | Runner/GeneratedPluginRegistrant.* 26 | 27 | # Exceptions to above rules. 28 | !default.mode1v3 29 | !default.mode2v3 30 | !default.pbxuser 31 | !default.perspectivev3 32 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Flutter/Flutter.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: This podspec is NOT to be published. It is only used as a local source! 3 | # 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'Flutter' 7 | s.version = '1.0.0' 8 | s.summary = 'High-performance, high-fidelity mobile apps.' 9 | s.description = <<-DESC 10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. 11 | DESC 12 | s.homepage = 'https://flutter.io' 13 | s.license = { :type => 'MIT' } 14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } 15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } 16 | s.ios.deployment_target = '8.0' 17 | s.vendored_frameworks = 'Flutter.framework' 18 | end 19 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | generated_key_values = {} 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) do |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | generated_key_values[podname] = podpath 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | end 32 | generated_key_values 33 | end 34 | 35 | target 'Runner' do 36 | #use_frameworks! 37 | use_modular_headers! 38 | 39 | # Flutter Pod 40 | 41 | copied_flutter_dir = File.join(__dir__, 'Flutter') 42 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') 43 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') 44 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) 45 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. 46 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. 47 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. 48 | 49 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') 50 | unless File.exist?(generated_xcode_build_settings_path) 51 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" 52 | end 53 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) 54 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; 55 | 56 | unless File.exist?(copied_framework_path) 57 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) 58 | end 59 | unless File.exist?(copied_podspec_path) 60 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) 61 | end 62 | end 63 | 64 | # Keep pod path relative so it can be checked into Podfile.lock. 65 | pod 'Flutter', :path => 'Flutter' 66 | 67 | # Plugin Pods 68 | 69 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 70 | # referring to absolute paths on developers' machines. 71 | system('rm -rf .symlinks') 72 | system('mkdir -p .symlinks/plugins') 73 | plugin_pods = parse_KV_file('../.flutter-plugins') 74 | plugin_pods.each do |name, path| 75 | symlink = File.join('.symlinks', 'plugins', name) 76 | File.symlink(path, symlink) 77 | pod name, :path => File.join(symlink, 'ios') 78 | end 79 | end 80 | 81 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 82 | install! 'cocoapods', :disable_input_output_paths => true 83 | 84 | post_install do |installer| 85 | installer.pods_project.targets.each do |target| 86 | target.build_configurations.each do |config| 87 | config.build_settings['ENABLE_BITCODE'] = 'NO' 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - flutter_webrtc (0.2.2): 4 | - Flutter 5 | - GoogleWebRTC (= 1.1.29400) 6 | - Libyuv (= 1703) 7 | - GoogleWebRTC (1.1.29400) 8 | - Libyuv (1703) 9 | 10 | DEPENDENCIES: 11 | - Flutter (from `Flutter`) 12 | - flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`) 13 | 14 | SPEC REPOS: 15 | trunk: 16 | - GoogleWebRTC 17 | - Libyuv 18 | 19 | EXTERNAL SOURCES: 20 | Flutter: 21 | :path: Flutter 22 | flutter_webrtc: 23 | :path: ".symlinks/plugins/flutter_webrtc/ios" 24 | 25 | SPEC CHECKSUMS: 26 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 27 | flutter_webrtc: 626ca239bcc4390a514a2ac2b21b16d0c58b33fe 28 | GoogleWebRTC: cfb83bc346435a17fe06bb05f04ad826b858a7fb 29 | Libyuv: 5f79ced0ee66e60a612ca97de1e6ccacd187a437 30 | 31 | PODFILE CHECKSUM: d6a5eef966181cbcd5960a9cb4150f11d90176fe 32 | 33 | COCOAPODS: 1.9.1 34 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "app_icon@1x.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "app_icon@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "app_icon@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/LaunchImage.imageset/app_icon@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/LaunchImage.imageset/app_icon@1x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/LaunchImage.imageset/app_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/LaunchImage.imageset/app_icon@2x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Assets.xcassets/LaunchImage.imageset/app_icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-flutter-client/ios/Runner/Assets.xcassets/LaunchImage.imageset/app_icon@3x.png -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | nft 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | NSCameraUsageDescription 26 | $(PRODUCT_NAME) Camera Usage! 27 | NSMicrophoneUsageDescription 28 | $(PRODUCT_NAME) Microphone Usage! 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | UIViewControllerBasedStatusBarAppearance 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /webrtc-flutter-client/ios/appcenter-post-clone.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #Place this script in project/ios/ 3 | 4 | # fail if any command fails 5 | set -e 6 | # debug log 7 | set -x 8 | 9 | cd .. 10 | git clone -b beta https://github.com/flutter/flutter.git 11 | export PATH=`pwd`/flutter/bin:$PATH 12 | 13 | flutter channel stable 14 | flutter doctor 15 | 16 | echo "Installed flutter to `pwd`/flutter" 17 | 18 | flutter build ios --release --no-codesign 19 | -------------------------------------------------------------------------------- /webrtc-flutter-client/lib/app_config.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2020 Nhan Cao 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | import 'package:flutter/material.dart'; 26 | import 'package:meta/meta.dart'; 27 | 28 | /// Environment declare here 29 | class Env { 30 | Env._({@required this.apiBaseUrl}); 31 | 32 | final String apiBaseUrl; 33 | 34 | factory Env.dev() { 35 | return Env._(apiBaseUrl: "https://api.github.com"); 36 | } 37 | } 38 | 39 | /// Global env 40 | class Config { 41 | Config._private(); 42 | 43 | static final Config instance = Config._private(); 44 | 45 | factory Config({Env environment}) { 46 | if (environment != null) { 47 | instance.env = environment; 48 | } 49 | return instance; 50 | } 51 | 52 | Env env; 53 | } 54 | -------------------------------------------------------------------------------- /webrtc-flutter-client/lib/main.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2020 Nhan Cao 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | import 'package:nft/my_app.dart'; 26 | import 'package:nft/app_config.dart'; 27 | 28 | void main() async { 29 | // Init dev global 30 | Config(environment: Env.dev()); 31 | await myMain(); 32 | } 33 | -------------------------------------------------------------------------------- /webrtc-flutter-client/lib/my_app.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2020 Nhan Cao 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | import 'package:flutter/material.dart'; 26 | import 'package:nft/pages/webrtc/call_screen.dart'; 27 | 28 | Future myMain() async { 29 | // @nhancv 2019-10-24: Start services later 30 | WidgetsFlutterBinding.ensureInitialized(); 31 | // @nhancv 10/23/2019: Run Application 32 | runApp(MyApp()); 33 | } 34 | 35 | class MyApp extends StatefulWidget { 36 | @override 37 | _MyAppState createState() => _MyAppState(); 38 | } 39 | 40 | class _MyAppState extends State { 41 | @override 42 | Widget build(BuildContext context) { 43 | return MaterialApp( 44 | debugShowCheckedModeBanner: false, 45 | theme: ThemeData( 46 | primarySwatch: Colors.blue, 47 | ), 48 | home: AppContent(), 49 | ); 50 | } 51 | } 52 | 53 | class AppContent extends StatelessWidget { 54 | @override 55 | Widget build(BuildContext context) { 56 | WidgetsBinding.instance.addPostFrameCallback((_) => onAfterBuild(context)); 57 | 58 | return Scaffold( 59 | backgroundColor: Colors.transparent, 60 | body: CallScreen(ip: '192.168.68.107'), 61 | ); 62 | } 63 | 64 | // @nhancv 10/25/2019: After widget initialized. 65 | void onAfterBuild(BuildContext context) {} 66 | } 67 | -------------------------------------------------------------------------------- /webrtc-flutter-client/lib/pages/webrtc/call_screen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_webrtc/webrtc.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | import 'signaling.dart'; 8 | 9 | class CallScreen extends StatelessWidget { 10 | final String ip; 11 | 12 | const CallScreen({Key key, @required this.ip}) : super(key: key); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return ChangeNotifierProvider( 17 | create: (_) => CallProvider(), 18 | child: CallBody(ip: ip), 19 | ); 20 | } 21 | } 22 | 23 | class CallBody extends StatefulWidget { 24 | static String tag = 'call_sample'; 25 | 26 | final String ip; 27 | 28 | CallBody({Key key, @required this.ip}) : super(key: key); 29 | 30 | @override 31 | _CallBodyState createState() => _CallBodyState(serverIP: ip); 32 | } 33 | 34 | class _CallBodyState extends State { 35 | Signaling _signaling; 36 | var _selfId; 37 | RTCVideoRenderer _localRenderer = RTCVideoRenderer(); 38 | RTCVideoRenderer _remoteRenderer = RTCVideoRenderer(); 39 | bool _inCalling = false; 40 | final String serverIP; 41 | final TextEditingController textEditingController = TextEditingController(); 42 | 43 | _CallBodyState({Key key, @required this.serverIP}); 44 | 45 | @override 46 | initState() { 47 | super.initState(); 48 | initRenderers(); 49 | _connect(); 50 | } 51 | 52 | initRenderers() async { 53 | await _localRenderer.initialize(); 54 | await _remoteRenderer.initialize(); 55 | } 56 | 57 | @override 58 | deactivate() { 59 | super.deactivate(); 60 | if (_signaling != null) _signaling.close(); 61 | _localRenderer.dispose(); 62 | _remoteRenderer.dispose(); 63 | } 64 | 65 | void _connect() async { 66 | if (_signaling == null) { 67 | _signaling = Signaling(serverIP)..connect(); 68 | 69 | _signaling.onStateChange = (SignalingState state) { 70 | switch (state) { 71 | case SignalingState.CallStateNew: 72 | this.setState(() { 73 | _inCalling = true; 74 | }); 75 | break; 76 | case SignalingState.CallStateBye: 77 | this.setState(() { 78 | _localRenderer.srcObject = null; 79 | _remoteRenderer.srcObject = null; 80 | _inCalling = false; 81 | }); 82 | break; 83 | case SignalingState.CallStateInvite: 84 | case SignalingState.CallStateConnected: 85 | case SignalingState.CallStateRinging: 86 | case SignalingState.ConnectionClosed: 87 | case SignalingState.ConnectionError: 88 | case SignalingState.ConnectionOpen: 89 | break; 90 | } 91 | }; 92 | 93 | _signaling.onEventUpdate = ((event) { 94 | final clientId = event['clientId']; 95 | context.read().updateClientIp(clientId); 96 | }); 97 | 98 | _signaling.onPeersUpdate = ((event) { 99 | this.setState(() { 100 | _selfId = event['self']; 101 | }); 102 | }); 103 | 104 | _signaling.onLocalStream = ((stream) { 105 | _localRenderer.srcObject = stream; 106 | }); 107 | 108 | _signaling.onAddRemoteStream = ((stream) { 109 | _remoteRenderer.srcObject = stream; 110 | }); 111 | 112 | _signaling.onRemoveRemoteStream = ((stream) { 113 | _remoteRenderer.srcObject = null; 114 | }); 115 | } 116 | } 117 | 118 | _invitePeer(context, peerId, useScreen) async { 119 | if (_signaling != null && peerId != _selfId) { 120 | _signaling.invite(peerId, 'video', useScreen); 121 | } 122 | } 123 | 124 | _hangUp() { 125 | if (_signaling != null) { 126 | _signaling.bye(); 127 | } 128 | } 129 | 130 | _switchCamera() { 131 | _signaling.switchCamera(); 132 | } 133 | 134 | _muteMic() {} 135 | 136 | @override 137 | Widget build(BuildContext context) { 138 | return Scaffold( 139 | appBar: AppBar( 140 | title: Consumer( 141 | builder: (context, provider, child) { 142 | final clientId = provider.clientId; 143 | return clientId.isNotEmpty 144 | ? Text('$clientId') 145 | : Text('P2P Call Sample'); 146 | }, 147 | ), 148 | actions: [ 149 | IconButton( 150 | icon: const Icon(Icons.settings), 151 | onPressed: null, 152 | tooltip: 'setup', 153 | ), 154 | ], 155 | ), 156 | floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, 157 | floatingActionButton: _inCalling 158 | ? SizedBox( 159 | width: 200.0, 160 | child: Row( 161 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 162 | children: [ 163 | FloatingActionButton( 164 | child: const Icon(Icons.switch_camera), 165 | onPressed: _switchCamera, 166 | ), 167 | FloatingActionButton( 168 | onPressed: _hangUp, 169 | tooltip: 'Hangup', 170 | child: Icon(Icons.call_end), 171 | backgroundColor: Colors.pink, 172 | ), 173 | FloatingActionButton( 174 | child: const Icon(Icons.mic_off), 175 | onPressed: _muteMic, 176 | ) 177 | ])) 178 | : null, 179 | body: _inCalling 180 | ? OrientationBuilder(builder: (context, orientation) { 181 | return Container( 182 | child: Stack(children: [ 183 | Positioned( 184 | left: 0.0, 185 | right: 0.0, 186 | top: 0.0, 187 | bottom: 0.0, 188 | child: Container( 189 | margin: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0), 190 | width: MediaQuery.of(context).size.width, 191 | height: MediaQuery.of(context).size.height, 192 | child: RTCVideoView(_remoteRenderer), 193 | decoration: BoxDecoration(color: Colors.black54), 194 | )), 195 | Positioned( 196 | left: 20.0, 197 | top: 20.0, 198 | child: Container( 199 | width: orientation == Orientation.portrait ? 90.0 : 120.0, 200 | height: 201 | orientation == Orientation.portrait ? 120.0 : 90.0, 202 | child: RTCVideoView(_localRenderer), 203 | decoration: BoxDecoration(color: Colors.black54), 204 | ), 205 | ), 206 | ]), 207 | ); 208 | }) 209 | : Container( 210 | color: Colors.yellow, 211 | child: Column( 212 | children: [ 213 | TextField( 214 | controller: textEditingController, 215 | ), 216 | FlatButton( 217 | child: Text('Call'), 218 | color: Colors.green, 219 | onPressed: () { 220 | _invitePeer(context, textEditingController.text, false); 221 | }, 222 | ) 223 | ], 224 | ), 225 | ), 226 | ); 227 | } 228 | } 229 | 230 | class CallProvider with ChangeNotifier { 231 | String clientId = ""; 232 | 233 | void updateClientIp(String newClientId) { 234 | clientId = newClientId; 235 | notifyListeners(); 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /webrtc-flutter-client/lib/pages/webrtc/device_info.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | class DeviceInfo { 4 | static String get label { 5 | return Platform.localHostname + '(' + Platform.operatingSystem + ")"; 6 | } 7 | 8 | static String get userAgent { 9 | return 'flutter-webrtc/' + Platform.operatingSystem + '-plugin 0.0.1'; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /webrtc-flutter-client/lib/pages/webrtc/random_string.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, Damon Douglas. All rights reserved. Use of this source code 2 | // is governed by a BSD-style license that can be found in the LICENSE file. 3 | 4 | /// Simple library for generating random ascii strings. 5 | /// 6 | /// More dartdocs go here. 7 | /// 8 | /// 9 | /// A simple usage example: 10 | /// 11 | /// import 'package:random_string/random_string.dart' as random; 12 | /// main() { 13 | /// print(randomBetween(10,20)); // some integer between 10 and 20 14 | /// print(randomNumeric(4)); // sequence of 4 random numbers i.e. 3259 15 | /// print(randomString(10)); // random sequence of 10 characters i.e. e~f93(4l- 16 | /// print(randomAlpha(5)); // random sequence of 5 alpha characters i.e. aRztC 17 | /// print(randomAlphaNumeric(10)); // random sequence of 10 alpha numeric i.e. aRztC1y32B 18 | /// } 19 | 20 | library random_string; 21 | 22 | import 'dart:math'; 23 | 24 | const ASCII_START = 33; 25 | const ASCII_END = 126; 26 | const NUMERIC_START = 48; 27 | const NUMERIC_END = 57; 28 | const LOWER_ALPHA_START = 97; 29 | const LOWER_ALPHA_END = 122; 30 | const UPPER_ALPHA_START = 65; 31 | const UPPER_ALPHA_END = 90; 32 | 33 | /// Generates a random integer where [from] <= [to]. 34 | int randomBetween(int from, int to) { 35 | if (from > to) throw Exception('$from cannot be > $to'); 36 | var rand = Random(); 37 | return ((to - from) * rand.nextDouble()).toInt() + from; 38 | } 39 | 40 | /// Generates a random string of [length] with characters 41 | /// between ascii [from] to [to]. 42 | /// Defaults to characters of ascii '!' to '~'. 43 | String randomString(int length, {int from: ASCII_START, int to: ASCII_END}) { 44 | return String.fromCharCodes( 45 | List.generate(length, (index) => randomBetween(from, to))); 46 | } 47 | 48 | /// Generates a random string of [length] with only numeric characters. 49 | String randomNumeric(int length) => 50 | randomString(length, from: NUMERIC_START, to: NUMERIC_END); 51 | /* 52 | /// Generates a random string of [length] with only alpha characters. 53 | String randomAlpha(int length) { 54 | var lowerAlphaLength = randomBetween(0, length); 55 | var upperAlphaLength = length - lowerAlphaLength; 56 | var lowerAlpha = randomString(lowerAlphaLength, 57 | from: LOWER_ALPHA_START, to: LOWER_ALPHA_END); 58 | var upperAlpha = randomString(upperAlphaLength, 59 | from: UPPER_ALPHA_START, to: UPPER_ALPHA_END); 60 | return randomMerge(lowerAlpha, upperAlpha); 61 | } 62 | 63 | /// Generates a random string of [length] with alpha-numeric characters. 64 | String randomAlphaNumeric(int length) { 65 | var alphaLength = randomBetween(0, length); 66 | var numericLength = length - alphaLength; 67 | var alpha = randomAlpha(alphaLength); 68 | var numeric = randomNumeric(numericLength); 69 | return randomMerge(alpha, numeric); 70 | } 71 | 72 | /// Merge [a] with [b] and scramble characters. 73 | String randomMerge(String a, String b) { 74 | var mergedCodeUnits = List.from("$a$b".codeUnits); 75 | mergedCodeUnits.shuffle(); 76 | return String.fromCharCodes(mergedCodeUnits); 77 | }*/ 78 | -------------------------------------------------------------------------------- /webrtc-flutter-client/lib/pages/webrtc/signaling.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2020 Nhan Cao 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | import 'dart:async'; 26 | 27 | import 'package:flutter_webrtc/webrtc.dart'; 28 | 29 | import 'device_info.dart'; 30 | import 'turn.dart'; 31 | import 'websocket.dart'; 32 | 33 | enum SignalingState { 34 | CallStateNew, 35 | CallStateRinging, 36 | CallStateInvite, 37 | CallStateConnected, 38 | CallStateBye, 39 | ConnectionOpen, 40 | ConnectionClosed, 41 | ConnectionError, 42 | } 43 | 44 | /* 45 | * callbacks for Signaling API. 46 | */ 47 | typedef void SignalingStateCallback(SignalingState state); 48 | typedef void StreamStateCallback(MediaStream stream); 49 | typedef void OtherEventCallback(dynamic event); 50 | typedef void DataChannelMessageCallback( 51 | RTCDataChannel dc, RTCDataChannelMessage data); 52 | typedef void DataChannelCallback(RTCDataChannel dc); 53 | 54 | class Signaling { 55 | SimpleWebSocket _socket; 56 | var _host; 57 | var _port = 3000; 58 | RTCPeerConnection peerConnection; 59 | RTCDataChannel dataChannel; 60 | var _remoteCandidates = []; 61 | var _turnCredential; 62 | 63 | MediaStream _localStream; 64 | List _remoteStreams; 65 | SignalingStateCallback onStateChange; 66 | StreamStateCallback onLocalStream; 67 | StreamStateCallback onAddRemoteStream; 68 | StreamStateCallback onRemoveRemoteStream; 69 | OtherEventCallback onPeersUpdate; 70 | OtherEventCallback onEventUpdate; 71 | DataChannelMessageCallback onDataChannelMessage; 72 | DataChannelCallback onDataChannel; 73 | 74 | Map _iceServers = { 75 | 'iceServers': [ 76 | {'url': 'stun:stun.l.google.com:19302'}, 77 | /* 78 | * turn server configuration example. 79 | { 80 | 'url': 'turn:123.45.67.89:3478', 81 | 'username': 'change_to_real_user', 82 | 'credential': 'change_to_real_secret' 83 | }, 84 | */ 85 | ] 86 | }; 87 | 88 | final Map _config = { 89 | 'mandatory': {}, 90 | 'optional': [ 91 | {'DtlsSrtpKeyAgreement': true}, 92 | ], 93 | }; 94 | 95 | final Map _constraints = { 96 | 'mandatory': { 97 | 'OfferToReceiveAudio': true, 98 | 'OfferToReceiveVideo': true, 99 | }, 100 | 'optional': [], 101 | }; 102 | 103 | final Map _dcConstraints = { 104 | 'mandatory': { 105 | 'OfferToReceiveAudio': false, 106 | 'OfferToReceiveVideo': false, 107 | }, 108 | 'optional': [], 109 | }; 110 | 111 | Signaling(this._host); 112 | 113 | close() { 114 | if (_localStream != null) { 115 | _localStream.dispose(); 116 | _localStream = null; 117 | } 118 | 119 | if (peerConnection != null) { 120 | peerConnection.close(); 121 | } 122 | if (_socket != null) _socket.close(); 123 | } 124 | 125 | void switchCamera() { 126 | if (_localStream != null) { 127 | _localStream.getVideoTracks()[0].switchCamera(); 128 | } 129 | } 130 | 131 | void invite(String peerId, String media, useScreen) { 132 | if (this.onStateChange != null) { 133 | this.onStateChange(SignalingState.CallStateNew); 134 | } 135 | 136 | _createPeerConnection(peerId, media, useScreen, isHost: true).then((pc) { 137 | peerConnection = pc; 138 | if (media == 'data') { 139 | _createDataChannel(peerId, pc); 140 | } 141 | _createOffer(peerId, pc, media); 142 | }); 143 | } 144 | 145 | void bye() { 146 | if (_localStream != null) { 147 | _localStream.dispose(); 148 | _localStream = null; 149 | } 150 | 151 | if (dataChannel != null) { 152 | dataChannel.close(); 153 | } 154 | if (peerConnection != null) { 155 | peerConnection.close(); 156 | } 157 | 158 | if (this.onStateChange != null) { 159 | this.onStateChange(SignalingState.CallStateBye); 160 | } 161 | _remoteCandidates.clear(); 162 | } 163 | 164 | void onMessage(tag, message) async { 165 | switch (tag) { 166 | case OFFER_EVENT: 167 | { 168 | var id = 'caller'; 169 | var description = message; 170 | var media = 'call'; 171 | 172 | if (this.onStateChange != null) { 173 | this.onStateChange(SignalingState.CallStateNew); 174 | } 175 | 176 | var pc = await _createPeerConnection(id, media, false); 177 | peerConnection = pc; 178 | await pc.setRemoteDescription( 179 | RTCSessionDescription(description['sdp'], description['type'])); 180 | await _createAnswer(id, pc, media); 181 | if (this._remoteCandidates.length > 0) { 182 | _remoteCandidates.forEach((candidate) async { 183 | await pc.addCandidate(candidate); 184 | }); 185 | _remoteCandidates.clear(); 186 | } 187 | } 188 | break; 189 | case ANSWER_EVENT: 190 | { 191 | var description = message; 192 | var pc = peerConnection; 193 | if (pc != null) { 194 | await pc.setRemoteDescription( 195 | RTCSessionDescription(description['sdp'], description['type'])); 196 | } 197 | } 198 | break; 199 | case ICE_CANDIDATE_EVENT: 200 | { 201 | var candidateMap = message; 202 | if (candidateMap != null) { 203 | var pc = peerConnection; 204 | RTCIceCandidate candidate = RTCIceCandidate( 205 | candidateMap['candidate'], 206 | candidateMap['sdpMid'], 207 | candidateMap['sdpMLineIndex']); 208 | if (pc != null) { 209 | await pc.addCandidate(candidate); 210 | } else { 211 | _remoteCandidates.add(candidate); 212 | } 213 | } 214 | } 215 | break; 216 | case CLIENT_ID_EVENT: 217 | { 218 | if (this.onEventUpdate != null) { 219 | this.onEventUpdate({'clientId': 'Id: $message'}); 220 | } 221 | } 222 | break; 223 | default: 224 | break; 225 | } 226 | } 227 | 228 | void connect() async { 229 | var url = 'http://$_host:$_port'; 230 | _socket = SimpleWebSocket(url); 231 | 232 | print('connect to $url'); 233 | 234 | if (_turnCredential == null) { 235 | try { 236 | _turnCredential = await getTurnCredential(_host, _port); 237 | /*{ 238 | "username": "1584195784:mbzrxpgjys", 239 | "password": "isyl6FF6nqMTB9/ig5MrMRUXqZg", 240 | "ttl": 86400, 241 | "uris": ["turn:127.0.0.1:19302?transport=udp"] 242 | } 243 | */ 244 | _iceServers = { 245 | 'iceServers': [ 246 | { 247 | 'url': _turnCredential['uris'][0], 248 | 'username': _turnCredential['username'], 249 | 'credential': _turnCredential['password'] 250 | }, 251 | ] 252 | }; 253 | } catch (e) {} 254 | } 255 | 256 | _socket.onOpen = () { 257 | print('onOpen'); 258 | this?.onStateChange(SignalingState.ConnectionOpen); 259 | print({'name': DeviceInfo.label, 'user_agent': DeviceInfo.userAgent}); 260 | }; 261 | 262 | _socket.onMessage = (tag, message) { 263 | print('Received data: $tag - $message'); 264 | this.onMessage(tag, message); 265 | }; 266 | 267 | _socket.onClose = (int code, String reason) { 268 | print('Closed by server [$code => $reason]!'); 269 | if (this.onStateChange != null) { 270 | this.onStateChange(SignalingState.ConnectionClosed); 271 | } 272 | }; 273 | 274 | await _socket.connect(); 275 | } 276 | 277 | Future createStream(media, userScreen) async { 278 | final Map mediaConstraints = { 279 | 'audio': true, 280 | 'video': { 281 | 'mandatory': { 282 | 'minWidth': 283 | '640', // Provide your own width, height and frame rate here 284 | 'minHeight': '480', 285 | 'minFrameRate': '30', 286 | }, 287 | 'facingMode': 'user', 288 | 'optional': [], 289 | } 290 | }; 291 | 292 | MediaStream stream = userScreen 293 | ? await navigator.getDisplayMedia(mediaConstraints) 294 | : await navigator.getUserMedia(mediaConstraints); 295 | if (this.onLocalStream != null) { 296 | this.onLocalStream(stream); 297 | } 298 | return stream; 299 | } 300 | 301 | _createPeerConnection(id, media, userScreen, {isHost = false}) async { 302 | if (media != 'data') _localStream = await createStream(media, userScreen); 303 | RTCPeerConnection pc = await createPeerConnection(_iceServers, _config); 304 | if (media != 'data') pc.addStream(_localStream); 305 | pc.onIceCandidate = (candidate) { 306 | final iceCandidate = { 307 | 'sdpMLineIndex': candidate.sdpMlineIndex, 308 | 'sdpMid': candidate.sdpMid, 309 | 'candidate': candidate.candidate, 310 | }; 311 | emitIceCandidateEvent(isHost, iceCandidate); 312 | }; 313 | 314 | print('Turn on speaker phone'); 315 | _localStream.getAudioTracks()[0].enableSpeakerphone(true); 316 | 317 | pc.onIceConnectionState = (state) { 318 | print('onIceConnectionState $state'); 319 | if (state == RTCIceConnectionState.RTCIceConnectionStateClosed || 320 | state == RTCIceConnectionState.RTCIceConnectionStateFailed) { 321 | bye(); 322 | } 323 | }; 324 | 325 | pc.onAddStream = (stream) { 326 | if (this.onAddRemoteStream != null) this.onAddRemoteStream(stream); 327 | //_remoteStreams.add(stream); 328 | }; 329 | 330 | pc.onRemoveStream = (stream) { 331 | if (this.onRemoveRemoteStream != null) this.onRemoveRemoteStream(stream); 332 | _remoteStreams.removeWhere((it) { 333 | return (it.id == stream.id); 334 | }); 335 | }; 336 | 337 | pc.onDataChannel = (channel) { 338 | _addDataChannel(id, channel); 339 | }; 340 | 341 | return pc; 342 | } 343 | 344 | _addDataChannel(id, RTCDataChannel channel) { 345 | channel.onDataChannelState = (e) {}; 346 | channel.onMessage = (RTCDataChannelMessage data) { 347 | if (this.onDataChannelMessage != null) 348 | this.onDataChannelMessage(channel, data); 349 | }; 350 | dataChannel = channel; 351 | 352 | if (this.onDataChannel != null) this.onDataChannel(channel); 353 | } 354 | 355 | _createDataChannel(id, RTCPeerConnection pc, {label: 'fileTransfer'}) async { 356 | RTCDataChannelInit dataChannelDict = RTCDataChannelInit(); 357 | RTCDataChannel channel = await pc.createDataChannel(label, dataChannelDict); 358 | _addDataChannel(id, channel); 359 | } 360 | 361 | _createOffer(String id, RTCPeerConnection pc, String media) async { 362 | try { 363 | RTCSessionDescription s = 364 | await pc.createOffer(media == 'data' ? _dcConstraints : _constraints); 365 | pc.setLocalDescription(s); 366 | 367 | final description = {'sdp': s.sdp, 'type': s.type}; 368 | emitOfferEvent(id, description); 369 | } catch (e) { 370 | print(e.toString()); 371 | } 372 | } 373 | 374 | _createAnswer(String id, RTCPeerConnection pc, media) async { 375 | try { 376 | RTCSessionDescription s = await pc 377 | .createAnswer(media == 'data' ? _dcConstraints : _constraints); 378 | pc.setLocalDescription(s); 379 | 380 | final description = {'sdp': s.sdp, 'type': s.type}; 381 | emitAnswerEvent(description); 382 | } catch (e) { 383 | print(e.toString()); 384 | } 385 | } 386 | 387 | _send(event, data) { 388 | _socket.send(event, data); 389 | } 390 | 391 | emitOfferEvent(peerId, description) { 392 | _send(OFFER_EVENT, {'peerId': peerId, 'description': description}); 393 | } 394 | 395 | emitAnswerEvent(description) { 396 | _send(ANSWER_EVENT, {'description': description}); 397 | } 398 | 399 | emitIceCandidateEvent(isHost, candidate) { 400 | _send(ICE_CANDIDATE_EVENT, {'isHost': isHost, 'candidate': candidate}); 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /webrtc-flutter-client/lib/pages/webrtc/turn.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:async'; 3 | import 'dart:io'; 4 | 5 | Future getTurnCredential(String host, int port) async { 6 | HttpClient client = HttpClient(context: SecurityContext()); 7 | client.badCertificateCallback = 8 | (X509Certificate cert, String host, int port) { 9 | print('getTurnCredential: Allow self-signed certificate => $host:$port. '); 10 | return true; 11 | }; 12 | var url = 'https://$host:$port/api/turn?service=turn&username=flutter-webrtc'; 13 | var request = await client.getUrl(Uri.parse(url)); 14 | var response = await request.close(); 15 | var responseBody = await response.transform(Utf8Decoder()).join(); 16 | print('getTurnCredential:response => $responseBody.'); 17 | Map data = JsonDecoder().convert(responseBody); 18 | return data; 19 | } 20 | -------------------------------------------------------------------------------- /webrtc-flutter-client/lib/pages/webrtc/websocket.dart: -------------------------------------------------------------------------------- 1 | import 'package:socket_io_client/socket_io_client.dart' as IO; 2 | 3 | typedef void OnMessageCallback(String tag, dynamic msg); 4 | typedef void OnCloseCallback(int code, String reason); 5 | typedef void OnOpenCallback(); 6 | 7 | const CLIENT_ID_EVENT = 'client-id-event'; 8 | const OFFER_EVENT = 'offer-event'; 9 | const ANSWER_EVENT = 'answer-event'; 10 | const ICE_CANDIDATE_EVENT = 'ice-candidate-event'; 11 | 12 | class SimpleWebSocket { 13 | String url; 14 | IO.Socket socket; 15 | OnOpenCallback onOpen; 16 | OnMessageCallback onMessage; 17 | OnCloseCallback onClose; 18 | 19 | SimpleWebSocket(this.url); 20 | 21 | connect() async { 22 | try { 23 | socket = IO.io(url, { 24 | 'transports': ['websocket'] 25 | }); 26 | // Dart client 27 | socket.on('connect', (_) { 28 | print('connected'); 29 | onOpen(); 30 | }); 31 | socket.on(CLIENT_ID_EVENT, (data) { 32 | onMessage(CLIENT_ID_EVENT, data); 33 | }); 34 | socket.on(OFFER_EVENT, (data) { 35 | onMessage(OFFER_EVENT, data); 36 | }); 37 | socket.on(ANSWER_EVENT, (data) { 38 | onMessage(ANSWER_EVENT, data); 39 | }); 40 | socket.on(ICE_CANDIDATE_EVENT, (data) { 41 | onMessage(ICE_CANDIDATE_EVENT, data); 42 | }); 43 | socket.on('exception', (e) => print('Exception: $e')); 44 | socket.on('connect_error', (e) => print('Connect error: $e')); 45 | socket.on('disconnect', (e) { 46 | print('disconnect'); 47 | onClose(0, e); 48 | }); 49 | socket.on('fromServer', (_) => print(_)); 50 | } catch (e) { 51 | this.onClose(500, e.toString()); 52 | } 53 | } 54 | 55 | send(event, data) { 56 | if (socket != null) { 57 | socket.emit(event, data); 58 | print('send: $event - $data'); 59 | } 60 | } 61 | 62 | close() { 63 | if (socket != null) socket.close(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /webrtc-flutter-client/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | analyzer: 5 | dependency: transitive 6 | description: 7 | name: analyzer 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "0.38.0" 11 | archive: 12 | dependency: transitive 13 | description: 14 | name: archive 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.0.13" 18 | args: 19 | dependency: transitive 20 | description: 21 | name: args 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.6.0" 25 | async: 26 | dependency: transitive 27 | description: 28 | name: async 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.4.1" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.0.0" 39 | build: 40 | dependency: transitive 41 | description: 42 | name: build 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.2.0" 46 | build_config: 47 | dependency: transitive 48 | description: 49 | name: build_config 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "0.4.1+1" 53 | build_daemon: 54 | dependency: transitive 55 | description: 56 | name: build_daemon 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "2.1.0" 60 | build_resolvers: 61 | dependency: transitive 62 | description: 63 | name: build_resolvers 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.1.1" 67 | build_runner: 68 | dependency: "direct dev" 69 | description: 70 | name: build_runner 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.7.1" 74 | build_runner_core: 75 | dependency: transitive 76 | description: 77 | name: build_runner_core 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "4.1.0" 81 | built_collection: 82 | dependency: transitive 83 | description: 84 | name: built_collection 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "4.1.0" 88 | built_value: 89 | dependency: transitive 90 | description: 91 | name: built_value 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "6.7.1" 95 | charcode: 96 | dependency: transitive 97 | description: 98 | name: charcode 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "1.1.3" 102 | checked_yaml: 103 | dependency: transitive 104 | description: 105 | name: checked_yaml 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "1.0.2" 109 | clock: 110 | dependency: transitive 111 | description: 112 | name: clock 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "1.0.1" 116 | code_builder: 117 | dependency: transitive 118 | description: 119 | name: code_builder 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "3.1.3" 123 | collection: 124 | dependency: transitive 125 | description: 126 | name: collection 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "1.14.12" 130 | convert: 131 | dependency: transitive 132 | description: 133 | name: convert 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "2.1.1" 137 | crypto: 138 | dependency: transitive 139 | description: 140 | name: crypto 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "2.1.4" 144 | csslib: 145 | dependency: transitive 146 | description: 147 | name: csslib 148 | url: "https://pub.dartlang.org" 149 | source: hosted 150 | version: "0.14.6" 151 | cupertino_icons: 152 | dependency: "direct main" 153 | description: 154 | name: cupertino_icons 155 | url: "https://pub.dartlang.org" 156 | source: hosted 157 | version: "0.1.2" 158 | dart_style: 159 | dependency: transitive 160 | description: 161 | name: dart_style 162 | url: "https://pub.dartlang.org" 163 | source: hosted 164 | version: "1.2.10" 165 | fake_async: 166 | dependency: transitive 167 | description: 168 | name: fake_async 169 | url: "https://pub.dartlang.org" 170 | source: hosted 171 | version: "1.1.0" 172 | fixnum: 173 | dependency: transitive 174 | description: 175 | name: fixnum 176 | url: "https://pub.dartlang.org" 177 | source: hosted 178 | version: "0.10.9" 179 | flutter: 180 | dependency: "direct main" 181 | description: flutter 182 | source: sdk 183 | version: "0.0.0" 184 | flutter_launcher_icons: 185 | dependency: "direct dev" 186 | description: 187 | name: flutter_launcher_icons 188 | url: "https://pub.dartlang.org" 189 | source: hosted 190 | version: "0.7.3" 191 | flutter_localizations: 192 | dependency: "direct main" 193 | description: flutter 194 | source: sdk 195 | version: "0.0.0" 196 | flutter_test: 197 | dependency: "direct dev" 198 | description: flutter 199 | source: sdk 200 | version: "0.0.0" 201 | flutter_webrtc: 202 | dependency: "direct main" 203 | description: 204 | name: flutter_webrtc 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "0.2.8" 208 | front_end: 209 | dependency: transitive 210 | description: 211 | name: front_end 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "0.1.22" 215 | glob: 216 | dependency: transitive 217 | description: 218 | name: glob 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "1.1.7" 222 | graphs: 223 | dependency: transitive 224 | description: 225 | name: graphs 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "0.2.0" 229 | html: 230 | dependency: transitive 231 | description: 232 | name: html 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "0.14.0+3" 236 | http: 237 | dependency: transitive 238 | description: 239 | name: http 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "0.12.0+2" 243 | http_multi_server: 244 | dependency: transitive 245 | description: 246 | name: http_multi_server 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "2.1.0" 250 | http_parser: 251 | dependency: transitive 252 | description: 253 | name: http_parser 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "3.1.3" 257 | image: 258 | dependency: transitive 259 | description: 260 | name: image 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "2.1.12" 264 | intl: 265 | dependency: transitive 266 | description: 267 | name: intl 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "0.16.1" 271 | io: 272 | dependency: transitive 273 | description: 274 | name: io 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "0.3.3" 278 | js: 279 | dependency: transitive 280 | description: 281 | name: js 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "0.6.1+1" 285 | json_annotation: 286 | dependency: transitive 287 | description: 288 | name: json_annotation 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "3.0.0" 292 | kernel: 293 | dependency: transitive 294 | description: 295 | name: kernel 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "0.3.22" 299 | logging: 300 | dependency: transitive 301 | description: 302 | name: logging 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "0.11.3+2" 306 | matcher: 307 | dependency: transitive 308 | description: 309 | name: matcher 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "0.12.6" 313 | meta: 314 | dependency: transitive 315 | description: 316 | name: meta 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "1.1.8" 320 | mime: 321 | dependency: transitive 322 | description: 323 | name: mime 324 | url: "https://pub.dartlang.org" 325 | source: hosted 326 | version: "0.9.6+2" 327 | nested: 328 | dependency: transitive 329 | description: 330 | name: nested 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "0.0.4" 334 | package_config: 335 | dependency: transitive 336 | description: 337 | name: package_config 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "1.0.5" 341 | package_resolver: 342 | dependency: transitive 343 | description: 344 | name: package_resolver 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "1.0.10" 348 | path: 349 | dependency: transitive 350 | description: 351 | name: path 352 | url: "https://pub.dartlang.org" 353 | source: hosted 354 | version: "1.7.0" 355 | pedantic: 356 | dependency: transitive 357 | description: 358 | name: pedantic 359 | url: "https://pub.dartlang.org" 360 | source: hosted 361 | version: "1.8.0+1" 362 | petitparser: 363 | dependency: transitive 364 | description: 365 | name: petitparser 366 | url: "https://pub.dartlang.org" 367 | source: hosted 368 | version: "2.4.0" 369 | pool: 370 | dependency: transitive 371 | description: 372 | name: pool 373 | url: "https://pub.dartlang.org" 374 | source: hosted 375 | version: "1.3.6" 376 | provider: 377 | dependency: "direct main" 378 | description: 379 | name: provider 380 | url: "https://pub.dartlang.org" 381 | source: hosted 382 | version: "4.1.3" 383 | pub_semver: 384 | dependency: transitive 385 | description: 386 | name: pub_semver 387 | url: "https://pub.dartlang.org" 388 | source: hosted 389 | version: "1.4.2" 390 | pubspec_parse: 391 | dependency: transitive 392 | description: 393 | name: pubspec_parse 394 | url: "https://pub.dartlang.org" 395 | source: hosted 396 | version: "0.1.5" 397 | quiver: 398 | dependency: transitive 399 | description: 400 | name: quiver 401 | url: "https://pub.dartlang.org" 402 | source: hosted 403 | version: "2.1.3" 404 | shelf: 405 | dependency: transitive 406 | description: 407 | name: shelf 408 | url: "https://pub.dartlang.org" 409 | source: hosted 410 | version: "0.7.5" 411 | shelf_web_socket: 412 | dependency: transitive 413 | description: 414 | name: shelf_web_socket 415 | url: "https://pub.dartlang.org" 416 | source: hosted 417 | version: "0.2.3" 418 | sky_engine: 419 | dependency: transitive 420 | description: flutter 421 | source: sdk 422 | version: "0.0.99" 423 | socket_io_client: 424 | dependency: "direct main" 425 | description: 426 | name: socket_io_client 427 | url: "https://pub.dartlang.org" 428 | source: hosted 429 | version: "0.9.9" 430 | socket_io_common: 431 | dependency: transitive 432 | description: 433 | name: socket_io_common 434 | url: "https://pub.dartlang.org" 435 | source: hosted 436 | version: "0.9.1" 437 | source_span: 438 | dependency: transitive 439 | description: 440 | name: source_span 441 | url: "https://pub.dartlang.org" 442 | source: hosted 443 | version: "1.7.0" 444 | stack_trace: 445 | dependency: transitive 446 | description: 447 | name: stack_trace 448 | url: "https://pub.dartlang.org" 449 | source: hosted 450 | version: "1.9.3" 451 | stream_channel: 452 | dependency: transitive 453 | description: 454 | name: stream_channel 455 | url: "https://pub.dartlang.org" 456 | source: hosted 457 | version: "2.0.0" 458 | stream_transform: 459 | dependency: transitive 460 | description: 461 | name: stream_transform 462 | url: "https://pub.dartlang.org" 463 | source: hosted 464 | version: "0.0.14+1" 465 | string_scanner: 466 | dependency: transitive 467 | description: 468 | name: string_scanner 469 | url: "https://pub.dartlang.org" 470 | source: hosted 471 | version: "1.0.5" 472 | term_glyph: 473 | dependency: transitive 474 | description: 475 | name: term_glyph 476 | url: "https://pub.dartlang.org" 477 | source: hosted 478 | version: "1.1.0" 479 | test_api: 480 | dependency: transitive 481 | description: 482 | name: test_api 483 | url: "https://pub.dartlang.org" 484 | source: hosted 485 | version: "0.2.16" 486 | timing: 487 | dependency: transitive 488 | description: 489 | name: timing 490 | url: "https://pub.dartlang.org" 491 | source: hosted 492 | version: "0.1.1+2" 493 | typed_data: 494 | dependency: transitive 495 | description: 496 | name: typed_data 497 | url: "https://pub.dartlang.org" 498 | source: hosted 499 | version: "1.1.6" 500 | vector_math: 501 | dependency: transitive 502 | description: 503 | name: vector_math 504 | url: "https://pub.dartlang.org" 505 | source: hosted 506 | version: "2.0.8" 507 | watcher: 508 | dependency: transitive 509 | description: 510 | name: watcher 511 | url: "https://pub.dartlang.org" 512 | source: hosted 513 | version: "0.9.7+10" 514 | web_socket_channel: 515 | dependency: transitive 516 | description: 517 | name: web_socket_channel 518 | url: "https://pub.dartlang.org" 519 | source: hosted 520 | version: "1.0.15" 521 | xml: 522 | dependency: transitive 523 | description: 524 | name: xml 525 | url: "https://pub.dartlang.org" 526 | source: hosted 527 | version: "3.6.1" 528 | yaml: 529 | dependency: transitive 530 | description: 531 | name: yaml 532 | url: "https://pub.dartlang.org" 533 | source: hosted 534 | version: "2.1.15" 535 | sdks: 536 | dart: ">=2.7.0 <3.0.0" 537 | flutter: ">=1.16.0 <2.0.0" 538 | -------------------------------------------------------------------------------- /webrtc-flutter-client/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: nft 2 | description: Flutter Template 3 | version: 1.0.0+1 4 | 5 | environment: 6 | sdk: ">=2.3.0 <3.0.0" 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | flutter_localizations: 12 | sdk: flutter 13 | cupertino_icons: ^0.1.2 14 | flutter_webrtc: ^0.2.8 15 | socket_io_client: ^0.9.9 16 | provider: ^4.1.3 17 | 18 | dev_dependencies: 19 | flutter_launcher_icons: ^0.7.3 20 | flutter_test: 21 | sdk: flutter 22 | build_runner: ^1.7.1 23 | 24 | flutter_icons: 25 | image_path: "assets/base/icons/app_icon.png" 26 | android: true # can specify file name here e.g. "ic_launcher" 27 | ios: true # can specify file name here e.g. "My-Launcher-Icon" 28 | image_path_android: "assets/base/icons/app_icon.png" 29 | image_path_ios: "assets/base/icons/app_icon.png" 30 | adaptive_icon_background: "assets/base/icons/app_icon.png" # only available for Android 8.0 devices and above 31 | adaptive_icon_foreground: "assets/base/icons/app_icon.png" # only available for Android 8.0 devices and above 32 | # To Generate icon 33 | # flutter pub get 34 | # flutter pub run flutter_launcher_icons:main 35 | 36 | flutter: 37 | uses-material-design: true 38 | assets: 39 | - assets/base/icons/ 40 | - assets/base/fonts/ 41 | - assets/app/icons/ 42 | - assets/app/fonts/ 43 | 44 | fonts: 45 | - family: SFProText 46 | fonts: 47 | - asset: assets/base/fonts/SFProText-Light.ttf 48 | weight: 300 49 | - asset: assets/base/fonts/SFProText-Regular.ttf 50 | weight: 400 51 | - asset: assets/base/fonts/SFProText-Medium.ttf 52 | weight: 500 53 | - asset: assets/base/fonts/SFProText-Semibold.ttf 54 | weight: 600 55 | - asset: assets/base/fonts/SFProText-Bold.ttf 56 | weight: 700 57 | - family: AvenirNextLTPro-Regular 58 | fonts: 59 | - asset: assets/base/fonts/AvenirNextLTPro-Regular.otf 60 | - family: AvenirNextLTPro-Demi 61 | fonts: 62 | - asset: assets/base/fonts/AvenirNextLTPro-Demi.otf 63 | - family: AvenirNextLTPro-Bold 64 | fonts: 65 | - asset: assets/base/fonts/AvenirNextLTPro-Bold.otf 66 | -------------------------------------------------------------------------------- /webrtc-flutter-client/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:nft/my_app.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:flutter_test/flutter_test.dart'; 11 | 12 | void main() { 13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 14 | // Build our app and trigger a frame. 15 | await tester.pumpWidget(MyApp()); 16 | 17 | // Verify that our counter starts at 0. 18 | expect(find.text('0'), findsOneWidget); 19 | expect(find.text('1'), findsNothing); 20 | 21 | // Tap the '+' icon and trigger a frame. 22 | await tester.tap(find.byIcon(Icons.add)); 23 | await tester.pump(); 24 | 25 | // Verify that our counter has incremented. 26 | expect(find.text('0'), findsNothing); 27 | expect(find.text('1'), findsOneWidget); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['@typescript-eslint/eslint-plugin'], 8 | extends: [ 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | 'prettier', 12 | 'prettier/@typescript-eslint', 13 | ], 14 | root: true, 15 | env: { 16 | node: true, 17 | jest: true, 18 | }, 19 | ignorePatterns: ["client/", "node_modules"], 20 | rules: { 21 | '@typescript-eslint/interface-name-prefix': 'off', 22 | '@typescript-eslint/explicit-function-return-type': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/.gitignore: -------------------------------------------------------------------------------- 1 | dis# Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/**/workspace.xml 8 | .idea/**/tasks.xml 9 | .idea/dictionaries 10 | 11 | # Sensitive or high-churn files: 12 | .idea/**/dataSources/ 13 | .idea/**/dataSources.ids 14 | .idea/**/dataSources.xml 15 | .idea/**/dataSources.local.xml 16 | .idea/**/sqlDataSources.xml 17 | .idea/**/dynamic.xml 18 | .idea/**/uiDesigner.xml 19 | 20 | # Gradle: 21 | .idea/**/gradle.xml 22 | .idea/**/libraries 23 | 24 | # CMake 25 | cmake-build-debug/ 26 | 27 | # Mongo Explorer plugin: 28 | .idea/**/mongoSettings.xml 29 | 30 | ## File-based project format: 31 | *.iws 32 | 33 | ## Plugin-specific files: 34 | 35 | # IntelliJ 36 | out/ 37 | 38 | # mpeltonen/sbt-idea plugin 39 | .idea_modules/ 40 | 41 | # JIRA plugin 42 | atlassian-ide-plugin.xml 43 | 44 | # Cursive Clojure plugin 45 | .idea/replstate.xml 46 | 47 | # Crashlytics plugin (for Android Studio and IntelliJ) 48 | com_crashlytics_export_strings.xml 49 | crashlytics.properties 50 | crashlytics-build.properties 51 | fabric.properties 52 | ### VisualStudio template 53 | ## Ignore Visual Studio temporary files, build results, and 54 | ## files generated by popular Visual Studio add-ons. 55 | ## 56 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 57 | 58 | # User-specific files 59 | *.suo 60 | *.user 61 | *.userosscache 62 | *.sln.docstates 63 | 64 | # User-specific files (MonoDevelop/Xamarin Studio) 65 | *.userprefs 66 | 67 | # Build results 68 | [Dd]ebug/ 69 | [Dd]ebugPublic/ 70 | [Rr]elease/ 71 | [Rr]eleases/ 72 | x64/ 73 | x86/ 74 | bld/ 75 | [Bb]in/ 76 | [Oo]bj/ 77 | [Ll]og/ 78 | 79 | # Visual Studio 2015 cache/options directory 80 | .vs/ 81 | # Uncomment if you have tasks that create the project's static files in wwwroot 82 | #wwwroot/ 83 | 84 | # MSTest test Results 85 | [Tt]est[Rr]esult*/ 86 | [Bb]uild[Ll]og.* 87 | 88 | # NUNIT 89 | *.VisualState.xml 90 | TestResult.xml 91 | 92 | # Build Results of an ATL Project 93 | [Dd]ebugPS/ 94 | [Rr]eleasePS/ 95 | dlldata.c 96 | 97 | # Benchmark Results 98 | BenchmarkDotNet.Artifacts/ 99 | 100 | # .NET Core 101 | project.lock.json 102 | project.fragment.lock.json 103 | artifacts/ 104 | **/Properties/launchSettings.json 105 | 106 | *_i.c 107 | *_p.c 108 | *_i.h 109 | *.ilk 110 | *.meta 111 | *.obj 112 | *.pch 113 | *.pdb 114 | *.pgc 115 | *.pgd 116 | *.rsp 117 | *.sbr 118 | *.tlb 119 | *.tli 120 | *.tlh 121 | *.tmp 122 | *.tmp_proj 123 | *.log 124 | *.vspscc 125 | *.vssscc 126 | .builds 127 | *.pidb 128 | *.svclog 129 | *.scc 130 | 131 | # Chutzpah Test files 132 | _Chutzpah* 133 | 134 | # Visual C++ cache files 135 | ipch/ 136 | *.aps 137 | *.ncb 138 | *.opendb 139 | *.opensdf 140 | *.sdf 141 | *.cachefile 142 | *.VC.db 143 | *.VC.VC.opendb 144 | 145 | # Visual Studio profiler 146 | *.psess 147 | *.vsp 148 | *.vspx 149 | *.sap 150 | 151 | # Visual Studio Trace Files 152 | *.e2e 153 | 154 | # TFS 2012 Local Workspace 155 | $tf/ 156 | 157 | # Guidance Automation Toolkit 158 | *.gpState 159 | 160 | # ReSharper is a .NET coding add-in 161 | _ReSharper*/ 162 | *.[Rr]e[Ss]harper 163 | *.DotSettings.user 164 | 165 | # JustCode is a .NET coding add-in 166 | .JustCode 167 | 168 | # TeamCity is a build add-in 169 | _TeamCity* 170 | 171 | # DotCover is a Code Coverage Tool 172 | *.dotCover 173 | 174 | # AxoCover is a Code Coverage Tool 175 | .axoCover/* 176 | !.axoCover/settings.json 177 | 178 | # Visual Studio code coverage results 179 | *.coverage 180 | *.coveragexml 181 | 182 | # NCrunch 183 | _NCrunch_* 184 | .*crunch*.local.xml 185 | nCrunchTemp_* 186 | 187 | # MightyMoose 188 | *.mm.* 189 | AutoTest.Net/ 190 | 191 | # Web workbench (sass) 192 | .sass-cache/ 193 | 194 | # Installshield output folder 195 | [Ee]xpress/ 196 | 197 | # DocProject is a documentation generator add-in 198 | DocProject/buildhelp/ 199 | DocProject/Help/*.HxT 200 | DocProject/Help/*.HxC 201 | DocProject/Help/*.hhc 202 | DocProject/Help/*.hhk 203 | DocProject/Help/*.hhp 204 | DocProject/Help/Html2 205 | DocProject/Help/html 206 | 207 | # Click-Once directory 208 | publish/ 209 | 210 | # Publish Web Output 211 | *.[Pp]ublish.xml 212 | *.azurePubxml 213 | # Note: Comment the next line if you want to checkin your web deploy settings, 214 | # but database connection strings (with potential passwords) will be unencrypted 215 | *.pubxml 216 | *.publishproj 217 | 218 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 219 | # checkin your Azure Web App publish settings, but sensitive information contained 220 | # in these scripts will be unencrypted 221 | PublishScripts/ 222 | 223 | # NuGet Packages 224 | *.nupkg 225 | # The packages folder can be ignored because of Package Restore 226 | **/[Pp]ackages/* 227 | # except build/, which is used as an MSBuild target. 228 | !**/[Pp]ackages/build/ 229 | # Uncomment if necessary however generally it will be regenerated when needed 230 | #!**/[Pp]ackages/repositories.config 231 | # NuGet v3's project.json files produces more ignorable files 232 | *.nuget.props 233 | *.nuget.targets 234 | 235 | # Microsoft Azure Build Output 236 | csx/ 237 | *.build.csdef 238 | 239 | # Microsoft Azure Emulator 240 | ecf/ 241 | rcf/ 242 | 243 | # Windows Store app package directories and files 244 | AppPackages/ 245 | BundleArtifacts/ 246 | Package.StoreAssociation.xml 247 | _pkginfo.txt 248 | *.appx 249 | 250 | # Visual Studio cache files 251 | # files ending in .cache can be ignored 252 | *.[Cc]ache 253 | # but keep track of directories ending in .cache 254 | !*.[Cc]ache/ 255 | 256 | # Others 257 | ClientBin/ 258 | ~$* 259 | *~ 260 | *.dbmdl 261 | *.dbproj.schemaview 262 | *.jfm 263 | *.pfx 264 | *.publishsettings 265 | orleans.codegen.cs 266 | 267 | # Since there are multiple workflows, uncomment next line to ignore bower_components 268 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 269 | #bower_components/ 270 | 271 | # RIA/Silverlight projects 272 | Generated_Code/ 273 | 274 | # Backup & report files from converting an old project file 275 | # to a newer Visual Studio version. Backup files are not needed, 276 | # because we have git ;-) 277 | _UpgradeReport_Files/ 278 | Backup*/ 279 | UpgradeLog*.XML 280 | UpgradeLog*.htm 281 | 282 | # SQL Server files 283 | *.mdf 284 | *.ldf 285 | *.ndf 286 | 287 | # Business Intelligence projects 288 | *.rdl.data 289 | *.bim.layout 290 | *.bim_*.settings 291 | 292 | # Microsoft Fakes 293 | FakesAssemblies/ 294 | 295 | # GhostDoc plugin setting file 296 | *.GhostDoc.xml 297 | 298 | # Node.js Tools for Visual Studio 299 | .ntvs_analysis.dat 300 | node_modules/ 301 | 302 | # Typescript v1 declaration files 303 | typings/ 304 | 305 | # Visual Studio 6 build log 306 | *.plg 307 | 308 | # Visual Studio 6 workspace options file 309 | *.opt 310 | 311 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 312 | *.vbw 313 | 314 | # Visual Studio LightSwitch build output 315 | **/*.HTMLClient/GeneratedArtifacts 316 | **/*.DesktopClient/GeneratedArtifacts 317 | **/*.DesktopClient/ModelManifest.xml 318 | **/*.Server/GeneratedArtifacts 319 | **/*.Server/ModelManifest.xml 320 | _Pvt_Extensions 321 | 322 | # Paket dependency manager 323 | .paket/paket.exe 324 | paket-files/ 325 | 326 | # FAKE - F# Make 327 | .fake/ 328 | 329 | # JetBrains Rider 330 | .idea/ 331 | *.sln.iml 332 | 333 | # CodeRush 334 | .cr/ 335 | 336 | # Python Tools for Visual Studio (PTVS) 337 | __pycache__/ 338 | *.pyc 339 | 340 | # Cake - Uncomment if you are using it 341 | # tools/** 342 | # !tools/packages.config 343 | 344 | # Tabs Studio 345 | *.tss 346 | 347 | # Telerik's JustMock configuration file 348 | *.jmconfig 349 | 350 | # BizTalk build output 351 | *.btp.cs 352 | *.btm.cs 353 | *.odx.cs 354 | *.xsd.cs 355 | 356 | # OpenCover UI analysis results 357 | OpenCover/ 358 | coverage/ 359 | 360 | ### macOS template 361 | # General 362 | .DS_Store 363 | .AppleDouble 364 | .LSOverride 365 | 366 | # Icon must end with two \r 367 | Icon 368 | 369 | # Thumbnails 370 | ._* 371 | 372 | # Files that might appear in the root of a volume 373 | .DocumentRevisions-V100 374 | .fseventsd 375 | .Spotlight-V100 376 | .TemporaryItems 377 | .Trashes 378 | .VolumeIcon.icns 379 | .com.apple.timemachine.donotpresent 380 | 381 | # Directories potentially created on remote AFP share 382 | .AppleDB 383 | .AppleDesktop 384 | Network Trash Folder 385 | Temporary Items 386 | .apdisk 387 | 388 | ======= 389 | # Local 390 | docker-compose.yml 391 | .env 392 | dist 393 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /webrtc-nestjs-server/README.md: -------------------------------------------------------------------------------- 1 |

2 | Nest Logo 3 |

4 | 5 | [travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master 6 | [travis-url]: https://travis-ci.org/nestjs/nest 7 | [linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux 8 | [linux-url]: https://travis-ci.org/nestjs/nest 9 | 10 |

A progressive Node.js framework for building efficient and scalable server-side applications.

11 |

12 | NPM Version 13 | Package License 14 | NPM Downloads 15 | Travis 16 | Linux 17 | Coverage 18 | Discord 19 | Backers on Open Collective 20 | Sponsors on Open Collective 21 | 22 | 23 |

24 | 26 | 27 | ## Description 28 | 29 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. 30 | 31 | ## Installation 32 | 33 | ```bash 34 | $ npm install 35 | ``` 36 | 37 | ## Running the app 38 | 39 | ```bash 40 | # development 41 | $ npm run start 42 | 43 | # watch mode 44 | $ npm run start:dev 45 | 46 | # production mode 47 | $ npm run start:prod 48 | ``` 49 | 50 | ## Test 51 | 52 | ```bash 53 | # unit tests 54 | $ npm run test 55 | 56 | # e2e tests 57 | $ npm run test:e2e 58 | 59 | # test coverage 60 | $ npm run test:cov 61 | ``` 62 | 63 | ## Support 64 | 65 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). 66 | 67 | ## Stay in touch 68 | 69 | - Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec) 70 | - Website - [https://nestjs.com](https://nestjs.com/) 71 | - Twitter - [@nestframework](https://twitter.com/nestframework) 72 | 73 | ## License 74 | 75 | Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE). 76 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nest-typescript-starter", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "Nest TypeScript starter repository", 6 | "license": "MIT", 7 | "scripts": { 8 | "prebuild": "rimraf dist", 9 | "build": "nest build", 10 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 11 | "start": "nest start", 12 | "start:dev": "nest start --watch", 13 | "start:debug": "nest start --debug --watch", 14 | "start:prod": "node dist/main", 15 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 16 | "test": "jest", 17 | "test:watch": "jest --watch", 18 | "test:cov": "jest --coverage", 19 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 20 | "test:e2e": "jest --config ./test/jest-e2e.json" 21 | }, 22 | "dependencies": { 23 | "@nestjs/common": "^7.0.5", 24 | "@nestjs/core": "^7.0.5", 25 | "@nestjs/platform-express": "^7.0.5", 26 | "@nestjs/platform-socket.io": "^7.0.5", 27 | "@nestjs/serve-static": "^2.1.0", 28 | "@nestjs/websockets": "^7.0.5", 29 | "reflect-metadata": "^0.1.13", 30 | "rimraf": "^3.0.2", 31 | "rxjs": "^6.5.4" 32 | }, 33 | "devDependencies": { 34 | "@nestjs/cli": "^6.14.2", 35 | "@nestjs/schematics": "^6.9.4", 36 | "@nestjs/testing": "^7.0.5", 37 | "@types/express": "^4.17.3", 38 | "@types/jest": "^24.9.1", 39 | "@types/node": "^13.9.4", 40 | "@types/socket.io": "^2.1.4", 41 | "@types/supertest": "^2.0.8", 42 | "@typescript-eslint/eslint-plugin": "^2.25.0", 43 | "@typescript-eslint/parser": "^2.25.0", 44 | "eslint": "^6.7.2", 45 | "eslint-config-prettier": "^6.10.1", 46 | "eslint-plugin-import": "^2.20.1", 47 | "jest": "^24.9.0", 48 | "prettier": "^1.19.1", 49 | "supertest": "^4.0.2", 50 | "ts-jest": "^24.3.0", 51 | "ts-loader": "^6.2.2", 52 | "ts-node": "^8.8.1", 53 | "tsconfig-paths": "^3.9.0", 54 | "typescript": "^3.8.3" 55 | }, 56 | "jest": { 57 | "moduleFileExtensions": [ 58 | "js", 59 | "json", 60 | "ts" 61 | ], 62 | "rootDir": "src", 63 | "testRegex": ".spec.ts$", 64 | "transform": { 65 | "^.+\\.(t|j)s$": "ts-jest" 66 | }, 67 | "collectCoverageFrom": [ 68 | "**/*.(t|j)s" 69 | ], 70 | "coverageDirectory": "../coverage", 71 | "testEnvironment": "node" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let app: TestingModule; 7 | 8 | beforeAll(async () => { 9 | app = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | }); 14 | 15 | describe('getHello', () => { 16 | it('should return "Hello World!"', () => { 17 | const appController = app.get(AppController); 18 | expect(appController.getHello()).toBe('Hello World!'); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | import { EventsModule } from './events/events.module'; 5 | 6 | @Module({ 7 | imports: [ 8 | EventsModule, 9 | ], 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }) 13 | export class AppModule {} 14 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/src/events/events.gateway.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { EventsGateway } from './events.gateway'; 3 | 4 | describe('EventsGateway', () => { 5 | let gateway: EventsGateway; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [EventsGateway], 10 | }).compile(); 11 | 12 | gateway = module.get(EventsGateway); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(gateway).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/src/events/events.gateway.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ConnectedSocket, 3 | MessageBody, 4 | OnGatewayConnection, 5 | OnGatewayDisconnect, 6 | OnGatewayInit, 7 | SubscribeMessage, 8 | WebSocketGateway, 9 | WebSocketServer, 10 | } from '@nestjs/websockets'; 11 | import {Logger} from '@nestjs/common'; 12 | import {Server, Socket} from 'socket.io'; 13 | 14 | const CLIENT_ID_EVENT = 'client-id-event'; 15 | const OFFER_EVENT = 'offer-event'; 16 | const ANSWER_EVENT = 'answer-event'; 17 | const ICE_CANDIDATE_EVENT = 'ice-candidate-event'; 18 | 19 | @WebSocketGateway() 20 | export class EventsGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect { 21 | @WebSocketServer() 22 | server: Server | undefined; 23 | 24 | private logger: Logger = new Logger('AppGateway'); 25 | private clientList: any = {}; 26 | private roomList: any = []; 27 | 28 | afterInit(server: Server) { 29 | this.logger.log(`Init socket server ${server.path()}`); 30 | } 31 | 32 | handleDisconnect(client: Socket) { 33 | this.logger.log(`Client disconnected: ${client.id}`); 34 | delete this.clientList[client.id]; 35 | for (let i = 0; i < this.roomList.length; i++) { 36 | if (this.roomList[i].host == client.id || 37 | this.roomList[i].peer == client.id) { 38 | this.roomList.splice(i, 1); 39 | } 40 | } 41 | } 42 | 43 | handleConnection(client: Socket, ...args: any[]) { 44 | this.logger.log(`Client connected: ${client.id}`); 45 | this.clientList[client.id] = client; 46 | // @nhancv 3/30/20: Send client id to client 47 | client.emit(CLIENT_ID_EVENT, client.id); 48 | } 49 | 50 | findPeerId(hostId: string) { 51 | for (let i = 0; i < this.roomList.length; i++) { 52 | if (this.roomList[i].host == hostId) { 53 | return this.roomList[i].peer; 54 | } 55 | } 56 | } 57 | 58 | findHostId(peerId: string) { 59 | for (let i = 0; i < this.roomList.length; i++) { 60 | if (this.roomList[i].peer == peerId) { 61 | return this.roomList[i].host; 62 | } 63 | } 64 | } 65 | 66 | @SubscribeMessage(OFFER_EVENT) 67 | async onOfferEvent(@ConnectedSocket() client: Socket, @MessageBody() data: { peerId: string, description: any }): Promise { 68 | console.log(data); 69 | // @nhancv 3/30/20: Create a room contain client id with peerId; 70 | this.roomList.push({host: client.id, peer: data.peerId}); 71 | 72 | const peer = this.clientList[data.peerId]; 73 | if (peer) { 74 | peer.emit(OFFER_EVENT, data.description); 75 | } else { 76 | console.log('onOfferEvent: Peer does not found'); 77 | } 78 | return 0; 79 | } 80 | 81 | @SubscribeMessage(ANSWER_EVENT) 82 | async onAnswerEvent(@ConnectedSocket() client: Socket, @MessageBody() data: { description: any }): Promise { 83 | console.log(data); 84 | const hostId = this.findHostId(client.id); 85 | const host = this.clientList[hostId]; 86 | if(host) { 87 | host.emit(ANSWER_EVENT, data.description); 88 | } else { 89 | console.log('onAnswerEvent: Host does not found'); 90 | } 91 | return 0; 92 | } 93 | 94 | @SubscribeMessage(ICE_CANDIDATE_EVENT) 95 | async onIceCandidateEvent(@ConnectedSocket() client: Socket, @MessageBody() data: { isHost: boolean, candidate: any }): Promise { 96 | console.log(data); 97 | let clientId; 98 | if (data.isHost) { 99 | clientId = this.findPeerId(client.id); 100 | } else { 101 | clientId = this.findHostId(client.id); 102 | } 103 | const peer = this.clientList[clientId]; 104 | if(peer) { 105 | peer.emit(ICE_CANDIDATE_EVENT, data.candidate); 106 | } else { 107 | console.log('onIceCandidateEvent: Peer does not found'); 108 | } 109 | return 0; 110 | } 111 | 112 | 113 | } 114 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/src/events/events.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2020 Nhan Cao 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | 26 | import {Module} from '@nestjs/common'; 27 | import {EventsGateway} from "./events.gateway"; 28 | 29 | @Module({ 30 | providers: [EventsGateway], 31 | }) 32 | export class EventsModule { 33 | } 34 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/src/main.ts: -------------------------------------------------------------------------------- 1 | import {NestFactory} from '@nestjs/core'; 2 | import {AppModule} from './app.module'; 3 | async function bootstrap() { 4 | 5 | const app = await NestFactory.create(AppModule); 6 | app.setGlobalPrefix('api'); 7 | await app.listen(3000, '0.0.0.0'); 8 | console.log(`Application is running on: ${await app.getUrl()}`); 9 | } 10 | 11 | bootstrap().then(); 12 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import * as request from 'supertest'; 2 | import { Test } from '@nestjs/testing'; 3 | import { AppModule } from './../src/app.module'; 4 | import { INestApplication } from '@nestjs/common'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeAll(async () => { 10 | const moduleFixture = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts", "client"] 4 | } 5 | -------------------------------------------------------------------------------- /webrtc-nestjs-server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { //https://www.typescriptlang.org/docs/handbook/compiler-options.html 3 | "module": "commonjs", 4 | "declaration": false, 5 | "esModuleInterop": true, 6 | "strict": true, 7 | "removeComments": true, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es2017", // es5 11 | "sourceMap": true, 12 | "outDir": "./dist", 13 | "baseUrl": "./", 14 | "typeRoots": ["./node_modules/@types"], 15 | "types": ["node"], 16 | "lib": ["es2015", "es2017", "dom"], 17 | "pretty": false, 18 | "incremental": true 19 | }, 20 | "exclude": ["node_modules", "dist", "client"] 21 | } 22 | -------------------------------------------------------------------------------- /webrtc-web-client/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['@typescript-eslint/eslint-plugin'], 8 | extends: [ 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | 'prettier', 12 | 'prettier/@typescript-eslint', 13 | ], 14 | root: true, 15 | env: { 16 | node: true, 17 | jest: true, 18 | }, 19 | ignorePatterns: ["public/", "node_modules"], 20 | rules: { 21 | '@typescript-eslint/interface-name-prefix': 'off', 22 | '@typescript-eslint/explicit-function-return-type': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /webrtc-web-client/.gitignore: -------------------------------------------------------------------------------- 1 | dis# Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/**/workspace.xml 8 | .idea/**/tasks.xml 9 | .idea/dictionaries 10 | 11 | # Sensitive or high-churn files: 12 | .idea/**/dataSources/ 13 | .idea/**/dataSources.ids 14 | .idea/**/dataSources.xml 15 | .idea/**/dataSources.local.xml 16 | .idea/**/sqlDataSources.xml 17 | .idea/**/dynamic.xml 18 | .idea/**/uiDesigner.xml 19 | 20 | # Gradle: 21 | .idea/**/gradle.xml 22 | .idea/**/libraries 23 | 24 | # CMake 25 | cmake-build-debug/ 26 | 27 | # Mongo Explorer plugin: 28 | .idea/**/mongoSettings.xml 29 | 30 | ## File-based project format: 31 | *.iws 32 | 33 | ## Plugin-specific files: 34 | 35 | # IntelliJ 36 | out/ 37 | 38 | # mpeltonen/sbt-idea plugin 39 | .idea_modules/ 40 | 41 | # JIRA plugin 42 | atlassian-ide-plugin.xml 43 | 44 | # Cursive Clojure plugin 45 | .idea/replstate.xml 46 | 47 | # Crashlytics plugin (for Android Studio and IntelliJ) 48 | com_crashlytics_export_strings.xml 49 | crashlytics.properties 50 | crashlytics-build.properties 51 | fabric.properties 52 | ### VisualStudio template 53 | ## Ignore Visual Studio temporary files, build results, and 54 | ## files generated by popular Visual Studio add-ons. 55 | ## 56 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 57 | 58 | # User-specific files 59 | *.suo 60 | *.user 61 | *.userosscache 62 | *.sln.docstates 63 | 64 | # User-specific files (MonoDevelop/Xamarin Studio) 65 | *.userprefs 66 | 67 | # Build results 68 | [Dd]ebug/ 69 | [Dd]ebugPublic/ 70 | [Rr]elease/ 71 | [Rr]eleases/ 72 | x64/ 73 | x86/ 74 | bld/ 75 | [Bb]in/ 76 | [Oo]bj/ 77 | [Ll]og/ 78 | 79 | # Visual Studio 2015 cache/options directory 80 | .vs/ 81 | # Uncomment if you have tasks that create the project's static files in wwwroot 82 | #wwwroot/ 83 | 84 | # MSTest test Results 85 | [Tt]est[Rr]esult*/ 86 | [Bb]uild[Ll]og.* 87 | 88 | # NUNIT 89 | *.VisualState.xml 90 | TestResult.xml 91 | 92 | # Build Results of an ATL Project 93 | [Dd]ebugPS/ 94 | [Rr]eleasePS/ 95 | dlldata.c 96 | 97 | # Benchmark Results 98 | BenchmarkDotNet.Artifacts/ 99 | 100 | # .NET Core 101 | project.lock.json 102 | project.fragment.lock.json 103 | artifacts/ 104 | **/Properties/launchSettings.json 105 | 106 | *_i.c 107 | *_p.c 108 | *_i.h 109 | *.ilk 110 | *.meta 111 | *.obj 112 | *.pch 113 | *.pdb 114 | *.pgc 115 | *.pgd 116 | *.rsp 117 | *.sbr 118 | *.tlb 119 | *.tli 120 | *.tlh 121 | *.tmp 122 | *.tmp_proj 123 | *.log 124 | *.vspscc 125 | *.vssscc 126 | .builds 127 | *.pidb 128 | *.svclog 129 | *.scc 130 | 131 | # Chutzpah Test files 132 | _Chutzpah* 133 | 134 | # Visual C++ cache files 135 | ipch/ 136 | *.aps 137 | *.ncb 138 | *.opendb 139 | *.opensdf 140 | *.sdf 141 | *.cachefile 142 | *.VC.db 143 | *.VC.VC.opendb 144 | 145 | # Visual Studio profiler 146 | *.psess 147 | *.vsp 148 | *.vspx 149 | *.sap 150 | 151 | # Visual Studio Trace Files 152 | *.e2e 153 | 154 | # TFS 2012 Local Workspace 155 | $tf/ 156 | 157 | # Guidance Automation Toolkit 158 | *.gpState 159 | 160 | # ReSharper is a .NET coding add-in 161 | _ReSharper*/ 162 | *.[Rr]e[Ss]harper 163 | *.DotSettings.user 164 | 165 | # JustCode is a .NET coding add-in 166 | .JustCode 167 | 168 | # TeamCity is a build add-in 169 | _TeamCity* 170 | 171 | # DotCover is a Code Coverage Tool 172 | *.dotCover 173 | 174 | # AxoCover is a Code Coverage Tool 175 | .axoCover/* 176 | !.axoCover/settings.json 177 | 178 | # Visual Studio code coverage results 179 | *.coverage 180 | *.coveragexml 181 | 182 | # NCrunch 183 | _NCrunch_* 184 | .*crunch*.local.xml 185 | nCrunchTemp_* 186 | 187 | # MightyMoose 188 | *.mm.* 189 | AutoTest.Net/ 190 | 191 | # Web workbench (sass) 192 | .sass-cache/ 193 | 194 | # Installshield output folder 195 | [Ee]xpress/ 196 | 197 | # DocProject is a documentation generator add-in 198 | DocProject/buildhelp/ 199 | DocProject/Help/*.HxT 200 | DocProject/Help/*.HxC 201 | DocProject/Help/*.hhc 202 | DocProject/Help/*.hhk 203 | DocProject/Help/*.hhp 204 | DocProject/Help/Html2 205 | DocProject/Help/html 206 | 207 | # Click-Once directory 208 | publish/ 209 | 210 | # Publish Web Output 211 | *.[Pp]ublish.xml 212 | *.azurePubxml 213 | # Note: Comment the next line if you want to checkin your web deploy settings, 214 | # but database connection strings (with potential passwords) will be unencrypted 215 | *.pubxml 216 | *.publishproj 217 | 218 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 219 | # checkin your Azure Web App publish settings, but sensitive information contained 220 | # in these scripts will be unencrypted 221 | PublishScripts/ 222 | 223 | # NuGet Packages 224 | *.nupkg 225 | # The packages folder can be ignored because of Package Restore 226 | **/[Pp]ackages/* 227 | # except build/, which is used as an MSBuild target. 228 | !**/[Pp]ackages/build/ 229 | # Uncomment if necessary however generally it will be regenerated when needed 230 | #!**/[Pp]ackages/repositories.config 231 | # NuGet v3's project.json files produces more ignorable files 232 | *.nuget.props 233 | *.nuget.targets 234 | 235 | # Microsoft Azure Build Output 236 | csx/ 237 | *.build.csdef 238 | 239 | # Microsoft Azure Emulator 240 | ecf/ 241 | rcf/ 242 | 243 | # Windows Store app package directories and files 244 | AppPackages/ 245 | BundleArtifacts/ 246 | Package.StoreAssociation.xml 247 | _pkginfo.txt 248 | *.appx 249 | 250 | # Visual Studio cache files 251 | # files ending in .cache can be ignored 252 | *.[Cc]ache 253 | # but keep track of directories ending in .cache 254 | !*.[Cc]ache/ 255 | 256 | # Others 257 | ClientBin/ 258 | ~$* 259 | *~ 260 | *.dbmdl 261 | *.dbproj.schemaview 262 | *.jfm 263 | *.pfx 264 | *.publishsettings 265 | orleans.codegen.cs 266 | 267 | # Since there are multiple workflows, uncomment next line to ignore bower_components 268 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 269 | #bower_components/ 270 | 271 | # RIA/Silverlight projects 272 | Generated_Code/ 273 | 274 | # Backup & report files from converting an old project file 275 | # to a newer Visual Studio version. Backup files are not needed, 276 | # because we have git ;-) 277 | _UpgradeReport_Files/ 278 | Backup*/ 279 | UpgradeLog*.XML 280 | UpgradeLog*.htm 281 | 282 | # SQL Server files 283 | *.mdf 284 | *.ldf 285 | *.ndf 286 | 287 | # Business Intelligence projects 288 | *.rdl.data 289 | *.bim.layout 290 | *.bim_*.settings 291 | 292 | # Microsoft Fakes 293 | FakesAssemblies/ 294 | 295 | # GhostDoc plugin setting file 296 | *.GhostDoc.xml 297 | 298 | # Node.js Tools for Visual Studio 299 | .ntvs_analysis.dat 300 | node_modules/ 301 | 302 | # Typescript v1 declaration files 303 | typings/ 304 | 305 | # Visual Studio 6 build log 306 | *.plg 307 | 308 | # Visual Studio 6 workspace options file 309 | *.opt 310 | 311 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 312 | *.vbw 313 | 314 | # Visual Studio LightSwitch build output 315 | **/*.HTMLClient/GeneratedArtifacts 316 | **/*.DesktopClient/GeneratedArtifacts 317 | **/*.DesktopClient/ModelManifest.xml 318 | **/*.Server/GeneratedArtifacts 319 | **/*.Server/ModelManifest.xml 320 | _Pvt_Extensions 321 | 322 | # Paket dependency manager 323 | .paket/paket.exe 324 | paket-files/ 325 | 326 | # FAKE - F# Make 327 | .fake/ 328 | 329 | # JetBrains Rider 330 | .idea/ 331 | *.sln.iml 332 | 333 | # CodeRush 334 | .cr/ 335 | 336 | # Python Tools for Visual Studio (PTVS) 337 | __pycache__/ 338 | *.pyc 339 | 340 | # Cake - Uncomment if you are using it 341 | # tools/** 342 | # !tools/packages.config 343 | 344 | # Tabs Studio 345 | *.tss 346 | 347 | # Telerik's JustMock configuration file 348 | *.jmconfig 349 | 350 | # BizTalk build output 351 | *.btp.cs 352 | *.btm.cs 353 | *.odx.cs 354 | *.xsd.cs 355 | 356 | # OpenCover UI analysis results 357 | OpenCover/ 358 | coverage/ 359 | 360 | ### macOS template 361 | # General 362 | .DS_Store 363 | .AppleDouble 364 | .LSOverride 365 | 366 | # Icon must end with two \r 367 | Icon 368 | 369 | # Thumbnails 370 | ._* 371 | 372 | # Files that might appear in the root of a volume 373 | .DocumentRevisions-V100 374 | .fseventsd 375 | .Spotlight-V100 376 | .TemporaryItems 377 | .Trashes 378 | .VolumeIcon.icns 379 | .com.apple.timemachine.donotpresent 380 | 381 | # Directories potentially created on remote AFP share 382 | .AppleDB 383 | .AppleDesktop 384 | Network Trash Folder 385 | Temporary Items 386 | .apdisk 387 | 388 | ======= 389 | # Local 390 | docker-compose.yml 391 | .env 392 | dist 393 | -------------------------------------------------------------------------------- /webrtc-web-client/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /webrtc-web-client/README.md: -------------------------------------------------------------------------------- 1 | Install local web server: https://www.npmjs.com/package/local-web-server 2 | 3 | ``` 4 | npm i -g local-web-server 5 | ``` 6 | 7 | Then start server: 8 | ``` 9 | ws --http2 10 | ``` 11 | 12 | -> Server start at: https://127.0.0.1:8000 13 | -------------------------------------------------------------------------------- /webrtc-web-client/basic_peerconnection/css/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2020 Nhan Cao 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | button { 26 | margin: 0 20px 0 0; 27 | width: 83px; 28 | } 29 | 30 | button#hangupButton { 31 | margin: 0; 32 | } 33 | 34 | video { 35 | --width: 45%; 36 | width: var(--width); 37 | height: calc(var(--width) * 0.75); 38 | margin: 0 0 20px 0; 39 | vertical-align: top; 40 | background: #222; 41 | } 42 | 43 | video#localVideo { 44 | margin: 0 20px 20px 0; 45 | } 46 | 47 | div.box { 48 | margin: 1em; 49 | } 50 | 51 | @media screen and (max-width: 400px) { 52 | button { 53 | width: 83px; 54 | margin: 0 11px 10px 0; 55 | } 56 | 57 | video { 58 | height: 90px; 59 | margin: 0 0 10px 0; 60 | width: calc(50% - 7px); 61 | } 62 | video#localVideo { 63 | margin: 0 10px 20px 0; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /webrtc-web-client/basic_peerconnection/index.html: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | Realtime communication with WebRTC 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |

Realtime communication with WebRTC

46 | 47 |
48 | 49 | 50 | 51 |
52 | 53 | 54 | 55 |
56 | 57 |
58 | SDP Semantics: 59 | 64 |
65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /webrtc-web-client/basic_peerconnection/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhancv/nc-flutter-webrtc-ex/ea298b16a81ba05da7f81a5292e74ebe75aea5e2/webrtc-web-client/basic_peerconnection/index.js -------------------------------------------------------------------------------- /webrtc-web-client/basic_peerconnection/js/webrtc.js: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2020 Nhan Cao 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | 26 | 'use strict'; 27 | // https://github.com/webrtc/samples/tree/gh-pages/src/content/peerconnection/pc1 28 | const startButton = document.getElementById('startButton'); 29 | const callButton = document.getElementById('callButton'); 30 | const hangupButton = document.getElementById('hangupButton'); 31 | callButton.disabled = true; 32 | hangupButton.disabled = true; 33 | startButton.addEventListener('click', start); 34 | callButton.addEventListener('click', call); 35 | hangupButton.addEventListener('click', hangup); 36 | 37 | let startTime; 38 | const localVideo = document.getElementById('localVideo'); 39 | const remoteVideo = document.getElementById('remoteVideo'); 40 | 41 | localVideo.addEventListener('loadedmetadata', function() { 42 | console.log(`Local video videoWidth: ${this.videoWidth}px, videoHeight: ${this.videoHeight}px`); 43 | }); 44 | 45 | remoteVideo.addEventListener('loadedmetadata', function() { 46 | console.log(`Remote video videoWidth: ${this.videoWidth}px, videoHeight: ${this.videoHeight}px`); 47 | }); 48 | 49 | remoteVideo.addEventListener('resize', () => { 50 | console.log(`Remote video size changed to ${remoteVideo.videoWidth}x${remoteVideo.videoHeight}`); 51 | // We'll use the first onsize callback as an indication that video has started 52 | // playing out. 53 | if (startTime) { 54 | const elapsedTime = window.performance.now() - startTime; 55 | console.log('Setup time: ' + elapsedTime.toFixed(3) + 'ms'); 56 | startTime = null; 57 | } 58 | }); 59 | 60 | let localStream; 61 | let pc1; 62 | let pc2; 63 | const offerOptions = { 64 | offerToReceiveAudio: 1, 65 | offerToReceiveVideo: 1 66 | }; 67 | 68 | function getName(pc) { 69 | return (pc === pc1) ? 'pc1' : 'pc2'; 70 | } 71 | 72 | function getOtherPc(pc) { 73 | return (pc === pc1) ? pc2 : pc1; 74 | } 75 | 76 | async function start() { 77 | console.log('Requesting local stream'); 78 | startButton.disabled = true; 79 | try { 80 | const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true}); 81 | console.log('Received local stream'); 82 | localVideo.srcObject = stream; 83 | localStream = stream; 84 | callButton.disabled = false; 85 | } catch (e) { 86 | alert(`getUserMedia() error: ${e.name}`); 87 | } 88 | } 89 | 90 | function getSelectedSdpSemantics() { 91 | const sdpSemanticsSelect = document.querySelector('#sdpSemantics'); 92 | const option = sdpSemanticsSelect.options[sdpSemanticsSelect.selectedIndex]; 93 | return option.value === '' ? {} : {sdpSemantics: option.value}; 94 | } 95 | 96 | async function call() { 97 | callButton.disabled = true; 98 | hangupButton.disabled = false; 99 | console.log('Starting call'); 100 | startTime = window.performance.now(); 101 | const videoTracks = localStream.getVideoTracks(); 102 | const audioTracks = localStream.getAudioTracks(); 103 | if (videoTracks.length > 0) { 104 | console.log(`Using video device: ${videoTracks[0].label}`); 105 | } 106 | if (audioTracks.length > 0) { 107 | console.log(`Using audio device: ${audioTracks[0].label}`); 108 | } 109 | const configuration = getSelectedSdpSemantics(); 110 | console.log('RTCPeerConnection configuration:', configuration); 111 | pc1 = new RTCPeerConnection(configuration); 112 | console.log('Created local peer connection object pc1'); 113 | pc1.addEventListener('icecandidate', e => onIceCandidate(pc1, e)); 114 | pc2 = new RTCPeerConnection(configuration); 115 | console.log('Created remote peer connection object pc2'); 116 | pc2.addEventListener('icecandidate', e => onIceCandidate(pc2, e)); 117 | pc1.addEventListener('iceconnectionstatechange', e => onIceStateChange(pc1, e)); 118 | pc2.addEventListener('iceconnectionstatechange', e => onIceStateChange(pc2, e)); 119 | pc2.addEventListener('track', gotRemoteStream); 120 | 121 | localStream.getTracks().forEach(track => pc1.addTrack(track, localStream)); 122 | console.log('Added local stream to pc1'); 123 | 124 | try { 125 | console.log('pc1 createOffer start'); 126 | const offer = await pc1.createOffer(offerOptions); 127 | await onCreateOfferSuccess(offer); 128 | } catch (e) { 129 | onCreateSessionDescriptionError(e); 130 | } 131 | } 132 | 133 | function onCreateSessionDescriptionError(error) { 134 | console.log(`Failed to create session description: ${error.toString()}`); 135 | } 136 | 137 | async function onCreateOfferSuccess(desc) { 138 | console.log(`Offer from pc1\n${desc.sdp}`); 139 | console.log('pc1 setLocalDescription start'); 140 | try { 141 | await pc1.setLocalDescription(desc); 142 | onSetLocalSuccess(pc1); 143 | } catch (e) { 144 | onSetSessionDescriptionError(); 145 | } 146 | 147 | console.log('pc2 setRemoteDescription start'); 148 | try { 149 | await pc2.setRemoteDescription(desc); 150 | onSetRemoteSuccess(pc2); 151 | } catch (e) { 152 | onSetSessionDescriptionError(); 153 | } 154 | 155 | console.log('pc2 createAnswer start'); 156 | // Since the 'remote' side has no media stream we need 157 | // to pass in the right constraints in order for it to 158 | // accept the incoming offer of audio and video. 159 | try { 160 | const answer = await pc2.createAnswer(); 161 | await onCreateAnswerSuccess(answer); 162 | } catch (e) { 163 | onCreateSessionDescriptionError(e); 164 | } 165 | } 166 | 167 | function onSetLocalSuccess(pc) { 168 | console.log(`${getName(pc)} setLocalDescription complete`); 169 | } 170 | 171 | function onSetRemoteSuccess(pc) { 172 | console.log(`${getName(pc)} setRemoteDescription complete`); 173 | } 174 | 175 | function onSetSessionDescriptionError(error) { 176 | console.log(`Failed to set session description: ${error.toString()}`); 177 | } 178 | 179 | function gotRemoteStream(e) { 180 | const remoteStream = e.streams[0]; 181 | if (remoteVideo.srcObject !== remoteStream) { 182 | remoteVideo.srcObject = remoteStream; 183 | remoteStream.getTracks().forEach(track => pc2.addTrack(track, remoteStream)); 184 | console.log('pc2 received remote stream'); 185 | } 186 | } 187 | 188 | async function onCreateAnswerSuccess(desc) { 189 | console.log(`Answer from pc2:\n${desc.sdp}`); 190 | console.log('pc2 setLocalDescription start'); 191 | try { 192 | await pc2.setLocalDescription(desc); 193 | onSetLocalSuccess(pc2); 194 | } catch (e) { 195 | onSetSessionDescriptionError(e); 196 | } 197 | console.log('pc1 setRemoteDescription start'); 198 | try { 199 | await pc1.setRemoteDescription(desc); 200 | onSetRemoteSuccess(pc1); 201 | } catch (e) { 202 | onSetSessionDescriptionError(e); 203 | } 204 | } 205 | 206 | async function onIceCandidate(pc, event) { 207 | try { 208 | await (getOtherPc(pc).addIceCandidate(event.candidate)); 209 | onAddIceCandidateSuccess(pc); 210 | } catch (e) { 211 | onAddIceCandidateError(pc, e); 212 | } 213 | console.log(`${getName(pc)} ICE candidate:\n${event.candidate ? event.candidate.candidate : '(null)'}`); 214 | } 215 | 216 | function onAddIceCandidateSuccess(pc) { 217 | console.log(`${getName(pc)} addIceCandidate success`); 218 | } 219 | 220 | function onAddIceCandidateError(pc, error) { 221 | console.log(`${getName(pc)} failed to add ICE Candidate: ${error.toString()}`); 222 | } 223 | 224 | function onIceStateChange(pc, event) { 225 | if (pc) { 226 | console.log(`${getName(pc)} ICE state: ${pc.iceConnectionState}`); 227 | console.log('ICE state change event: ', event); 228 | } 229 | } 230 | 231 | function hangup() { 232 | console.log('Ending call'); 233 | pc1.close(); 234 | pc2.close(); 235 | pc1 = null; 236 | pc2 = null; 237 | hangupButton.disabled = true; 238 | callButton.disabled = false; 239 | } 240 | -------------------------------------------------------------------------------- /webrtc-web-client/basic_peerconnection/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 22 | 23 | 25 | 26 | 28 | image/svg+xml 29 | 31 | 32 | 33 | 34 | 35 | 38 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /webrtc-web-client/index.html: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | 28 | 29 | 30 | Demo 31 | 32 | 33 |
34 | 35 |
36 |
37 | 38 |
39 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /webrtc-web-client/socket_peerconnection/css/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2020 Nhan Cao 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | h1 { 26 | border-bottom: 1px solid #ccc; 27 | font-family: 'Roboto', sans-serif; 28 | font-weight: 500; 29 | margin: 0 0 0.8em 0; 30 | padding: 0 0 0.2em 0; 31 | } 32 | 33 | div#container { 34 | margin: 0 auto 0 auto; 35 | max-width: 60em; 36 | padding: 1em 1.5em 1.3em 1.5em; 37 | } 38 | 39 | button { 40 | margin: 0 20px 0 0; 41 | width: 83px; 42 | } 43 | 44 | button#hangupButton { 45 | margin: 0; 46 | } 47 | 48 | video { 49 | --width: 45%; 50 | width: var(--width); 51 | height: calc(var(--width) * 0.75); 52 | margin: 0 0 20px 0; 53 | vertical-align: top; 54 | background: #222; 55 | } 56 | 57 | video#localVideo { 58 | margin: 0 20px 20px 0; 59 | } 60 | 61 | div.box { 62 | margin: 1em; 63 | } 64 | 65 | @media screen and (max-width: 400px) { 66 | button { 67 | width: 83px; 68 | margin: 0 11px 10px 0; 69 | } 70 | 71 | video { 72 | height: 90px; 73 | margin: 0 0 10px 0; 74 | width: calc(50% - 7px); 75 | } 76 | video#localVideo { 77 | margin: 0 10px 20px 0; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /webrtc-web-client/socket_peerconnection/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Realtime communication with WebRTC 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 |

WebRTC

23 |

24 | 25 | 26 | 27 | 28 |
29 |

30 |
31 | 32 |
33 |
34 | 35 | 36 |
37 | 38 |
39 | 40 |
41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /webrtc-web-client/socket_peerconnection/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 22 | 23 | 25 | 26 | 28 | image/svg+xml 29 | 31 | 32 | 33 | 34 | 35 | 38 | 42 | 43 | 44 | --------------------------------------------------------------------------------