@webex/plugin-meetings 2.19.1 → 2.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -300
- package/dist/constants.js +3 -206
- package/dist/constants.js.map +1 -1
- package/dist/meeting/index.js +352 -489
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +4 -213
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +0 -28
- package/dist/meetings/index.js.map +1 -1
- package/dist/statsAnalyzer/index.js +145 -86
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/package.json +5 -7
- package/src/constants.ts +1 -214
- package/src/meeting/index.js +110 -208
- package/src/meeting/util.js +4 -252
- package/src/meetings/index.js +0 -22
- package/src/statsAnalyzer/index.js +164 -99
- package/test/integration/spec/journey.js +2 -67
- package/test/unit/spec/meeting/index.js +88 -29
- package/test/unit/spec/meeting/utils.js +0 -2
- package/test/unit/spec/stats-analyzer/index.js +209 -1
- package/dist/analyzer/analyzer.js +0 -113
- package/dist/analyzer/analyzer.js.map +0 -1
- package/dist/analyzer/calculator.js +0 -87
- package/dist/analyzer/calculator.js.map +0 -1
- package/dist/metrics/mqa-processor.js +0 -170
- package/dist/metrics/mqa-processor.js.map +0 -1
- package/dist/stats/data.js +0 -93
- package/dist/stats/data.js.map +0 -1
- package/dist/stats/events.js +0 -222
- package/dist/stats/events.js.map +0 -1
- package/dist/stats/filter.js +0 -84
- package/dist/stats/filter.js.map +0 -1
- package/dist/stats/history.js +0 -147
- package/dist/stats/history.js.map +0 -1
- package/dist/stats/index.js +0 -425
- package/dist/stats/index.js.map +0 -1
- package/dist/stats/metrics.js +0 -112
- package/dist/stats/metrics.js.map +0 -1
- package/dist/stats/stats.js +0 -592
- package/dist/stats/stats.js.map +0 -1
- package/dist/stats/stream.js +0 -156
- package/dist/stats/stream.js.map +0 -1
- package/dist/stats/transformer.js +0 -126
- package/dist/stats/transformer.js.map +0 -1
- package/dist/stats/util.js +0 -64
- package/dist/stats/util.js.map +0 -1
- package/src/analyzer/analyzer.js +0 -78
- package/src/analyzer/calculator.js +0 -77
- package/src/metrics/mqa-processor.js +0 -118
- package/src/stats/data.js +0 -56
- package/src/stats/events.js +0 -185
- package/src/stats/filter.js +0 -40
- package/src/stats/history.js +0 -107
- package/src/stats/index.js +0 -320
- package/src/stats/metrics.js +0 -95
- package/src/stats/stats.js +0 -477
- package/src/stats/stream.js +0 -108
- package/src/stats/transformer.js +0 -109
- package/src/stats/util.js +0 -44
|
@@ -11,6 +11,8 @@ import {Credentials} from '@webex/webex-core';
|
|
|
11
11
|
import Support from '@webex/internal-plugin-support';
|
|
12
12
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
13
13
|
|
|
14
|
+
import * as StatsAnalyzerModule from '@webex/plugin-meetings/src/statsAnalyzer';
|
|
15
|
+
import EventsScope from '@webex/plugin-meetings/src/common/events/events-scope';
|
|
14
16
|
import Meetings, {CONSTANTS} from '@webex/plugin-meetings';
|
|
15
17
|
import Meeting from '@webex/plugin-meetings/src/meeting';
|
|
16
18
|
import Members from '@webex/plugin-meetings/src/members';
|
|
@@ -18,7 +20,6 @@ import Roap from '@webex/plugin-meetings/src/roap';
|
|
|
18
20
|
import MeetingRequest from '@webex/plugin-meetings/src/meeting/request';
|
|
19
21
|
import LocusInfo from '@webex/plugin-meetings/src/locus-info';
|
|
20
22
|
import MediaProperties from '@webex/plugin-meetings/src/media/properties';
|
|
21
|
-
import WebRTCStats from '@webex/plugin-meetings/src/stats';
|
|
22
23
|
import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
|
|
23
24
|
import Media from '@webex/plugin-meetings/src/media/index';
|
|
24
25
|
import PeerConnectionManager from '@webex/plugin-meetings/src/peer-connection-manager';
|
|
@@ -206,7 +207,6 @@ describe('plugin-meetings', () => {
|
|
|
206
207
|
);
|
|
207
208
|
|
|
208
209
|
meeting.members.selfId = uuid1;
|
|
209
|
-
meeting.startMediaQualityMetrics = sinon.stub();
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
describe('meeting index', () => {
|
|
@@ -229,7 +229,6 @@ describe('plugin-meetings', () => {
|
|
|
229
229
|
assert.isNull(meeting.audio);
|
|
230
230
|
assert.isNull(meeting.video);
|
|
231
231
|
assert.instanceOf(meeting.meetingFiniteStateMachine, StateMachine);
|
|
232
|
-
assert.isNull(meeting.stats);
|
|
233
232
|
assert.isNull(meeting.conversationUrl);
|
|
234
233
|
assert.equal(meeting.locusUrl, url1);
|
|
235
234
|
assert.isNull(meeting.sipUri);
|
|
@@ -307,19 +306,6 @@ describe('plugin-meetings', () => {
|
|
|
307
306
|
assert.instanceOf(members, Members);
|
|
308
307
|
});
|
|
309
308
|
});
|
|
310
|
-
describe('#getStats', () => {
|
|
311
|
-
it('should have #getStats', () => {
|
|
312
|
-
assert.exists(meeting.getStats);
|
|
313
|
-
});
|
|
314
|
-
it('should create stats if not exists and return WebRTCStats', () => {
|
|
315
|
-
assert.notOk(meeting.stats);
|
|
316
|
-
meeting.createStats = sinon.stub().returns(new WebRTCStats({}, {parent: webex}));
|
|
317
|
-
const stats = meeting.getStats();
|
|
318
|
-
|
|
319
|
-
assert.calledOnce(meeting.createStats);
|
|
320
|
-
assert.instanceOf(stats, WebRTCStats);
|
|
321
|
-
});
|
|
322
|
-
});
|
|
323
309
|
describe('#isAudioMuted', () => {
|
|
324
310
|
it('should have #isAudioMuted', () => {
|
|
325
311
|
assert.exists(meeting.invite);
|
|
@@ -901,14 +887,12 @@ describe('plugin-meetings', () => {
|
|
|
901
887
|
Media.attachMedia = sinon.stub().returns(Promise.resolve([test1, test2]));
|
|
902
888
|
meeting.setMercuryListener = sinon.stub().returns(true);
|
|
903
889
|
meeting.setRemoteStream = sinon.stub().returns(true);
|
|
904
|
-
meeting.startMediaQualityMetrics = sinon.stub();
|
|
905
890
|
meeting.setMercuryListener = sinon.stub();
|
|
906
891
|
meeting.roap.sendRoapMediaRequest = sinon.stub().returns(new Promise((resolve) => {
|
|
907
892
|
meeting.mediaProperties.peerConnection.connectionState = CONSTANTS.CONNECTION_STATE.CONNECTED;
|
|
908
893
|
resolve();
|
|
909
894
|
}));
|
|
910
895
|
PeerConnectionManager.setContentSlides = sinon.stub().returns(true);
|
|
911
|
-
MeetingUtil.startInternalStats = sinon.stub();
|
|
912
896
|
});
|
|
913
897
|
|
|
914
898
|
it('should have #addMedia', () => {
|
|
@@ -1037,7 +1021,6 @@ describe('plugin-meetings', () => {
|
|
|
1037
1021
|
/* statsAnalyzer is initiated inside of addMedia so there isn't
|
|
1038
1022
|
* a good way to mock it without mocking the constructor
|
|
1039
1023
|
*/
|
|
1040
|
-
// assert.calledOnce(meeting.startMediaQualityMetrics);
|
|
1041
1024
|
});
|
|
1042
1025
|
|
|
1043
1026
|
it('should attach the media and return promise', async () => {
|
|
@@ -1052,6 +1035,90 @@ describe('plugin-meetings', () => {
|
|
|
1052
1035
|
assert.instanceOf(err, WebExMeetingsErrors);
|
|
1053
1036
|
});
|
|
1054
1037
|
});
|
|
1038
|
+
|
|
1039
|
+
describe('handles StatsAnalyzer events', () => {
|
|
1040
|
+
let prevConfigValue;
|
|
1041
|
+
let statsAnalyzerStub;
|
|
1042
|
+
|
|
1043
|
+
beforeEach(async () => {
|
|
1044
|
+
meeting.meetingState = 'ACTIVE';
|
|
1045
|
+
prevConfigValue = meeting.config.stats.enableStatsAnalyzer;
|
|
1046
|
+
|
|
1047
|
+
meeting.config.stats.enableStatsAnalyzer = true;
|
|
1048
|
+
|
|
1049
|
+
statsAnalyzerStub = new EventsScope();
|
|
1050
|
+
// mock the StatsAnalyzer constructor
|
|
1051
|
+
sinon.stub(StatsAnalyzerModule, 'StatsAnalyzer').returns(statsAnalyzerStub);
|
|
1052
|
+
|
|
1053
|
+
await meeting.addMedia({
|
|
1054
|
+
mediaSettings: {}
|
|
1055
|
+
});
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
afterEach(() => {
|
|
1059
|
+
meeting.config.stats.enableStatsAnalyzer = prevConfigValue;
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
it('LOCAL_MEDIA_STARTED triggers "meeting:media:local:start" event and sends metrics', async () => {
|
|
1063
|
+
statsAnalyzerStub.emit({file: 'test', function: 'test'}, StatsAnalyzerModule.EVENTS.LOCAL_MEDIA_STARTED, {type: 'audio'});
|
|
1064
|
+
|
|
1065
|
+
assert.calledWith(
|
|
1066
|
+
TriggerProxy.trigger,
|
|
1067
|
+
sinon.match.instanceOf(Meeting),
|
|
1068
|
+
{
|
|
1069
|
+
file: 'meeting/index',
|
|
1070
|
+
function: 'addMedia'
|
|
1071
|
+
},
|
|
1072
|
+
EVENT_TRIGGERS.MEETING_MEDIA_LOCAL_STARTED,
|
|
1073
|
+
{
|
|
1074
|
+
type: 'audio'
|
|
1075
|
+
}
|
|
1076
|
+
);
|
|
1077
|
+
assert.calledWithMatch(Metrics.postEvent, {event: eventType.SENDING_MEDIA_START, data: {mediaType: 'audio'}});
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
it('LOCAL_MEDIA_STOPPED triggers the right metrics', async () => {
|
|
1081
|
+
statsAnalyzerStub.emit({file: 'test', function: 'test'}, StatsAnalyzerModule.EVENTS.LOCAL_MEDIA_STOPPED, {type: 'video'});
|
|
1082
|
+
|
|
1083
|
+
assert.calledWithMatch(Metrics.postEvent, {event: eventType.SENDING_MEDIA_STOP, data: {mediaType: 'video'}});
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
it('REMOTE_MEDIA_STARTED triggers "meeting:media:remote:start" event and sends metrics', async () => {
|
|
1087
|
+
statsAnalyzerStub.emit({file: 'test', function: 'test'}, StatsAnalyzerModule.EVENTS.REMOTE_MEDIA_STARTED, {type: 'video'});
|
|
1088
|
+
|
|
1089
|
+
assert.calledWith(
|
|
1090
|
+
TriggerProxy.trigger,
|
|
1091
|
+
sinon.match.instanceOf(Meeting),
|
|
1092
|
+
{
|
|
1093
|
+
file: 'meeting/index',
|
|
1094
|
+
function: 'addMedia'
|
|
1095
|
+
},
|
|
1096
|
+
EVENT_TRIGGERS.MEETING_MEDIA_REMOTE_STARTED,
|
|
1097
|
+
{
|
|
1098
|
+
type: 'video'
|
|
1099
|
+
}
|
|
1100
|
+
);
|
|
1101
|
+
assert.calledWithMatch(Metrics.postEvent, {event: eventType.RECEIVING_MEDIA_START, data: {mediaType: 'video'}});
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
it('REMOTE_MEDIA_STOPPED triggers the right metrics', async () => {
|
|
1105
|
+
statsAnalyzerStub.emit({file: 'test', function: 'test'}, StatsAnalyzerModule.EVENTS.REMOTE_MEDIA_STOPPED, {type: 'audio'});
|
|
1106
|
+
|
|
1107
|
+
assert.calledWithMatch(Metrics.postEvent, {event: eventType.RECEIVING_MEDIA_STOP, data: {mediaType: 'audio'}});
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
it('MEDIA_QUALITY triggers the right metrics', async () => {
|
|
1111
|
+
const fakeData = {intervalMetadata: {bla: 'bla'}};
|
|
1112
|
+
|
|
1113
|
+
statsAnalyzerStub.emit(
|
|
1114
|
+
{file: 'test', function: 'test'},
|
|
1115
|
+
StatsAnalyzerModule.EVENTS.MEDIA_QUALITY,
|
|
1116
|
+
{data: fakeData, networkType: 'wifi'}
|
|
1117
|
+
);
|
|
1118
|
+
|
|
1119
|
+
assert.calledWithMatch(Metrics.postEvent, {event: eventType.MEDIA_QUALITY, data: {intervalData: fakeData, networkType: 'wifi'}});
|
|
1120
|
+
});
|
|
1121
|
+
});
|
|
1055
1122
|
});
|
|
1056
1123
|
describe('#acknowledge', () => {
|
|
1057
1124
|
it('should have #acknowledge', () => {
|
|
@@ -1123,7 +1190,7 @@ describe('plugin-meetings', () => {
|
|
|
1123
1190
|
meeting.unsetLocalVideoTrack = sinon.stub().returns(true);
|
|
1124
1191
|
meeting.unsetLocalShareTrack = sinon.stub().returns(true);
|
|
1125
1192
|
meeting.unsetRemoteTracks = sinon.stub();
|
|
1126
|
-
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub()};
|
|
1193
|
+
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
|
1127
1194
|
meeting.unsetRemoteStream = sinon.stub().returns(true);
|
|
1128
1195
|
meeting.unsetPeerConnections = sinon.stub().returns(true);
|
|
1129
1196
|
meeting.roap.stop = sinon.stub().returns(Promise.resolve());
|
|
@@ -2618,7 +2685,7 @@ describe('plugin-meetings', () => {
|
|
|
2618
2685
|
meeting.unsetLocalVideoTrack = sinon.stub().returns(true);
|
|
2619
2686
|
meeting.unsetLocalShareTrack = sinon.stub().returns(true);
|
|
2620
2687
|
meeting.unsetRemoteTracks = sinon.stub();
|
|
2621
|
-
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub()};
|
|
2688
|
+
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
|
2622
2689
|
meeting.unsetRemoteStream = sinon.stub().returns(true);
|
|
2623
2690
|
meeting.unsetPeerConnections = sinon.stub().returns(true);
|
|
2624
2691
|
meeting.roap.stop = sinon.stub().returns(Promise.resolve());
|
|
@@ -3306,14 +3373,6 @@ describe('plugin-meetings', () => {
|
|
|
3306
3373
|
assert.calledOnce(meeting.mediaProperties.unsetPeerConnection);
|
|
3307
3374
|
});
|
|
3308
3375
|
});
|
|
3309
|
-
describe('#createStats', () => {
|
|
3310
|
-
it('should create stats for the meeting object', () => {
|
|
3311
|
-
const stats = meeting.createStats();
|
|
3312
|
-
|
|
3313
|
-
assert.instanceOf(stats, WebRTCStats);
|
|
3314
|
-
assert.instanceOf(meeting.getStats(), WebRTCStats);
|
|
3315
|
-
});
|
|
3316
|
-
});
|
|
3317
3376
|
describe('#parseMeetingInfo', () => {
|
|
3318
3377
|
const checkParseMeetingInfo = (expectedInfoToParse) => {
|
|
3319
3378
|
assert.equal(meeting.conversationUrl, expectedInfoToParse.conversationUrl);
|
|
@@ -40,7 +40,6 @@ describe('plugin-meetings', () => {
|
|
|
40
40
|
meeting.unsetLocalShareTrack = sinon.stub();
|
|
41
41
|
meeting.unsetRemoteTracks = sinon.stub();
|
|
42
42
|
meeting.unsetPeerConnections = sinon.stub();
|
|
43
|
-
meeting.cleanMQAInterval = sinon.stub();
|
|
44
43
|
meeting.reconnectionManager = {cleanUp: sinon.stub()};
|
|
45
44
|
meeting.roap = {stop: sinon.stub()};
|
|
46
45
|
});
|
|
@@ -62,7 +61,6 @@ describe('plugin-meetings', () => {
|
|
|
62
61
|
assert.calledOnce(meeting.unsetLocalShareTrack);
|
|
63
62
|
assert.calledOnce(meeting.unsetRemoteTracks);
|
|
64
63
|
assert.calledOnce(meeting.unsetPeerConnections);
|
|
65
|
-
assert.calledOnce(meeting.cleanMQAInterval);
|
|
66
64
|
assert.calledOnce(meeting.reconnectionManager.cleanUp);
|
|
67
65
|
assert.calledOnce(meeting.roap.stop);
|
|
68
66
|
});
|
|
@@ -3,8 +3,9 @@ import chai from 'chai';
|
|
|
3
3
|
import chaiAsPromised from 'chai-as-promised';
|
|
4
4
|
import sinon from 'sinon';
|
|
5
5
|
|
|
6
|
-
import StatsAnalyzer from '../../../../src/statsAnalyzer';
|
|
6
|
+
import {StatsAnalyzer, EVENTS} from '../../../../src/statsAnalyzer';
|
|
7
7
|
import NetworkQualityMonitor from '../../../../src/networkQualityMonitor';
|
|
8
|
+
import testUtils from '../../../utils/testUtils';
|
|
8
9
|
|
|
9
10
|
const {assert} = chai;
|
|
10
11
|
|
|
@@ -70,5 +71,212 @@ describe('plugin-meetings', () => {
|
|
|
70
71
|
}));
|
|
71
72
|
});
|
|
72
73
|
});
|
|
74
|
+
|
|
75
|
+
describe('startAnalyzer', () => {
|
|
76
|
+
let clock;
|
|
77
|
+
let pc;
|
|
78
|
+
let networkQualityMonitor;
|
|
79
|
+
let statsAnalyzer;
|
|
80
|
+
|
|
81
|
+
let receivedEventsData = {
|
|
82
|
+
local: {},
|
|
83
|
+
remote: {},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const initialConfig = {
|
|
87
|
+
analyzerInterval: 1000,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
let fakeStats;
|
|
91
|
+
|
|
92
|
+
const resetReceivedEvents = () => {
|
|
93
|
+
receivedEventsData = {
|
|
94
|
+
local: {},
|
|
95
|
+
remote: {},
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
beforeEach(() => {
|
|
100
|
+
clock = sinon.useFakeTimers();
|
|
101
|
+
|
|
102
|
+
resetReceivedEvents();
|
|
103
|
+
|
|
104
|
+
// bytesReceived and bytesSent need to be non-zero in order for StatsAnalyzer to parse any other values
|
|
105
|
+
fakeStats = {
|
|
106
|
+
audio: {
|
|
107
|
+
receiver: {
|
|
108
|
+
type: 'inbound-rtp',
|
|
109
|
+
packetsReceived: 0,
|
|
110
|
+
bytesReceived: 1,
|
|
111
|
+
},
|
|
112
|
+
sender: {
|
|
113
|
+
type: 'outbound-rtp',
|
|
114
|
+
packetsSent: 0,
|
|
115
|
+
bytesSent: 1,
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
video: {
|
|
119
|
+
receiver: {
|
|
120
|
+
type: 'inbound-rtp',
|
|
121
|
+
framesDecoded: 0,
|
|
122
|
+
bytesReceived: 1,
|
|
123
|
+
},
|
|
124
|
+
sender: {
|
|
125
|
+
type: 'outbound-rtp',
|
|
126
|
+
framesSent: 0,
|
|
127
|
+
bytesSent: 1,
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
pc = {
|
|
133
|
+
audioTransceiver: {
|
|
134
|
+
sender: {
|
|
135
|
+
getStats: sinon.stub().resolves([fakeStats.audio.sender])
|
|
136
|
+
},
|
|
137
|
+
receiver: {
|
|
138
|
+
getStats: sinon.stub().resolves([fakeStats.audio.receiver])
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
videoTransceiver: {
|
|
142
|
+
sender: {
|
|
143
|
+
getStats: sinon.stub().resolves([fakeStats.video.sender])
|
|
144
|
+
},
|
|
145
|
+
receiver: {
|
|
146
|
+
getStats: sinon.stub().resolves([fakeStats.video.receiver])
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
shareTransceiver: {
|
|
150
|
+
sender: {
|
|
151
|
+
getStats: sinon.stub().resolves([])
|
|
152
|
+
},
|
|
153
|
+
receiver: {
|
|
154
|
+
getStats: sinon.stub().resolves([])
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
|
|
160
|
+
|
|
161
|
+
statsAnalyzer = new StatsAnalyzer(initialConfig, networkQualityMonitor);
|
|
162
|
+
|
|
163
|
+
statsAnalyzer.on(EVENTS.LOCAL_MEDIA_STARTED, (data) => {
|
|
164
|
+
receivedEventsData.local.started = data;
|
|
165
|
+
});
|
|
166
|
+
statsAnalyzer.on(EVENTS.LOCAL_MEDIA_STOPPED, (data) => {
|
|
167
|
+
receivedEventsData.local.stopped = data;
|
|
168
|
+
});
|
|
169
|
+
statsAnalyzer.on(EVENTS.REMOTE_MEDIA_STARTED, (data) => {
|
|
170
|
+
receivedEventsData.remote.started = data;
|
|
171
|
+
});
|
|
172
|
+
statsAnalyzer.on(EVENTS.REMOTE_MEDIA_STOPPED, (data) => {
|
|
173
|
+
receivedEventsData.remote.stopped = data;
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
afterEach(() => {
|
|
178
|
+
clock.restore();
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const startStatsAnalyzer = async (mediaStatus) => {
|
|
182
|
+
statsAnalyzer.updateMediaStatus(mediaStatus);
|
|
183
|
+
statsAnalyzer.startAnalyzer(pc);
|
|
184
|
+
|
|
185
|
+
await testUtils.flushPromises();
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const progressTime = async () => {
|
|
189
|
+
await clock.tickAsync(initialConfig.analyzerInterval);
|
|
190
|
+
await testUtils.flushPromises();
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const checkReceivedEvent = ({expected}) => {
|
|
194
|
+
// check that we got the REMOTE_MEDIA_STARTED event for audio
|
|
195
|
+
assert.deepEqual(receivedEventsData.local.started, expected.local?.started);
|
|
196
|
+
assert.deepEqual(receivedEventsData.local.stopped, expected.local?.stopped);
|
|
197
|
+
assert.deepEqual(receivedEventsData.remote.started, expected.remote?.started);
|
|
198
|
+
assert.deepEqual(receivedEventsData.remote.stopped, expected.remote?.stopped);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
it('emits LOCAL_MEDIA_STARTED and LOCAL_MEDIA_STOPPED events for audio', async () => {
|
|
202
|
+
await startStatsAnalyzer({expected: {sendAudio: true}});
|
|
203
|
+
|
|
204
|
+
// check that we haven't received any events yet
|
|
205
|
+
checkReceivedEvent({expected: {}});
|
|
206
|
+
|
|
207
|
+
// setup a mock to return some values higher the previous ones
|
|
208
|
+
fakeStats.audio.sender.packetsSent += 10;
|
|
209
|
+
|
|
210
|
+
await progressTime();
|
|
211
|
+
|
|
212
|
+
// check that we got the LOCAL_MEDIA_STARTED event for audio
|
|
213
|
+
checkReceivedEvent({expected: {local: {started: {type: 'audio'}}}});
|
|
214
|
+
|
|
215
|
+
// now advance the clock and the mock still returns same values, so only "stopped" event should be triggered
|
|
216
|
+
resetReceivedEvents();
|
|
217
|
+
await progressTime();
|
|
218
|
+
checkReceivedEvent({expected: {local: {stopped: {type: 'audio'}}}});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('emits LOCAL_MEDIA_STARTED and LOCAL_MEDIA_STOPPED events for video', async () => {
|
|
222
|
+
await startStatsAnalyzer({expected: {sendVideo: true}});
|
|
223
|
+
|
|
224
|
+
// check that we haven't received any events yet
|
|
225
|
+
checkReceivedEvent({expected: {}});
|
|
226
|
+
|
|
227
|
+
// setup a mock to return some values higher the previous ones
|
|
228
|
+
fakeStats.video.sender.framesSent += 1;
|
|
229
|
+
|
|
230
|
+
await progressTime();
|
|
231
|
+
|
|
232
|
+
// check that we got the LOCAL_MEDIA_STARTED event for audio
|
|
233
|
+
checkReceivedEvent({expected: {local: {started: {type: 'video'}}}});
|
|
234
|
+
|
|
235
|
+
// now advance the clock and the mock still returns same values, so only "stopped" event should be triggered
|
|
236
|
+
resetReceivedEvents();
|
|
237
|
+
await progressTime();
|
|
238
|
+
checkReceivedEvent({expected: {local: {stopped: {type: 'video'}}}});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('emits REMOTE_MEDIA_STARTED and REMOTE_MEDIA_STOPPED events for audio', async () => {
|
|
242
|
+
await startStatsAnalyzer({expected: {receiveAudio: true}});
|
|
243
|
+
|
|
244
|
+
// check that we haven't received any events yet
|
|
245
|
+
checkReceivedEvent({expected: {}});
|
|
246
|
+
|
|
247
|
+
// setup a mock to return some values higher the previous ones
|
|
248
|
+
fakeStats.audio.receiver.packetsReceived += 5;
|
|
249
|
+
|
|
250
|
+
await progressTime();
|
|
251
|
+
// check that we got the REMOTE_MEDIA_STARTED event for audio
|
|
252
|
+
checkReceivedEvent({expected: {remote: {started: {type: 'audio'}}}});
|
|
253
|
+
|
|
254
|
+
// now advance the clock and the mock still returns same values, so only "stopped" event should be triggered
|
|
255
|
+
resetReceivedEvents();
|
|
256
|
+
await progressTime();
|
|
257
|
+
|
|
258
|
+
checkReceivedEvent({expected: {remote: {stopped: {type: 'audio'}}}});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('emits REMOTE_MEDIA_STARTED and REMOTE_MEDIA_STOPPED events for video', async () => {
|
|
262
|
+
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
263
|
+
|
|
264
|
+
// check that we haven't received any events yet
|
|
265
|
+
checkReceivedEvent({expected: {}});
|
|
266
|
+
|
|
267
|
+
// setup a mock to return some values higher the previous ones
|
|
268
|
+
fakeStats.video.receiver.framesDecoded += 1;
|
|
269
|
+
|
|
270
|
+
await progressTime();
|
|
271
|
+
// check that we got the REMOTE_MEDIA_STARTED event for video
|
|
272
|
+
checkReceivedEvent({expected: {remote: {started: {type: 'video'}}}});
|
|
273
|
+
|
|
274
|
+
// now advance the clock and the mock still returns same values, so only "stopped" event should be triggered
|
|
275
|
+
resetReceivedEvents();
|
|
276
|
+
await progressTime();
|
|
277
|
+
|
|
278
|
+
checkReceivedEvent({expected: {remote: {stopped: {type: 'video'}}}});
|
|
279
|
+
});
|
|
280
|
+
});
|
|
73
281
|
});
|
|
74
282
|
});
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
4
|
-
|
|
5
|
-
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
6
|
-
|
|
7
|
-
_Object$defineProperty(exports, "__esModule", {
|
|
8
|
-
value: true
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
exports.default = void 0;
|
|
12
|
-
|
|
13
|
-
var _set = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/set"));
|
|
14
|
-
|
|
15
|
-
var _isArray2 = _interopRequireDefault(require("lodash/isArray"));
|
|
16
|
-
|
|
17
|
-
var _isFinite2 = _interopRequireDefault(require("lodash/isFinite"));
|
|
18
|
-
|
|
19
|
-
var _forEach2 = _interopRequireDefault(require("lodash/forEach"));
|
|
20
|
-
|
|
21
|
-
var _constants = require("../constants");
|
|
22
|
-
|
|
23
|
-
var _parameter = _interopRequireDefault(require("../common/errors/parameter"));
|
|
24
|
-
|
|
25
|
-
var StatsAnalyzer = {};
|
|
26
|
-
/**
|
|
27
|
-
* Can involve changing of the default plugin-meetings sdk for deeper results
|
|
28
|
-
* @param {Array} series of WebRTCData
|
|
29
|
-
* @param {Object} options
|
|
30
|
-
* @param {Array} options.analysisKeys [{key: 'bytesSent', check: 'increasing'}, {key: 'bytesReceived', check: 'increasing'}]
|
|
31
|
-
* @returns {Object} analysis {valid: true/false, failed: { key: [number] }, data: { webRtcKeyToAnalyze: { valid: true/false, reports: [ { value: number, valid: true/false, difference: number } ] } } }
|
|
32
|
-
* @public
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
StatsAnalyzer.analyze = function (series) {
|
|
36
|
-
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
|
|
37
|
-
analysisKeys: _constants.ANALYSIS_STATS.DEFAULT_KEYS
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
if (!(0, _isArray2.default)(series) || !series.length || !options || !(0, _isArray2.default)(options.analysisKeys) || !options.analysisKeys.length) {
|
|
41
|
-
throw new _parameter.default('analyzer->analyze#series must be defined as a nonempty array of WebRTCData objects, and options.analysisKeys must be a nonempty array of strings, representing the properties to analyze.');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
var properties = new _set.default(options.analysisKeys);
|
|
45
|
-
var analysis = {
|
|
46
|
-
valid: true,
|
|
47
|
-
failed: {},
|
|
48
|
-
data: {}
|
|
49
|
-
};
|
|
50
|
-
properties.forEach(function (config) {
|
|
51
|
-
var property = config.key;
|
|
52
|
-
analysis.data[property] = {
|
|
53
|
-
valid: true,
|
|
54
|
-
reports: []
|
|
55
|
-
};
|
|
56
|
-
analysis.failed[property] = [];
|
|
57
|
-
var previous = {
|
|
58
|
-
value: 0
|
|
59
|
-
};
|
|
60
|
-
var index = 0;
|
|
61
|
-
|
|
62
|
-
var _loop = function _loop(i) {
|
|
63
|
-
var singular = {};
|
|
64
|
-
(0, _forEach2.default)(series[i].data.getData()[config.prop], function (webrtcData) {
|
|
65
|
-
// eslint-disable-line
|
|
66
|
-
var value = webrtcData[property];
|
|
67
|
-
|
|
68
|
-
if (!value || !(0, _isFinite2.default)(value)) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
singular.value = value;
|
|
73
|
-
singular.difference = 0;
|
|
74
|
-
singular.valid = false;
|
|
75
|
-
singular.index = index;
|
|
76
|
-
singular.difference = singular.value - previous.value;
|
|
77
|
-
|
|
78
|
-
if (config.check === _constants.ANALYSIS_CHECKS.INCREASING && singular.difference > 0) {
|
|
79
|
-
singular.valid = true;
|
|
80
|
-
} else if (config.check === _constants.ANALYSIS_CHECKS.DECREASING && singular.difference < 0) {
|
|
81
|
-
singular.valid = true;
|
|
82
|
-
} else if (config.check === _constants.ANALYSIS_CHECKS.CONSTANT) {
|
|
83
|
-
singular.valid = true;
|
|
84
|
-
} else {
|
|
85
|
-
singular.valid = false;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (!singular.valid) {
|
|
89
|
-
analysis.data[property].valid = false;
|
|
90
|
-
analysis.valid = false;
|
|
91
|
-
analysis.failed[property].push(i);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
previous = singular;
|
|
95
|
-
analysis.data[property].reports.push(singular);
|
|
96
|
-
});
|
|
97
|
-
index += 1;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
for (var i = series.length - 1; i > 0; i -= 1) {
|
|
101
|
-
_loop(i);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (!analysis.data[property].valid) {
|
|
105
|
-
analysis.valid = false;
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
return analysis;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
var _default = StatsAnalyzer;
|
|
112
|
-
exports.default = _default;
|
|
113
|
-
//# sourceMappingURL=analyzer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["StatsAnalyzer","analyze","series","options","analysisKeys","ANALYSIS_STATS","DEFAULT_KEYS","length","ParameterError","properties","analysis","valid","failed","data","forEach","config","property","key","reports","previous","value","index","i","singular","getData","prop","webrtcData","difference","check","ANALYSIS_CHECKS","INCREASING","DECREASING","CONSTANT","push"],"sources":["analyzer.js"],"sourcesContent":["import {forEach, isFinite, isArray} from 'lodash';\n\nimport {\n ANALYSIS_STATS,\n ANALYSIS_CHECKS\n} from '../constants';\nimport ParameterError from '../common/errors/parameter';\n\nconst StatsAnalyzer = {};\n\n/**\n * Can involve changing of the default plugin-meetings sdk for deeper results\n * @param {Array} series of WebRTCData\n * @param {Object} options\n * @param {Array} options.analysisKeys [{key: 'bytesSent', check: 'increasing'}, {key: 'bytesReceived', check: 'increasing'}]\n * @returns {Object} analysis {valid: true/false, failed: { key: [number] }, data: { webRtcKeyToAnalyze: { valid: true/false, reports: [ { value: number, valid: true/false, difference: number } ] } } }\n * @public\n */\nStatsAnalyzer.analyze = (series, options = {analysisKeys: ANALYSIS_STATS.DEFAULT_KEYS}) => {\n if (!isArray(series) || !series.length || !options || !isArray(options.analysisKeys) || !options.analysisKeys.length) {\n throw new ParameterError('analyzer->analyze#series must be defined as a nonempty array of WebRTCData objects, and options.analysisKeys must be a nonempty array of strings, representing the properties to analyze.');\n }\n const properties = new Set(options.analysisKeys);\n const analysis = {valid: true, failed: {}, data: {}};\n\n properties.forEach((config) => {\n const property = config.key;\n\n analysis.data[property] = {valid: true, reports: []};\n analysis.failed[property] = [];\n let previous = {value: 0};\n let index = 0;\n\n for (let i = series.length - 1; i > 0; i -= 1) {\n const singular = {};\n\n forEach(series[i].data.getData()[config.prop], (webrtcData) => { // eslint-disable-line\n const value = webrtcData[property];\n\n if (!value || !isFinite(value)) {\n return;\n }\n singular.value = value;\n singular.difference = 0;\n singular.valid = false;\n singular.index = index;\n singular.difference = singular.value - previous.value;\n if (config.check === ANALYSIS_CHECKS.INCREASING && singular.difference > 0) {\n singular.valid = true;\n }\n else if (config.check === ANALYSIS_CHECKS.DECREASING && singular.difference < 0) {\n singular.valid = true;\n }\n else if (config.check === ANALYSIS_CHECKS.CONSTANT) {\n singular.valid = true;\n }\n else {\n singular.valid = false;\n }\n if (!singular.valid) {\n analysis.data[property].valid = false;\n analysis.valid = false;\n analysis.failed[property].push(i);\n }\n previous = singular;\n analysis.data[property].reports.push(singular);\n });\n index += 1;\n }\n if (!analysis.data[property].valid) {\n analysis.valid = false;\n }\n });\n\n return analysis;\n};\n\nexport default StatsAnalyzer;\n"],"mappings":"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"}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
4
|
-
|
|
5
|
-
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
6
|
-
|
|
7
|
-
_Object$defineProperty(exports, "__esModule", {
|
|
8
|
-
value: true
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
exports.default = void 0;
|
|
12
|
-
|
|
13
|
-
var _isFinite2 = _interopRequireDefault(require("lodash/isFinite"));
|
|
14
|
-
|
|
15
|
-
var _keys2 = _interopRequireDefault(require("lodash/keys"));
|
|
16
|
-
|
|
17
|
-
var _constants = require("../constants");
|
|
18
|
-
|
|
19
|
-
var StatsCalculator = {};
|
|
20
|
-
/**
|
|
21
|
-
* Calculate an interval of values between 2 data points, using updated as the "latest" so updated - previous = interval
|
|
22
|
-
* @param {WebRTCData} previous
|
|
23
|
-
* @param {WebRTCData} updated
|
|
24
|
-
* @returns {Object} interval: {StringKey: IntervalValue, ..., n}
|
|
25
|
-
* @public
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
StatsCalculator.difference = function (previous, updated) {
|
|
29
|
-
// if there was no previous, just take the updated
|
|
30
|
-
if (!previous || !previous.data || !previous.data.getData || (0, _keys2.default)(previous.data.getData()).length === 0) {
|
|
31
|
-
return updated;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
var interval = {}; // get inside the data from the filtered report
|
|
35
|
-
|
|
36
|
-
(0, _keys2.default)(updated.data.getData()).forEach(function (key) {
|
|
37
|
-
interval[key] = interval[key] ? interval[key] : {};
|
|
38
|
-
(0, _keys2.default)(updated.data.getData()[key]).forEach(function (stat) {
|
|
39
|
-
var value = updated.data.getData()[key][stat]; // only use some simple data points that are numbers and aren't silly things like timestamp
|
|
40
|
-
|
|
41
|
-
if ((0, _isFinite2.default)(value) && !(_constants.DEFAULT_EXCLUDED_STATS.includes(stat) && value !== 0)) {
|
|
42
|
-
// if there was nothing there before, just return the updated data
|
|
43
|
-
if (!previous.data.getData()[key] || !previous.data.getData()[key][stat]) {
|
|
44
|
-
interval[key][stat] = value;
|
|
45
|
-
} // subract and store
|
|
46
|
-
else {
|
|
47
|
-
value -= previous.data.getData()[key][stat];
|
|
48
|
-
interval[key][stat] = value;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
return interval;
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* Calculate an aggregate of values between an old summary and a new data point, using summary as the base to add to so aggregate = summary + data
|
|
57
|
-
* @param {WebRTCData} data
|
|
58
|
-
* @param {Object} summary
|
|
59
|
-
* @returns {Object} aggregate {StringKey: SummedValue, ..., n}
|
|
60
|
-
* @public
|
|
61
|
-
*/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
StatsCalculator.sum = function (data, summary) {
|
|
65
|
-
var aggregate = summary; // get inside the data from the filtered report
|
|
66
|
-
|
|
67
|
-
(0, _keys2.default)(data.data.getData()).forEach(function (key) {
|
|
68
|
-
(0, _keys2.default)(data.data.getData()[key]).forEach(function (stat) {
|
|
69
|
-
var value = data.data.getData()[key][stat]; // only use some simple data points that are numbers and aren't silly things like timestamp
|
|
70
|
-
|
|
71
|
-
if ((0, _isFinite2.default)(value) && !(_constants.DEFAULT_EXCLUDED_STATS.includes(stat) && value !== 0)) {
|
|
72
|
-
// if there was something there before, add to that value
|
|
73
|
-
if (aggregate[key][stat]) {
|
|
74
|
-
aggregate[key][stat] += value;
|
|
75
|
-
} // set up the value as the new data point
|
|
76
|
-
else {
|
|
77
|
-
aggregate[key][stat] = value;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
return aggregate;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
var _default = StatsCalculator;
|
|
86
|
-
exports.default = _default;
|
|
87
|
-
//# sourceMappingURL=calculator.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["StatsCalculator","difference","previous","updated","data","getData","length","interval","forEach","key","stat","value","DEFAULT_EXCLUDED_STATS","includes","sum","summary","aggregate"],"sources":["calculator.js"],"sourcesContent":["import {keys, isFinite} from 'lodash';\n\nimport {DEFAULT_EXCLUDED_STATS} from '../constants';\n\nconst StatsCalculator = {};\n\n/**\n * Calculate an interval of values between 2 data points, using updated as the \"latest\" so updated - previous = interval\n * @param {WebRTCData} previous\n * @param {WebRTCData} updated\n * @returns {Object} interval: {StringKey: IntervalValue, ..., n}\n * @public\n */\nStatsCalculator.difference = (previous, updated) => {\n // if there was no previous, just take the updated\n if (!previous || !previous.data || !previous.data.getData || keys(previous.data.getData()).length === 0) {\n return updated;\n }\n const interval = {};\n\n // get inside the data from the filtered report\n keys(updated.data.getData()).forEach((key) => {\n interval[key] = interval[key] ? interval[key] : {};\n keys(updated.data.getData()[key]).forEach((stat) => {\n let value = updated.data.getData()[key][stat];\n\n // only use some simple data points that are numbers and aren't silly things like timestamp\n if (isFinite(value) && !(DEFAULT_EXCLUDED_STATS.includes(stat) && value !== 0)) {\n // if there was nothing there before, just return the updated data\n if (!previous.data.getData()[key] || !previous.data.getData()[key][stat]) {\n interval[key][stat] = value;\n }\n // subract and store\n else {\n value -= previous.data.getData()[key][stat];\n interval[key][stat] = value;\n }\n }\n });\n });\n\n return interval;\n};\n\n/**\n * Calculate an aggregate of values between an old summary and a new data point, using summary as the base to add to so aggregate = summary + data\n * @param {WebRTCData} data\n * @param {Object} summary\n * @returns {Object} aggregate {StringKey: SummedValue, ..., n}\n * @public\n */\nStatsCalculator.sum = (data, summary) => {\n const aggregate = summary;\n\n // get inside the data from the filtered report\n keys(data.data.getData()).forEach((key) => {\n keys(data.data.getData()[key]).forEach((stat) => {\n const value = data.data.getData()[key][stat];\n\n // only use some simple data points that are numbers and aren't silly things like timestamp\n if (isFinite(value) && !(DEFAULT_EXCLUDED_STATS.includes(stat) && value !== 0)) {\n // if there was something there before, add to that value\n if (aggregate[key][stat]) {\n aggregate[key][stat] += value;\n }\n // set up the value as the new data point\n else {\n aggregate[key][stat] = value;\n }\n }\n });\n });\n\n return aggregate;\n};\n\nexport default StatsCalculator;\n"],"mappings":"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"}
|