add initial network logic
This commit is contained in:
parent
dcbce93e7c
commit
08d177dac0
@ -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;
|
@ -0,0 +1,2 @@
|
||||
import './methods';
|
||||
import './publisher';
|
@ -0,0 +1,6 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import userInstabilityDetected from './methods/userInstabilityDetected';
|
||||
|
||||
Meteor.methods({
|
||||
userInstabilityDetected,
|
||||
});
|
@ -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);
|
||||
}
|
@ -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);
|
@ -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;
|
||||
|
@ -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(() => {
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -83,9 +83,10 @@ public:
|
||||
showHelpButton: true
|
||||
enableExternalVideo: true
|
||||
effectiveConnection:
|
||||
- slow-2g
|
||||
- 2g
|
||||
- 3g
|
||||
- critical
|
||||
- danger
|
||||
- warning
|
||||
- good
|
||||
kurento:
|
||||
wsUrl: HOST
|
||||
chromeDefaultExtensionKey: akgoaoikmbmhcopjgakkcepdgdgkjfbc
|
||||
|
@ -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';
|
||||
|
Loading…
Reference in New Issue
Block a user