diff --git a/app/lib/RoomClient.js b/app/lib/RoomClient.js index 93ac56a..5420adc 100644 --- a/app/lib/RoomClient.js +++ b/app/lib/RoomClient.js @@ -1,6 +1,7 @@ import protooClient from 'protoo-client'; import * as mediasoupClient from 'mediasoup-client'; import Logger from './Logger'; +import hark from 'hark'; import ScreenShare from './ScreenShare'; import { getProtooUrl } from './urlFactory'; import * as cookiesManager from './cookiesManager'; @@ -1380,7 +1381,33 @@ export default class RoomClient }) .then(() => { + const stream = new MediaStream; + logger.debug('_setMicProducer() succeeded'); + stream.addTrack(producer.track); + if (!stream.getAudioTracks()[0]) + throw new Error('_setMicProducer(): given stream has no audio track'); + producer.hark = hark(stream, { play: false }); + + // eslint-disable-next-line no-unused-vars + producer.hark.on('volume_change', (dBs, threshold) => + { + // The exact formula to convert from dBs (-100..0) to linear (0..1) is: + // Math.pow(10, dBs / 20) + // However it does not produce a visually useful output, so let exagerate + // it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to + // minimize component renderings. + let volume = Math.round(Math.pow(10, dBs / 85) * 10); + + if (volume === 1) + volume = 0; + + if (volume !== producer.volume) + { + producer.volume = volume; + this._dispatch(stateActions.setProducerVolume(producer.id, volume)); + } + }); }) .catch((error) => { @@ -1823,7 +1850,8 @@ export default class RoomClient track : null, codec : codec ? codec.name : null }, - consumer.peer.name)); + consumer.peer.name) + ); consumer.on('close', (originator) => { @@ -1835,6 +1863,43 @@ export default class RoomClient consumer.id, consumer.peer.name)); }); + consumer.on('handled', (originator) => + { + logger.debug( + 'consumer "handled" event [id:%s, originator:%s, consumer:%o]', + consumer.id, originator, consumer); + if (consumer.kind === 'audio') + { + const stream = new MediaStream; + + stream.addTrack(consumer.track); + if (!stream.getAudioTracks()[0]) + throw new Error('consumer.on("handled" | given stream has no audio track'); + + consumer.hark = hark(stream, { play: false }); + + // eslint-disable-next-line no-unused-vars + consumer.hark.on('volume_change', (dBs, threshold) => + { + // The exact formula to convert from dBs (-100..0) to linear (0..1) is: + // Math.pow(10, dBs / 20) + // However it does not produce a visually useful output, so let exagerate + // it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to + // minimize component renderings. + let volume = Math.round(Math.pow(10, dBs / 85) * 10); + + if (volume === 1) + volume = 0; + + if (volume !== consumer.volume) + { + consumer.volume = volume; + this._dispatch(stateActions.setConsumerVolume(consumer.id, volume)); + } + }); + } + }); + consumer.on('pause', (originator) => { logger.debug( diff --git a/app/lib/components/Me.jsx b/app/lib/components/Me.jsx index 38dc747..dcedb94 100644 --- a/app/lib/components/Me.jsx +++ b/app/lib/components/Me.jsx @@ -140,6 +140,7 @@ class Me extends React.Component advancedMode={advancedMode} peer={me} audioTrack={micProducer ? micProducer.track : null} + volume={micProducer ? micProducer.volume : null} videoTrack={webcamProducer ? webcamProducer.track : null} videoVisible={videoVisible} audioCodec={micProducer ? micProducer.codec : null} diff --git a/app/lib/components/Peer.jsx b/app/lib/components/Peer.jsx index d3961ae..2b06f13 100644 --- a/app/lib/components/Peer.jsx +++ b/app/lib/components/Peer.jsx @@ -8,27 +8,27 @@ import * as stateActions from '../redux/stateActions'; import PeerView from './PeerView'; import ScreenView from './ScreenView'; -class Peer extends Component +class Peer extends Component { state = { controlsVisible : false }; - handleMouseOver = () => + handleMouseOver = () => { this.setState({ controlsVisible : true }); }; - handleMouseOut = () => + handleMouseOut = () => { this.setState({ controlsVisible : false }); }; - render() + render() { const { advancedMode, @@ -45,35 +45,35 @@ class Peer extends Component toggleConsumerFullscreen, style } = this.props; - + const micEnabled = ( Boolean(micConsumer) && !micConsumer.locallyPaused && !micConsumer.remotelyPaused ); - + const videoVisible = ( Boolean(webcamConsumer) && !webcamConsumer.locallyPaused && !webcamConsumer.remotelyPaused ); - + const screenVisible = ( Boolean(screenConsumer) && !screenConsumer.locallyPaused && !screenConsumer.remotelyPaused ); - + let videoProfile; - + if (webcamConsumer) videoProfile = webcamConsumer.profile; - + let screenProfile; - + if (screenConsumer) screenProfile = screenConsumer.profile; - + return (