Integrar o SDK do Cast ao app de transmissão da Web

Este guia do desenvolvedor descreve como adicionar compatibilidade com o Google Cast ao seu app Web Sender usando o SDK do Cast.

Terminologia

O dispositivo móvel ou navegador é o remetente, que controla a reprodução. O dispositivo com Google Cast é o receptor, que exibe o conteúdo na tela para reprodução.

O SDK do Web Sender consiste em duas partes: a API Framework (cast.framework) e a API Base (chrome.cast). Em geral, você faz chamadas na API Framework mais simples e de nível superior, que são processadas pela API Base de nível inferior.

O framework do remetente se refere à API do framework, ao módulo e aos recursos associados que fornecem um wrapper para a funcionalidade de nível inferior. O app remetente ou o app Google Cast para Chrome refere-se a um app da Web (HTML/JavaScript) executado no navegador Chrome em um dispositivo remetente. Um app receptor da Web refere-se a um app HTML/JavaScript executado no Chromecast ou em um dispositivo com Google Cast.

O framework do remetente usa um design de callback assíncrono para informar eventos ao app remetente e fazer a transição entre vários estados do ciclo de vida do app Google Cast.

Carregar a biblioteca

Para que seu app implemente os recursos do Google Cast, ele precisa saber o local do SDK do Web Sender para Google Cast, conforme mostrado abaixo. Adicione o parâmetro de consulta de URL loadCastFramework para carregar também a API Web Sender Framework. Todas as páginas do app precisam se referir à biblioteca da seguinte maneira:

<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>

Framework

O SDK do remetente da Web usa o namespace cast.framework.*. O namespace representa o seguinte:

  • Métodos ou funções que invocam operações na API
  • Listeners de eventos para funções de listener na API

O framework consiste nestes componentes principais:

  • O CastContext é um objeto singleton que fornece informações sobre o estado atual do Google Cast e aciona eventos para fazer as mudanças no estado da transmissão e da sessão de transmissão.
  • O objeto CastSession gerencia a sessão. Ele fornece informações de estado e aciona eventos, como mudanças no volume do dispositivo, estado de silenciamento e metadados do app.
  • O elemento do botão Transmitir, que é um elemento personalizado HTML simples, que estende o botão HTML. Se o botão Transmitir fornecido não for suficiente, use o estado Transmitir para implementá-lo.
  • O RemotePlayerController fornece a vinculação de dados para simplificar a implementação do player remoto.

Leia a Referência da API Google Cast Web Sender para uma descrição completa do namespace.

Botão "Transmitir"

O componente do botão Transmitir no app é processado inteiramente pelo framework. Isso inclui o gerenciamento de visibilidade e o gerenciamento de eventos de clique.

<google-cast-launcher></google-cast-launcher>

Como alternativa, você pode criar o botão de forma programática:

document.createElement("google-cast-launcher");

Você pode aplicar qualquer outro estilo ao elemento, como tamanho ou posicionamento, conforme necessário. Use o atributo --connected-color para escolher a cor para o estado do receptor da Web conectado e --disconnected-color para o estado desconectado.

Inicialização

Depois de carregar a API do framework, o app chamará o gerenciador window.__onGCastApiAvailable. Verifique se o app define esse gerenciador no window antes de carregar a biblioteca do remetente.

Nesse gerenciador, você inicializa a interação do Google Cast chamando o método setOptions(options) de CastContext.

Exemplo:

<script>
window['__onGCastApiAvailable'] = function(isAvailable) {
  if (isAvailable) {
    initializeCastApi();
  }
};
</script>

Em seguida, inicialize a API da seguinte maneira:

initializeCastApi = function() {
  cast.framework.CastContext.getInstance().setOptions({
    receiverApplicationId: applicationId,
    autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
  });
};

Primeiro, o app recupera a instância singleton do objeto CastContext fornecido pelo framework. Em seguida, ele usa setOptions(options) com um objeto CastOptions para definir o applicationID.

Se você estiver usando o receptor de mídia padrão, que não requer registro, use uma constante predefinida pelo SDK do remetente da Web, conforme mostrado abaixo, em vez de applicationID:

cast.framework.CastContext.getInstance().setOptions({
  receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
});

Controle de mídia

Depois que o CastContext for inicializado, o app poderá extrair a CastSession atual a qualquer momento usando getCurrentSession().

var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

O CastSession pode ser usado para carregar mídia ao dispositivo de transmissão conectado usando loadMedia(loadRequest). Primeiro, crie um MediaInfo, usando o contentId e o contentType, além de qualquer outra informação relacionada ao conteúdo. Em seguida, crie um LoadRequest com base nele, definindo todas as informações relevantes para a solicitação. Por fim, chame loadMedia(loadRequest) no CastSession.

var mediaInfo = new chrome.cast.media.MediaInfo(currentMediaURL, contentType);
var request = new chrome.cast.media.LoadRequest(mediaInfo);
castSession.loadMedia(request).then(
  function() { console.log('Load succeed'); },
  function(errorCode) { console.log('Error code: ' + errorCode); });

O método loadMedia retornará uma promessa que pode ser usada para executar qualquer operação necessária para um resultado bem-sucedido. Se a promessa for rejeitada, o argumento da função será um chrome.cast.ErrorCode.

É possível acessar as variáveis de estado do player em RemotePlayer. Todas as interações com o RemotePlayer, incluindo callbacks e comandos de eventos de mídia, são processadas com o RemotePlayerController.

var player = new cast.framework.RemotePlayer();
var playerController = new cast.framework.RemotePlayerController(player);

O RemotePlayerController dá ao app controle total de mídia para REPRODUZIR, PAUSAR, STOP e PROCURAR para a mídia carregada.

  • REPRODUZIR/PAUSAR: playerController.playOrPause();
  • PARAR: playerController.stop();
  • PROCURAR: playerController.seek();

RemotePlayer e RemotePlayerController podem ser usados com frameworks de vinculação de dados, como Polymer ou Angular, para implementar um player remoto.

Este é um snippet de código para o Angular:

<button id="playPauseButton" class="playerButton"
  ng-disabled="!player.canPause"
  ng-click="controller.playOrPause()">
    {{player.isPaused ? 'Play' : 'Pause'}}
</button>
<script>
var player = new cast.framework.RemotePlayer();
var controller = new cast.framework.RemotePlayerController(player);
// Listen to any player update, and trigger angular data binding
update.controller.addEventListener(
  cast.framework.RemotePlayerEventType.ANY_CHANGE,
  function(event) {
    if (!$scope.$$phase) $scope.$apply();
  });
</script>

Status da mídia

Durante a reprodução de mídia, ocorrem vários eventos que podem ser capturados definindo listeners para vários eventos cast.framework.RemotePlayerEventType no objeto RemotePlayerController.

Para conferir as informações de status da mídia, use o evento cast.framework.RemotePlayerEventType.MEDIA_INFO_CHANGED, que é acionado quando a reprodução e o CastSession.getMediaSession().media mudam.

playerController.addEventListener(
  cast.framework.RemotePlayerEventType.MEDIA_INFO_CHANGED, function() {
    // Use the current session to get an up to date media status.
    let session = cast.framework.CastContext.getInstance().getCurrentSession();

    if (!session) {
        return;
    }

    // Contains information about the playing media including currentTime.
    let mediaStatus = session.getMediaSession();
    if (!mediaStatus) {
        return;
    }

    // mediaStatus also contains the mediaInfo containing metadata and other
    // information about the in progress content.
    let mediaInfo = mediaStatus.media;
  });

Quando eventos como pausa, reprodução, retomada ou busca ocorrerem, o app precisará agir sobre eles e sincronizar entre si e o app receptor da Web no dispositivo de transmissão. Consulte Atualizações de status para mais informações.

Como funciona o gerenciamento de sessões

O SDK do Cast apresenta o conceito de uma sessão do Google Cast. Esse estabelecimento combina as etapas de conexão a um dispositivo, inicialização (ou associação) de um app receptor da Web, conexão a esse app e inicialização de um canal de controle de mídia. Consulte o Guia do ciclo de vida do aplicativo para mais informações sobre as sessões do Google Cast e o ciclo de vida do receptor da Web.

As sessões são gerenciadas pela classe CastContext, que seu app pode recuperar via cast.framework.CastContext.getInstance(). Sessões individuais são representadas por subclasses da classe Session. Por exemplo, CastSession representa sessões com dispositivos de transmissão. Seu app pode acessar a sessão do Google Cast ativa no momento via CastContext.getCurrentSession().

Para monitorar o estado da sessão, adicione um listener ao CastContext para o tipo de evento CastContextEventType.SESSION_STATE_CHANGED.

var context = cast.framework.CastContext.getInstance();
context.addEventListener(
  cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
  function(event) {
    switch (event.sessionState) {
      case cast.framework.SessionState.SESSION_STARTED:
      case cast.framework.SessionState.SESSION_RESUMED:
        break;
      case cast.framework.SessionState.SESSION_ENDED:
        console.log('CastContext: CastSession disconnected');
        // Update locally as necessary
        break;
    }
  })

Para desconexão, como quando o usuário clica no botão "Parar transmissão" na caixa de diálogo "Transmitir", adicione um listener para o tipo de evento RemotePlayerEventType.IS_CONNECTED_CHANGED no seu listener. No listener, verifique se RemotePlayer está desconectado. Se for o caso, atualize o estado do player local conforme necessário. Exemplo:

playerController.addEventListener(
  cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED, function() {
    if (!player.isConnected) {
      console.log('RemotePlayerController: Player disconnected');
      // Update local player to disconnected state
    }
  });

Embora o usuário possa controlar diretamente o encerramento da transmissão usando o botão "Transmitir" do framework, o próprio remetente pode interromper a transmissão usando o objeto CastSession atual.

function stopCasting() {
  var castSession = cast.framework.CastContext.getInstance().getCurrentSession();
  // End the session and pass 'true' to indicate
  // that Web Receiver app should be stopped.
  castSession.endSession(true);
}

Transferência de stream

A preservação do estado da sessão é a base da transferência de stream, em que os usuários podem mover os streams de áudio e vídeo existentes entre dispositivos usando comandos de voz, o app Google Home ou smart displays. A mídia é interrompida em um dispositivo (a origem) e continua em outro (o destino). Qualquer dispositivo de transmissão com o firmware mais recente pode servir como origens ou destinos em uma transferência por stream.

Para acessar o novo dispositivo de destino durante a transferência de stream, chame CastSession#getCastDevice() quando o evento cast.framework.SessionState.SESSION_RESUMED for chamado.

Consulte Transferência de stream no receptor da Web para mais informações.