├── .editorconfig ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── angular.json ├── e2e ├── protractor.conf.js ├── src │ ├── app.e2e-spec.ts │ └── app.po.ts └── tsconfig.e2e.json ├── package-lock.json ├── package.json ├── projects └── angular-agora-rtc │ ├── README.md │ ├── karma.conf.js │ ├── ng-package.json │ ├── ng-package.prod.json │ ├── node_modules │ └── agora-rtc-sdk │ │ ├── AgoraRTCSDK.min.js │ │ ├── LICENSE.md │ │ ├── README.md │ │ └── package.json │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── lib │ │ ├── AgoraClient.ts │ │ ├── AgoraConfig.ts │ │ ├── Device.ts │ │ ├── Stream.ts │ │ ├── agora-local-component.html │ │ ├── agora-local.component.css │ │ ├── agora-local.component.ts │ │ ├── angular-agora-rtc.component.spec.ts │ │ ├── angular-agora-rtc.module.ts │ │ ├── angular-agora-rtc.service.spec.ts │ │ └── angular-agora-rtc.service.ts │ ├── public_api.ts │ └── test.ts │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ └── tslint.json ├── src ├── app │ ├── app.component.css │ ├── app.component.html │ ├── app.component.spec.ts │ ├── app.component.ts │ └── app.module.ts ├── assets │ └── .gitkeep ├── browserslist ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── karma.conf.js ├── main.ts ├── polyfills.ts ├── styles.css ├── test.ts ├── tsconfig.app.json ├── tsconfig.spec.json └── tslint.json ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | /project/angular-agora-rtc/node_modules 12 | 13 | # IDEs and editors 14 | /.idea 15 | .project 16 | .classpath 17 | .c9/ 18 | *.launch 19 | .settings/ 20 | *.sublime-workspace 21 | 22 | # IDE - VSCode 23 | .vscode/* 24 | !.vscode/settings.json 25 | !.vscode/tasks.json 26 | !.vscode/launch.json 27 | !.vscode/extensions.json 28 | 29 | # misc 30 | /.sass-cache 31 | /connect.lock 32 | /coverage 33 | /libpeerconnection.log 34 | npm-debug.log 35 | yarn-error.log 36 | testem.log 37 | /typings 38 | 39 | # System Files 40 | .DS_Store 41 | Thumbs.db 42 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## angular-agora-rtc 2 | > Angular 6 wrapper for Agora RTC client from https://www.agora.io/en/ 3 | 4 | [![npm version](https://badge.fury.io/js/angular-agora-rtc.svg)](https://badge.fury.io/js/angular-agora-rtc) 5 | ![npm license](https://img.shields.io/npm/l/express.svg) 6 | 7 | 8 | ### Installation 9 | Install angular-agora-rtc and from npm: 10 | ```bash 11 | npm install angular-agora-rtc --save 12 | ``` 13 | 14 | ### Examples 15 | 16 | ### Introduction 17 | 18 | 19 | ### Setup 20 | 21 | In your app's main module, import `AngularAgoraRtcModule` and `AgoraConfig` from `angular-agora-rtc` and add the module to the imports array. Create an instance of `AgoraConfig` and set `AppID` equal to the value found in your project list on Agora.io. 22 | 23 | ```ts 24 | import { BrowserModule } from '@angular/platform-browser'; 25 | import { NgModule } from '@angular/core'; 26 | import { AngularAgoraRtcModule, AgoraConfig } from 'angular-agora-rtc'; 27 | 28 | import { AppComponent } from './app.component'; 29 | 30 | const agoraConfig: AgoraConfig = { 31 | AppID: '1239021930912039-02193', 32 | }; 33 | 34 | @NgModule({ 35 | declarations: [ 36 | AppComponent 37 | ], 38 | imports: [ 39 | BrowserModule, 40 | AngularAgoraRtcModule.forRoot(agoraConfig) 41 | ], 42 | providers: [], 43 | bootstrap: [AppComponent] 44 | }) 45 | export class AppModule { } 46 | ``` 47 | 48 | You can then inject the `AngularAgoraRtcService` into your components constructor and call `createClient()` to create the broadcast client object 49 | **Note:** The broadcast client object can only be created once per call session. 50 | ```ts 51 | import { AngularAgoraRtcService } from 'angular-agora-rtc'; 52 | ... 53 | constructor( 54 | private agoraService: AngularAgoraRtcService, 55 | ) { 56 | this.agoraService.createClient(); 57 | } 58 | ... 59 | ``` 60 | 61 | Once the client is created and initialization is complete, the user can now join the session by calling `client.join()`. Pass the channel key, channel name, and user ID to the method parameters: 62 | ```ts 63 | this.agoraService.client.join(null, '1000', null, (uid) => { 64 | }); 65 | ``` 66 | * Channel key: String used for broadcast security. For low security requirements, pass null as the parameter value. 67 | * Channel name: String that provides a unique channel name for the Agora session. This should be a numerical value for the Web SDK. The sample app uses channel.value (the value from the Channel UI text field). 68 | * User ID: The user ID is a 32-bit unsigned integer ranging from 1 to (2^32-1). If you set the user ID to null, the Agora server allocates a user ID and returns it in the onSuccess callback. If you decide to enter a specific user ID, make sure the integer is unique or an error will occur. 69 | 70 | **Note:** Users in the same channel can talk to each other, but users with different app IDs cannot call each other even if they join the same channel. 71 | 72 | Once this method is called successfully, the SDK triggers the callback with the user id as the parameter. 73 | 74 | ### Create and Manage a Stream 75 | * Host a Stream 76 | * Create a Stream 77 | * Set the Stream Video Profile 78 | * Set the Stream Event Listeners for Camera and Microphone Access 79 | 80 | #### Host a Stream 81 | If a user who has joined the stream will act as the host, the app must create a stream. 82 | 83 | #### Create a Stream 84 | 85 | If the user is a host, start the stream using the `this.agoraService.createStream()` method. The sample app passes in an object with the following properties: 86 | `this.localStream = this.agoraService.createStream(uid, true, null, null, true, false);` 87 | 88 | * streamID: The stream ID. Normally the stream ID is set as the user ID, which can be retrieved from the client.join() callback. 89 | * audio: Indicates if this stream contains an audio track. 90 | * cameraId: (Optional, defaults to first camera device found) All available video devices can be found by calling `agoraService.videoDevices` 91 | * microphoneId: (Optional, defaults to the first audio device found) All available audio devices can be found by calling `agoraService.audioDevices` 92 | * video: Indicates if this stream contains a video track. 93 | * screen: Indicates if this stream contains a screen sharing track. Currently screen sharing is only supported by the Google Chrome Explorer. 94 | 95 | The createStream object is set up for additional optional attributes. See the Agora API documentation for more information. 96 | 97 | #### Set the Stream Video Profile 98 | If the user is a host, the video profile must be set. The sample app sets the video profile to 720p_3, which represents a resolution of 1280x720, frame rate (fps) of 30, and a bitrate (kbps) of 1710. See the Agora API documentation for additional video profile options. 99 | `localStream.setVideoProfile('720p_3');` 100 | 101 | #### Set the Stream Event Listeners for Camera and Microphone Access 102 | 103 | Once the stream has been set up and configured, the sample app adds event listeners using the `localStream.on()` method to check for the user's microphone and camera permissions. These event listeners are used for debugging and to send alerts to request permissions. The sample app uses console logs to check if access to the camera and microphone was allowed or denied by the user. 104 | 105 | ```ts 106 | // The user has granted access to the camera and mic. 107 | this.localStream.on("accessAllowed", () => { 108 | console.log("accessAllowed"); 109 | }); 110 | // The user has denied access to the camera and mic. 111 | this.localStream.on("accessDenied", () => { 112 | console.log("accessDenied"); 113 | }); 114 | ``` 115 | Next, the sample app initializes the stream by calling the `localStream.init()` method. Once initialized, the stream's host publishes the stream using the `client.publish()` method. 116 | 117 | ```ts 118 | this.localStream.init(() => { 119 | console.log("getUserMedia successfully"); 120 | this.localStream.play('agora_local'); 121 | this.agoraService.client.publish(this.localStream, (err) => console.log("Publish local stream error: " + err)); 122 | this.agoraService.client.on('stream-published', (evt) => console.log("Publish local stream successfully")); 123 | }, (err) => console.log("getUserMedia failed", err)); 124 | ``` 125 | 126 | #### Setup Client Error Handling 127 | Passing error into the `client.on()` method will return the error type `err.reason`. The sample app uses this error type for debugging and re-invoking methods that failed. 128 | 129 | Since the Channel Key has an expiration, the sample app checks for the error `DYNAMIC_KET_TIMEOUT` in the `onFailure` callback. It then renews the channel key using the `client.renewChannelKey()` method. 130 | 131 | **Note:** If the channel key is not renewed, the communication to the SDK will disconnect. 132 | 133 | ```ts 134 | this.agoraService.client.on('error', (err) => { 135 | console.log("Got error msg:", err.reason); 136 | if (err.reason === 'DYNAMIC_KEY_TIMEOUT') { 137 | this.agoraService.client.renewChannelKey("",() =>{ 138 | console.log("Renew channel key successfully"); 139 | }, (err) =>{ 140 | console.log("Renew channel key failed: ", err); 141 | }); 142 | } 143 | }); 144 | ``` 145 | #### Add a Stream to the Client 146 | The stream-added event listener detects when a new stream is added to the client. The sample app subscribes the newly added stream to the client after a new stream is added to the client 147 | ```ts 148 | this.agoraService.client.on('stream-added', (evt) => { 149 | const stream = evt.stream; 150 | this.agoraService.client.subscribe(stream, (err) => { 151 | console.log("Subscribe stream failed", err); 152 | }); 153 | }); 154 | ``` 155 | #### Subscribe a Stream to the Client and Add to the DOM 156 | The sample app uses the `stream-subscribed` event listener to detect when a new stream has been subscribed to the client, and to retrieve its stream ID using the `stream.getId()` method. 157 | ```ts 158 | this.agoraService.client.on('stream-subscribed', (evt) => { 159 | const stream = evt.stream; 160 | if (!this.remoteCalls.includes(`agora_remote${stream.getId()}`)) this.remoteCalls.push(`agora_remote${stream.getId()}`); 161 | setTimeout(() => stream.play(`agora_remote${stream.getId()}`), 1000); 162 | }); 163 | ``` 164 | Once the stream has been added to the `remoteCalls` array, the sample app sets a one second timeout to allow the change detection to run and render the new div. Then to play the stream we call the stream.play() method, passing in the string agora_remote followed by the stream ID. 165 | 166 | #### Remove a Stream from the Client 167 | If the stream is removed from the client, the `stream-removed` event listener is called, the sample app stops the stream from playing by calling the `stream.stop()` method. We then remove the stream from the `remoteCalls` array using the `filter()` method. 168 | 169 | ```ts 170 | this.agoraService.client.on('stream-removed', (evt) => { 171 | const stream = evt.stream; 172 | stream.stop(); 173 | this.remoteCalls = this.remoteCalls.filter(call => call === `#agora_remote${stream.getId()}`); 174 | console.log(`Remote stream is removed ${stream.getId()}`); 175 | }); 176 | ``` 177 | 178 | #### Remove a Peer from the Client 179 | When the sample app detects that a peer leaves the client using the `peer-leave` event listener, it stops the stream from playing. We then remove the stream from the `remoteCalls` array using the `filter()` method. 180 | ```ts 181 | this.agoraService.client.on('peer-leave', (evt) => { 182 | const stream = evt.stream; 183 | if (stream) { 184 | stream.stop(); 185 | this.remoteCalls = this.remoteCalls.filter(call => call === `#agora_remote${stream.getId()}`); 186 | console.log(`${evt.uid} left from this channel`); 187 | } 188 | }); 189 | ``` 190 | #### Leave a Channel 191 | The `client.leave()` method removes the user from the current video call (channel). The sample app checks if the action succeeds or fails using the `onSuccess` and `onFailure` callbacks. 192 | ```ts 193 | leave() { 194 | this.agoraService.client.leave(() => { 195 | console.log("Leavel channel successfully"); 196 | }, (err) => { 197 | console.log("Leave channel failed"); 198 | }); 199 | } 200 | ``` 201 | 202 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "AngularAgoraRTCDemo": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": {}, 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/AngularAgoraRTCDemo", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "src/tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "src/styles.css" 27 | ], 28 | "scripts": [] 29 | }, 30 | "configurations": { 31 | "production": { 32 | "fileReplacements": [ 33 | { 34 | "replace": "src/environments/environment.ts", 35 | "with": "src/environments/environment.prod.ts" 36 | } 37 | ], 38 | "optimization": true, 39 | "outputHashing": "all", 40 | "sourceMap": false, 41 | "extractCss": true, 42 | "namedChunks": false, 43 | "aot": true, 44 | "extractLicenses": true, 45 | "vendorChunk": false, 46 | "buildOptimizer": true 47 | } 48 | } 49 | }, 50 | "serve": { 51 | "builder": "@angular-devkit/build-angular:dev-server", 52 | "options": { 53 | "browserTarget": "AngularAgoraRTCDemo:build" 54 | }, 55 | "configurations": { 56 | "production": { 57 | "browserTarget": "AngularAgoraRTCDemo:build:production" 58 | } 59 | } 60 | }, 61 | "extract-i18n": { 62 | "builder": "@angular-devkit/build-angular:extract-i18n", 63 | "options": { 64 | "browserTarget": "AngularAgoraRTCDemo:build" 65 | } 66 | }, 67 | "test": { 68 | "builder": "@angular-devkit/build-angular:karma", 69 | "options": { 70 | "main": "src/test.ts", 71 | "polyfills": "src/polyfills.ts", 72 | "tsConfig": "src/tsconfig.spec.json", 73 | "karmaConfig": "src/karma.conf.js", 74 | "styles": [ 75 | "src/styles.css" 76 | ], 77 | "scripts": [], 78 | "assets": [ 79 | "src/favicon.ico", 80 | "src/assets" 81 | ] 82 | } 83 | }, 84 | "lint": { 85 | "builder": "@angular-devkit/build-angular:tslint", 86 | "options": { 87 | "tsConfig": [ 88 | "src/tsconfig.app.json", 89 | "src/tsconfig.spec.json" 90 | ], 91 | "exclude": [ 92 | "**/node_modules/**" 93 | ] 94 | } 95 | } 96 | } 97 | }, 98 | "AngularAgoraRTCDemo-e2e": { 99 | "root": "e2e/", 100 | "projectType": "application", 101 | "architect": { 102 | "e2e": { 103 | "builder": "@angular-devkit/build-angular:protractor", 104 | "options": { 105 | "protractorConfig": "e2e/protractor.conf.js", 106 | "devServerTarget": "AngularAgoraRTCDemo:serve" 107 | }, 108 | "configurations": { 109 | "production": { 110 | "devServerTarget": "AngularAgoraRTCDemo:serve:production" 111 | } 112 | } 113 | }, 114 | "lint": { 115 | "builder": "@angular-devkit/build-angular:tslint", 116 | "options": { 117 | "tsConfig": "e2e/tsconfig.e2e.json", 118 | "exclude": [ 119 | "**/node_modules/**" 120 | ] 121 | } 122 | } 123 | } 124 | }, 125 | "angular-agora-rtc": { 126 | "root": "projects/angular-agora-rtc", 127 | "sourceRoot": "projects/angular-agora-rtc/src", 128 | "projectType": "library", 129 | "prefix": "lib", 130 | "architect": { 131 | "build": { 132 | "builder": "@angular-devkit/build-ng-packagr:build", 133 | "options": { 134 | "tsConfig": "projects/angular-agora-rtc/tsconfig.lib.json", 135 | "project": "projects/angular-agora-rtc/ng-package.json" 136 | }, 137 | "configurations": { 138 | "production": { 139 | "project": "projects/angular-agora-rtc/ng-package.prod.json" 140 | } 141 | } 142 | }, 143 | "test": { 144 | "builder": "@angular-devkit/build-angular:karma", 145 | "options": { 146 | "main": "projects/angular-agora-rtc/src/test.ts", 147 | "tsConfig": "projects/angular-agora-rtc/tsconfig.spec.json", 148 | "karmaConfig": "projects/angular-agora-rtc/karma.conf.js" 149 | } 150 | }, 151 | "lint": { 152 | "builder": "@angular-devkit/build-angular:tslint", 153 | "options": { 154 | "tsConfig": [ 155 | "projects/angular-agora-rtc/tsconfig.lib.json", 156 | "projects/angular-agora-rtc/tsconfig.spec.json" 157 | ], 158 | "exclude": [ 159 | "**/node_modules/**" 160 | ] 161 | } 162 | } 163 | } 164 | } 165 | }, 166 | "defaultProject": "AngularAgoraRTCDemo" 167 | } -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('workspace-project App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to AngularAgoraRTCDemo!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-agora-rtcdemo", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "^6.0.3", 15 | "@angular/common": "^6.0.3", 16 | "@angular/compiler": "^6.0.3", 17 | "@angular/core": "^6.0.3", 18 | "@angular/forms": "^6.0.3", 19 | "@angular/http": "^6.0.3", 20 | "@angular/platform-browser": "^6.0.3", 21 | "@angular/platform-browser-dynamic": "^6.0.3", 22 | "@angular/router": "^6.0.3", 23 | "angular-agora-rtc": "0.0.2", 24 | "core-js": "^2.5.4", 25 | "rxjs": "^6.0.0", 26 | "zone.js": "^0.8.26" 27 | }, 28 | "devDependencies": { 29 | "@angular/compiler-cli": "^6.0.3", 30 | "@angular-devkit/build-ng-packagr": "~0.6.8", 31 | "@angular-devkit/build-angular": "~0.6.8", 32 | "ng-packagr": "^3.0.0-rc.2", 33 | "tsickle": ">=0.25.5", 34 | "tslib": "^1.7.1", 35 | "typescript": "~2.7.2", 36 | "@angular/cli": "~6.0.8", 37 | "@angular/language-service": "^6.0.3", 38 | "@types/jasmine": "~2.8.6", 39 | "@types/jasminewd2": "~2.0.3", 40 | "@types/node": "~8.9.4", 41 | "codelyzer": "~4.2.1", 42 | "jasmine-core": "~2.99.1", 43 | "jasmine-spec-reporter": "~4.2.1", 44 | "karma": "~1.7.1", 45 | "karma-chrome-launcher": "~2.2.0", 46 | "karma-coverage-istanbul-reporter": "~2.0.0", 47 | "karma-jasmine": "~1.1.1", 48 | "karma-jasmine-html-reporter": "^0.2.2", 49 | "protractor": "~5.3.0", 50 | "ts-node": "~5.0.1", 51 | "tslint": "~5.9.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/README.md: -------------------------------------------------------------------------------- 1 | ## angular-agora-rtc 2 | > Angular 6 wrapper for Agora RTC client from https://www.agora.io/en/ 3 | 4 | [![npm version](https://badge.fury.io/js/angular-agora-rtc.svg)](https://badge.fury.io/js/angular-agora-rtc) 5 | ![npm license](https://img.shields.io/npm/l/express.svg) 6 | 7 | 8 | ### Installation 9 | Install angular-agora-rtc and from npm: 10 | ```bash 11 | npm install angular-agora-rtc --save 12 | ``` 13 | 14 | ### Examples 15 | 16 | ### Introduction 17 | 18 | 19 | ### Setup 20 | 21 | In your app's main module, import `AngularAgoraRtcModule` and `AgoraConfig` from `angular-agora-rtc` and add the module to the imports array. Create an instance of `AgoraConfig` and set `AppID` equal to the the value found in your project list on Agora.io. 22 | 23 | ```ts 24 | import { BrowserModule } from '@angular/platform-browser'; 25 | import { NgModule } from '@angular/core'; 26 | import { AngularAgoraRtcModule, AgoraConfig } from 'angular-agora-rtc'; 27 | 28 | import { AppComponent } from './app.component'; 29 | 30 | const agoraConfig: AgoraConfig = { 31 | AppID: '1239021930912039-02193', 32 | }; 33 | 34 | @NgModule({ 35 | declarations: [ 36 | AppComponent 37 | ], 38 | imports: [ 39 | BrowserModule, 40 | AngularAgoraRtcModule.forRoot(agoraConfig) 41 | ], 42 | providers: [], 43 | bootstrap: [AppComponent] 44 | }) 45 | export class AppModule { } 46 | ``` 47 | 48 | You can then inject the `AngularAgoraRtcService` into your components constructor and call `createClient()` to create the broadcast client object 49 | **Note:** The broadcast client object can only be created once per call session. 50 | ```ts 51 | import { AngularAgoraRtcService } from 'angular-agora-rtc'; 52 | ... 53 | constructor( 54 | private agoraService: AngularAgoraRtcService, 55 | ) { 56 | this.agoraService.createClient(); 57 | } 58 | ... 59 | ``` 60 | 61 | Once the client is created and initialization is complete, the user can now join the session by calling `client.join()`. Pass the channel key, channel name, and user ID to the method parameters: 62 | ```ts 63 | this.agoraService.client.join(null, '1000', null, (uid) => { 64 | }); 65 | ``` 66 | * Channel key: String used for broadcast security. For low security requirements, pass null as the parameter value. 67 | * Channel name: String that provides a unique channel name for the Agora session. This should be a numerical value for the Web SDK. The sample app uses channel.value (the value from the Channel UI text field). 68 | * User ID: The user ID is a 32-bit unsigned integer ranging from 1 to (2^32-1). If you set the user ID to null, the Agora server allocates a user ID and returns it in the onSuccess callback. If you decide to enter a specific user ID, make sure the integer is unique or an error will occur. 69 | 70 | **Note:** Users in the same channel can talk to each other, but users with different app IDs cannot call each other even if they join the same channel. 71 | 72 | Once this method is called successfully, the SDK triggers the callback with the user id as the parameter. 73 | 74 | ### Create and Manage a Stream 75 | * Host a Stream 76 | * Create a Stream 77 | * Set the Stream Video Profile 78 | * Set the Stream Event Listeners for Camera and Microphone Access 79 | 80 | #### Host a Stream 81 | If a user who has joined the stream will act as the host, the app must create a stream. 82 | 83 | #### Create a Stream 84 | 85 | If the user is a host, start the stream using the `this.agoraService.createStream()` method. The sample app passes in an object with the following properties: 86 | `this.localStream = this.agoraService.createStream(uid, true, null, null, true, false);` 87 | 88 | * streamID: The stream ID. Normally the stream ID is set as the user ID, which can be retrieved from the client.join() callback. 89 | * audio: Indicates if this stream contains an audio track. 90 | * cameraId: (Optional, defaults to first camera device found) All available video devices can be found by calling `agoraService.videoDevices` 91 | * microphoneId: (Optional, defaults to the first audio device found) All available audio devices can be found by calling `agoraService.audioDevices` 92 | * video: Indicates if this stream contains a video track. 93 | * screen: Indicates if this stream contains a screen sharing track. Currently screen sharing is only supported by the Google Chrome Explorer. 94 | 95 | The createStream object is set up for additional optional attributes. See the Agora API documentation for more information. 96 | 97 | #### Set the Stream Video Profile 98 | If the user is a host, the video profile must be set. The sample app sets the video profile to 720p_3, which represents a resolution of 1280x720, frame rate (fps) of 30, and a bitrate (kbps) of 1710. See the Agora API documentation for additional video profile options. 99 | `localStream.setVideoProfile('720p_3');` 100 | 101 | #### Set the Stream Event Listeners for Camera and Microphone Access 102 | 103 | Once the stream has been set up and configured, the sample app adds event listeners using the `localStream.on()` method to check for the user's microphone and camera permissions. These event listeners are used for debugging and to send alerts to request permissions. The sample app uses console logs to check if access to the camera and microphone was allowed or denied by the user. 104 | 105 | ```ts 106 | // The user has granted access to the camera and mic. 107 | this.localStream.on("accessAllowed", () => { 108 | console.log("accessAllowed"); 109 | }); 110 | // The user has denied access to the camera and mic. 111 | this.localStream.on("accessDenied", () => { 112 | console.log("accessDenied"); 113 | }); 114 | ``` 115 | Next, the sample app initializes the stream by calling the `localStream.init()` method. Once initialized, the stream's host publishes the stream using the `client.publish()` method. 116 | 117 | ```ts 118 | this.localStream.init(() => { 119 | console.log("getUserMedia successfully"); 120 | this.localStream.play('agora_local'); 121 | this.agoraService.client.publish(this.localStream, (err) => console.log("Publish local stream error: " + err)); 122 | this.agoraService.client.on('stream-published', (evt) => console.log("Publish local stream successfully")); 123 | }, (err) => console.log("getUserMedia failed", err)); 124 | ``` 125 | 126 | #### Setup Client Error Handling 127 | Passing error into the `client.on()` method will return the error type `err.reason`. The sample app uses this error type for debugging and re-invoking methods that failed. 128 | 129 | Since the Channel Key has an expiration, the sample app checks for the error `DYNAMIC_KET_TIMEOUT` in the `onFailure` callback. It then renews the channel key using the `client.renewChannelKey()` method. 130 | 131 | **Note:** If the channel key is not renewed, the communication to the SDK will disconnect. 132 | 133 | ```ts 134 | this.agoraService.client.on('error', (err) => { 135 | console.log("Got error msg:", err.reason); 136 | if (err.reason === 'DYNAMIC_KEY_TIMEOUT') { 137 | this.agoraService.client.renewChannelKey("",() =>{ 138 | console.log("Renew channel key successfully"); 139 | }, (err) =>{ 140 | console.log("Renew channel key failed: ", err); 141 | }); 142 | } 143 | }); 144 | ``` 145 | #### Add a Stream to the Client 146 | The stream-added event listener detects when a new stream is added to the client. The sample app subscribes the newly added stream to the client after a new stream is added to the client 147 | ```ts 148 | this.agoraService.client.on('stream-added', (evt) => { 149 | const stream = evt.stream; 150 | this.agoraService.client.subscribe(stream, (err) => { 151 | console.log("Subscribe stream failed", err); 152 | }); 153 | }); 154 | ``` 155 | #### Subscribe a Stream to the Client and Add to the DOM 156 | The sample app uses the `stream-subscribed` event listener to detect when a new stream has been subscribed to the client, and to retrieve its stream ID using the `stream.getId()` method. 157 | ```ts 158 | this.agoraService.client.on('stream-subscribed', (evt) => { 159 | const stream = evt.stream; 160 | if (!this.remoteCalls.includes(`agora_remote${stream.getId()}`)) this.remoteCalls.push(`agora_remote${stream.getId()}`); 161 | setTimeout(() => stream.play(`agora_remote${stream.getId()}`), 1000); 162 | }); 163 | ``` 164 | Once the stream has been added to the `remoteCalls` array, the sample app sets a one second timeout to allow the change detection to run and render the new div. Then to play the stream we call the stream.play() method, passing in the string agora_remote followed by the stream ID. 165 | 166 | #### Remove a Stream from the Client 167 | If the stream is removed from the client, the `stream-removed` event listener is called, the sample app stops the stream from playing by calling the `stream.stop()` method. We then remove the stream from the `remoteCalls` array using the `filter()` method. 168 | 169 | ```ts 170 | this.agoraService.client.on('stream-removed', (evt) => { 171 | const stream = evt.stream; 172 | stream.stop(); 173 | this.remoteCalls = this.remoteCalls.filter(call => call === `#agora_remote${stream.getId()}`); 174 | console.log(`Remote stream is removed ${stream.getId()}`); 175 | }); 176 | ``` 177 | 178 | #### Remove a Peer from the Client 179 | When the sample app detects that a peer leaves the client using the `peer-leave` event listener, it stops the stream from playing. We then remove the stream from the `remoteCalls` array using the `filter()` method. 180 | ```ts 181 | this.agoraService.client.on('peer-leave', (evt) => { 182 | const stream = evt.stream; 183 | if (stream) { 184 | stream.stop(); 185 | this.remoteCalls = this.remoteCalls.filter(call => call === `#agora_remote${stream.getId()}`); 186 | console.log(`${evt.uid} left from this channel`); 187 | } 188 | }); 189 | ``` 190 | #### Leave a Channel 191 | The `client.leave()` method removes the user from the current video call (channel). The sample app checks if the action succeeds or fails using the `onSuccess` and `onFailure` callbacks. 192 | ```ts 193 | leave() { 194 | this.agoraService.client.leave(() => { 195 | console.log("Leavel channel successfully"); 196 | }, (err) => { 197 | console.log("Leave channel failed"); 198 | }); 199 | } 200 | ``` 201 | 202 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../../coverage'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/angular-agora-rtc", 4 | "deleteDestPath": false, 5 | "lib": { 6 | "entryFile": "src/public_api.ts" 7 | }, 8 | "whitelistedNonPeerDependencies": [ 9 | "agora-rtc-sdk", 10 | "material-design-icons" 11 | ] 12 | } -------------------------------------------------------------------------------- /projects/angular-agora-rtc/ng-package.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/angular-agora-rtc", 4 | "lib": { 5 | "entryFile": "src/public_api.ts" 6 | }, 7 | "whitelistedNonPeerDependencies": [ 8 | "agora-rtc-sdk", 9 | "material-design-icons" 10 | ] 11 | } -------------------------------------------------------------------------------- /projects/angular-agora-rtc/node_modules/agora-rtc-sdk/LICENSE.md: -------------------------------------------------------------------------------- 1 | See [here](https://www.agora.io/en/sdk-license-agreement/?_ga=2.210801749.1535711986.1520219996-1414345485.1520219996) for licensing. -------------------------------------------------------------------------------- /projects/angular-agora-rtc/node_modules/agora-rtc-sdk/README.md: -------------------------------------------------------------------------------- 1 | # AgoraRTC SDK (Web) 2 | For publishing npm package AgoraRTC SDK (Web). 3 | Get more infomation from [https://www.agora.io](https://www.agora.io/en/). -------------------------------------------------------------------------------- /projects/angular-agora-rtc/node_modules/agora-rtc-sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_from": "agora-rtc-sdk", 3 | "_id": "agora-rtc-sdk@2.3.1", 4 | "_inBundle": false, 5 | "_integrity": "sha512-QLQKlwtugjR0wY9qE2igM97UI83dpYQENLeqodnCV1Dz9x+AncVdB+WX1m5kO726vHUGsI/wW1i1rtN5vyY9iA==", 6 | "_location": "/agora-rtc-sdk", 7 | "_phantomChildren": {}, 8 | "_requested": { 9 | "type": "tag", 10 | "registry": true, 11 | "raw": "agora-rtc-sdk", 12 | "name": "agora-rtc-sdk", 13 | "escapedName": "agora-rtc-sdk", 14 | "rawSpec": "", 15 | "saveSpec": null, 16 | "fetchSpec": "latest" 17 | }, 18 | "_requiredBy": [ 19 | "#USER", 20 | "/" 21 | ], 22 | "_resolved": "https://registry.npmjs.org/agora-rtc-sdk/-/agora-rtc-sdk-2.3.1.tgz", 23 | "_shasum": "ba99637ee0d28b3b6453965876e7e35f8d76cfd8", 24 | "_spec": "agora-rtc-sdk", 25 | "_where": "/Users/andrewanderson/Desktop/development/Agora/AngularAgoraRTCDemo/projects/angular-agora-rtc", 26 | "author": { 27 | "name": "agora" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/AgoraIO/web-archive/issues" 31 | }, 32 | "bundleDependencies": false, 33 | "deprecated": false, 34 | "description": "AgoraRTC SDK for web", 35 | "homepage": "https://github.com/AgoraIO/web-archive#readme", 36 | "keywords": [ 37 | "Agora", 38 | "Webrtc", 39 | "Javascript" 40 | ], 41 | "license": "SEE LICENSE IN LICENSE.md", 42 | "main": "AgoraRTCSDK.min.js", 43 | "name": "agora-rtc-sdk", 44 | "repository": { 45 | "type": "git", 46 | "url": "git+https://github.com/AgoraIO/web-archive.git" 47 | }, 48 | "scripts": { 49 | "test": "echo \"Error: no test specified\" && exit 1" 50 | }, 51 | "version": "2.3.1" 52 | } 53 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-agora-rtc", 3 | "version": "0.0.7", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "agora-rtc-sdk": { 8 | "version": "2.3.1", 9 | "resolved": "https://registry.npmjs.org/agora-rtc-sdk/-/agora-rtc-sdk-2.3.1.tgz", 10 | "integrity": "sha512-QLQKlwtugjR0wY9qE2igM97UI83dpYQENLeqodnCV1Dz9x+AncVdB+WX1m5kO726vHUGsI/wW1i1rtN5vyY9iA==" 11 | }, 12 | "material-design-icons": { 13 | "version": "3.0.1", 14 | "resolved": "https://registry.npmjs.org/material-design-icons/-/material-design-icons-3.0.1.tgz", 15 | "integrity": "sha1-mnHEh0chjrylHlGmbaaCA4zct78=" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-agora-rtc", 3 | "version": "0.0.9", 4 | "homepage": "https://github.com/Only1MrAnderson/Angular-Agora-RTC#readme", 5 | "peerDependencies": { 6 | "@angular/common": "^6.0.0-rc.0 || ^6.0.0", 7 | "@angular/core": "^6.0.0-rc.0 || ^6.0.0" 8 | }, 9 | "dependencies": { 10 | "agora-rtc-sdk": "^2.3.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/AgoraClient.ts: -------------------------------------------------------------------------------- 1 | export class AgoraClient { 2 | aesMode: string; 3 | aespassword: string; 4 | configPublisher: any; // function 5 | disableDualStream: any; // function 6 | enableDualStream: any; // function 7 | gatewayClient: {}; // add object 8 | highStream: any; // ? type 9 | highStreamState: number; 10 | init: any; // function 11 | isDualStream: boolean; 12 | join: any; // function 13 | key: any; // ? string 14 | leave: any; // function 15 | lowStream: any; // ? 16 | lowStreamParameter: any // ? 17 | lowStreamState: number; 18 | on: any; // function 19 | proxyServer: any; // ? 20 | publish: any; // function 21 | renewChannelKey: any; // function 22 | setEncryptionMode: any; // function 23 | setEncryptionSecret: any; // function 24 | setLiveTranscoding: any; // function 25 | setLowStreamParameter: any; // function 26 | setProxyServer: any; // function 27 | setRemoteVideoStreamType: any; // function 28 | setTurnServer: any; // function 29 | startLiveStreaming: any; // function 30 | stopLiveStreaming: any; // function 31 | subscribe: any; // function 32 | turnServer: any; // function 33 | unpublish: any; // function 34 | unsubscribe: any; // function 35 | } -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/AgoraConfig.ts: -------------------------------------------------------------------------------- 1 | export class AgoraConfig{ 2 | AppID:string; 3 | } -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/Device.ts: -------------------------------------------------------------------------------- 1 | export class Device { 2 | deviceId:string; 3 | groupId:string; 4 | kind:string; 5 | label:string; 6 | } -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/Stream.ts: -------------------------------------------------------------------------------- 1 | export class Stream { 2 | addEventListener: any; // function 3 | audio: boolean; 4 | audioEnabled: boolean; 5 | audioLevelHelper: any // ? 6 | aux_stream: any; // ? 7 | close: any; // function 8 | disableAudio: any; // function 9 | disableVideo: any; // function 10 | dispatchEvent: any; // function 11 | dispatchSocketEvent: any; // function 12 | dispatcher: any; // event listener 13 | enableAudio: any; // function 14 | enableVideo: any; // function 15 | getAttributes: any; // function 16 | getAudioLevel: any; // function 17 | getId: any; // function 18 | getStats: any; // function 19 | hasAudio: any; // function 20 | hasScreen: any; // function 21 | hasVideo: any; // function 22 | init: any; // function 23 | initialized: boolean; 24 | isAudioOn: any; // function 25 | isVideoOn: any; // function 26 | local: boolean; 27 | lowStream: any; //? 28 | mirror: boolean; 29 | muteAudio: any; // ? 30 | muteVideo: any; // ? 31 | on: any; // function 32 | onClose: any // ? 33 | params: 34 | { streamID: number, audio: boolean, cameraId: string, microphoneId: string, video: boolean } 35 | play: any; // function 36 | player: any; // ? 37 | removeEventListener: any; // function 38 | screen: boolean; 39 | screenAttributes: { width: number, height: number, maxFr: number, minFr: number } 40 | setScreenProfile: any; // function 41 | setVideoBitRate: any; // function 42 | setVideoFrameRate: any; // function 43 | setVideoProfile: any; // function 44 | setVideoProfileCustom: any; // function 45 | setVideoProfileCustomPlus: any; // function 46 | setVideoResolution: any; // function 47 | stop: any; // function 48 | streamLanyl // ? 49 | streamId: number; 50 | unmuteAudio: any; // ? 51 | unmuteVideo: any; // ? 52 | url: any; //? 53 | video: boolean; 54 | videoEnabled: boolean; 55 | videoHeight: number; 56 | videoSize: Array 57 | videoWidth: number; 58 | } -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/agora-local-component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | videocam 7 | 8 | phone 9 | 10 | mic 11 | mic_off 12 | 13 | videocam 14 | videocam_off 15 | 16 |
17 |
18 |
19 |
20 | 21 |
22 |
-------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/agora-local.component.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/icon?family=Material+Icons'); 2 | 3 | p { 4 | font-family: Lato; 5 | } 6 | 7 | .video-container{ 8 | height: 100vh; 9 | display: flex; 10 | flex-wrap: wrap; 11 | flex-direction: row; 12 | justify-content: center; 13 | } 14 | 15 | .agora_local{ 16 | background-color: #404040; 17 | height: 250px; 18 | width: 250px; 19 | border: black 1px solid; 20 | margin: 8px; 21 | } 22 | #agora_local{ 23 | height: 250px; 24 | width: 250px; 25 | } 26 | 27 | .agora_remote{ 28 | background-color: #404040; 29 | height: 250px; 30 | width: 250px; 31 | border: black 1px solid; 32 | margin: 8px; 33 | } 34 | 35 | .video-buttons{ 36 | width: 250px; 37 | top: 210px; 38 | position: relative; 39 | text-align: center; 40 | z-index: 999; 41 | } 42 | 43 | .video-buttons i{ 44 | cursor: pointer; 45 | } 46 | 47 | .endCall{ 48 | color: red; 49 | } 50 | 51 | .startCall{ 52 | color: white; 53 | } 54 | 55 | .mic{ 56 | color: white; 57 | } 58 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/agora-local.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { AngularAgoraRtcService } from './angular-agora-rtc.service'; 3 | import { Stream } from './Stream'; 4 | 5 | @Component({ 6 | selector: 'agora-rtc', 7 | templateUrl: 'agora-local-component.html', 8 | styleUrls: ['agora-local.component.css'] 9 | }) 10 | export class AgoraLocalComponent { 11 | 12 | activeCall: boolean = false; 13 | audioEnabled: boolean = true; 14 | videoEnabled: boolean = true; 15 | localStream: Stream 16 | remoteCalls: any = []; 17 | 18 | constructor( 19 | private agoraService: AngularAgoraRtcService 20 | ) { 21 | this.agoraService.createClient(); 22 | } 23 | 24 | startCall() { 25 | this.activeCall = true; 26 | this.agoraService.client.join(null, '1000', null, (uid) => { 27 | this.localStream = this.agoraService.createStream(uid, true, null, null, true, false); 28 | this.localStream.setVideoProfile('720p_3'); 29 | this.subscribeToStreams(); 30 | }); 31 | } 32 | 33 | private subscribeToStreams() { 34 | this.localStream.on("accessAllowed", () => { 35 | console.log("accessAllowed"); 36 | }); 37 | // The user has denied access to the camera and mic. 38 | this.localStream.on("accessDenied", () => { 39 | console.log("accessDenied"); 40 | }); 41 | 42 | this.localStream.init(() => { 43 | console.log("getUserMedia successfully"); 44 | this.localStream.play('agora_local'); 45 | this.agoraService.client.publish(this.localStream, function (err) { 46 | console.log("Publish local stream error: " + err); 47 | }); 48 | this.agoraService.client.on('stream-published', function (evt) { 49 | console.log("Publish local stream successfully"); 50 | }); 51 | }, function (err) { 52 | console.log("getUserMedia failed", err); 53 | }); 54 | 55 | this.agoraService.client.on('error', (err) => { 56 | console.log("Got error msg:", err.reason); 57 | if (err.reason === 'DYNAMIC_KEY_TIMEOUT') { 58 | this.agoraService.client.renewChannelKey("", () => { 59 | console.log("Renew channel key successfully"); 60 | }, (err) => { 61 | console.log("Renew channel key failed: ", err); 62 | }); 63 | } 64 | }); 65 | 66 | this.agoraService.client.on('stream-added', (evt) => { 67 | const stream = evt.stream; 68 | this.agoraService.client.subscribe(stream, (err) => { 69 | console.log("Subscribe stream failed", err); 70 | }); 71 | }); 72 | 73 | this.agoraService.client.on('stream-subscribed', (evt) => { 74 | const stream = evt.stream; 75 | if (!this.remoteCalls.includes(`agora_remote${stream.getId()}`)) this.remoteCalls.push(`agora_remote${stream.getId()}`); 76 | setTimeout(() => stream.play(`agora_remote${stream.getId()}`), 2000); 77 | }); 78 | 79 | this.agoraService.client.on('stream-removed', (evt) => { 80 | const stream = evt.stream; 81 | stream.stop(); 82 | this.remoteCalls = this.remoteCalls.filter(call => call !== `#agora_remote${stream.getId()}`); 83 | console.log(`Remote stream is removed ${stream.getId()}`); 84 | }); 85 | 86 | this.agoraService.client.on('peer-leave', (evt) => { 87 | const stream = evt.stream; 88 | if (stream) { 89 | stream.stop(); 90 | this.remoteCalls = this.remoteCalls.filter(call => call === `#agora_remote${stream.getId()}`); 91 | console.log(`${evt.uid} left from this channel`); 92 | } 93 | }); 94 | } 95 | leave() { 96 | this.agoraService.client.leave(() => { 97 | this.activeCall = false; 98 | document.getElementById('agora_local').innerHTML = ""; 99 | console.log("Leavel channel successfully"); 100 | }, (err) => { 101 | console.log("Leave channel failed"); 102 | }); 103 | } 104 | 105 | toggleAudio() { 106 | this.audioEnabled = !this.audioEnabled; 107 | if (this.audioEnabled) this.localStream.enableAudio(); 108 | else this.localStream.disableAudio(); 109 | } 110 | 111 | toggleVideo() { 112 | this.videoEnabled = !this.videoEnabled; 113 | if (this.videoEnabled) this.localStream.enableVideo(); 114 | else this.localStream.disableVideo(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/angular-agora-rtc.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AgoraLocalComponent } from './agora-local.component'; 4 | 5 | describe('AgoraLocalComponent', () => { 6 | let component: AgoraLocalComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AgoraLocalComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AgoraLocalComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/angular-agora-rtc.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule, ModuleWithProviders } from '@angular/core'; 2 | import { AgoraLocalComponent } from './agora-local.component'; 3 | import { AgoraConfig } from './AgoraConfig'; 4 | import { AngularAgoraRtcService } from './angular-agora-rtc.service'; 5 | import { CommonModule } from '@angular/common'; 6 | 7 | @NgModule({ 8 | imports: [ 9 | CommonModule 10 | ], 11 | declarations: [AgoraLocalComponent], 12 | exports: [AgoraLocalComponent] 13 | }) 14 | export class AngularAgoraRtcModule { 15 | static forRoot(config: AgoraConfig): ModuleWithProviders{ 16 | return { 17 | ngModule: AngularAgoraRtcModule, 18 | providers: [AngularAgoraRtcService, {provide: 'config', useValue: config}] 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/angular-agora-rtc.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { AngularAgoraRtcService } from './angular-agora-rtc.service'; 4 | 5 | describe('AngularAgoraRtcService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [AngularAgoraRtcService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([AngularAgoraRtcService], (service: AngularAgoraRtcService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/lib/angular-agora-rtc.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | import * as AgoraRTC from 'agora-rtc-sdk'; 3 | import { Subject, BehaviorSubject } from 'rxjs'; 4 | import { AgoraConfig } from './AgoraConfig'; 5 | import { AgoraClient } from './AgoraClient'; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class AngularAgoraRtcService { 11 | 12 | public audioDevices: any[]; 13 | public videoDevices: any[]; 14 | 15 | public client: AgoraClient; 16 | 17 | constructor( 18 | @Inject('config') private config:AgoraConfig 19 | ) { 20 | if (!this.checkSystemRequirements()) { 21 | this.logger('error', 'Web RTC is not supported'); 22 | } else{ 23 | this.getDevices(); 24 | } 25 | } 26 | 27 | checkSystemRequirements() { 28 | return AgoraRTC.checkSystemRequirements(); 29 | } 30 | 31 | private getDevices() { 32 | AgoraRTC.getDevices((devices) => { 33 | let audioDevices = devices.filter(device => { 34 | return device.kind === 'audioinput' && device.deviceId !== 'default' 35 | }); 36 | let videoDevices = devices.filter(device => { 37 | return device.kind === 'videoinput' && device.deviceId !== 'default' 38 | }); 39 | this.audioDevices = audioDevices; 40 | this.videoDevices = videoDevices; 41 | }); 42 | } 43 | 44 | createClient(mode: string = 'interop', codec: string = 'vp8') { 45 | this.client = AgoraRTC.createClient({ mode: mode, codec: codec }); 46 | this.client.init(this.config.AppID); 47 | } 48 | 49 | createStream(streamID: any, audio: boolean, cameraId: string = this.videoDevices[0].deviceId, microphoneId: string = this.audioDevices[0].deviceId, video: boolean, screen: boolean) { 50 | return AgoraRTC.createStream({streamID, audio, cameraId, microphoneId, video, screen}); 51 | } 52 | 53 | logger(type: string, message: string) { 54 | switch (type) { 55 | case 'error': 56 | AgoraRTC.Logger.error(message); 57 | break; 58 | case 'warning': 59 | AgoraRTC.Logger.warning(message); 60 | break; 61 | case 'info': 62 | AgoraRTC.Logger.info(message); 63 | break; 64 | case 'debug': 65 | AgoraRTC.Logger.debug(message); 66 | break; 67 | default: 68 | AgoraRTC.Logger.error(message); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/public_api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of angular-agora-rtc 3 | */ 4 | 5 | export * from './lib/angular-agora-rtc.service'; 6 | export * from './lib/agora-local.component'; 7 | export * from './lib/angular-agora-rtc.module'; 8 | export * from './lib/AgoraClient'; 9 | export * from './lib/Stream'; 10 | export * from './lib/Device'; 11 | export * from './lib/AgoraConfig'; -------------------------------------------------------------------------------- /projects/angular-agora-rtc/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'core-js/es7/reflect'; 4 | import 'zone.js/dist/zone'; 5 | import 'zone.js/dist/zone-testing'; 6 | import { getTestBed } from '@angular/core/testing'; 7 | import { 8 | BrowserDynamicTestingModule, 9 | platformBrowserDynamicTesting 10 | } from '@angular/platform-browser-dynamic/testing'; 11 | 12 | declare const require: any; 13 | 14 | // First, initialize the Angular testing environment. 15 | getTestBed().initTestEnvironment( 16 | BrowserDynamicTestingModule, 17 | platformBrowserDynamicTesting() 18 | ); 19 | // Then we find all the tests. 20 | const context = require.context('./', true, /\.spec\.ts$/); 21 | // And load the modules. 22 | context.keys().map(context); 23 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "target": "es2015", 6 | "module": "es2015", 7 | "moduleResolution": "node", 8 | "declaration": true, 9 | "sourceMap": true, 10 | "inlineSources": true, 11 | "emitDecoratorMetadata": true, 12 | "experimentalDecorators": true, 13 | "importHelpers": true, 14 | "types": [], 15 | "lib": [ 16 | "dom", 17 | "es2015" 18 | ] 19 | }, 20 | "angularCompilerOptions": { 21 | "annotateForClosureCompiler": true, 22 | "skipTemplateCodegen": true, 23 | "strictMetadataEmit": true, 24 | "fullTemplateTypeCheck": true, 25 | "strictInjectionParameters": true, 26 | "flatModuleId": "AUTOGENERATED", 27 | "flatModuleOutFile": "AUTOGENERATED" 28 | }, 29 | "exclude": [ 30 | "src/test.ts", 31 | "**/*.spec.ts" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts" 12 | ], 13 | "include": [ 14 | "**/*.spec.ts", 15 | "**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/angular-agora-rtc/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "lib", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "lib", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- 1 | #agora_local{ 2 | height: 500px; 3 | width: 500px; 4 | display: inline-block; 5 | } 6 | 7 | .remote-containers div{ 8 | height: 250px; 9 | width: 250px; 10 | } -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 | 8 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | describe('AppComponent', () => { 4 | beforeEach(async(() => { 5 | TestBed.configureTestingModule({ 6 | declarations: [ 7 | AppComponent 8 | ], 9 | }).compileComponents(); 10 | })); 11 | it('should create the app', async(() => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.debugElement.componentInstance; 14 | expect(app).toBeTruthy(); 15 | })); 16 | it(`should have as title 'app'`, async(() => { 17 | const fixture = TestBed.createComponent(AppComponent); 18 | const app = fixture.debugElement.componentInstance; 19 | expect(app.title).toEqual('app'); 20 | })); 21 | it('should render title in a h1 tag', async(() => { 22 | const fixture = TestBed.createComponent(AppComponent); 23 | fixture.detectChanges(); 24 | const compiled = fixture.debugElement.nativeElement; 25 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to AngularAgoraRTCDemo!'); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { AngularAgoraRtcService, Stream } from 'angular-agora-rtc'; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.css'] 8 | }) 9 | export class AppComponent { 10 | title = 'AgoraDemo'; 11 | localStream: Stream 12 | remoteCalls: any = []; 13 | 14 | constructor( 15 | private agoraService: AngularAgoraRtcService 16 | ) { 17 | this.agoraService.createClient(); 18 | } 19 | 20 | startCall() { 21 | this.agoraService.client.join(null, '1000', null, (uid) => { 22 | this.localStream = this.agoraService.createStream(uid, true, null, null, true, false); 23 | this.localStream.setVideoProfile('720p_3'); 24 | this.subscribeToStreams(); 25 | }); 26 | } 27 | 28 | private subscribeToStreams() { 29 | this.localStream.on("accessAllowed", () => { 30 | console.log("accessAllowed"); 31 | }); 32 | // The user has denied access to the camera and mic. 33 | this.localStream.on("accessDenied", () => { 34 | console.log("accessDenied"); 35 | }); 36 | 37 | this.localStream.init(() => { 38 | console.log("getUserMedia successfully"); 39 | this.localStream.play('agora_local'); 40 | this.agoraService.client.publish(this.localStream, function (err) { 41 | console.log("Publish local stream error: " + err); 42 | }); 43 | this.agoraService.client.on('stream-published', function (evt) { 44 | console.log("Publish local stream successfully"); 45 | }); 46 | }, function (err) { 47 | console.log("getUserMedia failed", err); 48 | }); 49 | 50 | this.agoraService.client.on('error', (err) => { 51 | console.log("Got error msg:", err.reason); 52 | if (err.reason === 'DYNAMIC_KEY_TIMEOUT') { 53 | this.agoraService.client.renewChannelKey("", () => { 54 | console.log("Renew channel key successfully"); 55 | }, (err) => { 56 | console.log("Renew channel key failed: ", err); 57 | }); 58 | } 59 | }); 60 | 61 | this.agoraService.client.on('stream-added', (evt) => { 62 | const stream = evt.stream; 63 | this.agoraService.client.subscribe(stream, (err) => { 64 | console.log("Subscribe stream failed", err); 65 | }); 66 | }); 67 | 68 | this.agoraService.client.on('stream-subscribed', (evt) => { 69 | const stream = evt.stream; 70 | if (!this.remoteCalls.includes(`agora_remote${stream.getId()}`)) this.remoteCalls.push(`agora_remote${stream.getId()}`); 71 | setTimeout(() => stream.play(`agora_remote${stream.getId()}`), 2000); 72 | }); 73 | 74 | this.agoraService.client.on('stream-removed', (evt) => { 75 | const stream = evt.stream; 76 | stream.stop(); 77 | this.remoteCalls = this.remoteCalls.filter(call => call !== `#agora_remote${stream.getId()}`); 78 | console.log(`Remote stream is removed ${stream.getId()}`); 79 | }); 80 | 81 | this.agoraService.client.on('peer-leave', (evt) => { 82 | const stream = evt.stream; 83 | if (stream) { 84 | stream.stop(); 85 | this.remoteCalls = this.remoteCalls.filter(call => call === `#agora_remote${stream.getId()}`); 86 | console.log(`${evt.uid} left from this channel`); 87 | } 88 | }); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { AngularAgoraRtcModule, AgoraConfig } from 'angular-agora-rtc'; 4 | 5 | import { AppComponent } from './app.component'; 6 | 7 | const agoraConfig: AgoraConfig = { 8 | AppID: 'ksdfjlkdsjfklsdjf', 9 | }; 10 | 11 | @NgModule({ 12 | declarations: [ 13 | AppComponent 14 | ], 15 | imports: [ 16 | BrowserModule, 17 | AngularAgoraRtcModule.forRoot(agoraConfig) 18 | ], 19 | providers: [], 20 | bootstrap: [AppComponent] 21 | }) 22 | export class AppModule { } 23 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgoraIO-Community/Angular-Agora-RTC/49f846058eb2a8dc0bde725602342e05cbc697f8/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # For IE 9-11 support, please uncomment the last line of the file and adjust as needed 5 | > 0.5% 6 | last 2 versions 7 | Firefox ESR 8 | not dead 9 | # IE 9-11 -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * In development mode, to ignore zone related error stack frames such as 11 | * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can 12 | * import the following file, but please comment it out in production mode 13 | * because it will have performance impact when throw error 14 | */ 15 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 16 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgoraIO-Community/Angular-Agora-RTC/49f846058eb2a8dc0bde725602342e05cbc697f8/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularAgoraRTCDemo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Web Animations `@angular/platform-browser/animations` 51 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 52 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 53 | **/ 54 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 55 | 56 | /** 57 | * By default, zone.js will patch all possible macroTask and DomEvents 58 | * user can disable parts of macroTask/DomEvents patch by setting following flags 59 | */ 60 | 61 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 62 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 63 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 64 | 65 | /* 66 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 67 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 68 | */ 69 | // (window as any).__Zone_enable_cross_context_check = true; 70 | 71 | /*************************************************************************************************** 72 | * Zone JS is required by default for Angular itself. 73 | */ 74 | import 'zone.js/dist/zone'; // Included with Angular CLI. 75 | 76 | 77 | 78 | /*************************************************************************************************** 79 | * APPLICATION IMPORTS 80 | */ 81 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "types": [] 7 | }, 8 | "exclude": [ 9 | "src/test.ts", 10 | "**/*.spec.ts" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "types": [ 7 | "jasmine", 8 | "node" 9 | ] 10 | }, 11 | "files": [ 12 | "test.ts", 13 | "polyfills.ts" 14 | ], 15 | "include": [ 16 | "**/*.spec.ts", 17 | "**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2017", 17 | "dom" 18 | ], 19 | "paths": { 20 | "angular-agora-rtc": [ 21 | "dist/angular-agora-rtc" 22 | ], 23 | "angular-agora-rtc/*": [ 24 | "dist/angular-agora-rtc/*" 25 | ] 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs/Rx" 22 | ], 23 | "import-spacing": true, 24 | "indent": [ 25 | true, 26 | "spaces" 27 | ], 28 | "interface-over-type-literal": true, 29 | "label-position": true, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-arg": true, 47 | "no-bitwise": true, 48 | "no-console": [ 49 | true, 50 | "debug", 51 | "info", 52 | "time", 53 | "timeEnd", 54 | "trace" 55 | ], 56 | "no-construct": true, 57 | "no-debugger": true, 58 | "no-duplicate-super": true, 59 | "no-empty": false, 60 | "no-empty-interface": true, 61 | "no-eval": true, 62 | "no-inferrable-types": [ 63 | true, 64 | "ignore-params" 65 | ], 66 | "no-misused-new": true, 67 | "no-non-null-assertion": true, 68 | "no-shadowed-variable": true, 69 | "no-string-literal": false, 70 | "no-string-throw": true, 71 | "no-switch-case-fall-through": true, 72 | "no-trailing-whitespace": true, 73 | "no-unnecessary-initializer": true, 74 | "no-unused-expression": true, 75 | "no-use-before-declare": true, 76 | "no-var-keyword": true, 77 | "object-literal-sort-keys": false, 78 | "one-line": [ 79 | true, 80 | "check-open-brace", 81 | "check-catch", 82 | "check-else", 83 | "check-whitespace" 84 | ], 85 | "prefer-const": true, 86 | "quotemark": [ 87 | true, 88 | "single" 89 | ], 90 | "radix": true, 91 | "semicolon": [ 92 | true, 93 | "always" 94 | ], 95 | "triple-equals": [ 96 | true, 97 | "allow-null-check" 98 | ], 99 | "typedef-whitespace": [ 100 | true, 101 | { 102 | "call-signature": "nospace", 103 | "index-signature": "nospace", 104 | "parameter": "nospace", 105 | "property-declaration": "nospace", 106 | "variable-declaration": "nospace" 107 | } 108 | ], 109 | "unified-signatures": true, 110 | "variable-name": false, 111 | "whitespace": [ 112 | true, 113 | "check-branch", 114 | "check-decl", 115 | "check-operator", 116 | "check-separator", 117 | "check-type" 118 | ], 119 | "no-output-on-prefix": true, 120 | "use-input-property-decorator": true, 121 | "use-output-property-decorator": true, 122 | "use-host-property-decorator": true, 123 | "no-input-rename": true, 124 | "no-output-rename": true, 125 | "use-life-cycle-interface": true, 126 | "use-pipe-transform-interface": true, 127 | "component-class-suffix": true, 128 | "directive-class-suffix": true 129 | } 130 | } 131 | --------------------------------------------------------------------------------