in src/task/CreatePeerConnectionTask.ts [153:246]
private addRemoteVideoTrack(track: MediaStreamTrack, stream: MediaStream): void {
let trackId = stream.id;
if (!this.context.browserBehavior.requiresUnifiedPlan()) {
stream = new MediaStream([track]);
trackId = track.id;
}
const attendeeId = this.context.videoStreamIndex.attendeeIdForTrack(trackId);
let skipAdding: boolean;
let tile: VideoTile;
if (this.context.videoTileController.getVideoTileForAttendeeId) {
tile = this.context.videoTileController.getVideoTileForAttendeeId(attendeeId);
skipAdding = !!tile?.state()?.boundVideoStream;
} else {
skipAdding = this.context.videoTileController.haveVideoTileForAttendeeId(attendeeId);
}
if (skipAdding) {
this.context.logger.info(
`Not adding remote track. Already have tile for attendeeId: ${attendeeId}`
);
return;
}
if (!tile) {
tile = this.context.videoTileController.addVideoTile();
this.logger.info(`Created video tile ${tile.id()}`);
}
let streamId: number | null = this.context.videoStreamIndex.streamIdForTrack(trackId);
if (typeof streamId === 'undefined') {
this.logger.warn(`stream not found for tile=${tile.id()} track=${trackId}`);
streamId = null;
}
for (let i = 0; i < this.trackEvents.length; i++) {
const trackEvent: string = this.trackEvents[i];
const videoTracks = stream.getVideoTracks();
if (videoTracks && videoTracks.length) {
const videoTrack: MediaStreamTrack = videoTracks[0];
const callback: EventListenerOrEventListenerObject = (): void => {
this.context.logger.info(
`received the ${trackEvent} event for tile=${tile.id()} id=${
track.id
} streamId=${streamId}`
);
if (trackEvent === 'ended' && this.context.browserBehavior.requiresUnifiedPlan()) {
this.removeRemoteVideoTrack(track, tile.state());
}
};
videoTrack.addEventListener(trackEvent, callback);
if (!this.removeVideoTrackEventListeners[track.id]) {
this.removeVideoTrackEventListeners[track.id] = [];
}
this.removeVideoTrackEventListeners[track.id].push(() => {
videoTrack.removeEventListener(trackEvent, callback);
});
}
}
let width: number;
let height: number;
if (track.getSettings) {
const cap: MediaTrackSettings = track.getSettings();
width = cap.width as number;
height = cap.height as number;
} else {
const cap: MediaTrackCapabilities = track.getCapabilities();
width = cap.width as number;
height = cap.height as number;
}
const externalUserId = this.context.videoStreamIndex.externalUserIdForTrack(trackId);
tile.bindVideoStream(attendeeId, false, stream, width, height, streamId, externalUserId);
this.logger.info(
`video track added, use tile=${tile.id()} track=${trackId} streamId=${streamId}`
);
let endEvent = 'removetrack';
let target: MediaStream = stream;
if (!this.context.browserBehavior.requiresUnifiedPlan()) {
this.logger.debug(() => {
return 'updating end event and target track (plan-b)';
});
endEvent = 'ended';
// @ts-ignore
target = track;
}
const trackRemovedHandler = (): void => this.removeRemoteVideoTrack(track, tile.state());
this.removeTrackRemovedEventListeners[track.id] = () => {
target.removeEventListener(endEvent, trackRemovedHandler);
delete this.removeTrackRemovedEventListeners[track.id];
};
target.addEventListener(endEvent, trackRemovedHandler);
}