Merge branch 'feat-audiocontext' into develop

master
Håvar Aambø Fosstveit 2019-03-14 09:36:39 +01:00
commit 23948f09d9
6 changed files with 139 additions and 22 deletions

View File

@ -53,7 +53,7 @@ export default class RoomClient
'constructor() [roomId:"%s", peerName:"%s", displayName:"%s", device:%s]', 'constructor() [roomId:"%s", peerName:"%s", displayName:"%s", device:%s]',
roomId, peerName, displayName, device.flag); roomId, peerName, displayName, device.flag);
const signalingUrl = getSignalingUrl(peerName, roomId); this._signalingUrl = getSignalingUrl(peerName, roomId);
// window element to external login site // window element to external login site
this._loginWindow; this._loginWindow;
@ -76,18 +76,21 @@ export default class RoomClient
// My peer name. // My peer name.
this._peerName = peerName; this._peerName = peerName;
// My display name
this._displayName = peerName;
// Alert sound // Alert sound
this._soundAlert = new Audio('/resources/sounds/notify.mp3'); this._soundAlert = new Audio('/resources/sounds/notify.mp3');
// AudioContext
this._audioContext;
// Socket.io peer connection // Socket.io peer connection
this._signalingSocket = io(signalingUrl); this._signalingSocket = null;
if (this._device.flag === 'firefox') // The mediasoup room instance
ROOM_OPTIONS = Object.assign({ iceTransportPolicy: 'relay' }, ROOM_OPTIONS); this._room = null;
this._roomId = roomId;
// mediasoup-client Room instance.
this._room = new mediasoupClient.Room(ROOM_OPTIONS);
this._room.roomId = roomId;
// Our WebTorrent client // Our WebTorrent client
this._webTorrent = this._torrentSupport && new WebTorrent({ this._webTorrent = this._torrentSupport && new WebTorrent({
@ -102,7 +105,7 @@ export default class RoomClient
this._maxSpotlights = ROOM_OPTIONS.maxSpotlights; this._maxSpotlights = ROOM_OPTIONS.maxSpotlights;
// Manager of spotlight // Manager of spotlight
this._spotlights = new Spotlights(this._maxSpotlights, this._room); this._spotlights = null;
// Transport for sending. // Transport for sending.
this._sendTransport = null; this._sendTransport = null;
@ -140,7 +143,9 @@ export default class RoomClient
this._startKeyListener(); this._startKeyListener();
this._join({ displayName, device }); this._audioContext = null;
this.join();
} }
close() close()
@ -983,8 +988,36 @@ export default class RoomClient
}, 500); }, 500);
} }
_join({ displayName, device }) async resumeAudio()
{ {
logger.debug('resumeAudio()');
try
{
await this._audioContext.resume();
store.dispatch(
stateActions.setAudioSuspended({ audioSuspended: false }));
}
catch (error)
{
logger.error('resumeAudioJoin() failed: %o', error);
}
}
join()
{
this._signalingSocket = io(this._signalingUrl);
if (this._device.flag === 'firefox')
ROOM_OPTIONS = Object.assign({ iceTransportPolicy: 'relay' }, ROOM_OPTIONS);
// mediasoup-client Room instance.
this._room = new mediasoupClient.Room(ROOM_OPTIONS);
this._room.roomId = this._roomId;
this._spotlights = new Spotlights(this._maxSpotlights, this._room);
store.dispatch(stateActions.setRoomState('connecting')); store.dispatch(stateActions.setRoomState('connecting'));
this._signalingSocket.on('connect', () => this._signalingSocket.on('connect', () =>
@ -996,7 +1029,7 @@ export default class RoomClient
{ {
logger.debug('signaling Peer "room-ready" event'); logger.debug('signaling Peer "room-ready" event');
this._joinRoom({ displayName, device }); this._joinRoom();
}); });
this._signalingSocket.on('room-locked', () => this._signalingSocket.on('room-locked', () =>
@ -1180,7 +1213,7 @@ export default class RoomClient
}); });
} }
async _joinRoom({ displayName, device }) async _joinRoom()
{ {
logger.debug('_joinRoom()'); logger.debug('_joinRoom()');
@ -1236,7 +1269,13 @@ export default class RoomClient
try try
{ {
await this._room.join(this._peerName, { displayName, device }); await this._room.join(
this._peerName,
{
displayName : this._displayName,
device : this._device
}
);
store.dispatch( store.dispatch(
stateActions.setFileSharingSupported(this._torrentSupport)); stateActions.setFileSharingSupported(this._torrentSupport));
@ -1277,7 +1316,7 @@ export default class RoomClient
if (this._produce) if (this._produce)
{ {
if (this._room.canSend('audio')) if (this._room.canSend('audio'))
this._setMicProducer(); await this._setMicProducer();
// Add our webcam (unless the cookie says no). // Add our webcam (unless the cookie says no).
if (this._room.canSend('video')) if (this._room.canSend('video'))
@ -1285,7 +1324,7 @@ export default class RoomClient
const devicesCookie = cookiesManager.getDevices(); const devicesCookie = cookiesManager.getDevices();
if (!devicesCookie || devicesCookie.webcamEnabled) if (!devicesCookie || devicesCookie.webcamEnabled)
this.enableWebcam(); await this.enableWebcam();
} }
} }
@ -1462,6 +1501,14 @@ export default class RoomClient
store.dispatch(stateActions.setProducerVolume(producer.id, volume)); store.dispatch(stateActions.setProducerVolume(producer.id, volume));
} }
}); });
this._audioContext = new AudioContext();
// We need to provoke user interaction to get permission from browser to start audio
if (this._audioContext.state === 'suspended')
{
store.dispatch(stateActions.setAudioSuspended({ audioSuspended: true }));
}
} }
catch (error) catch (error)
{ {
@ -1472,7 +1519,6 @@ export default class RoomClient
if (producer) if (producer)
producer.close(); producer.close();
throw error;
} }
} }

View File

@ -1,5 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { withRoomContext } from '../RoomContext';
import ReactTooltip from 'react-tooltip'; import ReactTooltip from 'react-tooltip';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
@ -63,6 +64,7 @@ class Room extends React.Component
render() render()
{ {
const { const {
roomClient,
room, room,
amActiveSpeaker, amActiveSpeaker,
onRoomLinkCopy onRoomLinkCopy
@ -73,7 +75,31 @@ class Room extends React.Component
democratic : Peers democratic : Peers
}[room.mode]; }[room.mode];
if (room.lockedOut) if (room.audioSuspended)
{
return (
<Fragment>
<Appear duration={300}>
<div data-component='Room'>
<div className='sound-suspended'>
This webpage required sound and video to play, please click to allow.
<div
onClick={() =>
{
roomClient.notify('Joining.');
roomClient.resumeAudio();
}}
className='button'
>
<span>Allow</span>
</div>
</div>
</div>
</Appear>
</Fragment>
);
}
else if (room.lockedOut)
{ {
return ( return (
<Fragment> <Fragment>
@ -186,6 +212,7 @@ class Room extends React.Component
Room.propTypes = Room.propTypes =
{ {
roomClient : PropTypes.object.isRequired,
room : appPropTypes.Room.isRequired, room : appPropTypes.Room.isRequired,
me : appPropTypes.Me.isRequired, me : appPropTypes.Me.isRequired,
amActiveSpeaker : PropTypes.bool.isRequired, amActiveSpeaker : PropTypes.bool.isRequired,
@ -228,9 +255,9 @@ const mapDispatchToProps = (dispatch) =>
}; };
}; };
const RoomContainer = connect( const RoomContainer = withRoomContext(connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(Room); )(Room));
export default RoomContainer; export default RoomContainer;

View File

@ -120,7 +120,7 @@ function run()
// TODO: Debugging stuff. // TODO: Debugging stuff.
global.CLIENT = roomClient; global.CLIENT = roomClient;
setInterval(() => /* setInterval(() =>
{ {
if (!roomClient._room.peers[0]) if (!roomClient._room.peers[0])
{ {
@ -133,7 +133,7 @@ setInterval(() =>
global.CONSUMER = peer.consumers[peer.consumers.length - 1]; global.CONSUMER = peer.consumers[peer.consumers.length - 1];
}, 2000); }, 2000);
*/
global.sendSdp = function() global.sendSdp = function()
{ {
logger.debug('---------- SEND_TRANSPORT LOCAL SDP OFFER:'); logger.debug('---------- SEND_TRANSPORT LOCAL SDP OFFER:');

View File

@ -4,6 +4,7 @@ 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,
activeSpeakerName : null, activeSpeakerName : null,
torrentSupport : false, torrentSupport : false,
showSettings : false, showSettings : false,
@ -52,6 +53,13 @@ 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_ROOM_ACTIVE_SPEAKER': case 'SET_ROOM_ACTIVE_SPEAKER':
{ {
const { peerName } = action.payload; const { peerName } = action.payload;

View File

@ -43,6 +43,14 @@ export const setRoomLockedOut = () =>
}; };
}; };
export const setAudioSuspended = ({ audioSuspended }) =>
{
return {
type : 'SET_AUDIO_SUSPENDED',
payload : { audioSuspended }
};
};
export const setMe = ({ peerName, displayName, displayNameSet, device, loginEnabled }) => export const setMe = ({ peerName, displayName, displayNameSet, device, loginEnabled }) =>
{ {
return { return {

View File

@ -15,6 +15,34 @@
padding: 2vmin; padding: 2vmin;
} }
> .sound-suspended {
position: fixed;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
width: 30vw;
text-align: center;
font-family: 'Roboto';
font-size: 2.5em;
box-shadow: 0px 5px 12px 2px rgba(17, 17, 17, 0.5);
background-color: #fff;
padding: 2vmin;
> .button {
font-size: 1.5em;
padding: 1.5vmin;
margin: 0.8vmin;
background-color: #38cd8b;
border-radius: 1.8vmin;
color: #fff;
border: 0;
}
> .button:hover {
background-color: #28bd7b;
}
}
> .room-wrapper { > .room-wrapper {
position: absolute; position: absolute;
top: 0; top: 0;