Merge branch 'feat-join-dialog' into develop

master
Håvar Aambø Fosstveit 2019-06-13 13:57:01 +02:00
commit e7a2b8bd6d
6 changed files with 162 additions and 107 deletions

View File

@ -65,10 +65,6 @@ const VIDEO_ENCODINGS =
let store; let store;
const AudioContext = window.AudioContext // Default
|| window.webkitAudioContext // Safari and old versions of Chrome
|| false;
export default class RoomClient export default class RoomClient
{ {
/** /**
@ -119,11 +115,6 @@ export default class RoomClient
// Alert sound // Alert sound
this._soundAlert = new Audio('/sounds/notify.mp3'); this._soundAlert = new Audio('/sounds/notify.mp3');
if (AudioContext)
{
this._audioContext = new AudioContext();
}
// Socket.io peer connection // Socket.io peer connection
this._signalingSocket = null; this._signalingSocket = null;
@ -661,9 +652,15 @@ export default class RoomClient
{ {
logger.debug('muteMic()'); logger.debug('muteMic()');
this._micProducer.pause();
try try
{ {
this._micProducer.pause(); await this.sendRequest(
'pauseProducer', { producerId: this._micProducer.id });
store.dispatch(
stateActions.setProducerPaused(this._micProducer.id));
} }
catch (error) catch (error)
{ {
@ -681,24 +678,32 @@ export default class RoomClient
{ {
logger.debug('unmuteMic()'); logger.debug('unmuteMic()');
try if (!this._micProducer)
{ {
if (this._micProducer) this.enableMic();
this._micProducer.resume();
else if (this._room.canSend('audio'))
await this.enableMic();
else
throw new Error('cannot send audio');
} }
catch (error) else
{ {
logger.error('unmuteMic() | failed: %o', error); this._micProducer.resume();
store.dispatch(requestActions.notify( try
{ {
type : 'error', await this.sendRequest(
text : 'An error occured while accessing your microphone.' 'resumeProducer', { producerId: this._micProducer.id });
}));
store.dispatch(
stateActions.setProducerResumed(this._micProducer.id));
}
catch (error)
{
logger.error('unmuteMic() | failed: %o', error);
store.dispatch(requestActions.notify(
{
type : 'error',
text : 'An error occured while accessing your microphone.'
}));
}
} }
} }
@ -1056,31 +1061,13 @@ export default class RoomClient
stateActions.setMyRaiseHandStateInProgress(false)); stateActions.setMyRaiseHandStateInProgress(false));
} }
async resumeAudio() async join({ joinVideo })
{
logger.debug('resumeAudio()');
try
{
await this._audioContext.resume();
store.dispatch(
stateActions.setAudioSuspended({ audioSuspended: false }));
}
catch (error)
{
store.dispatch(
stateActions.setAudioSuspended({ audioSuspended: true }));
logger.error('resumeAudioJoin() failed: %o', error);
}
}
async join()
{ {
this._signalingSocket = io(this._signalingUrl); this._signalingSocket = io(this._signalingUrl);
this._spotlights = new Spotlights(this._maxSpotlights, this._signalingSocket); this._spotlights = new Spotlights(this._maxSpotlights, this._signalingSocket);
store.dispatch(stateActions.toggleJoined());
store.dispatch(stateActions.setRoomState('connecting')); store.dispatch(stateActions.setRoomState('connecting'));
this._signalingSocket.on('connect', () => this._signalingSocket.on('connect', () =>
@ -1258,7 +1245,7 @@ export default class RoomClient
{ {
case 'roomReady': case 'roomReady':
{ {
await this._joinRoom(); await this._joinRoom({ joinVideo });
break; break;
} }
@ -1514,7 +1501,7 @@ export default class RoomClient
}); });
} }
async _joinRoom() async _joinRoom({ joinVideo })
{ {
logger.debug('_joinRoom()'); logger.debug('_joinRoom()');
@ -1664,10 +1651,10 @@ export default class RoomClient
if (this._produce) if (this._produce)
{ {
if (this._mediasoupDevice.canProduce('audio')) if (this._mediasoupDevice.canProduce('audio'))
await this.enableMic(); this.enableMic();
if (this._mediasoupDevice.canProduce('video')) if (joinVideo && this._mediasoupDevice.canProduce('video'))
await this.enableWebcam(); this.enableWebcam();
} }
store.dispatch(stateActions.setRoomState('connected')); store.dispatch(stateActions.setRoomState('connected'));
@ -1875,15 +1862,6 @@ export default class RoomClient
store.dispatch(stateActions.setPeerVolume(this._peerId, volume)); store.dispatch(stateActions.setPeerVolume(this._peerId, volume));
} }
}); });
if (this._audioContext)
{
// We need to provoke user interaction to get permission from browser to start audio
if (this._audioContext.state === 'suspended')
{
this.resumeAudio();
}
}
} }
catch (error) catch (error)
{ {

View File

@ -43,14 +43,6 @@ export const setRoomLockedOut = () =>
}; };
}; };
export const setAudioSuspended = ({ audioSuspended }) =>
{
return {
type : 'SET_AUDIO_SUSPENDED',
payload : { audioSuspended }
};
};
export const setSettingsOpen = ({ settingsOpen }) => export const setSettingsOpen = ({ settingsOpen }) =>
({ ({
type : 'SET_SETTINGS_OPEN', type : 'SET_SETTINGS_OPEN',
@ -568,6 +560,11 @@ export const loggedIn = () =>
type : 'LOGGED_IN' type : 'LOGGED_IN'
}); });
export const toggleJoined = () =>
({
type : 'TOGGLE_JOINED'
});
export const setSelectedPeer = (selectedPeerId) => export const setSelectedPeer = (selectedPeerId) =>
({ ({
type : 'SET_SELECTED_PEER', type : 'SET_SELECTED_PEER',

View File

@ -78,11 +78,16 @@ const Sidebar = (props) =>
let micTip; let micTip;
if (!me.canSendMic || !micProducer) if (!me.canSendMic)
{ {
micState = 'unsupported'; micState = 'unsupported';
micTip = 'Audio unsupported'; micTip = 'Audio unsupported';
} }
else if (!micProducer)
{
micState = 'off';
micTip = 'Activate audio';
}
else if (!micProducer.locallyPaused && !micProducer.remotelyPaused) else if (!micProducer.locallyPaused && !micProducer.remotelyPaused)
{ {
micState = 'on'; micState = 'on';
@ -90,7 +95,7 @@ const Sidebar = (props) =>
} }
else else
{ {
micState = 'off'; micState = 'muted';
micTip = 'Unmute audio'; micTip = 'Unmute audio';
} }
@ -152,9 +157,12 @@ const Sidebar = (props) =>
size={smallScreen ? 'large' : 'medium'} size={smallScreen ? 'large' : 'medium'}
onClick={() => onClick={() =>
{ {
micState === 'on' ? if (micState === 'off')
roomClient.disableMic() :
roomClient.enableMic(); roomClient.enableMic();
else if (micState === 'on')
roomClient.muteMic();
else
roomClient.unmuteMic();
}} }}
> >
{ micState === 'on' ? { micState === 'on' ?

View File

@ -0,0 +1,90 @@
import React from 'react';
import { withStyles } from '@material-ui/core/styles';
import { withRoomContext } from '../RoomContext';
import PropTypes from 'prop-types';
import Dialog from '@material-ui/core/Dialog';
import Typography from '@material-ui/core/Typography';
import DialogActions from '@material-ui/core/DialogActions';
import Button from '@material-ui/core/Button';
const styles = (theme) =>
({
root :
{
},
dialogPaper :
{
width : '20vw',
padding : theme.spacing.unit * 2,
[theme.breakpoints.down('lg')] :
{
width : '30vw'
},
[theme.breakpoints.down('md')] :
{
width : '40vw'
},
[theme.breakpoints.down('sm')] :
{
width : '60vw'
},
[theme.breakpoints.down('xs')] :
{
width : '80vw'
}
},
logo :
{
display : 'block'
}
});
const JoinDialog = ({
roomClient,
classes
}) =>
{
return (
<Dialog
className={classes.root}
open
classes={{
paper : classes.dialogPaper
}}
>
{ window.config.logo ?
<img alt='Logo' className={classes.logo} src={window.config.logo} />
:null
}
<Typography variant='subtitle1'>You are about to join a meeting, how would you like to join?</Typography>
<DialogActions>
<Button
onClick={() =>
{
roomClient.join({ joinVideo: false });
}}
variant='contained'
>
Audio only
</Button>
<Button
onClick={() =>
{
roomClient.join({ joinVideo: true });
}}
variant='contained'
>
Audio and Video
</Button>
</DialogActions>
</Dialog>
);
};
JoinDialog.propTypes =
{
roomClient : PropTypes.any.isRequired,
classes : PropTypes.object.isRequired
};
export default withRoomContext(withStyles(styles)(JoinDialog));

View File

@ -15,7 +15,6 @@ import SwipeableDrawer from '@material-ui/core/SwipeableDrawer';
import Hidden from '@material-ui/core/Hidden'; import Hidden from '@material-ui/core/Hidden';
import Paper from '@material-ui/core/Paper'; import Paper from '@material-ui/core/Paper';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton'; import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu'; import MenuIcon from '@material-ui/icons/Menu';
import Avatar from '@material-ui/core/Avatar'; import Avatar from '@material-ui/core/Avatar';
@ -33,6 +32,7 @@ import FullScreenIcon from '@material-ui/icons/Fullscreen';
import FullScreenExitIcon from '@material-ui/icons/FullscreenExit'; import FullScreenExitIcon from '@material-ui/icons/FullscreenExit';
import SettingsIcon from '@material-ui/icons/Settings'; import SettingsIcon from '@material-ui/icons/Settings';
import Settings from './Settings/Settings'; import Settings from './Settings/Settings';
import JoinDialog from './JoinDialog';
const TIMEOUT = 10 * 1000; const TIMEOUT = 10 * 1000;
@ -176,10 +176,6 @@ class Room extends React.PureComponent
componentDidMount() componentDidMount()
{ {
const { roomClient } = this.props;
roomClient.join();
if (this.fullscreen.fullscreenEnabled) if (this.fullscreen.fullscreenEnabled)
{ {
this.fullscreen.addEventListener('fullscreenchange', this.handleFullscreenChange); this.fullscreen.addEventListener('fullscreenchange', this.handleFullscreenChange);
@ -242,29 +238,7 @@ class Room extends React.PureComponent
democratic : Democratic democratic : Democratic
}[room.mode]; }[room.mode];
if (room.audioSuspended) if (room.lockedOut)
{
return (
<div className={classes.root}>
<Paper className={classes.message}>
<Typography variant='h2'>
This webpage required sound and video to play, please click to allow.
</Typography>
<Button
variant='contained'
onClick={() =>
{
roomClient.notify('Joining.');
roomClient.resumeAudio();
}}
>
Allow
</Button>
</Paper>
</div>
);
}
else if (room.lockedOut)
{ {
return ( return (
<div className={classes.root}> <div className={classes.root}>
@ -274,6 +248,14 @@ class Room extends React.PureComponent
</div> </div>
); );
} }
else if (!room.joined)
{
return (
<div className={classes.root}>
<JoinDialog />
</div>
);
}
else else
{ {
return ( return (

View File

@ -4,7 +4,6 @@ const initialState =
state : 'new', // new/connecting/connected/disconnected/closed, state : 'new', // new/connecting/connected/disconnected/closed,
locked : false, locked : false,
lockedOut : false, lockedOut : false,
audioSuspended : false,
activeSpeakerId : null, activeSpeakerId : null,
torrentSupport : false, torrentSupport : false,
showSettings : false, showSettings : false,
@ -14,7 +13,8 @@ const initialState =
mode : 'democratic', mode : 'democratic',
selectedPeerId : null, selectedPeerId : null,
spotlights : [], spotlights : [],
settingsOpen : false settingsOpen : false,
joined : false
}; };
const room = (state = initialState, action) => const room = (state = initialState, action) =>
@ -53,13 +53,6 @@ const room = (state = initialState, action) =>
return { ...state, lockedOut: true }; return { ...state, lockedOut: true };
} }
case 'SET_AUDIO_SUSPENDED':
{
const { audioSuspended } = action.payload;
return { ...state, audioSuspended };
}
case 'SET_SETTINGS_OPEN': case 'SET_SETTINGS_OPEN':
{ {
const { settingsOpen } = action.payload; const { settingsOpen } = action.payload;
@ -88,6 +81,13 @@ const room = (state = initialState, action) =>
return { ...state, showSettings }; return { ...state, showSettings };
} }
case 'TOGGLE_JOINED':
{
const joined = !state.joined;
return { ...state, joined };
}
case 'TOGGLE_FULLSCREEN_CONSUMER': case 'TOGGLE_FULLSCREEN_CONSUMER':
{ {
const { consumerId } = action.payload; const { consumerId } = action.payload;