Esta página contém snippets de código e descrições dos recursos disponíveis para um app Custom Web Receiver.
- Um elemento
cast-media-player
que representa a interface do jogador integrada fornecida com o Web Receiver. - Estilo personalizado semelhante ao CSS para o elemento
cast-media-player
, que estiliza vários elementos da interface, comobackground-image
,splash-image
efont-family
. - Um elemento de script para carregar o framework Web Receiver.
- Código JavaScript para interceptar mensagens e processar eventos.
- Adicionar à fila para reprodução automática.
- Opções para configurar a reprodução.
- Opções para definir o contexto do Web Receiver.
- Opções para definir comandos compatíveis com o app Web Receiver.
- 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 oCastReceiverContext
.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 paragetPlaybackConfig()
. 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 propriedadecontentUrl
) 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 nocontentUrl
.
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:
- Usar
PlayerManager.setSupportedMediaCommands
para definir oCommands
específico - Adicionar um novo comando usando
addSupportedMediaCommands
- 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 é:
- No dispositivo de origem:
- A mídia para de ser reproduzida.
- O aplicativo Web Receiver recebe um comando para salvar o estado atual da mídia.
- O aplicativo Web Receiver é encerrado.
- No dispositivo de destino:
- O aplicativo Web Receiver é carregado.
- O aplicativo Web Receiver recebe um comando para restaurar o estado salvo da mídia.
- 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:
- Atualize
supportedMediaCommands
com o comandoSTREAM_TRANSFER
:playerManager.addSupportedMediaCommands( cast.framework.messages.Command.STREAM_TRANSFER, true);
- Se quiser, substitua os interceptores de mensagens
SESSION_STATE
eRESUME_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>
, comotimeupdate
,pause
ewaiting
. Evite usar eventos relacionados a rede, comoprogress
,suspend
estalled
, 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.