constructor(video, player, receiverAppId,
      androidReceiverCompatible = false) {
    super();

    /** @private {HTMLMediaElement} */
    this.localVideo_ = video;

    /** @private {shaka.Player} */
    this.localPlayer_ = player;

    /** @private {Object} */
    this.videoProxy_ = null;

    /** @private {Object} */
    this.playerProxy_ = null;

    /** @private {shaka.util.FakeEventTarget} */
    this.videoEventTarget_ = null;

    /** @private {shaka.util.FakeEventTarget} */
    this.playerEventTarget_ = null;

    /** @private {shaka.util.EventManager} */
    this.eventManager_ = null;

    /** @private {string} */
    this.receiverAppId_ = receiverAppId;

    /** @private {boolean} */
    this.androidReceiverCompatible_ = androidReceiverCompatible;

    /** @private {!Array<?>} */
    this.addThumbnailsTrackCalls_ = [];

    /** @private {!Array<?>} */
    this.addTextTrackAsyncCalls_ = [];

    /** @private {!Array<?>} */
    this.addChaptersTrackCalls_ = [];

    /** @private {!Map} */
    this.compiledToExternNames_ = new Map();

    /** @private {shaka.cast.CastSender} */
    this.sender_ = null;

    if (window.chrome) {
      this.sender_ = new shaka.cast.CastSender(
          receiverAppId,
          () => this.onCastStatusChanged_(),
          () => this.onFirstCastStateUpdate_(),
          (targetName, event) => this.onRemoteEvent_(targetName, event),
          () => this.onResumeLocal_(),
          () => this.getInitState_(),
          androidReceiverCompatible);
      this.init_();
    } else {
      this.initWithoutSender_();
    }
  }
@param {!HTMLMediaElement} video The local video element associated with
  the local Player instance.
@param {!shaka.Player} player A local Player instance.
@param {string} receiverAppId The ID of the cast receiver application.
  If blank, casting will not be available, but the proxy will still
  function otherwise.
@param {boolean} androidReceiverCompatible Indicates if the app is
  compatible with an Android Receiver.