Lots of performance fixes

master
Håvar Aambø Fosstveit 2019-04-03 16:20:17 +02:00
parent 168affbc57
commit e84af94544
16 changed files with 219 additions and 117 deletions

View File

@ -799,7 +799,7 @@ export default class RoomClient
if (volume !== this._micProducer.volume)
{
this._micProducer.volume = volume;
store.dispatch(stateActions.setProducerVolume(this._micProducer.id, volume));
store.dispatch(stateActions.setPeerVolume(this._peerName, volume));
}
});
@ -1504,7 +1504,7 @@ export default class RoomClient
if (volume !== producer.volume)
{
producer.volume = volume;
store.dispatch(stateActions.setProducerVolume(producer.id, volume));
store.dispatch(stateActions.setPeerVolume(this._peerName, volume));
}
});
@ -1937,7 +1937,7 @@ export default class RoomClient
if (volume !== consumer.volume)
{
consumer.volume = volume;
store.dispatch(stateActions.setConsumerVolume(consumer.id, volume));
store.dispatch(stateActions.setPeerVolume(consumer.peer.name, volume));
}
});
}

View File

@ -378,19 +378,11 @@ export const setConsumerTrack = (consumerId, track) =>
};
};
export const setConsumerVolume = (consumerId, volume) =>
export const setPeerVolume = (peerName, volume) =>
{
return {
type : 'SET_CONSUMER_VOLUME',
payload : { consumerId, volume }
};
};
export const setProducerVolume = (producerId, volume) =>
{
return {
type : 'SET_PRODUCER_VOLUME',
payload : { producerId, volume }
type : 'SET_PEER_VOLUME',
payload : { peerName, volume }
};
};

View File

@ -55,6 +55,7 @@ const Me = (props) =>
micProducer,
webcamProducer,
screenProducer,
volume,
classes
} = props;
@ -87,7 +88,7 @@ const Me = (props) =>
peer={me}
showPeerInfo
audioTrack={micProducer ? micProducer.track : null}
volume={micProducer ? micProducer.volume : null}
volume={volume}
videoTrack={webcamProducer ? webcamProducer.track : null}
videoVisible={videoVisible}
audioCodec={micProducer ? micProducer.codec : null}
@ -121,13 +122,13 @@ const Me = (props) =>
Me.propTypes =
{
roomClient : PropTypes.any.isRequired,
connected : PropTypes.bool.isRequired,
advancedMode : PropTypes.bool,
me : appPropTypes.Me.isRequired,
activeSpeaker : PropTypes.bool,
micProducer : appPropTypes.Producer,
webcamProducer : appPropTypes.Producer,
screenProducer : appPropTypes.Producer,
volume : PropTypes.number,
style : PropTypes.object,
classes : PropTypes.object.isRequired
};
@ -135,9 +136,9 @@ Me.propTypes =
const mapStateToProps = (state) =>
{
return {
connected : state.room.state === 'connected',
me : state.me,
...meProducersSelector(state),
volume : state.peerVolumes[state.me.name],
activeSpeaker : state.me.name === state.room.activeSpeakerName
};
};

View File

@ -125,6 +125,7 @@ const Peer = (props) =>
micConsumer,
webcamConsumer,
screenConsumer,
volume,
toggleConsumerFullscreen,
toggleConsumerWindow,
style,
@ -133,6 +134,9 @@ const Peer = (props) =>
theme
} = props;
if (!peer)
return;
const micEnabled = (
Boolean(micConsumer) &&
!micConsumer.locallyPaused &&
@ -285,7 +289,7 @@ const Peer = (props) =>
advancedMode={advancedMode}
peer={peer}
showPeerInfo
volume={micConsumer ? micConsumer.volume : null}
volume={volume}
videoTrack={webcamConsumer ? webcamConsumer.track : null}
videoVisible={videoVisible}
videoProfile={videoProfile}
@ -411,10 +415,11 @@ Peer.propTypes =
{
roomClient : PropTypes.any.isRequired,
advancedMode : PropTypes.bool,
peer : appPropTypes.Peer.isRequired,
peer : appPropTypes.Peer,
micConsumer : appPropTypes.Consumer,
webcamConsumer : appPropTypes.Consumer,
screenConsumer : appPropTypes.Consumer,
volume : PropTypes.number,
windowConsumer : PropTypes.number,
activeSpeaker : PropTypes.bool,
style : PropTypes.object,
@ -424,15 +429,16 @@ Peer.propTypes =
theme : PropTypes.object.isRequired
};
const makeMapStateToProps = () =>
const makeMapStateToProps = (initialState, props) =>
{
const getPeerConsumers = makePeerConsumerSelector();
const mapStateToProps = (state, props) =>
const mapStateToProps = (state) =>
{
return {
peer : state.peers[props.name],
...getPeerConsumers(state, props),
volume : state.peerVolumes[props.name],
windowConsumer : state.room.windowConsumer,
activeSpeaker : props.name === state.room.activeSpeakerName
};

View File

@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { meProducersSelector } from '../Selectors';
import { withStyles } from '@material-ui/core/styles';
import { unstable_useMediaQuery as useMediaQuery } from '@material-ui/core/useMediaQuery';
import classnames from 'classnames';
@ -8,7 +9,6 @@ import * as appPropTypes from '../appPropTypes';
import { withRoomContext } from '../../RoomContext';
import Fab from '@material-ui/core/Fab';
import Tooltip from '@material-ui/core/Tooltip';
// import Avatar from '@material-ui/core/Avatar';
import MicIcon from '@material-ui/icons/Mic';
import MicOffIcon from '@material-ui/icons/MicOff';
import VideoIcon from '@material-ui/icons/Videocam';
@ -18,8 +18,6 @@ import ScreenOffIcon from '@material-ui/icons/StopScreenShare';
import ExtensionIcon from '@material-ui/icons/Extension';
import LockIcon from '@material-ui/icons/Lock';
import LockOpenIcon from '@material-ui/icons/LockOpen';
// import HandOff from '../../images/icon-hand-black.svg';
// import HandOn from '../../images/icon-hand-white.svg';
import LeaveIcon from '@material-ui/icons/Cancel';
const styles = (theme) =>
@ -309,16 +307,24 @@ Sidebar.propTypes =
const mapStateToProps = (state) =>
({
toolbarsVisible : state.room.toolbarsVisible,
micProducer : Object.values(state.producers)
.find((producer) => producer.source === 'mic'),
webcamProducer : Object.values(state.producers)
.find((producer) => producer.source === 'webcam'),
screenProducer : Object.values(state.producers)
.find((producer) => producer.source === 'screen'),
me : state.me,
locked : state.room.locked
...meProducersSelector(state),
me : state.me,
locked : state.room.locked
});
export default withRoomContext(connect(
mapStateToProps
mapStateToProps,
null,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.room.toolbarsVisible === next.room.toolbarsVisible &&
prev.room.locked === next.room.locked &&
prev.producers === next.producers &&
prev.me === next.me
);
}
}
)(withStyles(styles, { withTheme: true })(Sidebar)));

View File

@ -100,4 +100,17 @@ const mapStateToProps = (state) =>
myPicture : state.me.picture
});
export default connect(mapStateToProps, null)(withStyles(styles)(MessageList));
export default connect(
mapStateToProps,
null,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.chatmessages === next.chatmessages &&
prev.me.picture === next.me.picture
);
}
}
)(withStyles(styles)(MessageList));

View File

@ -169,9 +169,13 @@ const ListPeer = (props) =>
peer,
micConsumer,
screenConsumer,
volume,
classes
} = props;
if (!peer)
return;
const micEnabled = (
Boolean(micConsumer) &&
!micConsumer.locallyPaused &&
@ -208,7 +212,7 @@ const ListPeer = (props) =>
}
</div>
<div className={classes.volumeContainer}>
<div className={classnames(classes.bar, `level${micEnabled && micConsumer ? micConsumer.volume:0}`)} />
<div className={classnames(classes.bar, `level${volume}`)} />
</div>
<div className={classes.controls}>
{ screenConsumer ?
@ -267,18 +271,20 @@ ListPeer.propTypes =
micConsumer : appPropTypes.Consumer,
webcamConsumer : appPropTypes.Consumer,
screenConsumer : appPropTypes.Consumer,
volume : PropTypes.number,
classes : PropTypes.object.isRequired
};
const makeMapStateToProps = () =>
const makeMapStateToProps = (initialState, props) =>
{
const getPeerConsumers = makePeerConsumerSelector();
const mapStateToProps = (state, props) =>
const mapStateToProps = (state) =>
{
return {
peer : state.peers[props.name],
...getPeerConsumers(state, props)
peer : state.peers[props.name],
...getPeerConsumers(state, props),
volume : state.peerVolumes[props.name]
};
};

View File

@ -1,8 +1,10 @@
import React from 'react';
import { connect } from 'react-redux';
import {
passivePeersSelector
} from '../../Selectors';
import classNames from 'classnames';
import { withStyles } from '@material-ui/core/styles';
import * as appPropTypes from '../../appPropTypes';
import { withRoomContext } from '../../../RoomContext';
import PropTypes from 'prop-types';
import ListPeer from './ListPeer';
@ -71,7 +73,7 @@ class ParticipantList extends React.PureComponent
const {
roomClient,
advancedMode,
peers,
passivePeers,
selectedPeerName,
spotlights,
classes
@ -86,38 +88,30 @@ class ParticipantList extends React.PureComponent
<br />
<ul className={classes.list}>
<li className={classes.listheader}>Participants in Spotlight:</li>
{peers.filter((peer) =>
{
return (spotlights.find((spotlight) =>
{ return (spotlight === peer.name); }));
}).map((peer) => (
{ spotlights.map((peerName) => (
<li
key={peer.name}
key={peerName}
className={classNames(classes.listItem, {
selected : peer.name === selectedPeerName
selected : peerName === selectedPeerName
})}
onClick={() => roomClient.setSelectedPeer(peer.name)}
onClick={() => roomClient.setSelectedPeer(peerName)}
>
<ListPeer name={peer.name} advancedMode={advancedMode} />
<ListPeer name={peerName} advancedMode={advancedMode} />
</li>
))}
</ul>
<br />
<ul className={classes.list}>
<li className={classes.listheader}>Passive Participants:</li>
{peers.filter((peer) =>
{
return !(spotlights.find((spotlight) =>
{ return (spotlight === peer.name); }));
}).map((peer) => (
{ passivePeers.map((peerName) => (
<li
key={peer.name}
key={peerName}
className={classNames(classes.listItem, {
selected : peer.name === selectedPeerName
selected : peerName === selectedPeerName
})}
onClick={() => roomClient.setSelectedPeer(peer.name)}
onClick={() => roomClient.setSelectedPeer(peerName)}
>
<ListPeer name={peer.name} advancedMode={advancedMode} />
<ListPeer name={peerName} advancedMode={advancedMode} />
</li>
))}
</ul>
@ -130,25 +124,33 @@ ParticipantList.propTypes =
{
roomClient : PropTypes.any.isRequired,
advancedMode : PropTypes.bool,
peers : PropTypes.arrayOf(appPropTypes.Peer).isRequired,
passivePeers : PropTypes.array,
selectedPeerName : PropTypes.string,
spotlights : PropTypes.array.isRequired,
classes : PropTypes.object.isRequired
};
const mapStateToProps = (state) =>
{
const peersArray = Object.values(state.peers);
return {
peers : peersArray,
({
passivePeers : passivePeersSelector(state),
selectedPeerName : state.room.selectedPeerName,
spotlights : state.room.spotlights
};
};
});
const ParticipantListContainer = withRoomContext(connect(
mapStateToProps
mapStateToProps,
null,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.peers === next.peers &&
prev.spotlights === next.spotlights &&
prev.room.selectedPeerName === next.room.selectedPeerName
);
}
}
)(withStyles(styles)(ParticipantList)));
export default ParticipantListContainer;

View File

@ -1,9 +1,8 @@
import React from 'react';
import { connect } from 'react-redux';
import {
peersSelector,
peersLengthSelector,
videoBoxesSelector,
spotlightsSelector,
spotlightsLengthSelector
} from '../Selectors';
import PropTypes from 'prop-types';
@ -117,7 +116,7 @@ class Democratic extends React.PureComponent
{
const {
advancedMode,
peers,
peersLength,
spotlights,
spotlightsLength,
classes
@ -135,27 +134,20 @@ class Democratic extends React.PureComponent
advancedMode={advancedMode}
style={style}
/>
{ Object.keys(peers).map((peerName) =>
{ spotlights.map((peerName) =>
{
if (spotlights.find((spotlightsElement) => spotlightsElement === peerName))
{
return (
<Peer
key={peerName}
advancedMode={advancedMode}
name={peerName}
style={style}
/>
);
}
else
{
return ('');
}
return (
<Peer
key={peerName}
advancedMode={advancedMode}
name={peerName}
style={style}
/>
);
})}
{ spotlightsLength < Object.keys(peers).length ?
{ spotlightsLength < peersLength ?
<HiddenPeers
hiddenPeersCount={Object.keys(peers).length - spotlightsLength}
hiddenPeersCount={peersLength - spotlightsLength}
/>
:null
}
@ -167,7 +159,7 @@ class Democratic extends React.PureComponent
Democratic.propTypes =
{
advancedMode : PropTypes.bool,
peers : PropTypes.object.isRequired,
peersLength : PropTypes.number,
boxes : PropTypes.number,
spotlightsLength : PropTypes.number,
spotlights : PropTypes.array.isRequired,
@ -177,13 +169,25 @@ Democratic.propTypes =
const mapStateToProps = (state) =>
{
return {
peers : peersSelector(state),
peersLength : peersLengthSelector(state),
boxes : videoBoxesSelector(state),
spotlights : spotlightsSelector(state),
spotlights : state.room.spotlights,
spotlightsLength : spotlightsLengthSelector(state)
};
};
export default connect(
mapStateToProps
mapStateToProps,
null,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.producers === next.producers &&
prev.consumers === next.consumers &&
prev.spotlights === next.spotlights
);
}
}
)(withStyles(styles)(Democratic));

View File

@ -433,5 +433,20 @@ const mapDispatchToProps = (dispatch) =>
export default withRoomContext(connect(
mapStateToProps,
mapDispatchToProps
mapDispatchToProps,
null,
{
areStatesEqual : (next, prev) =>
{
return (
prev.room === next.room &&
prev.me.loggedIn === next.me.loggedIn &&
prev.me.loginEnabled === next.me.loginEnabled &&
prev.me.picture === next.me.picture &&
prev.toolarea.toolAreaOpen === next.toolarea.toolAreaOpen &&
prev.toolarea.unreadMessages === next.toolarea.unreadMessages &&
prev.toolarea.unreadFiles === next.toolarea.unreadFiles
);
}
}
)(withStyles(styles, { withTheme: true })(Room)));

View File

@ -5,7 +5,7 @@ const consumersSelect = (state) => state.consumers;
export const spotlightsSelector = (state) => state.room.spotlights;
export const peersSelector = (state) => state.peers;
const peersSelector = (state) => state.peers;
export const micProducersSelector = createSelector(
producersSelect,
@ -57,6 +57,28 @@ export const spotlightsLengthSelector = createSelector(
(spotlights) => (spotlights ? spotlights.length : 0)
);
export const spotlightPeersSelector = createSelector(
spotlightsSelector,
peersSelector,
(spotlights, peers) => spotlights.map((peerName) => peers[peerName])
);
export const peersLengthSelector = createSelector(
peersSelector,
(peers) => Object.values(peers).length
);
const peersKeySelector = createSelector(
peersSelector,
(peers) => Object.keys(peers)
);
export const passivePeersSelector = createSelector(
peersKeySelector,
spotlightsSelector,
(peers, spotlights) => peers.filter((peerName) => !spotlights.includes(peerName))
);
export const videoBoxesSelector = createSelector(
spotlightsLengthSelector,
screenProducersSelector,
@ -79,7 +101,8 @@ export const meProducersSelector = createSelector(
}
);
const getPeerConsumers = (state, props) => state.peers[props.name].consumers;
const getPeerConsumers = (state, props) =>
(state.peers[props.name] ? state.peers[props.name].consumers : null);
const getAllConsumers = (state) => state.consumers;
export const makePeerConsumerSelector = () =>
@ -89,6 +112,9 @@ export const makePeerConsumerSelector = () =>
getAllConsumers,
(consumers, allConsumers) =>
{
if (!consumers)
return null;
const consumersArray = consumers
.map((consumerId) => allConsumers[consumerId]);
const micConsumer =

View File

@ -25,6 +25,7 @@ const consumers = (state = initialState, action) =>
{
const { consumerId, originator } = action.payload;
const consumer = state[consumerId];
let newConsumer;
if (originator === 'local')
@ -35,19 +36,11 @@ 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;
const consumer = state[consumerId];
let newConsumer;
if (originator === 'local')

View File

@ -0,0 +1,44 @@
const initialState = {};
const peerVolumes = (state = initialState, action) =>
{
switch (action.type)
{
case 'SET_ME':
{
const {
peerName
} = action.payload;
return { ...state, [peerName]: 0 };
}
case 'ADD_PEER':
{
const { peer } = action.payload;
return { ...state, [peer.name]: 0 };
}
case 'REMOVE_PEER':
{
const { peerName } = action.payload;
const newState = { ...state };
delete newState[peerName];
return newState;
}
case 'SET_PEER_VOLUME':
{
const { peerName, volume } = action.payload;
return { ...state, [peerName]: volume };
}
default:
return state;
}
};
export default peerVolumes;

View File

@ -25,6 +25,7 @@ const producers = (state = initialState, action) =>
{
const { producerId, originator } = action.payload;
const producer = state[producerId];
let newProducer;
if (originator === 'local')
@ -35,19 +36,11 @@ 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;
const producer = state[producerId];
let newProducer;
if (originator === 'local')

View File

@ -4,6 +4,7 @@ import me from './me';
import producers from './producers';
import peers from './peers';
import consumers from './consumers';
import peerVolumes from './peerVolumes';
import notifications from './notifications';
import chatmessages from './chatmessages';
import toolarea from './toolarea';
@ -15,6 +16,7 @@ export default combineReducers({
producers,
peers,
consumers,
peerVolumes,
notifications,
chatmessages,
toolarea,

View File

@ -28,8 +28,7 @@ if (process.env.NODE_ENV !== 'production')
const reduxLogger = createLogger(
{
// filter VOLUME level actions from log
predicate : (getState, action) => ! (action.type === 'SET_PRODUCER_VOLUME'
|| action.type === 'SET_CONSUMER_VOLUME'),
predicate : (getState, action) => !(action.type === 'SET_PEER_VOLUME'),
duration : true,
timestamp : false,
level : 'log',