Description
In a previous correspondence with @vic.yang, he informed me that I could create more than the required subsessions and only open the ones which I wanted to use per time. I had created new logic to either reduce the number of subsessions or increase the number of subsessions as required.
The problem now is that it doesn’t work as expected. Below I will share all relevant snippets of my code with you so you can help point out where I may not be getting it right.
Browser Console Error
“exceeded max limit”
Which Web Video SDK version?
1.9.5
Video SDK Code Snippets
Code to open the subsessions. This can be called independent of the create subsessions
const openSubsessions = useCallback(async () => {
if (ssClient) {
const guests = zmClient.getAllUser().filter(
p => !p.displayName.endsWith('(Dozent:in)') &&
!p.displayName.endsWith('(Moderator:in)')
);
if (guests.length < 1) {
message.info(
'Bitte versuchen Sie es erneut, wenn Teilnehmer verfügbar sind.'
);
return 0;
}
console.log('subsessions to open', subsessions);
setRetryOpeningSubsessions(true);
setIsRetryingOpenSubSessions(true);
try {
if (!subsessions.length || !ssClient.getSubsessionList().length || unassignedUserList.length) {
console.log('in attempt');
if (!subsessions.length) {
await ssClient.createSubsessions(
roomsToOpen,
SubsessionAllocationPattern.Automatically
).then(async (newSubSessions) => {
await ssClient.openSubsessions(
[...subsessions, ...newSubSessions as unknown as Subsession[]],
options
).then(() => {
setSubsessionStatus(SubsessionStatus.InProgress);
setSubsessions(() => [...subsessions, ...newSubSessions as unknown as Subsession[]]);
if (chatClient && chatClient.getPrivilege() === ChatPrivilege.NoOne) {
chatClient?.setPrivilege(ChatPrivilege.EveryonePublicly).then(() => {
message.info('Die Chat-Berechtigung "Alle dürfen sprechen" wurde wieder aktiviert, um sicherzustellen, dass die Nutzer in den Breakout-Räumen schreiben können.');
setAllowChatting(true);
});
}
if (guests.length) {
guests.forEach(async (g) => {
await mediaStream?.unmuteAudio(g.userId);
console.log('muted', g);
});
setUnmuteAllParticipants(true);
setCurrentQueue((currentQueue: HandQueue[]) => []);
}
setDoNotDisturb(false);
const moderator = zmClient.getAllUser().filter((u) => u.displayName.endsWith('(Moderator:in)'));
if (moderator.length) {
let command = {
action: 'sent-moderation-update',
dnd: false,
}
cmdClient?.send(JSON.stringify(command), moderator[0].userId);
}
setRetryOpeningSubsessions(false);
setIsRetryingOpenSubSessions(false);
}).catch((err) => {
if (err.reason === 'only host can do the operation') {
message.error('Nur der Host kann den Vorgang ausführen');
} else {
message.error(err.reason)
}
});
}).catch((err) => {
if (err.reason === 'only host can do the operation') {
message.error('Nur der Host kann den Vorgang ausführen');
} else {
message.error(err.reason)
}
});
} else {
ssClient.openSubsessions(subsessions, options).then(() => {
setSubsessionStatus(SubsessionStatus.InProgress);
if (unassignedUserList.length) {
const randomSubSession = subsessions[Math.floor(Math.random() * subsessions.length)];
let participant: Participant | null;
unassignedUserList.forEach(async (user) => {
participant = user;
ssClient.assignUserToSubsession(
user.userId,
randomSubSession.subsessionId
).then(() => {
setSubsessions(
produce((subsessions: Subsession[]) => {
const subsession = subsessions.find((r: Subsession) => r.subsessionId === randomSubSession.subsessionId);
if (subsession && participant) {
subsession.userList.push({
userId: participant.userId,
displayName: participant.displayName,
avatar: participant.avatar,
isInSubsession: true
});
}
})
);
});
});
}
if (chatClient && chatClient.getPrivilege() === ChatPrivilege.NoOne) {
chatClient?.setPrivilege(ChatPrivilege.EveryonePublicly).then(() => {
message.info('Die Chat-Berechtigung "Alle dürfen sprechen" wurde wieder aktiviert, um sicherzustellen, dass die Nutzer in den Breakout-Räumen schreiben können.');
setAllowChatting(true);
});
}
if (guests.length) {
guests.forEach(async (g) => {
await mediaStream?.unmuteAudio(g.userId);
console.log('muted', g);
});
setUnmuteAllParticipants(true);
setCurrentQueue((currentQueue: HandQueue[]) => []);
}
setDoNotDisturb(false);
const moderator = zmClient.getAllUser().filter((u) => u.displayName.endsWith('(Moderator:in)'));
if (moderator.length) {
let command = {
action: 'sent-moderation-update',
dnd: false,
}
cmdClient?.send(JSON.stringify(command), moderator[0].userId);
}
}).catch((err) => {
if (err.reason === 'only host can do the operation') {
message.error('Nur der Host kann den Vorgang ausführen');
} else {
message.error(err.reason)
}
});
}
console.log('after attempt');
} else {
await ssClient.openSubsessions(subsessions, options).then(() => {
setSubsessionStatus(SubsessionStatus.InProgress);
if (chatClient && chatClient.getPrivilege() === ChatPrivilege.NoOne) {
chatClient?.setPrivilege(ChatPrivilege.EveryonePublicly).then(() => {
message.info('Die Chat-Berechtigung "Alle dürfen sprechen" wurde wieder aktiviert, um sicherzustellen, dass die Nutzer in den Breakout-Räumen schreiben können.');
setAllowChatting(true);
});
}
const participants = zmClient.getAllUser();
const guests = participants.filter(
(p) => !p.isHost && !p.isManager && p.userId !== zmClient.getCurrentUserInfo().userId
);
if (guests.length) {
guests.forEach(async (g) => {
await mediaStream?.unmuteAudio(g.userId);
console.log('muted', g);
});
setUnmuteAllParticipants(true);
setCurrentQueue((currentQueue: HandQueue[]) => []);
}
setDoNotDisturb(false);
const moderator = zmClient.getAllUser().filter((u) => u.displayName.endsWith('(Moderator:in)'));
if (moderator.length) {
let command = {
action: 'sent-moderation-update',
dnd: false,
}
cmdClient?.send(JSON.stringify(command), moderator[0].userId);
}
}).catch((err) => {
if (err.reason === 'only host can do the operation') {
message.error('Nur der Host kann den Vorgang ausführen');
} else {
message.error(err.reason)
}
});
}
} catch (err) {
console.log(err);
}
setRetryOpeningSubsessions(false);
setIsRetryingOpenSubSessions(false);
// await assignUnassignedUsersToAnyRunningSubsessions();
console.log('sub open status', subsessionStatus);
console.log('ssclient stat', ssClient.getSubsessionStatus());
}
}, [
ssClient,
zmClient,
setIsRetryingOpenSubSessions,
subsessionStatus,
subsessions,
unassignedUserList,
roomsToOpen,
options,
chatClient,
setDoNotDisturb,
setAllowChatting,
setUnmuteAllParticipants,
setCurrentQueue,
mediaStream,
cmdClient
]);
Function to calculate the total number of subsessions to open:
const calculateNumberOfRooms = useCallback((participantsPerRoom: number): number => {
const totalParticipants = zmClient.getAllUser().filter(
p => !p.displayName.endsWith('(Dozent:in)') &&
!p.displayName.endsWith('(Moderator:in)')
);
if (totalParticipants.length < 1) {
console.log('generated rooms', 0);
return 0;
}
if (totalParticipants.length <= participantsPerRoom) {
console.log('generated rooms', 1);
return 1;
}
console.log('generated rooms', Math.floor(totalParticipants.length / participantsPerRoom));
return Math.floor(totalParticipants.length / participantsPerRoom);
}, [zmClient]);
Function to recreate the subsessions after closing:
const recreateSubsessions = useCallback(
async (participantsPerRoom: number, pattern: SubsessionAllocationPattern) => {
const totalRooms = calculateNumberOfRooms(participantsPerRoom);
if (totalRooms === 0) {
message.info('Bitte versuchen Sie es erneut, wenn Teilnehmer verfügbar sind.');
return;
}
setRoomsToOpen(() => totalRooms);
message.info('Breakout-Räume werden erstellt. Bitte haben Sie etwas Geduld, da dies bis zu 10 Sekunden dauern kann. Wenn der Button nach 10 Sekunden nicht rot wird, klicken Sie bitte erneut.', 10);
if (ssClient) {
try {
setRetryOpeningSubsessions(true);
setIsRetryingOpenSubSessions(true);
const currentNumberOfRooms = ssClient.getSubsessionList().length;
if (currentNumberOfRooms > totalRooms) {
setSubsessions((subsessions: Subsession[]) => subsessions.slice(0, totalRooms));
} else if (totalRooms > currentNumberOfRooms) {
const totalSubSessionsToCreate = totalRooms - currentNumberOfRooms;
await ssClient.createSubsessions(
totalSubSessionsToCreate,
SubsessionAllocationPattern.Automatically
).then((newSubSessions) => {
setSubsessions((subsessions: Subsession[]) => [
...subsessions,
...newSubSessions as unknown as Subsession[]
]);
}).catch((err) => {
if (err.reason === 'only host can do the operation') {
message.error('Nur der Host kann den Vorgang ausführen');
} else {
message.error(err.reason)
}
});
}
openSubsessions();
} catch (e) {
console.warn(e);
}
}
},
[calculateNumberOfRooms, ssClient, setIsRetryingOpenSubSessions, openSubsessions]
);
Function to create the subsessions at the first instance:
const createSubsessions = useCallback(
async (participantsPerRoom: number, pattern: SubsessionAllocationPattern) => {
const totalRooms = calculateNumberOfRooms(participantsPerRoom);
if (totalRooms === 0) {
message.info('Bitte versuchen Sie es erneut, wenn Teilnehmer verfügbar sind.');
return;
}
setRoomsToOpen(() => totalRooms);
message.info('Breakout-Räume werden erstellt. Bitte haben Sie etwas Geduld, da dies bis zu 10 Sekunden dauern kann. Wenn der Button nach 10 Sekunden nicht rot wird, klicken Sie bitte erneut.', 10);
if (ssClient) {
try {
setRetryOpeningSubsessions(true);
setIsRetryingOpenSubSessions(true);
await ssClient.createSubsessions(totalRooms, pattern).then((subsessions) => {
setSubsessions(() => subsessions as unknown as Subsession[]);
openSubsessions();
}).catch((err) => {
if (err.reason === 'only host can do the operation') {
message.error('Nur der Host kann den Vorgang ausführen');
} else {
message.error(err.reason)
}
});
} catch (e) {
console.warn(e);
}
}
},
[calculateNumberOfRooms, ssClient, setIsRetryingOpenSubSessions, openSubsessions]
);
Then I have a retry interval that retries to open the subsessions if it fails when called by the create or recreate subsessions methods:
let retryInterval = useRef<NodeJS.Timeout | undefined>(undefined);
useEffect(() => {
async function retryOpenSubsessions() {
await openSubsessions();
}
retryInterval.current = setInterval(() => {
if (ssClient) {
if (
(ssClient.getSubsessionStatus() === SubsessionStatus.InProgress &&
ssClient.getSubsessionList().length) ||
ssClient.getSubsessionStatus() === SubsessionStatus.Closed ||
ssClient.getSubsessionStatus() === SubsessionStatus.Closing
) {
setRetryOpeningSubsessions(false);
setIsRetryingOpenSubSessions(false);
clearInterval(retryInterval.current);
} else if (
retryOpeningSubsessions &&
(
ssClient.getSubsessionStatus() !== SubsessionStatus.Closed ||
ssClient.getSubsessionStatus() !== SubsessionStatus.Closing
)
) {
retryOpenSubsessions();
console.log('would have retried here');
}
}
}, 10000);
}, [openSubsessions, retryOpeningSubsessions, ssClient, setRetryOpeningSubsessions, setIsRetryingOpenSubSessions]);
All of these are done in the useSubsession hook, and returned by the hook.
I would greatly appreciate if you can help decipher what I may be missing.
The following are the current behaviour of the things:
- The createSubsessions method throws an error sometimes even when I have awaited it to resolve before opening the subsessions. However, the subsessions eventually open, but the behaviour is unstable.
- When I recreate subsessions specifying the participants per room, and this results in more rooms than was already created, the browser freezes. If I close or exit those tabs, and refresh, then retry opening the subsessions with the same settings, all the participants are sent to the same subsession.
- Recreating with fewer subsessions by specifying more participants per room also causes the same issue as above, and if it eventually succeeds, the participants are not reassigned to different rooms.
Thanks.