mirror of https://github.com/OpenVidu/openvidu.git
Dynamic change of Publisher without leaving the Session
parent
7c29052e70
commit
34b753a298
|
@ -19,6 +19,7 @@ import { OpenViduInternal } from '../OpenViduInternal/OpenViduInternal';
|
|||
import { Session } from './Session';
|
||||
import { Publisher } from './Publisher';
|
||||
import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/OpenViduError';
|
||||
import { OutboundStreamOptions } from '../OpenViduInternal/index';
|
||||
|
||||
import * as adapter from 'webrtc-adapter';
|
||||
import * as screenSharing from '../ScreenSharing/Screen-Capturing.js';
|
||||
|
@ -58,7 +59,6 @@ export class OpenVidu {
|
|||
|
||||
initPublisher(parentId: string, cameraOptions?: any, callback?: Function): any {
|
||||
if (this.checkSystemRequirements()) {
|
||||
this.openVidu.storedPublisherOptions = cameraOptions;
|
||||
let publisher: Publisher;
|
||||
if (cameraOptions != null) {
|
||||
|
||||
|
@ -66,6 +66,7 @@ export class OpenVidu {
|
|||
cameraOptions.video = cameraOptions.video != null ? cameraOptions.video : true;
|
||||
|
||||
if (!cameraOptions.screen) {
|
||||
|
||||
// Webcam and/or microphone is being requested
|
||||
|
||||
let cameraOptionsAux = {
|
||||
|
@ -73,16 +74,19 @@ export class OpenVidu {
|
|||
sendVideo: cameraOptions.video != null ? cameraOptions.video : true,
|
||||
activeAudio: cameraOptions.audioActive != null ? cameraOptions.audioActive : true,
|
||||
activeVideo: cameraOptions.videoActive != null ? cameraOptions.videoActive : true,
|
||||
data: true,
|
||||
dataChannel: true,
|
||||
mediaConstraints: this.openVidu.generateMediaConstraints(cameraOptions)
|
||||
};
|
||||
cameraOptions = cameraOptionsAux;
|
||||
publisher = new Publisher(this.openVidu.initPublisherTagged(parentId, cameraOptions, callback), parentId, false);
|
||||
|
||||
publisher = new Publisher(this.openVidu.initPublisherTagged(parentId, cameraOptions, true, callback), parentId, false);
|
||||
console.info("'Publisher' initialized");
|
||||
|
||||
return publisher;
|
||||
|
||||
} else {
|
||||
publisher = new Publisher(this.openVidu.initPublisherScreen(parentId, callback), parentId, true);
|
||||
|
||||
publisher = new Publisher(this.openVidu.initPublisherScreen(parentId, true, callback), parentId, true);
|
||||
if (adapter.browserDetails.browser === 'firefox' && adapter.browserDetails.version >= 52) {
|
||||
screenSharingAuto.getScreenId((error, sourceId, screenConstraints) => {
|
||||
cameraOptions = {
|
||||
|
@ -90,14 +94,17 @@ export class OpenVidu {
|
|||
sendVideo: cameraOptions.video,
|
||||
activeAudio: cameraOptions.audioActive != null ? cameraOptions.audioActive : true,
|
||||
activeVideo: cameraOptions.videoActive != null ? cameraOptions.videoActive : true,
|
||||
data: true,
|
||||
dataChannel: true,
|
||||
mediaConstraints: {
|
||||
video: screenConstraints.video,
|
||||
audio: false
|
||||
}
|
||||
}
|
||||
|
||||
publisher.stream.configureScreenOptions(cameraOptions);
|
||||
console.info("'Publisher' initialized");
|
||||
|
||||
publisher.stream.ee.emitEvent('can-request-screen');
|
||||
});
|
||||
return publisher;
|
||||
} else if (adapter.browserDetails.browser === 'chrome') {
|
||||
|
@ -145,14 +152,16 @@ export class OpenVidu {
|
|||
sendVideo: cameraOptions.video != null ? cameraOptions.video : true,
|
||||
activeAudio: cameraOptions.audioActive != null ? cameraOptions.audioActive : true,
|
||||
activeVideo: cameraOptions.videoActive != null ? cameraOptions.videoActive : true,
|
||||
data: true,
|
||||
dataChannel: true,
|
||||
mediaConstraints: {
|
||||
video: screenConstraints.video,
|
||||
audio: false
|
||||
}
|
||||
}
|
||||
|
||||
publisher.stream.configureScreenOptions(cameraOptions);
|
||||
|
||||
publisher.stream.ee.emitEvent('can-request-screen');
|
||||
}, (error) => {
|
||||
console.error('getScreenId error', error);
|
||||
return;
|
||||
|
@ -169,14 +178,15 @@ export class OpenVidu {
|
|||
sendVideo: true,
|
||||
activeAudio: true,
|
||||
activeVideo: true,
|
||||
data: true,
|
||||
dataChannel: true,
|
||||
mediaConstraints: {
|
||||
audio: true,
|
||||
video: { width: { ideal: 1280 } }
|
||||
}
|
||||
}
|
||||
publisher = new Publisher(this.openVidu.initPublisherTagged(parentId, cameraOptions, callback), parentId, false);
|
||||
publisher = new Publisher(this.openVidu.initPublisherTagged(parentId, cameraOptions, true, callback), parentId, false);
|
||||
console.info("'Publisher' initialized");
|
||||
|
||||
return publisher;
|
||||
}
|
||||
} else {
|
||||
|
@ -184,6 +194,50 @@ export class OpenVidu {
|
|||
}
|
||||
}
|
||||
|
||||
reinitPublisher(publisher: Publisher): any {
|
||||
if (publisher.stream.typeOfVideo !== 'SCREEN') {
|
||||
publisher = new Publisher(this.openVidu.initPublisherTagged(publisher.stream.getParentId(), publisher.stream.outboundOptions, false), publisher.stream.getParentId(), false);
|
||||
console.info("'Publisher' initialized");
|
||||
return publisher;
|
||||
} else {
|
||||
publisher = new Publisher(this.openVidu.initPublisherScreen(publisher.stream.getParentId(), false), publisher.stream.getParentId(), true);
|
||||
if (adapter.browserDetails.browser === 'firefox' && adapter.browserDetails.version >= 52) {
|
||||
screenSharingAuto.getScreenId((error, sourceId, screenConstraints) => {
|
||||
|
||||
publisher.stream.outboundOptions.mediaConstraints.video = screenConstraints.video;
|
||||
publisher.stream.configureScreenOptions(publisher.stream.outboundOptions);
|
||||
console.info("'Publisher' initialized");
|
||||
|
||||
publisher.stream.ee.emitEvent('can-request-screen');
|
||||
});
|
||||
return publisher;
|
||||
} else if (adapter.browserDetails.browser === 'chrome') {
|
||||
screenSharingAuto.getScreenId((error, sourceId, screenConstraints) => {
|
||||
if (error === 'not-installed') {
|
||||
let error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, 'https://chrome.google.com/webstore/detail/screen-capturing/ajhifddimkapgcifgcodmmfdlknahffk');
|
||||
console.error(error);
|
||||
return;
|
||||
} else if (error === 'permission-denied') {
|
||||
let error = new OpenViduError(OpenViduErrorName.SCREEN_CAPTURE_DENIED, 'You must allow access to one window of your desktop');
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
publisher.stream.outboundOptions.mediaConstraints.video = screenConstraints.video;
|
||||
publisher.stream.configureScreenOptions(publisher.stream.outboundOptions);
|
||||
|
||||
publisher.stream.ee.emitEvent('can-request-screen');
|
||||
}, (error) => {
|
||||
console.error('getScreenId error', error);
|
||||
return;
|
||||
});
|
||||
console.info("'Publisher' initialized");
|
||||
return publisher;
|
||||
} else {
|
||||
console.error('Screen sharing not supported on ' + adapter.browserDetails.browser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkSystemRequirements(): number {
|
||||
let browser = adapter.browserDetails.browser;
|
||||
let version = adapter.browserDetails.version;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* stream.hasAudio(); stream.hasVideo(); stream.hasData();
|
||||
*/
|
||||
import { Stream, StreamOptions } from '../OpenViduInternal/Stream';
|
||||
import { Stream } from '../OpenViduInternal/Stream';
|
||||
import { Session } from './Session';
|
||||
|
||||
import EventEmitter = require('wolfy87-eventemitter');
|
||||
|
|
|
@ -11,7 +11,6 @@ import EventEmitter = require('wolfy87-eventemitter');
|
|||
export class Session {
|
||||
|
||||
sessionId: String;
|
||||
//capabilities: Capabilities
|
||||
connection: Connection;
|
||||
|
||||
private ee = new EventEmitter();
|
||||
|
@ -89,13 +88,14 @@ export class Session {
|
|||
this.streamPublish(publisher);
|
||||
}
|
||||
} else { // 'Session.unpublish(Publisher)' has been called
|
||||
let mypublisher = this.openVidu.initPublisher(publisher.stream.getParentId(), this.openVidu.openVidu.storedPublisherOptions);
|
||||
if (mypublisher.isScreenRequested && !mypublisher.stream.isScreenRequestedReady) { // Screen sharing Publisher and video stream not available yet
|
||||
mypublisher.stream.addOnceEventListener('screen-ready', () => {
|
||||
this.streamPublish(mypublisher);
|
||||
publisher = this.openVidu.reinitPublisher(publisher);
|
||||
|
||||
if (publisher.isScreenRequested && !publisher.stream.isScreenRequestedReady) { // Screen sharing Publisher and video stream not available yet
|
||||
publisher.stream.addOnceEventListener('screen-ready', () => {
|
||||
this.streamPublish(publisher);
|
||||
});
|
||||
} else { // Video stream already available
|
||||
this.streamPublish(mypublisher);
|
||||
this.streamPublish(publisher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Stream, StreamOptions } from '../OpenViduInternal/Stream';
|
||||
import { Stream } from '../OpenViduInternal/Stream';
|
||||
|
||||
import EventEmitter = require('wolfy87-eventemitter');
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Stream, StreamOptions } from './Stream';
|
||||
import { Stream, StreamOptionsServer, InboundStreamOptions } from './Stream';
|
||||
import { OpenViduInternal } from './OpenViduInternal';
|
||||
import { SessionInternal } from './SessionInternal';
|
||||
|
||||
|
@ -7,9 +7,7 @@ type ObjMap<T> = { [s: string]: T; }
|
|||
export interface ConnectionOptions {
|
||||
id: string;
|
||||
metadata: string;
|
||||
streams?: StreamOptions[];
|
||||
audioActive: boolean;
|
||||
videoActive: boolean;
|
||||
streams: StreamOptionsServer[];
|
||||
}
|
||||
|
||||
export class Connection {
|
||||
|
@ -18,7 +16,7 @@ export class Connection {
|
|||
public data: string;
|
||||
public creationTime: number;
|
||||
private streams: ObjMap<Stream> = {};
|
||||
private streamsOpts: StreamOptions;
|
||||
private inboundStreamsOpts: InboundStreamOptions;
|
||||
|
||||
constructor( private openVidu: OpenViduInternal, private local: boolean, private room: SessionInternal, private options?: ConnectionOptions ) {
|
||||
|
||||
|
@ -27,10 +25,11 @@ export class Connection {
|
|||
if ( options ) {
|
||||
|
||||
this.connectionId = options.id;
|
||||
this.data = options.metadata;
|
||||
|
||||
if ( options.streams ) {
|
||||
this.initStreams(options);
|
||||
if (options.metadata) {
|
||||
this.data = options.metadata;
|
||||
}
|
||||
if (options.streams) {
|
||||
this.initRemoteStreams(options);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +43,11 @@ export class Connection {
|
|||
removeStream( key: string ) {
|
||||
delete this.streams[key];
|
||||
delete this.room.getStreams()[key];
|
||||
delete this.streamsOpts;
|
||||
delete this.inboundStreamsOpts;
|
||||
}
|
||||
|
||||
setOptions(options: ConnectionOptions) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
getStreams() {
|
||||
|
@ -75,28 +78,23 @@ export class Connection {
|
|||
});
|
||||
}
|
||||
|
||||
initStreams(options) {
|
||||
for ( let streamOptions of options.streams ) {
|
||||
initRemoteStreams(options: ConnectionOptions) {
|
||||
let opts: StreamOptionsServer;
|
||||
for ( opts of options.streams ) {
|
||||
|
||||
let streamOpts = {
|
||||
id: streamOptions.id,
|
||||
let streamOptions: InboundStreamOptions = {
|
||||
id: opts.id,
|
||||
connection: this,
|
||||
sendAudio: streamOptions.sendAudio,
|
||||
sendVideo: streamOptions.sendVideo,
|
||||
recvAudio: ( streamOptions.audioActive == undefined ? true : streamOptions.audioActive ),
|
||||
recvVideo: ( streamOptions.videoActive == undefined ? true : streamOptions.videoActive ),
|
||||
typeOfVideo: streamOptions.typeOfVideo,
|
||||
activeAudio: streamOptions.activeAudio,
|
||||
activeVideo: streamOptions.activeVideo,
|
||||
data: streamOptions.data,
|
||||
mediaConstraints: streamOptions.mediaConstraints
|
||||
recvAudio: ( opts.audioActive == null ? true : opts.audioActive ),
|
||||
recvVideo: ( opts.videoActive == null ? true : opts.videoActive ),
|
||||
typeOfVideo: opts.typeOfVideo,
|
||||
}
|
||||
let stream = new Stream(this.openVidu, false, this.room, streamOpts );
|
||||
let stream = new Stream(this.openVidu, false, this.room, streamOptions);
|
||||
|
||||
this.addStream( stream );
|
||||
this.streamsOpts = streamOpts;
|
||||
this.addStream(stream);
|
||||
this.inboundStreamsOpts = streamOptions;
|
||||
}
|
||||
|
||||
console.info("Remote 'Connection' with 'connectionId' [" + this.connectionId + "] is now configured for receiving Streams with options: ", this.streamsOpts );
|
||||
console.info("Remote 'Connection' with 'connectionId' [" + this.connectionId + "] is now configured for receiving Streams with options: ", this.inboundStreamsOpts );
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
export enum OpenViduErrorName {
|
||||
export const enum OpenViduErrorName {
|
||||
CAMERA_ACCESS_DENIED = 'CAMERA_ACCESS_DENIED',
|
||||
MICROPHONE_ACCESS_DENIED = 'MICROPHONE_ACCESS_DENIED',
|
||||
SCREEN_CAPTURE_DENIED = 'SCREEN_CAPTURE_DENIED',
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
import { SessionInternal, SessionOptions } from './SessionInternal';
|
||||
import { OpenViduError, OpenViduErrorName } from './OpenViduError';
|
||||
import { Stream } from './Stream';
|
||||
import { Stream, OutboundStreamOptions } from './Stream';
|
||||
import * as RpcBuilder from '../KurentoUtils/kurento-jsonrpc';
|
||||
|
||||
export type Callback<T> = (error?: any, openVidu?: T) => void;
|
||||
|
@ -28,15 +28,10 @@ export class OpenViduInternal {
|
|||
private jsonRpcClient: any;
|
||||
private rpcParams: any;
|
||||
private callback: Callback<OpenViduInternal>;
|
||||
private camera: Stream;
|
||||
private localStream: Stream;
|
||||
private remoteStreams: Stream[] = [];
|
||||
|
||||
private secret: string;
|
||||
|
||||
constructor() { };
|
||||
|
||||
storedPublisherOptions: any;
|
||||
|
||||
/* NEW METHODS */
|
||||
initSession(sessionId) {
|
||||
console.info("'Session' initialized with 'sessionId' [" + sessionId + "]");
|
||||
|
@ -44,36 +39,56 @@ export class OpenViduInternal {
|
|||
return this.session;
|
||||
}
|
||||
|
||||
initPublisherTagged(parentId: string, cameraOptions: any, callback?: Function): Stream {
|
||||
initPublisherTagged(parentId: string, cameraOptions: OutboundStreamOptions, newStream: boolean, callback?: Function): Stream {
|
||||
|
||||
this.getCamera(cameraOptions);
|
||||
if (newStream) {
|
||||
if (cameraOptions == null) {
|
||||
cameraOptions = {
|
||||
connection: this.session.getLocalParticipant(),
|
||||
sendAudio: true,
|
||||
sendVideo: true,
|
||||
activeAudio: true,
|
||||
activeVideo: true,
|
||||
dataChannel: true,
|
||||
mediaConstraints: {
|
||||
audio: true,
|
||||
video: { width: { ideal: 1280 } }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cameraOptions.connection = this.session.getLocalParticipant();
|
||||
}
|
||||
this.localStream = new Stream(this, true, this.session, cameraOptions);
|
||||
}
|
||||
|
||||
this.camera.requestCameraAccess((error, camera) => {
|
||||
this.localStream.requestCameraAccess((error, localStream) => {
|
||||
if (error) {
|
||||
// Neither camera or microphone device is allowed/able to capture media
|
||||
// Neither localStream or microphone device is allowed/able to capture media
|
||||
console.error(error);
|
||||
if (callback) {
|
||||
callback(error);
|
||||
}
|
||||
this.camera.ee.emitEvent('access-denied-by-publisher');
|
||||
this.localStream.ee.emitEvent('access-denied-by-publisher');
|
||||
} else {
|
||||
this.camera.setVideoElement(this.cameraReady(camera!, parentId));
|
||||
this.localStream.setVideoElement(this.cameraReady(localStream!, parentId));
|
||||
if (callback) {
|
||||
callback(undefined);
|
||||
}
|
||||
}
|
||||
});
|
||||
return this.camera;
|
||||
return this.localStream;
|
||||
}
|
||||
|
||||
initPublisherScreen(parentId: string, callback?): Stream {
|
||||
if (!this.camera) {
|
||||
this.camera = new Stream(this, true, this.session, 'screen-options');
|
||||
initPublisherScreen(parentId: string, newStream: boolean, callback?): Stream {
|
||||
|
||||
if (newStream) {
|
||||
this.localStream = new Stream(this, true, this.session, 'screen-options');
|
||||
}
|
||||
this.camera.addOnceEventListener('can-request-screen', () => {
|
||||
this.camera.requestCameraAccess((error, camera) => {
|
||||
|
||||
this.localStream.addOnceEventListener('can-request-screen', () => {
|
||||
this.localStream.requestCameraAccess((error, localStream) => {
|
||||
if (error) {
|
||||
this.camera.ee.emitEvent('access-denied-by-publisher');
|
||||
this.localStream.ee.emitEvent('access-denied-by-publisher');
|
||||
let errorName: OpenViduErrorName = OpenViduErrorName.SCREEN_CAPTURE_DENIED;
|
||||
let errorMessage = 'You must allow access to one window of your desktop';
|
||||
let e = new OpenViduError(errorName, errorMessage);
|
||||
|
@ -83,20 +98,26 @@ export class OpenViduInternal {
|
|||
}
|
||||
}
|
||||
else {
|
||||
this.camera.setVideoElement(this.cameraReady(camera!, parentId));
|
||||
if (this.camera.getSendAudio()) {
|
||||
this.localStream.setVideoElement(this.cameraReady(localStream!, parentId));
|
||||
if (this.localStream.getSendAudio()) {
|
||||
// If the user wants to send audio with the screen capturing
|
||||
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
|
||||
.then(userStream => {
|
||||
this.camera.getMediaStream().addTrack(userStream.getAudioTracks()[0]);
|
||||
this.camera.isScreenRequestedReady = true;
|
||||
this.camera.ee.emitEvent('screen-ready');
|
||||
this.localStream.getMediaStream().addTrack(userStream.getAudioTracks()[0]);
|
||||
|
||||
// Mute audio if 'activeAudio' property is false
|
||||
if (userStream.getAudioTracks()[0] != null) {
|
||||
userStream.getAudioTracks()[0].enabled = this.localStream.outboundOptions.activeAudio;
|
||||
}
|
||||
|
||||
this.localStream.isScreenRequestedReady = true;
|
||||
this.localStream.ee.emitEvent('screen-ready');
|
||||
if (callback) {
|
||||
callback(undefined);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.camera.ee.emitEvent('access-denied-by-publisher');
|
||||
this.localStream.ee.emitEvent('access-denied-by-publisher');
|
||||
console.error("Error accessing the microphone", error);
|
||||
if (callback) {
|
||||
let errorName: OpenViduErrorName = OpenViduErrorName.MICROPHONE_ACCESS_DENIED;
|
||||
|
@ -105,8 +126,8 @@ export class OpenViduInternal {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
this.camera.isScreenRequestedReady = true;
|
||||
this.camera.ee.emitEvent('screen-ready');
|
||||
this.localStream.isScreenRequestedReady = true;
|
||||
this.localStream.ee.emitEvent('screen-ready');
|
||||
if (callback) {
|
||||
callback(undefined);
|
||||
}
|
||||
|
@ -114,18 +135,18 @@ export class OpenViduInternal {
|
|||
}
|
||||
});
|
||||
});
|
||||
return this.camera;
|
||||
return this.localStream;
|
||||
}
|
||||
|
||||
cameraReady(camera: Stream, parentId: string) {
|
||||
this.camera = camera;
|
||||
let videoElement = this.camera.playOnlyVideo(parentId, null);
|
||||
this.camera.emitStreamReadyEvent();
|
||||
cameraReady(localStream: Stream, parentId: string): HTMLVideoElement {
|
||||
this.localStream = localStream;
|
||||
let videoElement = this.localStream.playOnlyVideo(parentId, null);
|
||||
this.localStream.emitStreamReadyEvent();
|
||||
return videoElement;
|
||||
}
|
||||
|
||||
getLocalStream() {
|
||||
return this.camera;
|
||||
return this.localStream;
|
||||
}
|
||||
|
||||
getRemoteStreams() {
|
||||
|
@ -327,29 +348,6 @@ export class OpenViduInternal {
|
|||
}
|
||||
}
|
||||
|
||||
getCamera(options?) {
|
||||
|
||||
if (this.camera) {
|
||||
return this.camera;
|
||||
}
|
||||
|
||||
options = options || {
|
||||
sendAudio: true,
|
||||
sendVideo: true,
|
||||
activeAudio: true,
|
||||
activeVideo: true,
|
||||
data: true,
|
||||
mediaConstraints: {
|
||||
audio: true,
|
||||
video: { width: { ideal: 1280 } }
|
||||
}
|
||||
}
|
||||
options.connection = this.session.getLocalParticipant();
|
||||
|
||||
this.camera = new Stream(this, true, this.session, options);
|
||||
return this.camera;
|
||||
};
|
||||
|
||||
//CHAT
|
||||
sendMessage(message) {
|
||||
this.sendRequest('sendMessage', {
|
||||
|
@ -361,26 +359,6 @@ export class OpenViduInternal {
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
toggleLocalVideoTrack(activate: boolean) {
|
||||
this.getCamera().getWebRtcPeer().videoEnabled = activate;
|
||||
}
|
||||
|
||||
toggleLocalAudioTrack(activate: boolean) {
|
||||
this.getCamera().getWebRtcPeer().audioEnabled = activate;
|
||||
}
|
||||
|
||||
publishLocalVideoAudio() {
|
||||
this.toggleLocalVideoTrack(true);
|
||||
this.toggleLocalAudioTrack(true);
|
||||
}
|
||||
|
||||
unpublishLocalVideoAudio() {
|
||||
this.toggleLocalVideoTrack(false);
|
||||
this.toggleLocalAudioTrack(false);
|
||||
}
|
||||
|
||||
generateMediaConstraints(cameraOptions: any) {
|
||||
let mediaConstraints = {
|
||||
audio: cameraOptions.audio,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Stream } from './Stream';
|
||||
import { Stream, StreamOptionsServer } from './Stream';
|
||||
import { OpenViduInternal } from './OpenViduInternal';
|
||||
import { Connection, ConnectionOptions } from './Connection';
|
||||
import EventEmitter = require('wolfy87-eventemitter');
|
||||
import { Publisher } from '../OpenVidu/Publisher';
|
||||
|
||||
import EventEmitter = require('wolfy87-eventemitter');
|
||||
|
||||
const SECRET_PARAM = '?secret=';
|
||||
|
||||
export interface SessionOptions {
|
||||
|
@ -119,7 +120,7 @@ export class SessionInternal {
|
|||
|
||||
this.connected = true;
|
||||
|
||||
let exParticipants = response.value;
|
||||
let exParticipants: ConnectionOptions[] = response.value;
|
||||
|
||||
// IMPORTANT: Update connectionId with value send by server
|
||||
this.localParticipant.connectionId = response.id;
|
||||
|
@ -256,19 +257,19 @@ export class SessionInternal {
|
|||
});
|
||||
}
|
||||
|
||||
onParticipantPublished(options) {
|
||||
onParticipantPublished(response: ConnectionOptions) {
|
||||
|
||||
// Get the existing Connection created on 'onParticipantJoined' for
|
||||
// existing participants or create a new one for new participants
|
||||
let connection = this.participants[options.id];
|
||||
if (connection) {
|
||||
let connection: Connection = this.participants[response.id];
|
||||
if (connection != null) {
|
||||
// Update existing Connection
|
||||
options.metadata = connection.data;
|
||||
connection.options = options;
|
||||
connection.initStreams(options);
|
||||
response.metadata = connection.data;
|
||||
connection.setOptions(response);
|
||||
connection.initRemoteStreams(response);
|
||||
} else {
|
||||
// Create new Connection
|
||||
connection = new Connection(this.openVidu, false, this, options);
|
||||
connection = new Connection(this.openVidu, false, this, response);
|
||||
}
|
||||
|
||||
let pid = connection.connectionId;
|
||||
|
@ -320,6 +321,7 @@ export class SessionInternal {
|
|||
stream.dispose();
|
||||
this.openVidu.getRemoteStreams().splice(index, 1);
|
||||
delete this.streams[stream.streamId];
|
||||
connection.removeStream(stream.streamId);
|
||||
|
||||
}
|
||||
} else {
|
||||
|
@ -329,9 +331,9 @@ export class SessionInternal {
|
|||
}
|
||||
}
|
||||
|
||||
onParticipantJoined(msg) {
|
||||
onParticipantJoined(response: ConnectionOptions) {
|
||||
|
||||
let connection = new Connection(this.openVidu, false, this, msg);
|
||||
let connection = new Connection(this.openVidu, false, this, response);
|
||||
connection.creationTime = new Date().getTime();
|
||||
|
||||
let pid = connection.connectionId;
|
||||
|
@ -574,6 +576,8 @@ export class SessionInternal {
|
|||
stream.isReadyToPublish = false;
|
||||
stream.isScreenRequestedReady = false;
|
||||
|
||||
delete stream.connection.getStreams()[stream.streamId];
|
||||
|
||||
publisher.ee.emitEvent('streamDestroyed', [{
|
||||
stream: publisher.stream,
|
||||
preventDefault: () => { this.ee.removeEvent('stream-destroyed-default'); }
|
||||
|
|
|
@ -32,17 +32,29 @@ function hide(id: string) {
|
|||
document.getElementById(jq(id))!.style.display = 'none';
|
||||
}
|
||||
|
||||
export interface StreamOptions {
|
||||
export interface StreamOptionsServer {
|
||||
id: string;
|
||||
audioActive: boolean;
|
||||
videoActive: boolean;
|
||||
typeOfVideo: string;
|
||||
}
|
||||
|
||||
export interface InboundStreamOptions {
|
||||
id: string;
|
||||
connection: Connection;
|
||||
recvVideo: boolean;
|
||||
recvAudio: boolean;
|
||||
sendVideo: boolean;
|
||||
sendAudio: boolean;
|
||||
recvVideo: boolean;
|
||||
typeOfVideo: string;
|
||||
}
|
||||
|
||||
export interface OutboundStreamOptions {
|
||||
activeAudio: boolean;
|
||||
activeVideo: boolean;
|
||||
data: boolean;
|
||||
connection: Connection;
|
||||
dataChannel: boolean;
|
||||
mediaConstraints: any;
|
||||
sendAudio: boolean;
|
||||
sendVideo: boolean;
|
||||
}
|
||||
|
||||
export class Stream {
|
||||
|
@ -58,19 +70,13 @@ export class Stream {
|
|||
private wp: any;
|
||||
private video: HTMLVideoElement;
|
||||
private speechEvent: any;
|
||||
private recvVideo: boolean;
|
||||
private recvAudio: boolean;
|
||||
private sendVideo: boolean;
|
||||
private sendAudio: boolean;
|
||||
private mediaConstraints: any;
|
||||
private showMyRemote = false;
|
||||
private localMirrored = false;
|
||||
private chanId = 0;
|
||||
private dataChannel: boolean;
|
||||
private dataChannelOpened = false;
|
||||
|
||||
private activeAudio = true;
|
||||
private activeVideo = true;
|
||||
inboundOptions: InboundStreamOptions;
|
||||
outboundOptions: OutboundStreamOptions;
|
||||
|
||||
private parentId: string;
|
||||
public isReadyToPublish: boolean = false;
|
||||
|
@ -83,9 +89,17 @@ export class Stream {
|
|||
|
||||
constructor(private openVidu: OpenViduInternal, private local: boolean, private room: SessionInternal, options: any) {
|
||||
if (options !== 'screen-options') {
|
||||
this.configureOptions(options);
|
||||
if ('id' in options) {
|
||||
this.inboundOptions = options;
|
||||
} else {
|
||||
this.outboundOptions = options;
|
||||
}
|
||||
this.streamId = (options.id != null) ? options.id : ((options.sendVideo) ? "CAMERA" : "MICRO");
|
||||
this.typeOfVideo = (options.typeOfVideo != null) ? options.typeOfVideo : '';
|
||||
this.connection = options.connection;
|
||||
} else {
|
||||
this.isScreenRequested = true;
|
||||
this.typeOfVideo = 'SCREEN';
|
||||
this.connection = this.room.getLocalParticipant();
|
||||
}
|
||||
this.addEventListener('mediastream-updated', () => {
|
||||
|
@ -131,19 +145,19 @@ export class Stream {
|
|||
}
|
||||
|
||||
getRecvVideo() {
|
||||
return this.recvVideo;
|
||||
return this.inboundOptions.recvVideo;
|
||||
}
|
||||
|
||||
getRecvAudio() {
|
||||
return this.recvAudio;
|
||||
return this.inboundOptions.recvAudio;
|
||||
}
|
||||
|
||||
getSendVideo() {
|
||||
return this.sendVideo;
|
||||
return this.outboundOptions.sendVideo;
|
||||
}
|
||||
|
||||
getSendAudio() {
|
||||
return this.sendAudio;
|
||||
return this.outboundOptions.sendAudio;
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,7 +188,7 @@ export class Stream {
|
|||
|
||||
|
||||
isDataChannelEnabled() {
|
||||
return this.dataChannel;
|
||||
return this.outboundOptions.dataChannel;
|
||||
}
|
||||
|
||||
|
||||
|
@ -318,7 +332,7 @@ export class Stream {
|
|||
|
||||
this.connection.addStream(this);
|
||||
|
||||
let constraints = this.mediaConstraints;
|
||||
let constraints = this.outboundOptions.mediaConstraints;
|
||||
|
||||
/*let constraints2 = {
|
||||
audio: true,
|
||||
|
@ -334,14 +348,14 @@ export class Stream {
|
|||
|
||||
this.userMediaHasVideo((hasVideo) => {
|
||||
if (!hasVideo) {
|
||||
if (this.sendVideo) {
|
||||
if (this.outboundOptions.sendVideo) {
|
||||
callback(new OpenViduError(OpenViduErrorName.NO_VIDEO_DEVICE, 'You have requested camera access but there is no video input device available. Trying to connect with an audio input device only'), this);
|
||||
}
|
||||
if (!this.sendAudio) {
|
||||
if (!this.outboundOptions.sendAudio) {
|
||||
callback(new OpenViduError(OpenViduErrorName.NO_INPUT_DEVICE, 'You must init Publisher object with audio or video streams enabled'), undefined);
|
||||
} else {
|
||||
constraints.video = false;
|
||||
this.sendVideo = false;
|
||||
this.outboundOptions.sendVideo = false;
|
||||
this.requestCameraAccesAux(constraints, callback);
|
||||
}
|
||||
} else {
|
||||
|
@ -351,6 +365,7 @@ export class Stream {
|
|||
}
|
||||
|
||||
private requestCameraAccesAux(constraints, callback) {
|
||||
console.log(constraints);
|
||||
navigator.mediaDevices.getUserMedia(constraints)
|
||||
.then(userStream => {
|
||||
this.cameraAccessSuccess(userStream, callback);
|
||||
|
@ -361,7 +376,7 @@ export class Stream {
|
|||
let errorName: OpenViduErrorName;
|
||||
let errorMessage = error.toString();;
|
||||
if (!this.isScreenRequested) {
|
||||
errorName = this.sendVideo ? OpenViduErrorName.CAMERA_ACCESS_DENIED : OpenViduErrorName.MICROPHONE_ACCESS_DENIED;
|
||||
errorName = this.outboundOptions.sendVideo ? OpenViduErrorName.CAMERA_ACCESS_DENIED : OpenViduErrorName.MICROPHONE_ACCESS_DENIED;
|
||||
} else {
|
||||
errorName = OpenViduErrorName.SCREEN_CAPTURE_DENIED; // This code is only reachable for Firefox
|
||||
}
|
||||
|
@ -375,10 +390,10 @@ export class Stream {
|
|||
this.ee.emitEvent('access-allowed-by-publisher');
|
||||
|
||||
if (userStream.getAudioTracks()[0] != null) {
|
||||
userStream.getAudioTracks()[0].enabled = this.activeAudio;
|
||||
userStream.getAudioTracks()[0].enabled = this.outboundOptions.activeAudio;
|
||||
}
|
||||
if (userStream.getVideoTracks()[0] != null) {
|
||||
userStream.getVideoTracks()[0].enabled = this.activeVideo;
|
||||
userStream.getVideoTracks()[0].enabled = this.outboundOptions.activeVideo;
|
||||
}
|
||||
|
||||
this.mediaStream = userStream;
|
||||
|
@ -416,9 +431,9 @@ export class Stream {
|
|||
this.openVidu.sendRequest("publishVideo", {
|
||||
sdpOffer: sdpOfferParam,
|
||||
doLoopback: this.displayMyRemote() || false,
|
||||
audioActive: this.sendAudio,
|
||||
videoActive: this.sendVideo,
|
||||
typeOfVideo: ((this.sendVideo) ? ((this.isScreenRequested) ? 'SCREEN' :'CAMERA') : '')
|
||||
audioActive: this.outboundOptions.sendAudio,
|
||||
videoActive: this.outboundOptions.sendVideo,
|
||||
typeOfVideo: ((this.outboundOptions.sendVideo) ? ((this.isScreenRequested) ? 'SCREEN' :'CAMERA') : '')
|
||||
}, (error, response) => {
|
||||
if (error) {
|
||||
console.error("Error on publishVideo: " + JSON.stringify(error));
|
||||
|
@ -452,8 +467,8 @@ export class Stream {
|
|||
if (this.local) {
|
||||
|
||||
let userMediaConstraints = {
|
||||
audio: this.sendAudio,
|
||||
video: this.sendVideo
|
||||
audio: this.outboundOptions.sendAudio,
|
||||
video: this.outboundOptions.sendVideo
|
||||
}
|
||||
|
||||
let options: any = {
|
||||
|
@ -462,7 +477,7 @@ export class Stream {
|
|||
onicecandidate: this.connection.sendIceCandidate.bind(this.connection),
|
||||
}
|
||||
|
||||
if (this.dataChannel) {
|
||||
if (this.outboundOptions.dataChannel) {
|
||||
options.dataChannelConfig = {
|
||||
id: this.getChannelName(),
|
||||
onopen: this.onDataChannelOpen,
|
||||
|
@ -490,8 +505,8 @@ export class Stream {
|
|||
this.ee.emitEvent('stream-created-by-publisher');
|
||||
} else {
|
||||
let offerConstraints = {
|
||||
audio: this.recvAudio,
|
||||
video: this.recvVideo
|
||||
audio: this.inboundOptions.recvAudio,
|
||||
video: this.inboundOptions.recvVideo
|
||||
};
|
||||
console.debug("'Session.subscribe(Stream)' called. Constraints of generate SDP offer",
|
||||
offerConstraints);
|
||||
|
@ -656,43 +671,8 @@ export class Stream {
|
|||
console.info((this.local ? "Local " : "Remote ") + "'Stream' with id [" + this.streamId + "]' has been succesfully disposed");
|
||||
}
|
||||
|
||||
private configureOptions(options) {
|
||||
this.connection = options.connection;
|
||||
this.recvVideo = options.recvVideo || false;
|
||||
this.recvAudio = options.recvAudio || false;
|
||||
this.sendVideo = options.sendVideo;
|
||||
this.sendAudio = options.sendAudio;
|
||||
this.activeAudio = options.activeAudio;
|
||||
this.activeVideo = options.activeVideo;
|
||||
this.dataChannel = options.data || false;
|
||||
this.mediaConstraints = options.mediaConstraints;
|
||||
|
||||
this.hasAudio = ((this.recvAudio || this.sendAudio) != undefined) ? (this.recvAudio || this.sendAudio) : false;
|
||||
this.hasVideo = ((this.recvVideo || this.sendVideo) != undefined) ? (this.recvVideo || this.sendVideo) : false;
|
||||
this.typeOfVideo = options.typeOfVideo;
|
||||
|
||||
if (options.id) {
|
||||
this.streamId = options.id;
|
||||
} else {
|
||||
this.streamId = this.sendVideo ? "WEBCAM" : "MICRO";
|
||||
}
|
||||
}
|
||||
|
||||
configureScreenOptions(options) {
|
||||
if (options.id) {
|
||||
this.streamId = options.id;
|
||||
} else {
|
||||
this.streamId = "SCREEN";
|
||||
}
|
||||
this.recvVideo = options.recvVideo || false;
|
||||
this.recvAudio = options.recvAudio || false;
|
||||
this.sendVideo = options.sendVideo;
|
||||
this.sendAudio = options.sendAudio;
|
||||
this.activeAudio = options.activeAudio;
|
||||
this.activeVideo = options.activeVideo;
|
||||
this.dataChannel = options.data || false;
|
||||
this.mediaConstraints = options.mediaConstraints;
|
||||
|
||||
this.ee.emitEvent('can-request-screen');
|
||||
configureScreenOptions(options: OutboundStreamOptions) {
|
||||
this.outboundOptions = options;
|
||||
this.streamId = "SCREEN";
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue