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

feat(plugin-meetings): Introduce SDK changes to call WCME and Locus APIs when current user steps away or returns #3942

Merged
merged 35 commits into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
705a330
feat: introduce step away in sdk and test-app
Oct 28, 2024
07a6389
chore: rename functions, update wcme
Nov 4, 2024
d0882cf
chore: update brbChanged SelfUtils
Nov 4, 2024
315bab0
chore: update beRightBack, add todo
Nov 5, 2024
5cb3c55
chore: add todo
Nov 5, 2024
58e044e
fix(plugin-meetings): fix beRightBack sourceStateOverride
fnowakow Nov 7, 2024
41b4452
fix(plugin-meetings): audio/video (un)mute fix
fnowakow Nov 7, 2024
0f1af35
fix(plugin-meetings): added unit tests
fnowakow Oct 31, 2024
15c48d5
fix(plugin-meetings): added NOT unit test
fnowakow Oct 31, 2024
2e1080b
fix(plugin-meetings): updated tests
fnowakow Nov 7, 2024
679ccf6
fix(plugin-meetings): added NOT unit test
fnowakow Oct 31, 2024
c155311
fix(plugin-meetings): updated tests
fnowakow Nov 7, 2024
18521e7
fix(plugin-meetings): event name change to self
fnowakow Nov 7, 2024
22e5a04
chore(plugin-meetings): add todo
fnowakow Nov 7, 2024
4f1a9ee
chore(plugin-meetings): multistream support
fnowakow Nov 8, 2024
5b5c132
chore(plugin-meetings): removed multistream
fnowakow Nov 8, 2024
d7549af
test(plugin-meetings): update brb tests
Nov 13, 2024
e12798e
chore: nit updates for logs
Nov 13, 2024
541dbe0
test(plugin-meetings): update brb test names
Nov 13, 2024
fa85fb5
chore: update beRightBack api logic
Nov 13, 2024
278e4e9
test(plugin-meetings): check brb for both multistream and transcoded
Nov 14, 2024
939509d
test(plugin-meetings): finalize brb tests
Nov 14, 2024
41cce5c
test(plugin-meetings): remove unnecessary stub
Nov 14, 2024
aa5c0df
test(plugin-meetings): re-arrange test and add afterEach
Nov 14, 2024
0417885
test(plugin-meetings): remove only
Nov 14, 2024
c74ef78
fix(plugin-meetings): log error
Nov 14, 2024
5941b61
fix(plugin-meetings): rever to return statement
Nov 14, 2024
ce7757f
fix(plugin-meetings): throw and log error
Nov 15, 2024
9a69c20
test(plugin-meetings): update brb tests
Nov 13, 2024
e87cd32
fix(plugin-meetings): log error
Nov 14, 2024
1a0b894
fix(plugin-meetings): throw and log error
Nov 15, 2024
fcc4f82
fix(plugin-meetings): adjust conditions for brb
Nov 18, 2024
52bddae
fix(plugin-meetings): update branch
Nov 19, 2024
3f11d6b
chore: update test and brb logic for transcoded meetings
Nov 21, 2024
91b1c15
chore: fix spacing
Nov 22, 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
27 changes: 22 additions & 5 deletions docs/samples/browser-plugin-meetings/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const breakoutsList = document.getElementById('breakouts-list');
const breakoutTable = document.getElementById('breakout-table');
const breakoutHostOperation = document.getElementById('breakout-host-operation');
const getStatsButton = document.getElementById('get-stats');
const tcpReachabilityConfigElm = document.getElementById('enable-tcp-reachability');
const tcpReachabilityConfigElm = document.getElementById('enable-tcp-reachability');
const tlsReachabilityConfigElm = document.getElementById('enable-tls-reachability');

const guestName = document.querySelector('#guest-name');
Expand Down Expand Up @@ -388,7 +388,7 @@ createMeetingSelectElm.addEventListener('change', (event) => {
}
else {
notes.classList.add('hidden');

}
});

Expand Down Expand Up @@ -950,7 +950,7 @@ function cleanUpMedia() {
elem.srcObject.getTracks().forEach((track) => track.stop());
// eslint-disable-next-line no-param-reassign
elem.srcObject = null;

if(elem.id === "local-video") {
clearVideoResolutionCheckInterval(localVideoResElm, localVideoResolutionInterval);
}
Expand Down Expand Up @@ -1566,7 +1566,7 @@ async function stopStartVideo() {
console.error(error);
}
}

}

async function stopStartAudio() {
Expand Down Expand Up @@ -1608,7 +1608,7 @@ async function stopStartAudio() {
console.error(error);
}
}

}

function populateSourceDevices(mediaDevice) {
Expand Down Expand Up @@ -3330,6 +3330,23 @@ function toggleBreakout() {
}
}

async function toggleBrb() {
const meeting = getCurrentMeeting();

if (meeting) {
const enabled = document.getElementById('brb').checked;
try {
const result = await meeting.beRightBack(enabled);
console.log(`meeting.beRightBack(${enabled}): success. Result: ${result}`);
} catch (error) {
console.error(`meeting.beRightBack({${enabled}): error: `, error);
} finally {
localMedia?.microphoneStream?.setUserMuted(enabled);
localMedia?.cameraStream?.setUserMuted(enabled);
}
}
}

const createAdmitDiv = () => {

const containerDiv = document.createElement('div');
Expand Down
8 changes: 8 additions & 0 deletions docs/samples/browser-plugin-meetings/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,14 @@ <h2 class="collapsible">
</div>
</div>

<div>
<fieldset>
<legend>Step Away</legend>
<input type="checkbox" id="brb" onclick="toggleBrb()">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this should be a button and not a checkbox, since it'll be a button in the web client. The button should reflect the brb status of the current user, and would be a good way for us to test whether we are able to accurately show our brb status in the UI, as well as handle any potential race condition that might occur because of it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good comment, and I believe it's worth changing. We can improve this part in this task and not block the RP with this issue. https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-574653

<label for="brb">Enable Step Away</label><br>
</fieldset>
</div>

</div>
</fieldset>
</form>
Expand Down
2 changes: 1 addition & 1 deletion packages/@webex/media-helpers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"deploy:npm": "yarn npm publish"
},
"dependencies": {
"@webex/internal-media-core": "2.11.3",
"@webex/internal-media-core": "2.12.0",
"@webex/ts-events": "^1.1.0",
"@webex/web-media-effects": "2.19.0"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/@webex/plugin-meetings/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
},
"dependencies": {
"@webex/common": "workspace:*",
"@webex/internal-media-core": "2.11.3",
"@webex/internal-media-core": "2.12.0",
"@webex/internal-plugin-conversation": "workspace:*",
"@webex/internal-plugin-device": "workspace:*",
"@webex/internal-plugin-llm": "workspace:*",
Expand Down
2 changes: 2 additions & 0 deletions packages/@webex/plugin-meetings/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ export const EVENT_TRIGGERS = {
MEETING_SELF_CANNOT_VIEW_PARTICIPANT_LIST: 'meeting:self:cannotViewParticipantList',
MEETING_SELF_IS_SHARING_BLOCKED: 'meeting:self:isSharingBlocked',
MEETING_SELF_ROLES_CHANGED: 'meeting:self:rolesChanged',
MEETING_SELF_BRB_UPDATE: 'meeting:self:brbUpdate',
MEETING_CONTROLS_LAYOUT_UPDATE: 'meeting:layout:update',
MEETING_ENTRY_EXIT_TONE_UPDATE: 'meeting:entryExitTone:update',
MEETING_BREAKOUTS_UPDATE: 'meeting:breakouts:update',
Expand Down Expand Up @@ -700,6 +701,7 @@ export const LOCUSINFO = {
SELF_IS_SHARING_BLOCKED_CHANGE: 'SELF_IS_SHARING_BLOCKED_CHANGE',
SELF_MEETING_BREAKOUTS_CHANGED: 'SELF_MEETING_BREAKOUTS_CHANGED',
SELF_MEETING_INTERPRETATION_CHANGED: 'SELF_MEETING_INTERPRETATION_CHANGED',
SELF_MEETING_BRB_CHANGED: 'SELF_MEETING_BRB_CHANGED',
MEDIA_INACTIVITY: 'MEDIA_INACTIVITY',
LINKS_SERVICES: 'LINKS_SERVICES',
},
Expand Down
13 changes: 13 additions & 0 deletions packages/@webex/plugin-meetings/src/locus-info/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,19 @@ export default class LocusInfo extends EventsScope {
);
}

if (parsedSelves.updates.brbChanged) {
this.emitScoped(
{
file: 'locus-info',
function: 'updateSelf',
},
LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED,
{
brb: parsedSelves.current.brb,
antsukanova marked this conversation as resolved.
Show resolved Hide resolved
}
);
}

if (parsedSelves.updates.interpretationChanged) {
this.emitScoped(
{
Expand Down
6 changes: 6 additions & 0 deletions packages/@webex/plugin-meetings/src/locus-info/selfUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ SelfUtils.parse = (self: any, deviceId: string) => {
breakoutSessions: SelfUtils.getBreakoutSessions(self),
breakout: SelfUtils.getBreakout(self),
interpretation: SelfUtils.getInterpretation(self),
brb: SelfUtils.getBrb(self),
};
}

Expand All @@ -75,6 +76,7 @@ SelfUtils.parse = (self: any, deviceId: string) => {
SelfUtils.getBreakoutSessions = (self) => self?.controls?.breakout?.sessions;
SelfUtils.getBreakout = (self) => self?.controls?.breakout;
SelfUtils.getInterpretation = (self) => self?.controls?.interpretation;
SelfUtils.getBrb = (self) => self?.controls?.brb;

SelfUtils.getLayout = (self) =>
Array.isArray(self?.controls?.layouts) ? self.controls.layouts[0].type : undefined;
Expand Down Expand Up @@ -128,6 +130,7 @@ SelfUtils.getSelves = (oldSelf, newSelf, deviceId) => {
updates.isSharingBlockedChanged = previous?.isSharingBlocked !== current.isSharingBlocked;
updates.breakoutsChanged = SelfUtils.breakoutsChanged(previous, current);
updates.interpretationChanged = SelfUtils.interpretationChanged(previous, current);
updates.brbChanged = SelfUtils.brbChanged(previous, current);

return {
previous,
Expand Down Expand Up @@ -159,6 +162,9 @@ SelfUtils.breakoutsChanged = (previous, current) =>
SelfUtils.interpretationChanged = (previous, current) =>
!isEqual(previous?.interpretation, current?.interpretation) && !!current?.interpretation;

SelfUtils.brbChanged = (previous, current) =>
!isEqual(previous?.brb, current?.brb) && current?.brb !== undefined;

SelfUtils.isMediaInactive = (previous, current) => {
if (
previous &&
Expand Down
58 changes: 58 additions & 0 deletions packages/@webex/plugin-meetings/src/meeting/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3303,6 +3303,20 @@ export default class Meeting extends StatelessWebexPlugin {
}
});

this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED, (payload) => {
Trigger.trigger(
this,
{
file: 'meeting/index',
function: 'setUpLocusInfoSelfListener',
},
EVENT_TRIGGERS.MEETING_SELF_BRB_UPDATE,
{
payload,
}
);
});

this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ROLES_CHANGED, (payload) => {
const isModeratorOrCohost =
payload.newRoles?.includes(SELF_ROLES.MODERATOR) ||
Expand Down Expand Up @@ -3505,6 +3519,50 @@ export default class Meeting extends StatelessWebexPlugin {
return this.members.admitMembers(memberIds, locusUrls);
}

/**
* Manages be right back status updates for the current participant.
*
* @param {boolean} enabled - Indicates whether the user enabled brb or not.
* @returns {Promise<void>} resolves when the brb status is updated or does nothing if not in a multistream meeting.
* @throws {Error} - Throws an error if the request fails.
*/
public async beRightBack(enabled: boolean): Promise<void> {
if (!this.isMultistream) {
const errorMessage = 'Meeting:index#beRightBack --> Not a multistream meeting';
const error = new Error(errorMessage);

LoggerProxy.logger.error(error);

return Promise.reject(error);
}

if (!this.mediaProperties.webrtcMediaConnection) {
const errorMessage = 'Meeting:index#beRightBack --> WebRTC media connection is not defined';
const error = new Error(errorMessage);

antsukanova marked this conversation as resolved.
Show resolved Hide resolved
LoggerProxy.logger.error(error);

return Promise.reject(error);
}

// this logic should be applied only to multistream meetings
return this.meetingRequest
.sendBrb({
enabled,
locusUrl: this.locusUrl,
deviceUrl: this.deviceUrl,
selfId: this.selfId,
})
antsukanova marked this conversation as resolved.
Show resolved Hide resolved
.then(() => {
this.sendSlotManager.setSourceStateOverride(MediaType.VideoMain, enabled ? 'away' : null);
})
.catch((error) => {
LoggerProxy.logger.error('Meeting:index#beRightBack --> Error ', error);

return Promise.reject(error);
});
}

/**
* Remove the member from the meeting, boot them
* @param {String} memberId
Expand Down
27 changes: 26 additions & 1 deletion packages/@webex/plugin-meetings/src/meeting/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
ANNOTATION,
IP_VERSION,
} from '../constants';
import {SendReactionOptions, ToggleReactionsOptions} from './request.type';
import {SendReactionOptions, BrbOptions, ToggleReactionsOptions} from './request.type';
import MeetingUtil from './util';
import {AnnotationInfo} from '../annotation/annotation.types';

Expand Down Expand Up @@ -916,4 +916,29 @@ export default class MeetingRequest extends StatelessWebexPlugin {
uri: locusUrl,
});
}

/**
* Sends a request to set be right back status.
*
* @param {Object} options - The options for brb request.
* @param {boolean} options.enabled - Whether brb status is enabled.
* @param {string} options.locusUrl - The URL of the locus.
* @param {string} options.deviceUrl - The URL of the device.
* @param {string} options.selfId - The ID of the participant.
* @returns {Promise}
*/
sendBrb({enabled, locusUrl, deviceUrl, selfId}: BrbOptions) {
const uri = `${locusUrl}/${PARTICIPANT}/${selfId}/${CONTROLS}`;

return this.locusDeltaRequest({
method: HTTP_VERBS.PATCH,
uri,
body: {
brb: {
enabled,
deviceUrl,
},
},
});
}
}
7 changes: 7 additions & 0 deletions packages/@webex/plugin-meetings/src/meeting/request.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ export type ToggleReactionsOptions = {
locusUrl: string;
requestingParticipantId: string;
};

export type BrbOptions = {
enabled: boolean;
locusUrl: string;
deviceUrl: string;
selfId: string;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
LocalStream,
MultistreamRoapMediaConnection,
NamedMediaGroup,
StreamState,
} from '@webex/internal-media-core';

export default class SendSlotManager {
Expand Down Expand Up @@ -83,6 +84,36 @@ export default class SendSlotManager {
);
}

/**
* Sets the source state override for the given media type.
* @param {MediaType} mediaType - The type of media (must be MediaType.VideoMain to apply source state changes).
* @param {StreamState | null} state - The state to set or null to clear the override value.
* @returns {void}
*/
public setSourceStateOverride(mediaType: MediaType, state: StreamState | null) {
if (mediaType !== MediaType.VideoMain) {
throw new Error(
`sendSlotManager cannot set source state override which media type is ${mediaType}`
);
}

const slot = this.slots.get(mediaType);

if (!slot) {
throw new Error(`Slot for ${mediaType} does not exist`);
}

if (state) {
slot.setSourceStateOverride(state);
} else {
slot.clearSourceStateOverride();
}

this.LoggerProxy.logger.info(
`SendSlotsManager->setSourceStateOverride#set source state override for ${mediaType} to ${state}`
);
}

/**
* This method publishes the given stream to the sendSlot for the given mediaType
* @param {MediaType} mediaType MediaType of the sendSlot to which a stream needs to be published (AUDIO_MAIN/VIDEO_MAIN/AUDIO_SLIDES/VIDEO_SLIDES)
Expand Down
Loading
Loading