226 lines
7.7 KiB
TypeScript
226 lines
7.7 KiB
TypeScript
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
import { Component, HostListener, OnDestroy } from '@angular/core';
|
|
import { OpenVidu, Publisher, 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']
|
|
})
|
|
export class AppComponent implements OnDestroy {
|
|
|
|
OPENVIDU_SERVER_URL = 'https://' + location.hostname + ':4443';
|
|
OPENVIDU_SERVER_SECRET = 'MY_SECRET';
|
|
|
|
// OpenVidu objects
|
|
OV: OpenVidu;
|
|
session: Session;
|
|
publisher: StreamManager; // Local
|
|
subscribers: StreamManager[] = []; // Remotes
|
|
|
|
// Join form
|
|
mySessionId: string;
|
|
myUserName: string;
|
|
|
|
// Main video of the page, will be 'publisher' or one of the 'subscribers',
|
|
// updated by click event in UserVideoComponent children
|
|
mainStreamManager: StreamManager;
|
|
|
|
constructor(private httpClient: HttpClient) {
|
|
this.generateParticipantInfo();
|
|
}
|
|
|
|
@HostListener('window:beforeunload')
|
|
beforeunloadHandler() {
|
|
// On window closed leave session
|
|
this.leaveSession();
|
|
}
|
|
|
|
ngOnDestroy() {
|
|
// On component destroyed leave session
|
|
this.leaveSession();
|
|
}
|
|
|
|
joinSession() {
|
|
|
|
// --- 1) Get an OpenVidu object ---
|
|
|
|
this.OV = new OpenVidu();
|
|
|
|
// --- 2) Init a session ---
|
|
|
|
this.session = this.OV.initSession();
|
|
|
|
// --- 3) Specify the actions when events take place in the 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 by its own
|
|
let subscriber: Subscriber = this.session.subscribe(event.stream, undefined);
|
|
this.subscribers.push(subscriber);
|
|
});
|
|
|
|
// On every Stream destroyed...
|
|
this.session.on('streamDestroyed', (event: StreamEvent) => {
|
|
|
|
// Remove the stream from 'subscribers' array
|
|
this.deleteSubscriber(event.stream.streamManager);
|
|
});
|
|
|
|
// --- 4) Connect to the session with a valid user token ---
|
|
|
|
// '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 can be retrieved 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) Get your own camera stream ---
|
|
|
|
// 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
|
|
let 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: false // Whether to mirror your local video or not
|
|
});
|
|
|
|
// --- 6) Publish your stream ---
|
|
|
|
this.session.publish(publisher);
|
|
|
|
// Set the main video in the page to display our webcam and store our Publisher
|
|
this.mainStreamManager = publisher;
|
|
this.publisher = publisher;
|
|
})
|
|
.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 ---
|
|
|
|
if (this.session) { this.session.disconnect(); };
|
|
|
|
// Empty all properties...
|
|
this.subscribers = [];
|
|
delete this.publisher;
|
|
delete this.session;
|
|
delete this.OV;
|
|
this.generateParticipantInfo();
|
|
}
|
|
|
|
|
|
private generateParticipantInfo() {
|
|
// Random user nickname and sessionId
|
|
this.mySessionId = 'SessionA';
|
|
this.myUserName = 'Participant' + Math.floor(Math.random() * 100);
|
|
}
|
|
|
|
private deleteSubscriber(streamManager: StreamManager): void {
|
|
let index = this.subscribers.indexOf(streamManager, 0);
|
|
if (index > -1) {
|
|
this.subscribers.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
updateMainStreamManager(streamManager: StreamManager) {
|
|
this.mainStreamManager = streamManager;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* --------------------------
|
|
* SERVER-SIDE RESPONSIBILITY
|
|
* --------------------------
|
|
* This method retrieve the mandatory user token from OpenVidu Server,
|
|
* in this case making use Angular http API.
|
|
* This behavior 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> {
|
|
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 +
|
|
'\"\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 = {};
|
|
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']);
|
|
});
|
|
});
|
|
}
|
|
|
|
}
|