@webex/plugin-meetings 2.18.0 → 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.
Files changed (64) hide show
  1. package/README.md +0 -300
  2. package/dist/constants.js +3 -206
  3. package/dist/constants.js.map +1 -1
  4. package/dist/meeting/effectsState.js +1 -2
  5. package/dist/meeting/effectsState.js.map +1 -1
  6. package/dist/meeting/index.js +366 -496
  7. package/dist/meeting/index.js.map +1 -1
  8. package/dist/meeting/util.js +4 -213
  9. package/dist/meeting/util.js.map +1 -1
  10. package/dist/meetings/index.js +0 -28
  11. package/dist/meetings/index.js.map +1 -1
  12. package/dist/statsAnalyzer/index.js +145 -86
  13. package/dist/statsAnalyzer/index.js.map +1 -1
  14. package/package.json +6 -8
  15. package/src/constants.ts +1 -214
  16. package/src/meeting/effectsState.js +1 -2
  17. package/src/meeting/index.js +120 -213
  18. package/src/meeting/util.js +4 -252
  19. package/src/meetings/index.js +0 -22
  20. package/src/statsAnalyzer/index.js +164 -99
  21. package/test/integration/spec/journey.js +2 -67
  22. package/test/unit/spec/meeting/effectsState.js +2 -1
  23. package/test/unit/spec/meeting/index.js +88 -29
  24. package/test/unit/spec/meeting/utils.js +0 -2
  25. package/test/unit/spec/stats-analyzer/index.js +209 -1
  26. package/dist/analyzer/analyzer.js +0 -113
  27. package/dist/analyzer/analyzer.js.map +0 -1
  28. package/dist/analyzer/calculator.js +0 -87
  29. package/dist/analyzer/calculator.js.map +0 -1
  30. package/dist/metrics/mqa-processor.js +0 -170
  31. package/dist/metrics/mqa-processor.js.map +0 -1
  32. package/dist/stats/data.js +0 -93
  33. package/dist/stats/data.js.map +0 -1
  34. package/dist/stats/events.js +0 -222
  35. package/dist/stats/events.js.map +0 -1
  36. package/dist/stats/filter.js +0 -84
  37. package/dist/stats/filter.js.map +0 -1
  38. package/dist/stats/history.js +0 -147
  39. package/dist/stats/history.js.map +0 -1
  40. package/dist/stats/index.js +0 -425
  41. package/dist/stats/index.js.map +0 -1
  42. package/dist/stats/metrics.js +0 -112
  43. package/dist/stats/metrics.js.map +0 -1
  44. package/dist/stats/stats.js +0 -592
  45. package/dist/stats/stats.js.map +0 -1
  46. package/dist/stats/stream.js +0 -156
  47. package/dist/stats/stream.js.map +0 -1
  48. package/dist/stats/transformer.js +0 -126
  49. package/dist/stats/transformer.js.map +0 -1
  50. package/dist/stats/util.js +0 -64
  51. package/dist/stats/util.js.map +0 -1
  52. package/src/analyzer/analyzer.js +0 -78
  53. package/src/analyzer/calculator.js +0 -77
  54. package/src/metrics/mqa-processor.js +0 -118
  55. package/src/stats/data.js +0 -56
  56. package/src/stats/events.js +0 -185
  57. package/src/stats/filter.js +0 -40
  58. package/src/stats/history.js +0 -107
  59. package/src/stats/index.js +0 -320
  60. package/src/stats/metrics.js +0 -95
  61. package/src/stats/stats.js +0 -477
  62. package/src/stats/stream.js +0 -108
  63. package/src/stats/transformer.js +0 -109
  64. package/src/stats/util.js +0 -44
@@ -1,118 +0,0 @@
1
- import {
2
- STATS,
3
- MQA_STATS
4
- } from '../constants';
5
- import BrowserDetection from '../common/browser-detection';
6
-
7
- const {isBrowser} = BrowserDetection();
8
-
9
- /**
10
- * @description MQAProcessor handles interval data for MQA
11
- * @export
12
- * @class MQAProcessor
13
- */
14
- class MQAProcessor {
15
- /**
16
- * @constructor
17
- * @public
18
- * @memberof MQAProcessor
19
- */
20
- constructor() {
21
- this.data = {
22
- videoReceive: [],
23
- audioTransmit: [],
24
- audioReceive: [],
25
- videoTransmit: []
26
- };
27
- this.intervalNumber = 1;
28
- }
29
-
30
- /**
31
- * @param {String} id
32
- * @param {Array<WebRTCData>} interval - a slice of metrics history
33
- * @returns {undefined}
34
- * @memberof MQAProcessor
35
- */
36
- process(id, interval) {
37
- let rtcCandidatePair, rtcOutVideo, rtpOutVideo; // TODO: , rtcInVideo, rtpInVideo, rtcOutAudio, rtcInAudio, rtpInAudio, rtpOutAudio; // TODO:
38
- let vsTransmit;
39
-
40
- const {
41
- videoReceive, audioTransmit, audioReceive, videoTransmit
42
- } = this.data;
43
-
44
- const sumValue = interval[0]; // the head is the last interval value, webRTC spec has some values automatically summed
45
-
46
- if (sumValue) {
47
- rtcCandidatePair = sumValue.rtcCandidatePair;
48
- }
49
-
50
- switch (id) {
51
- case STATS.AUDIO_SENDER_ID:
52
- audioTransmit.push();
53
- break;
54
- case STATS.AUDIO_RECEIVER_ID:
55
- audioReceive.push();
56
- break;
57
- case STATS.VIDEO_SENDER_ID:
58
- videoTransmit.push();
59
- break;
60
- case STATS.VIDEO_RECEIVER_ID:
61
- videoReceive.push();
62
- break;
63
- case STATS.SHARE_SENDER_ID:
64
- if (sumValue) {
65
- rtcOutVideo = sumValue.rtcOutVideo;
66
- rtpOutVideo = sumValue.rtpOutVideo;
67
- }
68
- vsTransmit = {...MQA_STATS.DEFAULT_SHARE_SENDER_STATS};
69
- if (isBrowser('firefox')) {
70
- vsTransmit.common.remoteLossRate = rtpOutVideo ? rtpOutVideo.pliCount / (interval.length * this.intervalNumber) : 0;
71
- vsTransmit.common.rtpPackets = rtpOutVideo ? rtpOutVideo.packetsSent / (interval.length * this.intervalNumber) : 0;
72
- vsTransmit.streams[0].common.transmittedFrameRate = rtcOutVideo ? rtcOutVideo.framesEncoded / (interval.length * this.intervalNumber) : 0;
73
- vsTransmit.streams[0].common.rtpPackets = rtpOutVideo ? rtpOutVideo.packetsSent / (interval.length * this.intervalNumber) : 0;
74
- }
75
- else {
76
- vsTransmit.common.availableBitRate = rtcCandidatePair ? rtcCandidatePair.availableOutgoingBitrate : 0;
77
- vsTransmit.common.remoteLossRate = rtpOutVideo ? rtpOutVideo.pliCount / (interval.length * this.intervalNumber) : 0;
78
- vsTransmit.common.roundTripTime = rtcCandidatePair ? rtcCandidatePair.totalRoundTripTime / (interval.length * this.intervalNumber) : 0;
79
- vsTransmit.common.rtpPackets = rtpOutVideo ? rtpOutVideo.packetsSent / (interval.length * this.intervalNumber) : 0;
80
- vsTransmit.streams[0].common.rtpPackets = rtpOutVideo ? rtpOutVideo.packetsSent / (interval.length * this.intervalNumber) : 0;
81
- vsTransmit.streams[0].common.transmittedBitrate = rtcCandidatePair ? rtcCandidatePair.availableOutgoingBitrate : 0;
82
- vsTransmit.streams[0].common.transmittedFrameRate = rtcOutVideo ? rtcOutVideo.framesSent / (interval.length * this.intervalNumber) : 0;
83
- vsTransmit.streams[0].transmittedHeight = rtcOutVideo ? rtcOutVideo.frameHeight : 0;
84
- vsTransmit.streams[0].transmittedKeyFrames = rtcOutVideo ? rtcOutVideo.hugeFramesSent : 0;
85
- vsTransmit.streams[0].transmittedWidth = rtcOutVideo ? rtcOutVideo.frameWidth : 0;
86
- }
87
- videoTransmit.push(vsTransmit);
88
- break;
89
- default:
90
- break;
91
- }
92
- this.data.intervalMetadata = this.data.intervalMetadata || {...MQA_STATS.intervalMetadata};
93
- }
94
-
95
- /**
96
- * get the data payload for media quality events after they all have been processed
97
- * wait to call this until after you have all the data from the interval you want
98
- * this method clears the data as a side effect
99
- * @returns {Object}
100
- * @memberof MQAProcessor
101
- */
102
- getData() {
103
- this.intervalNumber += 1;
104
-
105
- const payload = {...this.data, intervalNumber: this.intervalNumber};
106
-
107
- this.data = {
108
- videoReceive: [],
109
- audioTransmit: [],
110
- audioReceive: [],
111
- videoTransmit: []
112
- };
113
-
114
- return payload;
115
- }
116
- }
117
-
118
- export default MQAProcessor;
package/src/stats/data.js DELETED
@@ -1,56 +0,0 @@
1
- import uuid from 'uuid';
2
- import {isEmpty, omit} from 'lodash';
3
-
4
- import {DEFAULT_OMISSION_DATA_KEYS} from '../constants';
5
-
6
- // TODO: Break this up a bit more, so that consumers aren't calling data.data.getData()
7
- /**
8
- * @class WebRTCData
9
- */
10
- export default class WebRTCData {
11
- /**
12
- * @param {Object} data
13
- */
14
- constructor(data) {
15
- this.data = data;
16
- this.id = uuid.v4();
17
- }
18
-
19
- /**
20
- * get omitted rtc/rtcp/rtp/track/transport/candidate data with omitted data (default)
21
- * @returns {Object}
22
- */
23
- omit() {
24
- const flat = {};
25
-
26
- Object.keys(this.data).forEach((key) => {
27
- flat[key] = omit(this.data[key], DEFAULT_OMISSION_DATA_KEYS);
28
- });
29
-
30
- return flat;
31
- }
32
-
33
- /**
34
- * returns if the data is empty
35
- * @returns {Boolean};
36
- */
37
- isEmpty() {
38
- return isEmpty(this.data);
39
- }
40
-
41
- /**
42
- * get the unique id for this specific stat pull
43
- * @returns {String};
44
- */
45
- getId() {
46
- return this.id;
47
- }
48
-
49
- /**
50
- * get the transformed data
51
- * @returns {Object}
52
- */
53
- getData() {
54
- return this.data;
55
- }
56
- }
@@ -1,185 +0,0 @@
1
- import StatsAnalyzer from '../analyzer/analyzer';
2
- import {
3
- DEFAULT_EVENT_VIDEO_SEND_KEYS,
4
- DEFAULT_EVENT_AUDIO_SEND_KEYS,
5
- DEFAULT_EVENT_AUDIO_RECEIVE_KEYS,
6
- DEFAULT_EVENT_VIDEO_RECEIVE_KEYS,
7
- EVENT_TYPES,
8
- EVENT_STATS_MAP,
9
- MEETINGS,
10
- AUDIO,
11
- VIDEO,
12
- ANALYSIS_CHECKS
13
- } from '../constants';
14
-
15
- /**
16
- * @param {Object} operate the filtered, parsed, converted, transformed, simplified data point to check against
17
- * @param {String} type - local or remote
18
- * @param {String} keys - the stat keys for types of stats defined by DEFAULT_TRANSFORM_REGEX
19
- * @param {String} stat - the accessor to get the actual stat
20
- * @param {String} kind - audio or video
21
- * @returns {Object} always whatever the first sentFirstVideoBytes were, in the past or if it happened now, or undefined if never
22
- * @private
23
- * @memberof StatsEvents
24
- */
25
- const operateEvent = (operate, type, keys, stat, kind) => {
26
- const foundMatch = {};
27
-
28
- foundMatch.found = keys.some((key) => {
29
- if (operate[key] && operate[key][stat] && operate[key][stat] > 0) {
30
- foundMatch.match = {
31
- type,
32
- key,
33
- data: operate[key],
34
- stat,
35
- kind
36
- };
37
-
38
- return true;
39
- }
40
-
41
- return false;
42
- });
43
-
44
- return foundMatch;
45
- };
46
-
47
- /**
48
- * @export
49
- * @class StatsEvents
50
- */
51
- export default class StatsEvents {
52
- namespace = MEETINGS;
53
-
54
- /**
55
- * constructs an instance
56
- * @constructor
57
- * @param {StatsHistory} series
58
- * @param {Function} callback
59
- * @memberof StatsEvents
60
- */
61
- constructor(series = null, callback = () => {}) {
62
- /**
63
- * @instance
64
- * @type {StatsHistory}
65
- * @private
66
- * @memberof StatsEvents
67
- */
68
- this.series = series;
69
- /**
70
- * @instance
71
- * @type {Function}
72
- * @private
73
- * @memberof StatsEvents
74
- */
75
- this.callback = callback;
76
- /**
77
- * @instance
78
- * @type {WebRTCData}
79
- * @private
80
- * @memberof StatsEvents
81
- */
82
- this.first = null;
83
- /**
84
- * @instance
85
- * @type {Boolean}
86
- * @private
87
- * @memberof StatsEvents
88
- */
89
- this.sendRemainStopped = false;
90
- /**
91
- * @instance
92
- * @type {Boolean}
93
- * @private
94
- * @memberof StatsEvents
95
- */
96
- this.recvRemainStopped = false;
97
- }
98
-
99
- /**
100
- * looks for data starting to flow through
101
- * @param {WebRTCData} data
102
- * @returns {Object}
103
- */
104
- start(data) {
105
- if (data && data.data && data.data.getData()) {
106
- const operate = data.data.getData();
107
-
108
- if (operate && !this.first) {
109
- const operator = [
110
- operateEvent(operate, EVENT_TYPES.LOCAL, DEFAULT_EVENT_AUDIO_SEND_KEYS, EVENT_STATS_MAP.BYTES_SENT, AUDIO),
111
- operateEvent(operate, EVENT_TYPES.LOCAL, DEFAULT_EVENT_VIDEO_SEND_KEYS, EVENT_STATS_MAP.BYTES_SENT, VIDEO),
112
- operateEvent(operate, EVENT_TYPES.REMOTE, DEFAULT_EVENT_VIDEO_RECEIVE_KEYS, EVENT_STATS_MAP.BYTES_RECEIVED, VIDEO),
113
- operateEvent(operate, EVENT_TYPES.REMOTE, DEFAULT_EVENT_AUDIO_RECEIVE_KEYS, EVENT_STATS_MAP.BYTES_RECEIVED, AUDIO)
114
- ];
115
- const somethingMatched = operator.find((element) => element && element.found && element.match);
116
-
117
- if (somethingMatched) {
118
- this.first = somethingMatched.match;
119
- this.callback(this.first);
120
-
121
- return somethingMatched;
122
- }
123
- }
124
- }
125
-
126
- return null;
127
- }
128
-
129
- /**
130
- * Looks for data to stop coming through
131
- * @returns {Object}
132
- */
133
- stop() {
134
- if (!this.series || this.series.get().length < 5) {
135
- return null;
136
- }
137
- const fiveSecondsData = this.series.getSlice(5);
138
- const prop = fiveSecondsData[0] && fiveSecondsData[0].rtpOutAudio || fiveSecondsData[0].rtpInAudio || fiveSecondsData[0].rtpInVideo || fiveSecondsData[0].rtpOutVideo;
139
- const sendAnalysis = StatsAnalyzer.analyze(fiveSecondsData, {analysisKeys: [{key: EVENT_STATS_MAP.BYTES_SENT, check: ANALYSIS_CHECKS.INCREASING, prop}]});
140
- const receiveAnalysis = StatsAnalyzer.analyze(fiveSecondsData, {analysisKeys: [{key: EVENT_STATS_MAP.BYTES_RECEIVED, check: ANALYSIS_CHECKS.INCREASING, prop}]});
141
-
142
- if (!sendAnalysis.valid && sendAnalysis.data.bytesSent.reports.length > 0) {
143
- if (!this.sendRemainStopped) {
144
- const ret = {stop: true, stat: EVENT_STATS_MAP.BYTES_SENT};
145
-
146
- this.callback(ret);
147
- this.sendRemainStopped = true;
148
- this.first = null;
149
-
150
- return ret;
151
- }
152
- }
153
- else if (sendAnalysis.valid && sendAnalysis.data.bytesSent.reports.length > 0) {
154
- this.sendRemainStopped = false;
155
- }
156
- if (!receiveAnalysis.valid && receiveAnalysis.data.bytesReceived.reports.length > 0) {
157
- if (!this.recvRemainStopped) {
158
- const ret = {stop: true, stat: EVENT_STATS_MAP.BYTES_RECEIVED};
159
-
160
- this.callback(ret);
161
- this.recvRemainStopped = true;
162
- this.first = null;
163
-
164
- return ret;
165
- }
166
- }
167
- else if (receiveAnalysis.valid && receiveAnalysis.data.bytesReceived.reports.length > 0) {
168
- this.recvRemainStopped = false;
169
- }
170
-
171
- return null;
172
- }
173
-
174
- /**
175
- * handles all the types of events that need to be sent when they happen from getStats API
176
- * @param {WebRTCData} data
177
- * @returns {Object}
178
- */
179
- event(data) {
180
- return {
181
- start: this.start(data),
182
- stop: this.stop()
183
- };
184
- }
185
- }
@@ -1,40 +0,0 @@
1
- import {Transform} from 'readable-stream';
2
-
3
- import StatsTransformer from '../stats/transformer';
4
- import WebRTCData from '../stats/data';
5
-
6
- /**
7
- * Reforms the interesting data from an RTCStatsReport to a new format
8
- */
9
- export default class StatsFilter extends Transform {
10
- /**
11
- * Tells the Stream we're operating in objectMode
12
- * @private
13
- */
14
- constructor() {
15
- super({objectMode: true});
16
- }
17
-
18
- /**
19
- * Filters out data on the RTCStatsReport to the data around call quality and pushes it as a WebRTCData object
20
- * @param {RTCStatsReport} report
21
- * @param {*} encoding
22
- * @param {Function} callback
23
- * @private
24
- * @returns {undefined}
25
- */
26
- _transform(report, encoding, callback) {
27
- if (!report) {
28
- callback();
29
-
30
- return;
31
- }
32
- const data = StatsTransformer.transform(report);
33
- const push = new WebRTCData(data);
34
-
35
- this.push({
36
- data: push
37
- });
38
- callback();
39
- }
40
- }
@@ -1,107 +0,0 @@
1
- /**
2
- * stores the last x filtered stream datas
3
- */
4
- /**
5
- * @export
6
- * @class StatsHistory
7
- */
8
- export default class StatsHistory {
9
- /**
10
- * instantiate our wrapped history array
11
- * @param {Number} max
12
- */
13
- constructor(max) {
14
- /**
15
- * @instance
16
- * @type {Array}
17
- * @public
18
- * @memberof StatsHistory
19
- */
20
- this.history = [];
21
- /**
22
- * @instance
23
- * @type {Number}
24
- * @public
25
- * @memberof StatsHistory
26
- */
27
- this.max = max;
28
- }
29
-
30
- /**
31
- * @returns {Array} the array of stats reports, read from [0] = most recent to [length - 1] = least recent
32
- * @public
33
- * @memberof StatsHistory
34
- */
35
- get() {
36
- return this.history;
37
- }
38
-
39
- /**
40
- * deletes the history array and resets it
41
- * @returns {undefined}
42
- * @public
43
- * @memberof StatsHistory
44
- */
45
- clear() {
46
- this.history = [];
47
- }
48
-
49
- /**
50
- * gets the stored stat
51
- * @param {Number} index the location
52
- * @returns {Object} the stat at location index
53
- * @public
54
- * @memberof StatsHistory
55
- */
56
- getAt(index) {
57
- return this.history[index];
58
- }
59
-
60
- /**
61
- * gets the most recently stored stat
62
- * @returns {Object} the most recently added stat to the history recorder
63
- * @public
64
- * @memberof StatsHistory
65
- */
66
- getMostRecent() {
67
- return this.history.length > 1 ? this.getAt(0) : null;
68
- }
69
-
70
- /**
71
- * gets the last two values, that can be used to compare
72
- * @returns {Object} {previous: WebRTCData, current: WebRTCData}
73
- */
74
- getComparable() {
75
- return {
76
- previous: this.getMostRecent(),
77
- current: this.history.length > 2 ? this.getAt(1) : null
78
- };
79
- }
80
-
81
- /**
82
- * gets a cut of the n most recent WebRTC datas stored
83
- * @param {Number} exclusiveEnd
84
- * @returns {Array}
85
- */
86
- getSlice(exclusiveEnd) {
87
- return this.history.slice(0, exclusiveEnd);
88
- }
89
-
90
- /**
91
- * adds a history entry into tshe array at the head, removes from the tail
92
- * if too large, returns the old tail if removed
93
- * @param {WebRTCData} data filtered stats report to add to the history array
94
- * @returns {Object} the removed stats report at the end if that had to be removed
95
- * to make space for the new stats data report to be added to the front
96
- */
97
- add(data) {
98
- let removed = null;
99
-
100
- if (this.history.length >= this.max) {
101
- removed = this.history.pop();
102
- }
103
- this.history.unshift(data);
104
-
105
- return removed;
106
- }
107
- }