@webex/plugin-meetings 3.9.0-next.19 → 3.9.0-next.20
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/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/media/properties.js +53 -5
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.js +109 -73
- package/dist/meeting/index.js.map +1 -1
- package/dist/metrics/constants.js +2 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/media/properties.d.ts +21 -0
- package/dist/types/meeting/index.d.ts +2 -1
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +3 -3
- package/src/constants.ts +1 -0
- package/src/media/properties.ts +43 -0
- package/src/meeting/index.ts +47 -0
- package/src/metrics/constants.ts +1 -0
- package/test/unit/spec/media/properties.ts +137 -0
- package/test/unit/spec/meeting/index.js +175 -4
@@ -91,6 +91,7 @@ var BEHAVIORAL_METRICS = exports.default = {
|
|
91
91
|
GUEST_EXITED_LOBBY: 'js_sdk_guest_exited_lobby',
|
92
92
|
VERIFY_REGISTRATION_ID_SUCCESS: 'js_sdk_verify_registrationId_success',
|
93
93
|
VERIFY_REGISTRATION_ID_ERROR: 'js_sdk_verify_registrationId_error',
|
94
|
-
JOIN_FORBIDDEN_ERROR: 'js_sdk_join_forbidden_error'
|
94
|
+
JOIN_FORBIDDEN_ERROR: 'js_sdk_join_forbidden_error',
|
95
|
+
MEDIA_ISSUE_DETECTED: 'js_sdk_media_issue_detected'
|
95
96
|
};
|
96
97
|
//# sourceMappingURL=constants.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"names":["BEHAVIORAL_METRICS","exports","default","MEETINGS_REGISTRATION_FAILED","MEETINGS_REGISTRATION_SUCCESS","MEETINGS_REGISTRATION_STEP","MERCURY_CONNECTION_FAILURE","MERCURY_CONNECTION_RESTORED","JOIN_SUCCESS","JOIN_FAILURE","ADD_MEDIA_SUCCESS","ADD_MEDIA_FAILURE","ADD_MEDIA_RETRY","ROAP_MERCURY_EVENT_RECEIVED","CONNECTION_SUCCESS","CONNECTION_FAILURE","MEETING_LEAVE_FAILURE","MEETING_END_ALL_FAILURE","MEETING_END_ALL_INITIATED","GET_USER_MEDIA_FAILURE","GET_DISPLAY_MEDIA_FAILURE","JOIN_WITH_MEDIA_FAILURE","LLM_CONNECTION_AFTER_JOIN_FAILURE","RECEIVE_TRANSCRIPTION_AFTER_JOIN_FAILURE","DISCONNECT_DUE_TO_INACTIVITY","MEETING_MEDIA_INACTIVE","MEETING_RECONNECT_FAILURE","MEETING_MAX_REJOIN_FAILURE","MEETING_SHARE_SUCCESS","MEETING_SHARE_FAILURE","MEETING_START_WHITEBOARD_SHARE_FAILURE","MEETING_STOP_WHITEBOARD_SHARE_FAILURE","MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE","MUTE_AUDIO_FAILURE","MUTE_VIDEO_FAILURE","SET_MEETING_QUALITY_FAILURE","STOP_FLOOR_REQUEST_FAILURE","ADD_DIAL_IN_FAILURE","ADD_DIAL_OUT_FAILURE","UPDATE_MEDIA_FAILURE","UNMUTE_AUDIO_FAILURE","UNMUTE_VIDEO_FAILURE","ROAP_ANSWER_FAILURE","ROAP_GLARE_CONDITION","PEERCONNECTION_FAILURE","INVALID_ICE_CANDIDATE","UPLOAD_LOGS_FAILURE","UPLOAD_LOGS_SUCCESS","RECEIVE_TRANSCRIPTION_FAILURE","MEETING_IS_IN_PROGRESS_ERROR","STATIC_MEETING_LINK_ALREADY_EXISTS_ERROR","FETCH_MEETING_INFO_V1_SUCCESS","FETCH_MEETING_INFO_V1_FAILURE","ENABLE_STATIC_METTING_LINK_SUCCESS","ENABLE_STATIC_METTING_LINK_FAILURE","DISABLE_STATIC_MEETING_LINK_SUCCESS","DISABLE_STATIC_MEETING_LINK_FAILURE","ADHOC_MEETING_SUCCESS","ADHOC_MEETING_FAILURE","FETCH_STATIC_MEETING_LINK_SUCCESS","FETCH_STATIC_MEETING_LINK_FAILURE","MEETING_LINK_DOES_NOT_EXIST_ERROR","VERIFY_PASSWORD_SUCCESS","VERIFY_PASSWORD_ERROR","VERIFY_CAPTCHA_ERROR","MOVE_TO_SUCCESS","MOVE_TO_FAILURE","MOVE_FROM_SUCCESS","MOVE_FROM_FAILURE","TURN_DISCOVERY_FAILURE","MEETING_INFO_POLICY_ERROR","LOCUS_DELTA_SYNC_FAILED","LOCUS_DELTA_OUT_OF_ORDER","LOCUS_SYNC_HANDLING_FAILED","PERMISSION_TOKEN_REFRESH","PERMISSION_TOKEN_REFRESH_ERROR","TURN_DISCOVERY_LATENCY","ROAP_OFFER_TO_ANSWER_LATENCY","ROAP_HTTP_RESPONSE_MISSING","TURN_DISCOVERY_REQUIRES_OK","REACHABILITY_COMPLETED","JOIN_WEBINAR_ERROR","GUEST_ENTERED_LOBBY","GUEST_EXITED_LOBBY","VERIFY_REGISTRATION_ID_SUCCESS","VERIFY_REGISTRATION_ID_ERROR","JOIN_FORBIDDEN_ERROR"],"sources":["constants.ts"],"sourcesContent":["// Metrics constants ----------------------------------------------------------\n\nconst BEHAVIORAL_METRICS = {\n MEETINGS_REGISTRATION_FAILED: 'js_sdk_meetings_registration_failed',\n MEETINGS_REGISTRATION_SUCCESS: 'js_sdk_meetings_registration_success',\n MEETINGS_REGISTRATION_STEP: 'meetings_registration_step',\n MERCURY_CONNECTION_FAILURE: 'js_sdk_mercury_connection_failure',\n MERCURY_CONNECTION_RESTORED: 'js_sdk_mercury_connection_restored',\n JOIN_SUCCESS: 'js_sdk_join_success',\n JOIN_FAILURE: 'js_sdk_join_failures',\n ADD_MEDIA_SUCCESS: 'js_sdk_add_media_success',\n ADD_MEDIA_FAILURE: 'js_sdk_add_media_failures',\n ADD_MEDIA_RETRY: 'js_sdk_add_media_retry',\n ROAP_MERCURY_EVENT_RECEIVED: 'js_sdk_roap_mercury_received',\n CONNECTION_SUCCESS: 'js_sdk_connection_success',\n CONNECTION_FAILURE: 'js_sdk_connection_failures',\n MEETING_LEAVE_FAILURE: 'js_sdk_meeting_leave_failure',\n MEETING_END_ALL_FAILURE: 'js_sdk_meeting_end_for_all_failure',\n MEETING_END_ALL_INITIATED: 'js_sdk_meeting_end_for_all_initiated',\n GET_USER_MEDIA_FAILURE: 'js_sdk_get_user_media_failures',\n GET_DISPLAY_MEDIA_FAILURE: 'js_sdk_get_display_media_failures',\n JOIN_WITH_MEDIA_FAILURE: 'js_sdk_join_with_media_failures',\n LLM_CONNECTION_AFTER_JOIN_FAILURE: 'js_sdk_llm_connection_after_join_failure',\n RECEIVE_TRANSCRIPTION_AFTER_JOIN_FAILURE: 'js_sdk_receive_transcription_after_join_failure',\n\n DISCONNECT_DUE_TO_INACTIVITY: 'js_sdk_disconnect_due_to_inactivity',\n MEETING_MEDIA_INACTIVE: 'js_sdk_meeting_media_inactive',\n MEETING_RECONNECT_FAILURE: 'js_sdk_meeting_reconnect_failures',\n MEETING_MAX_REJOIN_FAILURE: 'js_sdk_meeting_max_rejoin_failure',\n MEETING_SHARE_SUCCESS: 'js_sdk_meeting_share_success',\n MEETING_SHARE_FAILURE: 'js_sdk_meeting_share_failures',\n MEETING_START_WHITEBOARD_SHARE_FAILURE: 'js_sdk_meeting_start_whiteboard_share_failures',\n MEETING_STOP_WHITEBOARD_SHARE_FAILURE: 'js_sdk_meeting_stop_whiteboard_share_failures',\n MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE: 'js_sdk_meeting_share_video_mute_state_change',\n MUTE_AUDIO_FAILURE: 'js_sdk_mute_audio_failures',\n MUTE_VIDEO_FAILURE: 'js_sdk_mute_video_failures',\n SET_MEETING_QUALITY_FAILURE: 'js_sdk_set_meeting_quality_failures',\n STOP_FLOOR_REQUEST_FAILURE: 'js_sdk_stop_floor_request_failures',\n ADD_DIAL_IN_FAILURE: 'js_sdk_add_dial_in_failure',\n ADD_DIAL_OUT_FAILURE: 'js_sdk_add_dial_out_failure',\n UPDATE_MEDIA_FAILURE: 'js_sdk_update_media_failures',\n UNMUTE_AUDIO_FAILURE: 'js_sdk_unmute_audio_failures',\n UNMUTE_VIDEO_FAILURE: 'js_sdk_unmute_video_failures',\n ROAP_ANSWER_FAILURE: 'js_sdk_roap_answer_failures',\n ROAP_GLARE_CONDITION: 'js_sdk_roap_glar_condition',\n PEERCONNECTION_FAILURE: 'js_sdk_peerConnection_failures',\n INVALID_ICE_CANDIDATE: 'js_sdk_invalid_ice_candidate',\n UPLOAD_LOGS_FAILURE: 'js_sdk_upload_logs_failure',\n UPLOAD_LOGS_SUCCESS: 'js_sdk_upload_logs_success',\n RECEIVE_TRANSCRIPTION_FAILURE: 'js_sdk_receive_transcription_failure',\n MEETING_IS_IN_PROGRESS_ERROR: 'js_sdk_meeting_is_in_progress_error',\n STATIC_MEETING_LINK_ALREADY_EXISTS_ERROR: 'js_sdk_static_meeting_link_already_exists_error',\n FETCH_MEETING_INFO_V1_SUCCESS: 'js_sdk_fetch_meeting_info_v1_success',\n FETCH_MEETING_INFO_V1_FAILURE: 'js_sdk_fetch_meeting_info_v1_failure',\n ENABLE_STATIC_METTING_LINK_SUCCESS: 'js_sdk_enable_static_meeting_link_success',\n ENABLE_STATIC_METTING_LINK_FAILURE: 'js_sdk_enable_static_meeting_link_failure',\n DISABLE_STATIC_MEETING_LINK_SUCCESS: 'js_sdk_disable_static_meeting_link_success',\n DISABLE_STATIC_MEETING_LINK_FAILURE: 'js_sdk_disable_static_meeting_link_failure',\n ADHOC_MEETING_SUCCESS: 'js_sdk_adhoc_meeting_success',\n ADHOC_MEETING_FAILURE: 'js_sdk_adhoc_meeting_failure',\n FETCH_STATIC_MEETING_LINK_SUCCESS: 'js_sdk_fetch_static_meeting_link_success',\n FETCH_STATIC_MEETING_LINK_FAILURE: 'js_sdk_fetch_static_meeting_link_failure',\n MEETING_LINK_DOES_NOT_EXIST_ERROR: 'js_sdk_meeting_link_does_not_exist_error',\n VERIFY_PASSWORD_SUCCESS: 'js_sdk_verify_password_success',\n VERIFY_PASSWORD_ERROR: 'js_sdk_verify_password_error',\n VERIFY_CAPTCHA_ERROR: 'js_sdk_verify_captcha_error',\n MOVE_TO_SUCCESS: 'js_sdk_move_to_success',\n MOVE_TO_FAILURE: 'js_sdk_move_to_failure',\n MOVE_FROM_SUCCESS: 'js_sdk_move_from_success',\n MOVE_FROM_FAILURE: 'js_sdk_move_from_failure',\n TURN_DISCOVERY_FAILURE: 'js_sdk_turn_discovery_failure',\n MEETING_INFO_POLICY_ERROR: 'js_sdk_meeting_info_policy_error',\n LOCUS_DELTA_SYNC_FAILED: 'js_sdk_locus_delta_sync_failed',\n LOCUS_DELTA_OUT_OF_ORDER: 'js_sdk_locus_delta_ooo',\n LOCUS_SYNC_HANDLING_FAILED: 'js_sdk_locus_sync_handling_failed',\n PERMISSION_TOKEN_REFRESH: 'js_sdk_permission_token_refresh',\n PERMISSION_TOKEN_REFRESH_ERROR: 'js_sdk_permission_token_refresh_error',\n TURN_DISCOVERY_LATENCY: 'js_sdk_turn_discovery_latency',\n ROAP_OFFER_TO_ANSWER_LATENCY: 'js_sdk_roap_offer_to_answer_latency',\n ROAP_HTTP_RESPONSE_MISSING: 'js_sdk_roap_http_response_missing',\n TURN_DISCOVERY_REQUIRES_OK: 'js_sdk_turn_discovery_requires_ok',\n REACHABILITY_COMPLETED: 'js_sdk_reachability_completed',\n JOIN_WEBINAR_ERROR: 'js_sdk_join_webinar_error',\n GUEST_ENTERED_LOBBY: 'js_sdk_guest_entered_lobby',\n GUEST_EXITED_LOBBY: 'js_sdk_guest_exited_lobby',\n VERIFY_REGISTRATION_ID_SUCCESS: 'js_sdk_verify_registrationId_success',\n VERIFY_REGISTRATION_ID_ERROR: 'js_sdk_verify_registrationId_error',\n JOIN_FORBIDDEN_ERROR: 'js_sdk_join_forbidden_error',\n};\n\nexport {BEHAVIORAL_METRICS as default};\n"],"mappings":"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"}
|
1
|
+
{"version":3,"names":["BEHAVIORAL_METRICS","exports","default","MEETINGS_REGISTRATION_FAILED","MEETINGS_REGISTRATION_SUCCESS","MEETINGS_REGISTRATION_STEP","MERCURY_CONNECTION_FAILURE","MERCURY_CONNECTION_RESTORED","JOIN_SUCCESS","JOIN_FAILURE","ADD_MEDIA_SUCCESS","ADD_MEDIA_FAILURE","ADD_MEDIA_RETRY","ROAP_MERCURY_EVENT_RECEIVED","CONNECTION_SUCCESS","CONNECTION_FAILURE","MEETING_LEAVE_FAILURE","MEETING_END_ALL_FAILURE","MEETING_END_ALL_INITIATED","GET_USER_MEDIA_FAILURE","GET_DISPLAY_MEDIA_FAILURE","JOIN_WITH_MEDIA_FAILURE","LLM_CONNECTION_AFTER_JOIN_FAILURE","RECEIVE_TRANSCRIPTION_AFTER_JOIN_FAILURE","DISCONNECT_DUE_TO_INACTIVITY","MEETING_MEDIA_INACTIVE","MEETING_RECONNECT_FAILURE","MEETING_MAX_REJOIN_FAILURE","MEETING_SHARE_SUCCESS","MEETING_SHARE_FAILURE","MEETING_START_WHITEBOARD_SHARE_FAILURE","MEETING_STOP_WHITEBOARD_SHARE_FAILURE","MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE","MUTE_AUDIO_FAILURE","MUTE_VIDEO_FAILURE","SET_MEETING_QUALITY_FAILURE","STOP_FLOOR_REQUEST_FAILURE","ADD_DIAL_IN_FAILURE","ADD_DIAL_OUT_FAILURE","UPDATE_MEDIA_FAILURE","UNMUTE_AUDIO_FAILURE","UNMUTE_VIDEO_FAILURE","ROAP_ANSWER_FAILURE","ROAP_GLARE_CONDITION","PEERCONNECTION_FAILURE","INVALID_ICE_CANDIDATE","UPLOAD_LOGS_FAILURE","UPLOAD_LOGS_SUCCESS","RECEIVE_TRANSCRIPTION_FAILURE","MEETING_IS_IN_PROGRESS_ERROR","STATIC_MEETING_LINK_ALREADY_EXISTS_ERROR","FETCH_MEETING_INFO_V1_SUCCESS","FETCH_MEETING_INFO_V1_FAILURE","ENABLE_STATIC_METTING_LINK_SUCCESS","ENABLE_STATIC_METTING_LINK_FAILURE","DISABLE_STATIC_MEETING_LINK_SUCCESS","DISABLE_STATIC_MEETING_LINK_FAILURE","ADHOC_MEETING_SUCCESS","ADHOC_MEETING_FAILURE","FETCH_STATIC_MEETING_LINK_SUCCESS","FETCH_STATIC_MEETING_LINK_FAILURE","MEETING_LINK_DOES_NOT_EXIST_ERROR","VERIFY_PASSWORD_SUCCESS","VERIFY_PASSWORD_ERROR","VERIFY_CAPTCHA_ERROR","MOVE_TO_SUCCESS","MOVE_TO_FAILURE","MOVE_FROM_SUCCESS","MOVE_FROM_FAILURE","TURN_DISCOVERY_FAILURE","MEETING_INFO_POLICY_ERROR","LOCUS_DELTA_SYNC_FAILED","LOCUS_DELTA_OUT_OF_ORDER","LOCUS_SYNC_HANDLING_FAILED","PERMISSION_TOKEN_REFRESH","PERMISSION_TOKEN_REFRESH_ERROR","TURN_DISCOVERY_LATENCY","ROAP_OFFER_TO_ANSWER_LATENCY","ROAP_HTTP_RESPONSE_MISSING","TURN_DISCOVERY_REQUIRES_OK","REACHABILITY_COMPLETED","JOIN_WEBINAR_ERROR","GUEST_ENTERED_LOBBY","GUEST_EXITED_LOBBY","VERIFY_REGISTRATION_ID_SUCCESS","VERIFY_REGISTRATION_ID_ERROR","JOIN_FORBIDDEN_ERROR","MEDIA_ISSUE_DETECTED"],"sources":["constants.ts"],"sourcesContent":["// Metrics constants ----------------------------------------------------------\n\nconst BEHAVIORAL_METRICS = {\n MEETINGS_REGISTRATION_FAILED: 'js_sdk_meetings_registration_failed',\n MEETINGS_REGISTRATION_SUCCESS: 'js_sdk_meetings_registration_success',\n MEETINGS_REGISTRATION_STEP: 'meetings_registration_step',\n MERCURY_CONNECTION_FAILURE: 'js_sdk_mercury_connection_failure',\n MERCURY_CONNECTION_RESTORED: 'js_sdk_mercury_connection_restored',\n JOIN_SUCCESS: 'js_sdk_join_success',\n JOIN_FAILURE: 'js_sdk_join_failures',\n ADD_MEDIA_SUCCESS: 'js_sdk_add_media_success',\n ADD_MEDIA_FAILURE: 'js_sdk_add_media_failures',\n ADD_MEDIA_RETRY: 'js_sdk_add_media_retry',\n ROAP_MERCURY_EVENT_RECEIVED: 'js_sdk_roap_mercury_received',\n CONNECTION_SUCCESS: 'js_sdk_connection_success',\n CONNECTION_FAILURE: 'js_sdk_connection_failures',\n MEETING_LEAVE_FAILURE: 'js_sdk_meeting_leave_failure',\n MEETING_END_ALL_FAILURE: 'js_sdk_meeting_end_for_all_failure',\n MEETING_END_ALL_INITIATED: 'js_sdk_meeting_end_for_all_initiated',\n GET_USER_MEDIA_FAILURE: 'js_sdk_get_user_media_failures',\n GET_DISPLAY_MEDIA_FAILURE: 'js_sdk_get_display_media_failures',\n JOIN_WITH_MEDIA_FAILURE: 'js_sdk_join_with_media_failures',\n LLM_CONNECTION_AFTER_JOIN_FAILURE: 'js_sdk_llm_connection_after_join_failure',\n RECEIVE_TRANSCRIPTION_AFTER_JOIN_FAILURE: 'js_sdk_receive_transcription_after_join_failure',\n\n DISCONNECT_DUE_TO_INACTIVITY: 'js_sdk_disconnect_due_to_inactivity',\n MEETING_MEDIA_INACTIVE: 'js_sdk_meeting_media_inactive',\n MEETING_RECONNECT_FAILURE: 'js_sdk_meeting_reconnect_failures',\n MEETING_MAX_REJOIN_FAILURE: 'js_sdk_meeting_max_rejoin_failure',\n MEETING_SHARE_SUCCESS: 'js_sdk_meeting_share_success',\n MEETING_SHARE_FAILURE: 'js_sdk_meeting_share_failures',\n MEETING_START_WHITEBOARD_SHARE_FAILURE: 'js_sdk_meeting_start_whiteboard_share_failures',\n MEETING_STOP_WHITEBOARD_SHARE_FAILURE: 'js_sdk_meeting_stop_whiteboard_share_failures',\n MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE: 'js_sdk_meeting_share_video_mute_state_change',\n MUTE_AUDIO_FAILURE: 'js_sdk_mute_audio_failures',\n MUTE_VIDEO_FAILURE: 'js_sdk_mute_video_failures',\n SET_MEETING_QUALITY_FAILURE: 'js_sdk_set_meeting_quality_failures',\n STOP_FLOOR_REQUEST_FAILURE: 'js_sdk_stop_floor_request_failures',\n ADD_DIAL_IN_FAILURE: 'js_sdk_add_dial_in_failure',\n ADD_DIAL_OUT_FAILURE: 'js_sdk_add_dial_out_failure',\n UPDATE_MEDIA_FAILURE: 'js_sdk_update_media_failures',\n UNMUTE_AUDIO_FAILURE: 'js_sdk_unmute_audio_failures',\n UNMUTE_VIDEO_FAILURE: 'js_sdk_unmute_video_failures',\n ROAP_ANSWER_FAILURE: 'js_sdk_roap_answer_failures',\n ROAP_GLARE_CONDITION: 'js_sdk_roap_glar_condition',\n PEERCONNECTION_FAILURE: 'js_sdk_peerConnection_failures',\n INVALID_ICE_CANDIDATE: 'js_sdk_invalid_ice_candidate',\n UPLOAD_LOGS_FAILURE: 'js_sdk_upload_logs_failure',\n UPLOAD_LOGS_SUCCESS: 'js_sdk_upload_logs_success',\n RECEIVE_TRANSCRIPTION_FAILURE: 'js_sdk_receive_transcription_failure',\n MEETING_IS_IN_PROGRESS_ERROR: 'js_sdk_meeting_is_in_progress_error',\n STATIC_MEETING_LINK_ALREADY_EXISTS_ERROR: 'js_sdk_static_meeting_link_already_exists_error',\n FETCH_MEETING_INFO_V1_SUCCESS: 'js_sdk_fetch_meeting_info_v1_success',\n FETCH_MEETING_INFO_V1_FAILURE: 'js_sdk_fetch_meeting_info_v1_failure',\n ENABLE_STATIC_METTING_LINK_SUCCESS: 'js_sdk_enable_static_meeting_link_success',\n ENABLE_STATIC_METTING_LINK_FAILURE: 'js_sdk_enable_static_meeting_link_failure',\n DISABLE_STATIC_MEETING_LINK_SUCCESS: 'js_sdk_disable_static_meeting_link_success',\n DISABLE_STATIC_MEETING_LINK_FAILURE: 'js_sdk_disable_static_meeting_link_failure',\n ADHOC_MEETING_SUCCESS: 'js_sdk_adhoc_meeting_success',\n ADHOC_MEETING_FAILURE: 'js_sdk_adhoc_meeting_failure',\n FETCH_STATIC_MEETING_LINK_SUCCESS: 'js_sdk_fetch_static_meeting_link_success',\n FETCH_STATIC_MEETING_LINK_FAILURE: 'js_sdk_fetch_static_meeting_link_failure',\n MEETING_LINK_DOES_NOT_EXIST_ERROR: 'js_sdk_meeting_link_does_not_exist_error',\n VERIFY_PASSWORD_SUCCESS: 'js_sdk_verify_password_success',\n VERIFY_PASSWORD_ERROR: 'js_sdk_verify_password_error',\n VERIFY_CAPTCHA_ERROR: 'js_sdk_verify_captcha_error',\n MOVE_TO_SUCCESS: 'js_sdk_move_to_success',\n MOVE_TO_FAILURE: 'js_sdk_move_to_failure',\n MOVE_FROM_SUCCESS: 'js_sdk_move_from_success',\n MOVE_FROM_FAILURE: 'js_sdk_move_from_failure',\n TURN_DISCOVERY_FAILURE: 'js_sdk_turn_discovery_failure',\n MEETING_INFO_POLICY_ERROR: 'js_sdk_meeting_info_policy_error',\n LOCUS_DELTA_SYNC_FAILED: 'js_sdk_locus_delta_sync_failed',\n LOCUS_DELTA_OUT_OF_ORDER: 'js_sdk_locus_delta_ooo',\n LOCUS_SYNC_HANDLING_FAILED: 'js_sdk_locus_sync_handling_failed',\n PERMISSION_TOKEN_REFRESH: 'js_sdk_permission_token_refresh',\n PERMISSION_TOKEN_REFRESH_ERROR: 'js_sdk_permission_token_refresh_error',\n TURN_DISCOVERY_LATENCY: 'js_sdk_turn_discovery_latency',\n ROAP_OFFER_TO_ANSWER_LATENCY: 'js_sdk_roap_offer_to_answer_latency',\n ROAP_HTTP_RESPONSE_MISSING: 'js_sdk_roap_http_response_missing',\n TURN_DISCOVERY_REQUIRES_OK: 'js_sdk_turn_discovery_requires_ok',\n REACHABILITY_COMPLETED: 'js_sdk_reachability_completed',\n JOIN_WEBINAR_ERROR: 'js_sdk_join_webinar_error',\n GUEST_ENTERED_LOBBY: 'js_sdk_guest_entered_lobby',\n GUEST_EXITED_LOBBY: 'js_sdk_guest_exited_lobby',\n VERIFY_REGISTRATION_ID_SUCCESS: 'js_sdk_verify_registrationId_success',\n VERIFY_REGISTRATION_ID_ERROR: 'js_sdk_verify_registrationId_error',\n JOIN_FORBIDDEN_ERROR: 'js_sdk_join_forbidden_error',\n MEDIA_ISSUE_DETECTED: 'js_sdk_media_issue_detected',\n};\n\nexport {BEHAVIORAL_METRICS as default};\n"],"mappings":"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"}
|
@@ -258,6 +258,7 @@ export declare const EVENT_TRIGGERS: {
|
|
258
258
|
MEETING_SELF_LEFT: string;
|
259
259
|
NETWORK_QUALITY: string;
|
260
260
|
MEDIA_NEGOTIATED: string;
|
261
|
+
MEDIA_INBOUND_AUDIO_ISSUE_DETECTED: string;
|
261
262
|
ACTIVE_SPEAKER_CHANGED: string;
|
262
263
|
REMOTE_VIDEO_SOURCE_COUNT_CHANGED: string;
|
263
264
|
REMOTE_AUDIO_SOURCE_COUNT_CHANGED: string;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { LocalCameraStream, LocalMicrophoneStream, LocalDisplayStream, LocalSystemAudioStream, RemoteStream } from '@webex/media-helpers';
|
2
2
|
import { ClientEvent } from '@webex/internal-plugin-metrics';
|
3
|
+
import { throttle } from 'lodash';
|
3
4
|
export type MediaDirection = {
|
4
5
|
sendAudio: boolean;
|
5
6
|
sendVideo: boolean;
|
@@ -26,6 +27,10 @@ export default class MediaProperties {
|
|
26
27
|
videoDeviceId: any;
|
27
28
|
videoStream?: LocalCameraStream;
|
28
29
|
namespace: string;
|
30
|
+
mediaIssueCounters: {
|
31
|
+
[key: string]: number;
|
32
|
+
};
|
33
|
+
throttledSendMediaIssueMetric: ReturnType<typeof throttle>;
|
29
34
|
/**
|
30
35
|
* @param {Object} [options] -- to auto construct
|
31
36
|
* @returns {MediaProperties}
|
@@ -63,6 +68,11 @@ export default class MediaProperties {
|
|
63
68
|
* @returns {void}
|
64
69
|
*/
|
65
70
|
setVideoDeviceId(deviceId: string): void;
|
71
|
+
/**
|
72
|
+
* Clears the webrtcMediaConnection. This method should be called after
|
73
|
+
* peer connection is closed and no longer needed.
|
74
|
+
* @returns {void}
|
75
|
+
*/
|
66
76
|
unsetPeerConnection(): void;
|
67
77
|
/**
|
68
78
|
* Removes both remote audio and video from class instance
|
@@ -129,4 +139,15 @@ export default class MediaProperties {
|
|
129
139
|
selectedCandidatePairChanges: number;
|
130
140
|
numTransports: number;
|
131
141
|
}>;
|
142
|
+
/**
|
143
|
+
* Sends a metric about a media issue. Metrics are throttled so that we don't
|
144
|
+
* send too many of them, but include a count so that we know how many issues
|
145
|
+
* were detected.
|
146
|
+
*
|
147
|
+
* @param {string} issueType
|
148
|
+
* @param {string} issueSubType
|
149
|
+
* @param {string} correlationId
|
150
|
+
* @returns {void}
|
151
|
+
*/
|
152
|
+
sendMediaIssueMetric(issueType: string, issueSubType: string, correlationId: any): void;
|
132
153
|
}
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import { StatelessWebexPlugin } from '@webex/webex-core';
|
3
3
|
import { ClientEvent, ClientEventLeaveReason } from '@webex/internal-plugin-metrics';
|
4
4
|
import { ClientEvent as RawClientEvent } from '@webex/event-dictionary-ts';
|
5
|
-
import { MediaType, StatsAnalyzer, NetworkQualityMonitor } from '@webex/internal-media-core';
|
5
|
+
import { MediaType, StatsAnalyzer, NetworkQualityMonitor, StatsMonitor } from '@webex/internal-media-core';
|
6
6
|
import { LocalStream, LocalCameraStream, LocalDisplayStream, LocalSystemAudioStream, LocalMicrophoneStream } from '@webex/media-helpers';
|
7
7
|
import Roap, { type TurnDiscoverySkipReason } from '../roap/index';
|
8
8
|
import { type TurnServerInfo } from '../roap/types';
|
@@ -429,6 +429,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
429
429
|
shareStatus: string;
|
430
430
|
screenShareFloorState: ScreenShareFloorStatus;
|
431
431
|
statsAnalyzer: StatsAnalyzer;
|
432
|
+
statsMonitor: StatsMonitor;
|
432
433
|
transcription: Transcription;
|
433
434
|
updateMediaConnections: (mediaConnections: any[]) => void;
|
434
435
|
userDisplayHints: any;
|
package/dist/webinar/index.js
CHANGED
package/package.json
CHANGED
@@ -62,7 +62,7 @@
|
|
62
62
|
"dependencies": {
|
63
63
|
"@webex/common": "3.8.1-next.11",
|
64
64
|
"@webex/event-dictionary-ts": "^1.0.1930",
|
65
|
-
"@webex/internal-media-core": "2.
|
65
|
+
"@webex/internal-media-core": "2.19.0",
|
66
66
|
"@webex/internal-plugin-conversation": "3.9.0-next.4",
|
67
67
|
"@webex/internal-plugin-device": "3.9.0-next.3",
|
68
68
|
"@webex/internal-plugin-llm": "3.9.0-next.3",
|
@@ -71,7 +71,7 @@
|
|
71
71
|
"@webex/internal-plugin-support": "3.9.0-next.5",
|
72
72
|
"@webex/internal-plugin-user": "3.9.0-next.3",
|
73
73
|
"@webex/internal-plugin-voicea": "3.9.0-next.4",
|
74
|
-
"@webex/media-helpers": "3.
|
74
|
+
"@webex/media-helpers": "3.9.0-next.1",
|
75
75
|
"@webex/plugin-people": "3.9.0-next.3",
|
76
76
|
"@webex/plugin-rooms": "3.9.0-next.4",
|
77
77
|
"@webex/ts-sdp": "^1.8.1",
|
@@ -92,5 +92,5 @@
|
|
92
92
|
"//": [
|
93
93
|
"TODO: upgrade jwt-decode when moving to node 18"
|
94
94
|
],
|
95
|
-
"version": "3.9.0-next.
|
95
|
+
"version": "3.9.0-next.20"
|
96
96
|
}
|
package/src/constants.ts
CHANGED
@@ -347,6 +347,7 @@ export const EVENT_TRIGGERS = {
|
|
347
347
|
MEETING_SELF_LEFT: 'meeting:self:left',
|
348
348
|
NETWORK_QUALITY: 'network:quality',
|
349
349
|
MEDIA_NEGOTIATED: 'media:negotiated',
|
350
|
+
MEDIA_INBOUND_AUDIO_ISSUE_DETECTED: 'media:inboundAudio:issueDetected',
|
350
351
|
// the following events apply only to multistream media connections
|
351
352
|
ACTIVE_SPEAKER_CHANGED: 'media:activeSpeakerChanged',
|
352
353
|
REMOTE_VIDEO_SOURCE_COUNT_CHANGED: 'media:remoteVideoSourceCountChanged',
|
package/src/media/properties.ts
CHANGED
@@ -9,9 +9,12 @@ import {
|
|
9
9
|
|
10
10
|
import {parse} from '@webex/ts-sdp';
|
11
11
|
import {ClientEvent} from '@webex/internal-plugin-metrics';
|
12
|
+
import {throttle} from 'lodash';
|
13
|
+
import Metrics from '../metrics';
|
12
14
|
import {MEETINGS, QUALITY_LEVELS} from '../constants';
|
13
15
|
import LoggerProxy from '../common/logs/logger-proxy';
|
14
16
|
import MediaConnectionAwaiter from './MediaConnectionAwaiter';
|
17
|
+
import BEHAVIORAL_METRICS from '../metrics/constants';
|
15
18
|
|
16
19
|
export type MediaDirection = {
|
17
20
|
sendAudio: boolean;
|
@@ -41,6 +44,8 @@ export default class MediaProperties {
|
|
41
44
|
videoDeviceId: any;
|
42
45
|
videoStream?: LocalCameraStream;
|
43
46
|
namespace = MEETINGS;
|
47
|
+
mediaIssueCounters: {[key: string]: number} = {};
|
48
|
+
throttledSendMediaIssueMetric: ReturnType<typeof throttle>;
|
44
49
|
|
45
50
|
/**
|
46
51
|
* @param {Object} [options] -- to auto construct
|
@@ -66,6 +71,15 @@ export default class MediaProperties {
|
|
66
71
|
this.remoteQualityLevel = QUALITY_LEVELS.HIGH;
|
67
72
|
this.mediaSettings = {};
|
68
73
|
this.videoDeviceId = null;
|
74
|
+
|
75
|
+
this.throttledSendMediaIssueMetric = throttle((eventPayload) => {
|
76
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED, {
|
77
|
+
...eventPayload,
|
78
|
+
});
|
79
|
+
Object.keys(this.mediaIssueCounters).forEach((key) => {
|
80
|
+
this.mediaIssueCounters[key] = 0;
|
81
|
+
});
|
82
|
+
}, 1000 * 60 * 5); // at most once every 5 minutes
|
69
83
|
}
|
70
84
|
|
71
85
|
/**
|
@@ -139,8 +153,14 @@ export default class MediaProperties {
|
|
139
153
|
this.videoDeviceId = deviceId;
|
140
154
|
}
|
141
155
|
|
156
|
+
/**
|
157
|
+
* Clears the webrtcMediaConnection. This method should be called after
|
158
|
+
* peer connection is closed and no longer needed.
|
159
|
+
* @returns {void}
|
160
|
+
*/
|
142
161
|
unsetPeerConnection() {
|
143
162
|
this.webrtcMediaConnection = null;
|
163
|
+
this.throttledSendMediaIssueMetric.flush();
|
144
164
|
}
|
145
165
|
|
146
166
|
/**
|
@@ -424,4 +444,27 @@ export default class MediaProperties {
|
|
424
444
|
};
|
425
445
|
}
|
426
446
|
}
|
447
|
+
|
448
|
+
/**
|
449
|
+
* Sends a metric about a media issue. Metrics are throttled so that we don't
|
450
|
+
* send too many of them, but include a count so that we know how many issues
|
451
|
+
* were detected.
|
452
|
+
*
|
453
|
+
* @param {string} issueType
|
454
|
+
* @param {string} issueSubType
|
455
|
+
* @param {string} correlationId
|
456
|
+
* @returns {void}
|
457
|
+
*/
|
458
|
+
public sendMediaIssueMetric(issueType: string, issueSubType: string, correlationId) {
|
459
|
+
const key = `${issueType}_${issueSubType}`;
|
460
|
+
|
461
|
+
const count = (this.mediaIssueCounters[key] || 0) + 1;
|
462
|
+
|
463
|
+
this.mediaIssueCounters[key] = count;
|
464
|
+
|
465
|
+
this.throttledSendMediaIssueMetric({
|
466
|
+
correlationId,
|
467
|
+
...this.mediaIssueCounters,
|
468
|
+
});
|
469
|
+
}
|
427
470
|
}
|
package/src/meeting/index.ts
CHANGED
@@ -28,6 +28,8 @@ import {
|
|
28
28
|
StatsAnalyzerEventNames,
|
29
29
|
NetworkQualityEventNames,
|
30
30
|
NetworkQualityMonitor,
|
31
|
+
StatsMonitor,
|
32
|
+
StatsMonitorEventNames,
|
31
33
|
} from '@webex/internal-media-core';
|
32
34
|
|
33
35
|
import {
|
@@ -634,6 +636,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
634
636
|
shareStatus: string;
|
635
637
|
screenShareFloorState: ScreenShareFloorStatus;
|
636
638
|
statsAnalyzer: StatsAnalyzer;
|
639
|
+
statsMonitor: StatsMonitor;
|
637
640
|
transcription: Transcription;
|
638
641
|
updateMediaConnections: (mediaConnections: any[]) => void;
|
639
642
|
userDisplayHints: any;
|
@@ -1287,6 +1290,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1287
1290
|
* @memberof Meeting
|
1288
1291
|
*/
|
1289
1292
|
this.networkQualityMonitor = null;
|
1293
|
+
/**
|
1294
|
+
* @instance
|
1295
|
+
* @type {StatsMonitor}
|
1296
|
+
* @private
|
1297
|
+
* @memberof Meeting
|
1298
|
+
*/
|
1299
|
+
this.statsMonitor = null;
|
1290
1300
|
/**
|
1291
1301
|
* Indicates network status of the webrtc media connection
|
1292
1302
|
* @instance
|
@@ -7346,10 +7356,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7346
7356
|
if (this.config.stats.enableStatsAnalyzer) {
|
7347
7357
|
// @ts-ignore - config coming from registerPlugin
|
7348
7358
|
this.networkQualityMonitor = new NetworkQualityMonitor(this.config.stats);
|
7359
|
+
this.statsMonitor = new StatsMonitor();
|
7349
7360
|
this.statsAnalyzer = new StatsAnalyzer({
|
7350
7361
|
// @ts-ignore - config coming from registerPlugin
|
7351
7362
|
config: this.config.stats,
|
7352
7363
|
networkQualityMonitor: this.networkQualityMonitor,
|
7364
|
+
statsMonitor: this.statsMonitor,
|
7353
7365
|
isMultistream: this.isMultistream,
|
7354
7366
|
});
|
7355
7367
|
this.shareCAEventSentStatus = {
|
@@ -7363,6 +7375,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7363
7375
|
NetworkQualityEventNames.NETWORK_QUALITY,
|
7364
7376
|
this.sendNetworkQualityEvent.bind(this)
|
7365
7377
|
);
|
7378
|
+
|
7379
|
+
this.statsMonitor.on(StatsMonitorEventNames.INBOUND_AUDIO_ISSUE, (data) => {
|
7380
|
+
// Before forwarding any inbound audio issues to the app, make sure that we have at least one other
|
7381
|
+
// participant in the meeting with unmuted audio.
|
7382
|
+
// We don't check this.mediaProperties.mediaDirection here, because that's already handled in statsAnalyzer,
|
7383
|
+
// so we won't get this event if we are not setup to receive any audio
|
7384
|
+
const atLeastOneUnmutedOtherMember = Object.values(
|
7385
|
+
this.members.membersCollection.getAll()
|
7386
|
+
).find((member) => {
|
7387
|
+
return !member.isSelf && !member.isPairedWithSelf && !member.isAudioMuted;
|
7388
|
+
});
|
7389
|
+
|
7390
|
+
if (atLeastOneUnmutedOtherMember) {
|
7391
|
+
this.mediaProperties.sendMediaIssueMetric(
|
7392
|
+
'inbound_audio',
|
7393
|
+
data.issueSubType,
|
7394
|
+
this.correlationId
|
7395
|
+
);
|
7396
|
+
|
7397
|
+
Trigger.trigger(
|
7398
|
+
this,
|
7399
|
+
{file: 'meeting/index', function: 'createStatsAnalyzer'},
|
7400
|
+
EVENT_TRIGGERS.MEDIA_INBOUND_AUDIO_ISSUE_DETECTED,
|
7401
|
+
data
|
7402
|
+
);
|
7403
|
+
}
|
7404
|
+
});
|
7366
7405
|
}
|
7367
7406
|
}
|
7368
7407
|
|
@@ -7661,6 +7700,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7661
7700
|
}
|
7662
7701
|
|
7663
7702
|
this.statsAnalyzer = null;
|
7703
|
+
this.networkQualityMonitor?.removeAllListeners();
|
7704
|
+
this.networkQualityMonitor = null;
|
7705
|
+
this.statsMonitor?.removeAllListeners();
|
7706
|
+
this.statsMonitor = null;
|
7664
7707
|
|
7665
7708
|
// when media fails, we want to upload a webrtc dump to see whats going on
|
7666
7709
|
// this function is async, but returns once the stats have been gathered
|
@@ -7684,6 +7727,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7684
7727
|
await this.statsAnalyzer.stopAnalyzer();
|
7685
7728
|
}
|
7686
7729
|
this.statsAnalyzer = null;
|
7730
|
+
this.networkQualityMonitor?.removeAllListeners();
|
7731
|
+
this.networkQualityMonitor = null;
|
7732
|
+
this.statsMonitor?.removeAllListeners();
|
7733
|
+
this.statsMonitor = null;
|
7687
7734
|
|
7688
7735
|
this.isMultistream = false;
|
7689
7736
|
|
package/src/metrics/constants.ts
CHANGED
@@ -86,6 +86,7 @@ const BEHAVIORAL_METRICS = {
|
|
86
86
|
VERIFY_REGISTRATION_ID_SUCCESS: 'js_sdk_verify_registrationId_success',
|
87
87
|
VERIFY_REGISTRATION_ID_ERROR: 'js_sdk_verify_registrationId_error',
|
88
88
|
JOIN_FORBIDDEN_ERROR: 'js_sdk_join_forbidden_error',
|
89
|
+
MEDIA_ISSUE_DETECTED: 'js_sdk_media_issue_detected',
|
89
90
|
};
|
90
91
|
|
91
92
|
export {BEHAVIORAL_METRICS as default};
|
@@ -6,6 +6,8 @@ import * as tsSdpModule from '@webex/ts-sdp';
|
|
6
6
|
import MediaProperties from '@webex/plugin-meetings/src/media/properties';
|
7
7
|
import {Defer} from '@webex/common';
|
8
8
|
import MediaConnectionAwaiter from '../../../../src/media/MediaConnectionAwaiter';
|
9
|
+
import Metrics from '../../../../src/metrics';
|
10
|
+
import BEHAVIORAL_METRICS from '../../../../src/metrics/constants';
|
9
11
|
|
10
12
|
describe('MediaProperties', () => {
|
11
13
|
let mediaProperties;
|
@@ -389,4 +391,139 @@ describe('MediaProperties', () => {
|
|
389
391
|
});
|
390
392
|
});
|
391
393
|
});
|
394
|
+
|
395
|
+
// issue types and subtypes used in these tests are just examples
|
396
|
+
// they don't reflect real issue types/subtypes used in production
|
397
|
+
describe('sendMediaIssueMetric', () => {
|
398
|
+
let sendBehavioralMetricStub;
|
399
|
+
let clock;
|
400
|
+
|
401
|
+
beforeEach(() => {
|
402
|
+
clock = sinon.useFakeTimers();
|
403
|
+
sendBehavioralMetricStub = sinon.stub(Metrics, 'sendBehavioralMetric');
|
404
|
+
});
|
405
|
+
|
406
|
+
afterEach(() => {
|
407
|
+
clock.restore();
|
408
|
+
});
|
409
|
+
|
410
|
+
it('should send a behavioral metric with correct parameters', () => {
|
411
|
+
const issueType = 'audio';
|
412
|
+
const issueSubType = 'packet-loss';
|
413
|
+
const correlationId = 'test-correlation-id-123';
|
414
|
+
|
415
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
416
|
+
|
417
|
+
assert.calledOnce(sendBehavioralMetricStub);
|
418
|
+
assert.calledWith(sendBehavioralMetricStub, BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED, {
|
419
|
+
correlationId,
|
420
|
+
'audio_packet-loss': 1,
|
421
|
+
});
|
422
|
+
});
|
423
|
+
|
424
|
+
it('should increment count while being throttled and reset it once metric goes out', () => {
|
425
|
+
const issueType = 'video';
|
426
|
+
const issueSubType = 'freeze';
|
427
|
+
const correlationId = 'test-correlation-id';
|
428
|
+
|
429
|
+
// Call multiple times with same issue type/subtype
|
430
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
431
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
432
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
433
|
+
|
434
|
+
// First call should go through immediately, subsequent calls are throttled
|
435
|
+
assert.calledOnce(sendBehavioralMetricStub);
|
436
|
+
assert.calledWith(sendBehavioralMetricStub, BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED, {
|
437
|
+
correlationId,
|
438
|
+
video_freeze: 1, // Only the first call goes through due to throttling
|
439
|
+
});
|
440
|
+
sendBehavioralMetricStub.resetHistory();
|
441
|
+
|
442
|
+
assert.equal(mediaProperties.mediaIssueCounters['video_freeze'], 2); // counter should be reset after the first metric goes out, hence only 2 not 3 here
|
443
|
+
|
444
|
+
clock.tick(5 * 60 * 1000); // Advance time by 5 minutes to expire throttle
|
445
|
+
|
446
|
+
assert.calledOnceWithExactly(
|
447
|
+
sendBehavioralMetricStub,
|
448
|
+
BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED,
|
449
|
+
{
|
450
|
+
correlationId,
|
451
|
+
video_freeze: 2,
|
452
|
+
}
|
453
|
+
);
|
454
|
+
});
|
455
|
+
|
456
|
+
it('should track different issue types separately in counters', () => {
|
457
|
+
const correlationId = 'test-correlation-id';
|
458
|
+
|
459
|
+
// Send different issue types
|
460
|
+
mediaProperties.sendMediaIssueMetric('audio', 'packet-loss', correlationId);
|
461
|
+
mediaProperties.sendMediaIssueMetric('video', 'freeze', correlationId);
|
462
|
+
mediaProperties.sendMediaIssueMetric('audio', 'packet-loss', correlationId);
|
463
|
+
mediaProperties.sendMediaIssueMetric('audio', 'packet-loss', correlationId);
|
464
|
+
mediaProperties.sendMediaIssueMetric('audio', 'packet-loss', correlationId);
|
465
|
+
mediaProperties.sendMediaIssueMetric('video', 'freeze', correlationId);
|
466
|
+
|
467
|
+
// First call should go through immediately, subsequent calls are throttled
|
468
|
+
assert.calledOnceWithExactly(
|
469
|
+
sendBehavioralMetricStub,
|
470
|
+
BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED,
|
471
|
+
{
|
472
|
+
correlationId,
|
473
|
+
'audio_packet-loss': 1,
|
474
|
+
}
|
475
|
+
);
|
476
|
+
|
477
|
+
// But the counters should be tracked separately
|
478
|
+
assert.equal(mediaProperties.mediaIssueCounters['audio_packet-loss'], 3);
|
479
|
+
assert.equal(mediaProperties.mediaIssueCounters['video_freeze'], 2);
|
480
|
+
|
481
|
+
sendBehavioralMetricStub.resetHistory();
|
482
|
+
|
483
|
+
clock.tick(5 * 60 * 1000); // Advance time by 5 minutes to expire throttle
|
484
|
+
|
485
|
+
assert.calledOnceWithExactly(
|
486
|
+
sendBehavioralMetricStub,
|
487
|
+
BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED,
|
488
|
+
{
|
489
|
+
correlationId,
|
490
|
+
video_freeze: 2,
|
491
|
+
'audio_packet-loss': 3,
|
492
|
+
}
|
493
|
+
);
|
494
|
+
});
|
495
|
+
|
496
|
+
it('should flush throttled metrics when unsetPeerConnection is called', () => {
|
497
|
+
const issueType = 'share';
|
498
|
+
const issueSubType = 'connection-lost';
|
499
|
+
const correlationId = 'test-correlation-id';
|
500
|
+
|
501
|
+
// Send metrics multiple times
|
502
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
503
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
504
|
+
|
505
|
+
// First call should go through immediately
|
506
|
+
assert.calledOnceWithExactly(
|
507
|
+
sendBehavioralMetricStub,
|
508
|
+
BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED,
|
509
|
+
{
|
510
|
+
correlationId,
|
511
|
+
'share_connection-lost': 1,
|
512
|
+
}
|
513
|
+
);
|
514
|
+
sendBehavioralMetricStub.resetHistory();
|
515
|
+
|
516
|
+
// Call unsetPeerConnection which should flush throttled metrics
|
517
|
+
mediaProperties.unsetPeerConnection();
|
518
|
+
|
519
|
+
assert.calledOnceWithExactly(
|
520
|
+
sendBehavioralMetricStub,
|
521
|
+
BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED,
|
522
|
+
{
|
523
|
+
correlationId,
|
524
|
+
'share_connection-lost': 1,
|
525
|
+
}
|
526
|
+
);
|
527
|
+
});
|
528
|
+
});
|
392
529
|
});
|