@webex/internal-plugin-metrics 3.3.1 → 3.4.0-next.1

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 (38) hide show
  1. package/dist/behavioral/behavioral-metrics.js +199 -0
  2. package/dist/behavioral/behavioral-metrics.js.map +1 -0
  3. package/dist/behavioral/config.js +11 -0
  4. package/dist/behavioral/config.js.map +1 -0
  5. package/dist/call-diagnostic/call-diagnostic-metrics.js +3 -0
  6. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  7. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +14 -11
  8. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  9. package/dist/call-diagnostic/config.js +19 -13
  10. package/dist/call-diagnostic/config.js.map +1 -1
  11. package/dist/index.js +7 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/metrics.js +1 -1
  14. package/dist/metrics.types.js.map +1 -1
  15. package/dist/new-metrics.js +31 -6
  16. package/dist/new-metrics.js.map +1 -1
  17. package/dist/types/behavioral/behavioral-metrics.d.ts +63 -0
  18. package/dist/types/behavioral/config.d.ts +1 -0
  19. package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +3 -2
  20. package/dist/types/call-diagnostic/config.d.ts +2 -0
  21. package/dist/types/index.d.ts +2 -1
  22. package/dist/types/metrics.types.d.ts +28 -7
  23. package/dist/types/new-metrics.d.ts +14 -6
  24. package/package.json +11 -11
  25. package/src/behavioral/behavioral-metrics.ts +179 -0
  26. package/src/behavioral/config.ts +3 -0
  27. package/src/call-diagnostic/call-diagnostic-metrics.ts +3 -0
  28. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +16 -17
  29. package/src/call-diagnostic/config.ts +9 -2
  30. package/src/index.ts +2 -0
  31. package/src/metrics.types.ts +59 -8
  32. package/src/new-metrics.ts +34 -8
  33. package/test/unit/spec/behavioral/behavioral-metrics.ts +164 -0
  34. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +48 -52
  35. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1 -1
  36. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +9 -0
  37. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +41 -22
  38. package/test/unit/spec/prelogin-metrics-batcher.ts +1 -1
@@ -21,6 +21,7 @@ import {
21
21
  MISSING_ROAP_ANSWER_CLIENT_CODE,
22
22
  WBX_APP_API_URL,
23
23
  ERROR_DESCRIPTIONS,
24
+ ICE_AND_REACHABILITY_FAILED_CLIENT_CODE,
24
25
  } from './config';
25
26
 
26
27
  const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
@@ -225,7 +226,7 @@ export const getBuildType = (
225
226
  */
226
227
  export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
227
228
  const origin: Partial<Event['origin']> = {
228
- buildType: exports.getBuildType(
229
+ buildType: getBuildType(
229
230
  item.eventPayload?.event?.eventData?.webClientDomain,
230
231
  item.eventPayload?.event?.eventData?.markAsTestEvent
231
232
  ),
@@ -284,6 +285,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
284
285
 
285
286
  case 'client.media.rx.start':
286
287
  joinTimes.localSDPGenRemoteSDPRecv = cdl.getLocalSDPGenRemoteSDPRecv();
288
+ audioSetupDelay.joinRespRxStart = cdl.getAudioJoinRespRxStart();
289
+ videoSetupDelay.joinRespRxStart = cdl.getVideoJoinRespRxStart();
287
290
  break;
288
291
 
289
292
  case 'client.media-engine.ready':
@@ -293,10 +296,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
293
296
  joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
294
297
  break;
295
298
 
296
- case 'client.mediaquality.event':
297
- audioSetupDelay.joinRespRxStart = cdl.getAudioJoinRespRxStart();
299
+ case 'client.media.tx.start':
298
300
  audioSetupDelay.joinRespTxStart = cdl.getAudioJoinRespTxStart();
299
- videoSetupDelay.joinRespRxStart = cdl.getVideoJoinRespRxStart();
300
301
  videoSetupDelay.joinRespTxStart = cdl.getVideoJoinRespTxStart();
301
302
  }
302
303
 
@@ -314,7 +315,6 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
314
315
 
315
316
  item.eventPayload.origin = Object.assign(origin, item.eventPayload.origin);
316
317
 
317
- // @ts-ignore
318
318
  webex.logger.log(
319
319
  `CallDiagnosticLatencies,prepareDiagnosticMetricItem: ${JSON.stringify({
320
320
  latencies: Object.fromEntries(cdl.latencyTimestamps),
@@ -370,12 +370,14 @@ export const extractVersionMetadata = (version: string) => {
370
370
  */
371
371
  export const generateClientErrorCodeForIceFailure = ({
372
372
  signalingState,
373
- iceConnectionState,
373
+ iceConnected,
374
374
  turnServerUsed,
375
+ unreachable,
375
376
  }: {
376
377
  signalingState: RTCPeerConnection['signalingState'];
377
- iceConnectionState: RTCPeerConnection['iceConnectionState'];
378
+ iceConnected: boolean;
378
379
  turnServerUsed: boolean;
380
+ unreachable: boolean;
379
381
  }) => {
380
382
  let errorCode = ICE_FAILURE_CLIENT_CODE; // default;
381
383
 
@@ -383,20 +385,17 @@ export const generateClientErrorCodeForIceFailure = ({
383
385
  errorCode = MISSING_ROAP_ANSWER_CLIENT_CODE;
384
386
  }
385
387
 
386
- if (
387
- signalingState === 'stable' &&
388
- (iceConnectionState === 'connected' || iceConnectionState === 'disconnected')
389
- ) {
388
+ if (signalingState === 'stable' && iceConnected) {
390
389
  errorCode = DTLS_HANDSHAKE_FAILED_CLIENT_CODE;
391
390
  }
392
391
 
393
- if (
394
- signalingState !== 'have-local-offer' &&
395
- iceConnectionState !== 'connected' &&
396
- iceConnectionState !== 'disconnected'
397
- ) {
392
+ if (signalingState !== 'have-local-offer' && !iceConnected) {
398
393
  if (turnServerUsed) {
399
- errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;
394
+ if (unreachable) {
395
+ errorCode = ICE_AND_REACHABILITY_FAILED_CLIENT_CODE;
396
+ } else {
397
+ errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;
398
+ }
400
399
  } else {
401
400
  errorCode = ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE;
402
401
  }
@@ -16,6 +16,7 @@ export const MISSING_ROAP_ANSWER_CLIENT_CODE = 2007;
16
16
  export const DTLS_HANDSHAKE_FAILED_CLIENT_CODE = 2008;
17
17
  export const ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE = 2010;
18
18
  export const ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE = 2009;
19
+ export const ICE_AND_REACHABILITY_FAILED_CLIENT_CODE = 2011;
19
20
  export const WBX_APP_API_URL = 'wbxappapi'; // MeetingInfo WebexAppApi response object normally contains a body.url that includes the string 'wbxappapi'
20
21
 
21
22
  export const WEBEX_SUB_SERVICE_TYPES: Record<string, ClientSubServiceType> = {
@@ -125,6 +126,7 @@ export const ERROR_DESCRIPTIONS = {
125
126
  DTLS_HANDSHAKE_FAILED: 'DTLSHandshakeFailed',
126
127
  ICE_FAILED_WITHOUT_TURN_TLS: 'ICEFailedWithoutTURN_TLS',
127
128
  ICE_FAILED_WITH_TURN_TLS: 'ICEFailedWithTURN_TLS',
129
+ ICE_AND_REACHABILITY_FAILED: 'ICEAndReachabilityFailed',
128
130
  SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError',
129
131
  SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec',
130
132
  };
@@ -377,7 +379,7 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
377
379
  },
378
380
  [MISSING_ROAP_ANSWER_CLIENT_CODE]: {
379
381
  errorDescription: ERROR_DESCRIPTIONS.MISSING_ROAP_ANSWER,
380
- category: 'signaling',
382
+ category: 'media',
381
383
  fatal: true,
382
384
  },
383
385
  [DTLS_HANDSHAKE_FAILED_CLIENT_CODE]: {
@@ -392,7 +394,12 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
392
394
  },
393
395
  [ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE]: {
394
396
  errorDescription: ERROR_DESCRIPTIONS.ICE_FAILED_WITH_TURN_TLS,
395
- category: 'network',
397
+ category: 'media',
398
+ fatal: true,
399
+ },
400
+ [ICE_AND_REACHABILITY_FAILED_CLIENT_CODE]: {
401
+ errorDescription: ERROR_DESCRIPTIONS.ICE_AND_REACHABILITY_FAILED,
402
+ category: 'expected',
396
403
  fatal: true,
397
404
  },
398
405
  2050: {
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config';
22
22
  import * as CallDiagnosticUtils from './call-diagnostic/call-diagnostic-metrics.util';
23
23
  import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
24
24
  import CallDiagnosticLatencies from './call-diagnostic/call-diagnostic-metrics-latencies';
25
+ import BehavioralMetrics from './behavioral/behavioral-metrics';
25
26
 
26
27
  registerInternalPlugin('metrics', Metrics, {
27
28
  config,
@@ -41,6 +42,7 @@ export {
41
42
  CallDiagnosticUtils,
42
43
  CallDiagnosticLatencies,
43
44
  CallDiagnosticMetrics,
45
+ BehavioralMetrics,
44
46
  };
45
47
  export type {
46
48
  ClientEvent,
@@ -20,6 +20,42 @@ export type BrowserLaunchMethodType = NonNullable<
20
20
  RawEvent['origin']['clientInfo']
21
21
  >['browserLaunchMethod'];
22
22
 
23
+ export type MetricEventProduct = 'webex' | 'wxcc_desktop';
24
+
25
+ export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';
26
+
27
+ export type MetricEventVerb =
28
+ | 'create'
29
+ | 'get'
30
+ | 'fetch'
31
+ | 'update'
32
+ | 'list'
33
+ | 'delete'
34
+ | 'select'
35
+ | 'view'
36
+ | 'set'
37
+ | 'toggle'
38
+ | 'load'
39
+ | 'reload'
40
+ | 'click'
41
+ | 'hover'
42
+ | 'register'
43
+ | 'unregister'
44
+ | 'enable'
45
+ | 'disable'
46
+ | 'use'
47
+ | 'complete'
48
+ | 'submit'
49
+ | 'apply'
50
+ | 'cancel'
51
+ | 'abort'
52
+ | 'sync'
53
+ | 'login'
54
+ | 'logout'
55
+ | 'answer'
56
+ | 'activate'
57
+ | 'deactivate';
58
+
23
59
  export type SubmitClientEventOptions = {
24
60
  meetingId?: string;
25
61
  mediaConnections?: any[];
@@ -66,13 +102,26 @@ export interface ClientEvent {
66
102
  options?: SubmitClientEventOptions;
67
103
  }
68
104
 
105
+ export interface BehavioralEventContext {
106
+ app: {version: string};
107
+ device: {id: string};
108
+ locale: string;
109
+ os: {
110
+ name: string;
111
+ version: string;
112
+ };
113
+ }
114
+
69
115
  export interface BehavioralEvent {
70
- // TODO: not implemented
71
- name: 'host.meeting.participant.admitted' | 'sdk.media-flow.started';
72
- payload?: never;
73
- options?: never;
116
+ context: BehavioralEventContext;
117
+ metricName: string;
118
+ tags: Record<string, string | number | boolean>;
119
+ timestamp: number;
120
+ type: string[];
74
121
  }
75
122
 
123
+ export type BehavioralEventPayload = BehavioralEvent['tags'];
124
+
76
125
  export interface OperationalEvent {
77
126
  // TODO: not implemented
78
127
  name: never;
@@ -104,7 +153,7 @@ export type RecursivePartial<T> = {
104
153
  export type MetricEventNames =
105
154
  | InternalEvent['name']
106
155
  | ClientEvent['name']
107
- | BehavioralEvent['name']
156
+ | BehavioralEvent['metricName']
108
157
  | OperationalEvent['name']
109
158
  | FeatureEvent['name']
110
159
  | MediaQualityEvent['name'];
@@ -137,9 +186,11 @@ export type SubmitInternalEvent = (args: {
137
186
  }) => void;
138
187
 
139
188
  export type SubmitBehavioralEvent = (args: {
140
- name: BehavioralEvent['name'];
141
- payload?: RecursivePartial<BehavioralEvent['payload']>;
142
- options?: any;
189
+ product: MetricEventProduct;
190
+ agent: MetricEventAgent;
191
+ target: string;
192
+ verb: MetricEventVerb;
193
+ payload?: BehavioralEventPayload;
143
194
  }) => void;
144
195
 
145
196
  export type SubmitClientEvent = (args: {
@@ -6,11 +6,15 @@
6
6
  import {WebexPlugin} from '@webex/webex-core';
7
7
 
8
8
  import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
9
+ import BehavioralMetrics from './behavioral/behavioral-metrics';
9
10
  import {
10
11
  RecursivePartial,
12
+ MetricEventProduct,
13
+ MetricEventAgent,
14
+ MetricEventVerb,
11
15
  ClientEvent,
12
16
  FeatureEvent,
13
- BehavioralEvent,
17
+ BehavioralEventPayload,
14
18
  OperationalEvent,
15
19
  MediaQualityEvent,
16
20
  InternalEvent,
@@ -32,6 +36,7 @@ class Metrics extends WebexPlugin {
32
36
  callDiagnosticLatencies: CallDiagnosticLatencies;
33
37
  // Helper classes to handle the different types of metrics
34
38
  callDiagnosticMetrics: CallDiagnosticMetrics;
39
+ behavioralMetrics: BehavioralMetrics;
35
40
 
36
41
  /**
37
42
  * Constructor
@@ -56,6 +61,8 @@ class Metrics extends WebexPlugin {
56
61
  this.webex.once('ready', () => {
57
62
  // @ts-ignore
58
63
  this.callDiagnosticMetrics = new CallDiagnosticMetrics({}, {parent: this.webex});
64
+ // @ts-ignore
65
+ this.behavioralMetrics = new BehavioralMetrics({}, {parent: this.webex});
59
66
  });
60
67
  }
61
68
 
@@ -79,21 +86,40 @@ class Metrics extends WebexPlugin {
79
86
  }
80
87
  }
81
88
 
89
+ /**
90
+ * @returns true once we have the deviceId we need to submit behavioral events to Amplitude
91
+ */
92
+ isReadyToSubmitBehavioralEvents() {
93
+ return this.behavioralMetrics.isReadyToSubmitBehavioralEvents();
94
+ }
95
+
82
96
  /**
83
97
  * Behavioral event
84
98
  * @param args
85
99
  */
86
100
  submitBehavioralEvent({
87
- name,
101
+ product,
102
+ agent,
103
+ target,
104
+ verb,
88
105
  payload,
89
- options,
90
106
  }: {
91
- name: BehavioralEvent['name'];
92
- payload?: RecursivePartial<BehavioralEvent['payload']>;
93
- options?: any;
107
+ product: MetricEventProduct;
108
+ agent: MetricEventAgent;
109
+ target: string;
110
+ verb: MetricEventVerb;
111
+ payload?: BehavioralEventPayload;
94
112
  }) {
95
- this.callDiagnosticLatencies.saveTimestamp({key: name});
96
- throw new Error('Not implemented.');
113
+ if (!this.behavioralMetrics) {
114
+ // @ts-ignore
115
+ this.webex.logger.log(
116
+ `NewMetrics: @submitBehavioralEvent. Attempted to submit before webex.ready: ${product}.${agent}.${target}.${verb}`
117
+ );
118
+
119
+ return Promise.resolve();
120
+ }
121
+
122
+ return this.behavioralMetrics.submitBehavioralEvent({product, agent, target, verb, payload});
97
123
  }
98
124
 
99
125
  /**
@@ -0,0 +1,164 @@
1
+ import sinon from 'sinon';
2
+ import {assert} from '@webex/test-helper-chai';
3
+ import {BrowserDetection} from '@webex/common';
4
+ import {BehavioralMetrics, config, getOSNameInternal} from '@webex/internal-plugin-metrics';
5
+ import uuid from 'uuid';
6
+ import {merge} from 'lodash';
7
+
8
+ //@ts-ignore
9
+ global.window = {location: {hostname: 'whatever'}, navigator: {language: 'language'}};
10
+ process.env.NODE_ENV = 'test';
11
+
12
+ const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
13
+
14
+ describe('internal-plugin-metrics', () => {
15
+ describe('BehavioralMetrics', () => {
16
+ let webex;
17
+ let now;
18
+ let behavioralMetrics: BehavioralMetrics;
19
+
20
+ const tags = {key: 'val'};
21
+
22
+ beforeEach(() => {
23
+ now = new Date();
24
+
25
+ webex = {
26
+ canAuthorize: true,
27
+ version: 'webex-version',
28
+ internal: {
29
+ services: {
30
+ get: () => 'locus-url',
31
+ },
32
+ metrics: {
33
+ submitClientMetrics: sinon.stub(),
34
+ config: {...config.metrics},
35
+ },
36
+ newMetrics: {},
37
+ device: {
38
+ userId: 'userId',
39
+ url: 'https://wdm-intb.ciscospark.com/wdm/api/v1/devices/deviceId',
40
+ orgId: 'orgId',
41
+ },
42
+ },
43
+ meetings: {
44
+ config: {
45
+ metrics: {
46
+ clientType: 'TEAMS_CLIENT',
47
+ subClientType: 'WEB_APP',
48
+ clientName: 'Cantina',
49
+ },
50
+ },
51
+ geoHintInfo: {
52
+ clientAddress: '1.3.4.5',
53
+ countryCode: 'UK',
54
+ },
55
+ },
56
+ credentials: {
57
+ isUnverifiedGuest: false,
58
+ },
59
+ prepareFetchOptions: sinon.stub().callsFake((opts: any) => ({...opts, foo: 'bar'})),
60
+ request: sinon.stub().resolves({body: {}}),
61
+ logger: {
62
+ log: sinon.stub(),
63
+ error: sinon.stub(),
64
+ },
65
+ };
66
+
67
+ sinon.createSandbox();
68
+ sinon.useFakeTimers(now.getTime());
69
+ behavioralMetrics = new BehavioralMetrics({}, {parent: webex});
70
+ sinon.stub(uuid, 'v4').returns('my-fake-id');
71
+ });
72
+
73
+ afterEach(() => {
74
+ sinon.restore();
75
+ });
76
+
77
+ describe('#getContext', () => {
78
+ it('should build context correctly', () => {
79
+ const res = behavioralMetrics.getContext();
80
+
81
+ assert.deepEqual(res, {
82
+ app: {
83
+ version: 'webex-version',
84
+ },
85
+ device: {
86
+ id: 'deviceId',
87
+ },
88
+ locale: 'language',
89
+ os: {
90
+ name: getOSNameInternal(),
91
+ version: getOSVersion(),
92
+ },
93
+ });
94
+ });
95
+ });
96
+
97
+ describe('#getDefaultTags', () => {
98
+ it('should build tags correctly', () => {
99
+ const res = behavioralMetrics.getDefaultTags();
100
+
101
+ assert.deepEqual(res, {
102
+ browser: getBrowserName(),
103
+ browserHeight: window.innerHeight,
104
+ browserVersion: getBrowserVersion(),
105
+ browserWidth: window.innerWidth,
106
+ domain: window.location.hostname,
107
+ inIframe: false,
108
+ locale: window.navigator.language,
109
+ os: getOSNameInternal(),
110
+ });
111
+ });
112
+ });
113
+
114
+ describe('#isReadyToSubmitBehavioralEvents', () => {
115
+ it('should return true when we have a deviceId, false when deviceId is empty or undefined', async () => {
116
+ assert.equal(true, behavioralMetrics.isReadyToSubmitBehavioralEvents());
117
+
118
+ webex.internal.device.url = "";
119
+ assert.equal(false, behavioralMetrics.isReadyToSubmitBehavioralEvents());
120
+
121
+ delete webex.internal.device.url;
122
+ assert.equal(false, behavioralMetrics.isReadyToSubmitBehavioralEvents());
123
+ });
124
+ });
125
+
126
+ describe('#createEventObject', () => {
127
+ it('should build event object correctly', async () => {
128
+ const res = behavioralMetrics.createEventObject({
129
+ product: 'webex',
130
+ agent: 'user',
131
+ target: 'target',
132
+ verb: 'create',
133
+ payload: tags,
134
+ });
135
+
136
+ assert.deepEqual(res, {
137
+ context: {
138
+ app: {
139
+ version: 'webex-version',
140
+ },
141
+ device: {
142
+ id: 'deviceId',
143
+ },
144
+ locale: 'language',
145
+ os: {
146
+ name: getOSNameInternal(),
147
+ version: getOSVersion(),
148
+ },
149
+ },
150
+ metricName: 'webex.user.target.create',
151
+ tags: merge(tags, {
152
+ browser: getBrowserName(),
153
+ browserVersion: getBrowserVersion(),
154
+ domain: window.location.hostname,
155
+ locale: window.navigator.language,
156
+ os: getOSNameInternal(),
157
+ }),
158
+ timestamp: res.timestamp,
159
+ type: ['behavioral'],
160
+ });
161
+ });
162
+ });
163
+ });
164
+ });
@@ -248,9 +248,15 @@ describe('plugin-metrics', () => {
248
248
  });
249
249
 
250
250
  it('appends the correct join times to the request for client.media.rx.start', async () => {
251
- webex.internal.newMetrics.callDiagnosticLatencies.getDiffBetweenTimestamps = sinon
251
+ webex.internal.newMetrics.callDiagnosticLatencies.getLocalSDPGenRemoteSDPRecv = sinon
252
+ .stub()
253
+ .returns(5);
254
+ webex.internal.newMetrics.callDiagnosticLatencies.getAudioJoinRespRxStart = sinon
252
255
  .stub()
253
256
  .returns(10);
257
+ webex.internal.newMetrics.callDiagnosticLatencies.getVideoJoinRespRxStart = sinon
258
+ .stub()
259
+ .returns(20);
254
260
  const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
255
261
  //@ts-ignore
256
262
  {event: {name: 'client.media.rx.start'}}
@@ -265,7 +271,13 @@ describe('plugin-metrics', () => {
265
271
  assert.deepEqual(webex.request.getCalls()[0].args[0].body.metrics[0].eventPayload.event, {
266
272
  name: 'client.media.rx.start',
267
273
  joinTimes: {
268
- localSDPGenRemoteSDPRecv: 10,
274
+ localSDPGenRemoteSDPRecv: 5,
275
+ },
276
+ audioSetupDelay: {
277
+ joinRespRxStart: 10,
278
+ },
279
+ videoSetupDelay: {
280
+ joinRespRxStart: 20,
269
281
  },
270
282
  });
271
283
  assert.lengthOf(
@@ -274,19 +286,16 @@ describe('plugin-metrics', () => {
274
286
  );
275
287
  });
276
288
 
277
- it('appends the correct join times to the request for client.media-engine.ready', async () => {
278
- webex.internal.newMetrics.callDiagnosticLatencies.getDiffBetweenTimestamps = sinon
279
- .stub()
280
- .returns(10);
281
- webex.internal.newMetrics.callDiagnosticLatencies.getInterstitialToMediaOKJMT = sinon
289
+ it('appends the correct join times to the request for client.media.tx.start', async () => {
290
+ webex.internal.newMetrics.callDiagnosticLatencies.getAudioJoinRespTxStart = sinon
282
291
  .stub()
283
292
  .returns(10);
284
- webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitial = sinon
293
+ webex.internal.newMetrics.callDiagnosticLatencies.getVideoJoinRespTxStart = sinon
285
294
  .stub()
286
- .returns(10);
295
+ .returns(20);
287
296
  const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
288
297
  //@ts-ignore
289
- {event: {name: 'client.media-engine.ready'}}
298
+ {event: {name: 'client.media.tx.start'}}
290
299
  );
291
300
  await flushPromises();
292
301
  clock.tick(config.metrics.batcherWait);
@@ -296,12 +305,12 @@ describe('plugin-metrics', () => {
296
305
  //@ts-ignore
297
306
  assert.calledOnce(webex.request);
298
307
  assert.deepEqual(webex.request.getCalls()[0].args[0].body.metrics[0].eventPayload.event, {
299
- name: 'client.media-engine.ready',
300
- joinTimes: {
301
- totalMediaJMT: 30,
302
- interstitialToMediaOKJMT: 10,
303
- callInitMediaEngineReady: 10,
304
- stayLobbyTime: 10,
308
+ name: 'client.media.tx.start',
309
+ audioSetupDelay: {
310
+ joinRespTxStart: 10,
311
+ },
312
+ videoSetupDelay: {
313
+ joinRespTxStart: 20,
305
314
  },
306
315
  });
307
316
  assert.lengthOf(
@@ -310,13 +319,28 @@ describe('plugin-metrics', () => {
310
319
  );
311
320
  });
312
321
 
313
- it('appends the correct audio and video setup delays to the request for client.mediaquality.event', async () => {
322
+ it('appends the correct join times to the request for client.media-engine.ready', async () => {
314
323
  webex.internal.newMetrics.callDiagnosticLatencies.getDiffBetweenTimestamps = sinon
315
324
  .stub()
316
325
  .returns(10);
326
+ webex.internal.newMetrics.callDiagnosticLatencies.getInterstitialToMediaOKJMT = sinon
327
+ .stub()
328
+ .returns(22);
329
+ webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitial = sinon
330
+ .stub()
331
+ .returns(35);
332
+ webex.internal.newMetrics.callDiagnosticLatencies.getInterstitialToJoinOK = sinon
333
+ .stub()
334
+ .returns(5);
335
+ webex.internal.newMetrics.callDiagnosticLatencies.getInterstitialToJoinOK = sinon
336
+ .stub()
337
+ .returns(7);
338
+ webex.internal.newMetrics.callDiagnosticLatencies.getStayLobbyTime = sinon
339
+ .stub()
340
+ .returns(1);
317
341
  const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
318
342
  //@ts-ignore
319
- {event: {name: 'client.mediaquality.event'}}
343
+ {event: {name: 'client.media-engine.ready'}}
320
344
  );
321
345
  await flushPromises();
322
346
  clock.tick(config.metrics.batcherWait);
@@ -326,14 +350,12 @@ describe('plugin-metrics', () => {
326
350
  //@ts-ignore
327
351
  assert.calledOnce(webex.request);
328
352
  assert.deepEqual(webex.request.getCalls()[0].args[0].body.metrics[0].eventPayload.event, {
329
- name: 'client.mediaquality.event',
330
- audioSetupDelay: {
331
- joinRespRxStart: 10,
332
- joinRespTxStart: 10,
333
- },
334
- videoSetupDelay: {
335
- joinRespRxStart: 10,
336
- joinRespTxStart: 10,
353
+ name: 'client.media-engine.ready',
354
+ joinTimes: {
355
+ totalMediaJMT: 61,
356
+ interstitialToMediaOKJMT: 22,
357
+ callInitMediaEngineReady: 10,
358
+ stayLobbyTime: 1,
337
359
  },
338
360
  });
339
361
  assert.lengthOf(
@@ -341,32 +363,6 @@ describe('plugin-metrics', () => {
341
363
  0
342
364
  );
343
365
  });
344
-
345
- it('doesnt include audioSetup and videoSetup delays for other events', async () => {
346
- const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
347
- //@ts-ignore
348
- {event: {name: 'client.alert.displayed'}}
349
- );
350
- await flushPromises();
351
- clock.tick(config.metrics.batcherWait);
352
-
353
- await promise;
354
-
355
- //@ts-ignore
356
- assert.calledOnce(webex.request);
357
- assert.deepEqual(
358
- webex.request.getCalls()[0].args[0].body.metrics[0].eventPayload.event.audioSetupDelay,
359
- undefined
360
- );
361
- assert.deepEqual(
362
- webex.request.getCalls()[0].args[0].body.metrics[0].eventPayload.event.videoSetupDelay,
363
- undefined
364
- );
365
- assert.lengthOf(
366
- webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.queue,
367
- 0
368
- );
369
- });
370
366
  });
371
367
 
372
368
  describe('when the request fails', () => {
@@ -668,7 +668,7 @@ describe('internal-plugin-metrics', () => {
668
668
  assert.deepEqual(cdl.getInterstitialToMediaOKJMT(), 10);
669
669
  });
670
670
 
671
- it('calculates getU2CTime correctly', () => {
671
+ describe('calculates getU2CTime correctly', () => {
672
672
  it('returns undefined when no precomputed value available', () => {
673
673
  assert.deepEqual(cdl.getU2CTime(), undefined);
674
674
  });
@@ -1454,6 +1454,9 @@ describe('internal-plugin-metrics', () => {
1454
1454
  eventData: {webClientDomain: 'whatever'},
1455
1455
  intervals: [{}],
1456
1456
  callingServiceType: 'LOCUS',
1457
+ meetingJoinInfo: {
1458
+ clientSignallingProtocol: 'WebRTC',
1459
+ },
1457
1460
  sourceMetadata: {
1458
1461
  applicationSoftwareType: 'webex-js-sdk',
1459
1462
  applicationSoftwareVersion: 'webex-version',
@@ -1490,6 +1493,9 @@ describe('internal-plugin-metrics', () => {
1490
1493
  eventData: {webClientDomain: 'whatever'},
1491
1494
  intervals: [{}],
1492
1495
  callingServiceType: 'LOCUS',
1496
+ meetingJoinInfo: {
1497
+ clientSignallingProtocol: 'WebRTC',
1498
+ },
1493
1499
  sourceMetadata: {
1494
1500
  applicationSoftwareType: 'webex-js-sdk',
1495
1501
  applicationSoftwareVersion: 'webex-version',
@@ -1524,6 +1530,9 @@ describe('internal-plugin-metrics', () => {
1524
1530
  eventData: {webClientDomain: 'whatever'},
1525
1531
  intervals: [{}],
1526
1532
  callingServiceType: 'LOCUS',
1533
+ meetingJoinInfo: {
1534
+ clientSignallingProtocol: 'WebRTC',
1535
+ },
1527
1536
  sourceMetadata: {
1528
1537
  applicationSoftwareType: 'webex-js-sdk',
1529
1538
  applicationSoftwareVersion: 'webex-version',