private addRemoteVideoTrack()

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);
  }