mirror of https://github.com/OpenVidu/openvidu.git
openvidu-browser: MediaManager class parent of Publisher and Subscriber
parent
0dcc77b0c5
commit
d5e4482e37
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* (C) Copyright 2017-2018 OpenVidu (https://openvidu.io/)
|
||||
*
|
||||
* 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 { Stream } from './Stream';
|
||||
import { EventDispatcher } from '../OpenViduInternal/Interfaces/Public/EventDispatcher';
|
||||
import { Event } from '../OpenViduInternal/Events/Event';
|
||||
import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent';
|
||||
import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
|
||||
|
||||
import EventEmitter = require('wolfy87-eventemitter');
|
||||
|
||||
|
||||
/**
|
||||
* Interface in charge of displaying the media streams in the HTML DOM. This wraps any Publisher and Subscriber object, as well as
|
||||
* any extra representation in the DOM you assign to some Stream by calling [[Stream.addVideoElement]].
|
||||
*
|
||||
* The use of this interface is useful when you don't need to differentiate between streams and just want to directly manage videos
|
||||
*/
|
||||
export class MediaManager implements EventDispatcher {
|
||||
|
||||
/**
|
||||
* The Stream represented in the DOM by the MediaManager
|
||||
*/
|
||||
stream: Stream;
|
||||
|
||||
/**
|
||||
* Whether the MediaManager is representing in the DOM a local Stream ([[Publisher]]) or a remote Stream ([[Subscriber]])
|
||||
*/
|
||||
remote: boolean;
|
||||
|
||||
/**
|
||||
* The DOM HTMLElement assigned as target element when initializing the MediaManager. This property is defined when [[OpenVidu.initPublisher]]
|
||||
* or [[Session.subscribe]] methods have been called passing a valid `targetElement` parameter. It is undefined when [[OpenVidu.initPublisher]]
|
||||
* or [[Session.subscribe]] methods have been called passing *null* or *undefined* as `targetElement` parameter or when the MediaManager hass been
|
||||
* created by calling [[Stream.addVideoElement]]
|
||||
*/
|
||||
targetElement?: HTMLElement;
|
||||
|
||||
/**
|
||||
* The DOM HTMLVideoElement displaying the MediaManager's stream
|
||||
*/
|
||||
video: HTMLVideoElement;
|
||||
|
||||
/**
|
||||
* `id` attribute of the DOM HTMLVideoElement displaying the MediaManager's stream
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
isVideoElementCreated = false;
|
||||
|
||||
protected ee = new EventEmitter();
|
||||
protected customEe = new EventEmitter();
|
||||
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
constructor(stream: Stream, targetElement?: HTMLElement | string) {
|
||||
this.stream = stream;
|
||||
this.stream.mediaManagers.push(this);
|
||||
if (typeof targetElement === 'string') {
|
||||
const e = document.getElementById(targetElement);
|
||||
if (!!e) {
|
||||
this.targetElement = e;
|
||||
}
|
||||
} else if (targetElement instanceof HTMLElement) {
|
||||
this.targetElement = targetElement;
|
||||
} else if (!!this.targetElement) {
|
||||
console.warn("The provided 'targetElement' couldn't be resolved to any HTML element: " + targetElement);
|
||||
}
|
||||
|
||||
this.customEe.on('video-removed', (element: HTMLVideoElement) => {
|
||||
this.ee.emitEvent('videoElementDestroyed', [new VideoElementEvent(element, this, 'videoElementDestroyed')]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* See [[EventDispatcher.on]]
|
||||
*/
|
||||
on(type: string, handler: (event: Event) => void): EventDispatcher {
|
||||
this.ee.on(type, event => {
|
||||
if (event) {
|
||||
console.info("Event '" + type + "' triggered", event);
|
||||
} else {
|
||||
console.info("Event '" + type + "' triggered");
|
||||
}
|
||||
handler(event);
|
||||
});
|
||||
if (type === 'videoElementCreated') {
|
||||
if (!!this.stream && this.isVideoElementCreated) {
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(this.video, this, 'videoElementCreated')]);
|
||||
} else {
|
||||
this.customEe.on('video-element-created', element => {
|
||||
this.id = element.id;
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(element.element, this, 'videoElementCreated')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (type === 'videoPlaying') {
|
||||
if (!this.stream.displayMyRemote() && !!this.video &&
|
||||
this.video.currentTime > 0 &&
|
||||
this.video.paused === false &&
|
||||
this.video.ended === false &&
|
||||
this.video.readyState === 4) {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.video, this, 'videoPlaying')]);
|
||||
} else {
|
||||
this.customEe.once('video-is-playing', (element) => {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(element.element, this, 'videoPlaying')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* See [[EventDispatcher.once]]
|
||||
*/
|
||||
once(type: string, handler: (event: Event) => void): MediaManager {
|
||||
this.ee.once(type, event => {
|
||||
if (event) {
|
||||
console.info("Event '" + type + "' triggered once", event);
|
||||
} else {
|
||||
console.info("Event '" + type + "' triggered once");
|
||||
}
|
||||
handler(event);
|
||||
});
|
||||
if (type === 'videoElementCreated') {
|
||||
if (!!this.stream && this.isVideoElementCreated) {
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(this.video, this, 'videoElementCreated')]);
|
||||
} else {
|
||||
this.customEe.once('video-element-created', element => {
|
||||
this.id = element.id;
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(element.element, this, 'videoElementCreated')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (type === 'videoPlaying') {
|
||||
if (!this.stream.displayMyRemote() && this.video &&
|
||||
this.video.currentTime > 0 &&
|
||||
this.video.paused === false &&
|
||||
this.video.ended === false &&
|
||||
this.video.readyState === 4) {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.video, this, 'videoPlaying')]);
|
||||
} else {
|
||||
this.customEe.once('video-is-playing', (element) => {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(element.element, this, 'videoPlaying')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* See [[EventDispatcher.off]]
|
||||
*/
|
||||
off(type: string, handler?: (event: Event) => void): MediaManager {
|
||||
if (!handler) {
|
||||
this.ee.removeAllListeners(type);
|
||||
} else {
|
||||
this.ee.off(type, handler);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
insertVideo(targetElement?: HTMLElement, insertMode?: VideoInsertMode): HTMLVideoElement {
|
||||
if (!!targetElement) {
|
||||
|
||||
this.video = document.createElement('video');
|
||||
|
||||
this.video.id = (this.stream.isLocal() ? 'local-' : 'remote-') + 'video-' + this.stream.streamId;
|
||||
this.video.autoplay = true;
|
||||
this.video.controls = false;
|
||||
this.video.srcObject = this.stream.getMediaStream();
|
||||
|
||||
if (this.stream.isLocal() && !this.stream.displayMyRemote()) {
|
||||
this.video.muted = true;
|
||||
|
||||
if (this.stream.outboundStreamOpts.publisherProperties.mirror) {
|
||||
this.mirrorVideo();
|
||||
}
|
||||
|
||||
this.video.oncanplay = () => {
|
||||
console.info("Local 'Stream' with id [" + this.stream.streamId + '] video is now playing');
|
||||
this.customEe.emitEvent('video-is-playing', [{
|
||||
element: this.video
|
||||
}]);
|
||||
};
|
||||
} else {
|
||||
this.video.title = this.stream.streamId;
|
||||
}
|
||||
|
||||
this.targetElement = targetElement;
|
||||
|
||||
const insMode = !!insertMode ? insertMode : VideoInsertMode.APPEND;
|
||||
|
||||
this.insertVideoWithMode(insMode);
|
||||
|
||||
this.customEe.emitEvent('video-element-created', [{
|
||||
element: this.video
|
||||
}]);
|
||||
|
||||
this.isVideoElementCreated = true;
|
||||
}
|
||||
|
||||
if (this.stream.isLocal()) {
|
||||
this.stream.isLocalStreamReadyToPublish = true;
|
||||
this.stream.emitEvent('stream-ready-to-publish', []);
|
||||
}
|
||||
|
||||
return this.video;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
insertVideoWithMode(insertMode: VideoInsertMode): void {
|
||||
if (!!this.targetElement) {
|
||||
switch (insertMode) {
|
||||
case VideoInsertMode.AFTER:
|
||||
this.targetElement.parentNode!!.insertBefore(this.video, this.targetElement.nextSibling);
|
||||
break;
|
||||
case VideoInsertMode.APPEND:
|
||||
this.targetElement.appendChild(this.video);
|
||||
break;
|
||||
case VideoInsertMode.BEFORE:
|
||||
this.targetElement.parentNode!!.insertBefore(this.video, this.targetElement);
|
||||
break;
|
||||
case VideoInsertMode.PREPEND:
|
||||
this.targetElement.insertBefore(this.video, this.targetElement.childNodes[0]);
|
||||
break;
|
||||
case VideoInsertMode.REPLACE:
|
||||
this.targetElement.parentNode!!.replaceChild(this.video, this.targetElement);
|
||||
break;
|
||||
default:
|
||||
this.insertVideoWithMode(VideoInsertMode.APPEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
removeVideo(): void {
|
||||
if (!!this.video) {
|
||||
this.video.parentNode!.removeChild(this.video);
|
||||
this.customEe.emitEvent('video-removed', [this.video]);
|
||||
delete this.video;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
addOnCanPlayEvent() {
|
||||
if (!!this.video) {
|
||||
// let thumbnailId = this.video.thumb;
|
||||
this.video.oncanplay = () => {
|
||||
if (this.stream.isLocal() && this.stream.displayMyRemote()) {
|
||||
console.info("Your own remote 'Stream' with id [" + this.stream.streamId + '] video is now playing');
|
||||
this.customEe.emitEvent('remote-video-is-playing', [{
|
||||
element: this.video
|
||||
}]);
|
||||
} else if (!this.stream.isLocal() && !this.stream.displayMyRemote()) {
|
||||
console.info("Remote 'Stream' with id [" + this.stream.streamId + '] video is now playing');
|
||||
this.customEe.emitEvent('video-is-playing', [{
|
||||
element: this.video
|
||||
}]);
|
||||
}
|
||||
// show(thumbnailId);
|
||||
// this.hideSpinner(this.streamId);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private mirrorVideo(): void {
|
||||
this.video.style.transform = 'rotateY(180deg)';
|
||||
this.video.style.webkitTransform = 'rotateY(180deg)';
|
||||
}
|
||||
|
||||
}
|
|
@ -92,7 +92,7 @@ export class OpenVidu {
|
|||
* The [[Publisher]] object will dispatch a `videoPlaying` event once the local video starts playing (only if `videoElementCreated` event has been previously dispatched)
|
||||
*
|
||||
* @param targetElement HTML DOM element (or its `id` attribute) in which the video element of the Publisher will be inserted (see [[PublisherProperties.insertMode]]). If null or undefined no default video will be created for this Publisher
|
||||
* (you can always access the native MediaStream object by calling _Publisher.stream.getMediaStream()_ and use it as _srcObject_ of any HTML video element)
|
||||
* (you can always call method [[Stream.addVideoElement]] for the object [[Publisher.stream]] to manage the video elements on your own)
|
||||
* @param completionHandler `error` parameter is null if `initPublisher` succeeds, and is defined if it fails.
|
||||
* `completionHandler` function is called before the Publisher dispatches an `accessAllowed` or an `accessDenied` event
|
||||
*/
|
||||
|
@ -145,7 +145,7 @@ export class OpenVidu {
|
|||
}
|
||||
publisher.emitEvent('accessAllowed', []);
|
||||
}).catch((error) => {
|
||||
if (!!completionHandler !== undefined) {
|
||||
if (completionHandler !== undefined) {
|
||||
completionHandler(error);
|
||||
}
|
||||
publisher.emitEvent('accessDenied', []);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { MediaManager } from './MediaManager';
|
||||
import { OpenVidu } from './OpenVidu';
|
||||
import { Session } from './Session';
|
||||
import { Stream } from './Stream';
|
||||
|
@ -22,78 +23,49 @@ import { EventDispatcher } from '../OpenViduInternal/Interfaces/Public/EventDisp
|
|||
import { PublisherProperties } from '../OpenViduInternal/Interfaces/Public/PublisherProperties';
|
||||
import { InboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/InboundStreamOptions';
|
||||
import { OutboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/OutboundStreamOptions';
|
||||
import { Event } from '../OpenViduInternal/Events/Event';
|
||||
import { StreamEvent } from '../OpenViduInternal/Events/StreamEvent';
|
||||
import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent';
|
||||
import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError';
|
||||
import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
|
||||
|
||||
import EventEmitter = require('wolfy87-eventemitter');
|
||||
|
||||
|
||||
/**
|
||||
* Packs local media streams. Participants can publish it to a session. Initialized with [[OpenVidu.initPublisher]] method
|
||||
*/
|
||||
export class Publisher implements EventDispatcher {
|
||||
export class Publisher extends MediaManager {
|
||||
|
||||
/**
|
||||
* Whether the Publisher has been granted access to the requested input devices or not
|
||||
*/
|
||||
accessAllowed = false;
|
||||
|
||||
/**
|
||||
* HTML DOM element in which the Publisher's video has been inserted
|
||||
*/
|
||||
element: HTMLElement;
|
||||
|
||||
/**
|
||||
* DOM id of the Publisher's video element
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* The [[Session]] to which the Publisher belongs
|
||||
*/
|
||||
session: Session; // Initialized by Session.publish(Publisher)
|
||||
|
||||
/**
|
||||
* The [[Stream]] that you are publishing
|
||||
* @hidden
|
||||
*/
|
||||
stream: Stream;
|
||||
|
||||
private ee = new EventEmitter();
|
||||
accessDenied = false;
|
||||
|
||||
private element?: HTMLElement;
|
||||
private properties: PublisherProperties;
|
||||
private permissionDialogTimeout: NodeJS.Timer;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
constructor(targetElement: string | HTMLElement, properties: PublisherProperties, private openvidu: OpenVidu) {
|
||||
constructor(targEl: string | HTMLElement, properties: PublisherProperties, private openvidu: OpenVidu) {
|
||||
super(new Stream(new Session(openvidu), { publisherProperties: properties, mediaConstraints: {} }), targEl);
|
||||
this.properties = properties;
|
||||
this.stream = new Stream(this.session, { publisherProperties: properties, mediaConstraints: {} });
|
||||
|
||||
this.stream.on('video-removed', (element: HTMLVideoElement) => {
|
||||
this.ee.emitEvent('videoElementDestroyed', [new VideoElementEvent(element, this, 'videoElementDestroyed')]);
|
||||
});
|
||||
|
||||
this.stream.on('stream-destroyed-by-disconnect', (reason: string) => {
|
||||
this.stream.on('local-stream-destroyed-by-disconnect', (reason: string) => {
|
||||
const streamEvent = new StreamEvent(true, this, 'streamDestroyed', this.stream, reason);
|
||||
this.ee.emitEvent('streamDestroyed', [streamEvent]);
|
||||
streamEvent.callDefaultBehaviour();
|
||||
});
|
||||
|
||||
if (typeof targetElement === 'string') {
|
||||
const e = document.getElementById(targetElement);
|
||||
if (!!e) {
|
||||
this.element = e;
|
||||
}
|
||||
} else if (targetElement instanceof HTMLElement) {
|
||||
this.element = targetElement;
|
||||
}
|
||||
|
||||
if (!this.element) {
|
||||
console.warn("The provided 'targetElement' for the Publisher couldn't be resolved to any HTML element: " + targetElement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,18 +97,10 @@ export class Publisher implements EventDispatcher {
|
|||
/**
|
||||
* See [[EventDispatcher.on]]
|
||||
*/
|
||||
on(type: string, handler: (event: StreamEvent | VideoElementEvent) => void): EventDispatcher {
|
||||
this.ee.on(type, event => {
|
||||
if (event) {
|
||||
console.info("Event '" + type + "' triggered by 'Publisher'", event);
|
||||
} else {
|
||||
console.info("Event '" + type + "' triggered by 'Publisher'");
|
||||
}
|
||||
handler(event);
|
||||
});
|
||||
|
||||
on(type: string, handler: (event: Event) => void): EventDispatcher {
|
||||
super.on(type, handler);
|
||||
if (type === 'streamCreated') {
|
||||
if (!!this.stream && this.stream.isPublisherPublished) {
|
||||
if (!!this.stream && this.stream.isLocalStreamPublished) {
|
||||
this.ee.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', this.stream, '')]);
|
||||
} else {
|
||||
this.stream.on('stream-created-by-publisher', () => {
|
||||
|
@ -144,38 +108,13 @@ export class Publisher implements EventDispatcher {
|
|||
});
|
||||
}
|
||||
}
|
||||
if (type === 'videoElementCreated') {
|
||||
if (!!this.stream && this.stream.isVideoELementCreated) {
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(this.stream.getVideoElement(), this, 'videoElementCreated')]);
|
||||
} else {
|
||||
this.stream.on('video-element-created-by-stream', (element) => {
|
||||
this.id = element.id;
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(element.element, this, 'videoElementCreated')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (type === 'videoPlaying') {
|
||||
const video = this.stream.getVideoElement();
|
||||
if (!this.stream.displayMyRemote() && video &&
|
||||
video.currentTime > 0 &&
|
||||
video.paused === false &&
|
||||
video.ended === false &&
|
||||
video.readyState === 4) {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.stream.getVideoElement(), this, 'videoPlaying')]);
|
||||
} else {
|
||||
this.stream.on('video-is-playing', (element) => {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(element.element, this, 'videoPlaying')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (type === 'remoteVideoPlaying') {
|
||||
const video = this.stream.getVideoElement();
|
||||
if (this.stream.displayMyRemote() && video &&
|
||||
video.currentTime > 0 &&
|
||||
video.paused === false &&
|
||||
video.ended === false &&
|
||||
video.readyState === 4) {
|
||||
this.ee.emitEvent('remoteVideoPlaying', [new VideoElementEvent(this.stream.getVideoElement(), this, 'remoteVideoPlaying')]);
|
||||
if (this.stream.displayMyRemote() && this.video &&
|
||||
this.video.currentTime > 0 &&
|
||||
this.video.paused === false &&
|
||||
this.video.ended === false &&
|
||||
this.video.readyState === 4) {
|
||||
this.ee.emitEvent('remoteVideoPlaying', [new VideoElementEvent(this.video, this, 'remoteVideoPlaying')]);
|
||||
} else {
|
||||
this.stream.on('remote-video-is-playing', (element) => {
|
||||
this.ee.emitEvent('remoteVideoPlaying', [new VideoElementEvent(element.element, this, 'remoteVideoPlaying')]);
|
||||
|
@ -183,16 +122,15 @@ export class Publisher implements EventDispatcher {
|
|||
}
|
||||
}
|
||||
if (type === 'accessAllowed') {
|
||||
if (this.stream.accessIsAllowed) {
|
||||
if (this.accessAllowed) {
|
||||
this.ee.emitEvent('accessAllowed');
|
||||
}
|
||||
}
|
||||
if (type === 'accessDenied') {
|
||||
if (this.stream.accessIsDenied) {
|
||||
if (this.accessDenied) {
|
||||
this.ee.emitEvent('accessDenied');
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -200,18 +138,10 @@ export class Publisher implements EventDispatcher {
|
|||
/**
|
||||
* See [[EventDispatcher.once]]
|
||||
*/
|
||||
once(type: string, handler: (event: StreamEvent | VideoElementEvent) => void): Publisher {
|
||||
this.ee.once(type, event => {
|
||||
if (event) {
|
||||
console.info("Event '" + type + "' triggered by 'Publisher'", event);
|
||||
} else {
|
||||
console.info("Event '" + type + "' triggered by 'Publisher'");
|
||||
}
|
||||
handler(event);
|
||||
});
|
||||
|
||||
once(type: string, handler: (event: Event) => void): Publisher {
|
||||
super.once(type, handler);
|
||||
if (type === 'streamCreated') {
|
||||
if (!!this.stream && this.stream.isPublisherPublished) {
|
||||
if (!!this.stream && this.stream.isLocalStreamPublished) {
|
||||
this.ee.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', this.stream, '')]);
|
||||
} else {
|
||||
this.stream.once('stream-created-by-publisher', () => {
|
||||
|
@ -219,38 +149,13 @@ export class Publisher implements EventDispatcher {
|
|||
});
|
||||
}
|
||||
}
|
||||
if (type === 'videoElementCreated') {
|
||||
if (!!this.stream && this.stream.isVideoELementCreated) {
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(this.stream.getVideoElement(), this, 'videoElementCreated')]);
|
||||
} else {
|
||||
this.stream.once('video-element-created-by-stream', (element) => {
|
||||
this.id = element.id;
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(element.element, this, 'videoElementCreated')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (type === 'videoPlaying') {
|
||||
const video = this.stream.getVideoElement();
|
||||
if (!this.stream.displayMyRemote() && video &&
|
||||
video.currentTime > 0 &&
|
||||
video.paused === false &&
|
||||
video.ended === false &&
|
||||
video.readyState === 4) {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.stream.getVideoElement(), this, 'videoPlaying')]);
|
||||
} else {
|
||||
this.stream.once('video-is-playing', (element) => {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(element.element, this, 'videoPlaying')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (type === 'remoteVideoPlaying') {
|
||||
const video = this.stream.getVideoElement();
|
||||
if (this.stream.displayMyRemote() && video &&
|
||||
video.currentTime > 0 &&
|
||||
video.paused === false &&
|
||||
video.ended === false &&
|
||||
video.readyState === 4) {
|
||||
this.ee.emitEvent('remoteVideoPlaying', [new VideoElementEvent(this.stream.getVideoElement(), this, 'remoteVideoPlaying')]);
|
||||
if (this.stream.displayMyRemote() && this.video &&
|
||||
this.video.currentTime > 0 &&
|
||||
this.video.paused === false &&
|
||||
this.video.ended === false &&
|
||||
this.video.readyState === 4) {
|
||||
this.ee.emitEvent('remoteVideoPlaying', [new VideoElementEvent(this.video, this, 'remoteVideoPlaying')]);
|
||||
} else {
|
||||
this.stream.once('remote-video-is-playing', (element) => {
|
||||
this.ee.emitEvent('remoteVideoPlaying', [new VideoElementEvent(element.element, this, 'remoteVideoPlaying')]);
|
||||
|
@ -258,29 +163,15 @@ export class Publisher implements EventDispatcher {
|
|||
}
|
||||
}
|
||||
if (type === 'accessAllowed') {
|
||||
if (this.stream.accessIsAllowed) {
|
||||
if (this.accessAllowed) {
|
||||
this.ee.emitEvent('accessAllowed');
|
||||
}
|
||||
}
|
||||
if (type === 'accessDenied') {
|
||||
if (this.stream.accessIsDenied) {
|
||||
if (this.accessDenied) {
|
||||
this.ee.emitEvent('accessDenied');
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See [[EventDispatcher.off]]
|
||||
*/
|
||||
off(type: string, handler?: (event: StreamEvent | VideoElementEvent) => void): Publisher {
|
||||
if (!handler) {
|
||||
this.ee.removeAllListeners(type);
|
||||
} else {
|
||||
this.ee.off(type, handler);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -294,14 +185,14 @@ export class Publisher implements EventDispatcher {
|
|||
return new Promise((resolve, reject) => {
|
||||
|
||||
const errorCallback = (openViduError: OpenViduError) => {
|
||||
this.stream.accessIsDenied = true;
|
||||
this.stream.accessIsAllowed = false;
|
||||
this.accessDenied = true;
|
||||
this.accessAllowed = false;
|
||||
reject(openViduError);
|
||||
};
|
||||
|
||||
const successCallback = (mediaStream: MediaStream) => {
|
||||
this.stream.accessIsAllowed = true;
|
||||
this.stream.accessIsDenied = false;
|
||||
this.accessAllowed = true;
|
||||
this.accessDenied = false;
|
||||
|
||||
if (this.openvidu.isMediaStreamTrack(this.properties.audioSource)) {
|
||||
mediaStream.removeTrack(mediaStream.getAudioTracks()[0]);
|
||||
|
@ -322,7 +213,7 @@ export class Publisher implements EventDispatcher {
|
|||
}
|
||||
|
||||
this.stream.setMediaStream(mediaStream);
|
||||
this.stream.insertVideo(this.element, <VideoInsertMode>this.properties.insertMode);
|
||||
this.insertVideo(this.targetElement, <VideoInsertMode>this.properties.insertMode);
|
||||
|
||||
resolve();
|
||||
};
|
||||
|
|
|
@ -185,7 +185,7 @@ export class Session implements EventDispatcher {
|
|||
*
|
||||
* @param stream Stream object to subscribe to
|
||||
* @param targetElement HTML DOM element (or its `id` attribute) in which the video element of the Subscriber will be inserted (see [[SubscriberProperties.insertMode]]). If null or undefined no default video will be created for this Subscriber
|
||||
* (you can always access the native MediaStream object by calling _Subscriber.stream.getMediaStream()_ and use it as _srcObject_ of any HTML video element)
|
||||
* (you can always call method [[Stream.addVideoElement]] for the object [[Subscriber.stream]] to manage the video elements on your own)
|
||||
* @param completionHandler `error` parameter is null if `subscribe` succeeds, and is defined if it fails.
|
||||
*/
|
||||
subscribe(stream: Stream, targetElement: string | HTMLElement, param3?: ((error: Error | undefined) => void) | SubscriberProperties, param4?: ((error: Error | undefined) => void)): Subscriber {
|
||||
|
@ -226,7 +226,9 @@ export class Session implements EventDispatcher {
|
|||
}
|
||||
});
|
||||
const subscriber = new Subscriber(stream, targetElement, properties);
|
||||
stream.insertVideo(subscriber.element, <VideoInsertMode>properties.insertMode);
|
||||
stream.mediaManagers.forEach(mediaManager => {
|
||||
mediaManager.insertVideo(subscriber.targetElement, <VideoInsertMode>properties.insertMode);
|
||||
});
|
||||
return subscriber;
|
||||
}
|
||||
|
||||
|
@ -272,9 +274,9 @@ export class Session implements EventDispatcher {
|
|||
|
||||
console.info('Unsubscribing from ' + connectionId);
|
||||
|
||||
this.openvidu.sendRequest('unsubscribeFromVideo', {
|
||||
sender: subscriber.stream.connection.connectionId
|
||||
},
|
||||
this.openvidu.sendRequest(
|
||||
'unsubscribeFromVideo',
|
||||
{ sender: subscriber.stream.connection.connectionId },
|
||||
(error, response) => {
|
||||
if (error) {
|
||||
console.error('Error unsubscribing from ' + connectionId, error);
|
||||
|
@ -283,8 +285,9 @@ export class Session implements EventDispatcher {
|
|||
}
|
||||
subscriber.stream.disposeWebRtcPeer();
|
||||
subscriber.stream.disposeMediaStream();
|
||||
});
|
||||
subscriber.stream.removeVideo();
|
||||
}
|
||||
);
|
||||
subscriber.stream.removeVideos();
|
||||
}
|
||||
|
||||
|
||||
|
@ -307,7 +310,7 @@ export class Session implements EventDispatcher {
|
|||
publisher.session = this;
|
||||
publisher.stream.session = this;
|
||||
|
||||
if (!publisher.stream.isPublisherPublished) {
|
||||
if (!publisher.stream.isLocalStreamPublished) {
|
||||
// 'Session.unpublish(Publisher)' has NOT been called
|
||||
this.connection.addStream(publisher.stream);
|
||||
publisher.stream.publish()
|
||||
|
@ -788,7 +791,7 @@ export class Session implements EventDispatcher {
|
|||
if (!!this.connection.stream) {
|
||||
// Make Publisher object dispatch 'streamDestroyed' event (if there's a local stream)
|
||||
this.connection.stream.disposeWebRtcPeer();
|
||||
this.connection.stream.emitEvent('stream-destroyed-by-disconnect', [reason]);
|
||||
this.connection.stream.emitEvent('local-stream-destroyed-by-disconnect', [reason]);
|
||||
}
|
||||
|
||||
if (!this.connection.disposed) {
|
||||
|
|
|
@ -16,15 +16,17 @@
|
|||
*/
|
||||
|
||||
import { Connection } from './Connection';
|
||||
import { MediaManager } from './MediaManager';
|
||||
import { Session } from './Session';
|
||||
import { InboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/InboundStreamOptions';
|
||||
import { OutboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/OutboundStreamOptions';
|
||||
import { WebRtcStats } from '../OpenViduInternal/WebRtcStats/WebRtcStats';
|
||||
import { PublisherSpeakingEvent } from '../OpenViduInternal/Events/PublisherSpeakingEvent';
|
||||
import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
|
||||
|
||||
import EventEmitter = require('wolfy87-eventemitter');
|
||||
|
||||
import * as kurentoUtils from '../OpenViduInternal/KurentoUtils/kurento-utils-js';
|
||||
import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -63,13 +65,15 @@ export class Stream {
|
|||
*/
|
||||
typeOfVideo?: string;
|
||||
|
||||
/**
|
||||
* Array of [[MediaManager]] objects displaying this stream in the DOM
|
||||
*/
|
||||
mediaManagers: MediaManager[] = [];
|
||||
|
||||
private ee = new EventEmitter();
|
||||
|
||||
private webRtcPeer: any;
|
||||
private mediaStream: MediaStream;
|
||||
private video: HTMLVideoElement;
|
||||
private targetElement: HTMLElement;
|
||||
private parentId: string;
|
||||
private webRtcStats: WebRtcStats;
|
||||
|
||||
private isSubscribeToRemote = false;
|
||||
|
@ -77,23 +81,11 @@ export class Stream {
|
|||
/**
|
||||
* @hidden
|
||||
*/
|
||||
isReadyToPublish = false;
|
||||
isLocalStreamReadyToPublish = false;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
isPublisherPublished = false;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
isVideoELementCreated = false;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
accessIsAllowed = false;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
accessIsDenied = false;
|
||||
isLocalStreamPublished = false;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
|
@ -149,11 +141,30 @@ export class Stream {
|
|||
}
|
||||
|
||||
this.on('mediastream-updated', () => {
|
||||
if (this.video) this.video.srcObject = this.mediaStream;
|
||||
this.mediaManagers.forEach(mediaManager => {
|
||||
if (!!mediaManager.video) {
|
||||
mediaManager.video.srcObject = this.mediaStream;
|
||||
}
|
||||
});
|
||||
console.debug('Video srcObject [' + this.mediaStream + '] updated in stream [' + this.streamId + ']');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes `video` element parameter display this Stream. This is useful when you are managing the video elements on your own
|
||||
* (parameter `targetElement` of methods [[OpenVidu.initPublisher]] or [[Session.subscribe]] is set to *null* or *undefined*)
|
||||
* or if you want to have multiple video elements display the same media stream
|
||||
*/
|
||||
addVideoElement(video: HTMLVideoElement): MediaManager {
|
||||
video.srcObject = this.mediaStream;
|
||||
const mediaManager = new MediaManager(this);
|
||||
mediaManager.video = video;
|
||||
mediaManager.id = video.id;
|
||||
mediaManager.isVideoElementCreated = true;
|
||||
mediaManager.remote = !this.isLocal();
|
||||
return mediaManager;
|
||||
}
|
||||
|
||||
|
||||
/* Hidden methods */
|
||||
|
||||
|
@ -186,13 +197,6 @@ export class Stream {
|
|||
return this.webRtcPeer.peerConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
getVideoElement(): HTMLVideoElement {
|
||||
return this.video;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
|
@ -227,7 +231,7 @@ export class Stream {
|
|||
*/
|
||||
publish(): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this.isReadyToPublish) {
|
||||
if (this.isLocalStreamReadyToPublish) {
|
||||
this.initWebRtcPeerSend()
|
||||
.then(() => {
|
||||
resolve();
|
||||
|
@ -301,68 +305,6 @@ export class Stream {
|
|||
this.ee.once(eventName, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
insertVideo(targetElement?: HTMLElement, insertMode?: VideoInsertMode): HTMLVideoElement {
|
||||
if (!!targetElement) {
|
||||
|
||||
this.video = document.createElement('video');
|
||||
|
||||
this.video.id = (this.isLocal() ? 'local-' : 'remote-') + 'video-' + this.streamId;
|
||||
this.video.autoplay = true;
|
||||
this.video.controls = false;
|
||||
this.video.srcObject = this.mediaStream;
|
||||
|
||||
if (this.isLocal() && !this.displayMyRemote()) {
|
||||
this.video.muted = true;
|
||||
|
||||
if (this.outboundStreamOpts.publisherProperties.mirror) {
|
||||
this.mirrorVideo(this.video);
|
||||
}
|
||||
|
||||
this.video.oncanplay = () => {
|
||||
console.info("Local 'Stream' with id [" + this.streamId + '] video is now playing');
|
||||
this.ee.emitEvent('video-is-playing', [{
|
||||
element: this.video
|
||||
}]);
|
||||
};
|
||||
} else {
|
||||
this.video.title = this.streamId;
|
||||
}
|
||||
|
||||
this.targetElement = targetElement;
|
||||
this.parentId = targetElement.id;
|
||||
|
||||
const insMode = !!insertMode ? insertMode : VideoInsertMode.APPEND;
|
||||
this.insertElementWithMode(this.video, insMode);
|
||||
|
||||
this.ee.emitEvent('video-element-created-by-stream', [{
|
||||
element: this.video
|
||||
}]);
|
||||
|
||||
this.isVideoELementCreated = true;
|
||||
}
|
||||
|
||||
this.isReadyToPublish = true;
|
||||
this.ee.emitEvent('stream-ready-to-publish');
|
||||
|
||||
return this.video;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
removeVideo(): void {
|
||||
if (this.video) {
|
||||
if (document.getElementById(this.parentId)) {
|
||||
document.getElementById(this.parentId)!.removeChild(this.video);
|
||||
this.ee.emitEvent('video-removed', [this.video]);
|
||||
}
|
||||
delete this.video;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
|
@ -445,6 +387,15 @@ export class Stream {
|
|||
this.speechEvent = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
removeVideos(): void {
|
||||
this.mediaManagers.forEach(mediaManager => {
|
||||
mediaManager.removeVideo();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* Private methods */
|
||||
|
||||
|
@ -510,7 +461,7 @@ export class Stream {
|
|||
this.webRtcPeer.generateOffer(successCallback);
|
||||
});
|
||||
}
|
||||
this.isPublisherPublished = true;
|
||||
this.isLocalStreamPublished = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -588,24 +539,9 @@ export class Stream {
|
|||
}
|
||||
}
|
||||
|
||||
if (!!this.video) {
|
||||
// let thumbnailId = this.video.thumb;
|
||||
this.video.oncanplay = () => {
|
||||
if (this.isLocal() && this.displayMyRemote()) {
|
||||
console.info("Your own remote 'Stream' with id [" + this.streamId + '] video is now playing');
|
||||
this.ee.emitEvent('remote-video-is-playing', [{
|
||||
element: this.video
|
||||
}]);
|
||||
} else if (!this.isLocal() && !this.displayMyRemote()) {
|
||||
console.info("Remote 'Stream' with id [" + this.streamId + '] video is now playing');
|
||||
this.ee.emitEvent('video-is-playing', [{
|
||||
element: this.video
|
||||
}]);
|
||||
}
|
||||
// show(thumbnailId);
|
||||
// this.hideSpinner(this.streamId);
|
||||
};
|
||||
}
|
||||
this.mediaManagers.forEach(mediaManager => {
|
||||
mediaManager.addOnCanPlayEvent();
|
||||
});
|
||||
this.session.emitEvent('stream-subscribed', [{
|
||||
stream: this
|
||||
}]);
|
||||
|
@ -631,38 +567,12 @@ export class Stream {
|
|||
}
|
||||
}
|
||||
|
||||
private isLocal(): boolean {
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
isLocal(): boolean {
|
||||
// inbound options undefined and outbound options defined
|
||||
return (!this.inboundStreamOpts && !!this.outboundStreamOpts);
|
||||
}
|
||||
|
||||
private insertElementWithMode(element: HTMLElement, insertMode: VideoInsertMode): void {
|
||||
if (!!this.targetElement) {
|
||||
switch (insertMode) {
|
||||
case VideoInsertMode.AFTER:
|
||||
this.targetElement.parentNode!!.insertBefore(element, this.targetElement.nextSibling);
|
||||
break;
|
||||
case VideoInsertMode.APPEND:
|
||||
this.targetElement.appendChild(element);
|
||||
break;
|
||||
case VideoInsertMode.BEFORE:
|
||||
this.targetElement.parentNode!!.insertBefore(element, this.targetElement);
|
||||
break;
|
||||
case VideoInsertMode.PREPEND:
|
||||
this.targetElement.insertBefore(element, this.targetElement.childNodes[0]);
|
||||
break;
|
||||
case VideoInsertMode.REPLACE:
|
||||
this.targetElement.parentNode!!.replaceChild(element, this.targetElement);
|
||||
break;
|
||||
default:
|
||||
this.insertElementWithMode(element, VideoInsertMode.APPEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private mirrorVideo(video: HTMLVideoElement): void {
|
||||
video.style.transform = 'rotateY(180deg)';
|
||||
video.style.webkitTransform = 'rotateY(180deg)';
|
||||
}
|
||||
|
||||
}
|
|
@ -15,56 +15,27 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { MediaManager } from './MediaManager';
|
||||
import { Stream } from './Stream';
|
||||
import { SubscriberProperties } from '../OpenViduInternal/Interfaces/Public/SubscriberProperties';
|
||||
import { EventDispatcher } from '../OpenViduInternal/Interfaces/Public/EventDispatcher';
|
||||
import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent';
|
||||
import EventEmitter = require('wolfy87-eventemitter');
|
||||
|
||||
|
||||
/**
|
||||
* Packs remote media streams. Participants automatically receive them when others publish their streams. Initialized with [[Session.subscribe]] method
|
||||
*/
|
||||
export class Subscriber implements EventDispatcher {
|
||||
|
||||
/**
|
||||
* HTML DOM element in which the Subscriber's video has been inserted
|
||||
*/
|
||||
element: HTMLElement;
|
||||
|
||||
/**
|
||||
* DOM id of the Subscriber's video element
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* The [[Stream]] to which you are subscribing
|
||||
*/
|
||||
stream: Stream;
|
||||
|
||||
private ee = new EventEmitter();
|
||||
export class Subscriber extends MediaManager {
|
||||
|
||||
private element?: HTMLElement;
|
||||
private properties: SubscriberProperties;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
constructor(stream: Stream, targetElement: string | HTMLElement, properties: SubscriberProperties) {
|
||||
constructor(stream: Stream, targEl: string | HTMLElement, properties: SubscriberProperties) {
|
||||
super(stream, targEl);
|
||||
this.element = this.targetElement;
|
||||
this.stream = stream;
|
||||
this.properties = properties;
|
||||
|
||||
if (typeof targetElement === 'string') {
|
||||
const e = document.getElementById(targetElement);
|
||||
if (!!e) {
|
||||
this.element = e;
|
||||
}
|
||||
} else if (targetElement instanceof HTMLElement) {
|
||||
this.element = targetElement;
|
||||
}
|
||||
|
||||
this.stream.once('video-removed', (element: HTMLVideoElement) => {
|
||||
this.ee.emitEvent('videoElementDestroyed', [new VideoElementEvent(element, this, 'videoElementDestroyed')]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,101 +62,4 @@ export class Subscriber implements EventDispatcher {
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See [[EventDispatcher.on]]
|
||||
*/
|
||||
on(type: string, handler: (event: VideoElementEvent) => void): EventDispatcher {
|
||||
this.ee.on(type, event => {
|
||||
if (event) {
|
||||
console.info("Event '" + type + "' triggered by 'Subscriber'", event);
|
||||
} else {
|
||||
console.info("Event '" + type + "' triggered by 'Subscriber'");
|
||||
}
|
||||
handler(event);
|
||||
});
|
||||
|
||||
if (type === 'videoElementCreated') {
|
||||
if (this.stream.isVideoELementCreated) {
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(this.stream.getVideoElement(), this, 'videoElementCreated')]);
|
||||
} else {
|
||||
this.stream.once('video-element-created-by-stream', element => {
|
||||
this.id = element.id;
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(element, this, 'videoElementCreated')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (type === 'videoPlaying') {
|
||||
const video = this.stream.getVideoElement();
|
||||
if (!this.stream.displayMyRemote() && video &&
|
||||
video.currentTime > 0 &&
|
||||
video.paused === false &&
|
||||
video.ended === false &&
|
||||
video.readyState === 4) {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.stream.getVideoElement(), this, 'videoPlaying')]);
|
||||
} else {
|
||||
this.stream.once('video-is-playing', (element) => {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(element.element, this, 'videoPlaying')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See [[EventDispatcher.once]]
|
||||
*/
|
||||
once(type: string, handler: (event: VideoElementEvent) => void): Subscriber {
|
||||
this.ee.once(type, event => {
|
||||
if (event) {
|
||||
console.info("Event '" + type + "' triggered once by 'Subscriber'", event);
|
||||
} else {
|
||||
console.info("Event '" + type + "' triggered once by 'Subscriber'");
|
||||
}
|
||||
handler(event);
|
||||
});
|
||||
|
||||
if (type === 'videoElementCreated') {
|
||||
if (this.stream.isVideoELementCreated) {
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(this.stream.getVideoElement(), this, 'videoElementCreated')]);
|
||||
} else {
|
||||
this.stream.once('video-element-created-by-stream', element => {
|
||||
this.id = element.id;
|
||||
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(element, this, 'videoElementCreated')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (type === 'videoPlaying') {
|
||||
const video = this.stream.getVideoElement();
|
||||
if (!this.stream.displayMyRemote() && video &&
|
||||
video.currentTime > 0 &&
|
||||
video.paused === false &&
|
||||
video.ended === false &&
|
||||
video.readyState === 4) {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.stream.getVideoElement(), this, 'videoPlaying')]);
|
||||
} else {
|
||||
this.stream.once('video-is-playing', (element) => {
|
||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(element.element, this, 'videoPlaying')]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See [[EventDispatcher.off]]
|
||||
*/
|
||||
off(type: string, handler?: (event: VideoElementEvent) => void): Subscriber {
|
||||
if (!handler) {
|
||||
this.ee.removeAllListeners(type);
|
||||
} else {
|
||||
this.ee.off(type, handler);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -15,9 +15,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { Publisher } from '../../OpenVidu/Publisher';
|
||||
import { MediaManager } from '../../OpenVidu/MediaManager';
|
||||
import { Session } from '../../OpenVidu/Session';
|
||||
import { Subscriber } from '../../OpenVidu/Subscriber';
|
||||
|
||||
export abstract class Event {
|
||||
|
||||
|
@ -29,7 +28,7 @@ export abstract class Event {
|
|||
/**
|
||||
* The object that dispatched the event
|
||||
*/
|
||||
target: Session | Subscriber | Publisher;
|
||||
target: Session | MediaManager;
|
||||
|
||||
/**
|
||||
* The type of event. This is the same string you pass as first parameter when calling method `on()` of any object implementing [[EventDispatcher]] interface
|
||||
|
@ -41,7 +40,7 @@ export abstract class Event {
|
|||
/**
|
||||
* @hidden
|
||||
*/
|
||||
constructor(cancelable, target, type) {
|
||||
constructor(cancelable: boolean, target: Session | MediaManager, type: string) {
|
||||
this.cancelable = cancelable;
|
||||
this.target = target;
|
||||
this.type = type;
|
||||
|
|
|
@ -52,7 +52,7 @@ export class SessionDisconnectedEvent extends Event {
|
|||
if (!!session.remoteConnections[connectionId].stream) {
|
||||
session.remoteConnections[connectionId].stream.disposeWebRtcPeer();
|
||||
session.remoteConnections[connectionId].stream.disposeMediaStream();
|
||||
session.remoteConnections[connectionId].stream.removeVideo();
|
||||
session.remoteConnections[connectionId].stream.removeVideos();
|
||||
delete session.remoteStreamsCreated[session.remoteConnections[connectionId].stream.streamId];
|
||||
session.remoteConnections[connectionId].dispose();
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ export class StreamEvent extends Event {
|
|||
// Remote Stream
|
||||
this.stream.disposeWebRtcPeer();
|
||||
this.stream.disposeMediaStream();
|
||||
this.stream.removeVideo();
|
||||
this.stream.removeVideos();
|
||||
|
||||
} else if (this.target instanceof Publisher) {
|
||||
|
||||
|
@ -73,8 +73,8 @@ export class StreamEvent extends Event {
|
|||
|
||||
// Local Stream
|
||||
this.stream.disposeMediaStream();
|
||||
this.stream.removeVideo();
|
||||
this.stream.isReadyToPublish = false;
|
||||
this.stream.removeVideos();
|
||||
this.stream.isLocalStreamReadyToPublish = false;
|
||||
}
|
||||
|
||||
// Delete stream from Session.remoteStreamsCreated map
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
import { Event } from './Event';
|
||||
import { MediaManager } from '../../OpenVidu/MediaManager';
|
||||
import { Publisher } from '../../OpenVidu/Publisher';
|
||||
import { Subscriber } from '../../OpenVidu/Subscriber';
|
||||
|
||||
|
@ -37,7 +38,7 @@ export class VideoElementEvent extends Event {
|
|||
/**
|
||||
* @hidden
|
||||
*/
|
||||
constructor(element: HTMLVideoElement, target: Publisher | Subscriber, type: string) {
|
||||
constructor(element: HTMLVideoElement, target: MediaManager, type: string) {
|
||||
super(false, target, type);
|
||||
this.element = element;
|
||||
}
|
||||
|
|
|
@ -21,17 +21,23 @@ export interface EventDispatcher {
|
|||
|
||||
/**
|
||||
* Adds function `handler` to handle event `type`
|
||||
*
|
||||
* @returns The EventDispatcher object
|
||||
*/
|
||||
on(type: string, handler: (event: Event) => void): EventDispatcher;
|
||||
|
||||
/**
|
||||
* Adds function `handler` to handle event `type` just once. The handler will be automatically removed after first execution
|
||||
*
|
||||
* @returns The object that dispatched the event
|
||||
*/
|
||||
once(type: string, handler: (event: Event) => void): any;
|
||||
once(type: string, handler: (event: Event) => void): Object;
|
||||
|
||||
/**
|
||||
* Removes a `handler` from event `type`. If no handler is provided, all handlers will be removed from the event
|
||||
*
|
||||
* @returns The object that dispatched the event
|
||||
*/
|
||||
off(type: string, handler?: (event: Event) => void): any;
|
||||
off(type: string, handler?: (event: Event) => void): Object;
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@ export { OpenVidu } from './OpenVidu/OpenVidu';
|
|||
export { Session } from './OpenVidu/Session';
|
||||
export { Publisher } from './OpenVidu/Publisher';
|
||||
export { Subscriber } from './OpenVidu/Subscriber';
|
||||
export { MediaManager } from './OpenVidu/MediaManager';
|
||||
export { Stream } from './OpenVidu/Stream';
|
||||
export { Connection } from './OpenVidu/Connection';
|
||||
export { LocalRecorder } from './OpenVidu/LocalRecorder';
|
||||
|
|
Loading…
Reference in New Issue