switchVariant_(variant, fromAdaptation, clearBuffer, safeMargin,
      force = false) {
    const currentVariant = this.streamingEngine_.getCurrentVariant();
    if (variant == currentVariant) {
      shaka.log.debug('Variant already selected.');
      // If you want to clear the buffer, we force to reselect the same variant.
      // We don't need to reset the timestampOffset since it's the same variant,
      // so 'adaptation' isn't passed here.
      if (clearBuffer) {
        this.streamingEngine_.switchVariant(variant, clearBuffer, safeMargin,
            /* force= */ true);
      }
      return;
    }

    // Add entries to the history.
    this.addVariantToSwitchHistory_(variant, fromAdaptation);
    this.streamingEngine_.switchVariant(
        variant, clearBuffer, safeMargin, force,
        /* adaptation= */ fromAdaptation);
    let oldTrack = null;
    if (currentVariant) {
      oldTrack = shaka.util.StreamUtils.variantToTrack(currentVariant);
    }
    const newTrack = shaka.util.StreamUtils.variantToTrack(variant);
    newTrack.active = true;

    if (this.lcevcDec_) {
      this.lcevcDec_.updateVariant(variant, this.getManifestType());
    }

    if (fromAdaptation) {
      // Dispatch an 'adaptation' event
      this.onAdaptation_(oldTrack, newTrack);
    } else {
      // Dispatch a 'variantchanged' event
      this.onVariantChanged_(oldTrack, newTrack);
    }
    // Dispatch a 'audiotrackschanged' event if necessary
    this.checkAudioTracksChanged_(oldTrack, newTrack);
  }
@param {shaka.extern.Variant} variant
@param {boolean} fromAdaptation
@param {boolean} clearBuffer
@param {number} safeMargin
@param {boolean=} force
@private