setPublishingLayersForSender method

Future<void> setPublishingLayersForSender(
  1. RTCRtpSender sender,
  2. List<RTCRtpEncoding> encodings,
  3. List<SubscribedQuality> layers
)

Implementation

Future<void> setPublishingLayersForSender(
    rtc.RTCRtpSender sender,
    List<rtc.RTCRtpEncoding> encodings,
    List<lk_rtc.SubscribedQuality> layers) async {
  logger.fine('Update publishing layers: $layers');

  final params = sender.parameters;

  var hasChanged = false;

  /* disable closable spatial layer as it has video blur / frozen issue with current server / client
  1. chrome 113: when switching to up layer with scalability Mode change, it will generate a
        low resolution frame and recover very quickly, but noticable
  2. livekit sfu: additional pli request cause video frozen for a few frames, also noticable */

  /* @ts-ignore */
  if (encodings[0].scalabilityMode != null) {
    // svc dynacast encodings
    var encoding = encodings[0];
    /* @ts-ignore */
    // const mode = new ScalabilityMode(encoding.scalabilityMode);
    var maxQuality = lk_models.VideoQuality.OFF;
    for (var q in layers) {
      if (q.enabled &&
          (maxQuality == lk_models.VideoQuality.OFF ||
              q.quality.value > maxQuality.value)) {
        maxQuality = q.quality;
      }
    }

    if (maxQuality == lk_models.VideoQuality.OFF) {
      if (encoding.active) {
        encoding.active = false;
        hasChanged = true;
      }
    } else if (!encoding.active /* || mode.spatial !== maxQuality + 1*/) {
      hasChanged = true;
      encoding.active = true;
      /*
      var originalMode = new ScalabilityMode(senderEncodings[0].scalabilityMode)
      mode.spatial = maxQuality + 1;
      mode.suffix = originalMode.suffix;
      if (mode.spatial === 1) {
        // no suffix for L1Tx
        mode.suffix = undefined;
      }
      encoding.scalabilityMode = mode.toString();
      encoding.scaleResolutionDownBy = 2 ** (2 - maxQuality);
    */
    }
  } else {
    // simulcast dynacast encodings
    var idx = 0;
    for (var encoding in encodings) {
      var rid = encoding.rid ?? '';
      if (rid == '') {
        rid = 'q';
      }
      var quality = videoQualityForRid(rid);
      var subscribedQuality =
          layers.firstWhereOrNull((q) => q.quality == quality);
      if (subscribedQuality == null) {
        continue;
      }
      if (encoding.active != subscribedQuality.enabled) {
        hasChanged = true;
        encoding.active = subscribedQuality.enabled;
        logger.fine(
          'setting layer ${subscribedQuality.quality} to ${encoding.active ? 'enabled' : 'disabled'}',
        );

        // FireFox does not support setting encoding.active to false, so we
        // have a workaround of lowering its bitrate and resolution to the min.
        if (kIsWeb && lkBrowser() == BrowserType.firefox) {
          if (subscribedQuality.enabled) {
            encoding.scaleResolutionDownBy =
                encodings[idx].scaleResolutionDownBy;
            encoding.maxBitrate = encodings[idx].maxBitrate;
            encoding.maxFramerate = encodings[idx].maxBitrate;
          } else {
            encoding.scaleResolutionDownBy = 4;
            encoding.maxBitrate = 10;
            encoding.maxFramerate = 2;
          }
        }
      }
      idx++;
    }
  }

  if (hasChanged) {
    params.encodings = encodings;
    final result = await sender.setParameters(params);
    if (result == false) {
      logger.warning('Failed to update sender parameters');
    }
  }
}