From bb022543a888e249aeee01cb64136e9bfee31aa3 Mon Sep 17 00:00:00 2001 From: Torjus Date: Tue, 17 Jul 2018 12:49:52 +0200 Subject: [PATCH 1/5] Fix fade-out animation running on page load --- app/stylus/components/Me.styl | 5 +---- app/stylus/components/Peer.styl | 7 ++----- app/stylus/index.styl | 1 - app/stylus/keyframes.styl | 23 ----------------------- 4 files changed, 3 insertions(+), 33 deletions(-) delete mode 100644 app/stylus/keyframes.styl diff --git a/app/stylus/components/Me.styl b/app/stylus/components/Me.styl index 2f21d71..7df0c0d 100644 --- a/app/stylus/components/Me.styl +++ b/app/stylus/components/Me.styl @@ -27,14 +27,11 @@ justify-content: flex-start; align-items: center; padding: 0.4vmin; - visibility: hidden; opacity: 0; - animation: fade-out 0.3s; + transition: opacity 0.3s; &.visible { - visibility: visible; opacity: 1; - animation: fade-in 0.3s; } > .button { diff --git a/app/stylus/components/Peer.styl b/app/stylus/components/Peer.styl index a6567d6..5a9e762 100644 --- a/app/stylus/components/Peer.styl +++ b/app/stylus/components/Peer.styl @@ -41,14 +41,11 @@ justify-content: flex-start; align-items: center; padding: 0.4vmin; - visibility: hidden; opacity: 0; - animation: fade-out 0.3s; - + transition: opacity 0.3s; + &.visible { - visibility: visible; opacity: 1; - animation: fade-in 0.3s; } > .button { diff --git a/app/stylus/index.styl b/app/stylus/index.styl index a9a58f8..dbc11ba 100644 --- a/app/stylus/index.styl +++ b/app/stylus/index.styl @@ -5,7 +5,6 @@ global-reset(); @import './mixins'; @import './fonts'; @import './reset'; -@import './keyframes'; html { height: 100%; diff --git a/app/stylus/keyframes.styl b/app/stylus/keyframes.styl deleted file mode 100644 index 9d200f7..0000000 --- a/app/stylus/keyframes.styl +++ /dev/null @@ -1,23 +0,0 @@ -@keyframes fade-in { - from { - opacity: 0; - visibility: hidden; - } - - to { - opacity: 1; - visibility: visible; - } -} - -@keyframes fade-out { - from { - opacity: 1; - visibility: visible; - } - - to { - opacity: 0; - visibility: hidden; - } -} \ No newline at end of file From 3ab603bbe7fdaec4d056a7ca3096ea42cf520c6a Mon Sep 17 00:00:00 2001 From: Stefan Otto Date: Tue, 17 Jul 2018 12:56:58 +0200 Subject: [PATCH 2/5] hark running now on producers and consumers directly instead on PeerView component, now we can send audiolevel events into more places ... --- app/lib/RoomClient.js | 67 ++++++++++++++++++++++++++++- app/lib/components/Me.jsx | 1 + app/lib/components/Peer.jsx | 37 ++++++++-------- app/lib/components/PeerView.jsx | 43 ++---------------- app/lib/redux/reducers/consumers.js | 9 ++++ app/lib/redux/reducers/producers.js | 9 ++++ app/lib/redux/stateActions.js | 16 +++++++ 7 files changed, 123 insertions(+), 59 deletions(-) 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 (
:null } - +
- +
- +
@@ -136,6 +136,7 @@ class Peer extends Component advancedMode={advancedMode} peer={peer} audioTrack={micConsumer ? micConsumer.track : null} + volume={micConsumer ? micConsumer.volume : null} videoTrack={webcamConsumer ? webcamConsumer.track : null} videoVisible={videoVisible} videoProfile={videoProfile} @@ -143,7 +144,7 @@ class Peer extends Component videoCodec={webcamConsumer ? webcamConsumer.codec : null} />
- + {screenConsumer ?
@@ -160,7 +161,7 @@ class Peer extends Component onDisableScreen(peer.name) : onEnableScreen(peer.name); }} /> - +
@@ -236,7 +237,7 @@ const mapDispatchToProps = (dispatch) => }, onEnableWebcam : (peerName) => { - + dispatch(requestActions.resumePeerVideo(peerName)); }, onDisableWebcam : (peerName) => diff --git a/app/lib/components/PeerView.jsx b/app/lib/components/PeerView.jsx index c258584..4a512a6 100644 --- a/app/lib/components/PeerView.jsx +++ b/app/lib/components/PeerView.jsx @@ -2,7 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import Spinner from 'react-spinner'; -import hark from 'hark'; import * as appPropTypes from './appPropTypes'; import EditableInput from './EditableInput'; @@ -27,10 +26,6 @@ export default class PeerView extends React.Component // @type {MediaStreamTrack} this._videoTrack = null; - // Hark instance. - // @type {Object} - this._hark = null; - // Periodic timer for showing video resolution. this._videoResolutionTimer = null; } @@ -40,6 +35,7 @@ export default class PeerView extends React.Component const { isMe, peer, + volume, advancedMode, videoVisible, videoProfile, @@ -49,7 +45,6 @@ export default class PeerView extends React.Component } = this.props; const { - volume, videoWidth, videoHeight } = this.state; @@ -149,9 +144,6 @@ export default class PeerView extends React.Component componentWillUnmount() { - if (this._hark) - this._hark.stop(); - clearInterval(this._videoResolutionTimer); } @@ -160,6 +152,7 @@ export default class PeerView extends React.Component const { audioTrack, videoTrack } = nextProps; this._setTracks(audioTrack, videoTrack); + } _setTracks(audioTrack, videoTrack) @@ -170,9 +163,6 @@ export default class PeerView extends React.Component this._audioTrack = audioTrack; this._videoTrack = videoTrack; - if (this._hark) - this._hark.stop(); - clearInterval(this._videoResolutionTimer); this._hideVideoResolution(); @@ -190,9 +180,6 @@ export default class PeerView extends React.Component video.srcObject = stream; - if (audioTrack) - this._runHark(stream); - if (videoTrack) this._showVideoResolution(); } @@ -202,31 +189,6 @@ export default class PeerView extends React.Component } } - _runHark(stream) - { - if (!stream.getAudioTracks()[0]) - throw new Error('_runHark() | given stream has no audio track'); - - this._hark = hark(stream, { play: false }); - - // eslint-disable-next-line no-unused-vars - this._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 !== this.state.volume) - this.setState({ volume: volume }); - }); - } - _showVideoResolution() { this._videoResolutionTimer = setInterval(() => @@ -259,6 +221,7 @@ PeerView.propTypes = [ appPropTypes.Me, appPropTypes.Peer ]).isRequired, advancedMode : PropTypes.bool, audioTrack : PropTypes.any, + volume : PropTypes.number, videoTrack : PropTypes.any, videoVisible : PropTypes.bool.isRequired, videoProfile : PropTypes.string, diff --git a/app/lib/redux/reducers/consumers.js b/app/lib/redux/reducers/consumers.js index 81f0e1c..117cdc5 100644 --- a/app/lib/redux/reducers/consumers.js +++ b/app/lib/redux/reducers/consumers.js @@ -35,6 +35,15 @@ const consumers = (state = initialState, action) => return { ...state, [consumerId]: newConsumer }; } + case 'SET_CONSUMER_VOLUME': + { + const { consumerId, volume } = action.payload; + const consumer = state[consumerId]; + const newConsumer = { ...consumer, volume }; + + return { ...state, [consumerId]: newConsumer }; + } + case 'SET_CONSUMER_RESUMED': { const { consumerId, originator } = action.payload; diff --git a/app/lib/redux/reducers/producers.js b/app/lib/redux/reducers/producers.js index 4562b8b..736f70b 100644 --- a/app/lib/redux/reducers/producers.js +++ b/app/lib/redux/reducers/producers.js @@ -35,6 +35,15 @@ const producers = (state = initialState, action) => return { ...state, [producerId]: newProducer }; } + case 'SET_PRODUCER_VOLUME': + { + const { producerId, volume } = action.payload; + const producer = state[producerId]; + const newProducer = { ...producer, volume }; + + return { ...state, [producerId]: newProducer }; + } + case 'SET_PRODUCER_RESUMED': { const { producerId, originator } = action.payload; diff --git a/app/lib/redux/stateActions.js b/app/lib/redux/stateActions.js index f9a88d4..62307a8 100644 --- a/app/lib/redux/stateActions.js +++ b/app/lib/redux/stateActions.js @@ -331,6 +331,22 @@ export const setConsumerTrack = (consumerId, track) => }; }; +export const setConsumerVolume = (consumerId, volume) => +{ + return { + type : 'SET_CONSUMER_VOLUME', + payload : { consumerId, volume } + }; +}; + +export const setProducerVolume = (producerId, volume) => +{ + return { + type : 'SET_PRODUCER_VOLUME', + payload : { producerId, volume } + }; +}; + export const addNotification = (notification) => { return { From 61d395c6d8406597e8cf24d86465a62de8551fdb Mon Sep 17 00:00:00 2001 From: Stefan Otto Date: Tue, 17 Jul 2018 14:59:45 +0200 Subject: [PATCH 3/5] microphone indicator changes opacity with volume level --- .../components/ParticipantList/ListPeer.jsx | 4 +++- app/lib/components/Peers.jsx | 6 +++--- app/package-lock.json | 19 ++++++++++++------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/app/lib/components/ParticipantList/ListPeer.jsx b/app/lib/components/ParticipantList/ListPeer.jsx index 2fb666c..5702100 100644 --- a/app/lib/components/ParticipantList/ListPeer.jsx +++ b/app/lib/components/ParticipantList/ListPeer.jsx @@ -67,6 +67,8 @@ const ListPeer = (props) => off : !micEnabled, disabled : peer.peerAudioInProgress })} + style={{ opacity : micEnabled && micConsumer ? (micConsumer.volume/10) + + 0.2 :1 }} onClick={(e) => { e.stopPropagation(); @@ -140,7 +142,7 @@ const mapDispatchToProps = (dispatch) => }, onEnableWebcam : (peerName) => { - + dispatch(requestActions.resumePeerVideo(peerName)); }, onDisableWebcam : (peerName) => diff --git a/app/lib/components/Peers.jsx b/app/lib/components/Peers.jsx index 14a11b0..67036f5 100644 --- a/app/lib/components/Peers.jsx +++ b/app/lib/components/Peers.jsx @@ -62,12 +62,12 @@ class Peers extends React.Component observer.observe(this.refs.peers); } - componentWillUnmount() + componentWillUnmount() { window.removeEventListener('resize', this.updateDimensions); } - componentDidUpdate() + componentDidUpdate() { this.updateDimensions(); } @@ -81,7 +81,7 @@ class Peers extends React.Component toolAreaOpen } = this.props; - const style = + const style = { 'width' : this.state.peerWidth, 'height' : this.state.peerHeight diff --git a/app/package-lock.json b/app/package-lock.json index cf150d1..5c87dfe 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -4771,7 +4771,8 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", @@ -4782,7 +4783,8 @@ "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4899,7 +4901,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4911,6 +4914,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4940,6 +4944,7 @@ "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -4958,6 +4963,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5058,6 +5064,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5179,6 +5186,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5602,7 +5610,6 @@ "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5745,8 +5752,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5772,7 +5778,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } From f17f6b54c1d33f004215bd48119a191cf9ecce67 Mon Sep 17 00:00:00 2001 From: Stefan Otto Date: Wed, 18 Jul 2018 11:20:32 +0200 Subject: [PATCH 4/5] Just to make toolarea a little bit less ugly --- app/stylus/components/Chat.styl | 19 ++++++++----------- app/stylus/components/ParticipantList.styl | 3 +-- app/stylus/components/Room.styl | 2 +- app/stylus/components/ToolArea.styl | 8 +++++--- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/app/stylus/components/Chat.styl b/app/stylus/components/Chat.styl index 6cfe785..e7adc4e 100644 --- a/app/stylus/components/Chat.styl +++ b/app/stylus/components/Chat.styl @@ -61,7 +61,7 @@ } [data-component='MessageList'] { - background-color: rgba(#fff, 0.9); + background-color: rgba(#000, 0.1); height: 91vmin; overflow-y: scroll; padding-top: 5px; @@ -71,10 +71,9 @@ margin: 5px; display: flex; word-wrap: break-word; - color: rgba(#000, 1.0) > .client { - background-color: rgba(#fff, 0.9); + background-color: rgba(#000, 0.1); border-radius: 5px; padding: 6px; max-width: 215px; @@ -83,17 +82,16 @@ > .message-text { font-size: 1.3vmin; - color: rgba(#000, 1.0); } > .message-time { font-size: 1vmin; - color: rgba(#777, 1.0) + opacity:0.8; } } > .response { - background-color: rgba(#fff, 0.9); + background-color: rgba(#000, 0.1); border-radius: 5px; padding: 6px; max-width: 215px; @@ -102,12 +100,11 @@ > .message-text { font-size: 1.3vmin; - color: rgba(#000, 1.0); } > .message-time { font-size: 1vmin; - color: rgba(#777, 1.0); + opacity: 0.8; } } } @@ -116,7 +113,7 @@ [data-component='Sender'] { align-items: center; display: flex; - background-color: rgba(#fff, 0.9); + background-color: rgba(#000, 0.1); height: 6vmin; padding: 0.5vmin; border-radius: 0 0 5px 5px; @@ -125,8 +122,8 @@ width: 100%; border: 0; border-radius: 5px; - background-color: rgba(#fff, 0.9); - color: #000; + background-color: rgba(#000, 0.1); + color: #fff; height: 30px; padding-left: 10px; font-size: 1.4vmin; diff --git a/app/stylus/components/ParticipantList.styl b/app/stylus/components/ParticipantList.styl index 1f0bd98..9481fad 100644 --- a/app/stylus/components/ParticipantList.styl +++ b/app/stylus/components/ParticipantList.styl @@ -125,8 +125,7 @@ float: left; width: auto; border: none; - display: block; outline: 0; - padding: 0.6vmin; + padding: 1vmin; } } diff --git a/app/stylus/components/Room.styl b/app/stylus/components/Room.styl index 16a5f5d..932406c 100644 --- a/app/stylus/components/Room.styl +++ b/app/stylus/components/Room.styl @@ -271,7 +271,7 @@ right: 0; width: 20%; height: 100%; - background-color: #FFF; + background-color: rgba(0,0,0,0.1); transition: width 0.3s; } } diff --git a/app/stylus/components/ToolArea.styl b/app/stylus/components/ToolArea.styl index b6f3a7f..e424e8b 100644 --- a/app/stylus/components/ToolArea.styl +++ b/app/stylus/components/ToolArea.styl @@ -73,6 +73,7 @@ [data-component='ToolArea'] { width: 100%; height: 100%; + color: #fff; > .tabs { display: flex; @@ -84,7 +85,7 @@ display: block; padding: 1vmin 0 0.8vmin 0; cursor: pointer; - background: rgba(#000, 0.3); + background: rgba(0,0,0,0.3); font-weight: bold; transition: background ease 0.2s; text-align: center; @@ -111,7 +112,7 @@ height: 100%; display: none; padding: 1vmin; - background: #fff; + background: rgba(0,0,0,0.1); } > input[type="radio"] { @@ -119,11 +120,12 @@ } > input[type="radio"]:checked + label { - background: #fff; + background: rgba(0,0,0,0.1); } > input[type="radio"]:checked + label + .tab { display: block; + background: rgba(0,0,0,0.1); } } } From 2a8d19ad56d19e4da095c3dd554ea2b746d847fa Mon Sep 17 00:00:00 2001 From: Stefan Otto Date: Wed, 18 Jul 2018 11:34:30 +0200 Subject: [PATCH 5/5] fix: unread badge is number not bool --- app/lib/components/ToolArea/ToolAreaButton.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/components/ToolArea/ToolAreaButton.jsx b/app/lib/components/ToolArea/ToolAreaButton.jsx index 14e7d92..ea9fa09 100644 --- a/app/lib/components/ToolArea/ToolAreaButton.jsx +++ b/app/lib/components/ToolArea/ToolAreaButton.jsx @@ -41,7 +41,7 @@ ToolAreaButton.propTypes = { toolAreaOpen : PropTypes.bool.isRequired, toggleToolArea : PropTypes.func.isRequired, - unread : PropTypes.bool.isRequired, + unread : PropTypes.number.isRequired, visible : PropTypes.bool.isRequired };