mirror of https://github.com/OpenVidu/openvidu.git
openvidu-browser: streamAudioVolumeChange event
parent
b0bc3d40d2
commit
5ac41f3471
|
@ -29,7 +29,9 @@ declare var MediaRecorder: any;
|
||||||
/**
|
/**
|
||||||
* Easy recording of [[Stream]] objects straightaway from the browser. Initialized with [[OpenVidu.initLocalRecorder]] method
|
* Easy recording of [[Stream]] objects straightaway from the browser. Initialized with [[OpenVidu.initLocalRecorder]] method
|
||||||
*
|
*
|
||||||
* > WARNING: Performing browser local recording of **remote streams** may cause some troubles. A long waiting time may be required after calling _LocalRecorder.stop()_ in this case
|
* > WARNINGS:
|
||||||
|
* - Performing browser local recording of **remote streams** may cause some troubles. A long waiting time may be required after calling _LocalRecorder.stop()_ in this case
|
||||||
|
* - Only Chrome and Firefox support local stream recording
|
||||||
*/
|
*/
|
||||||
export class LocalRecorder {
|
export class LocalRecorder {
|
||||||
|
|
||||||
|
|
|
@ -80,11 +80,11 @@ export class Session implements EventDispatcher {
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
*/
|
*/
|
||||||
isFirstIonicIosSubscriber: boolean = true;
|
isFirstIonicIosSubscriber = true;
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
*/
|
*/
|
||||||
countDownForIonicIosSubscribers: boolean = true;
|
countDownForIonicIosSubscribers = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
|
@ -567,7 +567,7 @@ export class Session implements EventDispatcher {
|
||||||
// If there are already available remote streams, enable hark 'speaking' event in all of them
|
// If there are already available remote streams, enable hark 'speaking' event in all of them
|
||||||
for (const connectionId in this.remoteConnections) {
|
for (const connectionId in this.remoteConnections) {
|
||||||
const str = this.remoteConnections[connectionId].stream;
|
const str = this.remoteConnections[connectionId].stream;
|
||||||
if (!!str && !str.speechEvent && str.hasAudio) {
|
if (!!str && str.hasAudio) {
|
||||||
str.enableSpeakingEvents();
|
str.enableSpeakingEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -596,7 +596,7 @@ export class Session implements EventDispatcher {
|
||||||
// If there are already available remote streams, enable hark in all of them
|
// If there are already available remote streams, enable hark in all of them
|
||||||
for (const connectionId in this.remoteConnections) {
|
for (const connectionId in this.remoteConnections) {
|
||||||
const str = this.remoteConnections[connectionId].stream;
|
const str = this.remoteConnections[connectionId].stream;
|
||||||
if (!!str && !str.speechEvent && str.hasAudio) {
|
if (!!str && str.hasAudio) {
|
||||||
str.enableOnceSpeakingEvents();
|
str.enableOnceSpeakingEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -623,7 +623,7 @@ export class Session implements EventDispatcher {
|
||||||
// If there are already available remote streams, disable hark in all of them
|
// If there are already available remote streams, disable hark in all of them
|
||||||
for (const connectionId in this.remoteConnections) {
|
for (const connectionId in this.remoteConnections) {
|
||||||
const str = this.remoteConnections[connectionId].stream;
|
const str = this.remoteConnections[connectionId].stream;
|
||||||
if (!!str && !!str.speechEvent) {
|
if (!!str) {
|
||||||
str.disableSpeakingEvents();
|
str.disableSpeakingEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { OutboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/Ou
|
||||||
import { WebRtcPeer, WebRtcPeerSendonly, WebRtcPeerRecvonly, WebRtcPeerSendrecv } from '../OpenViduInternal/WebRtcPeer/WebRtcPeer';
|
import { WebRtcPeer, WebRtcPeerSendonly, WebRtcPeerRecvonly, WebRtcPeerSendrecv } from '../OpenViduInternal/WebRtcPeer/WebRtcPeer';
|
||||||
import { WebRtcStats } from '../OpenViduInternal/WebRtcStats/WebRtcStats';
|
import { WebRtcStats } from '../OpenViduInternal/WebRtcStats/WebRtcStats';
|
||||||
import { PublisherSpeakingEvent } from '../OpenViduInternal/Events/PublisherSpeakingEvent';
|
import { PublisherSpeakingEvent } from '../OpenViduInternal/Events/PublisherSpeakingEvent';
|
||||||
|
import { StreamManagerEvent } from '../OpenViduInternal/Events/StreamManagerEvent';
|
||||||
import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent';
|
import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent';
|
||||||
import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError';
|
import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError';
|
||||||
|
|
||||||
|
@ -156,6 +157,18 @@ export class Stream implements EventDispatcher {
|
||||||
* @hidden
|
* @hidden
|
||||||
*/
|
*/
|
||||||
speechEvent: any;
|
speechEvent: any;
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
publisherStartSpeakingEventEnabled = false;
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
publisherStopSpeakingEventEnabled = false;
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
volumeChangeEventEnabled = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -334,7 +347,6 @@ export class Stream implements EventDispatcher {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Hidden methods */
|
/* Hidden methods */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -439,6 +451,7 @@ export class Stream implements EventDispatcher {
|
||||||
}
|
}
|
||||||
if (this.speechEvent) {
|
if (this.speechEvent) {
|
||||||
this.speechEvent.stop();
|
this.speechEvent.stop();
|
||||||
|
delete this.speechEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stopWebRtcStats();
|
this.stopWebRtcStats();
|
||||||
|
@ -503,7 +516,6 @@ export class Stream implements EventDispatcher {
|
||||||
const harkOptions = this.session.openvidu.advancedConfiguration.publisherSpeakingEventsOptions || {};
|
const harkOptions = this.session.openvidu.advancedConfiguration.publisherSpeakingEventsOptions || {};
|
||||||
harkOptions.interval = (typeof harkOptions.interval === 'number') ? harkOptions.interval : 50;
|
harkOptions.interval = (typeof harkOptions.interval === 'number') ? harkOptions.interval : 50;
|
||||||
harkOptions.threshold = (typeof harkOptions.threshold === 'number') ? harkOptions.threshold : -50;
|
harkOptions.threshold = (typeof harkOptions.threshold === 'number') ? harkOptions.threshold : -50;
|
||||||
|
|
||||||
this.speechEvent = hark(this.mediaStream, harkOptions);
|
this.speechEvent = hark(this.mediaStream, harkOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -513,35 +525,106 @@ export class Stream implements EventDispatcher {
|
||||||
*/
|
*/
|
||||||
enableSpeakingEvents(): void {
|
enableSpeakingEvents(): void {
|
||||||
this.setSpeechEventIfNotExists();
|
this.setSpeechEventIfNotExists();
|
||||||
|
if (!this.publisherStartSpeakingEventEnabled) {
|
||||||
|
this.publisherStartSpeakingEventEnabled = 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)]);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
if (!this.publisherStopSpeakingEventEnabled) {
|
||||||
|
this.publisherStopSpeakingEventEnabled = 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)]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
*/
|
*/
|
||||||
enableOnceSpeakingEvents(): void {
|
enableOnceSpeakingEvents(): void {
|
||||||
this.setSpeechEventIfNotExists();
|
this.setSpeechEventIfNotExists();
|
||||||
this.speechEvent.on('speaking', () => {
|
if (!this.publisherStartSpeakingEventEnabled) {
|
||||||
|
this.publisherStartSpeakingEventEnabled = true;
|
||||||
|
this.speechEvent.once('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.disableSpeakingEvents();
|
this.disableSpeakingEvents();
|
||||||
});
|
});
|
||||||
this.speechEvent.on('stopped_speaking', () => {
|
}
|
||||||
|
if (!this.publisherStopSpeakingEventEnabled) {
|
||||||
|
this.publisherStopSpeakingEventEnabled = true;
|
||||||
|
this.speechEvent.once('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.disableSpeakingEvents();
|
this.disableSpeakingEvents();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
*/
|
*/
|
||||||
disableSpeakingEvents(): void {
|
disableSpeakingEvents(): void {
|
||||||
|
if (!!this.speechEvent) {
|
||||||
|
if (this.volumeChangeEventEnabled) {
|
||||||
|
// 'streamAudioVolumeChange' event is enabled. Cannot stop the hark process
|
||||||
|
this.speechEvent.off('speaking');
|
||||||
|
this.speechEvent.off('stopped_speaking');
|
||||||
|
} else {
|
||||||
this.speechEvent.stop();
|
this.speechEvent.stop();
|
||||||
this.speechEvent = undefined;
|
delete this.speechEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.publisherStartSpeakingEventEnabled = false;
|
||||||
|
this.publisherStopSpeakingEventEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
enableVolumeChangeEvent(): void {
|
||||||
|
this.setSpeechEventIfNotExists();
|
||||||
|
if (!this.volumeChangeEventEnabled) {
|
||||||
|
this.volumeChangeEventEnabled = true;
|
||||||
|
this.speechEvent.on('volume_change', harkEvent => {
|
||||||
|
const oldValue = this.speechEvent.oldVolumeValue;
|
||||||
|
const value = { newValue: harkEvent, oldValue };
|
||||||
|
this.speechEvent.oldVolumeValue = harkEvent;
|
||||||
|
this.streamManager.emitEvent('streamAudioVolumeChange', [new StreamManagerEvent(this.streamManager, 'streamAudioVolumeChange', value)]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
enableOnceVolumeChangeEvent(): void {
|
||||||
|
this.setSpeechEventIfNotExists();
|
||||||
|
if (!this.volumeChangeEventEnabled) {
|
||||||
|
this.volumeChangeEventEnabled = true;
|
||||||
|
this.speechEvent.once('volume_change', harkEvent => {
|
||||||
|
const oldValue = this.speechEvent.oldVolumeValue;
|
||||||
|
const value = { newValue: harkEvent, oldValue };
|
||||||
|
this.speechEvent.oldVolumeValue = harkEvent;
|
||||||
|
this.disableVolumeChangeEvent();
|
||||||
|
this.streamManager.emitEvent('streamAudioVolumeChange', [new StreamManagerEvent(this.streamManager, 'streamAudioVolumeChange', value)]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
disableVolumeChangeEvent(): void {
|
||||||
|
if (!!this.speechEvent) {
|
||||||
|
if (this.session.speakingEventsEnabled) {
|
||||||
|
// 'publisherStartSpeaking' and/or publisherStopSpeaking` events are enabled. Cannot stop the hark process
|
||||||
|
this.speechEvent.off('volume_change');
|
||||||
|
} else {
|
||||||
|
this.speechEvent.stop();
|
||||||
|
delete this.speechEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.volumeChangeEventEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -133,7 +133,7 @@ export class StreamManager implements EventDispatcher {
|
||||||
console.info("Remote 'Stream' with id [" + this.stream.streamId + '] video is now playing');
|
console.info("Remote 'Stream' with id [" + this.stream.streamId + '] video is now playing');
|
||||||
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]);
|
this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]);
|
||||||
}
|
}
|
||||||
this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this)]);
|
this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,10 +161,13 @@ export class StreamManager implements EventDispatcher {
|
||||||
this.videos[0].video.paused === false &&
|
this.videos[0].video.paused === false &&
|
||||||
this.videos[0].video.ended === false &&
|
this.videos[0].video.ended === false &&
|
||||||
this.videos[0].video.readyState === 4) {
|
this.videos[0].video.readyState === 4) {
|
||||||
this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this)]);
|
this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]);
|
||||||
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) {
|
||||||
|
this.stream.enableVolumeChangeEvent();
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,10 +194,13 @@ export class StreamManager implements EventDispatcher {
|
||||||
this.videos[0].video.paused === false &&
|
this.videos[0].video.paused === false &&
|
||||||
this.videos[0].video.ended === false &&
|
this.videos[0].video.ended === false &&
|
||||||
this.videos[0].video.readyState === 4) {
|
this.videos[0].video.readyState === 4) {
|
||||||
this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this)]);
|
this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]);
|
||||||
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) {
|
||||||
|
this.stream.enableOnceVolumeChangeEvent();
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +213,11 @@ export class StreamManager implements EventDispatcher {
|
||||||
} else {
|
} else {
|
||||||
this.ee.off(type, handler);
|
this.ee.off(type, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === 'streamAudioVolumeChange') {
|
||||||
|
this.stream.disableVolumeChangeEvent();
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,14 +33,14 @@ export class ConnectionEvent extends Event {
|
||||||
connection: Connection;
|
connection: Connection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For 'connectionDestroyed' event:
|
* For `connectionDestroyed` event:
|
||||||
* - "disconnect": the remote user has called `Session.disconnect()`
|
* - "disconnect": the remote user has called `Session.disconnect()`
|
||||||
* - "forceDisconnectByUser": the remote user has been evicted from the Session by other user calling `Session.forceDisconnect()`
|
* - "forceDisconnectByUser": the remote user has been evicted from the Session by other user calling `Session.forceDisconnect()`
|
||||||
* - "forceDisconnectByServer": the remote user has been evicted from the Session by the application
|
* - "forceDisconnectByServer": the remote user has been evicted from the Session by the application
|
||||||
* - "sessionClosedByServer": the Session has been closed by the application
|
* - "sessionClosedByServer": the Session has been closed by the application
|
||||||
* - "networkDisconnect": the remote user network connection has dropped
|
* - "networkDisconnect": the remote user network connection has dropped
|
||||||
*
|
*
|
||||||
* For 'connectionCreated' empty string
|
* For `connectionCreated` event an empty string
|
||||||
*/
|
*/
|
||||||
reason: string;
|
reason: string;
|
||||||
|
|
||||||
|
|
|
@ -20,15 +20,29 @@ import { StreamManager } from '../../OpenVidu/StreamManager';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the following events:
|
* Defines the following events:
|
||||||
* - `streamPlaying`: dispatched by [[StreamManager]] ([[Publisher]] and [[Subscriber]])
|
* - `streamPlaying`: dispatched by [[StreamManager]] ([[Publisher]] and [[Subscriber]]) whenever its media stream starts playing (one of its videos has media
|
||||||
|
* and has begun to play)
|
||||||
|
* - `streamAudioVolumeChange`: dispatched by [[StreamManager]] ([[Publisher]] and [[Subscriber]]) when the volume of its Stream's audio track
|
||||||
|
* changes. Only applies if [[Stream.hasAudio]] is `true`. The frequency this event is fired with is defined by property `interval` of
|
||||||
|
* [[OpenViduAdvancedConfiguration.publisherSpeakingEventsOptions]] (default 50ms)
|
||||||
*/
|
*/
|
||||||
export class StreamManagerEvent extends Event {
|
export class StreamManagerEvent extends Event {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For `streamAudioVolumeChange` event:
|
||||||
|
* - `{newValue: number, oldValue: number}`: new and old audio volume values. These values are between -100 (silence) and 0 (loudest possible volume).
|
||||||
|
* They are not exact and depend on how the browser is managing the audio track, but -100 and 0 can be taken as limit values.
|
||||||
|
*
|
||||||
|
* For `streamPlaying` event undefined
|
||||||
|
*/
|
||||||
|
value: Object | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
*/
|
*/
|
||||||
constructor(target: StreamManager) {
|
constructor(target: StreamManager, type: string, value: Object | undefined) {
|
||||||
super(false, target, 'streamPlaying');
|
super(false, target, type);
|
||||||
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue