Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: metrics and meetings beta changes #3525

Merged
merged 24 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c8202f0
Feat/si: cancel named media groups after remove interpreter role (#3508)
mickelr Apr 3, 2024
ca99162
feat(plugin-meetings): Return resourceType when get locus annotation …
JudyZhuHz Apr 3, 2024
d875966
fix(internal-plugin-metrics): define latency before ready (#3514)
shnaaz Apr 3, 2024
2b596e9
fix: handle empty TURN url (#3516)
marcin-bazyl Apr 3, 2024
f2a612d
fix(meetings-and-device): installationid-and-machineid (#3454)
peter7cole Apr 3, 2024
738ed38
feat(internal-plugin-metrics): added helpers (#3515)
shnaaz Apr 4, 2024
86e7308
feat(jmt): remove server side JMT (#3511)
torgeadelin Apr 4, 2024
24593d4
fix: add-next-in-beta-plugin-meetings (#3493)
Shreyas281299 Apr 5, 2024
367a1d5
feat(metrics): add otherAppApi jmt (#3496)
torgeadelin Apr 5, 2024
b0d33a6
feat(internal-plugin-meetings): u2c latency (#3519)
shnaaz Apr 8, 2024
d72597a
fix: Roap optimizations phase 2 (#3449)
marcin-bazyl Apr 8, 2024
dfcbe9d
feat(plugin-meetings): Return resourceType when get locus annotation …
JudyZhuHz Apr 9, 2024
ec6bf6e
Fix: Added updateLLMConnection when guest is admitted from the lobby …
Ashwin7mak Apr 11, 2024
0cfa952
feat(plugin-meetings): separate API for enabled and muted states (#3443)
brycetham Apr 15, 2024
4c0217c
feat(metrics): fix test failure due to circular dep
Apr 15, 2024
51236db
Merge branch 'cherry-pick-08042024' of github.com:mkesavan13/webex-js…
Apr 15, 2024
23d86af
Merge branch 'next' into cherry-pick-08042024
torgeadelin Apr 15, 2024
3b2808d
test(media-helpers): conflict due to media-helper importing jsdom/reg…
mkesavan13 Apr 15, 2024
1b23b20
Merge branch 'next' into cherry-pick-08042024
mkesavan13 Apr 15, 2024
a84876a
feat(metrics): fix unit test
Apr 16, 2024
80a3bb0
Merge branch 'cherry-pick-08042024' of github.com:mkesavan13/webex-js…
Apr 16, 2024
31e8fc0
feat(metrics): fix other unit test in wb core
Apr 16, 2024
e6c5a41
fix: webex-core integration tests
mkesavan13 Apr 17, 2024
0836d09
fix: add server for mocha test (#3)
arun3528 Apr 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 40 additions & 11 deletions docs/samples/browser-plugin-meetings/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,8 @@ const stopShareBtn = document.querySelector('#ts-stop-screenshare');
const toggleAudioButton = document.querySelector('#ts-toggle-audio');
const stopVideoButton = document.querySelector('#ts-stop-video');
const stopAudioButton = document.querySelector('#ts-stop-audio');
const muteVideoMessage = document.querySelector('#ts-mute-video-message');
const muteAudioMessage = document.querySelector('#ts-mute-audio-message');
const modeBtn = document.getElementById('mode-type');

/**
Expand Down Expand Up @@ -1320,6 +1322,15 @@ async function loadCamera(constraints) {

meetingStreamsLocalVideo.srcObject = localMedia.cameraStream.outputStream;

localMedia.cameraStream.on('user-mute-state-change', (muted) => {
console.log('MeetingControls#loadCamera() :: local camera stream user mute state changed to', muted);
});

localMedia.cameraStream.on('system-mute-state-change', (muted) => {
console.log('MeetingControls#loadCamera() :: local camera stream system mute state changed to', muted);
handleMuteVideoMessage();
});

localMedia.cameraStream.on('stream-ended', () => {
console.log('MeetingControls#loadCamera() :: local camera stream ended');

Expand All @@ -1332,6 +1343,7 @@ async function loadCamera(constraints) {
clearVideoResolutionCheckInterval(localVideoResElm, localVideoResolutionInterval);
});

handleMuteVideoMessage();
handleEffectsButton(toggleVbgBtn, VBG);
loadCameraBtn.disabled = true;
stopVideoButton.disabled = false;
Expand Down Expand Up @@ -1392,6 +1404,16 @@ async function loadMicrophone(constraints) {

meetingStreamsLocalAudio.srcObject = localMedia.microphoneStream.outputStream;

localMedia.microphoneStream.on('user-mute-state-change', (muted) => {
console.log('MeetingControls#loadMicrophone() :: local microphone stream user mute state changed to', muted);
handleAudioButton();
});

localMedia.microphoneStream.on('system-mute-state-change', (muted) => {
console.log('MeetingControls#loadMicrophone() :: local microphone stream system mute state changed to', muted);
handleMuteAudioMessage();
});

localMedia.microphoneStream.on('stream-ended', () => {
console.log('MeetingControls#loadMicrophone() :: local microphone stream ended');

Expand All @@ -1402,6 +1424,7 @@ async function loadMicrophone(constraints) {
loadMicrophoneBtn.disabled = false;
});

handleMuteAudioMessage();
handleEffectsButton(toggleBNRBtn, BNR);
loadMicrophoneBtn.disabled = true;
stopAudioButton.disabled = false;
Expand Down Expand Up @@ -1642,12 +1665,12 @@ function setVideoInputDevice() {
const {video} = getAudioVideoInput();

if (meeting) {
const isMuted = localMedia.cameraStream?.muted;
const isMuted = localMedia.cameraStream?.userMuted;
localMedia.cameraStream?.stop();

return getUserMedia({video})
.then(() => {
localMedia.cameraStream.setMuted(!!isMuted);
localMedia.cameraStream.setUserMuted(!!isMuted);
localVideoResolutionCheckInterval();
meeting.publishStreams({camera: localMedia.cameraStream});
});
Expand All @@ -1662,12 +1685,12 @@ function setAudioInputDevice() {
const {audio} = getAudioVideoInput();

if (meeting) {
const isMuted = localMedia.microphoneStream?.muted;
const isMuted = localMedia.microphoneStream?.userMuted;
localMedia.microphoneStream?.stop();

return getUserMedia({audio})
.then(() => {
localMedia.microphoneStream.setMuted(!!isMuted);
localMedia.microphoneStream.setUserMuted(!!isMuted);
meeting.publishStreams({microphone: localMedia.microphoneStream});
});
}
Expand All @@ -1690,31 +1713,38 @@ function setAudioOutputDevice() {
}

function handleAudioButton() {
const audioButtonTitle = localMedia.microphoneStream.muted ? 'Unmute' : 'Mute';
const audioButtonTitle = localMedia.microphoneStream.userMuted ? 'Unmute' : 'Mute';
toggleAudioButton.innerHTML = `${audioButtonTitle} Audio`;
}

function handleMuteAudioMessage() {
muteAudioMessage.innerHTML = localMedia.microphoneStream.systemMuted ? "Warning: microphone may be muted by the system" : "";
}

function toggleSendAudio() {
console.log('MeetingControls#toggleSendAudio()');

if (localMedia.microphoneStream) {
const newMuteValue = !localMedia.microphoneStream.muted;
const newMuteValue = !localMedia.microphoneStream.userMuted;

localMedia.microphoneStream.setMuted(newMuteValue);
handleAudioButton();
localMedia.microphoneStream.setUserMuted(newMuteValue);

console.log(`MeetingControls#toggleSendAudio() :: Successfully ${newMuteValue ? 'muted': 'unmuted'} audio!`);
return;
}
}

function handleMuteVideoMessage() {
muteVideoMessage.innerHTML = localMedia.cameraStream.systemMuted ? "Warning: camera may be muted by the system" : "";
}

function toggleSendVideo() {
console.log('MeetingControls#toggleSendVideo()');

if (localMedia.cameraStream) {
const newMuteValue = !localMedia.cameraStream.muted;
const newMuteValue = !localMedia.cameraStream.userMuted;

localMedia.cameraStream.setMuted(newMuteValue);
localMedia.cameraStream.setUserMuted(newMuteValue);

console.log(`MeetingControls#toggleSendVideo() :: Successfully ${newMuteValue ? 'muted': 'unmuted'} video!`);

Expand Down Expand Up @@ -3083,7 +3113,6 @@ function muteMember(muteButton) {
if (meeting) {
meeting.mute(participantID, newMuteStatus).then((res) => {
console.log(res, `participant is ${newMuteStatus ? 'muted' : 'unmuted'}`);
handleAudioButton();
}).catch((err) => {
console.log('error', err);
});
Expand Down
2 changes: 2 additions & 0 deletions docs/samples/browser-plugin-meetings/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ <h2 class="collapsible">
<!--mute-unmute-video -->
<button id="ts-toggle-video" type="button" onclick="toggleSendVideo()" class="btn-code">Toggle Video</button>
<button id="ts-stop-video" type="button" disabled onclick="stopStartVideo()" class="btn-code">Stop Video</button>
<span id="ts-mute-video-message" class="webex-warning"></span>
</div>
</div>

Expand All @@ -209,6 +210,7 @@ <h2 class="collapsible">
<!--mute-unmute audio -->
<button id="ts-toggle-audio" type="button" onclick="toggleSendAudio()" class="btn-code">Mute Audio</button>
<button id="ts-stop-audio" type="button" disabled onclick="stopStartAudio()" class="btn-code">Stop Audio</button>
<span id="ts-mute-audio-message" class="webex-warning"></span>
</div>
</div>

Expand Down
4 changes: 4 additions & 0 deletions docs/samples/browser-plugin-meetings/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,10 @@ legend {
padding: 0.3rem;
}

.webex-warning {
color: #7d4705;
}

.webex-error {
color: #de3434;
}
Expand Down
9 changes: 9 additions & 0 deletions packages/@webex/internal-plugin-device/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,13 @@ export default {
*/
ephemeralDeviceTTL: 30 * 60,
},

/**
* installationId is used exclusively as web client for fraud prevention,
* and is aliased to as machineId by CA.
*
* @alias device.machineId
* @type {string}
*/
installationId: undefined,
};
2 changes: 1 addition & 1 deletion packages/@webex/internal-plugin-metrics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"dependencies": {
"@webex/common": "workspace:*",
"@webex/common-timers": "workspace:*",
"@webex/event-dictionary-ts": "^1.0.1329",
"@webex/event-dictionary-ts": "^1.0.1387",
"@webex/internal-plugin-device": "workspace:*",
"@webex/internal-plugin-metrics": "workspace:*",
"@webex/test-helper-chai": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,33 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
/**
* Store precomputed latency value
* @param key - key
* @param value -value
* @param value - value
* @param overwrite - overwrite existing value or add it
* @throws
* @returns
*/
public saveLatency(key: PreComputedLatencies, value: number) {
this.precomputedLatencies.set(key, value);
public saveLatency(key: PreComputedLatencies, value: number, overwrite = true) {
const existingValue = overwrite ? 0 : this.precomputedLatencies.get(key) || 0;
this.precomputedLatencies.set(key, value + existingValue);
}

/**
* Measure latency for a request
* @param key - key
* @param callback - callback for which you would like to measure latency
* @param overwrite - overwite existing value or add to it
* @returns
*/
public measureLatency(
callback: () => Promise<any>,
key: PreComputedLatencies,
overwrite = false
) {
const start = performance.now();

return callback().finally(() => {
this.saveLatency(key, performance.now() - start, overwrite);
});
}

/**
Expand Down Expand Up @@ -158,6 +179,16 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
);
}

/**
* getU2CTime
* @returns - latency
*/
public getU2CTime() {
const u2cLatency = this.precomputedLatencies.get('internal.get.u2c.time');

return u2cLatency ? Math.floor(u2cLatency) : undefined;
}

/**
* Device Register Time
* @returns - latency
Expand Down Expand Up @@ -188,15 +219,6 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
return this.getDiffBetweenTimestamps('client.locus.join.request', 'client.locus.join.response');
}

/**
* Locus Join Response Sent Received
* @returns - latency
*/
public getJoinRespSentReceived() {
// TODO: not clear SPARK-440554
return undefined;
}

/**
* Time taken to do turn discovery
* @returns - latency
Expand Down Expand Up @@ -432,4 +454,14 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
public getVideoJoinRespTxStart() {
return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.media.tx.start');
}

/**
* Total latency for all other app api requests.
* Excludes meeting info, because it's measured separately.
*/
public getOtherAppApiReqResp() {
const otherAppApiJMT = this.precomputedLatencies.get('internal.other.app.api.time');

return otherAppApiJMT > 0 ? Math.floor(otherAppApiJMT) : undefined;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,17 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
if (this.webex.internal) {
// @ts-ignore
const {device} = this.webex.internal;
const {installationId} = device.config || {};

identifiers.userId = device.userId || preLoginId;
identifiers.deviceId = device.url;
identifiers.orgId = device.orgId;
// @ts-ignore
identifiers.locusUrl = this.webex.internal.services.get('locus');

if (installationId) {
identifiers.machineId = installationId;
}
}

if (meeting?.locusInfo?.fullState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
case 'client.webexapp.launched':
joinTimes.downloadTime = cdl.getDownloadTimeJMT();
break;
case 'client.login.end':
joinTimes.otherAppApiReqResp = cdl.getOtherAppApiReqResp();
break;
case 'client.interstitial-window.launched':
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();
joinTimes.clickToInterstitial = cdl.getClickToInterstitial();
Expand All @@ -253,13 +256,13 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();
joinTimes.showInterstitialTime = cdl.getShowInterstitialTime();
joinTimes.registerWDMDeviceJMT = cdl.getRegisterWDMDeviceJMT();
joinTimes.getU2CTime = cdl.getU2CTime();
break;

case 'client.locus.join.response':
joinTimes.meetingInfoReqResp = cdl.getMeetingInfoReqResp();
joinTimes.callInitJoinReq = cdl.getCallInitJoinReq();
joinTimes.joinReqResp = cdl.getJoinReqResp();
joinTimes.joinReqSentReceived = cdl.getJoinRespSentReceived();
joinTimes.pageJmt = cdl.getPageJMT();
joinTimes.clickToInterstitial = cdl.getClickToInterstitial();
joinTimes.interstitialToJoinOK = cdl.getInterstitialToJoinOK();
Expand Down
2 changes: 2 additions & 0 deletions packages/@webex/internal-plugin-metrics/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
SubmitInternalEvent,
SubmitOperationalEvent,
SubmitMQE,
PreComputedLatencies,
} from './metrics.types';
import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config';
import * as CallDiagnosticUtils from './call-diagnostic/call-diagnostic-metrics.util';
Expand Down Expand Up @@ -51,4 +52,5 @@ export type {
SubmitInternalEvent,
SubmitMQE,
SubmitOperationalEvent,
PreComputedLatencies,
};
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,6 @@ export type PreComputedLatencies =
| 'internal.client.pageJMT'
| 'internal.download.time'
| 'internal.click.to.interstitial'
| 'internal.call.init.join.req';
| 'internal.get.u2c.time'
| 'internal.call.init.join.req'
| 'internal.other.app.api.time';
4 changes: 2 additions & 2 deletions packages/@webex/internal-plugin-metrics/src/new-metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class Metrics extends WebexPlugin {
constructor(...args) {
super(...args);

// @ts-ignore
this.callDiagnosticLatencies = new CallDiagnosticLatencies({}, {parent: this.webex});
this.onReady();
}

Expand All @@ -54,8 +56,6 @@ class Metrics extends WebexPlugin {
this.webex.once('ready', () => {
// @ts-ignore
this.callDiagnosticMetrics = new CallDiagnosticMetrics({}, {parent: this.webex});
// @ts-ignore
this.callDiagnosticLatencies = new CallDiagnosticLatencies({}, {parent: this.webex});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ describe('plugin-metrics', () => {
webex.internal.newMetrics.callDiagnosticLatencies.getDiffBetweenTimestamps = sinon
.stub()
.returns(10);
webex.internal.newMetrics.callDiagnosticLatencies.getU2CTime = sinon
.stub()
.returns(20);
const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
//@ts-ignore
{event: {name: 'client.call.initiated'}}
Expand All @@ -147,6 +150,7 @@ describe('plugin-metrics', () => {
meetingInfoReqResp: 10,
registerWDMDeviceJMT: 10,
showInterstitialTime: 10,
getU2CTime: 20
},
});
assert.lengthOf(
Expand All @@ -159,9 +163,6 @@ describe('plugin-metrics', () => {
webex.internal.newMetrics.callDiagnosticLatencies.getDiffBetweenTimestamps = sinon
.stub()
.returns(10);
webex.internal.newMetrics.callDiagnosticLatencies.getJoinRespSentReceived = sinon
.stub()
.returns(20);
webex.internal.newMetrics.callDiagnosticLatencies.getPageJMT = sinon.stub().returns(30);
webex.internal.newMetrics.callDiagnosticLatencies.getClientJMT = sinon.stub().returns(5);
webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitial = sinon
Expand Down Expand Up @@ -191,7 +192,6 @@ describe('plugin-metrics', () => {
clickToInterstitial: 10,
interstitialToJoinOK: 10,
joinReqResp: 10,
joinReqSentReceived: 20,
meetingInfoReqResp: 10,
pageJmt: 30,
totalJmt: 20,
Expand Down
Loading
Loading