in src/audiovideocontroller/DefaultAudioVideoController.ts [828:923]
private updateRemoteVideosFromLastVideosToReceive(): boolean {
const context = this.meetingSessionContext;
if (context.videosToReceive?.empty() || context.lastVideosToReceive?.empty()) {
return false;
}
// Check existence of all required dependencies and requisite functions
if (
!context.transceiverController ||
!context.transceiverController.getMidForStreamId ||
!context.transceiverController.setStreamIdForMid ||
!context.videosToReceive.forEach ||
!context.signalingClient.remoteVideoUpdate ||
!context.videoStreamIndex.overrideStreamIdMappings
) {
return false;
}
let added: number[] = [];
const simulcastStreamUpdates: Map<number, number> = new Map();
let removed: number[] = [];
if (context.lastVideosToReceive === null) {
added = context.videosToReceive.array();
} else {
const index = context.videoStreamIndex;
context.videosToReceive.forEach((currentId: number) => {
if (context.lastVideosToReceive.contain(currentId)) {
return;
}
// Check if group ID exists in previous set (i.e. simulcast stream switch)
let foundUpdatedPreviousStreamId = false;
context.lastVideosToReceive.forEach((previousId: number) => {
if (foundUpdatedPreviousStreamId) {
return; // Short circuit since we have already found it
}
if (index.StreamIdsInSameGroup(previousId, currentId)) {
simulcastStreamUpdates.set(previousId, currentId);
foundUpdatedPreviousStreamId = true;
}
});
if (!foundUpdatedPreviousStreamId) {
// Otherwise this must be a new stream
added.push(currentId);
}
});
removed = context.lastVideosToReceive.array().filter(idFromPrevious => {
const stillReceiving = context.videosToReceive.contain(idFromPrevious);
const isUpdated = simulcastStreamUpdates.has(idFromPrevious);
return !stillReceiving && !isUpdated;
});
}
this.logger.info(
`Request to update remote videos with added: ${added}, updated: ${[
...simulcastStreamUpdates.entries(),
]}, removed: ${removed}`
);
const updatedVideoSubscriptionConfigurations: SignalingClientVideoSubscriptionConfiguration[] = [];
for (const [previousId, currentId] of simulcastStreamUpdates.entries()) {
const updatedConfig = new SignalingClientVideoSubscriptionConfiguration();
updatedConfig.streamId = currentId;
updatedConfig.attendeeId = context.videoStreamIndex.attendeeIdForStreamId(currentId);
updatedConfig.mid = context.transceiverController.getMidForStreamId(previousId);
if (updatedConfig.mid === undefined) {
this.logger.info(
`No MID found for stream ID ${previousId}, cannot update stream without renegotiation`
);
return false;
}
updatedVideoSubscriptionConfigurations.push(updatedConfig);
// We need to override some other components dependent on the subscribe paths for certain functionality
context.transceiverController.setStreamIdForMid(updatedConfig.mid, currentId);
context.videoStreamIndex.overrideStreamIdMappings(previousId, currentId);
if (context.videoTileController.haveVideoTileForAttendeeId(updatedConfig.attendeeId)) {
const tile = context.videoTileController.getVideoTileForAttendeeId(
updatedConfig.attendeeId
);
if (!tile.setStreamId) {
// Required function
return false;
}
tile.setStreamId(currentId);
}
}
if (updatedVideoSubscriptionConfigurations.length !== 0) {
context.signalingClient.remoteVideoUpdate(updatedVideoSubscriptionConfigurations, []);
}
// Only simulcast stream switches (i.e. not add/remove/source switches) are possible currently
if (added.length !== 0 || removed.length !== 0) {
return false;
}
return true;
}