From 87117f31e4039f91c1c54c5034bef469ee29856e Mon Sep 17 00:00:00 2001 From: pabloFuente Date: Tue, 30 Mar 2021 18:04:56 +0200 Subject: [PATCH] openvidu-browser: hark refactoring. Allow PublisherSpeakingEvent for local streams --- openvidu-browser/src/OpenVidu/Publisher.ts | 2 +- openvidu-browser/src/OpenVidu/Session.ts | 119 ++++++++----- openvidu-browser/src/OpenVidu/Stream.ts | 166 +++++++++--------- .../src/OpenVidu/StreamManager.ts | 57 ++++-- openvidu-browser/src/OpenVidu/Subscriber.ts | 4 + .../Events/PublisherSpeakingEvent.ts | 11 +- 6 files changed, 215 insertions(+), 144 deletions(-) diff --git a/openvidu-browser/src/OpenVidu/Publisher.ts b/openvidu-browser/src/OpenVidu/Publisher.ts index caa5e8cb..b063c949 100644 --- a/openvidu-browser/src/OpenVidu/Publisher.ts +++ b/openvidu-browser/src/OpenVidu/Publisher.ts @@ -51,7 +51,7 @@ let platform: PlatformUtils; * - accessDialogClosed * - streamCreated ([[StreamEvent]]) * - streamDestroyed ([[StreamEvent]]) - * - streamPropertyChanged ([[StreamPropertyChangedEvent]]) + * - _All events inherited from [[StreamManager]] class_ */ export class Publisher extends StreamManager { diff --git a/openvidu-browser/src/OpenVidu/Session.ts b/openvidu-browser/src/OpenVidu/Session.ts index 7fae5b27..51db7322 100644 --- a/openvidu-browser/src/OpenVidu/Session.ts +++ b/openvidu-browser/src/OpenVidu/Session.ts @@ -120,22 +120,6 @@ export class Session extends EventDispatcher { * @hidden */ options: SessionOptions; - /** - * @hidden - */ - startSpeakingEventsEnabled = false; - /** - * @hidden - */ - startSpeakingEventsEnabledOnce = false; - /** - * @hidden - */ - stopSpeakingEventsEnabled = false; - /** - * @hidden - */ - stopSpeakingEventsEnabledOnce = false; /** * @hidden */ @@ -655,22 +639,28 @@ export class Session extends EventDispatcher { super.onAux(type, "Event '" + type + "' triggered by 'Session'", handler); if (type === 'publisherStartSpeaking') { - this.startSpeakingEventsEnabled = true; - // If there are already available remote streams, enable hark 'speaking' event in all of them + // If there are already available remote streams with audio, enable hark 'speaking' event in all of them this.remoteConnections.forEach(remoteConnection => { - if (!!remoteConnection.stream && remoteConnection.stream.hasAudio) { - remoteConnection.stream.enableStartSpeakingEvent(); + if (!!remoteConnection.stream?.hasAudio) { + remoteConnection.stream.enableHarkSpeakingEvent(); } }); + if (!!this.connection?.stream?.hasAudio) { + // If connected to the Session and publishing with audio, also enable hark 'speaking' event for the Publisher + this.connection.stream.enableHarkSpeakingEvent(); + } } if (type === 'publisherStopSpeaking') { - this.stopSpeakingEventsEnabled = true; - // If there are already available remote streams, enable hark 'stopped_speaking' event in all of them + // If there are already available remote streams with audio, enable hark 'stopped_speaking' event in all of them this.remoteConnections.forEach(remoteConnection => { - if (!!remoteConnection.stream && remoteConnection.stream.hasAudio) { - remoteConnection.stream.enableStopSpeakingEvent(); + if (!!remoteConnection.stream?.hasAudio) { + remoteConnection.stream.enableHarkStoppedSpeakingEvent(); } }); + if (!!this.connection?.stream?.hasAudio) { + // If connected to the Session and publishing with audio, also enable hark 'stopped_speaking' event for the Publisher + this.connection.stream.enableHarkStoppedSpeakingEvent(); + } } return this; @@ -685,22 +675,28 @@ export class Session extends EventDispatcher { super.onceAux(type, "Event '" + type + "' triggered once by 'Session'", handler); if (type === 'publisherStartSpeaking') { - this.startSpeakingEventsEnabledOnce = true; - // If there are already available remote streams, enable hark 'speaking' event in all of them once + // If there are already available remote streams with audio, enable hark 'speaking' event (once) in all of them once this.remoteConnections.forEach(remoteConnection => { - if (!!remoteConnection.stream && remoteConnection.stream.hasAudio) { - remoteConnection.stream.enableOnceStartSpeakingEvent(); + if (!!remoteConnection.stream?.hasAudio) { + remoteConnection.stream.enableOnceHarkSpeakingEvent(); } }); + if (!!this.connection?.stream?.hasAudio) { + // If connected to the Session and publishing with audio, also enable hark 'speaking' event (once) for the Publisher + this.connection.stream.enableOnceHarkSpeakingEvent(); + } } if (type === 'publisherStopSpeaking') { - this.stopSpeakingEventsEnabledOnce = true; - // If there are already available remote streams, enable hark 'stopped_speaking' event in all of them once + // If there are already available remote streams with audio, enable hark 'stopped_speaking' event (once) in all of them once this.remoteConnections.forEach(remoteConnection => { - if (!!remoteConnection.stream && remoteConnection.stream.hasAudio) { - remoteConnection.stream.enableOnceStopSpeakingEvent(); + if (!!remoteConnection.stream?.hasAudio) { + remoteConnection.stream.enableOnceHarkStoppedSpeakingEvent(); } }); + if (!!this.connection?.stream?.hasAudio) { + // If connected to the Session and publishing with audio, also enable hark 'stopped_speaking' event (once) for the Publisher + this.connection.stream.enableOnceHarkStoppedSpeakingEvent(); + } } return this; @@ -715,27 +711,41 @@ export class Session extends EventDispatcher { super.off(type, handler); if (type === 'publisherStartSpeaking') { - let remainingStartSpeakingListeners = this.ee.getListeners(type).length; - if (remainingStartSpeakingListeners === 0) { - this.startSpeakingEventsEnabled = false; - // If there are already available remote streams, disable hark in all of them + // Check if Session object still has some listener for the event + if (!this.anySpeechEventListenerEnabled('publisherStartSpeaking', false)) { this.remoteConnections.forEach(remoteConnection => { - if (!!remoteConnection.stream) { - remoteConnection.stream.disableStartSpeakingEvent(false); + if (!!remoteConnection.stream?.streamManager) { + // Check if Subscriber object still has some listener for the event + if (!this.anySpeechEventListenerEnabled('publisherStartSpeaking', false, remoteConnection.stream.streamManager)) { + remoteConnection.stream.disableHarkSpeakingEvent(false); + } } }); + if (!!this.connection?.stream?.streamManager) { + // Check if Publisher object still has some listener for the event + if (!this.anySpeechEventListenerEnabled('publisherStartSpeaking', false, this.connection.stream.streamManager)) { + this.connection.stream.disableHarkSpeakingEvent(false); + } + } } } if (type === 'publisherStopSpeaking') { - let remainingStopSpeakingListeners = this.ee.getListeners(type).length; - if (remainingStopSpeakingListeners === 0) { - this.stopSpeakingEventsEnabled = false; - // If there are already available remote streams, disable hark in all of them + // Check if Session object still has some listener for the event + if (!this.anySpeechEventListenerEnabled('publisherStopSpeaking', false)) { this.remoteConnections.forEach(remoteConnection => { - if (!!remoteConnection.stream) { - remoteConnection.stream.disableStopSpeakingEvent(false); + if (!!remoteConnection.stream?.streamManager) { + // Check if Subscriber object still has some listener for the event + if (!this.anySpeechEventListenerEnabled('publisherStopSpeaking', false, remoteConnection.stream.streamManager)) { + remoteConnection.stream.disableHarkStoppedSpeakingEvent(false); + } } }); + if (!!this.connection?.stream?.streamManager) { + // Check if Publisher object still has some listener for the event + if (!this.anySpeechEventListenerEnabled('publisherStopSpeaking', false, this.connection.stream.streamManager)) { + this.connection.stream.disableHarkStoppedSpeakingEvent(false); + } + } } } return this; @@ -1271,6 +1281,27 @@ export class Session extends EventDispatcher { return new OpenViduError(OpenViduErrorName.OPENVIDU_NOT_CONNECTED, "There is no connection to the session. Method 'Session.connect' must be successfully completed first"); } + /** + * @hidden + */ + anySpeechEventListenerEnabled(event: string, onlyOnce: boolean, streamManager?: StreamManager): boolean { + let handlersInSession = this.ee.getListeners(event); + if (onlyOnce) { + handlersInSession = handlersInSession.filter(h => (h as any).once); + } + let listenersInSession = handlersInSession.length; + if (listenersInSession > 0) return true; + let listenersInStreamManager = 0; + if (!!streamManager) { + let handlersInStreamManager = streamManager.ee.getListeners(event); + if (onlyOnce) { + handlersInStreamManager = handlersInStreamManager.filter(h => (h as any).once); + } + listenersInStreamManager = handlersInStreamManager.length; + } + return listenersInStreamManager > 0; + } + /* Private methods */ private connectAux(token: string): Promise { diff --git a/openvidu-browser/src/OpenVidu/Stream.ts b/openvidu-browser/src/OpenVidu/Stream.ts index b7b427b1..38c7e2c5 100644 --- a/openvidu-browser/src/OpenVidu/Stream.ts +++ b/openvidu-browser/src/OpenVidu/Stream.ts @@ -181,27 +181,27 @@ export class Stream { /** * @hidden */ - publisherStartSpeakingEventEnabled = false; + harkSpeakingEnabled = false; /** * @hidden */ - publisherStartSpeakingEventEnabledOnce = false; + harkSpeakingEnabledOnce = false; /** * @hidden */ - publisherStopSpeakingEventEnabled = false; + harkStoppedSpeakingEnabled = false; /** * @hidden */ - publisherStopSpeakingEventEnabledOnce = false; + harkStoppedSpeakingEnabledOnce = false; /** * @hidden */ - volumeChangeEventEnabled = false; + harkVolumeChangeEnabled = false; /** * @hidden */ - volumeChangeEventEnabledOnce = false; + harkVolumeChangeEnabledOnce = false; /** * @hidden */ @@ -540,13 +540,14 @@ export class Stream { /** * @hidden */ - enableStartSpeakingEvent(): void { - this.setSpeechEventIfNotExists(); - if (!this.publisherStartSpeakingEventEnabled) { - this.publisherStartSpeakingEventEnabled = true; + enableHarkSpeakingEvent(): void { + this.setHarkListenerIfNotExists(); + if (!this.harkSpeakingEnabled) { + this.harkSpeakingEnabled = true; this.speechEvent.on('speaking', () => { this.session.emitEvent('publisherStartSpeaking', [new PublisherSpeakingEvent(this.session, 'publisherStartSpeaking', this.connection, this.streamId)]); - this.publisherStartSpeakingEventEnabledOnce = false; // Disable 'once' version if 'on' version was triggered + this.streamManager.emitEvent('publisherStartSpeaking', [new PublisherSpeakingEvent(this.streamManager, 'publisherStartSpeaking', this.connection, this.streamId)]); + this.harkSpeakingEnabledOnce = false; // Disable 'once' version if 'on' version was triggered }); } } @@ -554,16 +555,17 @@ export class Stream { /** * @hidden */ - enableOnceStartSpeakingEvent(): void { - this.setSpeechEventIfNotExists(); - if (!this.publisherStartSpeakingEventEnabledOnce) { - this.publisherStartSpeakingEventEnabledOnce = true; + enableOnceHarkSpeakingEvent(): void { + this.setHarkListenerIfNotExists(); + if (!this.harkSpeakingEnabledOnce) { + this.harkSpeakingEnabledOnce = true; this.speechEvent.once('speaking', () => { - if (this.publisherStartSpeakingEventEnabledOnce) { + if (this.harkSpeakingEnabledOnce) { // If the listener has been disabled in the meantime (for example by the 'on' version) do not trigger the event this.session.emitEvent('publisherStartSpeaking', [new PublisherSpeakingEvent(this.session, 'publisherStartSpeaking', this.connection, this.streamId)]); + this.streamManager.emitEvent('publisherStartSpeaking', [new PublisherSpeakingEvent(this.streamManager, 'publisherStartSpeaking', this.connection, this.streamId)]); } - this.disableStartSpeakingEvent(true); + this.disableHarkSpeakingEvent(true); }); } } @@ -571,22 +573,22 @@ export class Stream { /** * @hidden */ - disableStartSpeakingEvent(disabledByOnce: boolean): void { + disableHarkSpeakingEvent(disabledByOnce: boolean): void { if (!!this.speechEvent) { - this.publisherStartSpeakingEventEnabledOnce = false; + this.harkSpeakingEnabledOnce = false; if (disabledByOnce) { - if (this.publisherStartSpeakingEventEnabled) { + if (this.harkSpeakingEnabled) { // The 'on' version of this same event is enabled too. Do not remove the hark listener return; } } else { - this.publisherStartSpeakingEventEnabled = false; + this.harkSpeakingEnabled = false; } // Shutting down the hark event - if (this.volumeChangeEventEnabled || - this.volumeChangeEventEnabledOnce || - this.publisherStopSpeakingEventEnabled || - this.publisherStopSpeakingEventEnabledOnce) { + if (this.harkVolumeChangeEnabled || + this.harkVolumeChangeEnabledOnce || + this.harkStoppedSpeakingEnabled || + this.harkStoppedSpeakingEnabledOnce) { // Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener this.speechEvent.off('speaking'); } else { @@ -600,13 +602,14 @@ export class Stream { /** * @hidden */ - enableStopSpeakingEvent(): void { - this.setSpeechEventIfNotExists(); - if (!this.publisherStopSpeakingEventEnabled) { - this.publisherStopSpeakingEventEnabled = true; + enableHarkStoppedSpeakingEvent(): void { + this.setHarkListenerIfNotExists(); + if (!this.harkStoppedSpeakingEnabled) { + this.harkStoppedSpeakingEnabled = true; this.speechEvent.on('stopped_speaking', () => { this.session.emitEvent('publisherStopSpeaking', [new PublisherSpeakingEvent(this.session, 'publisherStopSpeaking', this.connection, this.streamId)]); - this.publisherStopSpeakingEventEnabledOnce = false; // Disable 'once' version if 'on' version was triggered + this.streamManager.emitEvent('publisherStopSpeaking', [new PublisherSpeakingEvent(this.streamManager, 'publisherStopSpeaking', this.connection, this.streamId)]); + this.harkStoppedSpeakingEnabledOnce = false; // Disable 'once' version if 'on' version was triggered }); } } @@ -614,16 +617,17 @@ export class Stream { /** * @hidden */ - enableOnceStopSpeakingEvent(): void { - this.setSpeechEventIfNotExists(); - if (!this.publisherStopSpeakingEventEnabledOnce) { - this.publisherStopSpeakingEventEnabledOnce = true; + enableOnceHarkStoppedSpeakingEvent(): void { + this.setHarkListenerIfNotExists(); + if (!this.harkStoppedSpeakingEnabledOnce) { + this.harkStoppedSpeakingEnabledOnce = true; this.speechEvent.once('stopped_speaking', () => { - if (this.publisherStopSpeakingEventEnabledOnce) { + if (this.harkStoppedSpeakingEnabledOnce) { // If the listener has been disabled in the meantime (for example by the 'on' version) do not trigger the event this.session.emitEvent('publisherStopSpeaking', [new PublisherSpeakingEvent(this.session, 'publisherStopSpeaking', this.connection, this.streamId)]); + this.streamManager.emitEvent('publisherStopSpeaking', [new PublisherSpeakingEvent(this.streamManager, 'publisherStopSpeaking', this.connection, this.streamId)]); } - this.disableStopSpeakingEvent(true); + this.disableHarkStoppedSpeakingEvent(true); }); } } @@ -631,23 +635,23 @@ export class Stream { /** * @hidden */ - disableStopSpeakingEvent(disabledByOnce: boolean): void { + disableHarkStoppedSpeakingEvent(disabledByOnce: boolean): void { if (!!this.speechEvent) { - this.publisherStopSpeakingEventEnabledOnce = false; + this.harkStoppedSpeakingEnabledOnce = false; if (disabledByOnce) { - if (this.publisherStopSpeakingEventEnabled) { + if (this.harkStoppedSpeakingEnabled) { // We are cancelling the 'once' listener for this event, but the 'on' version // of this same event is enabled too. Do not remove the hark listener return; } } else { - this.publisherStopSpeakingEventEnabled = false; + this.harkStoppedSpeakingEnabled = false; } // Shutting down the hark event - if (this.volumeChangeEventEnabled || - this.volumeChangeEventEnabledOnce || - this.publisherStartSpeakingEventEnabled || - this.publisherStartSpeakingEventEnabledOnce) { + if (this.harkVolumeChangeEnabled || + this.harkVolumeChangeEnabledOnce || + this.harkSpeakingEnabled || + this.harkSpeakingEnabledOnce) { // Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener this.speechEvent.off('stopped_speaking'); } else { @@ -661,10 +665,10 @@ export class Stream { /** * @hidden */ - enableVolumeChangeEvent(force: boolean): void { - if (this.setSpeechEventIfNotExists()) { - if (!this.volumeChangeEventEnabled || force) { - this.volumeChangeEventEnabled = true; + enableHarkVolumeChangeEvent(force: boolean): void { + if (this.setHarkListenerIfNotExists()) { + if (!this.harkVolumeChangeEnabled || force) { + this.harkVolumeChangeEnabled = true; this.speechEvent.on('volume_change', harkEvent => { const oldValue = this.speechEvent.oldVolumeValue; const value = { newValue: harkEvent, oldValue }; @@ -674,51 +678,51 @@ export class Stream { } } else { // This way whenever the MediaStream object is available, the event listener will be automatically added - this.volumeChangeEventEnabled = true; + this.harkVolumeChangeEnabled = true; } } /** * @hidden */ - enableOnceVolumeChangeEvent(force: boolean): void { - if (this.setSpeechEventIfNotExists()) { - if (!this.volumeChangeEventEnabledOnce || force) { - this.volumeChangeEventEnabledOnce = true; + enableOnceHarkVolumeChangeEvent(force: boolean): void { + if (this.setHarkListenerIfNotExists()) { + if (!this.harkVolumeChangeEnabledOnce || force) { + this.harkVolumeChangeEnabledOnce = true; this.speechEvent.once('volume_change', harkEvent => { const oldValue = this.speechEvent.oldVolumeValue; const value = { newValue: harkEvent, oldValue }; this.speechEvent.oldVolumeValue = harkEvent; - this.disableVolumeChangeEvent(true); + this.disableHarkVolumeChangeEvent(true); this.streamManager.emitEvent('streamAudioVolumeChange', [new StreamManagerEvent(this.streamManager, 'streamAudioVolumeChange', value)]); }); } } else { // This way whenever the MediaStream object is available, the event listener will be automatically added - this.volumeChangeEventEnabledOnce = true; + this.harkVolumeChangeEnabledOnce = true; } } /** * @hidden */ - disableVolumeChangeEvent(disabledByOnce: boolean): void { + disableHarkVolumeChangeEvent(disabledByOnce: boolean): void { if (!!this.speechEvent) { - this.volumeChangeEventEnabledOnce = false; + this.harkVolumeChangeEnabledOnce = false; if (disabledByOnce) { - if (this.volumeChangeEventEnabled) { + if (this.harkVolumeChangeEnabled) { // We are cancelling the 'once' listener for this event, but the 'on' version // of this same event is enabled too. Do not remove the hark listener return; } } else { - this.volumeChangeEventEnabled = false; + this.harkVolumeChangeEnabled = false; } // Shutting down the hark event - if (this.publisherStartSpeakingEventEnabled || - this.publisherStartSpeakingEventEnabledOnce || - this.publisherStopSpeakingEventEnabled || - this.publisherStopSpeakingEventEnabledOnce) { + if (this.harkSpeakingEnabled || + this.harkSpeakingEnabledOnce || + this.harkStoppedSpeakingEnabled || + this.harkStoppedSpeakingEnabledOnce) { // Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener this.speechEvent.off('volume_change'); } else { @@ -779,7 +783,7 @@ export class Stream { /* Private methods */ - private setSpeechEventIfNotExists(): boolean { + private setHarkListenerIfNotExists(): boolean { if (!!this.mediaStream) { if (!this.speechEvent) { const harkOptions = !!this.harkOptions ? this.harkOptions : (this.session.openvidu.advancedConfiguration.publisherSpeakingEventsOptions || {}); @@ -1026,27 +1030,23 @@ export class Stream { private initHarkEvents(): void { if (!!this.mediaStream!.getAudioTracks()[0]) { // Hark events can only be set if audio track is available - if (this.streamManager.remote) { - // publisherStartSpeaking/publisherStopSpeaking is only defined for remote streams - if (this.session.startSpeakingEventsEnabled) { - this.enableStartSpeakingEvent(); - } - if (this.session.startSpeakingEventsEnabledOnce) { - this.enableOnceStartSpeakingEvent(); - } - if (this.session.stopSpeakingEventsEnabled) { - this.enableStopSpeakingEvent(); - } - if (this.session.stopSpeakingEventsEnabledOnce) { - this.enableOnceStopSpeakingEvent(); - } + if (this.session.anySpeechEventListenerEnabled('publisherStartSpeaking', true, this.streamManager)) { + this.enableOnceHarkSpeakingEvent(); } - // streamAudioVolumeChange event is defined for both Publishers and Subscribers - if (this.volumeChangeEventEnabled) { - this.enableVolumeChangeEvent(true); + if (this.session.anySpeechEventListenerEnabled('publisherStartSpeaking', false, this.streamManager)) { + this.enableHarkSpeakingEvent(); } - if (this.volumeChangeEventEnabledOnce) { - this.enableOnceVolumeChangeEvent(true); + if (this.session.anySpeechEventListenerEnabled('publisherStopSpeaking', true, this.streamManager)) { + this.enableOnceHarkStoppedSpeakingEvent(); + } + if (this.session.anySpeechEventListenerEnabled('publisherStopSpeaking', false, this.streamManager)) { + this.enableHarkStoppedSpeakingEvent(); + } + if (this.harkVolumeChangeEnabledOnce) { + this.enableOnceHarkVolumeChangeEvent(true); + } + if (this.harkVolumeChangeEnabled) { + this.enableHarkVolumeChangeEvent(true); } } } diff --git a/openvidu-browser/src/OpenVidu/StreamManager.ts b/openvidu-browser/src/OpenVidu/StreamManager.ts index a2d3e03f..8c0730a6 100644 --- a/openvidu-browser/src/OpenVidu/StreamManager.ts +++ b/openvidu-browser/src/OpenVidu/StreamManager.ts @@ -48,6 +48,9 @@ let platform: PlatformUtils; * - videoElementCreated ([[VideoElementEvent]]) * - videoElementDestroyed ([[VideoElementEvent]]) * - streamPlaying ([[StreamManagerEvent]]) + * - streamPropertyChanged ([[StreamPropertyChangedEvent]]) + * - publisherStartSpeaking ([[PublisherSpeakingEvent]]) + * - publisherStopSpeaking ([[PublisherSpeakingEvent]]) * - streamAudioVolumeChange ([[StreamManagerEvent]]) * */ @@ -174,8 +177,16 @@ export class StreamManager extends EventDispatcher { this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); } } - if (type === 'streamAudioVolumeChange' && this.stream.hasAudio) { - this.stream.enableVolumeChangeEvent(false); + if (this.stream.hasAudio) { + if (type === 'publisherStartSpeaking') { + this.stream.enableHarkSpeakingEvent(); + } + if (type === 'publisherStopSpeaking') { + this.stream.enableHarkStoppedSpeakingEvent(); + } + if (type === 'streamAudioVolumeChange') { + this.stream.enableHarkVolumeChangeEvent(false); + } } return this; } @@ -202,8 +213,16 @@ export class StreamManager extends EventDispatcher { this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); } } - if (type === 'streamAudioVolumeChange' && this.stream.hasAudio) { - this.stream.enableOnceVolumeChangeEvent(false); + if (this.stream.hasAudio) { + if (type === 'publisherStartSpeaking') { + this.stream.enableOnceHarkSpeakingEvent(); + } + if (type === 'publisherStopSpeaking') { + this.stream.enableOnceHarkStoppedSpeakingEvent(); + } + if (type === 'streamAudioVolumeChange') { + this.stream.enableOnceHarkVolumeChangeEvent(false); + } } return this; } @@ -215,10 +234,25 @@ export class StreamManager extends EventDispatcher { super.off(type, handler); + if (type === 'publisherStartSpeaking') { + // Both StreamManager and Session can have "publisherStartSpeaking" event listeners + const remainingStartSpeakingEventListeners = this.ee.getListeners(type).length + this.stream.session.ee.getListeners(type).length; + if (remainingStartSpeakingEventListeners === 0) { + this.stream.disableHarkSpeakingEvent(false); + } + } + if (type === 'publisherStopSpeaking') { + // Both StreamManager and Session can have "publisherStopSpeaking" event listeners + const remainingStopSpeakingEventListeners = this.ee.getListeners(type).length + this.stream.session.ee.getListeners(type).length; + if (remainingStopSpeakingEventListeners === 0) { + this.stream.disableHarkStoppedSpeakingEvent(false); + } + } if (type === 'streamAudioVolumeChange') { - let remainingVolumeEventListeners = this.ee.getListeners(type).length; + // Only StreamManager can have "streamAudioVolumeChange" event listeners + const remainingVolumeEventListeners = this.ee.getListeners(type).length; if (remainingVolumeEventListeners === 0) { - this.stream.disableVolumeChangeEvent(false); + this.stream.disableHarkVolumeChangeEvent(false); } } @@ -419,9 +453,10 @@ export class StreamManager extends EventDispatcher { this.videos.forEach(streamManagerVideo => { // Remove oncanplay event listener (only OpenVidu browser listener, not the user ones) - if(!!streamManagerVideo.video && !!streamManagerVideo.video.removeEventListener){ + if (!!streamManagerVideo.video && !!streamManagerVideo.video.removeEventListener) { streamManagerVideo.video.removeEventListener('canplay', this.canPlayListener); - } streamManagerVideo.canplayListenerAdded = false; + } + streamManagerVideo.canplayListenerAdded = false; if (!!streamManagerVideo.targetElement) { // Only remove from DOM videos created by OpenVidu Browser (those generated by passing a valid targetElement in OpenVidu.initPublisher // and Session.subscribe or those created by StreamManager.createVideoElement). All this videos triggered a videoElementCreated event @@ -486,9 +521,9 @@ export class StreamManager extends EventDispatcher { this.ee.emitEvent(type, eventArray); } - /** - * @hidden - */ + /** + * @hidden + */ createVideo(): HTMLVideoElement { return document.createElement('video'); } diff --git a/openvidu-browser/src/OpenVidu/Subscriber.ts b/openvidu-browser/src/OpenVidu/Subscriber.ts index 6fffdcd4..115604bb 100644 --- a/openvidu-browser/src/OpenVidu/Subscriber.ts +++ b/openvidu-browser/src/OpenVidu/Subscriber.ts @@ -27,6 +27,10 @@ const logger: OpenViduLogger = OpenViduLogger.getInstance(); /** * Packs remote media streams. Participants automatically receive them when others publish their streams. Initialized with [[Session.subscribe]] method + * + * ### Available event listeners (and events dispatched) + * + * - _All events inherited from [[StreamManager]] class_ */ export class Subscriber extends StreamManager { diff --git a/openvidu-browser/src/OpenViduInternal/Events/PublisherSpeakingEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/PublisherSpeakingEvent.ts index 3507528b..ccaae71a 100644 --- a/openvidu-browser/src/OpenViduInternal/Events/PublisherSpeakingEvent.ts +++ b/openvidu-browser/src/OpenViduInternal/Events/PublisherSpeakingEvent.ts @@ -17,16 +17,17 @@ import { Event } from './Event'; import { Connection } from '../../OpenVidu/Connection'; -import { Session } from '../..'; +import { Session } from '../../OpenVidu/Session'; +import { StreamManager } from '../../OpenVidu/StreamManager'; /** * Defines the following events: - * - `publisherStartSpeaking`: dispatched by [[Session]] when a remote user has started speaking - * - `publisherStopSpeaking`: dispatched by [[Session]] when a remote user has stopped speaking + * - `publisherStartSpeaking`: dispatched by [[Session]] and [[StreamManager]] when a user has started speaking + * - `publisherStopSpeaking`: dispatched by [[Session]] and [[StreamManager]] when a user has stopped speaking * * More information: - * - This events will only be triggered for **remote streams that have audio tracks** ([[Stream.hasAudio]] must be true) + * - This events will only be triggered for **streams that have audio tracks** ([[Stream.hasAudio]] must be true) * - You can further configure how the events are dispatched by setting property `publisherSpeakingEventsOptions` in the call of [[OpenVidu.setAdvancedConfiguration]] */ export class PublisherSpeakingEvent extends Event { @@ -44,7 +45,7 @@ export class PublisherSpeakingEvent extends Event { /** * @hidden */ - constructor(target: Session, type: string, connection: Connection, streamId: string) { + constructor(target: Session | StreamManager, type: string, connection: Connection, streamId: string) { super(false, target, type); this.type = type; this.connection = connection;