diff --git a/app/package.json b/app/package.json
index 1dab672..583dd08 100644
--- a/app/package.json
+++ b/app/package.json
@@ -32,6 +32,7 @@
"react-router-dom": "^5.1.2",
"react-scripts": "3.4.1",
"react-wakelock-react16": "0.0.7",
+ "react-wifi-indicator": "^1.0.1",
"redux": "^4.0.4",
"redux-logger": "^3.0.6",
"redux-persist": "^6.0.0",
diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js
index 630851a..5d6efad 100644
--- a/app/src/RoomClient.js
+++ b/app/src/RoomClient.js
@@ -257,6 +257,7 @@ export default class RoomClient
this._startKeyListener();
this._startDevicesListener();
+
}
close()
@@ -594,6 +595,21 @@ export default class RoomClient
});
}
+ async getTransportStats(transportId)
+ {
+
+ logger.debug('getTransportStats() [transportId: "%s"]', transportId);
+
+ try
+ {
+ return await this.sendRequest('getTransportStats', { transportId: transportId });
+ }
+ catch (error)
+ {
+ logger.error('getTransportStats() | failed: %o', error);
+ }
+ }
+
async changeDisplayName(displayName)
{
logger.debug('changeDisplayName() [displayName:"%s"]', displayName);
@@ -1959,6 +1975,7 @@ export default class RoomClient
{
switch (notification.method)
{
+
case 'enteredLobby':
{
store.dispatch(roomActions.setInLobby(true));
diff --git a/app/src/components/Controls/NetworkIndicator.js b/app/src/components/Controls/NetworkIndicator.js
new file mode 100644
index 0000000..a888386
--- /dev/null
+++ b/app/src/components/Controls/NetworkIndicator.js
@@ -0,0 +1,259 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import {
+ peersLengthSelector
+} from '../Selectors';
+import * as appPropTypes from '../appPropTypes';
+import { withRoomContext } from '../../RoomContext';
+import { withStyles } from '@material-ui/core/styles';
+import WifiIndicator from 'react-wifi-indicator';
+import Logger from '../../Logger';
+
+const logger = new Logger('NetworkIndicator');
+
+const styles = () =>
+ ({
+ root : {
+ verticalAlign : 'middle',
+ '& img' : {
+ display : 'inline',
+ width : '1.7em',
+ height : '1.7em',
+ margin : '10px'
+ }
+ },
+
+ label : {
+ color : 'white'
+ },
+
+ strength :
+ {
+ margin : 0,
+ padding : 0
+ }
+
+ });
+
+class NetworkIndicator extends React.Component
+{
+ constructor(props)
+ {
+ super(props);
+
+ this.state = {
+ strengthScale : {
+ 1 : 'EXCELLENT',
+ 2 : 'GREAT',
+ 3 : 'OKAY',
+ 4 : 'WEAK',
+ 5 : 'UNUSABLE',
+ 6 : 'DISCONNECTED'
+ },
+ strength : 6,
+ bitrate : null,
+ recv : {},
+ send : {},
+ probe : [],
+ currBitrate : 0,
+ maxBitrate : 0,
+ avgBitrate : 0,
+ medBitrate : 0
+ };
+ }
+
+ // const intl = useIntl();
+ async handleUpdateStrength()
+ {
+ // if (this.props.peersLength == 0)
+ // {
+
+ const percent = this.state.percent;
+
+ logger.warn('[percent: "%s"]', percent);
+
+ switch (true)
+ {
+ case (percent <= 20):
+
+ await this.setState({ strength: 5 });
+ break;
+
+ case (percent <= 40):
+
+ await this.setState({ strength: 4 });
+ break;
+
+ case (percent <= 60):
+
+ await this.setState({ strength: 3 });
+ break;
+
+ case (percent <= 80):
+
+ await this.setState({ strength: 2 });
+ break;
+
+ case (percent <= 100):
+
+ await this.setState({ strength: 1 });
+ break;
+
+ default:
+ break;
+ }
+
+ // }
+ // else
+ // {
+ // this.setState({ strength: 6 });
+ // }
+ }
+
+ async handleGetData()
+ {
+ const rc = this.props.roomClient;
+
+ const recv = await rc.getTransportStats(rc._recvTransport.id);
+
+ const send = await rc.getTransportStats(rc._sendTransport.id);
+
+ // current
+ const currBitrate = Math.round(send[0].recvBitrate / 1024 / 8); // in kb
+
+ // probe
+ const probe = [ ...this.state.probe ]; // clone
+
+ const sec = new Date().getSeconds()
+ .toString()
+ .split('')
+ .map(Number)[1];
+
+ probe[sec] = currBitrate; // add/update next element
+
+ // median
+ const med = (arr) =>
+ {
+ const mid = Math.floor(arr.length / 2);
+ const nums = [ ...arr ].sort((a, b) => a - b);
+
+ return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
+ };
+
+ const medBitrate = med([ ...probe ]);
+
+ // maximum
+ let maxBitrate = Math.max(...probe);
+
+ maxBitrate = (currBitrate > maxBitrate) ? currBitrate : maxBitrate;
+
+ // average
+ const avgBitrate = [ ...probe ]
+ .map((x, i, avgBitrate) => x/avgBitrate.length)
+ .reduce((a, b) => a + b);
+
+ const percent =
+ await Math.round(this.state.currBitrate / this.state.medBitrate * 100);
+
+ this.setState({
+ recv : recv[0],
+ send : send[0],
+ probe,
+ currBitrate,
+ maxBitrate,
+ avgBitrate,
+ medBitrate,
+ percent
+ });
+
+ logger.warn('[currBitrate: "%s"]', currBitrate);
+ logger.warn('[maxBitrate: "%s"]', maxBitrate);
+ logger.warn('[medBitrate: "%s"]', medBitrate);
+ logger.warn('[avgBitrate: "%s"]', avgBitrate);
+ }
+
+ componentDidMount()
+ {
+ this.update = setInterval(async () =>
+ {
+ await this.handleGetData();
+ await this.handleUpdateStrength();
+ }, 1000);
+ }
+
+ componentWillUnmount()
+ {
+ clearInterval(this.update);
+ }
+
+ render()
+ {
+ const {
+ classes,
+ advancedMode
+ } = this.props;
+
+ return (
+