fix suspended Web Audio context / fixed delayed getUsermedia if user has to interact -> broken audio/video on one side
parent
bdfe2c32cc
commit
f03a84ef28
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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:');
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue