ionic-cordova: Added mute and toggle media devices

This commit is contained in:
csantosm 2022-07-20 14:01:34 +02:00
parent cc87de9541
commit e4cf86bc22
4 changed files with 531 additions and 387 deletions

View File

@ -26,7 +26,7 @@
"@ionic/angular": "6.1.11",
"@ionic/cordova-builders": "^6.1.0",
"compare-func": "2.0.0",
"cordova-android": "10.1.2",
"cordova-android": "11.0.0",
"cordova-ios": "6.2.0",
"cordova-plugin-android-permissions": "1.1.3",
"cordova-plugin-device": "2.1.0",

View File

@ -23,4 +23,8 @@
ion-col {
padding: 1px;
}
.action-button {
padding: 5px;
}

View File

@ -1,72 +1,103 @@
<ion-app>
<ion-header>
<ion-toolbar color="dark">
<img
class="demo-logo"
src="assets/images/openvidu_vert_white_bg_trans_cropped.png"
/>
<ion-buttons slot="primary">
<ion-button
color="light"
href="https://github.com/OpenVidu/openvidu-tutorials/tree/master/openvidu-ionic"
>
<ion-icon slot="icon-only" name="logo-github"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-header>
<ion-toolbar color="dark">
<img class="demo-logo" src="assets/images/openvidu_vert_white_bg_trans_cropped.png" />
<ion-buttons slot="primary">
<ion-button color="light" href="https://github.com/OpenVidu/openvidu-tutorials/tree/master/openvidu-ionic">
<ion-icon slot="icon-only" name="logo-github"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding" *ngIf="!session">
<div id="img-div">
<img src="assets/images/openvidu_grey_bg_transp_cropped.png" />
</div>
<h1 align="center" id="title">Join a video session</h1>
<ion-item>
<ion-label position="floating">Participant</ion-label>
<ion-input [(ngModel)]="myUserName"></ion-input>
</ion-item>
<ion-item>
<ion-label position="floating">Session</ion-label>
<ion-input [(ngModel)]="mySessionId"></ion-input>
</ion-item>
<ion-content class="ion-padding" *ngIf="!session">
<ion-button
id="join-button"
[disabled]="!mySessionId && !myUserName"
(click)="joinSession()"
expand="block"
shape="round"
color="primary"
>
<ion-icon slot="start" name="videocam"></ion-icon>
Join
</ion-button>
<div id="img-div"><img src="assets/images/openvidu_grey_bg_transp_cropped.png" /></div>
<h1 align="center" id="title">Join a video session</h1>
<ion-item>
<ion-label position="floating">Participant</ion-label>
<ion-input [(ngModel)]="myUserName"></ion-input>
</ion-item>
<ion-item>
<ion-label position="floating">Session</ion-label>
<ion-input [(ngModel)]="mySessionId"></ion-input>
</ion-item>
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button
id="settings-button"
[disabled]="!mySessionId && !myUserName"
(click)="presentSettingsAlert()"
size="small"
color="dark"
>
<ion-icon name="settings"></ion-icon>
</ion-fab-button>
</ion-fab>
</ion-content>
<ion-button id="join-button" [disabled]="!mySessionId && !myUserName" (click)="joinSession()" expand="block" shape="round"
color="primary">
<ion-icon slot="start" name="videocam"></ion-icon>
Join
</ion-button>
<ion-content *ngIf="session">
<div id="session-header">
<h1 id="session-title">{{ mySessionId }}</h1>
</div>
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button id="settings-button" [disabled]="!mySessionId && !myUserName" (click)="presentSettingsAlert()"
size="small" color="dark">
<ion-icon name="settings"></ion-icon>
</ion-fab-button>
</ion-fab>
<ion-grid>
<!--Subscribers and Publishers-->
<ion-row>
<ion-col size="6">
<div *ngIf="publisher" class="stream-container">
<user-video [streamManager]="publisher"></user-video>
</div>
</ion-col>
</ion-content>
<ion-col size="6" *ngFor="let sub of subscribers">
<div class="stream-container">
<user-video [streamManager]="sub"></user-video>
</div>
</ion-col>
</ion-row>
</ion-grid>
<ion-content *ngIf="session">
<div id="session-header">
<h1 id="session-title">{{mySessionId}}</h1>
</div>
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button
class="action-button"
color="light"
id="camButton"
(click)="swapCamera()"
>
<ion-icon name="camera-reverse-sharp"></ion-icon>
</ion-fab-button>
<ion-grid>
<!--Subscribers and Publishers-->
<ion-row>
<ion-col size="6">
<div *ngIf="publisher" class="stream-container">
<user-video [streamManager]="publisher"></user-video>
</div>
</ion-col>
<ion-fab-button (click)="toggleMicrophone()" class="action-button">
<ion-icon name="{{microphoneIcon}}"></ion-icon>
</ion-fab-button>
<ion-col size="6" *ngFor="let sub of subscribers">
<div class="stream-container">
<user-video [streamManager]="sub"></user-video>
</div>
</ion-col>
<ion-fab-button (click)="toggleCamera()" class="action-button">
<ion-icon name="{{cameraIcon}}"></ion-icon>
</ion-fab-button>
</ion-row>
</ion-grid>
<ion-fab vertical="bottom" horizontal="center" slot="fixed">
<ion-fab-button size="small" color="danger" (click)="leaveSession()">
<ion-icon name="power"></ion-icon>
</ion-fab-button>
</ion-fab>
</ion-content>
</ion-app>
<ion-fab-button color="danger" (click)="leaveSession()" class="action-button">
<ion-icon name="power"></ion-icon>
</ion-fab-button>
</ion-fab>
</ion-content>
</ion-app>

View File

@ -1,363 +1,472 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Component, HostListener, OnDestroy } from '@angular/core';
import { AndroidPermissions } from '@ionic-native/android-permissions/ngx';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { Platform, AlertController } from '@ionic/angular';
import { OpenVidu, Publisher, Session, StreamEvent, StreamManager, Subscriber } from 'openvidu-browser';
import { throwError as observableThrowError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Component, HostListener, OnDestroy } from "@angular/core";
import { AndroidPermissions } from "@ionic-native/android-permissions/ngx";
import { SplashScreen } from "@ionic-native/splash-screen/ngx";
import { StatusBar } from "@ionic-native/status-bar/ngx";
import { Platform, AlertController } from "@ionic/angular";
import {
Device,
OpenVidu,
Publisher,
PublisherProperties,
Session,
StreamEvent,
StreamManager,
Subscriber,
} from "openvidu-browser";
import { throwError as observableThrowError } from "rxjs";
import { catchError } from "rxjs/operators";
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
selector: "app-root",
templateUrl: "app.component.html",
styleUrls: ["app.component.css"],
})
export class AppComponent implements OnDestroy {
OPENVIDU_SERVER_URL = "https://" + location.hostname + ":4443";
OPENVIDU_SERVER_SECRET = "MY_SECRET";
OPENVIDU_SERVER_URL = 'https://' + location.hostname + ':4443';
OPENVIDU_SERVER_SECRET = 'MY_SECRET';
ANDROID_PERMISSIONS = [
this.androidPermissions.PERMISSION.CAMERA,
this.androidPermissions.PERMISSION.RECORD_AUDIO,
this.androidPermissions.PERMISSION.MODIFY_AUDIO_SETTINGS,
];
ANDROID_PERMISSIONS = [
this.androidPermissions.PERMISSION.CAMERA,
this.androidPermissions.PERMISSION.RECORD_AUDIO,
this.androidPermissions.PERMISSION.MODIFY_AUDIO_SETTINGS
];
// OpenVidu objects
OV: OpenVidu;
session: Session;
publisher: StreamManager; // Local
subscribers: StreamManager[] = []; // Remotes
// OpenVidu objects
OV: OpenVidu;
session: Session;
publisher: StreamManager; // Local
subscribers: StreamManager[] = []; // Remotes
// Join form
mySessionId: string;
myUserName: string;
// Join form
mySessionId: string;
myUserName: string;
cameraIcon = "videocam";
microphoneIcon = "mic";
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private httpClient: HttpClient,
private androidPermissions: AndroidPermissions,
public alertController: AlertController
) {
this.initializeApp();
this.generateParticipantInfo();
}
private devices: Device[];
private cameras: Device[];
private microphones: Device[];
private cameraSelected: Device;
private microphoneSelected: Device;
private isFrontCamera: boolean = false;
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.overlaysWebView(false);
this.splashScreen.hide();
});
}
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private httpClient: HttpClient,
private androidPermissions: AndroidPermissions,
public alertController: AlertController
) {
this.initializeApp();
this.generateParticipantInfo();
}
@HostListener('window:beforeunload')
beforeunloadHandler() {
// On window closed leave session
this.leaveSession();
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.overlaysWebView(false);
this.splashScreen.hide();
});
}
ngOnDestroy() {
// On component destroyed leave session
this.leaveSession();
}
@HostListener("window:beforeunload")
beforeunloadHandler() {
// On window closed leave session
this.leaveSession();
}
joinSession() {
// --- 1) Get an OpenVidu object ---
ngOnDestroy() {
// On component destroyed leave session
this.leaveSession();
}
this.OV = new OpenVidu();
async joinSession() {
// --- 1) Get an OpenVidu object ---
// --- 2) Init a session ---
this.OV = new OpenVidu();
this.session = this.OV.initSession();
this.initDevices();
// --- 3) Specify the actions when events take place in the session ---
// --- 2) Init a session ---
// On every new Stream received...
this.session.on('streamCreated', (event: StreamEvent) => {
// Subscribe to the Stream to receive it. Second parameter is undefined
// so OpenVidu doesn't create an HTML video on its own
const subscriber: Subscriber = this.session.subscribe(event.stream, undefined);
this.subscribers.push(subscriber);
});
this.session = this.OV.initSession();
// On every Stream destroyed...
this.session.on('streamDestroyed', (event: StreamEvent) => {
// Remove the stream from 'subscribers' array
this.deleteSubscriber(event.stream.streamManager);
});
// --- 3) Specify the actions when events take place in the session ---
// On every asynchronous exception...
this.session.on('exception', (exception) => {
console.warn(exception);
});
// On every new Stream received...
this.session.on("streamCreated", (event: StreamEvent) => {
// Subscribe to the Stream to receive it. Second parameter is undefined
// so OpenVidu doesn't create an HTML video on its own
const subscriber: Subscriber = this.session.subscribe(
event.stream,
undefined
);
this.subscribers.push(subscriber);
});
// --- 4) Connect to the session with a valid user token ---
// On every Stream destroyed...
this.session.on("streamDestroyed", (event: StreamEvent) => {
// Remove the stream from 'subscribers' array
this.deleteSubscriber(event.stream.streamManager);
});
// 'getToken' method is simulating what your server-side should do.
// 'token' parameter should be retrieved and returned by your own backend
this.getToken().then((token) => {
// First param is the token got from OpenVidu Server. Second param will be used by every user on event
// 'streamCreated' (property Stream.connection.data), and will be appended to DOM as the user's nickname
this.session
.connect(token, { clientData: this.myUserName })
.then(() => {
// --- 5) Requesting and Checking Android Permissions
if (this.platform.is('cordova')) {
// Ionic platform
if (this.platform.is('android')) {
console.log('Android platform');
this.checkAndroidPermissions()
.then(() => this.initPublisher())
.catch(err => console.error(err));
} else if (this.platform.is('ios')) {
console.log('iOS platform');
this.initPublisher();
}
} else {
this.initPublisher();
}
})
.catch(error => {
console.log('There was an error connecting to the session:', error.code, error.message);
});
});
}
// On every asynchronous exception...
this.session.on("exception", (exception) => {
console.warn(exception);
});
initPublisher() {
// Init a publisher passing undefined as targetElement (we don't want OpenVidu to insert a video
// element: we will manage it on our own) and with the desired properties
const publisher: Publisher = this.OV.initPublisher(undefined, {
audioSource: undefined, // The source of audio. If undefined default microphone
videoSource: undefined, // The source of video. If undefined default webcam
publishAudio: true, // Whether you want to start publishing with your audio unmuted or not
publishVideo: true, // Whether you want to start publishing with your video enabled or not
resolution: '640x480', // The resolution of your video
frameRate: 30, // The frame rate of your video
insertMode: 'APPEND', // How the video is inserted in the target element 'video-container'
mirror: true // Whether to mirror your local video or not
});
// --- 4) Connect to the session with a valid user token ---
// --- 6) Publish your stream ---
try {
// 'getToken' method is simulating what your server-side should do.
// 'token' parameter should be retrieved and returned by your own backend
const token = await this.getToken();
// First param is the token got from OpenVidu Server. Second param will be used by every user on event
// 'streamCreated' (property Stream.connection.data), and will be appended to DOM as the user's nickname
await this.session.connect(token, { clientData: this.myUserName });
this.session.publish(publisher).then(() => {
// Store our Publisher
this.publisher = publisher;
});
}
// --- 5) Requesting and Checking Android Permissions
if (this.platform.is("cordova")) {
// Ionic platform
if (this.platform.is("android")) {
console.log("Android platform");
await this.checkAndroidPermissions();
this.initPublisher();
} else if (this.platform.is("ios")) {
console.log("iOS platform");
this.initPublisher();
}
} else {
this.initPublisher();
}
} catch (error) {
console.log(
"There was an error connecting to the session:",
error.code,
error.message
);
}
}
leaveSession() {
// --- 7) Leave the session by calling 'disconnect' method over the Session object ---
async initPublisher() {
// Init a publisher passing undefined as targetElement (we don't want OpenVidu to insert a video
// element: we will manage it on our own) and with the desired properties
const publisher: Publisher = await this.OV.initPublisherAsync(undefined, {
audioSource: this.microphones[0].deviceId, // The source of audio. If undefined default microphone
videoSource: this.cameras[0].deviceId, // The source of video. If undefined default webcam
publishAudio: true, // Whether you want to start publishing with your audio unmuted or not
publishVideo: true, // Whether you want to start publishing with your video enabled or not
resolution: "640x480", // The resolution of your video
frameRate: 30, // The frame rate of your video
insertMode: "APPEND", // How the video is inserted in the target element 'video-container'
mirror: this.isFrontCamera, // Whether to mirror your local video or not
});
if (this.session) {
this.session.disconnect();
}
// --- 6) Publish your stream ---
// Empty all properties...
this.subscribers = [];
delete this.publisher;
delete this.session;
delete this.OV;
this.generateParticipantInfo();
}
await this.session.publish(publisher);
// Store our Publisher
this.publisher = publisher;
}
private checkAndroidPermissions(): Promise<void> {
return new Promise((resolve, reject) => {
this.platform.ready().then(() => {
this.androidPermissions
.requestPermissions(this.ANDROID_PERMISSIONS)
.then(() => {
this.androidPermissions
.checkPermission(this.androidPermissions.PERMISSION.CAMERA)
.then(camera => {
this.androidPermissions
.checkPermission(this.androidPermissions.PERMISSION.RECORD_AUDIO)
.then(audio => {
this.androidPermissions
.checkPermission(this.androidPermissions.PERMISSION.MODIFY_AUDIO_SETTINGS)
.then(modifyAudio => {
if (camera.hasPermission && audio.hasPermission && modifyAudio.hasPermission) {
resolve();
} else {
reject(
new Error(
'Permissions denied: ' +
'\n' +
' CAMERA = ' +
camera.hasPermission +
'\n' +
' AUDIO = ' +
audio.hasPermission +
'\n' +
' AUDIO_SETTINGS = ' +
modifyAudio.hasPermission,
),
);
}
})
.catch(err => {
console.error(
'Checking permission ' +
this.androidPermissions.PERMISSION.MODIFY_AUDIO_SETTINGS +
' failed',
);
reject(err);
});
})
.catch(err => {
console.error(
'Checking permission ' + this.androidPermissions.PERMISSION.RECORD_AUDIO + ' failed',
);
reject(err);
});
})
.catch(err => {
console.error('Checking permission ' + this.androidPermissions.PERMISSION.CAMERA + ' failed');
reject(err);
});
})
.catch(err => console.error('Error requesting permissions: ', err));
});
});
}
leaveSession() {
// --- 7) Leave the session by calling 'disconnect' method over the Session object ---
private generateParticipantInfo() {
// Random user nickname and sessionId
this.mySessionId = 'SessionA';
this.myUserName = 'Participant' + Math.floor(Math.random() * 100);
}
if (this.session) {
this.session.disconnect();
}
private deleteSubscriber(streamManager: StreamManager): void {
const index = this.subscribers.indexOf(streamManager, 0);
if (index > -1) {
this.subscribers.splice(index, 1);
}
}
// Empty all properties...
this.subscribers = [];
delete this.publisher;
delete this.session;
delete this.OV;
this.generateParticipantInfo();
}
async presentSettingsAlert() {
const alert = await this.alertController.create({
header: 'OpenVidu Server config',
inputs: [
{
name: 'url',
type: 'text',
value: 'https://demos.openvidu.io',
placeholder: 'URL'
},
{
name: 'secret',
type: 'text',
value: 'MY_SECRET',
placeholder: 'Secret'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary'
}, {
text: 'Ok',
handler: data => {
this.OPENVIDU_SERVER_URL = data.url;
this.OPENVIDU_SERVER_SECRET = data.secret;
}
}
]
});
async swapCamera() {
try {
const newCamera = this.cameras.find(
(cam) => cam.deviceId !== this.cameraSelected.deviceId
);
if (!!newCamera) {
await alert.present();
}
this.isFrontCamera = !this.isFrontCamera;
const pp: PublisherProperties = {
videoSource: newCamera.deviceId,
audioSource: false,
mirror: this.isFrontCamera
};
/*
* --------------------------
* SERVER-SIDE RESPONSIBILITY
* --------------------------
* This method retrieve the mandatory user token from OpenVidu Server,
* in this case making use Angular http API.
* This behaviour MUST BE IN YOUR SERVER-SIDE IN PRODUCTION. In this case:
* 1) Initialize a Session in OpenVidu Server (POST /openvidu/api/sessions)
* 2) Create a Connection in OpenVidu Server (POST /openvidu/api/sessions/<SESSION_ID>/connection)
* 3) The Connection.token must be consumed in Session.connect() method
*/
// Stopping the video tracks after request for another MediaStream
this.publisher.stream.getMediaStream().getVideoTracks().forEach((track) => {
track.stop();
});
const newTrack = await this.OV.getUserMedia(pp);
const videoTrack: MediaStreamTrack = newTrack.getVideoTracks()[0];
await (this.publisher as Publisher).replaceTrack(videoTrack);
this.cameraSelected = newCamera;
}
} catch (error) {
console.error(error);
}
}
toggleCamera() {
const publish = !this.publisher.stream.videoActive;
(this.publisher as Publisher).publishVideo(publish, true);
this.cameraIcon = publish ? "videocam" : "eye-off";
}
getToken(): Promise<string> {
if (this.platform.is('ios') && this.platform.is('cordova') && this.OPENVIDU_SERVER_URL === 'https://localhost:4443') {
// To make easier first steps with iOS apps, use demos OpenVidu Sever if no custom valid server is configured
this.OPENVIDU_SERVER_URL = 'https://demos.openvidu.io';
}
return this.createSession(this.mySessionId).then((sessionId) => {
return this.createToken(sessionId);
});
}
toggleMicrophone() {
const publish = !this.publisher.stream.audioActive;
(this.publisher as Publisher).publishAudio(publish);
this.microphoneIcon = publish ? "mic" : "mic-off";
}
createSession(sessionId) {
return new Promise((resolve, reject) => {
const body = JSON.stringify({ customSessionId: sessionId });
const options = {
headers: new HttpHeaders({
Authorization: 'Basic ' + btoa('OPENVIDUAPP:' + this.OPENVIDU_SERVER_SECRET),
'Content-Type': 'application/json',
}),
};
return this.httpClient
.post(this.OPENVIDU_SERVER_URL + '/openvidu/api/sessions', body, options)
.pipe(
catchError((error) => {
if (error.status === 409) {
resolve(sessionId);
} else {
console.warn(
'No connection to OpenVidu Server. This may be a certificate error at ' +
this.OPENVIDU_SERVER_URL,
);
if (
window.confirm(
'No connection to OpenVidu Server. This may be a certificate error at "' +
this.OPENVIDU_SERVER_URL +
// tslint:disable-next-line:max-line-length
'"\n\nClick OK to navigate and accept it. If no certificate warning is shown, then check that your OpenVidu Server' +
'is up and running at "' +
this.OPENVIDU_SERVER_URL +
'"',
)
) {
location.assign(this.OPENVIDU_SERVER_URL + '/accept-certificate');
}
}
return observableThrowError(error);
}),
)
.subscribe((response) => {
console.log(response);
resolve(response['id']);
});
});
}
private async initDevices() {
this.devices = await this.OV.getDevices();
createToken(sessionId): Promise<string> {
return new Promise((resolve, reject) => {
const body = JSON.stringify({});
const options = {
headers: new HttpHeaders({
Authorization: 'Basic ' + btoa('OPENVIDUAPP:' + this.OPENVIDU_SERVER_SECRET),
'Content-Type': 'application/json',
}),
};
return this.httpClient
.post(this.OPENVIDU_SERVER_URL + '/openvidu/api/sessions/' + sessionId + '/connection', body, options)
.pipe(
catchError((error) => {
reject(error);
return observableThrowError(error);
}),
)
.subscribe((response) => {
console.log(response);
resolve(response['token']);
});
});
}
this.cameras = this.devices.filter((d) => d.kind === "videoinput");
this.microphones = this.devices.filter(
(d) => d.kind === "audioinput" && d.label !== "Default"
);
this.cameraSelected = this.cameras[0];
this.microphoneSelected = this.microphones[0];
}
private checkAndroidPermissions(): Promise<void> {
return new Promise((resolve, reject) => {
this.platform.ready().then(() => {
this.androidPermissions
.requestPermissions(this.ANDROID_PERMISSIONS)
.then(() => {
this.androidPermissions
.checkPermission(this.androidPermissions.PERMISSION.CAMERA)
.then((camera) => {
this.androidPermissions
.checkPermission(
this.androidPermissions.PERMISSION.RECORD_AUDIO
)
.then((audio) => {
this.androidPermissions
.checkPermission(
this.androidPermissions.PERMISSION.MODIFY_AUDIO_SETTINGS
)
.then((modifyAudio) => {
if (
camera.hasPermission &&
audio.hasPermission &&
modifyAudio.hasPermission
) {
resolve();
} else {
reject(
new Error(
"Permissions denied: " +
"\n" +
" CAMERA = " +
camera.hasPermission +
"\n" +
" AUDIO = " +
audio.hasPermission +
"\n" +
" AUDIO_SETTINGS = " +
modifyAudio.hasPermission
)
);
}
})
.catch((err) => {
console.error(
"Checking permission " +
this.androidPermissions.PERMISSION
.MODIFY_AUDIO_SETTINGS +
" failed"
);
reject(err);
});
})
.catch((err) => {
console.error(
"Checking permission " +
this.androidPermissions.PERMISSION.RECORD_AUDIO +
" failed"
);
reject(err);
});
})
.catch((err) => {
console.error(
"Checking permission " +
this.androidPermissions.PERMISSION.CAMERA +
" failed"
);
reject(err);
});
})
.catch((err) => console.error("Error requesting permissions: ", err));
});
});
}
private generateParticipantInfo() {
// Random user nickname and sessionId
this.mySessionId = "SessionA";
this.myUserName = "Participant" + Math.floor(Math.random() * 100);
}
private deleteSubscriber(streamManager: StreamManager): void {
const index = this.subscribers.indexOf(streamManager, 0);
if (index > -1) {
this.subscribers.splice(index, 1);
}
}
async presentSettingsAlert() {
const alert = await this.alertController.create({
header: "OpenVidu Server config",
inputs: [
{
name: "url",
type: "text",
value: "https://demos.openvidu.io",
placeholder: "URL",
},
{
name: "secret",
type: "text",
value: "MY_SECRET",
placeholder: "Secret",
},
],
buttons: [
{
text: "Cancel",
role: "cancel",
cssClass: "secondary",
},
{
text: "Ok",
handler: (data) => {
this.OPENVIDU_SERVER_URL = data.url;
this.OPENVIDU_SERVER_SECRET = data.secret;
},
},
],
});
await alert.present();
}
/*
* --------------------------
* SERVER-SIDE RESPONSIBILITY
* --------------------------
* This method retrieve the mandatory user token from OpenVidu Server,
* in this case making use Angular http API.
* This behaviour MUST BE IN YOUR SERVER-SIDE IN PRODUCTION. In this case:
* 1) Initialize a Session in OpenVidu Server (POST /openvidu/api/sessions)
* 2) Create a Connection in OpenVidu Server (POST /openvidu/api/sessions/<SESSION_ID>/connection)
* 3) The Connection.token must be consumed in Session.connect() method
*/
getToken(): Promise<string> {
if (
this.platform.is("ios") &&
this.platform.is("cordova") &&
this.OPENVIDU_SERVER_URL === "https://localhost:4443"
) {
// To make easier first steps with iOS apps, use demos OpenVidu Sever if no custom valid server is configured
this.OPENVIDU_SERVER_URL = "https://demos.openvidu.io";
}
return this.createSession(this.mySessionId).then((sessionId) => {
return this.createToken(sessionId);
});
}
createSession(sessionId) {
return new Promise((resolve, reject) => {
const body = JSON.stringify({ customSessionId: sessionId });
const options = {
headers: new HttpHeaders({
Authorization:
"Basic " + btoa("OPENVIDUAPP:" + this.OPENVIDU_SERVER_SECRET),
"Content-Type": "application/json",
}),
};
return this.httpClient
.post(
this.OPENVIDU_SERVER_URL + "/openvidu/api/sessions",
body,
options
)
.pipe(
catchError((error) => {
if (error.status === 409) {
resolve(sessionId);
} else {
console.warn(
"No connection to OpenVidu Server. This may be a certificate error at " +
this.OPENVIDU_SERVER_URL
);
if (
window.confirm(
'No connection to OpenVidu Server. This may be a certificate error at "' +
this.OPENVIDU_SERVER_URL +
// tslint:disable-next-line:max-line-length
'"\n\nClick OK to navigate and accept it. If no certificate warning is shown, then check that your OpenVidu Server' +
'is up and running at "' +
this.OPENVIDU_SERVER_URL +
'"'
)
) {
location.assign(
this.OPENVIDU_SERVER_URL + "/accept-certificate"
);
}
}
return observableThrowError(error);
})
)
.subscribe((response) => {
console.log(response);
resolve(response["id"]);
});
});
}
createToken(sessionId): Promise<string> {
return new Promise((resolve, reject) => {
const body = JSON.stringify({});
const options = {
headers: new HttpHeaders({
Authorization:
"Basic " + btoa("OPENVIDUAPP:" + this.OPENVIDU_SERVER_SECRET),
"Content-Type": "application/json",
}),
};
return this.httpClient
.post(
this.OPENVIDU_SERVER_URL +
"/openvidu/api/sessions/" +
sessionId +
"/connection",
body,
options
)
.pipe(
catchError((error) => {
reject(error);
return observableThrowError(error);
})
)
.subscribe((response) => {
console.log(response);
resolve(response["token"]);
});
});
}
}