OpenVidu + OpenViduTokBox Interfaces

pull/3/head
pabloFuente 2017-04-12 00:54:35 +02:00
parent c19307e066
commit 471fca15ac
16 changed files with 332 additions and 132 deletions

View File

@ -47,10 +47,24 @@ export class OpenVidu {
return this.session; return this.session;
} }
initPublisherTagged(parentId: string, cameraOptions: any, callback) { initPublisherTagged(parentId: string, cameraOptions: any, callback?) {
console.log("Publisher tagged initialized!"); console.log("Publisher tagged initialized!");
this.getCamera(cameraOptions); this.getCamera(cameraOptions);
if (callback == null) {
this.camera.requestCameraAccess((error, camera) => {
if (error) {
console.log("Error accessing the camera");
}
else {
this.camera.playOnlyVideo(parentId, null);
this.camera.isReady = true;
this.camera.emitStreamReadyEvent();
}
});
return this.camera;
} else {
this.camera.requestCameraAccess((error, camera) => { this.camera.requestCameraAccess((error, camera) => {
if (error){ if (error){
callback(error); callback(error);
@ -60,6 +74,8 @@ export class OpenVidu {
callback(undefined); callback(undefined);
} }
}); });
return this.camera;
}
} }
initPublisher(cameraOptions: any, callback) { initPublisher(cameraOptions: any, callback) {

View File

@ -41,7 +41,8 @@ export class Session {
else { else {
this.configure({ this.configure({
sessionId: this.sessionId, sessionId: this.sessionId,
participantId: token participantId: token,
subscribeToStreams: this.subscribeToStreams
}); });
let joinParams = { let joinParams = {
@ -91,14 +92,14 @@ export class Session {
} }
} }
if (this.subscribeToStreams) { //if (this.subscribeToStreams) {
for (let stream of roomEvent.streams) { for (let stream of roomEvent.streams) {
this.ee.emitEvent('stream-added', [{ stream }]); this.ee.emitEvent('stream-added', [{ stream }]);
// Adding the remote stream to the OpenVidu object // Adding the remote stream to the OpenVidu object
this.openVidu.getRemoteStreams().push(stream); this.openVidu.getRemoteStreams().push(stream);
} }
} //}
callback(undefined); callback(undefined);
} }
@ -174,7 +175,7 @@ export class Session {
this.options = options; this.options = options;
this.id = options.sessionId; this.id = options.sessionId;
this.subscribeToStreams = options.subscribeToStreams || true; this.subscribeToStreams = options.subscribeToStreams == null ? true : options.subscribeToStreams;
this.updateSpeakerInterval = options.updateSpeakerInterval || 1500; this.updateSpeakerInterval = options.updateSpeakerInterval || 1500;
this.thresholdSpeaker = options.thresholdSpeaker || -50; this.thresholdSpeaker = options.thresholdSpeaker || -50;
this.localParticipant.setId(options.participantId); this.localParticipant.setId(options.participantId);
@ -187,6 +188,10 @@ export class Session {
return this.id; return this.id;
} }
getSessionId(){
return this.sessionId;
}
private activateUpdateMainSpeaker() { private activateUpdateMainSpeaker() {
setInterval(() => { setInterval(() => {
@ -236,13 +241,12 @@ export class Session {
if ( this.subscribeToStreams ) { if ( this.subscribeToStreams ) {
stream.subscribe(); stream.subscribe();
}
this.ee.emitEvent( 'stream-added', [{ stream }] ); this.ee.emitEvent( 'stream-added', [{ stream }] );
// Adding the remote stream to the OpenVidu object // Adding the remote stream to the OpenVidu object
this.openVidu.getRemoteStreams().push(stream); this.openVidu.getRemoteStreams().push(stream);
} }
} }
}
onParticipantJoined( msg ) { onParticipantJoined( msg ) {
@ -457,6 +461,31 @@ export class Session {
} }
} }
unpublish(stream: Stream){
let participant = stream.getParticipant();
if ( !participant ) {
console.error( "Stream to disconnect has no participant", stream );
return;
}
if ( participant === this.localParticipant ) {
delete this.participants[participant.getId()];
participant.dispose();
console.log( "Unpublishing my media (I'm " + participant.getId() + ")" );
delete this.localParticipant;
this.openVidu.sendRequest( 'unpublishVideo', function( error, response ) {
if ( error ) {
console.error( error );
} else {
console.info( "Media unpublished correctly" );
}
});
}
}
getStreams() { getStreams() {
return this.streams; return this.streams;
} }

View File

@ -70,6 +70,7 @@ export class Stream {
private dataChannelOpened = false; private dataChannelOpened = false;
private videoSrc: string; private videoSrc: string;
public isReady: boolean = false;
constructor(private openVidu: OpenVidu, private local: boolean, private room: Session, options: StreamOptions) { constructor(private openVidu: OpenVidu, private local: boolean, private room: Session, options: StreamOptions) {
@ -100,6 +101,10 @@ export class Stream {
}]); }]);
} }
emitStreamReadyEvent(){
this.ee.emitEvent('stream-ready'), [{}];
}
getVideoSrc() { getVideoSrc() {
return this.videoSrc; return this.videoSrc;
} }
@ -426,8 +431,13 @@ export class Stream {
publish() { publish() {
// FIXME: Throw error when stream is not local // FIXME: Throw error when stream is not local
if (this.isReady) {
this.initWebRtcPeer(this.publishVideoCallback); this.initWebRtcPeer(this.publishVideoCallback);
} else {
this.addEventListener('stream-ready', streamEvent => {
this.publish();
});
}
// FIXME: Now we have coupled connecting to a room and adding a // FIXME: Now we have coupled connecting to a room and adding a
// stream to this room. But in the new API, there are two steps. // stream to this room. But in the new API, there are two steps.

View File

@ -18,7 +18,7 @@
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"strictNullChecks": true, "strictNullChecks": true,
"outDir": "../lib", "outDir": "../../lib/OpenVidu",
"emitBOM": false, "emitBOM": false,
"preserveConstEnums": true, "preserveConstEnums": true,
"sourceMap": true "sourceMap": true

View File

@ -0,0 +1,12 @@
import { OpenViduTokBox } from './OpenViduTokBox';
//This export with --standalone option allows using OpenVidu from bowser with namespace
//export { OpenVidu } from './OpenVidu';
//This "hack" allows to use OpenVidu from the global space window
if(window){
window["OpenViduTokBox"] = OpenViduTokBox;
}
//Command to generate bundle.js without namespace
//watchify Main.ts -p [ tsify ] --exclude kurento-browser-extensions --debug -o ../static/js/OpenVidu.js -v

View File

@ -0,0 +1,45 @@
/*
* (C) Copyright 2016 OpenVidu (http://kurento.org/)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import { OpenVidu } from '../OpenVidu/OpenVidu';
import { SessionTokBox } from './SessionTokBox';
import { PublisherTokBox } from './PublisherTokBox';
export class OpenViduTokBox {
openVidu: OpenVidu;
constructor(private wsUri: string) {
this.openVidu = new OpenVidu(wsUri);
}
initSession(apiKey: string, sessionId: string): SessionTokBox;
initSession(sessionId: string): SessionTokBox;
initSession(param1, param2?): any {
if (typeof param2 == "string") {
return new SessionTokBox(this.openVidu.initSession(param2), this);
} else {
return new SessionTokBox(this.openVidu.initSession(param1), this);
}
}
initPublisher(parentId: string, cameraOptions: any): PublisherTokBox {
return new PublisherTokBox(this.openVidu.initPublisherTagged(parentId, cameraOptions));
}
}

View File

@ -0,0 +1,20 @@
/*
* options: name: XXX data: true (Maybe this is based on webrtc) audio: true,
* video: true, url: "file:///..." > Player screen: true > Desktop (implicit
* video:true, audio:false) audio: true, video: true > Webcam
*
* stream.hasAudio(); stream.hasVideo(); stream.hasData();
*/
import { Stream, StreamOptions, VideoOptions } from '../OpenVidu/Stream';
import { OpenViduTokBox } from './OpenViduTokBox';
import { SessionTokBox } from './SessionTokBox';
export class PublisherTokBox {
stream: Stream;
constructor(stream: Stream) {
this.stream = stream;
}
}

View File

@ -0,0 +1,121 @@
import { Session, SessionOptions } from '../OpenVidu/Session';
import { Stream } from '../OpenVidu/Stream';
import { OpenViduTokBox } from './OpenViduTokBox';
import { PublisherTokBox } from './PublisherTokBox';
export class SessionTokBox {
constructor(private session: Session, private openVidu: OpenViduTokBox) { }
connect(token, callback) {
// Early configuration to deactivate automatic subscription to streams
this.session.configure({
sessionId: this.session.getSessionId(),
participantId: token,
subscribeToStreams: false
});
this.session.connect(token, callback);
}
disconnect() {
this.openVidu.openVidu.close(false);
}
publish(publisher: PublisherTokBox) {
publisher.stream.publish();
}
unpublish(publisher: PublisherTokBox) {
this.session.unpublish(publisher.stream);
}
on(eventName: string, callback) {
let realEventName = '';
switch (eventName) {
case 'streamCreated':
realEventName = 'stream-added'
break;
case 'streamDestroyed':
realEventName = 'stream-removed'
break;
}
if (realEventName != '') {
this.session.addEventListener(realEventName, event => {
callback(event);
});
} else {
console.warn("That is not a supported event!");
}
}
subscribe(stream: Stream, htmlId: string, videoOptions: any);
subscribe(stream: Stream, htmlId: string);
subscribe(param1, param2, param3?) {
// Subscription
this.session.subscribe(param1);
param1.playOnlyVideo(param2, null);
}
/* Shortcut event API */
onStreamCreated(callback) {
this.session.addEventListener("stream-added", streamEvent => {
callback(streamEvent.stream);
});
}
onStreamDestroyed(callback) {
this.session.addEventListener("stream-removed", streamEvent => {
callback(streamEvent.stream);
});
}
onParticipantJoined(callback) {
this.session.addEventListener("participant-joined", participantEvent => {
callback(participantEvent.participant);
});
}
onParticipantLeft(callback) {
this.session.addEventListener("participant-left", participantEvent => {
callback(participantEvent.participant);
});
}
onParticipantPublished(callback) {
this.session.addEventListener("participant-published", participantEvent => {
callback(participantEvent.participant);
});
}
onParticipantEvicted(callback) {
this.session.addEventListener("participant-evicted", participantEvent => {
callback(participantEvent.participant);
});
}
onRoomClosed(callback) {
this.session.addEventListener("room-closed", roomEvent => {
callback(roomEvent.room);
});
}
onLostConnection(callback) {
this.session.addEventListener("lost-connection", roomEvent => {
callback(roomEvent.room);
});
}
onMediaError(callback) {
this.session.addEventListener("error-media", errorEvent => {
callback(errorEvent.error)
});
}
/* Shortcut event API */
}

View File

@ -0,0 +1,3 @@
declare module "kurento-jsonrpc";
declare module "webrtc-adapter";
declare module "kurento-utils";

View File

@ -0,0 +1,3 @@
export * from './OpenViduTokBox';
export * from './PublisherTokBox';
export * from './SessionTokBox';

View File

@ -0,0 +1,28 @@
{
"compilerOptions": {
"declaration": true,
"target": "es5",
"module": "commonjs",
//"noImplicitAny": true,
"noImplicitThis": true,
//"noUnusedLocals": true,
//"noUnusedParameters": true,
"skipDefaultLibCheck": true,
"skipLibCheck": true,
"suppressExcessPropertyErrors": true,
"suppressImplicitAnyIndexErrors": true,
//"allowUnusedLabels": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
//"allowUnreachableCode": true,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
"strictNullChecks": true,
"outDir": "../../lib/OpenViduTokBox",
"emitBOM": false,
"preserveConstEnums": true,
"sourceMap": true
},
//"buildOnSave": true,
"compileOnSave":true
}

View File

@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { OpenVidu, Session, Stream } from 'openvidu-browser'; import { OpenViduTokBox, SessionTokBox, PublisherTokBox } from 'openvidu-browser';
import { VideoSessionService } from '../../services/video-session.service'; import { VideoSessionService } from '../../services/video-session.service';
import { AuthenticationService } from '../../services/authentication.service'; import { AuthenticationService } from '../../services/authentication.service';
@ -16,8 +16,8 @@ export class VideoSessionComponent implements OnInit {
lesson: Lesson; lesson: Lesson;
OV: OpenVidu; OV: OpenViduTokBox;
session: Session; session: SessionTokBox;
sessionId: string; sessionId: string;
token: string; token: string;
@ -44,69 +44,27 @@ export class VideoSessionComponent implements OnInit {
// In this case, the method ngOnInit takes care of it // In this case, the method ngOnInit takes care of it
// 1) Initialize OpenVidu and your Session // 1) Initialize OpenVidu and your Session
this.OV = new OpenVidu("wss://" + location.hostname + ":8443/"); this.OV = new OpenViduTokBox("wss://" + location.hostname + ":8443/");
this.session = this.OV.initSession(this.sessionId); this.session = this.OV.initSession(this.sessionId);
// 2) Specify the actions when events take place
// 2) Specify the actions when participants enter and leave the session this.session.on('streamCreated', (event) => {
this.session.onStreamAddedOV((stream) => { console.warn("Stream created:");
console.warn("Stream added:"); console.warn(event.stream);
console.warn(stream); this.session.subscribe(event.stream, this.remoteParentId);
stream.playOnlyVideo(this.remoteParentId, null);
}); });
this.session.onStreamRemovedOV((stream) => {
console.warn("Stream removed:");
console.warn(stream);
stream.removeVideo(this.remoteParentId);
});
this.session.onParticipantJoinedOV((participant) => {
console.warn("Participant joined:");
console.warn(participant);
});
this.session.onParticipantLeftOV((participant) => {
console.warn("Participant left:");
console.warn(participant);
});
this.session.onParticipantPublishedOV((participant) => {
console.warn("Participant published:");
console.warn(participant);
});
this.session.onParticipantEvictedOV((participant) => {
console.warn("Participant evicted:");
console.warn(participant);
});
this.session.onRoomClosedOV((room) => {
console.warn("Room closed:");
console.warn(room);
});
this.session.onLostConnectionOV((room) => {
console.warn("Connection lost:");
console.warn(room);
});
this.session.onMediaErrorOV((error) => {
console.warn("Media error:");
console.warn(error);
});
// 3) Connect to the session // 3) Connect to the session
this.session.connect(this.token, (error) => { this.session.connect(this.token, (error) => {
if (error) return console.log("There was an error: " + error); if (!error) {
// 4) Get your own camera stream with the desired resolution and publish it, only if the user is supposed to do so // 4) Get your own camera stream with the desired resolution and publish it, only if the user is supposed to do so
let publisher = this.OV.initPublisher(this.localParentId, this.cameraOptions);
// Local publish generating an HTML video element as a child of parentId HTML element // 5) Publish your stream
this.OV.initPublisherTagged(this.localParentId, this.cameraOptions, (error) => { this.session.publish(publisher);
if (error) return console.log("There was an error with your camera: " + error); }
this.session.publish(); else {
}); return console.log("There was an error: " + error);
}
// Local publish without generating an HTML video element
/*this.OV.initPublisher(this.cameraOptions, (error) => {
if (error) return console.log("There was an error: " + error);
this.session.publish();
});*/
}); });
@ -176,19 +134,7 @@ export class VideoSessionComponent implements OnInit {
}); });
this.toggleScrollPage("auto"); this.toggleScrollPage("auto");
this.exitFullScreen(); this.exitFullScreen();
if (this.OV) this.OV.close(false); if (this.OV) this.session.disconnect();
}
toggleLocalVideo() {
this.localVideoActivated = !this.localVideoActivated;
this.OV.toggleLocalVideoTrack(this.localVideoActivated);
this.videoIcon = this.localVideoActivated ? 'videocam' : 'videocam_off';
}
toggleLocalAudio() {
this.localAudioActivated = !this.localAudioActivated;
this.OV.toggleLocalAudioTrack(this.localAudioActivated);
this.audioIcon = this.localAudioActivated ? 'mic' : 'mic_off';
} }
toggleScrollPage(scroll: string) { toggleScrollPage(scroll: string) {
@ -196,39 +142,6 @@ export class VideoSessionComponent implements OnInit {
content.style.overflow = scroll; content.style.overflow = scroll;
} }
toggleFullScreen() {
let document: any = window.document;
let fs = document.getElementsByTagName('html')[0];
if (!document.fullscreenElement &&
!document.mozFullScreenElement &&
!document.webkitFullscreenElement &&
!document.msFullscreenElement) {
console.log("enter FULLSCREEN!");
this.fullscreenIcon = 'fullscreen_exit';
if (fs.requestFullscreen) {
fs.requestFullscreen();
} else if (fs.msRequestFullscreen) {
fs.msRequestFullscreen();
} else if (fs.mozRequestFullScreen) {
fs.mozRequestFullScreen();
} else if (fs.webkitRequestFullscreen) {
fs.webkitRequestFullscreen();
}
} else {
console.log("exit FULLSCREEN!");
this.fullscreenIcon = 'fullscreen';
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
}
}
exitFullScreen() { exitFullScreen() {
let document: any = window.document; let document: any = window.document;
let fs = document.getElementsByTagName('html')[0]; let fs = document.getElementsByTagName('html')[0];