diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js
index 0189103..11d72b2 100644
--- a/app/src/RoomClient.js
+++ b/app/src/RoomClient.js
@@ -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));
}
});
}
diff --git a/app/src/actions/stateActions.js b/app/src/actions/stateActions.js
index bb57e28..968e949 100644
--- a/app/src/actions/stateActions.js
+++ b/app/src/actions/stateActions.js
@@ -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 }
};
};
diff --git a/app/src/components/Containers/Me.js b/app/src/components/Containers/Me.js
index d63448d..2934dee 100644
--- a/app/src/components/Containers/Me.js
+++ b/app/src/components/Containers/Me.js
@@ -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
};
};
diff --git a/app/src/components/Containers/Peer.js b/app/src/components/Containers/Peer.js
index e89bbaa..91d0db3 100644
--- a/app/src/components/Containers/Peer.js
+++ b/app/src/components/Containers/Peer.js
@@ -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
};
diff --git a/app/src/components/Controls/Sidebar.js b/app/src/components/Controls/Sidebar.js
index 7319f35..a35a0af 100644
--- a/app/src/components/Controls/Sidebar.js
+++ b/app/src/components/Controls/Sidebar.js
@@ -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)));
diff --git a/app/src/components/MeetingDrawer/Chat/MessageList.js b/app/src/components/MeetingDrawer/Chat/MessageList.js
index 9aec4ba..3e8b2d8 100644
--- a/app/src/components/MeetingDrawer/Chat/MessageList.js
+++ b/app/src/components/MeetingDrawer/Chat/MessageList.js
@@ -100,4 +100,17 @@ const mapStateToProps = (state) =>
myPicture : state.me.picture
});
-export default connect(mapStateToProps, null)(withStyles(styles)(MessageList));
\ No newline at end of file
+export default connect(
+ mapStateToProps,
+ null,
+ null,
+ {
+ areStatesEqual : (next, prev) =>
+ {
+ return (
+ prev.chatmessages === next.chatmessages &&
+ prev.me.picture === next.me.picture
+ );
+ }
+ }
+)(withStyles(styles)(MessageList));
\ No newline at end of file
diff --git a/app/src/components/MeetingDrawer/ParticipantList/ListPeer.js b/app/src/components/MeetingDrawer/ParticipantList/ListPeer.js
index e6574b8..e98d09c 100644
--- a/app/src/components/MeetingDrawer/ParticipantList/ListPeer.js
+++ b/app/src/components/MeetingDrawer/ParticipantList/ListPeer.js
@@ -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) =>
}
{ 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]
};
};
diff --git a/app/src/components/MeetingDrawer/ParticipantList/ParticipantList.js b/app/src/components/MeetingDrawer/ParticipantList/ParticipantList.js
index c03bfa5..1b6655f 100644
--- a/app/src/components/MeetingDrawer/ParticipantList/ParticipantList.js
+++ b/app/src/components/MeetingDrawer/ParticipantList/ParticipantList.js
@@ -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
- Participants in Spotlight:
- {peers.filter((peer) =>
- {
- return (spotlights.find((spotlight) =>
- { return (spotlight === peer.name); }));
- }).map((peer) => (
+ { spotlights.map((peerName) => (
- roomClient.setSelectedPeer(peer.name)}
+ onClick={() => roomClient.setSelectedPeer(peerName)}
>
-
+
))}
- Passive Participants:
- {peers.filter((peer) =>
- {
- return !(spotlights.find((spotlight) =>
- { return (spotlight === peer.name); }));
- }).map((peer) => (
+ { passivePeers.map((peerName) => (
- roomClient.setSelectedPeer(peer.name)}
+ onClick={() => roomClient.setSelectedPeer(peerName)}
>
-
+
))}
@@ -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;
diff --git a/app/src/components/MeetingViews/Democratic.js b/app/src/components/MeetingViews/Democratic.js
index a5e6772..14211d6 100644
--- a/app/src/components/MeetingViews/Democratic.js
+++ b/app/src/components/MeetingViews/Democratic.js
@@ -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 (
-
- );
- }
- else
- {
- return ('');
- }
+ return (
+
+ );
})}
- { spotlightsLength < Object.keys(peers).length ?
+ { spotlightsLength < peersLength ?
: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));
diff --git a/app/src/components/Room.js b/app/src/components/Room.js
index 1f64460..aa4bf0f 100644
--- a/app/src/components/Room.js
+++ b/app/src/components/Room.js
@@ -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)));
\ No newline at end of file
diff --git a/app/src/components/Selectors.js b/app/src/components/Selectors.js
index 836d158..0497119 100644
--- a/app/src/components/Selectors.js
+++ b/app/src/components/Selectors.js
@@ -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 =
@@ -101,4 +127,4 @@ export const makePeerConsumerSelector = () =>
return { micConsumer, webcamConsumer, screenConsumer };
}
);
-};
\ No newline at end of file
+};
diff --git a/app/src/reducers/consumers.js b/app/src/reducers/consumers.js
index 117cdc5..758efd2 100644
--- a/app/src/reducers/consumers.js
+++ b/app/src/reducers/consumers.js
@@ -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')
diff --git a/app/src/reducers/peerVolumes.js b/app/src/reducers/peerVolumes.js
new file mode 100644
index 0000000..6b89db8
--- /dev/null
+++ b/app/src/reducers/peerVolumes.js
@@ -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;
diff --git a/app/src/reducers/producers.js b/app/src/reducers/producers.js
index 736f70b..64aee90 100644
--- a/app/src/reducers/producers.js
+++ b/app/src/reducers/producers.js
@@ -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')
diff --git a/app/src/reducers/rootReducer.js b/app/src/reducers/rootReducer.js
index 8b3fdce..b7e3b75 100644
--- a/app/src/reducers/rootReducer.js
+++ b/app/src/reducers/rootReducer.js
@@ -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,
diff --git a/app/src/store.js b/app/src/store.js
index 4b247db..14c8460 100644
--- a/app/src/store.js
+++ b/app/src/store.js
@@ -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',