add initial network logic

This commit is contained in:
Joao Siebel 2019-04-18 18:15:48 -03:00
parent dcbce93e7c
commit 08d177dac0
13 changed files with 186 additions and 21 deletions

View File

@ -0,0 +1,9 @@
import { Meteor } from 'meteor/meteor';
const NetworkInformation = new Mongo.Collection('network-information');
if (Meteor.isServer) {
NetworkInformation._ensureIndex({ meetingId: 1 });
}
export default NetworkInformation;

View File

@ -0,0 +1,2 @@
import './methods';
import './publisher';

View File

@ -0,0 +1,6 @@
import { Meteor } from 'meteor/meteor';
import userInstabilityDetected from './methods/userInstabilityDetected';
Meteor.methods({
userInstabilityDetected,
});

View File

@ -0,0 +1,22 @@
import { check } from 'meteor/check';
import NetworkInformation from '/imports/api/network-information';
import Logger from '/imports/startup/server/logger';
export default function userInstabilityDetected(credentials, sender) {
const { meetingId, requesterUserId: receiver } = credentials;
check(meetingId, String);
check(receiver, String);
check(sender, String);
const payload = {
time: new Date().getTime(),
meetingId,
receiver,
sender,
};
Logger.debug(`Receiver ${receiver} reported a network instability`);
return NetworkInformation.insert(payload);
}

View File

@ -0,0 +1,21 @@
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import NetworkInformation from '/imports/api/network-information';
function networkInformation(credentials) {
const { meetingId } = credentials;
check(meetingId, String);
return NetworkInformation.find({
meetingId,
});
}
function publish(...args) {
const boundNetworkInformation = networkInformation.bind(this);
return boundNetworkInformation(...args);
}
Meteor.publish('network-information', publish);

View File

@ -4,7 +4,6 @@ import RedisPubSub from '/imports/startup/server/redis';
import Logger from '/imports/startup/server/logger';
import setEffectiveConnectionType from '../modifiers/setUserEffectiveConnectionType';
// http://wicg.github.io/netinfo/#effective-connection-types
export default function setUserEffectiveConnectionType(credentials, effectiveConnectionType) {
const REDIS_CONFIG = Meteor.settings.private.redis;
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;

View File

@ -202,7 +202,7 @@ Base.defaultProps = defaultProps;
const SUBSCRIPTIONS_NAME = [
'users', 'meetings', 'polls', 'presentations',
'slides', 'captions', 'voiceUsers', 'whiteboard-multi-user', 'screenshare',
'group-chat', 'presentation-pods', 'users-settings', 'guestUser',
'group-chat', 'presentation-pods', 'users-settings', 'guestUser', 'network-information',
];
const BaseContainer = withTracker(() => {

View File

@ -3,15 +3,15 @@ import cx from 'classnames';
import { styles } from './styles';
const SLOW_CONNECTIONS_TYPES = {
'slow-2g': {
critical: {
level: styles.bad,
bars: styles.oneBar,
},
'2g': {
danger: {
level: styles.bad,
bars: styles.twoBars,
},
'3g': {
warning: {
level: styles.warning,
bars: styles.threeBars,
},

View File

@ -4,7 +4,6 @@ import Icon from '/imports/ui/components/icon/component';
import SlowConnection from '/imports/ui/components/slow-connection/component';
import { styles } from './styles';
// https://github.com/bigbluebutton/bigbluebutton/issues/5286#issuecomment-465342716
const SLOW_CONNECTIONS_TYPES = Meteor.settings.public.app.effectiveConnection;
const propTypes = {

View File

@ -185,7 +185,7 @@ class VideoProvider extends Component {
this.customGetStats(peer.peerConnection, peer.peerConnection.getRemoteStreams()[0].getVideoTracks()[0], (stats => updateWebcamStats(id, stats)));
}
});
}, 10000);
}, 5000);
}
componentWillUpdate({ users, userId }) {
@ -560,7 +560,6 @@ class VideoProvider extends Component {
if (this.webRtcPeers[id].peerConnection) {
this.webRtcPeers[id].peerConnection.oniceconnectionstatechange = this._getOnIceConnectionStateChangeCallback(id);
}
console.log('VideoProvider.createWebRTCPeer', this.webRtcPeers);
newWebcamConnection({ userId: id, peer: this.webRtcPeers[id] });
currentWebcamConnections(this.webRtcPeers);
}
@ -769,6 +768,7 @@ class VideoProvider extends Component {
encodeUsagePercent: videoInOrOutbound.encodeUsagePercent,
rtt: videoInOrOutbound.rtt,
currentDelay: videoInOrOutbound.currentDelay,
pliCount: videoInOrOutbound.pliCount,
};
const videoStatsArray = statsState;
@ -827,6 +827,7 @@ class VideoProvider extends Component {
encodeUsagePercent: videoStats.encodeUsagePercent,
rtt: videoStats.rtt,
currentDelay: videoStats.currentDelay,
pliCount: videoStats.pliCount,
},
};

View File

@ -1,4 +1,8 @@
const NetworkInformationCollection = new Mongo.Collection(null);
import NetworkInformation from '/imports/api/network-information';
import { makeCall } from '/imports/ui/services/api';
import Auth from '/imports/ui/services/auth';
const NetworkInformationLocal = new Mongo.Collection(null);
const NAVIGATOR_CONNECTION = 'NAVIGATOR_CONNECTION';
const NUMBER_OF_WEBCAMS_CHANGED = 'NUMBER_OF_WEBCAMS_CHANGED';
@ -6,6 +10,11 @@ const STARTED_WEBCAM_SHARING = 'STARTED_WEBCAM_SHARING';
const STOPPED_WEBCAM_SHARING = 'STOPPED_WEBCAM_SHARING';
const WEBCAMS_GET_STATUS = 'WEBCAMS_GET_STATUS';
const DANGER_BEGIN_TIME = 5000;
const DANGER_END_TIME = 30000;
const WARNING_END_TIME = 60000;
let monitoringIntervalRef;
export const currentWebcamConnections = (webrtcConnections) => {
@ -15,7 +24,7 @@ export const currentWebcamConnections = (webrtcConnections) => {
payload: Object.keys(webrtcConnections),
};
NetworkInformationCollection.insert(doc);
NetworkInformationLocal.insert(doc);
};
export const deleteWebcamConnection = (id) => {
@ -25,10 +34,10 @@ export const deleteWebcamConnection = (id) => {
payload: { id },
};
NetworkInformationCollection.insert(doc);
NetworkInformationLocal.insert(doc);
};
export const getCurrentWebcams = () => NetworkInformationCollection
export const getCurrentWebcams = () => NetworkInformationLocal
.findOne({
event: NUMBER_OF_WEBCAMS_CHANGED,
}, { sort: { timestamp: -1 } });
@ -45,13 +54,74 @@ export const newWebcamConnection = (webRtcPeer) => {
},
};
NetworkInformationCollection.insert(doc);
NetworkInformationLocal.insert(doc);
};
export const startBandwidthMonitoring = () => {
monitoringIntervalRef = setInterval(() => {
console.log('startBandwidthMonitoring', NetworkInformationCollection.find({}).fetch());
}, 15000);
const monitoringTime = new Date().getTime();
const dangerLowerBoundary = monitoringTime - DANGER_BEGIN_TIME;
const warningLowerBoundary = monitoringTime - DANGER_END_TIME;
const warningUpperBoundary = monitoringTime - WARNING_END_TIME;
const warningZone = NetworkInformationLocal
.find({
event: WEBCAMS_GET_STATUS,
timestamp: { $lte: warningLowerBoundary, $gt: warningUpperBoundary },
$or: [
{
'payload.id': Auth.userID,
'payload.stats.deltaPliCount': { $gt: 0 },
},
{
'payload.id': { $ne: Auth.userID },
'payload.stats.deltaPacketsLost': { $gt: 0 },
},
],
}).count();
const warningZoneReceivers = NetworkInformation
.find({
sender: Auth.userID,
time: { $lte: warningLowerBoundary, $gt: warningUpperBoundary },
}).count();
const dangerZone = NetworkInformationLocal
.find({
event: WEBCAMS_GET_STATUS,
timestamp: { $lt: dangerLowerBoundary, $gte: warningLowerBoundary },
$or: [
{
'payload.id': Auth.userID,
'payload.stats.deltaPliCount': { $gt: 0 },
},
{
'payload.id': { $ne: Auth.userID },
'payload.stats.deltaPacketsLost': { $gt: 0 },
},
],
}).count();
const dangerZoneReceivers = NetworkInformation
.find({
sender: Auth.userID,
time: { $lt: dangerLowerBoundary, $gte: warningLowerBoundary },
}).count();
if (warningZoneReceivers && !dangerZone) {
if (!warningZoneReceivers) {
makeCall('setUserEffectiveConnectionType', 'warning');
}
} else if (dangerZone) {
if (!dangerZoneReceivers) {
makeCall('setUserEffectiveConnectionType', 'danger');
}
} else {
makeCall('setUserEffectiveConnectionType', '');
}
}, 5000);
};
export const stopBandwidthMonitoring = () => {
@ -69,12 +139,18 @@ export const updateNavigatorConnection = ({ effectiveType, downlink, rtt }) => {
},
};
NetworkInformationCollection.insert(doc);
NetworkInformationLocal.insert(doc);
};
export const updateWebcamStats = (id, stats) => {
if (!stats) return;
const lastStatus = NetworkInformationLocal
.findOne(
{ event: WEBCAMS_GET_STATUS, 'payload.id': id },
{ sort: { timestamp: -1 } },
);
const { video } = stats;
const doc = {
@ -83,11 +159,39 @@ export const updateWebcamStats = (id, stats) => {
payload: { id, stats: video },
};
NetworkInformationCollection.insert(doc);
if (lastStatus) {
const {
payload: {
stats: {
packetsLost,
packetsReceived,
packetsSent,
pliCount,
},
},
} = lastStatus;
const normalizedVideo = { ...video };
normalizedVideo.deltaPacketsLost = video.packetsLost - packetsLost;
normalizedVideo.deltaPacketsReceived = video.packetsReceived - packetsReceived;
normalizedVideo.deltaPacketsSent = video.packetsSent - packetsSent;
normalizedVideo.deltaPliCount = video.pliCount - pliCount;
doc.payload = {
id,
stats: normalizedVideo,
};
if (normalizedVideo.deltaPacketsLost > 0) {
makeCall('userInstabilityDetected', id);
}
}
NetworkInformationLocal.insert(doc);
};
export default {
NetworkInformationCollection,
NetworkInformationLocal,
currentWebcamConnections,
deleteWebcamConnection,
getCurrentWebcams,

View File

@ -83,9 +83,10 @@ public:
showHelpButton: true
enableExternalVideo: true
effectiveConnection:
- slow-2g
- 2g
- 3g
- critical
- danger
- warning
- good
kurento:
wsUrl: HOST
chromeDefaultExtensionKey: akgoaoikmbmhcopjgakkcepdgdgkjfbc

View File

@ -19,6 +19,7 @@ import '/imports/api/users-settings/server';
import '/imports/api/voice-users/server';
import '/imports/api/whiteboard-multi-user/server';
import '/imports/api/video/server';
import '/imports/api/network-information/server';
import '/imports/api/external-videos/server';
import '/imports/api/guest-users/server';