protected calculateOptimalReceiveStreams()

in src/videodownlinkbandwidthpolicy/VideoPriorityBasedPolicy.ts [284:420]


  protected calculateOptimalReceiveStreams(): void {
    const chosenStreams: VideoStreamDescription[] = [];
    const remoteInfos: VideoStreamDescription[] = this.videoIndex.remoteStreamDescriptions();
    if (remoteInfos.length === 0 || this.videoPreferences?.isEmpty()) {
      this.optimalReceiveStreams = [];
      return;
    }

    const lastProbeState = this.rateProbeState;
    this.cleanBwPausedTiles(remoteInfos);
    this.handleAppPausedStreams(chosenStreams, remoteInfos);

    const sameStreamChoices = this.availStreamsSameAsLast(remoteInfos);

    // If no major changes then don't allow subscribes for the allowed amount of time
    const noMajorChange = !this.startupPeriod && sameStreamChoices;

    // subscribe interval will be changed if probe failed, will take this temporary interval into account
    if (
      noMajorChange &&
      this.probeFailed &&
      Date.now() - this.lastSubscribeTimestamp < this.timeBeforeAllowSubscribeMs
    ) {
      return;
    }

    this.probeFailed = false;

    // Sort streams by bitrate ascending.
    remoteInfos.sort((a, b) => {
      if (a.maxBitrateKbps === b.maxBitrateKbps) {
        return a.streamId - b.streamId;
      }
      return a.maxBitrateKbps - b.maxBitrateKbps;
    });

    // Convert 0 avg bitrates to max and handle special cases
    for (const info of remoteInfos) {
      if (info.avgBitrateKbps === 0 || info.avgBitrateKbps > info.maxBitrateKbps) {
        // Content can be a special case
        if (info.attendeeId.endsWith(ContentShareConstants.Modality) && info.maxBitrateKbps < 100) {
          info.maxBitrateKbps = info.avgBitrateKbps;
        } else {
          info.avgBitrateKbps = info.maxBitrateKbps;
        }
      }
    }

    const rates: PolicyRates = {
      targetDownlinkBitrate: 0,
      chosenTotalBitrate: 0,
      deltaToNextUpgrade: 0,
    };
    rates.targetDownlinkBitrate = this.determineTargetRate();

    // calculate subscribe delay based on bandwidth increasing/decreasing
    const numberOfParticipants = this.subscribedReceiveSet.size();
    const prevEstimated = this.prevDownlinkStats.bandwidthEstimateKbps;
    const currEstimated = this.downlinkStats.bandwidthEstimateKbps;

    if (currEstimated > prevEstimated) {
      // if bw increases, we use recovery delay
      this.timeBeforeAllowSubscribeMs = this.getSubscribeDelay(
        NetworkEvent.Increase,
        numberOfParticipants
      );
    } else if (currEstimated < prevEstimated) {
      // if bw decreases, we use response delay
      this.timeBeforeAllowSubscribeMs = this.getSubscribeDelay(
        NetworkEvent.Decrease,
        numberOfParticipants
      );
    }

    // If no major changes then don't allow subscribes for the allowed amount of time
    if (
      noMajorChange &&
      Date.now() - this.lastSubscribeTimestamp < this.timeBeforeAllowSubscribeMs
    ) {
      return;
    }

    const upgradeStream: VideoStreamDescription = this.priorityPolicy(
      rates,
      remoteInfos,
      chosenStreams
    );

    let subscriptionChoice = UseReceiveSet.NewOptimal;
    // Look for probing or override opportunities
    if (!this.startupPeriod && sameStreamChoices) {
      if (this.rateProbeState === RateProbeState.Probing) {
        subscriptionChoice = this.handleProbe(chosenStreams, rates.targetDownlinkBitrate);
      } else if (rates.deltaToNextUpgrade !== 0) {
        subscriptionChoice = this.maybeOverrideOrProbe(chosenStreams, rates, upgradeStream);
      }
    } else {
      // If there was a change in streams to choose from, then cancel any probing or upgrades
      this.setProbeState(RateProbeState.NotProbing);
      this.lastUpgradeRateKbps = 0;
    }

    this.prevRemoteInfos = remoteInfos;
    this.videoPreferencesUpdated = false;

    if (subscriptionChoice === UseReceiveSet.PreviousOptimal) {
      this.logger.info(`bwe: keepSameSubscriptions stats:${JSON.stringify(this.downlinkStats)}`);
      this.prevTargetRateKbps = rates.targetDownlinkBitrate;
      return;
    }
    if (subscriptionChoice === UseReceiveSet.PreProbe) {
      const subscribedRate = this.calculateSubscribeRate(this.preProbeNonPausedReceiveStreams);
      this.optimalReceiveStreams = this.preProbeReceiveStreams.slice();
      this.processBwPausedStreams(remoteInfos, this.preProbeNonPausedReceiveStreams);
      this.logger.info('bwe: Use Pre-Probe subscription subscribedRate:' + subscribedRate);
      return;
    }

    this.optimalNonPausedReceiveStreams = chosenStreams.slice();
    const lastNumberPaused = this.pausedBwAttendeeIds.size;
    this.processBwPausedStreams(remoteInfos, chosenStreams);

    if (
      this.logger.getLogLevel() <= LogLevel.INFO &&
      (this.logCount % 15 === 0 ||
        this.rateProbeState !== lastProbeState ||
        this.optimalReceiveStreams.length !== chosenStreams.length ||
        lastNumberPaused !== this.pausedBwAttendeeIds.size)
    ) {
      this.logger.info(this.policyStateLogStr(remoteInfos, rates.targetDownlinkBitrate));
      this.logCount = 0;
    }
    this.logCount++;

    this.prevTargetRateKbps = rates.targetDownlinkBitrate;
    this.optimalReceiveStreams = chosenStreams.slice();
  }