diff --git a/openvidu-browser/src/OpenVidu/EventDispatcher.ts b/openvidu-browser/src/OpenVidu/EventDispatcher.ts index 726a0d93..cb298681 100644 --- a/openvidu-browser/src/OpenVidu/EventDispatcher.ts +++ b/openvidu-browser/src/OpenVidu/EventDispatcher.ts @@ -16,6 +16,9 @@ */ import { Event as Event } from '../OpenViduInternal/Events/Event'; +import { SessionEventMap } from '../OpenViduInternal/Events/EventMap/SessionEventMap'; +import { StreamManagerEventMap } from '../OpenViduInternal/Events/EventMap/StreamManagerEventMap'; + import EventEmitter = require('wolfy87-eventemitter'); import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; @@ -40,33 +43,21 @@ export abstract class EventDispatcher { * * @returns The EventDispatcher object */ - abstract on(type: string, handler: (event: Event) => void): EventDispatcher; + abstract on(type: K, handler: (event: (SessionEventMap | StreamManagerEventMap)[K]) => void): this; /** * 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 */ - abstract once(type: string, handler: (event: Event) => void): EventDispatcher; + abstract once(type: K, handler: (event: (SessionEventMap | StreamManagerEventMap)[K]) => void): this; /** * 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): EventDispatcher { - if (!handler) { - this.ee.removeAllListeners(type); - } else { - // Must remove internal arrow function handler paired with user handler - const arrowHandler = this.userHandlerArrowHandler.get(handler); - if (!!arrowHandler) { - this.ee.off(type, arrowHandler); - } - this.userHandlerArrowHandler.delete(handler); - } - return this; - } + abstract off(type: K, handler?: (event: (SessionEventMap | StreamManagerEventMap)[K]) => void): this; /** * @hidden @@ -104,4 +95,21 @@ export abstract class EventDispatcher { return this; } + /** + * @hidden + */ + offAux(type: string, handler?: (event: Event) => void): EventDispatcher { + if (!handler) { + this.ee.removeAllListeners(type); + } else { + // Must remove internal arrow function handler paired with user handler + const arrowHandler = this.userHandlerArrowHandler.get(handler); + if (!!arrowHandler) { + this.ee.off(type, arrowHandler); + } + this.userHandlerArrowHandler.delete(handler); + } + return this; + } + } \ No newline at end of file diff --git a/openvidu-browser/src/OpenVidu/Publisher.ts b/openvidu-browser/src/OpenVidu/Publisher.ts index 8c8e6dc2..9dcb3f86 100644 --- a/openvidu-browser/src/OpenVidu/Publisher.ts +++ b/openvidu-browser/src/OpenVidu/Publisher.ts @@ -19,12 +19,10 @@ import { OpenVidu } from './OpenVidu'; import { Session } from './Session'; import { Stream } from './Stream'; import { StreamManager } from './StreamManager'; -import { EventDispatcher } from './EventDispatcher'; import { PublisherProperties } from '../OpenViduInternal/Interfaces/Public/PublisherProperties'; -import { Event } from '../OpenViduInternal/Events/Event'; +import { PublisherEventMap } from '../OpenViduInternal/Events/EventMap/PublisherEventMap'; import { StreamEvent } from '../OpenViduInternal/Events/StreamEvent'; import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent'; -import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent'; import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; @@ -214,8 +212,10 @@ export class Publisher extends StreamManager { /** * See [[EventDispatcher.on]] */ - on(type: string, handler: (event: Event) => void): EventDispatcher { - super.on(type, handler); + on(type: K, handler: (event: PublisherEventMap[K]) => void): this { + + super.on(type, handler); + if (type === 'streamCreated') { if (!!this.stream && this.stream.isLocalStreamPublished) { this.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', this.stream, '')]); @@ -225,15 +225,6 @@ export class Publisher extends StreamManager { }); } } - if (type === 'remoteVideoPlaying') { - if (this.stream.displayMyRemote() && this.videos[0] && this.videos[0].video && - this.videos[0].video.currentTime > 0 && - this.videos[0].video.paused === false && - this.videos[0].video.ended === false && - this.videos[0].video.readyState === 4) { - this.emitEvent('remoteVideoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'remoteVideoPlaying')]); - } - } if (type === 'accessAllowed') { if (this.accessAllowed) { this.emitEvent('accessAllowed', []); @@ -251,8 +242,10 @@ export class Publisher extends StreamManager { /** * See [[EventDispatcher.once]] */ - once(type: string, handler: (event: Event) => void): Publisher { - super.once(type, handler); + once(type: K, handler: (event: PublisherEventMap[K]) => void): this { + + super.once(type, handler); + if (type === 'streamCreated') { if (!!this.stream && this.stream.isLocalStreamPublished) { this.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', this.stream, '')]); @@ -262,15 +255,6 @@ export class Publisher extends StreamManager { }); } } - if (type === 'remoteVideoPlaying') { - if (this.stream.displayMyRemote() && this.videos[0] && this.videos[0].video && - this.videos[0].video.currentTime > 0 && - this.videos[0].video.paused === false && - this.videos[0].video.ended === false && - this.videos[0].video.readyState === 4) { - this.emitEvent('remoteVideoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'remoteVideoPlaying')]); - } - } if (type === 'accessAllowed') { if (this.accessAllowed) { this.emitEvent('accessAllowed', []); @@ -284,6 +268,16 @@ export class Publisher extends StreamManager { return this; } + + /** + * See [[EventDispatcher.off]] + */ + off(type: K, handler?: (event: PublisherEventMap[K]) => void): this { + super.off(type, handler); + return this; + } + + /** * Replaces the current video or audio track with a different one. This allows you to replace an ongoing track with a different one * without having to renegotiate the whole WebRTC connection (that is, initializing a new Publisher, unpublishing the previous one diff --git a/openvidu-browser/src/OpenVidu/Session.ts b/openvidu-browser/src/OpenVidu/Session.ts index 124f1b4b..1dcc8997 100644 --- a/openvidu-browser/src/OpenVidu/Session.ts +++ b/openvidu-browser/src/OpenVidu/Session.ts @@ -29,10 +29,9 @@ import { SubscriberProperties } from '../OpenViduInternal/Interfaces/Public/Subs import { RemoteConnectionOptions } from '../OpenViduInternal/Interfaces/Private/RemoteConnectionOptions'; import { LocalConnectionOptions } from '../OpenViduInternal/Interfaces/Private/LocalConnectionOptions'; import { SessionOptions } from '../OpenViduInternal/Interfaces/Private/SessionOptions'; +import { SessionEventMap } from '../OpenViduInternal/Events/EventMap/SessionEventMap'; import { ConnectionEvent } from '../OpenViduInternal/Events/ConnectionEvent'; -import { ExceptionEvent } from '../OpenViduInternal/Events/ExceptionEvent'; import { FilterEvent } from '../OpenViduInternal/Events/FilterEvent'; -import { PublisherSpeakingEvent } from '../OpenViduInternal/Events/PublisherSpeakingEvent'; import { RecordingEvent } from '../OpenViduInternal/Events/RecordingEvent'; import { SessionDisconnectedEvent } from '../OpenViduInternal/Events/SessionDisconnectedEvent'; import { SignalEvent } from '../OpenViduInternal/Events/SignalEvent'; @@ -63,25 +62,6 @@ const logger: OpenViduLogger = OpenViduLogger.getInstance(); */ let platform: PlatformUtils; -export interface SessionEventMap { - connectionCreated: ConnectionEvent - connectionDestroyed: ConnectionEvent - connectionPropertyChanged: ConnectionPropertyChangedEvent - sessionDisconnected: SessionDisconnectedEvent - streamCreated: StreamEvent - streamDestroyed: StreamEvent - streamPropertyChanged: StreamPropertyChangedEvent - publisherStartSpeaking: PublisherSpeakingEvent - publisherStopSpeaking: PublisherSpeakingEvent - signal: SignalEvent - recordingStarted: RecordingEvent - recordingStopped: RecordingEvent - networkQualityLevelChanged: NetworkQualityLevelChangedEvent - reconnecting: never - reconnected: never - exception: ExceptionEvent -} - /** * Represents a video call. It can also be seen as a videoconference room where multiple users can connect. * Participants who publish their videos to a session can be seen by the rest of users connected to that specific session. @@ -665,7 +645,7 @@ export class Session extends EventDispatcher { /** * See [[EventDispatcher.on]] */ - on(type: K, handler: (event: SessionEventMap[K]) => void): this { + on(type: K, handler: (event: SessionEventMap[K]) => void): this { super.onAux(type, "Event '" + type + "' triggered by 'Session'", handler); @@ -739,7 +719,7 @@ export class Session extends EventDispatcher { */ off(type: K, handler?: (event: SessionEventMap[K]) => void): this { - super.off(type, handler); + super.offAux(type, handler); if (type === 'publisherStartSpeaking') { // Check if Session object still has some listener for the event @@ -1041,7 +1021,6 @@ export class Session extends EventDispatcher { */ recvIceCandidate(event: { senderConnectionId: string, endpointName: string, sdpMLineIndex: number, sdpMid: string, candidate: string }): void { const candidate: RTCIceCandidate = { - address: null, candidate: event.candidate, sdpMid: event.sdpMid, sdpMLineIndex: event.sdpMLineIndex, diff --git a/openvidu-browser/src/OpenVidu/StreamManager.ts b/openvidu-browser/src/OpenVidu/StreamManager.ts index 9d42ac81..7f3ea912 100644 --- a/openvidu-browser/src/OpenVidu/StreamManager.ts +++ b/openvidu-browser/src/OpenVidu/StreamManager.ts @@ -19,13 +19,13 @@ import { Stream } from './Stream'; import { Subscriber } from './Subscriber'; import { EventDispatcher } from './EventDispatcher'; import { StreamManagerVideo } from '../OpenViduInternal/Interfaces/Public/StreamManagerVideo'; -import { Event } from '../OpenViduInternal/Events/Event'; +import { StreamManagerEventMap } from '../OpenViduInternal/Events/EventMap/StreamManagerEventMap'; import { StreamManagerEvent } from '../OpenViduInternal/Events/StreamManagerEvent'; import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent'; +import { ExceptionEvent, ExceptionEventName } from '../OpenViduInternal/Events/ExceptionEvent'; import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; import { PlatformUtils } from '../OpenViduInternal/Utils/Platform'; -import { ExceptionEvent, ExceptionEventName } from '../OpenViduInternal/Events/ExceptionEvent'; /** * @hidden @@ -145,18 +145,6 @@ export class StreamManager extends EventDispatcher { this.canPlayListener = () => { this.deactivateStreamPlayingEventExceptionTimeout(); - if (this.remote) { - logger.info("Remote 'Stream' with id [" + this.stream.streamId + '] video is now playing'); - this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); - } else { - if (!this.stream.displayMyRemote()) { - logger.info("Your local 'Stream' with id [" + this.stream.streamId + '] video is now playing'); - this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); - } else { - logger.info("Your own remote 'Stream' with id [" + this.stream.streamId + '] video is now playing'); - this.ee.emitEvent('remoteVideoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'remoteVideoPlaying')]); - } - } this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]); }; } @@ -164,9 +152,9 @@ export class StreamManager extends EventDispatcher { /** * See [[EventDispatcher.on]] */ - on(type: string, handler: (event: Event) => void): EventDispatcher { + on(type: K, handler: (event: StreamManagerEventMap[K]) => void): this { - super.onAux(type, "Event '" + type + "' triggered by '" + (this.remote ? 'Subscriber' : 'Publisher') + "'", handler) + super.onAux(type, "Event '" + type + "' triggered by '" + (this.remote ? 'Subscriber' : 'Publisher') + "'", handler); if (type === 'videoElementCreated') { if (!!this.stream && this.lazyLaunchVideoElementCreatedEvent) { @@ -174,14 +162,13 @@ export class StreamManager extends EventDispatcher { this.lazyLaunchVideoElementCreatedEvent = false; } } - if (type === 'streamPlaying' || type === 'videoPlaying') { + if (type === 'streamPlaying') { if (this.videos[0] && this.videos[0].video && this.videos[0].video.currentTime > 0 && this.videos[0].video.paused === false && this.videos[0].video.ended === false && this.videos[0].video.readyState === 4) { this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]); - this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); } } if (this.stream.hasAudio) { @@ -201,7 +188,7 @@ export class StreamManager extends EventDispatcher { /** * See [[EventDispatcher.once]] */ - once(type: string, handler: (event: Event) => void): StreamManager { + once(type: K, handler: (event: StreamManagerEventMap[K]) => void): this { super.onceAux(type, "Event '" + type + "' triggered once by '" + (this.remote ? 'Subscriber' : 'Publisher') + "'", handler); @@ -210,14 +197,13 @@ export class StreamManager extends EventDispatcher { this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(this.videos[0].video, this, 'videoElementCreated')]); } } - if (type === 'streamPlaying' || type === 'videoPlaying') { + if (type === 'streamPlaying') { if (this.videos[0] && this.videos[0].video && this.videos[0].video.currentTime > 0 && this.videos[0].video.paused === false && this.videos[0].video.ended === false && this.videos[0].video.readyState === 4) { this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]); - this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); } } if (this.stream.hasAudio) { @@ -237,9 +223,9 @@ export class StreamManager extends EventDispatcher { /** * See [[EventDispatcher.off]] */ - off(type: string, handler?: (event: Event) => void): StreamManager { + off(type: K, handler?: (event: StreamManagerEventMap[K]) => void): this { - super.off(type, handler); + super.offAux(type, handler); if (type === 'publisherStartSpeaking') { // Both StreamManager and Session can have "publisherStartSpeaking" event listeners diff --git a/openvidu-browser/src/OpenViduInternal/Events/EventMap/PublisherEventMap.ts b/openvidu-browser/src/OpenViduInternal/Events/EventMap/PublisherEventMap.ts new file mode 100644 index 00000000..c90a7393 --- /dev/null +++ b/openvidu-browser/src/OpenViduInternal/Events/EventMap/PublisherEventMap.ts @@ -0,0 +1,11 @@ +import { StreamEvent } from '../StreamEvent'; +import { StreamManagerEventMap } from './StreamManagerEventMap'; + +export interface PublisherEventMap extends StreamManagerEventMap { + streamCreated: StreamEvent; + streamDestroyed: StreamEvent; + accessAllowed: never; + accessDenied: never; + accessDialogOpened: never; + accessDialogClosed: never; +} \ No newline at end of file diff --git a/openvidu-browser/src/OpenViduInternal/Events/EventMap/SessionEventMap.ts b/openvidu-browser/src/OpenViduInternal/Events/EventMap/SessionEventMap.ts new file mode 100644 index 00000000..979b52de --- /dev/null +++ b/openvidu-browser/src/OpenViduInternal/Events/EventMap/SessionEventMap.ts @@ -0,0 +1,29 @@ +import { ConnectionEvent } from '../ConnectionEvent'; +import { ConnectionPropertyChangedEvent } from '../ConnectionPropertyChangedEvent'; +import { ExceptionEvent } from '../ExceptionEvent'; +import { NetworkQualityLevelChangedEvent } from '../NetworkQualityLevelChangedEvent'; +import { PublisherSpeakingEvent } from '../PublisherSpeakingEvent'; +import { RecordingEvent } from '../RecordingEvent'; +import { SessionDisconnectedEvent } from '../SessionDisconnectedEvent'; +import { SignalEvent } from '../SignalEvent'; +import { StreamEvent } from '../StreamEvent'; +import { StreamPropertyChangedEvent } from '../StreamPropertyChangedEvent'; + +export interface SessionEventMap { + connectionCreated: ConnectionEvent; + connectionDestroyed: ConnectionEvent; + connectionPropertyChanged: ConnectionPropertyChangedEvent; + sessionDisconnected: SessionDisconnectedEvent; + streamCreated: StreamEvent; + streamDestroyed: StreamEvent; + streamPropertyChanged: StreamPropertyChangedEvent; + publisherStartSpeaking: PublisherSpeakingEvent; + publisherStopSpeaking: PublisherSpeakingEvent; + signal: SignalEvent; + recordingStarted: RecordingEvent; + recordingStopped: RecordingEvent; + networkQualityLevelChanged: NetworkQualityLevelChangedEvent; + reconnecting: never; + reconnected: never; + exception: ExceptionEvent; +} \ No newline at end of file diff --git a/openvidu-browser/src/OpenViduInternal/Events/EventMap/StreamManagerEventMap.ts b/openvidu-browser/src/OpenViduInternal/Events/EventMap/StreamManagerEventMap.ts new file mode 100644 index 00000000..704d9f37 --- /dev/null +++ b/openvidu-browser/src/OpenViduInternal/Events/EventMap/StreamManagerEventMap.ts @@ -0,0 +1,14 @@ +import { PublisherSpeakingEvent } from '../PublisherSpeakingEvent'; +import { StreamManagerEvent } from '../StreamManagerEvent'; +import { StreamPropertyChangedEvent } from '../StreamPropertyChangedEvent'; +import { VideoElementEvent } from '../VideoElementEvent'; + +export interface StreamManagerEventMap { + videoElementCreated: VideoElementEvent; + videoElementDestroyed: VideoElementEvent; + streamPlaying: StreamManagerEvent; + streamAudioVolumeChange: StreamManagerEvent; + streamPropertyChanged: StreamPropertyChangedEvent; + publisherStartSpeaking: PublisherSpeakingEvent; + publisherStopSpeaking: PublisherSpeakingEvent; +} \ No newline at end of file