Inital work on lobby.
parent
937f142c6e
commit
66a2becf63
|
|
@ -1283,6 +1283,46 @@ export default class RoomClient
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'parkedPeer':
|
||||||
|
{
|
||||||
|
const { peerId } = notification.data;
|
||||||
|
|
||||||
|
store.dispatch(
|
||||||
|
stateActions.addLobbyPeer(peerId));
|
||||||
|
|
||||||
|
store.dispatch(requestActions.notify(
|
||||||
|
{
|
||||||
|
text : 'New participant entered the lobby.'
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'promotedPeer':
|
||||||
|
{
|
||||||
|
const { peerId } = notification.data;
|
||||||
|
|
||||||
|
store.dispatch(
|
||||||
|
stateActions.removeLobbyPeer(peerId));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'parkedPeerDisplayName':
|
||||||
|
{
|
||||||
|
const { peerId, displayName } = notification.data;
|
||||||
|
|
||||||
|
store.dispatch(
|
||||||
|
stateActions.setLobbyPeerDisplayName(displayName, peerId));
|
||||||
|
|
||||||
|
store.dispatch(requestActions.notify(
|
||||||
|
{
|
||||||
|
text : `Participant in lobby changed name to ${displayName}.`
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'activeSpeaker':
|
case 'activeSpeaker':
|
||||||
{
|
{
|
||||||
const { peerId } = notification.data;
|
const { peerId } = notification.data;
|
||||||
|
|
|
||||||
|
|
@ -391,11 +391,11 @@ export const setPeerVolume = (peerId, volume) =>
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addLobbyPeer = (lobbyPeer) =>
|
export const addLobbyPeer = (peerId) =>
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
type : 'ADD_LOBBY_PEER',
|
type : 'ADD_LOBBY_PEER',
|
||||||
payload : { lobbyPeer }
|
payload : { peerId }
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,231 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import * as appPropTypes from '../../appPropTypes';
|
||||||
|
import { withRoomContext } from '../../../RoomContext';
|
||||||
|
import EmptyAvatar from '../../../images/avatar-empty.jpeg';
|
||||||
|
import HandIcon from '../../../images/icon-hand-white.svg';
|
||||||
|
|
||||||
|
const styles = (theme) =>
|
||||||
|
({
|
||||||
|
root :
|
||||||
|
{
|
||||||
|
padding : theme.spacing(1),
|
||||||
|
width : '100%',
|
||||||
|
overflow : 'hidden',
|
||||||
|
cursor : 'auto',
|
||||||
|
display : 'flex'
|
||||||
|
},
|
||||||
|
listPeer :
|
||||||
|
{
|
||||||
|
display : 'flex'
|
||||||
|
},
|
||||||
|
avatar :
|
||||||
|
{
|
||||||
|
borderRadius : '50%',
|
||||||
|
height : '2rem'
|
||||||
|
},
|
||||||
|
peerInfo :
|
||||||
|
{
|
||||||
|
fontSize : '1rem',
|
||||||
|
border : 'none',
|
||||||
|
display : 'flex',
|
||||||
|
paddingLeft : theme.spacing(1),
|
||||||
|
flexGrow : 1,
|
||||||
|
alignItems : 'center'
|
||||||
|
},
|
||||||
|
indicators :
|
||||||
|
{
|
||||||
|
left : 0,
|
||||||
|
top : 0,
|
||||||
|
display : 'flex',
|
||||||
|
flexDirection : 'row',
|
||||||
|
justifyContent : 'flex-start',
|
||||||
|
alignItems : 'center',
|
||||||
|
transition : 'opacity 0.3s'
|
||||||
|
},
|
||||||
|
icon :
|
||||||
|
{
|
||||||
|
flex : '0 0 auto',
|
||||||
|
margin : '0.3rem',
|
||||||
|
borderRadius : 2,
|
||||||
|
backgroundPosition : 'center',
|
||||||
|
backgroundSize : '75%',
|
||||||
|
backgroundRepeat : 'no-repeat',
|
||||||
|
backgroundColor : 'rgba(0, 0, 0, 0.5)',
|
||||||
|
transitionProperty : 'opacity, background-color',
|
||||||
|
transitionDuration : '0.15s',
|
||||||
|
width : 'var(--media-control-button-size)',
|
||||||
|
height : 'var(--media-control-button-size)',
|
||||||
|
opacity : 0.85,
|
||||||
|
'&:hover' :
|
||||||
|
{
|
||||||
|
opacity : 1
|
||||||
|
},
|
||||||
|
'&.on' :
|
||||||
|
{
|
||||||
|
opacity : 1
|
||||||
|
},
|
||||||
|
'&.off' :
|
||||||
|
{
|
||||||
|
opacity : 0.2
|
||||||
|
},
|
||||||
|
'&.raise-hand' :
|
||||||
|
{
|
||||||
|
backgroundImage : `url(${HandIcon})`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controls :
|
||||||
|
{
|
||||||
|
float : 'right',
|
||||||
|
display : 'flex',
|
||||||
|
flexDirection : 'row',
|
||||||
|
justifyContent : 'flex-start',
|
||||||
|
alignItems : 'center'
|
||||||
|
},
|
||||||
|
button :
|
||||||
|
{
|
||||||
|
flex : '0 0 auto',
|
||||||
|
margin : '0.3rem',
|
||||||
|
borderRadius : 2,
|
||||||
|
backgroundColor : 'rgba(0, 0, 0, 0.5)',
|
||||||
|
cursor : 'pointer',
|
||||||
|
transitionProperty : 'opacity, background-color',
|
||||||
|
transitionDuration : '0.15s',
|
||||||
|
width : 'var(--media-control-button-size)',
|
||||||
|
height : 'var(--media-control-button-size)',
|
||||||
|
opacity : 0.85,
|
||||||
|
'&:hover' :
|
||||||
|
{
|
||||||
|
opacity : 1
|
||||||
|
},
|
||||||
|
'&.unsupported' :
|
||||||
|
{
|
||||||
|
pointerEvents : 'none'
|
||||||
|
},
|
||||||
|
'&.disabled' :
|
||||||
|
{
|
||||||
|
pointerEvents : 'none',
|
||||||
|
backgroundColor : 'var(--media-control-botton-disabled)'
|
||||||
|
},
|
||||||
|
'&.on' :
|
||||||
|
{
|
||||||
|
backgroundColor : 'var(--media-control-botton-on)'
|
||||||
|
},
|
||||||
|
'&.off' :
|
||||||
|
{
|
||||||
|
backgroundColor : 'var(--media-control-botton-off)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ListLobbyPeer = (props) =>
|
||||||
|
{
|
||||||
|
const {
|
||||||
|
// roomClient,
|
||||||
|
peer,
|
||||||
|
classes
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const picture = peer.picture || EmptyAvatar;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.root}>
|
||||||
|
<img alt='Peer avatar' className={classes.avatar} src={picture} />
|
||||||
|
|
||||||
|
<div className={classes.peerInfo}>
|
||||||
|
{peer.displayName}
|
||||||
|
</div>
|
||||||
|
<div className={classes.indicators}>
|
||||||
|
{ /* peer.raiseHandState ?
|
||||||
|
<div className={
|
||||||
|
classnames(
|
||||||
|
classes.icon, 'raise-hand', {
|
||||||
|
on : peer.raiseHandState,
|
||||||
|
off : !peer.raiseHandState
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
:null
|
||||||
|
*/ }
|
||||||
|
</div>
|
||||||
|
<div className={classes.controls}>
|
||||||
|
{/* { screenConsumer ?
|
||||||
|
<div
|
||||||
|
className={classnames(classes.button, 'screen', {
|
||||||
|
on : screenVisible,
|
||||||
|
off : !screenVisible,
|
||||||
|
disabled : peer.peerScreenInProgress
|
||||||
|
})}
|
||||||
|
onClick={(e) =>
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
screenVisible ?
|
||||||
|
roomClient.modifyPeerConsumer(peer.id, 'screen', true) :
|
||||||
|
roomClient.modifyPeerConsumer(peer.id, 'screen', false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ screenVisible ?
|
||||||
|
<ScreenIcon />
|
||||||
|
:
|
||||||
|
<ScreenOffIcon />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
:null
|
||||||
|
}
|
||||||
|
<div
|
||||||
|
className={classnames(classes.button, 'mic', {
|
||||||
|
on : micEnabled,
|
||||||
|
off : !micEnabled,
|
||||||
|
disabled : peer.peerAudioInProgress
|
||||||
|
})}
|
||||||
|
onClick={(e) =>
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
micEnabled ?
|
||||||
|
roomClient.modifyPeerConsumer(peer.id, 'mic', true) :
|
||||||
|
roomClient.modifyPeerConsumer(peer.id, 'mic', false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ micEnabled ?
|
||||||
|
<MicIcon />
|
||||||
|
:
|
||||||
|
<MicOffIcon />
|
||||||
|
}
|
||||||
|
</div> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ListLobbyPeer.propTypes =
|
||||||
|
{
|
||||||
|
roomClient : PropTypes.any.isRequired,
|
||||||
|
advancedMode : PropTypes.bool,
|
||||||
|
peer : appPropTypes.Peer.isRequired,
|
||||||
|
classes : PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state, { id }) =>
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
peer : state.lobbyPeers[id]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withRoomContext(connect(
|
||||||
|
mapStateToProps,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
areStatesEqual : (next, prev) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
prev.lobbyPeers === next.lobbyPeers
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(withStyles(styles)(ListLobbyPeer)));
|
||||||
|
|
@ -2,13 +2,15 @@ import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
passivePeersSelector,
|
passivePeersSelector,
|
||||||
spotlightPeersSelector
|
spotlightPeersSelector,
|
||||||
|
lobbyPeersKeySelector
|
||||||
} 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';
|
||||||
import { withRoomContext } from '../../../RoomContext';
|
import { withRoomContext } from '../../../RoomContext';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ListPeer from './ListPeer';
|
import ListPeer from './ListPeer';
|
||||||
|
import ListLobbyPeer from './ListLobbyPeer';
|
||||||
import ListMe from './ListMe';
|
import ListMe from './ListMe';
|
||||||
import Volume from '../../Containers/Volume';
|
import Volume from '../../Containers/Volume';
|
||||||
|
|
||||||
|
|
@ -78,6 +80,7 @@ class ParticipantList extends React.PureComponent
|
||||||
passivePeers,
|
passivePeers,
|
||||||
selectedPeerId,
|
selectedPeerId,
|
||||||
spotlightPeers,
|
spotlightPeers,
|
||||||
|
lobbyPeers,
|
||||||
classes
|
classes
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
|
@ -88,6 +91,22 @@ class ParticipantList extends React.PureComponent
|
||||||
<ListMe />
|
<ListMe />
|
||||||
</ul>
|
</ul>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
{ lobbyPeers ?
|
||||||
|
<ul className={classes.list}>
|
||||||
|
<li className={classes.listheader}>Participants in Spotlight:</li>
|
||||||
|
{ lobbyPeers.map((peerId) => (
|
||||||
|
<li
|
||||||
|
key={peerId}
|
||||||
|
className={classes.listItem}
|
||||||
|
>
|
||||||
|
<ListLobbyPeer id={peerId} advancedMode={advancedMode} />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
:null
|
||||||
|
}
|
||||||
|
|
||||||
<ul className={classes.list}>
|
<ul className={classes.list}>
|
||||||
<li className={classes.listheader}>Participants in Spotlight:</li>
|
<li className={classes.listheader}>Participants in Spotlight:</li>
|
||||||
{ spotlightPeers.map((peer) => (
|
{ spotlightPeers.map((peer) => (
|
||||||
|
|
@ -131,6 +150,7 @@ ParticipantList.propTypes =
|
||||||
passivePeers : PropTypes.array,
|
passivePeers : PropTypes.array,
|
||||||
selectedPeerId : PropTypes.string,
|
selectedPeerId : PropTypes.string,
|
||||||
spotlightPeers : PropTypes.array,
|
spotlightPeers : PropTypes.array,
|
||||||
|
lobbyPeers : PropTypes.array,
|
||||||
classes : PropTypes.object.isRequired
|
classes : PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -139,7 +159,8 @@ const mapStateToProps = (state) =>
|
||||||
return {
|
return {
|
||||||
passivePeers : passivePeersSelector(state),
|
passivePeers : passivePeersSelector(state),
|
||||||
selectedPeerId : state.room.selectedPeerId,
|
selectedPeerId : state.room.selectedPeerId,
|
||||||
spotlightPeers : spotlightPeersSelector(state)
|
spotlightPeers : spotlightPeersSelector(state),
|
||||||
|
lobbyPeers : lobbyPeersKeySelector(state)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -153,7 +174,8 @@ const ParticipantListContainer = withRoomContext(connect(
|
||||||
return (
|
return (
|
||||||
prev.peers === next.peers &&
|
prev.peers === next.peers &&
|
||||||
prev.room.spotlights === next.room.spotlights &&
|
prev.room.spotlights === next.room.spotlights &&
|
||||||
prev.room.selectedPeerId === next.room.selectedPeerId
|
prev.room.selectedPeerId === next.room.selectedPeerId &&
|
||||||
|
prev.lobbyPeers === next.lobbyPeers
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ const producersSelect = (state) => state.producers;
|
||||||
const consumersSelect = (state) => state.consumers;
|
const consumersSelect = (state) => state.consumers;
|
||||||
const spotlightsSelector = (state) => state.room.spotlights;
|
const spotlightsSelector = (state) => state.room.spotlights;
|
||||||
const peersSelector = (state) => state.peers;
|
const peersSelector = (state) => state.peers;
|
||||||
|
const lobbyPeersSelector = (state) => state.lobbyPeers;
|
||||||
const getPeerConsumers = (state, props) =>
|
const getPeerConsumers = (state, props) =>
|
||||||
(state.peers[props.id] ? state.peers[props.id].consumers : null);
|
(state.peers[props.id] ? state.peers[props.id].consumers : null);
|
||||||
const getAllConsumers = (state) => state.consumers;
|
const getAllConsumers = (state) => state.consumers;
|
||||||
|
|
@ -12,6 +13,11 @@ const peersKeySelector = createSelector(
|
||||||
(peers) => Object.keys(peers)
|
(peers) => Object.keys(peers)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const lobbyPeersKeySelector = createSelector(
|
||||||
|
lobbyPeersSelector,
|
||||||
|
(lobbyPeers) => Object.keys(lobbyPeers)
|
||||||
|
);
|
||||||
|
|
||||||
export const micProducersSelector = createSelector(
|
export const micProducersSelector = createSelector(
|
||||||
producersSelect,
|
producersSelect,
|
||||||
(producers) => Object.values(producers).filter((producer) => producer.source === 'mic')
|
(producers) => Object.values(producers).filter((producer) => producer.source === 'mic')
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ const lobbyPeer = (state = {}, action) =>
|
||||||
switch (action.type)
|
switch (action.type)
|
||||||
{
|
{
|
||||||
case 'ADD_LOBBY_PEER':
|
case 'ADD_LOBBY_PEER':
|
||||||
return action.payload.lobbyPeer;
|
return { peerId: action.payload.peerId };
|
||||||
|
|
||||||
case 'SET_LOBBY_PEER_DISPLAY_NAME':
|
case 'SET_LOBBY_PEER_DISPLAY_NAME':
|
||||||
return { ...state, displayName: action.payload.displayName };
|
return { ...state, displayName: action.payload.displayName };
|
||||||
|
|
@ -19,7 +19,7 @@ const lobbyPeers = (state = {}, action) =>
|
||||||
{
|
{
|
||||||
case 'ADD_LOBBY_PEER':
|
case 'ADD_LOBBY_PEER':
|
||||||
{
|
{
|
||||||
return { ...state, [action.payload.lobbyPeer.id]: lobbyPeer(undefined, action) };
|
return { ...state, [action.payload.peerId]: lobbyPeer(undefined, action) };
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'REMOVE_LOBBY_PEER':
|
case 'REMOVE_LOBBY_PEER':
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
const Logger = require('./Logger');
|
const Logger = require('./Logger');
|
||||||
|
const Lobby = require('./Lobby');
|
||||||
const config = require('../config/config');
|
const config = require('../config/config');
|
||||||
|
|
||||||
const logger = new Logger('Room');
|
const logger = new Logger('Room');
|
||||||
|
|
@ -54,6 +55,15 @@ class Room extends EventEmitter
|
||||||
// Locked flag.
|
// Locked flag.
|
||||||
this._locked = false;
|
this._locked = false;
|
||||||
|
|
||||||
|
this._lobby = new Lobby();
|
||||||
|
|
||||||
|
this._lobby.on('promotePeer', (peer) =>
|
||||||
|
{
|
||||||
|
logger.info('promotePeer() [peer:"%o"]', peer);
|
||||||
|
|
||||||
|
this._peerJoining({ ...peer });
|
||||||
|
});
|
||||||
|
|
||||||
this._chatHistory = [];
|
this._chatHistory = [];
|
||||||
|
|
||||||
this._fileHistory = [];
|
this._fileHistory = [];
|
||||||
|
|
@ -118,6 +128,8 @@ class Room extends EventEmitter
|
||||||
|
|
||||||
this._closed = true;
|
this._closed = true;
|
||||||
|
|
||||||
|
this._lobby.close();
|
||||||
|
|
||||||
// Close the peers
|
// Close the peers
|
||||||
if (this._peers)
|
if (this._peers)
|
||||||
{
|
{
|
||||||
|
|
@ -165,11 +177,21 @@ class Room extends EventEmitter
|
||||||
}
|
}
|
||||||
else if (this._locked) // Don't allow connections to a locked room
|
else if (this._locked) // Don't allow connections to a locked room
|
||||||
{
|
{
|
||||||
this._notification(socket, 'roomLocked');
|
this._lobby.parkPeer({ peerId, consume, socket });
|
||||||
socket.disconnect(true);
|
|
||||||
|
this._peers.forEach((peer) =>
|
||||||
|
{
|
||||||
|
this._notification(peer.socket, 'parkedPeer', { peerId });
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._peerJoining({ peerId, consume, socket });
|
||||||
|
}
|
||||||
|
|
||||||
|
_peerJoining({ peerId, consume, socket })
|
||||||
|
{
|
||||||
socket.join(this._roomId);
|
socket.join(this._roomId);
|
||||||
|
|
||||||
const peer = { id : peerId, socket : socket };
|
const peer = { id : peerId, socket : socket };
|
||||||
|
|
@ -808,6 +830,28 @@ class Room extends EventEmitter
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'promotePeer':
|
||||||
|
{
|
||||||
|
const { peerId } = request.data;
|
||||||
|
|
||||||
|
this._lobby.promotePeer(peerId);
|
||||||
|
|
||||||
|
// Return no error
|
||||||
|
cb();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'promoteAllPeers':
|
||||||
|
{
|
||||||
|
this._lobby.promoteAllPeers();
|
||||||
|
|
||||||
|
// Return no error
|
||||||
|
cb();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'sendFile':
|
case 'sendFile':
|
||||||
{
|
{
|
||||||
const { magnetUri } = request.data;
|
const { magnetUri } = request.data;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue