/**
 * @archivo html5.js
 * /
importar tecnología desde './tech.js';
importar * como Dom desde '../utils/dom.js';
importar * como URL desde '../utils/url.js';
importar registro desde '../utils/log.js';
importar * como navegador desde '../utils/browser.js';
importar documento desde 'global/document';
importar ventana desde 'global/window';
importar {asignar} desde '../utils/obj';
importar mergeOptions desde '../utils/merge-options.js';
importar {toTitleCase} desde '../utils/string-cases.js';
importar {NORMAL como TRACK_TYPES, REMOTE} desde '../tracks/track-types';
importar setupSourceset desde './setup-sourceset';
importar defineLazyProperty desde '../utils/define-lazy-property.js';
importar {silencePromise} desde '../utils/promise';

/**
 * Controlador de medios HTML5: contenedor para API de medios HTML5
 *
 * @mixes Tech~SourceHandlerAdditions
 * @extiende tecnología
 * /
class Html5 extiende Tech {

  /**
  * Crear una instancia de este Tech.
  *
  * @param {Objeto} [opciones]
  * El almacén de clave/valor de las opciones del jugador.
  *
  * @param {Componente~ReadyCallback} listo
  * Función de devolución de llamada para llamar cuando la tecnología `HTML5` esté lista.
  * /
  constructor(opciones, listo) {
    super(opciones, listo);

    const fuente = opciones.fuente;
    let crossoriginTracks = false;

    this.featuresVideoFrameCallback = this.featuresVideoFrameCallback && this.el_.tagName === 'VIDEO';

    // Establecer la fuente si se proporciona una
    // 1) Comprobar si la fuente es nueva (si no, queremos mantener la original para que la reproducción no se interrumpa)
    // 2) Verifique si el estado de la red de la etiqueta falló en el inicio y, de ser así, restablezca la fuente
    // de todos modos, el error se dispara.
    si (fuente && (this.el_.currentSrc !== source.src || (options.tag && opciones.tag.initNetworkState_ === 3))) {
      this.setSource(fuente);
    } else {
      this.handleLateInit_(this.el_);
    }

    // configurar el conjunto de fuentes después del conjunto de fuentes tardío/init
    si (opciones.enableSourceset) {
      this.setupSourcesetHandling_();
    }

    this.isScrubbing_ = false;

    if (this.el_.hasChildNodes()) {

      const nodos = this.el_.childNodes;
      let nodosLength = nodos.longitud;
      const eliminarNodos = [];

      while (longitud de nodos--) {
        const nodo = nodos[longitudnodos];
        const nodeName = node.nodeName.toLowerCase();

        if (nombreNodo === 'pista') {
          if (!this.featuresNativeTextTracks) {
            // Vacíe las pistas de etiquetas de video para que el reproductor incorporado no las use también.
            // Esto puede no ser lo suficientemente rápido para evitar que los navegadores HTML5 lean las etiquetas
            // así que tendremos que desactivar las pistas predeterminadas si lo hacemos manualmente
            // títulos y subtítulos. videoElement.textPistas
            removeNodes.push(nodo);
          } else {
            // almacenar HTMLTrackElement y TextTrack en la lista remota
            this.remoteTextTrackEls().addTrackElement_(nodo);
            this.remoteTextTracks().addTrack(nodo.pista);
            this.textTracks().addTrack(nodo.pista);
            if (!crossoriginTracks &&
                !this.el_.hasAttribute('origen cruzado') &&
                Url.isCrossOrigin(nodo.src)) {
              pistas de origen cruzado = verdadero;
            }
          }
        }
      }

      para (sea i = 0; i < removeNodes.longitud; i++) {
        this.el_.removeChild(removeNodes[i]);
      }
    }

    this.proxyNativeTracks_();
    if (this.featuresNativeTextTracks && pistas de origen cruzado) {
      log.warn('Las pistas de texto se están cargando desde otro origen pero el atributo crossorigin no se usa.\n' +
            'Esto puede evitar que se carguen las pistas de texto.');
    }

    // evita que iOS Safari deshabilite las pistas de texto de metadatos durante la reproducción nativa
    this.restoreMetadataTracksInIOSNativePlayer_();

    // Determinar si se deben usar controles nativos
    // Nuestro objetivo debe ser obtener los controles personalizados en dispositivos móviles sólidos en todas partes
    // para que podamos eliminar todo esto juntos. En este momento esto bloqueará la costumbre
    // controles en portátiles con capacidad táctil como Chrome Pixel
    if ((navegador.TOUCH_ENABLED || navegador.IS_IPHONE ||
        navegador.IS_NATIVE_ANDROID) && opciones.nativeControlsForTouch === verdadero) {
      este.setControls(verdadero);
    }

    // en iOS, queremos proxy `webkitbeginfullscreen` y `webkitendfullscreen`
    // en un evento `cambio de pantalla completa`
    this.proxyWebkitFullscreen_();

    this.triggerReady();
  }

  /**
   * Deseche el elemento multimedia `HTML5` y elimine todas las pistas.
   * /
  disponer () {
    si (esto.el_ && this.el_.resetSourceset_) {
      this.el_.resetSourceset_();
    }
    Html5.disposeMediaElement(this.el_);
    esto.opciones_ = nulo;

    // el técnico se encargará de borrar la lista de pistas emuladas
    super.dispose();
  }

  /**
   * Modificar el elemento multimedia para que podamos detectar cuándo
   * se cambia la fuente. Activa `sourceset` justo después de que la fuente haya cambiado
   * /
  setupSourcesetHandling_() {
    setupSourceset(esto);
  }

  /**
   * Cuando una pista de subtítulos está habilitada en el reproductor nativo iOS Safari, todos los demás
   * las pistas están deshabilitadas (incluidas las pistas de metadatos), lo que anula todas sus
   * puntos de referencia asociados. Esto restaurará las pistas de metadatos a su estado previo a la pantalla completa.
   * estado en esos casos para que los puntos de referencia no se pierdan innecesariamente.
   *
   * @privado
   * /
  restaurarMetadataTracksInIOSNativePlayer_() {
    const textTracks = this.textTracks();
    let metadataTracksPreFullscreenState;

    // captura una instantánea del estado actual de cada pista de metadatos
    const tomarMetadataTrackSnapshot = () => {
      metadataTracksPreFullscreenState = [];

      para (sea i = 0; i < Pistas de texto.longitud; i++) {
        const track = textTracks[i];

        if (pista.tipo === 'metadatos') {
          metadataTracksPreFullscreenState.push({
            pista,
            modo almacenado: track.mode
          });
        }
      }
    };

    // instantánea del estado inicial de cada pista de metadatos y actualización de la instantánea
    // cada vez que hay un evento de 'cambio' de pista
    tomarMetadataTrackSnapshot();
    textTracks.addEventListener('cambiar', tomarMetadataTrackSnapshot);

    this.on('dispose', () => textTracks.removeEventListener('cambiar', tomarMetadataTrackSnapshot));

    const restaurarTrackMode = () => {
      para (sea i = 0; i < metadataTracksPreFullscreenState.length; i++) {
        const PistaAlmacenada = MetadataTracksPreFullscreenState[i];

        if (storedTrack.track.mode === 'deshabilitado' && PistaAlmacenada.modo.pista !== PistaAlmacenada.ModoAlmacenado) {
          PistaAlmacenada.modo.pista = PistaAlmacenada.ModoAlmacenado;
        }
      }
      // solo queremos que este controlador se ejecute en el primer evento de 'cambio'
      textTracks.removeEventListener('cambiar', restoreTrackMode);
    };

    // cuando entramos en reproducción a pantalla completa, dejamos de actualizar la instantánea y
    // restaurar todos los modos de pista a su estado previo a la pantalla completa
    this.on('webkitbeginfullscreen', () => {
      textTracks.removeEventListener('cambiar', tomarMetadataTrackSnapshot);

      // elimine el oyente antes de agregarlo en caso de que no se haya eliminado previamente
      textTracks.removeEventListener('cambiar', restoreTrackMode);
      textTracks.addEventListener('cambiar', restoreTrackMode);
    });

    // comienza a actualizar la instantánea nuevamente después de salir de la pantalla completa
    this.on('webkitendfullscreen', () => {
      // elimine el oyente antes de agregarlo en caso de que no se haya eliminado previamente
      textTracks.removeEventListener('cambiar', tomarMetadataTrackSnapshot);
      textTracks.addEventListener('cambiar', tomarMetadataTrackSnapshot);

      // elimine el controlador restoreTrackMode en caso de que no se haya activado durante la reproducción a pantalla completa
      textTracks.removeEventListener('cambiar', restoreTrackMode);
    });
  }

  /**
   * Intento de forzar la anulación de pistas para el tipo dado
   *
   * @param {string} tipo: tipo de pista para anular, los valores posibles incluyen 'Audio',
   * 'Video' y 'Texto'.
   * @param {boolean} anular: si se establece en verdadero audio/video nativo, se anulará,
   * de lo contrario, se utilizará potencialmente audio/video nativo.
   * @privado
   * /
  overrideNative_(tipo, anular) {
    // Si no hay un cambio de comportamiento, no agregue/elimine oyentes
    if (anular !== this[`featuresNative${type}Tracks`]) {
      devolver;
    }

    const lowerCaseType = type.toLowerCase();

    if (this[`${lowerCaseType}TracksListeners_`]) {
      Object.keys(this[`${lowerCaseType}TracksListeners_`]).forEach((eventName) => {
        const elTracks = this.el()[`${lowerCaseType}Tracks`];

        elTracks.removeEventListener(nombreEvento, this[`${lowerCaseType}TracksListeners_`][nombreEvento]);
      });
    }

    this[`featuresNative${type}Tracks`] = !override;
    this[`${lowerCaseType}TracksListeners_`] = nulo;

    this.proxyNativeTracksForType_(lowerCaseType);
  }

  /**
   * Intento de forzar la anulación de las pistas de audio nativas.
   *
   * @param {boolean} anular: si se establece en verdadero audio nativo, se anulará,
   * de lo contrario, se utilizará potencialmente el audio nativo.
   * /
  anular las pistas de audio nativas (anular) {
    this.overrideNative_('Audio', anular);
  }

  /**
   * Intento de forzar la anulación de pistas de video nativas.
   *
   * @param {boolean} anular: si se establece en verdadero video nativo, se anulará,
   * de lo contrario, se utilizará potencialmente el video nativo.
   * /
  anular las pistas de video nativas (anular) {
    this.overrideNative_('Video', anular);
  }

  /**
   * Eventos de la lista de pistas nativas de proxy para el tipo dado a nuestra pista
   * enumera si el navegador en el que estamos jugando admite ese tipo de lista de pistas.
   *
   * @param {cadena} nombre - Tipo de pista; los valores incluyen 'audio', 'video' y 'texto'
   * @privado
   * /
  proxyNativeTracksForType_(nombre) {
    const props = TRACK_TYPES[nombre];
    const elTracks = this.el()[props.getterName];
    const techTracks = this[props.getterName]();

    if (!this[`featuresNative${props.capitalName}Tracks`] ||
        !elPistas ||
        !elTracks.addEventListener) {
      devolver;
    }
    oyentes const = {
      cambio: (e) => {
        evento constante = {
          tipo: 'cambio',
          objetivo: pistas tecnológicas,
          objetivo actual: pistas tecnológicas,
          srcElement: pistas tecnológicas
        };

        techTracks.trigger(evento);

        // si somos un evento de cambio de pista de texto, también debemos notificar al
        // lista de pistas de texto remoto. Esto puede potencialmente causar un falso positivo
        // si obtuviéramos un evento de cambio en una pista no remota y
        // activamos el evento en la lista de pistas de texto remoto que no
        // contiene esa pista. Sin embargo, las mejores prácticas significan recorrer los
        // lista de pistas y buscando el valor de modo apropiado, entonces,
        // esto no debería suponer un problema
        if (nombre === 'texto') {
          this[REMOTE.remoteText.getterName]().trigger(evento);
        }
      },
      añadir pista (e) {
        techTracks.addTrack(pista electrónica);
      },
      eliminar pista (e) {
        techTracks.removeTrack(e.track);
      }
    };
    const removeOldTracks = function() {
      const removeTracks = [];

      para (sea i = 0; i < techTracks.longitud; i++) {
        let encontrado = falso;

        para (sea j = 0; j < elTracks.longitud; j++) {
          if (elTracks[j] === techTracks[i]) {
            encontrado = verdadero;
            romper;
          }
        }

        si se encuentra) {
          removeTracks.push(techTracks[i]);
        }
      }

      while (eliminar pistas.longitud) {
        techTracks.removeTrack(removeTracks.shift());
      }
    };

    this[props.getterName + 'Listeners_'] = oyentes;

    Object.keys(oyentes).forEach((nombreEvento) => {
      const oyente = oyentes[nombreEvento];

      elTracks.addEventListener(nombreEvento, oyente);
      this.on('dispose', (e) => elTracks.removeEventListener(eventName, listener));
    });

    // Eliminar pistas (nativas) que ya no se usan
    this.on('loadstart', removeOldTracks);
    this.on('dispose', (e) => this.off('loadstart', removeOldTracks));
  }

  /**
   * Proxy todos los eventos de la lista de pistas nativas a nuestras listas de pistas si el navegador que estamos jugando
   * en admite ese tipo de lista de pistas.
   *
   * @privado
   * /
  proxyNativeTracks_() {
    TRACK_TYPES.names.forEach((nombre) => {
      this.proxyNativeTracksForType_(nombre);
    });
  }

  /**
   * Crear el elemento DOM de `Html5` Tech.
   *
   * @return {Elemento}
   * El elemento que se crea.
   * /
  crearEl() {
    let el = esto.opciones_.etiqueta;

    // Comprueba si este navegador admite mover el elemento al cuadro.
    // En el iPhone, el video se romperá si mueves el elemento,
    // Así que tenemos que crear un elemento completamente nuevo.
    // Si ingerimos el player div, no necesitamos mover el elemento multimedia.
    si (!el ||
        !(this.options_.playerElIngest ||
          this.movingMediaElementInDOM)) {

      // Si la etiqueta original todavía está allí, clonarla y eliminarla.
      Me caí) {
        const clon = el.cloneNode(true);

        if (el.parentNode) {
          el.parentNode.insertBefore(clon, el);
        }
        Html5.disposeMediaElement(el);
        el = clon;

      } else {
        el = documento.createElement('video');

        // determinar si se deben usar controles nativos
        const tagAttributes = this.options_.tag && Dom.getAttributes(this.options_.tag);
        const atributos = mergeOptions({}, tagAttributes);

        if (!browser.TOUCH_ENABLED || this.options_.nativeControlsForTouch !== verdadero) {
          eliminar atributos.controles;
        }

        Dom.setAttributes(
          el,
          asignar(atributos, {
            id: this.options_.techId,
            clase: 'tecnología vjs'
          })
        );
      }

      el.playerId = this.options_.playerId;
    }

    if (typeof this.options_.preload !== 'indefinido') {
      Dom.setAttribute(el, 'precargar', this.options_.preload);
    }

    if (this.options_.disablePictureInPicture!== indefinido) {
      el.disablePictureInPicture = this.options_.disablePictureInPicture;
    }

    // Actualice la configuración de etiquetas específicas, en caso de que se hayan anulado
    // `autoplay` tiene que ser *último* para que `mud` y `playsinline` estén presentes
    // cuando iOS/Safari u otros navegadores intentan reproducir automáticamente.
    const settingsAttrs = ['loop', 'mud', 'playsinline', 'autoplay'];

    para (sea i = 0; i < ajustesAttrs.longitud; i++) {
      const attr = settingsAttrs[i];
      valor constante = this.options_[attr];

      if (tipo de valor! == 'indefinido') {
        si (valor) {
          Dom.setAttribute(el, atributo, atributo);
        } else {
          Dom.removeAttribute(el, attr);
        }
        el[atributo] = valor;
      }
    }

    volver el;
  }

  /**
   * Esto se activará si el evento de inicio de carga ya se ha activado, antes de que se disparara videojs.
   * listo. Dos ejemplos conocidos de cuándo puede ocurrir esto son:
   * 1. Si estamos cargando el objeto de reproducción después de que haya comenzado a cargarse
   * 2. El medio ya está reproduciendo el (a menudo con la reproducción automática activada)
   *
   * Esta función activará otro inicio de carga para que videojs pueda ponerse al día.
   *
   * @incendios Tech#loadstart
   *
   * @return {indefinido}
   * no devuelve nada.
   * /
  handleLateInit_(el) {
    if (el.networkState === 0 || el.networkState === 3) {
      // El elemento de video aún no ha comenzado a cargar la fuente
      // o no encontre una fuente
      devolver;
    }

    if (el.readyState === 0) {
      // NetworkState se establece sincrónicamente PERO loadstart se activa en el
      // final de la pila actual, normalmente antes de setInterval(fn, 0).
      // Así que en este punto sabemos que loadstart ya se ha disparado o está
      // a punto de disparar, y de cualquier manera el jugador aún no lo ha visto.
      // No queremos activar loadstart prematuramente aquí y causar un
      // inicio de carga doble, así que esperaremos y veremos si sucede entre ahora
      // y el siguiente bucle, y dispararlo si no.
      // SIN EMBARGO, también queremos asegurarnos de que se active antes de los metadatos cargados
      // lo que también podría ocurrir entre ahora y el siguiente bucle, así que
      // cuidado con eso también.
      let loadstartFired = false;
      const setLoadstartFired = function() {
        loadstartFired = verdadero;
      };

      this.on('loadstart', setLoadstartFired);

      const triggerLoadstart = function() {
        // Echamos de menos el inicio de carga original. Asegúrese de que el jugador
        // ve inicio de carga antes de metadatos cargados
        si (!loadstartFired) {
          this.trigger('loadstart');
        }
      };

      this.on('metadatos cargados', triggerLoadstart);

      esto.listo(función() {
        this.off('loadstart', setLoadstartFired);
        this.off('metadatos cargados', triggerLoadstart);

        si (!loadstartFired) {
          // Echamos de menos el inicio de carga nativo original. Dispáralo ahora.
          this.trigger('loadstart');
        }
      });

      devolver;
    }

    // De aquí en adelante sabemos que loadstart ya se disparó y lo perdimos.
    // Los otros eventos readyState no son un gran problema si duplicamos
    // ellos, por lo que no va a tener tantos problemas como loadstart para evitar
    // eso a menos que encontremos una razón para hacerlo.
    const eventsToTrigger = ['loadstart'];

    // metadatos cargados: nuevo igual a HAVE_METADATA (1) o mayor
    eventsToTrigger.push('metadatos cargados');

    // datos cargados: recién aumentado a HAVE_CURRENT_DATA (2) o mayor
    si (el.readyState > = 2) {
      eventsToTrigger.push('datos cargados');
    }

    // canplay: recién aumentado a HAVE_FUTURE_DATA (3) o mayor
    si (el.readyState > = 3) {
      eventsToTrigger.push('canplay');
    }

    // canplaythrough: recién igual a HAVE_ENOUGH_DATA (4)
    si (el.readyState > = 4) {
      eventsToTrigger.push('canplaythrough');
    }

    // Todavía necesitamos darle tiempo al jugador para agregar detectores de eventos
    esto.listo(función() {
      eventsToTrigger.forEach(función(tipo) {
        this.trigger(tipo);
      }, this);
    });
  }

  /**
   * Establecer si estamos fregando o no.
   * Esto se usa para decidir si debemos usar `fastSeek` o no.
   * `fastSeek` se usa para proporcionar trucos en los navegadores Safari.
   *
   * @param {booleano} está fregando
   * - cierto porque actualmente estamos limpiando
   * - falso porque ya no estamos fregando
   * /
  setScrubbing(isScrubbing) {
    this.isScrubbing_ = isScrubbing;
  }

  /**
   * Obtener si estamos fregando o no.
   *
   * @return {booleano} está fregando
   * - cierto porque actualmente estamos limpiando
   * - falso porque ya no estamos fregando
   * /
  fregado() {
    devuelve esto.isScrubbing_;
  }

  /**
   * Establecer la hora actual para la tecnología `HTML5`.
   *
   * @param {número} segundos
   * Establezca la hora actual de los medios en esto.
   * /
  establecerHoraActual(segundos) {
    intentar {
      if (this.isScrubbing_ && this.el_.fastSeek && navegador.IS_ANY_SAFARI) {
        this.el_.fastSeek(segundos);
      } else {
        this.el_.currentTime = segundos;
      }
    } catch (e) {
      log(e, 'El video no está listo. (Video.js)');
      // this.warning(VideoJS.warnings.videoNotReady);
    }
  }

  /**
   * Obtener la duración actual del elemento multimedia HTML5.
   *
   * @return {número}
   * La duración del medio o 0 si no hay duración.
   * /
  duración() {
    // Android Chrome informará la duración como Infinity para VOD HLS hasta después
    // la reproducción ha comenzado, lo que activa la visualización en vivo de forma errónea.
    // Devuelve NaN si la reproducción no ha comenzado y activa una actualización de duración una vez
    // la duración puede conocerse de forma fiable.
    si (
      this.el_.duration === Infinito &&
      navegador.IS_ANDROID &&
      navegador.IS_CHROME &&
      this.el_.currentTime === 0
    ) {
      // Espere la primera `timeupdate` con currentTime > 0 - puede haber
      // varios con 0
      const comprobarProgreso = () => {
        if (this.el_.currentTime > 0) {
          // Activar cambio de duración para video en vivo genuino
          if (this.el_.duration === Infinito) {
            this.trigger('cambio de duración');
          }
          this.off('actualización de la hora', comprobarProgreso);
        }
      };

      this.on('actualización de la hora', comprobarProgreso);
      devolver NaN;
    }
    devuelve this.el_.duration || Yaya;
  }

  /**
   * Obtener el ancho actual del elemento multimedia HTML5.
   *
   * @return {número}
   * El ancho del elemento multimedia HTML5.
   * /
  ancho() {
    devuelve this.el_.offsetWidth;
  }

  /**
   * Obtenga la altura actual del elemento multimedia HTML5.
   *
   * @return {número}
   * La altura del elemento multimedia HTML5.
   * /
  altura() {
    devuelve this.el_.offsetHeight;
  }

  /**
   * Proxy iOS `webkitbeginfullscreen` y `webkitendfullscreen` en
   * Evento `cambio de pantalla completa`.
   *
   * @privado
   * @fires cambio de pantalla completa
   * @escucha webkitendfullscreen
   * @escucha webkitbeginfullscreen
   * @escucha webkitbeginfullscreen
   * /
  proxyWebkitFullscreen_() {
    if (!('webkitDisplayingFullscreen' en this.el_)) {
      devolver;
    }

    const finFn = función() {
      this.trigger('cambio de pantalla completa', { isFullscreen: false });
      // Safari a veces establecerá controles en el elemento de video cuando exista una pantalla completa.
      si (esto.el_.controles && !this.options_.nativeControlsForTouch && esto.controles()) {
        this.el_.controles = false;
      }
    };

    const comienzoFn = función () {
      if ('webkitPresentationMode' en this.el_ && this.el_.webkitPresentationMode !== 'imagen en imagen') {
        this.one('webkitendfullscreen', endFn);

        this.trigger('cambio de pantalla completa', {
          isFullscreen: cierto,
          // establece una bandera en caso de que otra tecnología active el cambio de pantalla completa
          nativeIOSFullscreen: verdadero
        });
      }
    };

    this.on('webkitbeginfullscreen', beginFn);
    this.on('dispose', () => {
      this.off('webkitbeginfullscreen', beginFn);
      this.off('webkitendfullscreen', endFn);
    });
  }

  /**
   * Compruebe si la pantalla completa es compatible con el dispositivo de reproducción actual.
   *
   * @return {booleano}
   * - Verdadero si se admite la pantalla completa.
   * - Falso si no se admite la pantalla completa.
   * /
  admite pantalla completa () {
    if (tipo de this.el_.webkitEnterFullScreen === 'función') {
      const userAgent = ventana.navegador && ventana.navigator.userAgent || '';

      // Parece estar roto en Chromium/Chrome && Safari en leopardo
      if ((/Android/).prueba(agente de usuario) || !(/Chrome|Mac OS X 10.5/).prueba(agente de usuario)) {
        devolver verdadero;
      }
    }
    falso retorno;
  }

  /**
   * Solicitar que el `HTML5` Tech entre en pantalla completa.
   * /
  ingrese a pantalla completa() {
    const video = esto.el_;

    si (video.en pausa && video.networkState < = vídeo.TENER_METADATA) {
      // intenta preparar el elemento de video para el acceso programático
      // esto no es necesario en el escritorio pero no debería doler
      silencioPromise(this.el_.play());

      // reproducir y pausar sincrónicamente durante la transición a pantalla completa
      // puede hacer que los dispositivos iOS ~6.1 entren en un ciclo de reproducción/pausa
      this.setTimeout(función() {
        video.pausa();
        intentar {
          video.webkitEnterFullScreen();
        } catch (e) {
          this.trigger('error de pantalla completa', e);
        }
      }, 0);
    } else {
      intentar {
        video.webkitEnterFullScreen();
      } catch (e) {
        this.trigger('error de pantalla completa', e);
      }
    }
  }

  /**
   * Solicite que `HTML5` Tech salga de la pantalla completa.
   * /
  salir de pantalla completa() {
    if (!this.el_.webkitDisplayingFullscreen) {
      this.trigger('fullscreenerror', new Error('El video no está en pantalla completa'));
      devolver;
    }

    this.el_.webkitExitFullScreen();
  }

  /**
   * Cree una ventana de video flotante siempre encima de otras ventanas para que los usuarios puedan
   * continuar consumiendo medios mientras interactúan con otros sitios de contenido, o
   * aplicaciones en su dispositivo.
   *
   * @ver [Especificación]{@enlace https://wicg.github.io/picture-in-picture}
   *
   * @return {Promesa}
   * Una promesa con una ventana Picture-in-Picture.
   * /
  solicitudImagenEnImagen() {
    devuelve this.el_.requestPictureInPicture();
  }

  /**
   * Solicitud nativa VideoFrameCallback si es compatible con el navegador/tecnología, o respaldo
   * No use rVCF en Safari cuando se está reproduciendo DRM, ya que no se dispara
   * Debe verificarse más tarde que el constructor
   * Esto será un falso positivo para fuentes claras cargadas después de una fuente Fairplay
   *
   * @param {función} cb función para llamar
   * @return {número} id de solicitud
   * /
  solicitudVideoFrameCallback(cb) {
    si (this.featuresVideoFrameCallback && !this.el_.webkitKeys) {
      devolver this.el_.requestVideoFrameCallback(cb);
    }
    volver super.requestVideoFrameCallback(cb);
  }

  /**
   * Solicitud nativa o alternativaVideoFrameCallback
   *
   * @param {number} id ID de solicitud para cancelar
   * /
  cancelarVideoFrameCallback(id) {
    si (this.featuresVideoFrameCallback && !this.el_.webkitKeys) {
      this.el_.cancelVideoFrameCallback(id);
    } else {
      super.cancelVideoFrameCallback(id);
    }
  }

  /**
   * Un getter/setter para el objeto fuente de `Html5` Tech.
   * > Nota: Utilice {@link Html5#setSource}
   *
   * @param {Tecnología~ObjetoOrigen} [src]
   * El objeto de origen que desea establecer en el elemento tecnológico `HTML5`.
   *
   * @return {Tecnología~ObjetoOrigen|indefinido}
   *: el objeto de origen actual cuando no se pasa un origen.
   * - indefinido al configurar
   *
   * @obsoleto Desde la versión 5.
   * /
  origen(origen) {
    si (origen === indefinido) {
      devolver este.el_.src;
    }

    // Establecer src a través de `src` en lugar de `setSrc` será obsoleto
    this.setSrc(src);
  }

  /**
   * Restablezca la tecnología eliminando todas las fuentes y luego llamando
   * {@enlace Html5.resetMediaElement}.
   * /
  reiniciar() {
    Html5.resetMediaElement(this.el_);
  }

  /**
   * Obtenga la fuente actual en `HTML5` Tech. Vuelve a devolver la fuente de
   * el elemento multimedia HTML5.
   *
   * @return {Tecnología~ObjetoOrigen}
   * El objeto fuente actual de la tecnología HTML5. Con un retroceso a la
   * fuente de elementos.
   * /
  fuenteActual() {
    if (this.currentSource_) {
      devuelve this.currentSource_.src;
    }
    devuelve this.el_.currentSrc;
  }

  /**
   * Establecer atributos de controles para el elemento de medios HTML5.
   *
   * @param {cadena} valor
   * Valor para establecer el atributo de controles en
   * /
  establecerControles(valor) {
    this.el_.controles = !!val;
  }

  /**
   * Crea y devuelve un objeto {@link TextTrack} remoto.
   *
   * @param {cadena} tipo
   * Tipo `TextTrack` (subtítulos, leyendas, descripciones, capítulos o metadatos)
   *
   * @param {cadena} [etiqueta]
   * Etiqueta para identificar la pista de texto
   *
   * @param {cadena} [idioma]
   * Abreviatura de idioma de dos letras
   *
   * @return {Pista de texto}
   * El TextTrack que se crea.
   * /
  addTextTrack(tipo, etiqueta, idioma) {
    if (!this.featuresNativeTextTracks) {
      return super.addTextTrack(tipo, etiqueta, idioma);
    }

    return this.el_.addTextTrack(tipo, etiqueta, idioma);
  }

  /**
   * Crea TextTrack nativo o un TextTrack emulado dependiendo
   * sobre el valor de `featuresNativeTextTracks`
   *
   * @param {Objeto} opciones
   * El objeto debe contener las opciones para inicializar TextTrack.
   *
   * @param {cadena} [opciones.tipo]
   * Tipo `TextTrack` (subtítulos, leyendas, descripciones, capítulos o metadatos).
   *
   * @param {cadena} [opciones.etiqueta]
   * Etiqueta para identificar la pista de texto
   *
   * @param {cadena} [opciones.idioma]
   * Abreviatura del idioma de dos letras.
   *
   * @param {booleano} [opciones.predeterminado]
   * Por defecto, esta pista está activada.
   *
   * @param {cadena} [opciones.id]
   * El id interno para asignar esta pista.
   *
   * @param {cadena} [opciones.src]
   * Una URL de origen para la pista.
   *
   * @return {HTMLTrackElement}
   * El elemento de pista que se crea.
   * /
  createRemoteTextTrack(opciones) {
    if (!this.featuresNativeTextTracks) {
      volver super.createRemoteTextTrack(opciones);
    }
    const htmlTrackElement = document.createElement('pista');

    if (opciones.tipo) {
      htmlTrackElement.tipo = opciones.tipo;
    }
    if (opciones.etiqueta) {
      htmlTrackElement.label = opciones.label;
    }
    if (opciones.idioma || opciones.srclang) {
      htmlTrackElement.srclang = opciones.idioma || opciones.srclang;
    }
    if (opciones.predeterminado) {
      htmlTrackElement.default = opciones.default;
    }
    if (opciones.id) {
      htmlTrackElement.id = opciones.id;
    }
    if (opciones.src) {
      htmlTrackElement.src = opciones.src;
    }

    devolver htmlTrackElement;
  }

  /**
   * Crea un objeto de seguimiento de texto remoto y devuelve un elemento de seguimiento html.
   *
   * @param {Objeto} opciones El objeto debe contener valores para
   * tipo, idioma, etiqueta y src (ubicación del archivo WebVTT)
   * @param {boolean} [manualCleanup=true] si se establece en false, TextTrack será
   * eliminado automáticamente del elemento de video cada vez que cambia la fuente
   * @return {HTMLTrackElement} Un elemento de pista Html.
   * Puede ser un {@link HTMLTrackElement} emulado o uno nativo.
   * @deprecated El valor predeterminado del parámetro "manualCleanup" será predeterminado
   * a &quot;falso&quot; en las próximas versiones de Video.js
   * /
  addRemoteTextTrack(opciones, limpiezamanual) {
    const htmlTrackElement = super.addRemoteTextTrack(opciones, limpiezamanual);

    if (this.featuresNativeTextTracks) {
      this.el().appendChild(htmlTrackElement);
    }

    devolver htmlTrackElement;
  }

  /**
   * Eliminar `TextTrack` remoto del objeto `TextTrackList`
   *
   * @param {TextTrack} pista
   * Objeto `TextTrack` para eliminar
   * /
  removeRemoteTextTrack(pista) {
    super.removeRemoteTextTrack(pista);

    if (this.featuresNativeTextTracks) {
      const pistas = esto.$$('pista');

      let i = pistas.longitud;

      mientras yo--) {
        if (pista === pistas[i] || pista === pistas[i].pista) {
          this.el().removeChild(pistas[i]);
        }
      }
    }
  }

  /**
   * Obtiene métricas de calidad de reproducción de medios disponibles según lo especificado por los medios de W3C
   * API de calidad de reproducción.
   *
   * @ver [Especificaciones]{@enlace https://wicg.github.io/media-playback-quality}
   *
   * @return {Objeto}
   * Un objeto con métricas de calidad de reproducción multimedia compatibles
   * /
  getVideoPlaybackQuality() {
    if (tipo de this.el().getVideoPlaybackQuality === 'función') {
      devuelve this.el().getVideoPlaybackQuality();
    }

    const videoPlaybackQuality = {};

    if (tipo de this.el().webkitDroppedFrameCount !== 'indefinido' &&
        typeof this.el().webkitDecodedFrameCount !== 'indefinido') {
      videoPlaybackQuality.droppedVideoFrames = this.el().webkitDroppedFrameCount;
      videoPlaybackQuality.totalVideoFrames = this.el().webkitDecodedFrameCount;
    }

    si (ventana.rendimiento && typeof window.rendimiento.ahora === 'función') {
      videoPlaybackQuality.creationTime = ventana.rendimiento.ahora();
    } más si (ventana.rendimiento &&
               tiempo.de.rendimiento.de.la.ventana &&
               typeof window.performance.timing.navigationStart === 'número') {
      videoPlaybackQuality.creationTime =
        ventana.Fecha.ahora() - ventana.rendimiento.timing.navigationStart;
    }

    devolver calidad de reproducción de video;
  }
}

/* Pruebas de compatibilidad con HTML5 --------------------------------------------- ------- */

/**
 * Elemento para probar las capacidades de medios HTML5 del navegador
 *
 * @tipo {Elemento}
 * @constante
 * @privado
 * /
defineLazyProperty(Html5, 'TEST_VID', function() {
  if (!Dom.isReal()) {
    devolver;
  }
  const video = documento.createElement('video');
  const pista = documento.createElement('pista');

  track.kind = 'subtítulos';
  pista.srclang = 'es';
  track.label = 'Español';
  video.appendChild(pista);

  devolver vídeo;
});

/**
 * Compruebe si los medios HTML5 son compatibles con este navegador/dispositivo.
 *
 * @return {booleano}
 * - Verdadero si se admiten medios HTML5.
 * - Falso si los medios HTML5 no son compatibles.
 * /
Html5.es compatible = función () {
  // ¡IE sin Media Player es un MENTIROSO! (#984)
  intentar {
    Html5.TEST_VID.volumen = 0,5;
  } catch (e) {
    falso retorno;
  }

  volver !!(Html5.TEST_VID && Html5.TEST_VID.canPlayType);
};

/**
 * Verifique si la tecnología puede admitir el tipo dado
 *
 * @param {cadena} tipo
 * El tipo MIME a comprobar
 * @return {cadena} 'probablemente', 'tal vez' o '' (cadena vacía)
 * /
Html5.canPlayType = función (tipo) {
  devuelve Html5.TEST_VID.canPlayType(tipo);
};

/**
 * Verifique si la tecnología puede admitir la fuente dada
 *
 * @param {Objeto} srcObj
 * El objeto fuente
 * @param {Objeto} opciones
 * Las opciones pasan a la tecnología
 * @return {cadena} 'probablemente', 'tal vez' o '' (cadena vacía)
 * /
Html5.canPlaySource = function(srcObj, opciones) {
  devuelve Html5.canPlayType(srcObj.type);
};

/**
 * Compruebe si el volumen se puede cambiar en este navegador/dispositivo.
 * El volumen no se puede cambiar en muchos dispositivos móviles.
 * Específicamente, no se puede cambiar de 1 en iOS.
 *
 * @return {booleano}
 * - Verdadero si se puede controlar el volumen
 * - Falso en caso contrario
 * /
Html5.canControlVolume = function() {
  // IE generará un error si Windows Media Player no está instalado #3315
  intentar {
    volumen constante = Html5.TEST_VID.volume;

    Html5.TEST_VID.volume = (volumen / 2) + 0.1;

    const canControl = volumen !== Html5.TEST_VID.volume;

    // Con la introducción de iOS 15, hay casos en los que el volumen se lee como
    // cambiado pero vuelve a su estado original al comienzo del siguiente tic.
    // Para determinar si el volumen se puede controlar en iOS,
    // se establece un tiempo de espera y el volumen se comprueba de forma asíncrona.
    // Dado que `características` actualmente no funciona de forma asíncrona, el valor se establece manualmente.
    si (puede controlar && navegador.IS_IOS) {
      ventana.setTimeout(() => {
        si (Html5 && Html5.prototipo) {
          Html5.prototype.featuresVolumeControl = volumen !== Html5.TEST_VID.volume;
        }
      });

      // predeterminado iOS a falso, que se actualizará en el tiempo de espera anterior.
      falso retorno;
    }

    volver canControl;
  } catch (e) {
    falso retorno;
  }
};

/**
 * Compruebe si el volumen se puede silenciar en este navegador/dispositivo.
 * Algunos dispositivos, por ejemplo, iOS, no permiten cambiar el volumen
 * pero permite silenciar/dessilenciar.
 *
 * @return {bolean}
 * - Verdadero si el volumen se puede silenciar
 * - Falso en caso contrario
 * /
Html5.canMuteVolume = function() {
  intentar {
    const silenciado = Html5.TEST_VID.muted;

    // en algunas versiones de iOS, la propiedad silenciada no siempre
    // funciona, por lo que queremos establecer tanto la propiedad como el atributo
    Html5.TEST_VID.muted = !silenciado;
    si (Html5.TEST_VID.silenciado) {
      Dom.setAttribute(Html5.TEST_VID, 'silenciado', 'silenciado');
    } else {
      Dom.removeAttribute(Html5.TEST_VID, 'silenciado', 'silenciado');
    }
    volver silenciado !== Html5.TEST_VID.muted;
  } catch (e) {
    falso retorno;
  }
};

/**
 * Compruebe si la velocidad de reproducción se puede cambiar en este navegador/dispositivo.
 *
 * @return {booleano}
 * - Verdadero si se puede controlar la velocidad de reproducción
 * - Falso en caso contrario
 * /
Html5.canControlPlaybackRate = función () {
  // La API de tasa de reproducción está implementada en Android Chrome, pero no hace nada
  // https://github.com/videojs/video.js/issues/3180
  si (navegador.IS_ANDROID && navegador.IS_CHROME && navegador.CHROME_VERSION < 58) {
    falso retorno;
  }
  // IE generará un error si Windows Media Player no está instalado #3315
  intentar {
    const tasa de reproducción = Html5.TEST_VID.tasa de reproducción;

    Html5.TEST_VID.playbackRate = (playbackRate / 2) + 0.1;
    return tasa de reproducción !== Html5.TEST_VID.playbackRate;
  } catch (e) {
    falso retorno;
  }
};

/**
 * Comprobar si podemos anular los atributos de los elementos de vídeo/audio, con
 * Objeto.defineProperty.
 *
 * @return {booleano}
 * - Verdadero si los atributos integrados se pueden anular
 * - Falso en caso contrario
 * /
Html5.canOverrideAttributes = función () {
  // si no podemos sobrescribir la propiedad src/innerHTML, no hay soporte
  // iOS 7 safari, por ejemplo, no puede hacer esto.
  intentar {
    const noop = () => {};

    Object.defineProperty(document.createElement('video'), 'src', {get: noop, set: noop});
    Object.defineProperty(document.createElement('audio'), 'src', {get: noop, set: noop});
    Object.defineProperty(document.createElement('video'), 'innerHTML', {get: noop, set: noop});
    Object.defineProperty(document.createElement('audio'), 'innerHTML', {get: noop, set: noop});
  } catch (e) {
    falso retorno;
  }

  devolver verdadero;
};

/**
 * Compruebe si este navegador/dispositivo admite `TextTrack` nativos.
 *
 * @return {booleano}
 * - Verdadero si se admiten `TextTrack` nativos.
 * - Falso en caso contrario
 * /
Html5.supportsNativeTextTracks = función () {
  regresar navegador.IS_ANY_SAFARI || (navegador.IS_IOS && navegador.IS_CHROME);
};

/**
 * Verifique si este navegador/dispositivo admite 'VideoTrack' nativos
 *
 * @return {booleano}
 * - Verdadero si se admiten `VideoTrack` nativos.
 * - Falso en caso contrario
 * /
Html5.supportsNativeVideoTracks = función () {
  volver !!(Html5.TEST_VID && Html5.TEST_VID.videoTracks);
};

/**
 * Compruebe si este navegador/dispositivo admite `AudioTrack` nativos
 *
 * @return {booleano}
 * - Verdadero si se admiten `AudioTrack` nativos.
 * - Falso en caso contrario
 * /
Html5.supportsNativeAudioTracks = función () {
  volver !!(Html5.TEST_VID && Html5.TEST_VID.audioTracks);
};

/**
 * Una variedad de eventos disponibles en la tecnología Html5.
 *
 * @privado
 * @tipo {Array}
 * /
Html5.Eventos = [
  'inicio de carga',
  'suspender',
  'abortar',
  'error',
  'vaciado',
  'estancado',
  'metadatos cargados',
  'datos cargados',
  'Poder jugar',
  'puede jugar',
  'jugando',
  'espera',
  'buscando',
  'buscado',
  'terminado',
  'cambio de duración',
  'actualización de tiempo',
  'progreso',
  'jugar',
  'pausa',
  'cambio de tasa',
  'redimensionar',
  'cambio de volumen'
];

/**
 * Booleano que indica si `Tech` admite control de volumen.
 *
 * @tipo {booleano}
 * @predeterminado {@enlace Html5.canControlVolume}
 * /
/**
 * Booleano que indica si `Tech` admite volumen de silenciamiento.
 *
 * @tipo {bolean}
 * @predeterminado {@link Html5.canMuteVolume}
 * /

/**
 * Booleano que indica si `Tech` admite cambiar la velocidad a la que los medios
 * obras de teatro. Ejemplos:
 * - Establecer jugador para jugar 2x (dos veces) tan rápido
 * - Configure el jugador para que juegue 0.5x (la mitad) más rápido
 *
 * @tipo {booleano}
 * @predeterminado {@enlace Html5.canControlPlaybackRate}
 * /

/**
 * Booleano que indica si `Tech` admite el evento `sourceset`.
 *
 * @tipo {booleano}
 * @por defecto
 * /
/**
 * Booleano que indica si la tecnología 'HTML5' actualmente es compatible con 'TextTrack' nativos.
 *
 * @tipo {booleano}
 * @predeterminado {@enlace Html5.supportsNativeTextTracks}
 * /
/**
 * Booleano que indica si la tecnología 'HTML5' actualmente es compatible con 'VideoTrack' nativos.
 *
 * @tipo {booleano}
 * @predeterminado {@link Html5.supportsNativeVideoTracks}
 * /
/**
 * Booleano que indica si la tecnología 'HTML5' actualmente es compatible con 'AudioTrack' nativos.
 *
 * @tipo {booleano}
 * @predeterminado {@link Html5.supportsNativeAudioTracks}
 * /
[
  ['featuresMuteControl', 'canMuteVolume'],
  ['featuresPlaybackRate', 'canControlPlaybackRate'],
  ['featuresSourceset', 'canOverrideAttributes'],
  ['featuresNativeTextTracks', 'supportsNativeTextTracks'],
  ['características NativeVideoTracks', 'supportsNativeVideoTracks'],
  ['características de NativeAudioTracks', 'supportsNativeAudioTracks']
].forEach(función([tecla, fn]) {
  defineLazyProperty(Html5.prototipo, clave, () => Html5[fn](), verdadero);
});

Html5.prototype.featuresVolumeControl = Html5.canControlVolume();

/**
 * Booleano que indica si la tecnología `HTML5` admite actualmente el elemento multimedia
 * moverse en el DOM. iOS se interrumpe si mueve el elemento multimedia, por lo que se establece en
 * falso allí. En cualquier otro lugar, esto debería ser cierto.
 *
 * @tipo {booleano}
 * @por defecto
 * /
Html5.prototype.movingMediaElementInDOM = !navegador.IS_IOS;

// HACER: Comentario anterior: Parece que ya no se utiliza. Probablemente se pueda quitar.
// ¿Es esto cierto?
/**
 * Booleano que indica si la tecnología `HTML5` actualmente admite el cambio de tamaño automático de medios
 * al entrar en pantalla completa.
 *
 * @tipo {booleano}
 * @por defecto
 * /
Html5.prototype.featuresFullscreenResize = verdadero;

/**
 * Booleano que indica si la tecnología `HTML5` admite actualmente el evento de progreso.
 * Si esto es falso, en su lugar se activarán eventos manuales de `progreso`.
 *
 * @tipo {booleano}
 * @por defecto
 * /
Html5.prototype.featuresProgressEvents = verdadero;

/**
 * Booleano que indica si la tecnología `HTML5` admite actualmente el evento de actualización de tiempo.
 * Si esto es falso, en su lugar se activarán los eventos manuales `timeupdate`.
 *
 * @por defecto
 * /
Html5.prototype.featuresTimeupdateEvents = verdadero;

/**
 * Si HTML5 el admite `requestVideoFrameCallback`
 *
 * @tipo {booleano}
 * /
Html5.prototype.featuresVideoFrameCallback = !!(Html5.TEST_VID && Html5.TEST_VID.requestVideoFrameCallback);

// Detección de funciones HTML5 y arreglos de dispositivos --------------------------------- //
let canPlayType;

Html5.patchCanPlayType = función () {

  // Android 4.0 y superiores pueden reproducir HLS hasta cierto punto, pero informa que no puede hacerlo
  // Firefox y Chrome informan correctamente
  si (navegador.ANDROID_VERSION > = 4,0 && !navegador.IS_FIREFOX && !navegador.IS_CHROME) {
    canPlayType = Html5.TEST_VID && Html5.TEST_VID.constructor.prototype.canPlayType;
    Html5.TEST_VID.constructor.prototype.canPlayType = función(tipo) {
      const mpegurlRE = /^aplicación\/(?:x-|vnd\.apple\.)mpegurl/i;

      si (tipo && mpegurlRE.prueba(tipo)) {
        volver 'tal vez';
      }
      return canPlayType.call(esto, tipo);
    };
  }
};

Html5.unpatchCanPlayType = función () {
  const r = Html5.TEST_VID.constructor.prototype.canPlayType;

  si (puedePlayType) {
    Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType;
  }
  devolver r;
};

// por defecto, parchear el elemento multimedia
Html5.patchCanPlayType();

Html5.disposeMediaElement = function(el) {
  Me caí) {
    devolver;
  }

  if (el.parentNode) {
    el.parentNode.removeChild(el);
  }

  // elimine cualquier pista secundaria o nodos de origen para evitar que se carguen
  while (el.hasChildNodes()) {
    el.removeChild(el.firstChild);
  }

  // eliminar cualquier referencia src. no establecer `src=''` porque eso provoca una advertencia
  // en Firefox
  el.removeAttribute('origen');

  // fuerza al elemento multimedia a actualizar su estado de carga llamando a load()
  // sin embargo, IE en Windows 7N tiene un error que arroja un error, por lo que necesita probar/atrapar (#793)
  if (typeof el.load === 'función') {
    // envolver en un iife para que no se desoptimice (#1060#discussion_r10324473)
    (función() {
      intentar {
        el.load();
      } catch (e) {
        // No soportado
      }
    }());
  }
};

Html5.resetMediaElement = función (el) {
  Me caí) {
    devolver;
  }

  const fuentes = el.querySelectorAll('fuente');
  let i = fuentes.longitud;

  mientras yo--) {
    el.removeChild(fuentes[i]);
  }

  // eliminar cualquier referencia src.
  // no establecer `src=''` porque arroja un error
  el.removeAttribute('origen');

  if (typeof el.load === 'función') {
    // envolver en un iife para que no se desoptimice (#1060#discussion_r10324473)
    (función() {
      intentar {
        el.load();
      } catch (e) {
        // satisfacer linter
      }
    }());
  }
};

/* Ajuste de propiedad de elemento HTML5 nativo ----------------------------------- */
// Envuelve los atributos booleanos nativos con captadores que comprueban tanto la propiedad como el atributo
// La lista es la siguiente:
// silenciado, silenciado por defecto, reproducción automática, controles, bucle, reproducción en línea
[
  /**
   * Obtenga el valor de `silenciado` del elemento multimedia. `silenciado` indica
   * que el volumen de los medios debe establecerse en silencio. esto en realidad no cambia
   * el atributo `volumen`.
   *
   * @método Html5#silenciado
   * @return {booleano}
   * - Verdadero si el valor de `volume` debe ignorarse y el audio debe establecerse en silencio.
   * - Falso si se debe usar el valor de 'volumen'.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}
   * /
  'apagado',

  /**
   * Obtenga el valor de `defaultMuted` del elemento multimedia. `predeterminado silenciado` indica
   * si los medios deben comenzar silenciados o no. Solo cambia el estado por defecto del
   * medios. `muted` y `defaultMuted` pueden tener valores diferentes. {@link Html5#muted} indica el
   * estado actual.
   *
   * @método Html5#predeterminado silenciado
   * @return {booleano}
   * - El valor de `defaultMuted` del elemento multimedia.
   * - True indica que los medios deben comenzar silenciados.
   * - Falso indica que los medios no deben comenzar silenciados
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted}
   * /
  'predeterminado silenciado',

  /**
   * Obtenga el valor de `reproducción automática` del elemento multimedia. `reproducción automática` indica
   * que los medios deben comenzar a reproducirse tan pronto como la página esté lista.
   *
   * @método Html5#reproducción automática
   * @return {booleano}
   * - El valor de `reproducción automática` del elemento multimedia.
   * - Verdadero indica que los medios deben comenzar tan pronto como se cargue la página.
   * - Falso indica que los medios no deben iniciarse tan pronto como se cargue la página.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}
   * /
  'auto-reproducción',

  /**
   * Obtener el valor de `controls` del elemento multimedia. `controles` indica
   * si los controles de medios nativos deben mostrarse u ocultarse.
   *
   * @método Html5#controles
   * @return {booleano}
   * - El valor de `controles` del elemento multimedia.
   * - True indica que deberían mostrarse los controles nativos.
   * - Falso indica que los controles nativos deben estar ocultos.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls}
   * /
  'control S',

  /**
   * Obtenga el valor de `loop` del elemento multimedia. `bucle` indica
   * que los medios deben volver al inicio de los medios y continuar reproduciendo una vez
   * llega al final.
   *
   * @método Html5#bucle
   * @return {booleano}
   * - El valor de `loop` del elemento multimedia.
   * - Verdadero indica que la reproducción debe buscar hacia atrás para comenzar una vez
   * se alcanza el final de un medio.
   * - Falso indica que la reproducción no debe volver al inicio cuando el
   * se alcanza el final del medio.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}
   * /
  'bucle',

  /**
   * Obtenga el valor de `playsinline` del elemento multimedia. `playsinline` indica
   * al navegador que se prefiere la reproducción que no es a pantalla completa cuando se está a pantalla completa
   * la reproducción es el valor predeterminado nativo, como en iOS Safari.
   *
   * @método Html5#playsinline
   * @return {booleano}
   * - El valor de `playsinline` del elemento multimedia.
   * - True indica que los medios deben reproducirse en línea.
   * - Falso indica que los medios no deben reproducirse en línea.
   *
   * @ver [Especificación]{@enlace https://html.spec.whatwg.org/#attr-video-playsinline}
   * /
  'juega sin línea'
].forEach(función(accesorio) {
  Html5.prototipo[accesorio] = función() {
    devuelve esto.el_[prop] || this.el_.hasAttribute(prop);
  };
});

// Envuelve los atributos booleanos nativos con setters que establecen tanto la propiedad como el atributo
// La lista es la siguiente:
// establecer silenciado, establecer predeterminado silenciado, establecer reproducción automática, establecer bucle, establecer reproducción en línea
// setControls está en mayúsculas y minúsculas arriba
[
  /**
   * Establecer el valor de `silenciado` en el elemento multimedia. `muted` indica que el actual
   * el nivel de audio debe ser silencioso.
   *
   * @método Html5#setMuted
   * @param {booleano} silenciado
   * - Verdadero si el audio debe establecerse en silencio
   * - Falso en caso contrario
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}
   * /
  'apagado',

  /**
   * Establecer el valor de `defaultMuted` en el elemento multimedia. `defaultMuted` indica que el actual
   * el nivel de audio debe estar en silencio, pero solo afectará el nivel silenciado en la reproducción inicial.
   *
   * @método Html5.prototype.setDefaultMuted
   * @param {booleano} por defecto silenciado
   * - Verdadero si el audio debe establecerse en silencio
   * - Falso en caso contrario
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted}
   * /
  'predeterminado silenciado',

  /**
   * Establecer el valor de `reproducción automática` en el elemento multimedia. `reproducción automática` indica
   * que los medios deben comenzar a reproducirse tan pronto como la página esté lista.
   *
   * @método Html5#setReproducción automática
   * @param {booleano} reproducción automática
   * - Verdadero indica que los medios deben comenzar tan pronto como se cargue la página.
   * - Falso indica que los medios no deben iniciarse tan pronto como se cargue la página.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}
   * /
  'auto-reproducción',

  /**
   * Establecer el valor de `loop` en el elemento multimedia. `bucle` indica
   * que los medios deben volver al inicio de los medios y continuar reproduciendo una vez
   * llega al final.
   *
   * @método Html5#setLoop
   * bucle @param {booleano}
   * - Verdadero indica que la reproducción debe buscar hacia atrás para comenzar una vez
   * se alcanza el final de un medio.
   * - Falso indica que la reproducción no debe volver al inicio cuando el
   * se alcanza el final del medio.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}
   * /
  'bucle',

  /**
   * Establecer el valor de `playsinline` desde el elemento multimedia. `playsinline` indica
   * al navegador que se prefiere la reproducción que no es a pantalla completa cuando se está a pantalla completa
   * la reproducción es el valor predeterminado nativo, como en iOS Safari.
   *
   * @método Html5#setPlaysinline
   * @param {boolean} juega en línea
   * - True indica que los medios deben reproducirse en línea.
   * - Falso indica que los medios no deben reproducirse en línea.
   *
   * @ver [Especificación]{@enlace https://html.spec.whatwg.org/#attr-video-playsinline}
   * /
  'juega sin línea'
].forEach(función(accesorio) {
  Html5.prototype['set' + toTitleCase(prop)] = function(v) {
    this.el_[prop] = v;

    si (v) {
      this.el_.setAttribute(prop, prop);
    } else {
      this.el_.removeAttribute(prop);
    }
  };
});

// Envuelve las propiedades nativas con un getter
// La lista es la siguiente
// en pausa, tiempo actual, almacenado en búfer, volumen, póster, precarga, error, búsqueda
// buscable, finalizado, tasa de reproducción, tasa de reproducción predeterminada, desactivar imagen en imagen
// reproducido, networkState, readyState, videoWidth, videoHeight, crossOrigin
[
  /**
   * Obtener el valor de `paused` del elemento multimedia. `paused` indica si el elemento multimedia
   * está actualmente en pausa o no.
   *
   * @método Html5#paused
   * @return {booleano}
   * El valor de `paused` del elemento multimedia.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-paused}
   * /
  'en pausa',

  /**
   * Obtener el valor de `currentTime` del elemento multimedia. `HoraActual` indica
   * el segundo actual en el que se encuentra el medio en reproducción.
   *
   * @método Html5#tiempoactual
   * @return {número}
   * El valor de `currentTime` del elemento multimedia.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-currenttime}
   * /
  'tiempo actual',

  /**
   * Obtener el valor de `buffered` del elemento multimedia. `buffered` es un `TimeRange`
   * objeto que representa las partes de los medios que ya están descargadas y
   * disponible para reproducción.
   *
   * @método Html5#buffered
   * @return {Intervalo de tiempo}
   * El valor de `buffered` del elemento multimedia.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-buffered}
   * /
  'amortiguado',

  /**
   * Obtenga el valor de `volume` del elemento multimedia. 'volumen' indica
   * el volumen de reproducción actual de audio para un medio. `volumen` será un valor de 0
   * (silencio) a 1 (más alto y predeterminado).
   *
   * @método Html5#volumen
   * @return {número}
   * El valor de 'volumen' del elemento multimedia. El valor estará entre 0 y 1.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}
   * /
  'volumen',

  /**
   * Obtener el valor de `poster` del elemento multimedia. `cartel` indica
   * que la URL de un archivo de imagen que puede/se mostrará cuando no haya datos multimedia disponibles.
   *
   * @método Html5#poster
   * @return {cadena}
   * El valor de `poster` del elemento multimedia. El valor será una URL a un
   * imagen.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#attr-video-poster}
   * /
  'póster',

  /**
   * Obtener el valor de `preload` del elemento multimedia. `precarga` indica
   * lo que debe descargarse antes de que se interactúe con los medios. Puede tener lo siguiente
   * valores:
   * - ninguno: no se debe descargar nada
   * - metadatos: el póster y los primeros fotogramas de los medios se pueden descargar para obtener
   * dimensiones de medios y otros metadatos
   * - automático: permite que los medios y los metadatos de los medios se descarguen antes
   * interacción
   *
   * @método Html5#preload
   * @return {cadena}
   * El valor de `preload` del elemento multimedia. Será 'ninguno', 'metadatos',
   * o 'automático'.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
   * /
  'precargar',

  /**
   * Obtener el valor del `error` del elemento multimedia. `error` indica cualquier
   * MediaError que puede haber ocurrido durante la reproducción. Si el error devuelve nulo, no hay
   * error actual.
   *
   * @método Html5#error
   * @return {Error de Medios|null}
   * El valor de `error` del elemento multimedia. Será `MediaError` si hay
   * es un error actual y nulo en caso contrario.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-error}
   * /
  'error',

  /**
   * Obtener el valor de `buscar` del elemento multimedia. `buscando` indica si el
   * los medios de comunicación están actualmente buscando una nueva posición o no.
   *
   * @método Html5#buscando
   * @return {booleano}
   * - El valor de `buscar` del elemento multimedia.
   * - Verdadero indica que el medio está buscando actualmente una nueva posición.
   * - Falso indica que el medio no está buscando una nueva posición en este momento.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seeking}
   * /
  'buscando',

  /**
   * Obtener el valor de `seekable` del elemento multimedia. `buscable` devuelve un
   * Objeto `TimeRange` que indica rangos de tiempo que actualmente se pueden `buscar`.
   *
   * @método Html5#buscable
   * @return {Intervalo de tiempo}
   * El valor de `buscable` del elemento multimedia. Un objeto `TimeRange`
   * indicando los rangos de tiempo actuales que se pueden buscar.
   *
   * @ver [Especificaciones]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seekable}
   * /
  'buscable',

  /**
   * Obtener el valor de `finalizado` del elemento multimedia. `finalizado` indica si
   * el medio ha llegado al final o no.
   *
   * @método Html5#finalizado
   * @return {booleano}
   * - El valor de `finalizado` del elemento multimedia.
   * - True indica que el contenido multimedia ha finalizado.
   * - Falso indica que el medio no ha terminado.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended}
   * /
  'terminado',

  /**
   * Obtenga el valor de `playbackRate` del elemento multimedia. `playbackRate` indica
   * la velocidad a la que se está reproduciendo actualmente el medio. Ejemplos:
   * - si la velocidad de reproducción se establece en 2, los medios se reproducirán el doble de rápido.
   * - si la velocidad de reproducción se establece en 0,5, los medios se reproducirán la mitad de rápido.
   *
   * @método Html5#tasa de reproducción
   * @return {número}
   * El valor de `playbackRate` del elemento multimedia. Un número que indica
   * la velocidad de reproducción actual de los medios, donde 1 es la velocidad normal.
   *
   * @ver [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
   * /
  'tasa de reproducción',

  /**
   * Obtenga el valor de `defaultPlaybackRate` del elemento multimedia. `defaultPlaybackRate` indica
   * la velocidad a la que se está reproduciendo actualmente el medio. Este valor no indicará la corriente
   * `playbackRate` después de que haya comenzado la reproducción, use {@link Html5#playbackRate} para eso.
   *
   * Ejemplos:
   * - si defaultPlaybackRate se establece en 2, los medios se reproducirán el doble de rápido.
   * - si defaultPlaybackRate se establece en 0,5, los medios se reproducirán la mitad de rápido.
   *
   * @método Html5.prototype.defaultPlaybackRate
   * @return {número}
   * El valor de `defaultPlaybackRate` del elemento multimedia. Un número que indica
   * la velocidad de reproducción actual de los medios, donde 1 es la velocidad normal.
   *
   * @ver [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
   * /
  'tasa de reproducción predeterminada',

  /**
   * Obtenga el valor de 'disablePictureInPicture' del elemento de video.
   *
   * @método Html5#disablePictureInPicture
   * valor @return {booleano}
   * - El valor de `disablePictureInPicture` del elemento de video.
   * - True indica que el video no se puede reproducir en modo Picture-In-Picture
   * - Falso indica que el video se puede reproducir en modo Picture-In-Picture
   *
   * @ver [Especificación]{@enlace https://w3c.github.io/picture-in-picture/#disable-pip}
   * /
  'deshabilitar imagen en imagen',

  /**
   * Obtener el valor de `reproducido` del elemento multimedia. `reproducido` devuelve un `TimeRange`
   * objeto que representa puntos en la línea de tiempo multimedia que se han reproducido.
   *
   * @método Html5#jugado
   * @return {Intervalo de tiempo}
   * El valor de `reproducido` del elemento multimedia. Un objeto `TimeRange` que indica
   * los rangos de tiempo que se han jugado.
   *
   * @ver [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-played}
   * /
  'jugó',

  /**
   * Obtenga el valor de `networkState` del elemento multimedia. `networkState` indica
   * el estado actual de la red. Devuelve una enumeración de la siguiente lista:
   * - 0: NETWORK_EMPTY
   * - 1: NETWORK_IDLE
   * - 2: NETWORK_LOADING
   * - 3: NETWORK_NO_SOURCE
   *
   * @método Html5#networkState
   * @return {número}
   * El valor de `networkState` del elemento multimedia. este sera un numero
   * de la lista en la descripción.
   *
   * @ver [Especificación] {@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-networkstate}
   * /
  'estado de la red',

  /**
   * Obtenga el valor de `readyState` del elemento multimedia. `readyState` indica
   * el estado actual del elemento multimedia. Devuelve una enumeración del
   * Lista de seguidores:
   * - 0: NO TIENE NADA
   * - 1: HAVE_METADATA
   * - 2: HAVE_CURRENT_DATA
   * - 3: HAVE_FUTURE_DATA
   * - 4: HAVE_ENOUGH_DATA
   *
   * @método Html5#readyState
   * @return {número}
   * El valor de `readyState` del elemento multimedia. este sera un numero
   * de la lista en la descripción.
   *
   * @ver [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#ready-states}
   * /
  'estado listo',

  /**
   * Obtenga el valor de `videoWidth` del elemento de video. `videoWidth` indica
   * el ancho actual del video en píxeles css.
   *
   * @método Html5#videoWidth
   * @return {número}
   * El valor de `videoWidth` del elemento de video. este sera un numero
   * en píxeles css.
   *
   * @ver [Especificación] {@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}
   * /
  'videoAncho',

  /**
   * Obtenga el valor de `videoHeight` del elemento de video. `videoHeight` indica
   * la altura actual del video en píxeles css.
   *
   * @método Html5#videoHeight
   * @return {número}
   * El valor de `videoHeight` del elemento de video. este sera un numero
   * en píxeles css.
   *
   * @ver [Especificación] {@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}
   * /
  'altura del video',

  /**
   * Obtenga el valor de `crossOrigin` del elemento multimedia. `crossOrigin` indica
   * al navegador que debe enviar las cookies junto con las solicitudes de
   * diferentes recursos/listas de reproducción
   *
   * @método Html5#crossOrigin
   * @return {cadena}
   * - anónimo indica que los medios no deben enviar cookies.
   * - use-credentials indica que los medios deben enviar cookies junto con las solicitudes.
   *
   * @ver [Especificación]{@enlace https://html.spec.whatwg.org/#attr-media-crossorigin}
   * /
  'origen cruzado'
].forEach(función(accesorio) {
  Html5.prototipo[accesorio] = función() {
    devuelve esto.el_[prop];
  };
});

// Envuelva las propiedades nativas con un setter en este formato:
// establecer + toTitleCase(nombre)
// La lista es la siguiente:
// setVolume, setSrc, setPoster, setPreload, setPlaybackRate, setDefaultPlaybackRate,
// establecerDeshabilitarImagenEnImagen, establecerCrossOrigin
[
  /**
   * Establecer el valor de 'volumen' en el elemento multimedia. 'volumen' indica el actual
   * nivel de audio como porcentaje en forma decimal. Esto significa que 1 es 100%, 0.5 es 50% y
   * pronto.
   *
   * @método Html5#setVolume
   * @param {número} porcentaje como decimal
   * El porcentaje de volumen como decimal. El rango válido es de 0 a 1.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}
   * /
  'volumen',

  /**
   * Establecer el valor de `src` en el elemento multimedia. `src` indica el actual
   * {@link Tech~SourceObject} para los medios.
   *
   * @método Html5#setSrc
   * @param {Tech~SourceObject} src
   * El objeto de origen que se establecerá como fuente actual.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-src}
   * /
  'origen',

  /**
   * Establece el valor de `poster` en el elemento multimedia. `poster` es la URL para
   * un archivo de imagen que puede/se mostrará cuando no haya datos multimedia disponibles.
   *
   * @método Html5#setPoster
   * @param {cadena} póster
   * La URL de una imagen que debe usarse como &quot;cartel&quot; para los medios
   * elemento.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-poster}
   * /
  'póster',

  /**
   * Establezca el valor de `precarga` en el elemento multimedia. `precarga` indica
   * lo que debe descargarse antes de que se interactúe con los medios. Puede tener lo siguiente
   * valores:
   * - ninguno: no se debe descargar nada
   * - metadatos: el póster y los primeros fotogramas de los medios se pueden descargar para obtener
   * dimensiones de medios y otros metadatos
   * - automático: permite que los medios y los metadatos de los medios se descarguen antes
   * interacción
   *
   * @método Html5#setPreload
   * @param {cadena} precarga
   * El valor de `preload` para establecer en el elemento multimedia. Debe ser 'ninguno', 'metadatos',
   * o 'automático'.
   *
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
   * /
  'precargar',

  /**
   * Establezca el valor de `playbackRate` en el elemento multimedia. `playbackRate` indica
   * la velocidad a la que deben reproducirse los medios. Ejemplos:
   * - si la velocidad de reproducción se establece en 2, los medios se reproducirán el doble de rápido.
   * - si la velocidad de reproducción se establece en 0,5, los medios se reproducirán la mitad de rápido.
   *
   * @método Html5#setPlaybackRate
   * @return {número}
   * El valor de `playbackRate` del elemento multimedia. Un número que indica
   * la velocidad de reproducción actual de los medios, donde 1 es la velocidad normal.
   *
   * @ver [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
   * /
  'tasa de reproducción',

  /**
   * Establezca el valor de `defaultPlaybackRate` en el elemento multimedia. `defaultPlaybackRate` indica
   * la velocidad a la que los medios deben reproducirse en el inicio inicial. Cambiando este valor
   * después de que un video haya comenzado no hará nada. En su lugar, debe usar {@link Html5#setPlaybackRate}.
   *
   * Valores de ejemplo:
   * - si la velocidad de reproducción se establece en 2, los medios se reproducirán el doble de rápido.
   * - si la velocidad de reproducción se establece en 0,5, los medios se reproducirán la mitad de rápido.
   *
   * @método Html5.prototype.setDefaultPlaybackRate
   * @return {número}
   * El valor de `defaultPlaybackRate` del elemento multimedia. Un número que indica
   * la velocidad de reproducción actual de los medios, donde 1 es la velocidad normal.
   *
   * @ver [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultplaybackrate}
   * /
  'tasa de reproducción predeterminada',

  /**
   * Evita que el navegador sugiera un menú contextual Picture-in-Picture
   * o para solicitar Picture-in-Picture automáticamente en algunos casos.
   *
   * @método Html5#setDisablePictureInPicture
   * valor @param {booleano}
   * El valor real desactivará el modo Picture-in-Picture.
   *
   * @ver [Especificación]{@enlace https://w3c.github.io/picture-in-picture/#disable-pip}
   * /
  'deshabilitar imagen en imagen',

  /**
   * Establece el valor de `crossOrigin` desde el elemento multimedia. `crossOrigin` indica
   * al navegador que debe enviar las cookies junto con las solicitudes de
   * diferentes recursos/listas de reproducción
   *
   * @método Html5#setCrossOrigin
   * @param {cadena} origen cruzado
   * - anónimo indica que los medios no deben enviar cookies.
   * - use-credentials indica que los medios deben enviar cookies junto con las solicitudes.
   *
   * @ver [Especificación]{@enlace https://html.spec.whatwg.org/#attr-media-crossorigin}
   * /
  'origen cruzado'
].forEach(función(accesorio) {
  Html5.prototype['set' + toTitleCase(prop)] = function(v) {
    this.el_[prop] = v;
  };
});

// envuelve funciones nativas con una función
// La lista es la siguiente:
// pausa, carga, reproduce
[
  /**
   * Un envoltorio alrededor de la función de `pausa` de los elementos multimedia. Esto llamará al `HTML5`
   * Función de `pausa` de elementos multimedia.
   *
   * @método Html5#pausa
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-pause}
   * /
  'pausa',

  /**
   * Un envoltorio alrededor de la función `load` de los elementos multimedia. Esto llamará a `HTML5`s
   * Función `load` del elemento multimedia.
   *
   * @método Html5#load
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-load}
   * /
  'carga',

  /**
   * Un envoltorio alrededor de la función `reproducir` de los elementos multimedia. Esto llamará a `HTML5`s
   * Función `reproducir` del elemento multimedia.
   *
   * @método Html5#play
   * @ver [Especificación]{@enlace https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-play}
   * /
  'jugar'
].forEach(función(accesorio) {
  Html5.prototipo[accesorio] = función() {
    devuelve esto.el_[prop]();
  };
});

Tech.withSourceHandlers(Html5);

/**
 * Controlador de fuente nativo para Html5, simplemente pasa la fuente al elemento multimedia.
 *
 * @property {Tech~SourceObject} fuente
 * El objeto fuente
 *
 * @propiedad {Html5} tecnología
 * La instancia de la tecnología HTML5.
 * /
Html5.NativeSourceHandler = {};

/**
 * Compruebe si el elemento multimedia puede reproducir el tipo mimo dado.
 *
 * @param {cadena} tipo
 * El tipo MIME a comprobar
 *
 * @return {cadena}
 * 'probablemente', 'tal vez' o '' (cadena vacía)
 * /
Html5.nativeSourceHandler.canPlayType = función (tipo) {
  // IE sin MediaPlayer arroja un error (#519)
  intentar {
    devuelve Html5.TEST_VID.canPlayType(tipo);
  } catch (e) {
    devolver '';
  }
};

/**
 * Compruebe si el elemento multimedia puede manejar una fuente de forma nativa.
 *
 * @param {Tech~SourceObject} fuente
 * El objeto fuente
 *
 * @param {Objeto} [opciones]
 * Opciones para pasar al técnico.
 *
 * @return {cadena}
 * 'probablemente', 'quizás' o '' (cadena vacía).
 * /
Html5.nativeSourceHandler.canHandleSource = función (fuente, opciones) {

  // Si se proporcionó un tipo, debemos confiar en eso
  if (fuente.tipo) {
    devuelve Html5.nativeSourceHandler.canPlayType(source.type);

  // Si no hay ningún tipo, vuelva a comprobar 'video/[EXTENSIÓN]'
  } más si (fuente.src) {
    const ext = Url.getFileExtension(fuente.src);

    devuelve Html5.nativeSourceHandler.canPlayType(`video/${ext}`);
  }

  devolver '';
};

/**
 * Pase la fuente al elemento multimedia nativo.
 *
 * @param {Tech~SourceObject} fuente
 * El objeto fuente
 *
 * @param {Html5} tecnología
 * La instancia de la tecnología Html5
 *
 * @param {Objeto} [opciones]
 * Las opciones para pasar a la fuente
 * /
Html5.nativeSourceHandler.handleSource = función (fuente, tecnología, opciones) {
  tech.setSrc(fuente.src);
};

/**
 * Un noop para la función de eliminación nativa, ya que no se necesita limpieza.
 * /
Html5.nativeSourceHandler.dispose = function() {};

// Registrar el controlador de origen nativo
Html5.registerSourceHandler(Html5.nativeSourceHandler);

Tecnología.registrarTecnología('Html5', Html5);
exportar Html5 predeterminado;