Felipe Cesar

    Como criar um player HLS do zero (Parte 1)

    Neste artigo, vamos dar inicio a uma série onde iremos construir um player de vídeo inspirado na biblioteca hls.js. Começaremos explorando conceitos fundamentais, como a arquitetura orientada a eventos, enquanto implementamos as primeiras funcionalidades.

    O que é HLS?

    HLS (HTTP Live Streaming) é um protocolo de streaming criado pela Apple. Ele divide vídeos em pequenos pedaços (chunks) e os organiza em um arquivo de texto chamado manifesto ou playlist (formato .m3u8). Isso garante uma reprodução eficiente e adaptativa, perfeita para transmissões ao vivo e vídeos sob demanda.

    Arquitetura Orientada a Eventos

    A arquitetura orientada a eventos organiza a comunicação do sistema por meio de mensagens (eventos). Componentes não interagem diretamente; eles emitem e ouvem eventos gerenciados por um intermediário, como um EventBus.

    Criando a classe Hls

    Nossa classe principal será chamada de Hls, onde centralizaremos a comunicação por eventos. Para isso, usaremos a biblioteca eventemitter3.

    import { EventEmitter } from 'eventemitter3'
    
    export default class Hls {
      _emitter = new EventEmitter();
      
      on(event, listener, context) {
        this._emitter.on(event, listener, context);
      }
      
      trigger(event, eventObject) {
        return this._emitter.emit(event, event, eventObject);
      }
    }

    Carregando a Playlist

    Adicionaremos o método loadSource para iniciar o carregamento da playlist e emitir um evento correspondente.

    class Hls {
      // ...
    
      loadSource(url) {
        this.trigger('hlsManifestLoading', { url });
      }
    }

    Criando a classe PlaylistLoader

    Agora, criaremos uma classe dedicada ao carregamento do manifesto, chamada PlaylistLoader.

    export default class PlaylistLoader {
      constructor(hls) {
        this.hls = hls;
        this.registerListeners();
      }
    
      registerListeners() {
        this.hls.on('hlsManifestLoading', this.onManifestLoading, this);
      }
    
      onManifestLoading(event, data) {
        const { url } = data;
        fetch(url)
          .then(response => response.text())
          .then(text => console.log(text));
      }
    }

    Essa classe recebe uma instância de Hls que permite que ela escute e emita eventos.

    export default class Hls {
      _emitter = new EventEmitter()
    
      constructor() {
        new PlaylistLoader(this)
      }
      
      // ...
    }

    Utilizando constantes para eventos

    Para evitar erros ao nomear eventos, criaremos um arquivo events.js com constantes:

    export const Events = {
      MANIFEST_LOADING: 'hlsManifestLoading',
    }

    Use as constantes no código:

    import { Events } from './events';
    
    export default class PlaylistLoader {
      // ...
    
      registerListeners() {
        this.hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
      }
    }

    Por que usar a arquitetura orientada a eventos?

    • Reutilização: Novos módulos podem ouvir eventos existentes, reduzindo a duplicação de código.
    • Flexibilidade: Alterações em um componente não afetam os demais.
    • Reatividade: Ideal para aplicações dinâmicas, como players de vídeo.

    Embora essa arquitetura ofereça diversas vantagens, também apresenta algumas limitações:

    • Dificuldade no debug: Rastrear eventos pode ser desafiador.
    • Sobrecarga: Eventos desnecessários podem consumir recursos.

    Conclusão

    Essa foi apenas a primeira etapa do projeto. Nos próximos artigos, evoluiremos o player até ele reproduzir vídeos. Acompanhe o repositório no GitHub para mais atualizações!

    Gostou? Deixe seu feedback ou compartilhe este post com outros desenvolvedores interessados em aprender mais sobre HLS.