Fixes to performance. Moved volume out to new component to optimize rerenders.

master
Håvar Aambø Fosstveit 2019-04-04 00:03:57 +02:00
parent e84af94544
commit abca6645a9
16 changed files with 359 additions and 200 deletions

View File

@ -7,6 +7,7 @@ import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import * as appPropTypes from '../appPropTypes'; import * as appPropTypes from '../appPropTypes';
import VideoView from '../VideoContainers/VideoView'; import VideoView from '../VideoContainers/VideoView';
import Volume from './Volume';
const styles = () => const styles = () =>
({ ({
@ -55,7 +56,6 @@ const Me = (props) =>
micProducer, micProducer,
webcamProducer, webcamProducer,
screenProducer, screenProducer,
volume,
classes classes
} = props; } = props;
@ -87,8 +87,6 @@ const Me = (props) =>
advancedMode={advancedMode} advancedMode={advancedMode}
peer={me} peer={me}
showPeerInfo showPeerInfo
audioTrack={micProducer ? micProducer.track : null}
volume={volume}
videoTrack={webcamProducer ? webcamProducer.track : null} videoTrack={webcamProducer ? webcamProducer.track : null}
videoVisible={videoVisible} videoVisible={videoVisible}
audioCodec={micProducer ? micProducer.codec : null} audioCodec={micProducer ? micProducer.codec : null}
@ -97,7 +95,9 @@ const Me = (props) =>
{ {
roomClient.changeDisplayName(displayName); roomClient.changeDisplayName(displayName);
}} }}
/> >
<Volume name={me.name} />
</VideoView>
</div> </div>
</div> </div>
{ screenProducer ? { screenProducer ?
@ -128,7 +128,6 @@ Me.propTypes =
micProducer : appPropTypes.Producer, micProducer : appPropTypes.Producer,
webcamProducer : appPropTypes.Producer, webcamProducer : appPropTypes.Producer,
screenProducer : appPropTypes.Producer, screenProducer : appPropTypes.Producer,
volume : PropTypes.number,
style : PropTypes.object, style : PropTypes.object,
classes : PropTypes.object.isRequired classes : PropTypes.object.isRequired
}; };
@ -138,12 +137,22 @@ const mapStateToProps = (state) =>
return { return {
me : state.me, me : state.me,
...meProducersSelector(state), ...meProducersSelector(state),
volume : state.peerVolumes[state.me.name],
activeSpeaker : state.me.name === state.room.activeSpeakerName activeSpeaker : state.me.name === state.room.activeSpeakerName
}; };
}; };
export default withRoomContext(connect( export default withRoomContext(connect(
mapStateToProps, mapStateToProps,
null null,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.me === next.me &&
prev.producers === next.producers &&
prev.room.activeSpeakerName === next.room.activeSpeakerName
);
}
}
)(withStyles(styles)(Me))); )(withStyles(styles)(Me)));

View File

@ -14,6 +14,7 @@ import MicIcon from '@material-ui/icons/Mic';
import MicOffIcon from '@material-ui/icons/MicOff'; import MicOffIcon from '@material-ui/icons/MicOff';
import NewWindowIcon from '@material-ui/icons/OpenInNew'; import NewWindowIcon from '@material-ui/icons/OpenInNew';
import FullScreenIcon from '@material-ui/icons/Fullscreen'; import FullScreenIcon from '@material-ui/icons/Fullscreen';
import Volume from './Volume';
const styles = (theme) => const styles = (theme) =>
({ ({
@ -125,7 +126,6 @@ const Peer = (props) =>
micConsumer, micConsumer,
webcamConsumer, webcamConsumer,
screenConsumer, screenConsumer,
volume,
toggleConsumerFullscreen, toggleConsumerFullscreen,
toggleConsumerWindow, toggleConsumerWindow,
style, style,
@ -134,9 +134,6 @@ const Peer = (props) =>
theme theme
} = props; } = props;
if (!peer)
return;
const micEnabled = ( const micEnabled = (
Boolean(micConsumer) && Boolean(micConsumer) &&
!micConsumer.locallyPaused && !micConsumer.locallyPaused &&
@ -289,13 +286,14 @@ const Peer = (props) =>
advancedMode={advancedMode} advancedMode={advancedMode}
peer={peer} peer={peer}
showPeerInfo showPeerInfo
volume={volume}
videoTrack={webcamConsumer ? webcamConsumer.track : null} videoTrack={webcamConsumer ? webcamConsumer.track : null}
videoVisible={videoVisible} videoVisible={videoVisible}
videoProfile={videoProfile} videoProfile={videoProfile}
audioCodec={micConsumer ? micConsumer.codec : null} audioCodec={micConsumer ? micConsumer.codec : null}
videoCodec={webcamConsumer ? webcamConsumer.codec : null} videoCodec={webcamConsumer ? webcamConsumer.codec : null}
/> >
<Volume name={peer.name} />
</VideoView>
</div> </div>
:null :null
} }
@ -419,7 +417,6 @@ Peer.propTypes =
micConsumer : appPropTypes.Consumer, micConsumer : appPropTypes.Consumer,
webcamConsumer : appPropTypes.Consumer, webcamConsumer : appPropTypes.Consumer,
screenConsumer : appPropTypes.Consumer, screenConsumer : appPropTypes.Consumer,
volume : PropTypes.number,
windowConsumer : PropTypes.number, windowConsumer : PropTypes.number,
activeSpeaker : PropTypes.bool, activeSpeaker : PropTypes.bool,
style : PropTypes.object, style : PropTypes.object,
@ -438,7 +435,6 @@ const makeMapStateToProps = (initialState, props) =>
return { return {
peer : state.peers[props.name], peer : state.peers[props.name],
...getPeerConsumers(state, props), ...getPeerConsumers(state, props),
volume : state.peerVolumes[props.name],
windowConsumer : state.room.windowConsumer, windowConsumer : state.room.windowConsumer,
activeSpeaker : props.name === state.room.activeSpeakerName activeSpeaker : props.name === state.room.activeSpeakerName
}; };
@ -465,5 +461,17 @@ const mapDispatchToProps = (dispatch) =>
export default withRoomContext(connect( export default withRoomContext(connect(
makeMapStateToProps, makeMapStateToProps,
mapDispatchToProps mapDispatchToProps,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.peers === next.peers &&
prev.consumers === next.consumers &&
prev.room.activeSpeakerName === next.room.activeSpeakerName &&
prev.room.windowConsumer === next.room.windowConsumer
);
}
}
)(withStyles(styles, { withTheme: true })(Peer))); )(withStyles(styles, { withTheme: true })(Peer)));

View File

@ -0,0 +1,162 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { withStyles } from '@material-ui/core/styles';
const styles = () =>
({
volumeLarge :
{
position : 'absolute',
top : 0,
bottom : 0,
right : 2,
width : 10,
display : 'flex',
flexDirection : 'column',
justifyContent : 'center',
alignItems : 'center'
},
largeBar :
{
width : 6,
borderRadius : 6,
background : 'rgba(yellow, 0.65)',
transitionProperty : 'height background-color',
transitionDuration : '0.25s',
'&.level0' :
{
height : 0,
backgroundColor : 'rgba(255, 255, 0, 0.65)'
},
'&.level1' :
{
height : '10%',
backgroundColor : 'rgba(255, 255, 0, 0.65)'
},
'&.level2' :
{
height : '20%',
backgroundColor : 'rgba(255, 255, 0, 0.65)'
},
'&.level3' :
{
height : '30%',
backgroundColor : 'rgba(255, 255, 0, 0.65)'
},
'&.level4' :
{
height : '40%',
backgroundColor : 'rgba(255, 165, 0, 0.65)'
},
'&.level5' :
{
height : '50%',
backgroundColor : 'rgba(255, 165, 0, 0.65)'
},
'&.level6' :
{
height : '60%',
backgroundColor : 'rgba(255, 0, 0, 0.65)'
},
'&.level7' :
{
height : '70%',
backgroundColor : 'rgba(255, 0, 0, 0.65)'
},
'&.level8' :
{
height : '80%',
backgroundColor : 'rgba(0, 0, 0, 0.65)'
},
'&.level9' :
{
height : '90%',
backgroundColor : 'rgba(0, 0, 0, 0.65)'
},
'&.level10' :
{
height : '100%',
backgroundColor : 'rgba(0, 0, 0, 0.65)'
}
},
volumeSmall :
{
float : 'right',
display : 'flex',
flexDirection : 'row',
justifyContent : 'flex-start',
width : '1vmin',
position : 'relative',
backgroundSize : '75%'
},
smallBar :
{
flex : '0 0 auto',
margin : '0.3rem',
backgroundSize : '75%',
backgroundRepeat : 'no-repeat',
backgroundColor : 'rgba(0, 0, 0, 1)',
cursor : 'pointer',
transitionProperty : 'opacity, background-color',
width : 3,
borderRadius : 6,
transitionDuration : '0.25s',
position : 'absolute',
bottom : 0,
'&.level0' : { height: 0 },
'&.level1' : { height: '0.2vh' },
'&.level2' : { height: '0.4vh' },
'&.level3' : { height: '0.6vh' },
'&.level4' : { height: '0.8vh' },
'&.level5' : { height: '1.0vh' },
'&.level6' : { height: '1.2vh' },
'&.level7' : { height: '1.4vh' },
'&.level8' : { height: '1.6vh' },
'&.level9' : { height: '1.8vh' },
'&.level10' : { height: '2.0vh' }
}
});
const Volume = (props) =>
{
const {
small,
volume,
classes
} = props;
return (
<div className={small ? classes.volumeSmall : classes.volumeLarge}>
<div
className={classnames(
small ? classes.smallBar : classes.largeBar, `level${volume}`
)}
/>
</div>
);
};
Volume.propTypes =
{
small : PropTypes.bool,
volume : PropTypes.number,
classes : PropTypes.object.isRequired
};
const makeMapStateToProps = (initialState, props) =>
{
const mapStateToProps = (state) =>
{
return {
volume : state.peerVolumes[props.name]
};
};
return mapStateToProps;
};
export default connect(
makeMapStateToProps
)(withStyles(styles)(Volume));

View File

@ -127,5 +127,18 @@ const mapStateToProps = (state) =>
}); });
export default withRoomContext( export default withRoomContext(
connect(mapStateToProps)(withStyles(styles)(ChatInput)) connect(
mapStateToProps,
null,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.me.displayName === next.me.displayName &&
prev.me.picture === next.me.picture
);
}
}
)(withStyles(styles)(ChatInput))
); );

View File

@ -119,5 +119,16 @@ const mapDispatchToProps = {
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.toolarea.currentToolTab === next.toolarea.currentToolTab &&
prev.toolarea.unreadMessages === next.toolarea.unreadMessages &&
prev.toolarea.unreadFiles === next.toolarea.unreadFiles
);
}
}
)(withStyles(styles, { withTheme: true })(MeetingDrawer)); )(withStyles(styles, { withTheme: true })(MeetingDrawer));

View File

@ -111,5 +111,15 @@ const mapStateToProps = (state) => ({
}); });
export default connect( export default connect(
mapStateToProps mapStateToProps,
null,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.me === next.me
);
}
}
)(withStyles(styles)(ListMe)); )(withStyles(styles)(ListMe));

View File

@ -82,42 +82,6 @@ const styles = () =>
backgroundImage : `url(${HandIcon})` backgroundImage : `url(${HandIcon})`
} }
}, },
volumeContainer :
{
float : 'right',
display : 'flex',
flexDirection : 'row',
justifyContent : 'flex-start',
width : '1vmin',
position : 'relative',
backgroundSize : '75%'
},
bar :
{
flex : '0 0 auto',
margin : '0.3rem',
backgroundSize : '75%',
backgroundRepeat : 'no-repeat',
backgroundColor : 'rgba(0, 0, 0, 1)',
cursor : 'pointer',
transitionProperty : 'opacity, background-color',
width : 3,
borderRadius : 6,
transitionDuration : '0.25s',
position : 'absolute',
bottom : 0,
'&.level0' : { height: 0 },
'&.level1' : { height: '0.2vh' },
'&.level2' : { height: '0.4vh' },
'&.level3' : { height: '0.6vh' },
'&.level4' : { height: '0.8vh' },
'&.level5' : { height: '1.0vh' },
'&.level6' : { height: '1.2vh' },
'&.level7' : { height: '1.4vh' },
'&.level8' : { height: '1.6vh' },
'&.level9' : { height: '1.8vh' },
'&.level10' : { height: '2.0vh' }
},
controls : controls :
{ {
float : 'right', float : 'right',
@ -169,13 +133,10 @@ const ListPeer = (props) =>
peer, peer,
micConsumer, micConsumer,
screenConsumer, screenConsumer,
volume, children,
classes classes
} = props; } = props;
if (!peer)
return;
const micEnabled = ( const micEnabled = (
Boolean(micConsumer) && Boolean(micConsumer) &&
!micConsumer.locallyPaused && !micConsumer.locallyPaused &&
@ -211,9 +172,7 @@ const ListPeer = (props) =>
:null :null
} }
</div> </div>
<div className={classes.volumeContainer}> {children}
<div className={classnames(classes.bar, `level${volume}`)} />
</div>
<div className={classes.controls}> <div className={classes.controls}>
{ screenConsumer ? { screenConsumer ?
<div <div
@ -271,7 +230,7 @@ ListPeer.propTypes =
micConsumer : appPropTypes.Consumer, micConsumer : appPropTypes.Consumer,
webcamConsumer : appPropTypes.Consumer, webcamConsumer : appPropTypes.Consumer,
screenConsumer : appPropTypes.Consumer, screenConsumer : appPropTypes.Consumer,
volume : PropTypes.number, children : PropTypes.object,
classes : PropTypes.object.isRequired classes : PropTypes.object.isRequired
}; };
@ -282,9 +241,8 @@ const makeMapStateToProps = (initialState, props) =>
const mapStateToProps = (state) => const mapStateToProps = (state) =>
{ {
return { return {
peer : state.peers[props.name], peer : state.peers[props.name],
...getPeerConsumers(state, props), ...getPeerConsumers(state, props)
volume : state.peerVolumes[props.name]
}; };
}; };
@ -292,5 +250,16 @@ const makeMapStateToProps = (initialState, props) =>
}; };
export default withRoomContext(connect( export default withRoomContext(connect(
makeMapStateToProps makeMapStateToProps,
null,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.peers === next.peers &&
prev.consumers === next.consumers
);
}
}
)(withStyles(styles)(ListPeer))); )(withStyles(styles)(ListPeer)));

View File

@ -1,7 +1,8 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
passivePeersSelector passivePeersSelector,
spotlightPeersSelector
} from '../../Selectors'; } from '../../Selectors';
import classNames from 'classnames'; import classNames from 'classnames';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
@ -9,6 +10,7 @@ import { withRoomContext } from '../../../RoomContext';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ListPeer from './ListPeer'; import ListPeer from './ListPeer';
import ListMe from './ListMe'; import ListMe from './ListMe';
import Volume from '../../Containers/Volume';
const styles = (theme) => const styles = (theme) =>
({ ({
@ -75,7 +77,7 @@ class ParticipantList extends React.PureComponent
advancedMode, advancedMode,
passivePeers, passivePeers,
selectedPeerName, selectedPeerName,
spotlights, spotlightPeers,
classes classes
} = this.props; } = this.props;
@ -88,15 +90,17 @@ class ParticipantList extends React.PureComponent
<br /> <br />
<ul className={classes.list}> <ul className={classes.list}>
<li className={classes.listheader}>Participants in Spotlight:</li> <li className={classes.listheader}>Participants in Spotlight:</li>
{ spotlights.map((peerName) => ( { spotlightPeers.map((peer) => (
<li <li
key={peerName} key={peer.name}
className={classNames(classes.listItem, { className={classNames(classes.listItem, {
selected : peerName === selectedPeerName selected : peer.name === selectedPeerName
})} })}
onClick={() => roomClient.setSelectedPeer(peerName)} onClick={() => roomClient.setSelectedPeer(peer.name)}
> >
<ListPeer name={peerName} advancedMode={advancedMode} /> <ListPeer name={peer.name} advancedMode={advancedMode}>
<Volume small name={peer.name} />
</ListPeer>
</li> </li>
))} ))}
</ul> </ul>
@ -126,16 +130,18 @@ ParticipantList.propTypes =
advancedMode : PropTypes.bool, advancedMode : PropTypes.bool,
passivePeers : PropTypes.array, passivePeers : PropTypes.array,
selectedPeerName : PropTypes.string, selectedPeerName : PropTypes.string,
spotlights : PropTypes.array.isRequired, spotlightPeers : PropTypes.array,
classes : PropTypes.object.isRequired classes : PropTypes.object.isRequired
}; };
const mapStateToProps = (state) => const mapStateToProps = (state) =>
({ {
return {
passivePeers : passivePeersSelector(state), passivePeers : passivePeersSelector(state),
selectedPeerName : state.room.selectedPeerName, selectedPeerName : state.room.selectedPeerName,
spotlights : state.room.spotlights spotlightPeers : spotlightPeersSelector(state)
}); };
};
const ParticipantListContainer = withRoomContext(connect( const ParticipantListContainer = withRoomContext(connect(
mapStateToProps, mapStateToProps,

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
spotlightPeersSelector,
peersLengthSelector, peersLengthSelector,
videoBoxesSelector, videoBoxesSelector,
spotlightsLengthSelector spotlightsLengthSelector
@ -117,7 +118,7 @@ class Democratic extends React.PureComponent
const { const {
advancedMode, advancedMode,
peersLength, peersLength,
spotlights, spotlightsPeers,
spotlightsLength, spotlightsLength,
classes classes
} = this.props; } = this.props;
@ -134,13 +135,13 @@ class Democratic extends React.PureComponent
advancedMode={advancedMode} advancedMode={advancedMode}
style={style} style={style}
/> />
{ spotlights.map((peerName) => { spotlightsPeers.map((peer) =>
{ {
return ( return (
<Peer <Peer
key={peerName} key={peer.name}
advancedMode={advancedMode} advancedMode={advancedMode}
name={peerName} name={peer.name}
style={style} style={style}
/> />
); );
@ -162,7 +163,7 @@ Democratic.propTypes =
peersLength : PropTypes.number, peersLength : PropTypes.number,
boxes : PropTypes.number, boxes : PropTypes.number,
spotlightsLength : PropTypes.number, spotlightsLength : PropTypes.number,
spotlights : PropTypes.array.isRequired, spotlightsPeers : PropTypes.array.isRequired,
classes : PropTypes.object.isRequired classes : PropTypes.object.isRequired
}; };
@ -171,7 +172,7 @@ const mapStateToProps = (state) =>
return { return {
peersLength : peersLengthSelector(state), peersLength : peersLengthSelector(state),
boxes : videoBoxesSelector(state), boxes : videoBoxesSelector(state),
spotlights : state.room.spotlights, spotlightsPeers : spotlightPeersSelector(state),
spotlightsLength : spotlightsLengthSelector(state) spotlightsLength : spotlightsLengthSelector(state)
}; };
}; };
@ -184,6 +185,7 @@ export default connect(
areStatesEqual : (next, prev) => areStatesEqual : (next, prev) =>
{ {
return ( return (
prev.peers === next.peers &&
prev.producers === next.producers && prev.producers === next.producers &&
prev.consumers === next.consumers && prev.consumers === next.consumers &&
prev.spotlights === next.spotlights prev.spotlights === next.spotlights

View File

@ -81,5 +81,17 @@ const mapDispatchToProps = (dispatch) =>
}); });
export default withSnackbar( export default withSnackbar(
connect(mapStateToProps, mapDispatchToProps)(Notifications) connect(
mapStateToProps,
mapDispatchToProps,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.notifications === next.notifications
);
}
}
)(Notifications)
); );

View File

@ -38,7 +38,17 @@ const mapStateToProps = (state) =>
}); });
const AudioPeersContainer = connect( const AudioPeersContainer = connect(
mapStateToProps mapStateToProps,
null,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.consumers === next.consumers
);
}
}
)(AudioPeers); )(AudioPeers);
export default AudioPeersContainer; export default AudioPeersContainer;

View File

@ -2,10 +2,15 @@ import { createSelector } from 'reselect';
const producersSelect = (state) => state.producers; const producersSelect = (state) => state.producers;
const consumersSelect = (state) => state.consumers; const consumersSelect = (state) => state.consumers;
const spotlightsSelector = (state) => state.room.spotlights;
export const spotlightsSelector = (state) => state.room.spotlights;
const peersSelector = (state) => state.peers; const peersSelector = (state) => state.peers;
const getPeerConsumers = (state, props) =>
(state.peers[props.name] ? state.peers[props.name].consumers : null);
const getAllConsumers = (state) => state.consumers;
const peersKeySelector = createSelector(
peersSelector,
(peers) => Object.keys(peers)
);
export const micProducersSelector = createSelector( export const micProducersSelector = createSelector(
producersSelect, producersSelect,
@ -54,13 +59,20 @@ export const screenConsumerSelector = createSelector(
export const spotlightsLengthSelector = createSelector( export const spotlightsLengthSelector = createSelector(
spotlightsSelector, spotlightsSelector,
(spotlights) => (spotlights ? spotlights.length : 0) (spotlights) => spotlights.length
); );
export const spotlightPeersSelector = createSelector( export const spotlightPeersSelector = createSelector(
spotlightsSelector, spotlightsSelector,
peersSelector, peersSelector,
(spotlights, peers) => spotlights.map((peerName) => peers[peerName]) (spotlights, peers) =>
spotlights.reduce((result, peerName) =>
{
if (peers[peerName])
result.push(peers[peerName]);
return result;
}, [])
); );
export const peersLengthSelector = createSelector( export const peersLengthSelector = createSelector(
@ -68,11 +80,6 @@ export const peersLengthSelector = createSelector(
(peers) => Object.values(peers).length (peers) => Object.values(peers).length
); );
const peersKeySelector = createSelector(
peersSelector,
(peers) => Object.keys(peers)
);
export const passivePeersSelector = createSelector( export const passivePeersSelector = createSelector(
peersKeySelector, peersKeySelector,
spotlightsSelector, spotlightsSelector,
@ -101,10 +108,6 @@ export const meProducersSelector = createSelector(
} }
); );
const getPeerConsumers = (state, props) =>
(state.peers[props.name] ? state.peers[props.name].consumers : null);
const getAllConsumers = (state) => state.consumers;
export const makePeerConsumerSelector = () => export const makePeerConsumerSelector = () =>
{ {
return createSelector( return createSelector(

View File

@ -215,5 +215,15 @@ const mapDispatchToProps = {
export default withRoomContext(connect( export default withRoomContext(connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.me === next.me &&
prev.room === next.room
);
}
}
)(withStyles(styles)(Settings))); )(withStyles(styles)(Settings)));

View File

@ -161,5 +161,16 @@ const mapDispatchToProps = (dispatch) =>
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.consumers[prev.room.fullScreenConsumer] ===
next.consumers[next.room.fullScreenConsumer] &&
prev.room.toolbarsVisible === next.room.toolbarsVisible
);
}
}
)(withStyles(styles)(FullScreenView)); )(withStyles(styles)(FullScreenView));

View File

@ -132,81 +132,6 @@ const styles = () =>
fontSize : 11, fontSize : 11,
color : 'rgba(255, 255, 255, 0.55)' color : 'rgba(255, 255, 255, 0.55)'
} }
},
volume :
{
position : 'absolute',
top : 0,
bottom : 0,
right : 2,
width : 10,
display : 'flex',
flexDirection : 'column',
justifyContent : 'center',
alignItems : 'center'
},
volumeBar :
{
width : 6,
borderRadius : 6,
background : 'rgba(yellow, 0.65)',
transitionProperty : 'height background-color',
transitionDuration : '0.25s',
'&.level0' :
{
height : 0,
backgroundColor : 'rgba(255, 255, 0, 0.65)'
},
'&.level1' :
{
height : '10%',
backgroundColor : 'rgba(255, 255, 0, 0.65)'
},
'&.level2' :
{
height : '20%',
backgroundColor : 'rgba(255, 255, 0, 0.65)'
},
'&.level3' :
{
height : '30%',
backgroundColor : 'rgba(255, 255, 0, 0.65)'
},
'&.level4' :
{
height : '40%',
backgroundColor : 'rgba(255, 165, 0, 0.65)'
},
'&.level5' :
{
height : '50%',
backgroundColor : 'rgba(255, 165, 0, 0.65)'
},
'&.level6' :
{
height : '60%',
backgroundColor : 'rgba(255, 0, 0, 0.65)'
},
'&.level7' :
{
height : '70%',
backgroundColor : 'rgba(255, 0, 0, 0.65)'
},
'&.level8' :
{
height : '80%',
backgroundColor : 'rgba(0, 0, 0, 0.65)'
},
'&.level9' :
{
height : '90%',
backgroundColor : 'rgba(0, 0, 0, 0.65)'
},
'&.level10' :
{
height : '100%',
backgroundColor : 'rgba(0, 0, 0, 0.65)'
}
} }
}); });
@ -218,15 +143,10 @@ class VideoView extends React.PureComponent
this.state = this.state =
{ {
volume : 0, // Integer from 0 to 10.,
videoWidth : null, videoWidth : null,
videoHeight : null videoHeight : null
}; };
// Latest received video track.
// @type {MediaStreamTrack}
this._audioTrack = null;
// Latest received video track. // Latest received video track.
// @type {MediaStreamTrack} // @type {MediaStreamTrack}
this._videoTrack = null; this._videoTrack = null;
@ -240,7 +160,6 @@ class VideoView extends React.PureComponent
const { const {
isMe, isMe,
peer, peer,
volume,
showPeerInfo, showPeerInfo,
videoContain, videoContain,
advancedMode, advancedMode,
@ -249,6 +168,7 @@ class VideoView extends React.PureComponent
audioCodec, audioCodec,
videoCodec, videoCodec,
onChangeDisplayName, onChangeDisplayName,
children,
classes classes
} = this.props; } = this.props;
@ -331,18 +251,16 @@ class VideoView extends React.PureComponent
muted={isMe} muted={isMe}
/> />
<div className={classes.volume}> {children}
<div className={classnames(classes.volumeBar, `level${volume}`)} />
</div>
</div> </div>
); );
} }
componentDidMount() componentDidMount()
{ {
const { audioTrack, videoTrack } = this.props; const { videoTrack } = this.props;
this._setTracks(audioTrack, videoTrack); this._setTracks(videoTrack);
} }
componentWillUnmount() componentWillUnmount()
@ -352,18 +270,17 @@ class VideoView extends React.PureComponent
componentWillReceiveProps(nextProps) componentWillReceiveProps(nextProps)
{ {
const { audioTrack, videoTrack } = nextProps; const { videoTrack } = nextProps;
this._setTracks(audioTrack, videoTrack); this._setTracks(videoTrack);
} }
_setTracks(audioTrack, videoTrack) _setTracks(videoTrack)
{ {
if (this._audioTrack === audioTrack && this._videoTrack === videoTrack) if (this._videoTrack === videoTrack)
return; return;
this._audioTrack = audioTrack;
this._videoTrack = videoTrack; this._videoTrack = videoTrack;
clearInterval(this._videoResolutionTimer); clearInterval(this._videoResolutionTimer);
@ -371,13 +288,10 @@ class VideoView extends React.PureComponent
const { video } = this.refs; const { video } = this.refs;
if (audioTrack || videoTrack) if (videoTrack)
{ {
const stream = new MediaStream(); const stream = new MediaStream();
if (audioTrack)
stream.addTrack(audioTrack);
if (videoTrack) if (videoTrack)
stream.addTrack(videoTrack); stream.addTrack(videoTrack);
@ -425,14 +339,13 @@ VideoView.propTypes =
showPeerInfo : PropTypes.bool, showPeerInfo : PropTypes.bool,
videoContain : PropTypes.bool, videoContain : PropTypes.bool,
advancedMode : PropTypes.bool, advancedMode : PropTypes.bool,
audioTrack : PropTypes.any,
volume : PropTypes.number,
videoTrack : PropTypes.any, videoTrack : PropTypes.any,
videoVisible : PropTypes.bool.isRequired, videoVisible : PropTypes.bool.isRequired,
videoProfile : PropTypes.string, videoProfile : PropTypes.string,
audioCodec : PropTypes.string, audioCodec : PropTypes.string,
videoCodec : PropTypes.string, videoCodec : PropTypes.string,
onChangeDisplayName : PropTypes.func, onChangeDisplayName : PropTypes.func,
children : PropTypes.object,
classes : PropTypes.object.isRequired classes : PropTypes.object.isRequired
}; };

View File

@ -66,7 +66,17 @@ const mapDispatchToProps = (dispatch) =>
const VideoWindowContainer = connect( const VideoWindowContainer = connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.consumers[prev.room.windowConsumer] ===
next.consumers[next.room.windowConsumer]
);
}
}
)(VideoWindow); )(VideoWindow);
export default VideoWindowContainer; export default VideoWindowContainer;