@webex/plugin-meetings 2.59.8-next.2 → 2.60.0
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/dist/common/browser-detection.d.ts +9 -0
- package/dist/common/browser-detection.js +2 -2
- package/dist/common/browser-detection.js.map +1 -1
- package/dist/common/collection.d.ts +48 -0
- package/dist/common/collection.js +2 -2
- package/dist/common/collection.js.map +1 -1
- package/dist/common/config.d.ts +2 -0
- package/dist/common/errors/captcha-error.d.ts +15 -0
- package/dist/common/errors/intent-to-join.d.ts +16 -0
- package/dist/common/errors/join-meeting.d.ts +17 -0
- package/dist/common/errors/media.d.ts +15 -0
- package/dist/common/errors/parameter.d.ts +15 -0
- package/dist/common/errors/password-error.d.ts +15 -0
- package/dist/common/errors/permission.d.ts +14 -0
- package/dist/common/errors/reclaim-host-role-error.d.ts +60 -0
- package/dist/common/errors/reclaim-host-role-error.js +158 -0
- package/dist/common/errors/reclaim-host-role-error.js.map +1 -0
- package/dist/common/errors/reconnection-in-progress.d.ts +9 -0
- package/dist/common/errors/reconnection.d.ts +15 -0
- package/dist/common/errors/stats.d.ts +15 -0
- package/dist/common/errors/webex-errors.d.ts +81 -0
- package/dist/common/errors/webex-meetings-error.d.ts +20 -0
- package/dist/common/events/events-scope.d.ts +17 -0
- package/dist/common/events/events.d.ts +12 -0
- package/dist/common/events/trigger-proxy.d.ts +2 -0
- package/dist/common/events/util.d.ts +2 -0
- package/dist/common/logs/logger-config.d.ts +2 -0
- package/dist/common/logs/logger-proxy.d.ts +2 -0
- package/dist/common/logs/request.d.ts +34 -0
- package/dist/common/queue.d.ts +32 -0
- package/dist/config.d.ts +73 -0
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +952 -0
- package/dist/constants.js +31 -2
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/constants.d.ts +4 -0
- package/dist/controls-options-manager/enums.d.ts +5 -0
- package/dist/controls-options-manager/index.d.ts +120 -0
- package/dist/controls-options-manager/index.js +2 -2
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/util.d.ts +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/locus-info/controlsUtils.d.ts +2 -0
- package/dist/locus-info/controlsUtils.js +6 -6
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/embeddedAppsUtils.d.ts +2 -0
- package/dist/locus-info/fullState.d.ts +2 -0
- package/dist/locus-info/hostUtils.d.ts +2 -0
- package/dist/locus-info/index.d.ts +269 -0
- package/dist/locus-info/index.js +18 -18
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.d.ts +2 -0
- package/dist/locus-info/mediaSharesUtils.d.ts +2 -0
- package/dist/locus-info/parser.d.ts +212 -0
- package/dist/locus-info/parser.js +2 -2
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.d.ts +2 -0
- package/dist/media/index.d.ts +32 -0
- package/dist/media/properties.d.ts +108 -0
- package/dist/media/util.d.ts +2 -0
- package/dist/mediaQualityMetrics/config.d.ts +233 -0
- package/dist/meeting/effectsState.d.ts +42 -0
- package/dist/meeting/in-meeting-actions.d.ts +79 -0
- package/dist/meeting/index.d.ts +1622 -0
- package/dist/meeting/index.js +51 -28
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.d.ts +116 -0
- package/dist/meeting/request.d.ts +255 -0
- package/dist/meeting/request.js +2 -2
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/state.d.ts +9 -0
- package/dist/meeting/util.d.ts +2 -0
- package/dist/meeting/util.js +4 -4
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/collection.d.ts +20 -0
- package/dist/meeting-info/collection.js +2 -2
- package/dist/meeting-info/collection.js.map +1 -1
- package/dist/meeting-info/index.d.ts +57 -0
- package/dist/meeting-info/meeting-info-v2.d.ts +93 -0
- package/dist/meeting-info/request.d.ts +22 -0
- package/dist/meeting-info/util.d.ts +2 -0
- package/dist/meeting-info/utilv2.d.ts +2 -0
- package/dist/meetings/collection.d.ts +23 -0
- package/dist/meetings/collection.js +2 -2
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.d.ts +296 -0
- package/dist/meetings/request.d.ts +27 -0
- package/dist/meetings/util.d.ts +18 -0
- package/dist/member/index.d.ts +148 -0
- package/dist/member/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/member.types.d.ts +11 -0
- package/dist/member/util.d.ts +2 -0
- package/dist/member/util.js +11 -0
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.d.ts +24 -0
- package/dist/members/index.d.ts +308 -0
- package/dist/members/index.js +39 -2
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.d.ts +58 -0
- package/dist/members/request.js +19 -0
- package/dist/members/request.js.map +1 -1
- package/dist/members/types.d.ts +25 -0
- package/dist/members/types.js +15 -0
- package/dist/members/types.js.map +1 -0
- package/dist/members/util.d.ts +2 -0
- package/dist/members/util.js +50 -0
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/config.d.ts +169 -0
- package/dist/metrics/constants.d.ts +59 -0
- package/dist/metrics/constants.js +2 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.d.ts +152 -0
- package/dist/metrics/index.js +2 -2
- package/dist/metrics/index.js.map +1 -1
- package/dist/networkQualityMonitor/index.d.ts +70 -0
- package/dist/peer-connection-manager/index.d.ts +6 -0
- package/dist/peer-connection-manager/util.d.ts +6 -0
- package/dist/personal-meeting-room/index.d.ts +47 -0
- package/dist/personal-meeting-room/request.d.ts +14 -0
- package/dist/personal-meeting-room/util.d.ts +2 -0
- package/dist/reachability/index.d.ts +139 -0
- package/dist/reachability/index.js +2 -9
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.d.ts +35 -0
- package/dist/reactions/reactions.d.ts +4 -0
- package/dist/reactions/reactions.type.d.ts +32 -0
- package/dist/reconnection-manager/index.d.ts +112 -0
- package/dist/recording-controller/enums.d.ts +7 -0
- package/dist/recording-controller/index.d.ts +193 -0
- package/dist/recording-controller/util.d.ts +13 -0
- package/dist/roap/collection.d.ts +10 -0
- package/dist/roap/handler.d.ts +47 -0
- package/dist/roap/index.d.ts +116 -0
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.d.ts +35 -0
- package/dist/roap/state.d.ts +9 -0
- package/dist/roap/turnDiscovery.d.ts +81 -0
- package/dist/roap/util.d.ts +2 -0
- package/dist/statsAnalyzer/global.d.ts +118 -0
- package/dist/statsAnalyzer/global.js +4 -12
- package/dist/statsAnalyzer/global.js.map +1 -1
- package/dist/statsAnalyzer/index.d.ts +193 -0
- package/dist/statsAnalyzer/index.js +56 -14
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.d.ts +22 -0
- package/dist/statsAnalyzer/mqaUtil.js +15 -15
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/transcription/index.d.ts +64 -0
- package/package.json +21 -22
- package/src/common/errors/reclaim-host-role-error.ts +134 -0
- package/src/config.ts +2 -2
- package/src/constants.ts +33 -0
- package/src/meeting/index.ts +35 -0
- package/src/member/index.ts +9 -0
- package/src/member/util.ts +14 -0
- package/src/members/index.ts +55 -1
- package/src/members/request.ts +20 -0
- package/src/members/types.ts +29 -0
- package/src/members/util.ts +52 -0
- package/src/metrics/constants.ts +2 -0
- package/src/roap/index.ts +1 -0
- package/src/statsAnalyzer/global.ts +2 -10
- package/src/statsAnalyzer/index.ts +80 -17
- package/test/unit/spec/meeting/index.js +77 -6
- package/test/unit/spec/member/index.js +7 -0
- package/test/unit/spec/member/util.js +32 -0
- package/test/unit/spec/members/index.js +205 -0
- package/test/unit/spec/members/utils.js +75 -0
- package/test/unit/spec/roap/index.ts +0 -1
- package/test/unit/spec/stats-analyzer/index.js +151 -0
package/src/members/request.ts
CHANGED
|
@@ -59,6 +59,26 @@ export default class MembersRequest extends StatelessWebexPlugin {
|
|
|
59
59
|
return this.request(requestParams);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Sends a request to assign roles to a member
|
|
64
|
+
* @param {Object} options
|
|
65
|
+
* @param {String} options.locusUrl
|
|
66
|
+
* @param {String} options.memberId ID of PSTN user
|
|
67
|
+
* @returns {Promise}
|
|
68
|
+
*/
|
|
69
|
+
assignRolesMember(options: any) {
|
|
70
|
+
if (!options || !options.locusUrl || !options.memberId) {
|
|
71
|
+
throw new ParameterError(
|
|
72
|
+
'memberId must be defined, and the associated locus url for this meeting object must be defined.'
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const requestParams = MembersUtil.getRoleAssignmentMemberRequestParams(options);
|
|
77
|
+
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
return this.request(requestParams);
|
|
80
|
+
}
|
|
81
|
+
|
|
62
82
|
removeMember(options) {
|
|
63
83
|
if (!options || !options.locusUrl || !options.memberId) {
|
|
64
84
|
throw new ParameterError(
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export enum ServerRoles {
|
|
2
|
+
Cohost = 'COHOST',
|
|
3
|
+
Moderator = 'MODERATOR',
|
|
4
|
+
Presenter = 'PRESENTER',
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type ServerRoleShape = {
|
|
8
|
+
type: ServerRoles;
|
|
9
|
+
hasRole: boolean;
|
|
10
|
+
hostKey?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type RoleAssignmentOptions = {
|
|
14
|
+
roles: Array<ServerRoleShape>;
|
|
15
|
+
locusUrl: string;
|
|
16
|
+
memberId: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type RoleAssignmentBody = {
|
|
20
|
+
role: {
|
|
21
|
+
roles: Array<ServerRoleShape>;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type RoleAssignmentRequest = {
|
|
26
|
+
method: string;
|
|
27
|
+
uri: string;
|
|
28
|
+
body: RoleAssignmentBody;
|
|
29
|
+
};
|
package/src/members/util.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
SEND_DTMF_ENDPOINT,
|
|
12
12
|
_REMOVE_,
|
|
13
13
|
} from '../constants';
|
|
14
|
+
import {RoleAssignmentOptions, RoleAssignmentRequest, ServerRoleShape} from './types';
|
|
14
15
|
|
|
15
16
|
const MembersUtil: any = {};
|
|
16
17
|
|
|
@@ -91,6 +92,20 @@ MembersUtil.getAddMemberRequestParams = (format: any) => {
|
|
|
91
92
|
return requestParams;
|
|
92
93
|
};
|
|
93
94
|
|
|
95
|
+
/**
|
|
96
|
+
* @param {ServerRoleShape} role
|
|
97
|
+
* @returns {ServerRoleShape} the role shape to be added to the body
|
|
98
|
+
*/
|
|
99
|
+
MembersUtil.getAddedRoleShape = (role: ServerRoleShape) => {
|
|
100
|
+
const roleShape: ServerRoleShape = {type: role.type, hasRole: role.hasRole};
|
|
101
|
+
|
|
102
|
+
if (role.hostKey) {
|
|
103
|
+
roleShape.hostKey = role.hostKey;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return roleShape;
|
|
107
|
+
};
|
|
108
|
+
|
|
94
109
|
MembersUtil.isInvalidInvitee = (invitee) => {
|
|
95
110
|
if (!(invitee && (invitee.email || invitee.emailAddress || invitee.phoneNumber))) {
|
|
96
111
|
return true;
|
|
@@ -116,6 +131,43 @@ MembersUtil.getRemoveMemberRequestParams = (options) => {
|
|
|
116
131
|
};
|
|
117
132
|
};
|
|
118
133
|
|
|
134
|
+
/**
|
|
135
|
+
* @param {String} memberId
|
|
136
|
+
* @param {[ServerRoleShape]} roles
|
|
137
|
+
* @param {String} locusUrl
|
|
138
|
+
* @returns {RoleAssignmentOptions}
|
|
139
|
+
*/
|
|
140
|
+
MembersUtil.generateRoleAssignmentMemberOptions = (
|
|
141
|
+
memberId: string,
|
|
142
|
+
roles: Array<ServerRoleShape>,
|
|
143
|
+
locusUrl: string
|
|
144
|
+
): RoleAssignmentOptions => ({
|
|
145
|
+
memberId,
|
|
146
|
+
roles,
|
|
147
|
+
locusUrl,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @param {RoleAssignmentOptions} options
|
|
152
|
+
* @returns {RoleAssignmentRequest} the request parameters (method, uri, body) needed to make a addMember request
|
|
153
|
+
*/
|
|
154
|
+
MembersUtil.getRoleAssignmentMemberRequestParams = (
|
|
155
|
+
options: RoleAssignmentOptions
|
|
156
|
+
): RoleAssignmentRequest => {
|
|
157
|
+
const body = {role: {roles: []}};
|
|
158
|
+
options.roles.forEach((role) => {
|
|
159
|
+
body.role.roles.push(MembersUtil.getAddedRoleShape(role));
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const uri = `${options.locusUrl}/${PARTICIPANT}/${options.memberId}/${CONTROLS}`;
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
method: HTTP_VERBS.PATCH,
|
|
166
|
+
uri,
|
|
167
|
+
body,
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
|
|
119
171
|
MembersUtil.generateTransferHostMemberOptions = (transfer, moderator, locusUrl) => ({
|
|
120
172
|
moderator,
|
|
121
173
|
locusUrl,
|
package/src/metrics/constants.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Metrics constants ----------------------------------------------------------
|
|
2
2
|
|
|
3
3
|
const BEHAVIORAL_METRICS = {
|
|
4
|
+
NO_FRAMES_SENT: 'js_sdk_meetings_no_frames_sent',
|
|
5
|
+
NO_VIDEO_ENCODED: 'js_sdk_meetings_no_video_encoded',
|
|
4
6
|
MEETINGS_REGISTRATION_FAILED: 'js_sdk_meetings_registration_failed',
|
|
5
7
|
MEETINGS_REGISTRATION_SUCCESS: 'js_sdk_meetings_registration_success',
|
|
6
8
|
MERCURY_CONNECTION_FAILURE: 'js_sdk_mercury_connection_failure',
|
package/src/roap/index.ts
CHANGED
|
@@ -76,20 +76,11 @@ const STATS_DEFAULT = {
|
|
|
76
76
|
},
|
|
77
77
|
},
|
|
78
78
|
resolutions: {
|
|
79
|
-
audio: {
|
|
80
|
-
send: {
|
|
81
|
-
width: 0,
|
|
82
|
-
height: 0,
|
|
83
|
-
},
|
|
84
|
-
recv: {
|
|
85
|
-
width: 0,
|
|
86
|
-
height: 0,
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
79
|
video: {
|
|
90
80
|
send: {
|
|
91
81
|
width: 0,
|
|
92
82
|
height: 0,
|
|
83
|
+
framesSent: 0,
|
|
93
84
|
},
|
|
94
85
|
recv: {
|
|
95
86
|
width: 0,
|
|
@@ -100,6 +91,7 @@ const STATS_DEFAULT = {
|
|
|
100
91
|
send: {
|
|
101
92
|
width: 0,
|
|
102
93
|
height: 0,
|
|
94
|
+
framesSent: 0,
|
|
103
95
|
},
|
|
104
96
|
recv: {
|
|
105
97
|
width: 0,
|
|
@@ -25,6 +25,8 @@ import {
|
|
|
25
25
|
|
|
26
26
|
export const EVENTS = {
|
|
27
27
|
MEDIA_QUALITY: 'MEDIA_QUALITY',
|
|
28
|
+
NO_FRAMES_SENT: 'NO_FRAMES_SENT',
|
|
29
|
+
NO_VIDEO_ENCODED: 'NO_VIDEO_ENCODED',
|
|
28
30
|
LOCAL_MEDIA_STARTED: 'LOCAL_MEDIA_STARTED',
|
|
29
31
|
LOCAL_MEDIA_STOPPED: 'LOCAL_MEDIA_STOPPED',
|
|
30
32
|
REMOTE_MEDIA_STARTED: 'REMOTE_MEDIA_STARTED',
|
|
@@ -420,9 +422,6 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
420
422
|
case 'inbound-rtp':
|
|
421
423
|
this.processInboundRTPResult(getStatsResult, type);
|
|
422
424
|
break;
|
|
423
|
-
case 'track':
|
|
424
|
-
this.processTrackResult(getStatsResult, type);
|
|
425
|
-
break;
|
|
426
425
|
case 'remote-inbound-rtp':
|
|
427
426
|
case 'remote-outbound-rtp':
|
|
428
427
|
// @ts-ignore
|
|
@@ -520,7 +519,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
520
519
|
|
|
521
520
|
if (currentValue - previousValue > 0) {
|
|
522
521
|
newEvent = isLocal ? EVENTS.LOCAL_MEDIA_STARTED : EVENTS.REMOTE_MEDIA_STARTED;
|
|
523
|
-
} else if (currentValue === previousValue && currentValue
|
|
522
|
+
} else if (currentValue === previousValue && currentValue >= 0) {
|
|
524
523
|
newEvent = isLocal ? EVENTS.LOCAL_MEDIA_STOPPED : EVENTS.REMOTE_MEDIA_STOPPED;
|
|
525
524
|
}
|
|
526
525
|
|
|
@@ -635,14 +634,25 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
635
634
|
LoggerProxy.logger.info(
|
|
636
635
|
`StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} RTP packets sent`
|
|
637
636
|
);
|
|
638
|
-
} else {
|
|
637
|
+
} else if (this.lastEmittedStartStopEvent[mediaType].local !== EVENTS.LOCAL_MEDIA_STOPPED) {
|
|
639
638
|
if (
|
|
640
639
|
currentStats.framesEncoded === previousStats.framesEncoded ||
|
|
641
640
|
currentStats.framesEncoded === 0
|
|
642
641
|
) {
|
|
642
|
+
this.lastEmittedStartStopEvent[mediaType].local = EVENTS.NO_VIDEO_ENCODED;
|
|
643
643
|
LoggerProxy.logger.info(
|
|
644
644
|
`StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} Frames Encoded`
|
|
645
645
|
);
|
|
646
|
+
this.emit(
|
|
647
|
+
{
|
|
648
|
+
file: 'statsAnalyzer',
|
|
649
|
+
function: 'compareLastStatsResult',
|
|
650
|
+
},
|
|
651
|
+
EVENTS.NO_VIDEO_ENCODED,
|
|
652
|
+
{
|
|
653
|
+
mediaType,
|
|
654
|
+
}
|
|
655
|
+
);
|
|
646
656
|
}
|
|
647
657
|
|
|
648
658
|
if (
|
|
@@ -654,8 +664,28 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
654
664
|
`StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} Frames sent`
|
|
655
665
|
);
|
|
656
666
|
}
|
|
657
|
-
}
|
|
658
667
|
|
|
668
|
+
// Video is encoded but frames are not sent
|
|
669
|
+
if (
|
|
670
|
+
currentStats.framesEncoded !== previousStats.framesEncoded &&
|
|
671
|
+
(currentStats.framesSent === previousStats.framesSent || currentStats.framesSent === 0)
|
|
672
|
+
) {
|
|
673
|
+
this.lastEmittedStartStopEvent[mediaType].local = EVENTS.NO_FRAMES_SENT;
|
|
674
|
+
LoggerProxy.logger.info(
|
|
675
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} frames sent even though frames are encoded`
|
|
676
|
+
);
|
|
677
|
+
this.emit(
|
|
678
|
+
{
|
|
679
|
+
file: 'statsAnalyzer',
|
|
680
|
+
function: 'compareLastStatsResult',
|
|
681
|
+
},
|
|
682
|
+
EVENTS.NO_FRAMES_SENT,
|
|
683
|
+
{
|
|
684
|
+
mediaType,
|
|
685
|
+
}
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
659
689
|
this.emitStartStopEvents(
|
|
660
690
|
mediaType,
|
|
661
691
|
previousStats.framesSent,
|
|
@@ -731,14 +761,25 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
731
761
|
LoggerProxy.logger.info(
|
|
732
762
|
`StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} RTP packets sent`
|
|
733
763
|
);
|
|
734
|
-
} else {
|
|
764
|
+
} else if (this.lastEmittedStartStopEvent[mediaType].local !== EVENTS.LOCAL_MEDIA_STOPPED) {
|
|
735
765
|
if (
|
|
736
766
|
currentStats.framesEncoded === previousStats.framesEncoded ||
|
|
737
767
|
currentStats.framesEncoded === 0
|
|
738
768
|
) {
|
|
769
|
+
this.lastEmittedStartStopEvent[mediaType].local = EVENTS.NO_VIDEO_ENCODED;
|
|
739
770
|
LoggerProxy.logger.info(
|
|
740
771
|
`StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} frames getting encoded`
|
|
741
772
|
);
|
|
773
|
+
this.emit(
|
|
774
|
+
{
|
|
775
|
+
file: 'statsAnalyzer',
|
|
776
|
+
function: 'compareLastStatsResult',
|
|
777
|
+
},
|
|
778
|
+
EVENTS.NO_VIDEO_ENCODED,
|
|
779
|
+
{
|
|
780
|
+
mediaType,
|
|
781
|
+
}
|
|
782
|
+
);
|
|
742
783
|
}
|
|
743
784
|
|
|
744
785
|
if (
|
|
@@ -750,6 +791,27 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
750
791
|
`StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} frames sent`
|
|
751
792
|
);
|
|
752
793
|
}
|
|
794
|
+
|
|
795
|
+
// Share video is encoded but frames are not sent
|
|
796
|
+
if (
|
|
797
|
+
currentStats.framesEncoded !== previousStats.framesEncoded &&
|
|
798
|
+
(currentStats.framesSent === previousStats.framesSent || currentStats.framesSent === 0)
|
|
799
|
+
) {
|
|
800
|
+
this.lastEmittedStartStopEvent[mediaType].local = EVENTS.NO_FRAMES_SENT;
|
|
801
|
+
LoggerProxy.logger.info(
|
|
802
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} Frames sent even though frames are being encoded`
|
|
803
|
+
);
|
|
804
|
+
this.emit(
|
|
805
|
+
{
|
|
806
|
+
file: 'statsAnalyzer',
|
|
807
|
+
function: 'compareLastStatsResult',
|
|
808
|
+
},
|
|
809
|
+
EVENTS.NO_FRAMES_SENT,
|
|
810
|
+
{
|
|
811
|
+
mediaType,
|
|
812
|
+
}
|
|
813
|
+
);
|
|
814
|
+
}
|
|
753
815
|
}
|
|
754
816
|
|
|
755
817
|
// TODO:need to check receive share value
|
|
@@ -881,6 +943,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
881
943
|
const mediaType = type || STATS.AUDIO_CORRELATE;
|
|
882
944
|
const sendrecvType = STATS.SEND_DIRECTION;
|
|
883
945
|
|
|
946
|
+
this.processTrackResult(result, type, sendrecvType);
|
|
884
947
|
if (result.bytesSent) {
|
|
885
948
|
let kilobytes = 0;
|
|
886
949
|
|
|
@@ -904,7 +967,6 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
904
967
|
|
|
905
968
|
this.statsResults[mediaType][sendrecvType].availableBandwidth = kilobytes.toFixed(1);
|
|
906
969
|
this.statsResults[mediaType].bytesSent = kilobytes;
|
|
907
|
-
|
|
908
970
|
this.statsResults[mediaType][sendrecvType].framesEncoded =
|
|
909
971
|
result.framesEncoded - this.statsResults.internal[mediaType][sendrecvType].framesEncoded;
|
|
910
972
|
this.statsResults[mediaType][sendrecvType].keyFramesEncoded =
|
|
@@ -955,6 +1017,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
955
1017
|
const mediaType = type || STATS.AUDIO_CORRELATE;
|
|
956
1018
|
const sendrecvType = STATS.RECEIVE_DIRECTION;
|
|
957
1019
|
|
|
1020
|
+
this.processTrackResult(result, type, sendrecvType);
|
|
958
1021
|
if (result.bytesReceived) {
|
|
959
1022
|
let kilobytes = 0;
|
|
960
1023
|
|
|
@@ -1158,29 +1221,29 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1158
1221
|
* @private
|
|
1159
1222
|
* @param {*} result
|
|
1160
1223
|
* @param {*} mediaType
|
|
1224
|
+
* @param {*} sendrecvType
|
|
1161
1225
|
* @returns {void}
|
|
1162
1226
|
* @memberof StatsAnalyzer
|
|
1163
1227
|
*/
|
|
1164
|
-
private processTrackResult(result: any, mediaType: any) {
|
|
1165
|
-
if (!result ||
|
|
1228
|
+
private processTrackResult(result: any, mediaType: any, sendrecvType: any) {
|
|
1229
|
+
if (!result || mediaType === STATS.AUDIO_CORRELATE) {
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
if (result.type !== 'inbound-rtp' && result.type !== 'outbound-rtp') {
|
|
1166
1233
|
return;
|
|
1167
1234
|
}
|
|
1168
|
-
if (result.type !== 'track') return;
|
|
1169
|
-
|
|
1170
|
-
const sendrecvType =
|
|
1171
|
-
result.remoteSource === true ? STATS.RECEIVE_DIRECTION : STATS.SEND_DIRECTION;
|
|
1172
|
-
|
|
1173
1235
|
if (result.frameWidth && result.frameHeight) {
|
|
1174
1236
|
this.statsResults.resolutions[mediaType][sendrecvType].width = result.frameWidth;
|
|
1175
1237
|
this.statsResults.resolutions[mediaType][sendrecvType].height = result.frameHeight;
|
|
1176
|
-
this.statsResults.resolutions[mediaType][sendrecvType].framesSent = result.framesSent;
|
|
1177
|
-
this.statsResults.resolutions[mediaType][sendrecvType].hugeFramesSent = result.hugeFramesSent;
|
|
1178
1238
|
}
|
|
1179
1239
|
|
|
1180
1240
|
if (sendrecvType === STATS.RECEIVE_DIRECTION) {
|
|
1181
1241
|
this.statsResults.resolutions[mediaType][sendrecvType].framesReceived = result.framesReceived;
|
|
1182
1242
|
this.statsResults.resolutions[mediaType][sendrecvType].framesDecoded = result.framesDecoded;
|
|
1183
1243
|
this.statsResults.resolutions[mediaType][sendrecvType].framesDropped = result.framesDropped;
|
|
1244
|
+
} else if (sendrecvType === STATS.SEND_DIRECTION) {
|
|
1245
|
+
this.statsResults.resolutions[mediaType][sendrecvType].framesSent = result.framesSent;
|
|
1246
|
+
this.statsResults.resolutions[mediaType][sendrecvType].hugeFramesSent = result.hugeFramesSent;
|
|
1184
1247
|
}
|
|
1185
1248
|
|
|
1186
1249
|
if (result.trackIdentifier && mediaType !== STATS.AUDIO_CORRELATE) {
|
|
@@ -1329,6 +1329,71 @@ describe('plugin-meetings', () => {
|
|
|
1329
1329
|
data: {intervalData: fakeData, networkType: 'wifi'},
|
|
1330
1330
|
});
|
|
1331
1331
|
});
|
|
1332
|
+
it('NO_FRAMES_SENT triggers "meeting:noFramesSent" event and sends metrics', async () => {
|
|
1333
|
+
meeting.mediaProperties.mediaDirection = {sendVideo: true};
|
|
1334
|
+
statsAnalyzerStub.emit(
|
|
1335
|
+
{file: 'test', function: 'test'},
|
|
1336
|
+
StatsAnalyzerModule.EVENTS.NO_FRAMES_SENT,
|
|
1337
|
+
{mediaType: 'video'}
|
|
1338
|
+
);
|
|
1339
|
+
|
|
1340
|
+
assert.calledWith(
|
|
1341
|
+
TriggerProxy.trigger,
|
|
1342
|
+
sinon.match.instanceOf(Meeting),
|
|
1343
|
+
{
|
|
1344
|
+
file: 'meeting/index',
|
|
1345
|
+
function: 'compareLastStatsResult',
|
|
1346
|
+
},
|
|
1347
|
+
EVENT_TRIGGERS.MEETING_NO_FRAMES_SENT,
|
|
1348
|
+
{
|
|
1349
|
+
mediaType: 'video',
|
|
1350
|
+
}
|
|
1351
|
+
);
|
|
1352
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.NO_FRAMES_SENT);
|
|
1353
|
+
});
|
|
1354
|
+
it('NO_FRAMES_SENT triggers "meeting:noFramesSent" event and sends metrics for share', async () => {
|
|
1355
|
+
meeting.mediaProperties.mediaDirection = {sendShare: true};
|
|
1356
|
+
statsAnalyzerStub.emit(
|
|
1357
|
+
{file: 'test', function: 'test'},
|
|
1358
|
+
StatsAnalyzerModule.EVENTS.NO_FRAMES_SENT,
|
|
1359
|
+
{mediaType: 'share'}
|
|
1360
|
+
);
|
|
1361
|
+
|
|
1362
|
+
assert.calledWith(
|
|
1363
|
+
TriggerProxy.trigger,
|
|
1364
|
+
sinon.match.instanceOf(Meeting),
|
|
1365
|
+
{
|
|
1366
|
+
file: 'meeting/index',
|
|
1367
|
+
function: 'compareLastStatsResult',
|
|
1368
|
+
},
|
|
1369
|
+
EVENT_TRIGGERS.MEETING_NO_FRAMES_SENT,
|
|
1370
|
+
{
|
|
1371
|
+
mediaType: 'share',
|
|
1372
|
+
}
|
|
1373
|
+
);
|
|
1374
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.NO_FRAMES_SENT);
|
|
1375
|
+
});
|
|
1376
|
+
it('NO_VIDEO_ENCODED triggers "meeting:noVideoEncoded" event and sends metrics', async () => {
|
|
1377
|
+
statsAnalyzerStub.emit(
|
|
1378
|
+
{file: 'test', function: 'test'},
|
|
1379
|
+
StatsAnalyzerModule.EVENTS.NO_VIDEO_ENCODED,
|
|
1380
|
+
{mediaType: 'video'}
|
|
1381
|
+
);
|
|
1382
|
+
|
|
1383
|
+
assert.calledWith(
|
|
1384
|
+
TriggerProxy.trigger,
|
|
1385
|
+
sinon.match.instanceOf(Meeting),
|
|
1386
|
+
{
|
|
1387
|
+
file: 'meeting/index',
|
|
1388
|
+
function: 'compareLastStatsResult',
|
|
1389
|
+
},
|
|
1390
|
+
EVENT_TRIGGERS.MEETING_NO_VIDEO_ENCODED,
|
|
1391
|
+
{
|
|
1392
|
+
mediaType: 'video',
|
|
1393
|
+
}
|
|
1394
|
+
);
|
|
1395
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.NO_VIDEO_ENCODED);
|
|
1396
|
+
});
|
|
1332
1397
|
});
|
|
1333
1398
|
});
|
|
1334
1399
|
describe('#acknowledge', () => {
|
|
@@ -3646,14 +3711,17 @@ describe('plugin-meetings', () => {
|
|
|
3646
3711
|
describe('#setUpLocusServicesListener', () => {
|
|
3647
3712
|
it('listens to the locus services update event', (done) => {
|
|
3648
3713
|
const newLocusServices = {
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
}
|
|
3714
|
+
services: {
|
|
3715
|
+
record: {
|
|
3716
|
+
url: 'url',
|
|
3653
3717
|
},
|
|
3718
|
+
},
|
|
3654
3719
|
};
|
|
3655
3720
|
|
|
3656
|
-
meeting.recordingController = {
|
|
3721
|
+
meeting.recordingController = {
|
|
3722
|
+
setServiceUrl: sinon.stub().returns(undefined),
|
|
3723
|
+
setSessionId: sinon.stub().returns(undefined),
|
|
3724
|
+
};
|
|
3657
3725
|
|
|
3658
3726
|
meeting.locusInfo.emit(
|
|
3659
3727
|
{function: 'test', file: 'test'},
|
|
@@ -3661,7 +3729,10 @@ describe('plugin-meetings', () => {
|
|
|
3661
3729
|
newLocusServices
|
|
3662
3730
|
);
|
|
3663
3731
|
|
|
3664
|
-
assert.calledWith(
|
|
3732
|
+
assert.calledWith(
|
|
3733
|
+
meeting.recordingController.setServiceUrl,
|
|
3734
|
+
newLocusServices.services.record.url
|
|
3735
|
+
);
|
|
3665
3736
|
assert.calledOnce(meeting.recordingController.setSessionId);
|
|
3666
3737
|
done();
|
|
3667
3738
|
});
|
|
@@ -20,6 +20,13 @@ describe('member', () => {
|
|
|
20
20
|
|
|
21
21
|
assert.calledOnceWithExactly(MemberUtil.isHandRaised, participant);
|
|
22
22
|
});
|
|
23
|
+
|
|
24
|
+
it('checks that processParticipant calls canReclaimHost', () => {
|
|
25
|
+
sinon.spy(MemberUtil, 'canReclaimHost');
|
|
26
|
+
member.processParticipant(participant);
|
|
27
|
+
|
|
28
|
+
assert.calledOnceWithExactly(MemberUtil.canReclaimHost, participant);
|
|
29
|
+
});
|
|
23
30
|
})
|
|
24
31
|
|
|
25
32
|
describe('#processMember', ()=>{
|
|
@@ -78,3 +78,35 @@ describe('extractMediaStatus', () => {
|
|
|
78
78
|
assert.deepEqual(mediaStatus, {audio: 'RECVONLY', video: 'SENDRECV'});
|
|
79
79
|
});
|
|
80
80
|
});
|
|
81
|
+
|
|
82
|
+
describe('MemberUtil.canReclaimHost', () => {
|
|
83
|
+
it('throws error when there is no participant', () => {
|
|
84
|
+
assert.throws(() => {
|
|
85
|
+
MemberUtil.canReclaimHost();
|
|
86
|
+
}, 'canReclaimHostRole could not be processed, participant is undefined.');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('returns true when canReclaimHostRole is true', () => {
|
|
90
|
+
const participant = {
|
|
91
|
+
canReclaimHostRole: true,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
assert.isTrue(MemberUtil.canReclaimHost(participant));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('returns false when canReclaimHostRole is false', () => {
|
|
98
|
+
const participant = {
|
|
99
|
+
canReclaimHostRole: false,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
assert.isFalse(MemberUtil.canReclaimHost(participant));
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('returns false when canReclaimHostRole is falsy', () => {
|
|
106
|
+
const participant = {
|
|
107
|
+
canReclaimHostRole: undefined,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
assert.isFalse(MemberUtil.canReclaimHost(participant));
|
|
111
|
+
});
|
|
112
|
+
});
|