dispatchEvent(event) {
    // In many browsers, it is complex to overwrite properties of actual Events.
    // Here we expect only to dispatch FakeEvents, which are simpler.
    goog.asserts.assert(event instanceof shaka.util.FakeEvent,
        'FakeEventTarget can only dispatch FakeEvents!');

    if (!this.listeners_) {
      return true;
    }

    let listeners = this.listeners_.get(event.type) || [];
    const universalListeners =
      this.listeners_.get(shaka.util.FakeEventTarget.ALL_EVENTS_);
    if (universalListeners) {
      listeners = listeners.concat(universalListeners);
    }

    // Execute this event on listeners until the event has been stopped or we
    // run out of listeners.
    for (const listener of listeners) {
      // Do this every time, since events can be re-dispatched from handlers.
      event.target = this.dispatchTarget;
      event.currentTarget = this.dispatchTarget;

      try {
        // Check for the |handleEvent| member to test if this is a
        // |EventListener| instance or a basic function.
        if (listener.handleEvent) {
          listener.handleEvent(event);
        } else {
          // eslint-disable-next-line no-restricted-syntax
          listener.call(this, event);
        }
      } catch (exception) {
        // Exceptions during event handlers should not affect the caller,
        // but should appear on the console as uncaught, according to MDN:
        // https://mzl.la/2JXgwRo
        shaka.log.error('Uncaught exception in event handler', exception,
            exception ? exception.message : null,
            exception ? exception.stack : null);
      }

      if (event.stopped) {
        break;
      }
    }

    return event.defaultPrevented;
  }
Dispatch an event from this object.

@param {!Event} event The event to be dispatched from this object.
@return {boolean} True if the default action was prevented.
@override
@exportInterface