Tornar um app da Web compatível com Cast

1. Visão geral

Logotipo do Google Cast

Este codelab ensina a modificar um app de vídeo da Web para transmitir conteúdo em um dispositivo com Google Cast.

O que é o Google Cast?

O Google Cast permite que os usuários transmitam conteúdo de um dispositivo móvel para uma TV. O dispositivo poderá ser usado como controle remoto para a reprodução de mídia na TV.

O SDK do Google Cast amplia seu app para controlar uma TV ou um sistema de som. Com ele, é possível adicionar os componentes de IU necessários de acordo com a Lista de verificação de design do Google Cast.

Essa lista é fornecida para facilitar a experiência do usuário do Google Cast e deixá-la mais previsível em todas as plataformas compatíveis.

O que vamos criar?

Ao concluir este codelab, você terá um app de vídeo da Web do Chrome que poderá transmitir conteúdo para um dispositivo com Google Cast.

O que você vai aprender

  • Como adicionar o SDK do Google Cast a um app de vídeo de amostra.
  • Como adicionar o botão "Transmitir" para selecionar um dispositivo com Google Cast.
  • Como se conectar a um dispositivo com Google Cast e iniciar um receptor de mídia.
  • Como transmitir um vídeo.
  • Como integrar a Cast Connect

O que é necessário

  • A versão mais recente do navegador Google Chrome.
  • Serviço de hospedagem HTTPS, como o Firebase Hosting ou o ngrok.
  • Um dispositivo com Google Cast, como um Chromecast ou Android TV, configurado com acesso à Internet.
  • Uma TV ou um monitor com entrada HDMI.
  • O Chromecast com Google TV é necessário para testar a integração do Cast Connect, mas é opcional no restante do codelab. Se você não tiver um, pule a etapa Adicionar suporte ao Google Cast Connect, no final deste tutorial.

Experiência

  • Você precisa ter conhecimento prévio em desenvolvimento para a Web.
  • Também é necessário ter conhecimento prévio de como assistir TV :)

Como você usará este tutorial?

Apenas leitura Leitura e exercícios

Como você classificaria sua experiência com a criação de apps da Web?

Iniciante Intermediário Proficiente

Como você classificaria sua experiência com o ato de assistir TV?

Iniciante Intermediário Proficiente

2. Fazer o download do exemplo de código

Você pode fazer download de todo o exemplo de código para seu computador…

e descompactar o arquivo ZIP salvo.

3. Executar o app de amostra

Logotipo do Google Chrome

Primeiro, vamos ver a aparência do app de amostra concluído. O app é um player de vídeo básico. O usuário pode selecionar um vídeo em uma lista e assisti-lo localmente no dispositivo ou transmiti-lo para um dispositivo com Google Cast.

Para usar o formulário, ele precisa ser hospedado.

Se você não tiver um servidor disponível, use o Firebase Hosting ou o ngrok.

Executar o servidor

Depois de configurar o serviço escolhido, acesse app-done e inicie o servidor.

No navegador, acesse o URL HTTPS do exemplo hospedado.

  1. Você verá o app de vídeo aparecer.
  2. Clique no botão "Transmitir" e selecione o dispositivo com Google Cast.
  3. Selecione um vídeo e clique no botão de reprodução.
  4. O vídeo começará a ser reproduzido no seu dispositivo com Google Cast.

Imagem de um vídeo sendo reproduzido em um dispositivo Google Cast

Clique no botão de pausa no elemento de vídeo para pausar o conteúdo no receptor. Clique no botão de reprodução no elemento de vídeo para continuar a assistir.

Clique no botão "Transmitir" para interromper a transmissão para o dispositivo com Google Cast.

Antes de continuar, pare o servidor.

4. Preparar o projeto inicial

Imagem de um vídeo sendo reproduzido em um dispositivo Google Cast

Precisamos adicionar compatibilidade com o Google Cast ao app inicial que você transferiu por download. Aqui está parte da terminologia do Google Cast que será usada neste codelab:

  • Um app remetente é executado em um dispositivo móvel ou laptop.
  • Um aplicativo receptor é executado no dispositivo com Google Cast.

Agora você já pode criar com base no projeto inicial usando seu editor de texto favorito:

  1. Selecione o diretório ícone da pastaapp-start no download do exemplo de código.
  2. Execute o app usando seu servidor e explore a interface.

Enquanto você trabalha neste codelab, será necessário hospedar o exemplo novamente no seu servidor, dependendo do serviço.

Design do app

O app busca uma lista de vídeos de um servidor da Web remoto e fornece uma lista para o usuário navegar. Os usuários podem selecionar um vídeo para ver os detalhes ou assisti-lo localmente no dispositivo móvel.

O app consiste em uma visualização principal, definida em index.html, e o controle principal, CastVideos.js..

index.html

Esse arquivo HTML declara quase toda a interface do app da Web.

Há algumas seções de visualizações, temos div#main_video, que contém o elemento de vídeo. Com relação à nossa div de vídeo, temos a div#media_control, que define todos os controles do elemento de vídeo. Abaixo dela, está a media_info, que mostra os detalhes do vídeo em exibição. Por fim, a div carousel exibe uma lista de vídeos em uma div.

O arquivo index.html também inicializa o SDK do Cast e instrui o carregamento da função CastVideos.

A maior parte do conteúdo que preencherá esses elementos é definida, injetada e controlada no CastVideos.js. Vamos dar uma olhada nisso.

CastVideos.js

Esse script gerencia toda a lógica para o app da Web do Google Cast. A lista de vídeos e os metadados associados definidos no CastVideos.js estão contidos em um objeto chamado mediaJSON.

Há algumas seções principais que, juntas, são responsáveis por gerenciar e iniciar o vídeo local e remotamente. De modo geral, esse é um app da Web bem simples.

A CastPlayer é a principal classe que gerencia todo o app, a configuração do player, a seleção de mídias e os eventos de vinculação com a PlayerHandler para assistir à mídia. CastPlayer.prototype.initializeCastPlayer é o método que configura toda a funcionalidade de transmissão. CastPlayer.prototype.switchPlayer alterna o estado entre players locais e remotos. O CastPlayer.prototype.setupLocalPlayer e o CastPlayer.prototype.setupRemotePlayer inicializam players de mídia locais e remotos.

PlayerHandler é a classe responsável por gerenciar a reprodução de mídia. Existem vários outros métodos responsáveis pelos detalhes do gerenciamento de mídia e reprodução.

Perguntas frequentes

5. Como adicionar o botão "Transmitir"

Imagem de um app compatível com Cast

Um aplicativo compatível com Cast exibe o botão "Transmitir" no elemento de vídeo. Ao clicar nesse botão, é exibida uma lista de dispositivos de transmissão que o usuário pode selecionar. Se o usuário estava assistindo conteúdo localmente no dispositivo remetente, selecionar um dispositivo de transmissão iniciará ou retomará a reprodução no dispositivo com Google Cast. A qualquer momento durante uma sessão, o usuário pode clicar no botão "Transmitir" e parar a transmissão do seu aplicativo para o dispositivo com Google Cast. O usuário precisa conseguir se conectar ou se desconectar do dispositivo de transmissão enquanto estiver em qualquer tela do app, conforme descrito na Lista de verificação de design do Google Cast.

Configuração

O projeto inicial exige as mesmas dependências e a configuração usadas para o app de exemplo concluído, mas desta vez hospeda o conteúdo de app-start.

No navegador, acesse o URL https da amostra que você hospedou.

Lembre-se de que, ao fazer mudanças, você vai precisar hospedar o exemplo novamente no seu servidor, dependendo do serviço.

Inicialização

O framework do Google Cast tem um objeto Singleton global, o CastContext, que coordena todas as atividades dele. Esse objeto precisa ser inicializado no início do ciclo de vida do aplicativo, normalmente chamado de um callback atribuído a window['__onGCastApiAvailable'], que é chamado depois que o SDK do Cast é carregado e está disponível para uso. Nesse caso, o CastContext é chamado em CastPlayer.prototype.initializeCastPlayer, que é chamado do callback mencionado acima.

Um objeto JSON options precisa ser fornecido ao inicializar o CastContext. Essa classe contém opções que afetam o comportamento do framework. O mais importante deles é o ID do aplicativo receptor, que é usado para filtrar a lista de dispositivos de transmissão disponíveis para mostrar apenas aqueles capazes de executar o app especificado e iniciar o app receptor quando uma sessão de transmissão é iniciada.

Quando você desenvolve seu próprio app compatível com Cast, é preciso se registrar como desenvolvedor do Google Cast e receber um ID para seu app. Para este codelab, usaremos um ID de app de amostra.

Adicione o seguinte código ao index.html no final da seção body:

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

Adicione o seguinte código ao index.html para inicializar o app CastVideos e o CastContext:

<script src="CastVideos.js"></script>
<script type="text/javascript">
var castPlayer = new CastPlayer();
window['__onGCastApiAvailable'] = function(isAvailable) {
  if (isAvailable) {
    castPlayer.initializeCastPlayer();
  }
};
</script>

Agora, é necessário adicionar um novo método no CastVideos.js, que corresponda ao método que acabamos de chamar no index.html. Vamos adicionar um novo método, com o nome initializeCastPlayer, que define opções no CastContext e inicializa novos RemotePlayer e RemotePlayerControllers:

/**
 * This method sets up the CastContext, and a few other members
 * that are necessary to play and control videos on a Cast
 * device.
 */
CastPlayer.prototype.initializeCastPlayer = function() {

    var options = {};

    // Set the receiver application ID to your own (created in
    // the Google Cast Developer Console), or optionally
    // use the chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
    options.receiverApplicationId = 'C0868879';

    // Auto join policy can be one of the following three:
    // ORIGIN_SCOPED - Auto connect from same appId and page origin
    // TAB_AND_ORIGIN_SCOPED - Auto connect from same appId, page origin, and tab
    // PAGE_SCOPED - No auto connect
    options.autoJoinPolicy = chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED;

    cast.framework.CastContext.getInstance().setOptions(options);

    this.remotePlayer = new cast.framework.RemotePlayer();
    this.remotePlayerController = new cast.framework.RemotePlayerController(this.remotePlayer);
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED,
        this.switchPlayer.bind(this)
    );
};

Por fim, precisamos criar as variáveis para RemotePlayer e RemotePlayerController:

var CastPlayer = function() {
  //...
  /* Cast player variables */
  /** @type {cast.framework.RemotePlayer} */
  this.remotePlayer = null;
  /** @type {cast.framework.RemotePlayerController} */
  this.remotePlayerController = null;
  //...
};

Botão "Transmitir"

Agora que o CastContext foi inicializado, precisamos adicionar o botão "Transmitir" para permitir que o usuário selecione um dispositivo com Google Cast. O SDK do Cast oferece um componente do botão Transmitir chamado google-cast-launcher com um ID de castbutton". Ele pode ser adicionado ao elemento de vídeo do app adicionando um button à seção media_control.

O elemento de botão vai ficar assim:

<google-cast-launcher id="castbutton"></google-cast-launcher>

Adicione o seguinte código ao index.html na seção media_control:

<div id="media_control">
  <div id="play"></div>
  <div id="pause"></div>
  <div id="progress_bg"></div>
  <div id="progress"></div>
  <div id="progress_indicator"></div>
  <div id="fullscreen_expand"></div>
  <div id="fullscreen_collapse"></div>
  <google-cast-launcher id="castbutton"></google-cast-launcher>
  <div id="audio_bg"></div>
  <div id="audio_bg_track"></div>
  <div id="audio_indicator"></div>
  <div id="audio_bg_level"></div>
  <div id="audio_on"></div>
  <div id="audio_off"></div>
  <div id="duration">00:00:00</div>
</div>

Agora, atualize a página no navegador Chrome. Você vai encontrar um botão "Transmitir" no elemento de vídeo. Quando clicar nele, os dispositivos de transmissão serão listados na sua rede local. A descoberta de dispositivos é gerenciada automaticamente pelo navegador Chrome. Selecione o dispositivo de transmissão para que o app de amostra receptor seja carregado nele.

Não adicionamos compatibilidade com a reprodução de mídia, então ainda não é possível assistir a vídeos no dispositivo de transmissão. Clique no botão "Transmitir" para interromper a transmissão.

6. Como transmitir conteúdo de vídeo

Imagem de um app compatível com Cast com o menu de seleção de dispositivo de transmissão

Nós ampliaremos o app de amostra para que ele também reproduza vídeos remotamente em um dispositivo com Google Cast. Para isso, precisamos detectar os diversos eventos gerados pelo framework do Google Cast.

Como transmitir mídia

De modo geral, se você quiser reproduzir mídia em um dispositivo de transmissão, precisará fazer o seguinte:

  1. Crie um objeto MediaInfo JSON do SDK do Cast que modele um item de mídia.
  2. O usuário se conecta ao dispositivo de transmissão para iniciar o app receptor.
  3. Carregar o objeto MediaInfo no seu receptor e reproduzir o conteúdo.
  4. Monitorar o status da mídia.
  5. Enviar comandos de reprodução ao receptor com base nas interações do usuário.

A etapa 1 equivale a mapear um objeto para outro. MediaInfo é algo que o SDK do Cast entende, e mediaJSON é o encapsulamento do nosso app para um item de mídia. Podemos facilmente mapear um mediaJSON para um MediaInfo. Já fizemos a etapa 2 na seção anterior. A etapa 3 é fácil de fazer com o SDK do Cast.

A CastPlayer do app de exemplo já distingue entre a reprodução local e remota no método switchPlayer:

if (cast && cast.framework) {
  if (this.remotePlayer.isConnected) {
    //...

Neste codelab, não é importante entender exatamente como toda a lógica do player da amostra funciona. No entanto, é importante entender que o player de mídia do app precisará ser modificado para estar ciente das reproduções locais e remotas.

No momento, o player local está sempre em estado de reprodução local, já que ele ainda não sabe nada sobre os estados de transmissão. Nós precisamos atualizar a IU com base nas transições de estado que ocorrem no framework do Google Cast. Por exemplo, se iniciarmos a transmissão, será necessário parar a reprodução local e desativar alguns controles. Da mesma forma, se pararmos a transmissão quando estivermos nesse controlador de visualização, precisaremos fazer a transição para a reprodução local. Para isso, precisamos detectar os diversos eventos gerados pelo framework do Google Cast.

Gerenciamento da sessão de transmissão

No framework do Google Cast, uma sessão combina as etapas de conexão a um dispositivo, inicialização ou participação em uma sessão existente, conexão com um aplicativo receptor e inicialização de um canal de controle de mídia, se apropriado. O canal de controle de mídia é como o framework do Google Cast envia e recebe mensagens relacionadas à reprodução de mídia do receptor.

A sessão de transmissão será iniciada automaticamente quando o usuário selecionar um dispositivo usando o botão Transmitir e será interrompida quando o usuário se desconectar. A reconexão a uma sessão de receptor devido a problemas na rede também é processada automaticamente pelo framework do Google Cast.

As sessões de transmissão são gerenciadas pelo CastSession, que pode ser acessado via cast.framework.CastContext.getInstance().getCurrentSession(). Os callbacks EventListener podem ser usados para monitorar eventos de sessão, como criação, suspensão, retomada e encerramento.

No nosso aplicativo atual, todo o gerenciamento da sessão e de estado é feito para nós no método setupRemotePlayer. Vamos começar a configurar isso no seu app adicionando o seguinte código ao CastVideos.js:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

Ainda precisamos vincular todos os eventos de callbacks e gerenciar todos os eventos recebidos. Essa é uma tarefa bastante simples, então vamos cuidar disso agora mesmo:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    // Add event listeners for player changes which may occur outside sender app
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_PAUSED_CHANGED,
        function() {
            if (this.remotePlayer.isPaused) {
                this.playerHandler.pause();
            } else {
                this.playerHandler.play();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_MUTED_CHANGED,
        function() {
            if (this.remotePlayer.isMuted) {
                this.playerHandler.mute();
            } else {
                this.playerHandler.unMute();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.VOLUME_LEVEL_CHANGED,
        function() {
            var newVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
            var p = document.getElementById('audio_bg_level');
            p.style.height = newVolume + 'px';
            p.style.marginTop = -newVolume + 'px';
        }.bind(this)
    );

    // This object will implement PlayerHandler callbacks with
    // remotePlayerController, and makes necessary UI updates specific
    // to remote playback
    var playerTarget = {};

    playerTarget.play = function () {
        if (this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }

        var vi = document.getElementById('video_image');
        vi.style.display = 'block';
        var localPlayer = document.getElementById('video_element');
        localPlayer.style.display = 'none';
    }.bind(this);

    playerTarget.pause = function () {
        if (!this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }
    }.bind(this);

    playerTarget.stop = function () {
         this.remotePlayerController.stop();
    }.bind(this);

    playerTarget.getCurrentMediaTime = function() {
        return this.remotePlayer.currentTime;
    }.bind(this);

    playerTarget.getMediaDuration = function() {
        return this.remotePlayer.duration;
    }.bind(this);

    playerTarget.updateDisplayMessage = function () {
        document.getElementById('playerstate').style.display = 'block';
        document.getElementById('playerstatebg').style.display = 'block';
        document.getElementById('video_image_overlay').style.display = 'block';
        document.getElementById('playerstate').innerHTML =
            this.mediaContents[ this.currentMediaIndex]['title'] + ' ' +
            this.playerState + ' on ' + castSession.getCastDevice().friendlyName;
    }.bind(this);

    playerTarget.setVolume = function (volumeSliderPosition) {
        // Add resistance to avoid loud volume
        var currentVolume = this.remotePlayer.volumeLevel;
        var p = document.getElementById('audio_bg_level');
        if (volumeSliderPosition < FULL_VOLUME_HEIGHT) {
            var vScale =  this.currentVolume * FULL_VOLUME_HEIGHT;
            if (volumeSliderPosition > vScale) {
                volumeSliderPosition = vScale + (pos - vScale) / 2;
            }
            p.style.height = volumeSliderPosition + 'px';
            p.style.marginTop = -volumeSliderPosition + 'px';
            currentVolume = volumeSliderPosition / FULL_VOLUME_HEIGHT;
        } else {
            currentVolume = 1;
        }
        this.remotePlayer.volumeLevel = currentVolume;
        this.remotePlayerController.setVolumeLevel();
    }.bind(this);

    playerTarget.mute = function () {
        if (!this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.unMute = function () {
        if (this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.isMuted = function() {
        return this.remotePlayer.isMuted;
    }.bind(this);

    playerTarget.seekTo = function (time) {
        this.remotePlayer.currentTime = time;
        this.remotePlayerController.seek();
    }.bind(this);

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

Como carregar mídia

No SDK do Cast, RemotePlayer e RemotePlayerController fornecem um conjunto de APIs convenientes para gerenciar a reprodução de mídia remota no receptor. Para uma CastSession compatível com a reprodução de mídia, instâncias da RemotePlayer e da RemotePlayerController serão criadas automaticamente pelo SDK. Eles podem ser acessados criando instâncias de cast.framework.RemotePlayer e cast.framework.RemotePlayerController, respectivamente, conforme mostrado anteriormente no codelab.

Em seguida, precisamos carregar o vídeo selecionado no momento no receptor criando um objeto MediaInfo para que o SDK processe e transmita a solicitação. Adicione o seguinte código a setupRemotePlayer para fazer isso:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    //...

    playerTarget.load = function (mediaIndex) {
        console.log('Loading...' + this.mediaContents[mediaIndex]['title']);
        var mediaInfo = new chrome.cast.media.MediaInfo(
            this.mediaContents[mediaIndex]['sources'][0], 'video/mp4');

        mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
        mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
        mediaInfo.metadata.title = this.mediaContents[mediaIndex]['title'];
        mediaInfo.metadata.images = [
            {'url': MEDIA_SOURCE_ROOT + this.mediaContents[mediaIndex]['thumb']}];

        var request = new chrome.cast.media.LoadRequest(mediaInfo);
        castSession.loadMedia(request).then(
            this.playerHandler.loaded.bind(this.playerHandler),
            function (errorCode) {
                this.playerState = PLAYER_STATE.ERROR;
                console.log('Remote media load error: ' +
                    CastPlayer.getErrorMessage(errorCode));
            }.bind(this));
    }.bind(this);

    //...
};

Agora, adicione um método para alternar entre reprodução local e remota:

/**
 * This is a method for switching between the local and remote
 * players. If the local player is selected, setupLocalPlayer()
 * is run. If there is a cast device connected we run
 * setupRemotePlayer().
 */
CastPlayer.prototype.switchPlayer = function() {
    this.stopProgressTimer();
    this.resetVolumeSlider();
    this.playerHandler.stop();
    this.playerState = PLAYER_STATE.IDLE;
    if (cast && cast.framework) {
        if (this.remotePlayer.isConnected) {
            this.setupRemotePlayer();
            return;
        }
    }
    this.setupLocalPlayer();
};

Por fim, adicione um método para processar mensagens de erro de transmissão:

/**
 * Makes human-readable message from chrome.cast.Error
 * @param {chrome.cast.Error} error
 * @return {string} error message
 */
CastPlayer.getErrorMessage = function(error) {
  switch (error.code) {
    case chrome.cast.ErrorCode.API_NOT_INITIALIZED:
      return 'The API is not initialized.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CANCEL:
      return 'The operation was canceled by the user' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CHANNEL_ERROR:
      return 'A channel to the receiver is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.EXTENSION_MISSING:
      return 'The Cast extension is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.INVALID_PARAMETER:
      return 'The parameters to the operation were not valid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.RECEIVER_UNAVAILABLE:
      return 'No receiver was compatible with the session request.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.SESSION_ERROR:
      return 'A session could not be created, or a session was invalid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.TIMEOUT:
      return 'The operation timed out.' +
        (error.description ? ' :' + error.description : '');
  }
};

Agora, execute o app. Conecte o dispositivo de transmissão e comece a assistir a um vídeo. Você verá o vídeo sendo reproduzido no receptor.

7. Adicionar suporte ao Cast Connect

A biblioteca Cast Connect permite que os aplicativos de envio se comuniquem com os aplicativos Android TV pelo protocolo do Cast. O Cast Connect é baseado na infraestrutura do Cast, com seu app Android TV atuando como receptor.

Dependências

  • Navegador Chrome versão M87 ou mais recente

Definir compatibilidade com o receptor Android

Para iniciar o aplicativo Android TV, também chamado de receptor do Android, é necessário definir a flag androidReceiverCompatible como true no objeto CastOptions.

Adicione o seguinte código ao CastVideos.js na função initializeCastPlayer:

var options = {};
...
options.androidReceiverCompatible = true;

cast.framework.CastContext.getInstance().setOptions(options);

Definir credenciais de inicialização

No lado do remetente, é possível especificar CredentialsData para representar quem está participando da sessão. O credentials é uma string que pode ser definida pelo usuário, desde que o app ATV a entenda. O CredentialsData só é transmitido para o app Android TV durante a inicialização ou a participação. Se você definir novamente enquanto estiver conectado, ele não será transmitido para o app Android TV.

Para definir as credenciais de inicialização, CredentialsData precisa ser definido a qualquer momento após a definição das opções de inicialização.

Adicione o seguinte código à classe CastVideos.js na função initializeCastPlayer:

cast.framework.CastContext.getInstance().setOptions(options);
...
let credentialsData = new chrome.cast.CredentialsData("{\"userId\": \"abc\"}");
cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);
...

Definir credenciais na solicitação de carregamento

Caso o app do receptor da Web e o app do Android TV processem o credentials de maneira diferente, talvez seja necessário definir credenciais separadas para cada um. Para fazer isso, adicione o seguinte código à função CastVideos.js em playerTarget.load na função setupRemotePlayer:

...
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.credentials = 'user-credentials';
request.atvCredentials = 'atv-user-credentials';
...

Dependendo do app receptor para o qual o remetente está transmitindo, o SDK agora processa automaticamente quais credenciais usar para a sessão atual.

Como testar o Cast Connect

Etapas para instalar o APK do Android TV no Chromecast com Google TV:

  1. Encontre o endereço IP do dispositivo Android TV. Normalmente, ela está disponível em Configurações > Rede e Internet > (Nome da rede à qual o dispositivo está conectado). À direita, serão mostrados os detalhes e o IP do dispositivo na rede.
  2. Use o endereço IP do dispositivo para se conectar a ele pelo ADB usando o terminal:
$ adb connect <device_ip_address>:5555
  1. Na janela do terminal, navegue até a pasta de nível superior dos exemplos de codelab que você fez o download no início deste codelab. Exemplo:
$ cd Desktop/chrome_codelab_src
  1. Para instalar o arquivo .apk dessa pasta no Android TV, execute o seguinte:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. Agora você vai encontrar um app chamado Cast Videos no menu Seus apps no dispositivo Android TV.
  2. Execute o código atualizado do remetente da Web e estabeleça uma sessão de transmissão com o dispositivo Android TV usando o ícone de transmissão ou selecionando Cast.. no menu suspenso do navegador Chrome. Isso vai iniciar o app Android TV no seu Android Receiver e permitir que você controle a reprodução usando o controle remoto do Android TV.

8. Parabéns

Agora você já sabe como adicionar compatibilidade com o Google Cast a um app de vídeo usando os widgets do SDK do Cast em um app da Web do Chrome.

Para mais detalhes, consulte o guia do desenvolvedor do Web Sender.