openvidu-browser: hark refactoring. Allow PublisherSpeakingEvent for local streams

pull/621/head
pabloFuente 2021-03-30 18:04:56 +02:00
parent 0a3553c704
commit 87117f31e4
6 changed files with 215 additions and 144 deletions

View File

@ -51,7 +51,7 @@ let platform: PlatformUtils;
* - accessDialogClosed * - accessDialogClosed
* - streamCreated ([[StreamEvent]]) * - streamCreated ([[StreamEvent]])
* - streamDestroyed ([[StreamEvent]]) * - streamDestroyed ([[StreamEvent]])
* - streamPropertyChanged ([[StreamPropertyChangedEvent]]) * - _All events inherited from [[StreamManager]] class_
*/ */
export class Publisher extends StreamManager { export class Publisher extends StreamManager {

View File

@ -120,22 +120,6 @@ export class Session extends EventDispatcher {
* @hidden * @hidden
*/ */
options: SessionOptions; options: SessionOptions;
/**
* @hidden
*/
startSpeakingEventsEnabled = false;
/**
* @hidden
*/
startSpeakingEventsEnabledOnce = false;
/**
* @hidden
*/
stopSpeakingEventsEnabled = false;
/**
* @hidden
*/
stopSpeakingEventsEnabledOnce = false;
/** /**
* @hidden * @hidden
*/ */
@ -655,22 +639,28 @@ export class Session extends EventDispatcher {
super.onAux(type, "Event '" + type + "' triggered by 'Session'", handler); super.onAux(type, "Event '" + type + "' triggered by 'Session'", handler);
if (type === 'publisherStartSpeaking') { if (type === 'publisherStartSpeaking') {
this.startSpeakingEventsEnabled = true; // If there are already available remote streams with audio, enable hark 'speaking' event in all of them
// If there are already available remote streams, enable hark 'speaking' event in all of them
this.remoteConnections.forEach(remoteConnection => { this.remoteConnections.forEach(remoteConnection => {
if (!!remoteConnection.stream && remoteConnection.stream.hasAudio) { if (!!remoteConnection.stream?.hasAudio) {
remoteConnection.stream.enableStartSpeakingEvent(); 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') { if (type === 'publisherStopSpeaking') {
this.stopSpeakingEventsEnabled = true; // If there are already available remote streams with audio, enable hark 'stopped_speaking' event in all of them
// If there are already available remote streams, enable hark 'stopped_speaking' event in all of them
this.remoteConnections.forEach(remoteConnection => { this.remoteConnections.forEach(remoteConnection => {
if (!!remoteConnection.stream && remoteConnection.stream.hasAudio) { if (!!remoteConnection.stream?.hasAudio) {
remoteConnection.stream.enableStopSpeakingEvent(); 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; return this;
@ -685,22 +675,28 @@ export class Session extends EventDispatcher {
super.onceAux(type, "Event '" + type + "' triggered once by 'Session'", handler); super.onceAux(type, "Event '" + type + "' triggered once by 'Session'", handler);
if (type === 'publisherStartSpeaking') { if (type === 'publisherStartSpeaking') {
this.startSpeakingEventsEnabledOnce = true; // If there are already available remote streams with audio, enable hark 'speaking' event (once) in all of them once
// If there are already available remote streams, enable hark 'speaking' event in all of them once
this.remoteConnections.forEach(remoteConnection => { this.remoteConnections.forEach(remoteConnection => {
if (!!remoteConnection.stream && remoteConnection.stream.hasAudio) { if (!!remoteConnection.stream?.hasAudio) {
remoteConnection.stream.enableOnceStartSpeakingEvent(); 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') { if (type === 'publisherStopSpeaking') {
this.stopSpeakingEventsEnabledOnce = true; // If there are already available remote streams with audio, enable hark 'stopped_speaking' event (once) in all of them once
// If there are already available remote streams, enable hark 'stopped_speaking' event in all of them once
this.remoteConnections.forEach(remoteConnection => { this.remoteConnections.forEach(remoteConnection => {
if (!!remoteConnection.stream && remoteConnection.stream.hasAudio) { if (!!remoteConnection.stream?.hasAudio) {
remoteConnection.stream.enableOnceStopSpeakingEvent(); 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; return this;
@ -715,27 +711,41 @@ export class Session extends EventDispatcher {
super.off(type, handler); super.off(type, handler);
if (type === 'publisherStartSpeaking') { if (type === 'publisherStartSpeaking') {
let remainingStartSpeakingListeners = this.ee.getListeners(type).length; // Check if Session object still has some listener for the event
if (remainingStartSpeakingListeners === 0) { if (!this.anySpeechEventListenerEnabled('publisherStartSpeaking', false)) {
this.startSpeakingEventsEnabled = false;
// If there are already available remote streams, disable hark in all of them
this.remoteConnections.forEach(remoteConnection => { this.remoteConnections.forEach(remoteConnection => {
if (!!remoteConnection.stream) { if (!!remoteConnection.stream?.streamManager) {
remoteConnection.stream.disableStartSpeakingEvent(false); // 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') { if (type === 'publisherStopSpeaking') {
let remainingStopSpeakingListeners = this.ee.getListeners(type).length; // Check if Session object still has some listener for the event
if (remainingStopSpeakingListeners === 0) { if (!this.anySpeechEventListenerEnabled('publisherStopSpeaking', false)) {
this.stopSpeakingEventsEnabled = false;
// If there are already available remote streams, disable hark in all of them
this.remoteConnections.forEach(remoteConnection => { this.remoteConnections.forEach(remoteConnection => {
if (!!remoteConnection.stream) { if (!!remoteConnection.stream?.streamManager) {
remoteConnection.stream.disableStopSpeakingEvent(false); // 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; 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"); 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 methods */
private connectAux(token: string): Promise<void> { private connectAux(token: string): Promise<void> {

View File

@ -181,27 +181,27 @@ export class Stream {
/** /**
* @hidden * @hidden
*/ */
publisherStartSpeakingEventEnabled = false; harkSpeakingEnabled = false;
/** /**
* @hidden * @hidden
*/ */
publisherStartSpeakingEventEnabledOnce = false; harkSpeakingEnabledOnce = false;
/** /**
* @hidden * @hidden
*/ */
publisherStopSpeakingEventEnabled = false; harkStoppedSpeakingEnabled = false;
/** /**
* @hidden * @hidden
*/ */
publisherStopSpeakingEventEnabledOnce = false; harkStoppedSpeakingEnabledOnce = false;
/** /**
* @hidden * @hidden
*/ */
volumeChangeEventEnabled = false; harkVolumeChangeEnabled = false;
/** /**
* @hidden * @hidden
*/ */
volumeChangeEventEnabledOnce = false; harkVolumeChangeEnabledOnce = false;
/** /**
* @hidden * @hidden
*/ */
@ -540,13 +540,14 @@ export class Stream {
/** /**
* @hidden * @hidden
*/ */
enableStartSpeakingEvent(): void { enableHarkSpeakingEvent(): void {
this.setSpeechEventIfNotExists(); this.setHarkListenerIfNotExists();
if (!this.publisherStartSpeakingEventEnabled) { if (!this.harkSpeakingEnabled) {
this.publisherStartSpeakingEventEnabled = true; this.harkSpeakingEnabled = true;
this.speechEvent.on('speaking', () => { this.speechEvent.on('speaking', () => {
this.session.emitEvent('publisherStartSpeaking', [new PublisherSpeakingEvent(this.session, 'publisherStartSpeaking', this.connection, this.streamId)]); 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 * @hidden
*/ */
enableOnceStartSpeakingEvent(): void { enableOnceHarkSpeakingEvent(): void {
this.setSpeechEventIfNotExists(); this.setHarkListenerIfNotExists();
if (!this.publisherStartSpeakingEventEnabledOnce) { if (!this.harkSpeakingEnabledOnce) {
this.publisherStartSpeakingEventEnabledOnce = true; this.harkSpeakingEnabledOnce = true;
this.speechEvent.once('speaking', () => { 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 // 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.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 * @hidden
*/ */
disableStartSpeakingEvent(disabledByOnce: boolean): void { disableHarkSpeakingEvent(disabledByOnce: boolean): void {
if (!!this.speechEvent) { if (!!this.speechEvent) {
this.publisherStartSpeakingEventEnabledOnce = false; this.harkSpeakingEnabledOnce = false;
if (disabledByOnce) { if (disabledByOnce) {
if (this.publisherStartSpeakingEventEnabled) { if (this.harkSpeakingEnabled) {
// The 'on' version of this same event is enabled too. Do not remove the hark listener // The 'on' version of this same event is enabled too. Do not remove the hark listener
return; return;
} }
} else { } else {
this.publisherStartSpeakingEventEnabled = false; this.harkSpeakingEnabled = false;
} }
// Shutting down the hark event // Shutting down the hark event
if (this.volumeChangeEventEnabled || if (this.harkVolumeChangeEnabled ||
this.volumeChangeEventEnabledOnce || this.harkVolumeChangeEnabledOnce ||
this.publisherStopSpeakingEventEnabled || this.harkStoppedSpeakingEnabled ||
this.publisherStopSpeakingEventEnabledOnce) { this.harkStoppedSpeakingEnabledOnce) {
// Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener // Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener
this.speechEvent.off('speaking'); this.speechEvent.off('speaking');
} else { } else {
@ -600,13 +602,14 @@ export class Stream {
/** /**
* @hidden * @hidden
*/ */
enableStopSpeakingEvent(): void { enableHarkStoppedSpeakingEvent(): void {
this.setSpeechEventIfNotExists(); this.setHarkListenerIfNotExists();
if (!this.publisherStopSpeakingEventEnabled) { if (!this.harkStoppedSpeakingEnabled) {
this.publisherStopSpeakingEventEnabled = true; this.harkStoppedSpeakingEnabled = true;
this.speechEvent.on('stopped_speaking', () => { this.speechEvent.on('stopped_speaking', () => {
this.session.emitEvent('publisherStopSpeaking', [new PublisherSpeakingEvent(this.session, 'publisherStopSpeaking', this.connection, this.streamId)]); 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 * @hidden
*/ */
enableOnceStopSpeakingEvent(): void { enableOnceHarkStoppedSpeakingEvent(): void {
this.setSpeechEventIfNotExists(); this.setHarkListenerIfNotExists();
if (!this.publisherStopSpeakingEventEnabledOnce) { if (!this.harkStoppedSpeakingEnabledOnce) {
this.publisherStopSpeakingEventEnabledOnce = true; this.harkStoppedSpeakingEnabledOnce = true;
this.speechEvent.once('stopped_speaking', () => { 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 // 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.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 * @hidden
*/ */
disableStopSpeakingEvent(disabledByOnce: boolean): void { disableHarkStoppedSpeakingEvent(disabledByOnce: boolean): void {
if (!!this.speechEvent) { if (!!this.speechEvent) {
this.publisherStopSpeakingEventEnabledOnce = false; this.harkStoppedSpeakingEnabledOnce = false;
if (disabledByOnce) { if (disabledByOnce) {
if (this.publisherStopSpeakingEventEnabled) { if (this.harkStoppedSpeakingEnabled) {
// We are cancelling the 'once' listener for this event, but the 'on' version // 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 // of this same event is enabled too. Do not remove the hark listener
return; return;
} }
} else { } else {
this.publisherStopSpeakingEventEnabled = false; this.harkStoppedSpeakingEnabled = false;
} }
// Shutting down the hark event // Shutting down the hark event
if (this.volumeChangeEventEnabled || if (this.harkVolumeChangeEnabled ||
this.volumeChangeEventEnabledOnce || this.harkVolumeChangeEnabledOnce ||
this.publisherStartSpeakingEventEnabled || this.harkSpeakingEnabled ||
this.publisherStartSpeakingEventEnabledOnce) { this.harkSpeakingEnabledOnce) {
// Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener // Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener
this.speechEvent.off('stopped_speaking'); this.speechEvent.off('stopped_speaking');
} else { } else {
@ -661,10 +665,10 @@ export class Stream {
/** /**
* @hidden * @hidden
*/ */
enableVolumeChangeEvent(force: boolean): void { enableHarkVolumeChangeEvent(force: boolean): void {
if (this.setSpeechEventIfNotExists()) { if (this.setHarkListenerIfNotExists()) {
if (!this.volumeChangeEventEnabled || force) { if (!this.harkVolumeChangeEnabled || force) {
this.volumeChangeEventEnabled = true; this.harkVolumeChangeEnabled = true;
this.speechEvent.on('volume_change', harkEvent => { this.speechEvent.on('volume_change', harkEvent => {
const oldValue = this.speechEvent.oldVolumeValue; const oldValue = this.speechEvent.oldVolumeValue;
const value = { newValue: harkEvent, oldValue }; const value = { newValue: harkEvent, oldValue };
@ -674,51 +678,51 @@ export class Stream {
} }
} else { } else {
// This way whenever the MediaStream object is available, the event listener will be automatically added // This way whenever the MediaStream object is available, the event listener will be automatically added
this.volumeChangeEventEnabled = true; this.harkVolumeChangeEnabled = true;
} }
} }
/** /**
* @hidden * @hidden
*/ */
enableOnceVolumeChangeEvent(force: boolean): void { enableOnceHarkVolumeChangeEvent(force: boolean): void {
if (this.setSpeechEventIfNotExists()) { if (this.setHarkListenerIfNotExists()) {
if (!this.volumeChangeEventEnabledOnce || force) { if (!this.harkVolumeChangeEnabledOnce || force) {
this.volumeChangeEventEnabledOnce = true; this.harkVolumeChangeEnabledOnce = true;
this.speechEvent.once('volume_change', harkEvent => { this.speechEvent.once('volume_change', harkEvent => {
const oldValue = this.speechEvent.oldVolumeValue; const oldValue = this.speechEvent.oldVolumeValue;
const value = { newValue: harkEvent, oldValue }; const value = { newValue: harkEvent, oldValue };
this.speechEvent.oldVolumeValue = harkEvent; this.speechEvent.oldVolumeValue = harkEvent;
this.disableVolumeChangeEvent(true); this.disableHarkVolumeChangeEvent(true);
this.streamManager.emitEvent('streamAudioVolumeChange', [new StreamManagerEvent(this.streamManager, 'streamAudioVolumeChange', value)]); this.streamManager.emitEvent('streamAudioVolumeChange', [new StreamManagerEvent(this.streamManager, 'streamAudioVolumeChange', value)]);
}); });
} }
} else { } else {
// This way whenever the MediaStream object is available, the event listener will be automatically added // This way whenever the MediaStream object is available, the event listener will be automatically added
this.volumeChangeEventEnabledOnce = true; this.harkVolumeChangeEnabledOnce = true;
} }
} }
/** /**
* @hidden * @hidden
*/ */
disableVolumeChangeEvent(disabledByOnce: boolean): void { disableHarkVolumeChangeEvent(disabledByOnce: boolean): void {
if (!!this.speechEvent) { if (!!this.speechEvent) {
this.volumeChangeEventEnabledOnce = false; this.harkVolumeChangeEnabledOnce = false;
if (disabledByOnce) { if (disabledByOnce) {
if (this.volumeChangeEventEnabled) { if (this.harkVolumeChangeEnabled) {
// We are cancelling the 'once' listener for this event, but the 'on' version // 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 // of this same event is enabled too. Do not remove the hark listener
return; return;
} }
} else { } else {
this.volumeChangeEventEnabled = false; this.harkVolumeChangeEnabled = false;
} }
// Shutting down the hark event // Shutting down the hark event
if (this.publisherStartSpeakingEventEnabled || if (this.harkSpeakingEnabled ||
this.publisherStartSpeakingEventEnabledOnce || this.harkSpeakingEnabledOnce ||
this.publisherStopSpeakingEventEnabled || this.harkStoppedSpeakingEnabled ||
this.publisherStopSpeakingEventEnabledOnce) { this.harkStoppedSpeakingEnabledOnce) {
// Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener // Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener
this.speechEvent.off('volume_change'); this.speechEvent.off('volume_change');
} else { } else {
@ -779,7 +783,7 @@ export class Stream {
/* Private methods */ /* Private methods */
private setSpeechEventIfNotExists(): boolean { private setHarkListenerIfNotExists(): boolean {
if (!!this.mediaStream) { if (!!this.mediaStream) {
if (!this.speechEvent) { if (!this.speechEvent) {
const harkOptions = !!this.harkOptions ? this.harkOptions : (this.session.openvidu.advancedConfiguration.publisherSpeakingEventsOptions || {}); const harkOptions = !!this.harkOptions ? this.harkOptions : (this.session.openvidu.advancedConfiguration.publisherSpeakingEventsOptions || {});
@ -1026,27 +1030,23 @@ export class Stream {
private initHarkEvents(): void { private initHarkEvents(): void {
if (!!this.mediaStream!.getAudioTracks()[0]) { if (!!this.mediaStream!.getAudioTracks()[0]) {
// Hark events can only be set if audio track is available // Hark events can only be set if audio track is available
if (this.streamManager.remote) { if (this.session.anySpeechEventListenerEnabled('publisherStartSpeaking', true, this.streamManager)) {
// publisherStartSpeaking/publisherStopSpeaking is only defined for remote streams this.enableOnceHarkSpeakingEvent();
if (this.session.startSpeakingEventsEnabled) {
this.enableStartSpeakingEvent();
}
if (this.session.startSpeakingEventsEnabledOnce) {
this.enableOnceStartSpeakingEvent();
}
if (this.session.stopSpeakingEventsEnabled) {
this.enableStopSpeakingEvent();
}
if (this.session.stopSpeakingEventsEnabledOnce) {
this.enableOnceStopSpeakingEvent();
}
} }
// streamAudioVolumeChange event is defined for both Publishers and Subscribers if (this.session.anySpeechEventListenerEnabled('publisherStartSpeaking', false, this.streamManager)) {
if (this.volumeChangeEventEnabled) { this.enableHarkSpeakingEvent();
this.enableVolumeChangeEvent(true);
} }
if (this.volumeChangeEventEnabledOnce) { if (this.session.anySpeechEventListenerEnabled('publisherStopSpeaking', true, this.streamManager)) {
this.enableOnceVolumeChangeEvent(true); this.enableOnceHarkStoppedSpeakingEvent();
}
if (this.session.anySpeechEventListenerEnabled('publisherStopSpeaking', false, this.streamManager)) {
this.enableHarkStoppedSpeakingEvent();
}
if (this.harkVolumeChangeEnabledOnce) {
this.enableOnceHarkVolumeChangeEvent(true);
}
if (this.harkVolumeChangeEnabled) {
this.enableHarkVolumeChangeEvent(true);
} }
} }
} }

View File

@ -48,6 +48,9 @@ let platform: PlatformUtils;
* - videoElementCreated ([[VideoElementEvent]]) * - videoElementCreated ([[VideoElementEvent]])
* - videoElementDestroyed ([[VideoElementEvent]]) * - videoElementDestroyed ([[VideoElementEvent]])
* - streamPlaying ([[StreamManagerEvent]]) * - streamPlaying ([[StreamManagerEvent]])
* - streamPropertyChanged ([[StreamPropertyChangedEvent]])
* - publisherStartSpeaking ([[PublisherSpeakingEvent]])
* - publisherStopSpeaking ([[PublisherSpeakingEvent]])
* - streamAudioVolumeChange ([[StreamManagerEvent]]) * - streamAudioVolumeChange ([[StreamManagerEvent]])
* *
*/ */
@ -174,8 +177,16 @@ export class StreamManager extends EventDispatcher {
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]);
} }
} }
if (type === 'streamAudioVolumeChange' && this.stream.hasAudio) { if (this.stream.hasAudio) {
this.stream.enableVolumeChangeEvent(false); if (type === 'publisherStartSpeaking') {
this.stream.enableHarkSpeakingEvent();
}
if (type === 'publisherStopSpeaking') {
this.stream.enableHarkStoppedSpeakingEvent();
}
if (type === 'streamAudioVolumeChange') {
this.stream.enableHarkVolumeChangeEvent(false);
}
} }
return this; return this;
} }
@ -202,8 +213,16 @@ export class StreamManager extends EventDispatcher {
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]);
} }
} }
if (type === 'streamAudioVolumeChange' && this.stream.hasAudio) { if (this.stream.hasAudio) {
this.stream.enableOnceVolumeChangeEvent(false); if (type === 'publisherStartSpeaking') {
this.stream.enableOnceHarkSpeakingEvent();
}
if (type === 'publisherStopSpeaking') {
this.stream.enableOnceHarkStoppedSpeakingEvent();
}
if (type === 'streamAudioVolumeChange') {
this.stream.enableOnceHarkVolumeChangeEvent(false);
}
} }
return this; return this;
} }
@ -215,10 +234,25 @@ export class StreamManager extends EventDispatcher {
super.off(type, handler); 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') { 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) { if (remainingVolumeEventListeners === 0) {
this.stream.disableVolumeChangeEvent(false); this.stream.disableHarkVolumeChangeEvent(false);
} }
} }
@ -419,9 +453,10 @@ export class StreamManager extends EventDispatcher {
this.videos.forEach(streamManagerVideo => { this.videos.forEach(streamManagerVideo => {
// Remove oncanplay event listener (only OpenVidu browser listener, not the user ones) // 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.video.removeEventListener('canplay', this.canPlayListener);
} streamManagerVideo.canplayListenerAdded = false; }
streamManagerVideo.canplayListenerAdded = false;
if (!!streamManagerVideo.targetElement) { if (!!streamManagerVideo.targetElement) {
// Only remove from DOM videos created by OpenVidu Browser (those generated by passing a valid targetElement in OpenVidu.initPublisher // 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 // 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); this.ee.emitEvent(type, eventArray);
} }
/** /**
* @hidden * @hidden
*/ */
createVideo(): HTMLVideoElement { createVideo(): HTMLVideoElement {
return document.createElement('video'); return document.createElement('video');
} }

View File

@ -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 * 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 { export class Subscriber extends StreamManager {

View File

@ -17,16 +17,17 @@
import { Event } from './Event'; import { Event } from './Event';
import { Connection } from '../../OpenVidu/Connection'; import { Connection } from '../../OpenVidu/Connection';
import { Session } from '../..'; import { Session } from '../../OpenVidu/Session';
import { StreamManager } from '../../OpenVidu/StreamManager';
/** /**
* Defines the following events: * Defines the following events:
* - `publisherStartSpeaking`: dispatched by [[Session]] when a remote user has started speaking * - `publisherStartSpeaking`: dispatched by [[Session]] and [[StreamManager]] when a user has started speaking
* - `publisherStopSpeaking`: dispatched by [[Session]] when a remote user has stopped speaking * - `publisherStopSpeaking`: dispatched by [[Session]] and [[StreamManager]] when a user has stopped speaking
* *
* More information: * 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]] * - You can further configure how the events are dispatched by setting property `publisherSpeakingEventsOptions` in the call of [[OpenVidu.setAdvancedConfiguration]]
*/ */
export class PublisherSpeakingEvent extends Event { export class PublisherSpeakingEvent extends Event {
@ -44,7 +45,7 @@ export class PublisherSpeakingEvent extends Event {
/** /**
* @hidden * @hidden
*/ */
constructor(target: Session, type: string, connection: Connection, streamId: string) { constructor(target: Session | StreamManager, type: string, connection: Connection, streamId: string) {
super(false, target, type); super(false, target, type);
this.type = type; this.type = type;
this.connection = connection; this.connection = connection;