Adicionar recursos principais ao receptor da Web personalizado

Esta página contém snippets de código e descrições dos recursos disponíveis para um app Custom Web Receiver.

  1. Um elemento cast-media-player que representa a interface do jogador integrada fornecida com o Web Receiver.
  2. Estilo personalizado semelhante ao CSS para o elemento cast-media-player, que estiliza vários elementos da interface, como background-image, splash-image e font-family.
  3. Um elemento de script para carregar o framework Web Receiver.
  4. Código JavaScript para interceptar mensagens e processar eventos.
  5. Adicionar à fila para reprodução automática.
  6. Opções para configurar a reprodução.
  7. Opções para definir o contexto do Web Receiver.
  8. Opções para definir comandos compatíveis com o app Web Receiver.
  9. Uma chamada JavaScript para iniciar o aplicativo Web Receiver.

Configuração e opções do aplicativo

Configurar o aplicativo

O CastReceiverContext é a classe mais externa exposta ao desenvolvedor. Ela gerencia o carregamento de bibliotecas subjacentes e processa a inicialização do SDK do Web Receiver. O SDK fornece APIs que permitem que os desenvolvedores de aplicativos configurem o SDK usando CastReceiverOptions. Essas configurações são avaliadas uma vez por inicialização do aplicativo e transmitidas ao SDK ao definir o parâmetro opcional na chamada para start.

O exemplo abaixo mostra como substituir o comportamento padrão para detectar se uma conexão do remetente ainda está ativa. Quando o Web Receiver não consegue se comunicar com um remetente por maxInactivity segundos, um evento SENDER_DISCONNECTED é enviado. A configuração abaixo substitui esse tempo limite. Isso pode ser útil ao depurar problemas, porque impede que o app Web Receiver feche a sessão do depurador remoto do Chrome quando não há remetentes conectados em um estado IDLE.

const context = cast.framework.CastReceiverContext.getInstance();
const options = new cast.framework.CastReceiverOptions();
options.maxInactivity = 3600; // Development only
context.start(options);

Configurar o player

Ao carregar conteúdo, o SDK Web Receiver oferece uma maneira de configurar variáveis de reprodução, como informações de DRM, configurações de nova tentativa e manipuladores de solicitações usando cast.framework.PlaybackConfig. Essas informações são processadas por PlayerManager e avaliadas no momento em que os jogadores são criados. Os players são criados sempre que uma nova carga é transmitida ao SDK Web Receiver. As modificações feitas no PlaybackConfig depois que o player é criado são avaliadas no próximo carregamento de conteúdo. O SDK oferece os seguintes métodos para modificar o PlaybackConfig.

  • CastReceiverOptions.playbackConfig para substituir as opções de configuração padrão ao inicializar o CastReceiverContext.
  • PlayerManager.getPlaybackConfig() para receber a configuração atual.
  • PlayerManager.setPlaybackConfig() para substituir a configuração atual. Essa configuração é aplicada a todos os carregamentos subsequentes ou até que seja substituída novamente.
  • PlayerManager.setMediaPlaybackInfoHandler() para aplicar configurações extras apenas ao item de mídia que está sendo carregado além das configurações atuais. O manipulador é chamado pouco antes da criação do player. As mudanças feitas aqui não são permanentes e não são incluídas em consultas para getPlaybackConfig(). Quando o próximo item de mídia é carregado, esse manipulador é chamado novamente.

O exemplo abaixo mostra como definir o PlaybackConfig ao inicializar o CastReceiverContext. A configuração substitui as solicitações de saída para obter manifestos. O manipulador especifica que as solicitações de controle de acesso do CORS devem ser feitas usando credenciais, como cookies ou cabeçalhos de autorização.

const playbackConfig = new cast.framework.PlaybackConfig();
playbackConfig.manifestRequestHandler = requestInfo => {
  requestInfo.withCredentials = true;
};
context.start({playbackConfig: playbackConfig});

O exemplo abaixo mostra como substituir o PlaybackConfig usando o getter e o setter fornecidos em PlayerManager. A configuração configura o player para retomar a reprodução de conteúdo depois que um segmento for carregado.

const playerManager =
    cast.framework.CastReceiverContext.getInstance().getPlayerManager();
const playbackConfig = (Object.assign(
            new cast.framework.PlaybackConfig(), playerManager.getPlaybackConfig()));
playbackConfig.autoResumeNumberOfSegments = 1;
playerManager.setPlaybackConfig(playbackConfig);

O exemplo abaixo mostra como substituir o PlaybackConfig para uma solicitação de carregamento específica usando o gerenciador de informações de reprodução de mídia. O gerenciador chama um método getLicenseUrlForMedia implementado pelo aplicativo para receber o licenseUrl do contentId do item atual.

playerManager.setMediaPlaybackInfoHandler((loadRequestData, playbackConfig) => {
  const mediaInformation = loadRequestData.media;
  playbackConfig.licenseUrl = getLicenseUrlForMedia(mediaInformation.contentId);

  return playbackConfig;
});

Listener de eventos

O SDK Web Receiver permite que o app Web Receiver processe eventos do player. O listener de eventos usa um parâmetro cast.framework.events.EventType (ou uma matriz desses parâmetros) que especifica os eventos que devem acionar o listener. Matrizes pré-configuradas de cast.framework.events.EventType úteis para depuração podem ser encontradas em cast.framework.events.category. O parâmetro de evento fornece mais informações sobre o evento.

Por exemplo, se você quiser saber quando uma mudança de mediaStatus está sendo transmitida, use a seguinte lógica para processar o evento:

const playerManager =
    cast.framework.CastReceiverContext.getInstance().getPlayerManager();
playerManager.addEventListener(
    cast.framework.events.EventType.MEDIA_STATUS, (event) => {
      // Write your own event handling code, for example
      // using the event.mediaStatus value
});

Interceptação de mensagens

O SDK Web Receiver permite que seu app Web Receiver intercepte mensagens e execute código personalizado nelas. O interceptador de mensagens usa um parâmetro cast.framework.messages.MessageType que especifica o tipo de mensagem a ser interceptada.

O interceptador precisa retornar a solicitação modificada ou uma promessa que seja resolvida com o valor da solicitação modificada. Retornar null impede a chamada do gerenciador de mensagens padrão. Consulte Como carregar mídia para mais detalhes.

Por exemplo, se você quiser mudar os dados da solicitação de carregamento, use a lógica a seguir para interceptar e modificar:

const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      const error = new cast.framework.messages.ErrorData(
                      cast.framework.messages.ErrorType.LOAD_FAILED);
      if (!loadRequestData.media) {
        error.reason = cast.framework.messages.ErrorReason.INVALID_PARAM;
        return error;
      }

      if (!loadRequestData.media.entity) {
        return loadRequestData;
      }

      return thirdparty.fetchAssetAndAuth(loadRequestData.media.entity,
                                          loadRequestData.credentials)
        .then(asset => {
          if (!asset) {
            throw cast.framework.messages.ErrorReason.INVALID_REQUEST;
          }

          loadRequestData.media.contentUrl = asset.url;
          loadRequestData.media.metadata = asset.metadata;
          loadRequestData.media.tracks = asset.tracks;
          return loadRequestData;
        }).catch(reason => {
          error.reason = reason; // cast.framework.messages.ErrorReason
          return error;
        });
    });

context.start();

Tratamento de erros

Quando ocorrem erros no interceptador de mensagens, o app Web Receiver precisa retornar um cast.framework.messages.ErrorType e cast.framework.messages.ErrorReason adequados.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      const error = new cast.framework.messages.ErrorData(
                      cast.framework.messages.ErrorType.LOAD_CANCELLED);
      if (!loadRequestData.media) {
        error.reason = cast.framework.messages.ErrorReason.INVALID_PARAM;
        return error;
      }

      ...

      return fetchAssetAndAuth(loadRequestData.media.entity,
                               loadRequestData.credentials)
        .then(asset => {
          ...
          return loadRequestData;
        }).catch(reason => {
          error.reason = reason; // cast.framework.messages.ErrorReason
          return error;
        });
    });

Interceptação de mensagens x listener de eventos

Algumas diferenças importantes entre a interceptação de mensagens e o listener de eventos são as seguintes:

  • Um listener de eventos não permite modificar os dados da solicitação.
  • Um listener de eventos é melhor usado para acionar análises ou uma função personalizada.
playerManager.addEventListener(cast.framework.events.category.CORE,
    event => {
        console.log(event);
    });
  • A interceptação de mensagens permite ouvir, interceptar e modificar os dados da solicitação.
  • O interceptação de mensagens é mais adequada para lidar com lógica personalizada em relação aos dados de solicitação.

Como carregar mídia

O MediaInformation fornece várias propriedades para carregar mídia na mensagem cast.framework.messages.MessageType.LOAD, incluindo entity, contentUrl e contentId.

  • O entity é a propriedade sugerida para uso na implementação dos apps remetente e receptor. A propriedade é um URL de link direto que pode ser uma playlist ou conteúdo de mídia. O aplicativo precisa analisar esse URL e preencher pelo menos um dos outros dois campos.
  • O contentUrl corresponde ao URL reproduzível que o player vai usar para carregar o conteúdo. Por exemplo, esse URL pode apontar para um manifesto DASH.
  • O contentId pode ser um URL de conteúdo reproduzível (semelhante ao da propriedade contentUrl ) ou um identificador exclusivo do conteúdo ou da playlist que está sendo carregada. Se você usar essa propriedade como um identificador, seu aplicativo precisará preencher um URL reproduzível no contentUrl.

A sugestão é usar entity para armazenar o ID real ou os parâmetros principais e contentUrl para o URL da mídia. Confira um exemplo no snippet a seguir, em que o entity está presente na solicitação LOAD e o conteúdo jogável contentUrl é recuperado:

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      ...

      if (!loadRequestData.media.entity) {
        // Copy the value from contentId for legacy reasons if needed
        loadRequestData.media.entity = loadRequestData.media.contentId;
      }

      return thirdparty.fetchAssetAndAuth(loadRequestData.media.entity,
                                          loadRequestData.credentials)
        .then(asset => {
          loadRequestData.media.contentUrl = asset.url;
          ...
          return loadRequestData;
        });
    });

Recursos do dispositivo

O método getDeviceCapabilities fornece informações sobre o dispositivo Cast conectado e o dispositivo de vídeo ou áudio conectado a ele. O método getDeviceCapabilities fornece informações de suporte para o Google Assistente, o Bluetooth e os dispositivos de áudio e tela conectados.

Esse método retorna um objeto que pode ser consultado transmitindo um dos enums especificados para receber a capacidade do dispositivo para esse enum. As enumerações são definidas em cast.framework.system.DeviceCapabilities.

Este exemplo verifica se o dispositivo Web Receiver é capaz de reproduzir HDR e DolbyVision (DV) com as chaves IS_HDR_SUPPORTED e IS_DV_SUPPORTED, respectivamente.

const context = cast.framework.CastReceiverContext.getInstance();
context.addEventListener(cast.framework.system.EventType.READY, () => {
  const deviceCapabilities = context.getDeviceCapabilities();
  if (deviceCapabilities &&
      deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_HDR_SUPPORTED]) {
    // Write your own event handling code, for example
    // using the deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_HDR_SUPPORTED] value
  }
  if (deviceCapabilities &&
      deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_DV_SUPPORTED]) {
    // Write your own event handling code, for example
    // using the deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_DV_SUPPORTED] value
  }
});
context.start();

Como processar interações do usuário

Um usuário pode interagir com seu aplicativo Web Receiver usando aplicativos remetentes (Web, Android e iOS), comandos de voz em dispositivos compatíveis com o Google Assistente, controles por toque em smart displays e controles remotos em dispositivos Android TV. O SDK do Cast oferece várias APIs para permitir que o app Web Receiver processe essas interações, atualize a interface do aplicativo usando estados de ação do usuário e, opcionalmente, envie as mudanças para atualizar os serviços de back-end.

Comandos de mídia compatíveis

Os estados dos controles de interface são definidos pelo MediaStatus.supportedMediaCommands para controles expandidos do remetente em iOS e Android, apps de controle remoto e receptor em dispositivos touch e apps receptores em dispositivos Android TV. Quando um determinado Command bit a bit é ativado na propriedade, os botões relacionados a essa ação também são ativados. Se o valor não for definido, o botão será desativado. Esses valores podem ser alterados no Web Receiver das seguintes maneiras:

  1. Usar PlayerManager.setSupportedMediaCommands para definir o Commands específico
  2. Adicionar um novo comando usando addSupportedMediaCommands
  3. Remover um comando usando removeSupportedMediaCommands.
playerManager.setSupportedMediaCommands(cast.framework.messages.Command.SEEK |
  cast.framework.messages.Command.PAUSE);

Quando o receptor preparar o MediaStatus atualizado, ele vai incluir as mudanças na propriedade supportedMediaCommands. Quando o status é transmitido, os apps remetentes conectados atualizam os botões na interface de acordo.

Para mais informações sobre comandos de mídia e dispositivos touchscreen compatíveis, consulte o guia Accessing UI controls.

Gerenciar estados de ações do usuário

Quando os usuários interagem com a interface ou enviam comandos de voz, eles podem controlar a reprodução do conteúdo e as propriedades relacionadas ao item em exibição. As solicitações que controlam a reprodução são processadas automaticamente pelo SDK. As solicitações que modificam propriedades do item em reprodução, como um comando LIKE, exigem que o aplicativo receptor as processe. O SDK fornece uma série de APIs para processar esses tipos de solicitações. Para oferecer suporte a essas solicitações, é necessário fazer o seguinte:

  • Defina o userActionStates MediaInformation com as preferências de um usuário ao carregar um item de mídia.
  • Intercepte mensagens USER_ACTION e determine a ação solicitada.
  • Atualize o MediaInformation UserActionState para atualizar a interface.

O snippet a seguir intercepta a solicitação LOAD e preenche o MediaInformation de LoadRequestData. Nesse caso, o usuário gosta do conteúdo que está sendo carregado.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, (loadRequestData) => {
      const userActionLike = new cast.framework.messages.UserActionState(
          cast.framework.messages.UserAction.LIKE);
      loadRequestData.media.userActionStates = [userActionLike];

      return loadRequestData;
    });

O snippet a seguir intercepta a mensagem USER_ACTION e processa a chamada do back-end com a mudança solicitada. Em seguida, ele faz uma chamada para atualizar o UserActionState no receptor.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.USER_ACTION,
  (userActionRequestData) => {
    // Obtain the media information of the current content to associate the action to.
    let mediaInfo = playerManager.getMediaInformation();

    // If there is no media info return an error and ignore the request.
    if (!mediaInfo) {
        console.error('Not playing media, user action is not supported');
        return new cast.framework.messages.ErrorData(messages.ErrorType.BAD_REQUEST);
    }

    // Reach out to backend services to store user action modifications. See sample below.
    return sendUserAction(userActionRequestData, mediaInfo)

    // Upon response from the backend, update the client's UserActionState.
    .then(backendResponse => updateUserActionStates(backendResponse))

    // If any errors occurred in the backend return them to the cast receiver.
    .catch((error) => {
      console.error(error);
      return error;
    });
});

O snippet a seguir simula uma chamada para um serviço de back-end. A função verifica o UserActionRequestData para ver o tipo de mudança que o usuário solicitou e só faz uma chamada de rede se a ação for compatível com o back-end.

function sendUserAction(userActionRequestData, mediaInfo) {
  return new Promise((resolve, reject) => {
    switch (userActionRequestData.userAction) {
      // Handle user action changes supported by the backend.
      case cast.framework.messages.UserAction.LIKE:
      case cast.framework.messages.UserAction.DISLIKE:
      case cast.framework.messages.UserAction.FOLLOW:
      case cast.framework.messages.UserAction.UNFOLLOW:
      case cast.framework.messages.UserAction.FLAG:
      case cast.framework.messages.UserAction.SKIP_AD:
        let backendResponse = {userActionRequestData: userActionRequestData, mediaInfo: mediaInfo};
        setTimeout(() => {resolve(backendResponse)}, 1000);
        break;
      // Reject all other user action changes.
      default:
        reject(
          new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType.INVALID_REQUEST));
    }
  });
}

O snippet a seguir usa o UserActionRequestData e adiciona ou remove o UserActionState do MediaInformation. Atualizar o UserActionState do MediaInformation muda o estado do botão associado à ação solicitada. Essa mudança é refletida na interface dos controles de tela inteligente, no app de controle remoto e na interface do Android TV. Ele também é transmitido por mensagens MediaStatus enviadas para atualizar a interface do controlador expandido para remetentes de iOS e Android.

function updateUserActionStates(backendResponse) {
  // Unwrap the backend response.
  let mediaInfo = backendResponse.mediaInfo;
  let userActionRequestData = backendResponse.userActionRequestData;

  // If the current item playing has changed, don't update the UserActionState for the current item.
  if (playerManager.getMediaInformation().entity !== mediaInfo.entity) {
    return;
  }

  // Check for existing userActionStates in the MediaInformation.
  // If none, initialize a new array to populate states with.
  let userActionStates = mediaInfo.userActionStates || [];

  // Locate the index of the UserActionState that will be updated in the userActionStates array.
  let index = userActionStates.findIndex((currUserActionState) => {
    return currUserActionState.userAction == userActionRequestData.userAction;
  });

  if (userActionRequestData.clear) {
    // Remove the user action state from the array if cleared.
    if (index >= 0) {
      userActionStates.splice(index, 1);
    }
    else {
      console.warn("Could not find UserActionState to remove in MediaInformation");
    }
  } else {
    // Add the UserActionState to the array if enabled.
    userActionStates.push(
      new cast.framework.messages.UserActionState(userActionRequestData.userAction));
  }

  // Update the UserActionState array and set the new MediaInformation
  mediaInfo.userActionStates = userActionStates;
  playerManager.setMediaInformation(mediaInfo, true);
  return;
}

Comandos de voz

No momento, os seguintes comandos de mídia são compatíveis com o SDK Web Receiver para dispositivos compatíveis com o Google Assistente. As implementações padrão desses comandos estão em cast.framework.PlayerManager.

Comando Descrição
Tocar Reproduzir ou retomar a reprodução do estado pausado.
Pausar Pausar o conteúdo em reprodução.
Anterior Voltar para o item de mídia anterior na fila.
Próxima Pular para o próximo item na fila de mídia.
Parar Parar a mídia em reprodução.
Não repetir Desativar a repetição de itens de mídia na fila quando o último item terminar de tocar.
Repetir single Repete a mídia em reprodução indefinidamente.
Repetir tudo Repete todos os itens na fila depois que o último item é reproduzido.
Repetir tudo e ordem aleatória Depois que o último item da fila terminar de tocar, embaralhe a fila e repita todos os itens.
Embaralhar Embaralhe os itens de mídia na fila de mídia.
Legenda descritiva ATIVADA / DESATIVADA Ative ou desative as legendas descritivas para sua mídia. A ativação / desativação também está disponível por idioma.
Procurar até o tempo absoluto Pula para o tempo absoluto especificado.
Procurar até o tempo relativo ao horário atual Avança ou volta no tempo pelo período especificado em relação ao tempo de reprodução atual.
Jogar de novo Reinicie a mídia em reprodução ou toque o último item de mídia reproduzido se nada estiver tocando no momento.
Definir a velocidade do vídeo Variar a velocidade de reprodução de mídia. Isso deve ser processado por padrão. Você pode usar o interceptor de mensagens SET_PLAYBACK_RATE para substituir as solicitações de taxa de entrada.

Comandos de mídia compatíveis com voz

Para evitar que um comando de voz acione um comando de mídia em um dispositivo compatível com o Google Assistente, primeiro defina os comandos de mídia compatíveis que você planeja oferecer suporte. Em seguida, aplique esses comandos ativando a propriedade CastReceiverOptions.enforceSupportedCommands. A interface nos remetentes do SDK do Cast e nos dispositivos com tela sensível ao toque vai mudar para refletir essas configurações. Se a flag não estiver ativada, os comandos de voz recebidos serão executados.

Por exemplo, se você permitir PAUSE nos aplicativos remetentes e dispositivos com tela sensível ao toque, também será necessário configurar o receptor para refletir essas configurações. Quando configurado, todos os comandos de voz recebidos serão descartados se não estiverem incluídos na lista de comandos compatíveis.

No exemplo abaixo, fornecemos o CastReceiverOptions ao iniciar o CastReceiverContext. Adicionamos suporte ao comando PAUSE e forçamos o player a oferecer suporte apenas a esse comando. Agora, se um comando de voz solicitar outra operação, como SEEK, ela será negada. O usuário vai receber uma notificação informando que o comando ainda não é compatível.

const context = cast.framework.CastReceiverContext.getInstance();

context.start({
  enforceSupportedCommands: true,
  supportedCommands: cast.framework.messages.Command.PAUSE
});

É possível aplicar uma lógica separada para cada comando que você quer restringir. Remova a flag enforceSupportedCommands e, para cada comando que você quer restringir, intercepte a mensagem recebida. Aqui, interceptamos a solicitação fornecida pelo SDK para que os comandos SEEK emitidos para dispositivos compatíveis com o Google Assistente não acionem uma busca no aplicativo Web Receiver.

Para comandos de mídia que seu aplicativo não aceita, retorne um motivo de erro adequado, como NOT_SUPPORTED.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.SEEK,
  seekData => {
    // Block seeking if the SEEK supported media command is disabled
    if (!(playerManager.getSupportedMediaCommands() & cast.framework.messages.Command.SEEK)) {
      let e = new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType
      .INVALID_REQUEST);
      e.reason = cast.framework.messages.ErrorReason.NOT_SUPPORTED;
      return e;
    }

    return seekData;
  });

Segundo plano da atividade de voz

Se a plataforma Cast colocar o som do seu aplicativo em segundo plano devido à atividade do Google Assistente, como ouvir a fala do usuário ou responder, uma mensagem FocusState de NOT_IN_FOCUS será enviada ao aplicativo Web Receiver quando a atividade começar. Outra mensagem com IN_FOCUS é enviada quando a atividade termina. Dependendo do aplicativo e da mídia que está sendo reproduzida, talvez seja necessário pausar a mídia quando o FocusState for NOT_IN_FOCUS interceptando o tipo de mensagem FOCUS_STATE.

Por exemplo, é uma boa experiência do usuário pausar a reprodução de audiolivros se o Assistente estiver respondendo a uma consulta do usuário.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.FOCUS_STATE,
  focusStateRequestData => {
    // Pause content when the app is out of focus. Resume when focus is restored.
    if (focusStateRequestData.state == cast.framework.messages.FocusState.NOT_IN_FOCUS) {
      playerManager.pause();
    } else {
      playerManager.play();
    }

    return focusStateRequestData;
  });

Idioma da legenda especificado por voz

Quando um usuário não especifica o idioma das legendas, o idioma usado é o mesmo em que o comando foi falado. Nesses cenários, o parâmetro isSuggestedLanguage da mensagem recebida indica se o idioma associado foi sugerido ou solicitado explicitamente pelo usuário.

Por exemplo, isSuggestedLanguage é definido como true para o comando "Ok Google, ative as legendas", porque o idioma foi inferido pelo idioma em que o comando foi falado. Se o idioma for solicitado explicitamente, como em "Ok Google, ative as legendas em inglês", isSuggestedLanguage será definido como false.

Metadados e dublagem

Embora os comandos de voz sejam processados pelo Web Receiver por padrão, verifique se os metadados do seu conteúdo estão completos e precisos. Isso garante que os comandos de voz sejam processados corretamente pelo Google Assistente e que os metadados apareçam corretamente em novos tipos de interfaces, como o app Google Home e telas inteligentes, como o Google Home Hub.

Transferência de stream

Preservar o estado da sessão é a base da transferência de stream, em que os usuários podem mover streams de áudio e vídeo entre dispositivos usando comandos de voz, o app Google Home ou Smart Displays. A mídia para de tocar em um dispositivo (a origem) e continua em outro (o destino). Qualquer dispositivo Cast com o firmware mais recente pode servir como fonte ou destino em uma transferência de stream.

O fluxo de eventos para transferência de stream é:

  1. No dispositivo de origem:
    1. A mídia para de ser reproduzida.
    2. O aplicativo Web Receiver recebe um comando para salvar o estado atual da mídia.
    3. O aplicativo Web Receiver é encerrado.
  2. No dispositivo de destino:
    1. O aplicativo Web Receiver é carregado.
    2. O aplicativo Web Receiver recebe um comando para restaurar o estado salvo da mídia.
    3. A mídia volta a ser reproduzida.

Os elementos do estado da mídia incluem:

  • Posição ou marca de tempo específica da música, do vídeo ou do item de mídia.
  • A posição dela em uma fila mais ampla, como uma playlist ou uma rádio de artista.
  • O usuário autenticado.
  • Estado da reprodução (por exemplo, em andamento ou pausada).

Como ativar a transferência de stream

Para implementar a transferência de stream no seu Web Receiver:

  1. Atualize supportedMediaCommands com o comando STREAM_TRANSFER:
    playerManager.addSupportedMediaCommands(
    cast.framework.messages.Command.STREAM_TRANSFER, true);
  2. Se quiser, substitua os interceptores de mensagens SESSION_STATE e RESUME_SESSION, conforme descrito em Preservar o estado da sessão. Substitua apenas se os dados personalizados precisarem ser armazenados como parte do snapshot da sessão. Caso contrário, a implementação padrão para preservar estados de sessão vai oferecer suporte à transferência de stream.

Como preservar o estado da sessão

O SDK Web Receiver oferece uma implementação padrão para apps Web Receiver preservarem os estados da sessão. Para isso, ele tira um instantâneo do status da mídia atual, converte o status em uma solicitação de carregamento e retoma a sessão com a solicitação de carregamento.

A solicitação de carregamento gerada pelo Web Receiver pode ser substituída no interceptador de mensagens SESSION_STATE, se necessário. Se você quiser adicionar dados personalizados à solicitação de carregamento, sugerimos colocá-los em loadRequestData.customData.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.SESSION_STATE,
    function (sessionState) {
        // Override sessionState.loadRequestData if needed.
        const newCredentials = updateCredentials_(sessionState.loadRequestData.credentials);
        sessionState.loadRequestData.credentials = newCredentials;

        // Add custom data if needed.
        sessionState.loadRequestData.customData = {
            'membership': 'PREMIUM'
        };

        return sessionState;
    });

Os dados personalizados podem ser recuperados de loadRequestData.customData no interceptor de mensagens RESUME_SESSION.

let cred_ = null;
let membership_ = null;

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.RESUME_SESSION,
    function (resumeSessionRequest) {
        let sessionState = resumeSessionRequest.sessionState;

        // Modify sessionState.loadRequestData if needed.
        cred_ = sessionState.loadRequestData.credentials;

        // Retrieve custom data.
        membership_ = sessionState.loadRequestData.customData.membership;

        return resumeSessionRequest;
    });

Pré-carregamento de conteúdo

O Web Receiver é compatível com o pré-carregamento de itens de mídia após o item de reprodução atual na fila.

A operação de pré-carga faz o pré-download de vários segmentos dos próximos itens. A especificação é feita no valor preloadTime do objeto QueueItem. O padrão é de 20 segundos se não for fornecido. O tempo é expresso em segundos, em relação ao fim do item em reprodução . Somente valores positivos são válidos. Por exemplo, se o valor for 10 segundos, o item será pré-carregado 10 segundos antes da conclusão do item anterior. Se o tempo para pré-carregar for maior que o tempo restante no currentItem, a pré-carga vai acontecer assim que possível. Assim, se um valor muito grande de pré-carregamento for especificado no queueItem, será possível alcançar o efeito de que, sempre que estivermos reproduzindo o item atual, já estaremos pré-carregando o próximo. No entanto, deixamos a configuração e a escolha desse valor para o desenvolvedor, já que ele pode afetar a largura de banda e o desempenho de streaming do item em reprodução.

Por padrão, o pré-carregamento funciona para conteúdo HLS, DASH e Smooth Streaming.

Arquivos de áudio e vídeo MP4 comuns, como MP3, não serão pré-carregados porque os dispositivos Cast só são compatíveis com um elemento de mídia e não podem ser usados para pré-carregar enquanto um item de conteúdo está sendo reproduzido.

Mensagens personalizadas

A troca de mensagens é o principal método de interação para aplicativos do Web Receiver.

Um remetente envia mensagens a um Web Receiver usando as APIs do remetente para a plataforma em que o remetente está sendo executado (Android, iOS, Web). O objeto de evento (que é a manifestação de uma mensagem) transmitido aos listeners de eventos tem um elemento de dados (event.data) em que os dados assumem as propriedades do tipo de evento específico.

Um aplicativo Web Receiver pode optar por detectar mensagens em um namespace especificado. Ao fazer isso, o aplicativo Web Receiver passa a oferecer suporte a esse protocolo de namespace. Cabe aos remetentes conectados que querem se comunicar nesse namespace usar o protocolo adequado.

Todos os namespaces são definidos por uma string e precisam começar com "urn:x-cast:" seguido por qualquer string. Por exemplo, "urn:x-cast:com.example.cast.mynamespace".

Confira um snippet de código para o Web Receiver ouvir mensagens personalizadas de remetentes conectados:

const context = cast.framework.CastReceiverContext.getInstance();

const CUSTOM_CHANNEL = 'urn:x-cast:com.example.cast.mynamespace';
context.addCustomMessageListener(CUSTOM_CHANNEL, function(customEvent) {
  // handle customEvent.
});

context.start();

Da mesma forma, os aplicativos Web Receiver podem manter os remetentes informados sobre o estado do Web Receiver enviando mensagens aos remetentes conectados. Um aplicativo Web Receiver pode enviar mensagens usando sendCustomMessage(namespace, senderId, message) em CastReceiverContext. Um Web Receiver pode enviar mensagens para um remetente individual, seja em resposta a uma mensagem recebida ou devido a uma mudança no estado do aplicativo. Além das mensagens ponto a ponto (com um limite de 64 kb), um Web Receiver também pode transmitir mensagens para todos os remetentes conectados.

Transmitir para dispositivos de áudio

Consulte o guia do Google Cast para dispositivos de áudio e saiba como fazer a reprodução apenas de áudio.

Android TV

Esta seção aborda como o Google Web Receiver usa suas entradas como reprodução e compatibilidade com o Android TV.

Como integrar seu aplicativo ao controle remoto

O Google Web Receiver em execução no dispositivo Android TV traduz a entrada dos controles do dispositivo (por exemplo, controle remoto portátil) como mensagens de reprodução de mídia definidas para o namespace urn:x-cast:com.google.cast.media, conforme descrito em Mensagens de reprodução de mídia. Seu aplicativo precisa oferecer suporte a essas mensagens para controlar a reprodução de mídia do aplicativo e permitir o controle básico de reprodução pelas entradas de controle do Android TV.

Diretrizes de compatibilidade com o Android TV

Confira algumas recomendações e erros comuns a serem evitados para garantir que seu aplicativo seja compatível com o Android TV:

  • A string do user agent contém "Android" e "CrKey". Alguns sites podem redirecionar para um site exclusivo para dispositivos móveis porque detectam o rótulo "Android". Não suponha que "Android" na string do user agent sempre indique um usuário de dispositivo móvel.
  • A pilha de mídia do Android pode usar GZIP transparente para buscar dados. Verifique se os dados de mídia podem responder a Accept-Encoding: gzip.
  • Os eventos de mídia HTML5 do Android TV podem ser acionados em momentos diferentes do Chromecast, o que pode revelar problemas que estavam ocultos no Chromecast.
  • Ao atualizar a mídia, use eventos relacionados a mídia acionados por elementos <audio>/<video>, como timeupdate, pause e waiting. Evite usar eventos relacionados a rede, como progress, suspend e stalled, porque eles tendem a depender da plataforma. Consulte Eventos de mídia para mais informações sobre como processar eventos de mídia no seu receptor.
  • Ao configurar os certificados HTTPS do site do receptor, inclua certificados intermediários da autoridade de certificação. Consulte a página de teste SSL da Qualsys para verificar: se o caminho de certificação confiável do seu site incluir um certificado de CA rotulado como "download extra", talvez ele não seja carregado em plataformas baseadas no Android.
  • Enquanto o Chromecast mostra a página do receptor em um plano gráfico de 720p, outras plataformas Cast, incluindo o Android TV, podem mostrar a página em até 1080p. Verifique se a página do receptor é dimensionada corretamente em diferentes resoluções.