Esta página contém snippets de código e descrições dos recursos disponíveis para um app de receptor da Web personalizado.
- Um elemento
cast-media-player
que representa a interface do player integrada fornecida com o Web Receiver. - Estilo personalizado semelhante ao CSS para o elemento
cast-media-player
para estilizar vários elementos da interface, comobackground-image
,splash-image
efont-family
. - Um elemento de script para carregar o framework do Web Receiver.
- Código JavaScript para interceptar mensagens e processar eventos.
- Enfileirar para a 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 de 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. Ele gerencia o carregamento das
bibliotecas e processa a inicialização do SDK do receptor da Web. O SDK
oferece APIs que permitem que os desenvolvedores de apps configurem o SDK usando
CastReceiverOptions
.
Essas configurações são avaliadas uma vez por inicialização do app 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 receptor da Web 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 Chrome Remote Debugger quando não
há nenhum remetente conectado 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 do receptor da Web oferece uma maneira de configurar variáveis
de reprodução, como informações
DRM, tentativas de configuração e manipuladores de solicitações usando
cast.framework.PlaybackConfig
.
Essas informações são processadas pelo
PlayerManager
e são avaliadas no momento em que os jogadores são criados. Os players são criados
sempre que uma nova carga é transmitida ao SDK do receptor da Web. As modificações no
PlaybackConfig
após a criação do player são avaliadas na próxima
carga 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 conferir a configuração atual.PlayerManager.setPlaybackConfig()
para substituir a configuração atual. Essa configuração é aplicada a todas as cargas subsequentes ou até ser substituída novamente.PlayerManager.setMediaPlaybackInfoHandler()
para aplicar outras configurações apenas ao item de mídia que está sendo carregado além das configurações atuais. O gerenciador é chamado logo 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 agetPlaybackConfig()
. 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 gerenciador especifica que as solicitações de controle de acesso CORS
precisam 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 do conteúdo depois que um segmento é 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 carga
específica usando o gerenciador de informações de reprodução de mídia. O gerenciador chama um método
implementado pelo aplicativo getLicenseUrlForMedia
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 do Web Receiver permite que o app processe eventos do player. O
listener de evento recebe um parâmetro
cast.framework.events.EventType
(ou uma matriz desses parâmetros) que especifica os eventos que
precisam acionar o listener. Matrizes pré-configuradas de
cast.framework.events.EventType
que são ú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 do Web Receiver permite que seu app intercepte mensagens e
execute códigos personalizados nelas. O interceptor de mensagens usa um parâmetro
cast.framework.messages.MessageType
que especifica o tipo de mensagem a ser interceptada.
O interceptor precisa retornar a solicitação modificada ou uma promessa que seja resolvida
com o valor da solicitação modificado. O retorno de 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 ocorrerem erros no interceptor de mensagens, o app Web Receiver precisará 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;
});
});
Intercepção de mensagens x listener de eventos
Confira algumas diferenças importantes entre a interceptação de mensagens e o listener de eventos:
- Um listener de eventos não permite modificar os dados da solicitação.
- Um listener de evento é 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 que você ouça, intercepte e modifique os dados da solicitação.
- A interceptação de mensagens é melhor usada para processar a lógica personalizada em relação aos dados de solicitação.
Como carregar mídia
MediaInformation
oferece várias propriedades para carregar mídia na
mensagem cast.framework.messages.MessageType.LOAD
, incluindo entity
, contentUrl
e contentId
.
- A
entity
é a propriedade sugerida para usar na implementação dos apps de 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 que o player vai usar para carregar o conteúdo. Por exemplo, este 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 para o conteúdo ou a 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 de chave e
contentUrl
para o URL da mídia. Um exemplo disso é mostrado no
snippet abaixo, em que o entity
está presente na solicitação LOAD
e o
contentUrl
reproduzível é 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 de transmissão do Google 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, Bluetooth e a tela e os dispositivos de áudio
conectados.
Esse método retorna um objeto que pode ser consultado transmitindo um dos
enums especificados para receber o capability do dispositivo para esse tipo. Os tipos enumerados são
definidos em
cast.framework.system.DeviceCapabilities
.
Este exemplo verifica se o dispositivo do 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 a interação do usuário
Um usuário pode interagir com seu app Web Receiver por apps de envio (Web, Android e iOS), comandos de voz em dispositivos com 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 gerencie essas interações, atualize a interface do aplicativo por 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 da interface são determinados pelo
MediaStatus.supportedMediaCommands
para controladores estendidos do iOS e do Android, apps de controle remoto e receptor
em execução em dispositivos com tela touch e apps de receptor em dispositivos Android TV. Quando um
Command
de bits específico é 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 da seguinte forma:
- Usar
PlayerManager.setSupportedMediaCommands
para definir oCommands
específico - Como adicionar um novo comando usando
addSupportedMediaCommands
- Remoção de um comando usando
removeSupportedMediaCommands
.
playerManager.setSupportedMediaCommands(cast.framework.messages.Command.SEEK |
cast.framework.messages.Command.PAUSE);
Quando o receptor prepara o MediaStatus
atualizado, ele inclui as
mudanças na propriedade supportedMediaCommands
. Quando o status é
transmitido, os apps de envio conectados atualizam os botões na interface
de acordo.
Para mais informações sobre comandos de mídia e dispositivos com tela touch compatíveis, consulte o
guia
Accessing UI controls
.
Como gerenciar estados de ação 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 reprodução. As solicitações
que controlam a reprodução são processadas automaticamente pelo SDK. As solicitações que
modificam as propriedades do item em reprodução atual, como um comando LIKE
,
exigem que o aplicativo receptor as processe. O SDK oferece 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
MediaInformation
userActionStates
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
UserActionState
MediaInformation
para atualizar a interface.
O snippet a seguir intercepta a solicitação LOAD
e preenche o
MediaInformation
do 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 saber o tipo de mudança que o usuário solicitou
e só faz uma chamada de rede se a ação tiver suporte do 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 que
está associado à ação solicitada. Essa mudança é refletida na interface
de controles da tela inteligente, no app de controle remoto e na interface do Android TV. Ele também é
enviado por mensagens MediaStatus
de saída para atualizar a interface do
controlador expandido para remetentes do iOS e do 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
Os comandos de mídia a seguir têm suporte no SDK do Web Receiver para
dispositivos com o Google Assistente. As implementações padrão desses comandos são
encontradas 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 de mídia. |
Próxima | Pular para o próximo item de mídia na fila. |
Parar | Parar a mídia em reprodução. |
Não repetir | Desative a repetição de itens de mídia na fila depois que o último item for reproduzido. |
Repetir | Repete a mídia em reprodução no momento indefinidamente. |
Repetir tudo | Repete todos os itens da fila depois que o último item é reproduzido. |
Repetir tudo e ordem aleatória | Quando o último item da fila terminar de tocar, embaralhe a fila e repita todos os itens. |
Embaralhar | Embaralhe os itens de mídia na sua fila. |
Legendas ATIVADAS / DESATIVADAS | Ative ou desative as closed captions da mídia. A opção "Ativar / desativar" também está disponível por idioma. |
Procurar o tempo absoluto | Pula para o tempo absoluto especificado. |
Procurar o tempo relativo ao atual | Avança ou volta o tempo de reprodução em relação ao tempo especificado. |
Tocar de novo | Reinicie a mídia em reprodução ou toque o último item de mídia se nada estiver sendo reproduzido. |
Definir a taxa de reprodução | Variar a taxa de reprodução de mídia. Isso precisa ser tratado por padrão. Você pode usar o interceptor de mensagens SET_PLAYBACK_RATE para substituir as solicitações de taxa recebidas. |
Comandos de mídia com voz compatíveis
Para evitar que um comando de voz acione um comando de mídia em um dispositivo
com o Google Assistente, primeiro defina os
comandos de mídia compatíveis
que você planeja oferecer suporte. Em seguida, você precisa aplicar esses comandos ativando a
propriedade
CastReceiverOptions.enforceSupportedCommands
. A interface dos remetentes do SDK do Google Cast e dos dispositivos com recurso de 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
dos aplicativos de envio e
dos dispositivos com recursos de 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 de 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 com o Google Assistente
não acionem uma busca no seu aplicativo de receptor da Web.
Para comandos de mídia que seu app não oferece suporte, 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;
});
Atividades em segundo plano da atividade de voz
Se o som do seu app for silenciado pelo
plataforma do Cast devido a uma atividade do Google Assistente, como ouvir a fala do usuário ou responder, uma
mensagem FocusState
de NOT_IN_FOCUS
será enviada ao app do receptor da Web 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, é possível
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 um audiolivro se o Google 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 explicitamente 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, ativar legendas em inglês", isSuggestedLanguage
será definido como false
.
Metadados e transmissão por voz
Embora os comandos de voz sejam processados pelo Web Receiver por padrão, é necessário garantir que os metadados do seu conteúdo sejam completos e precisos. Isso garante que os comandos de voz sejam processados corretamente pelo Google Assistente e que os metadados sejam exibidos corretamente em novos tipos de interfaces, como o app Google Home e telas inteligentes, como o Google Home Hub.
Transferência de stream
A preservação do estado da sessão é a base da transferência de streaming, em que os usuários podem mover streams de áudio e vídeo entre dispositivos usando comandos de voz, o app Google Home ou telas inteligentes. A mídia para de ser reproduzida em um dispositivo (a origem) e continua em outro (o destino). Qualquer dispositivo Cast com o firmware mais recente pode servir como origem ou destino em uma transferência de streaming.
O fluxo de eventos para a transferência de stream é o seguinte:
- No dispositivo de origem:
- A mídia é interrompida.
- O aplicativo do receptor da Web 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 do receptor da Web recebe um comando para restaurar o estado da mídia salva.
- A mídia é retomada.
Os elementos do estado da mídia incluem:
- Posição ou marcação de tempo específica da música, do vídeo ou do item de mídia.
- O lugar na fila (por exemplo, em uma playlist ou rádio de artista).
- O usuário autenticado.
- Estado de reprodução (por exemplo, em reprodução ou pausado).
Como ativar a transferência de streaming
Para implementar a transferência de stream para seu receptor da Web:
- Atualize
supportedMediaCommands
com o comandoSTREAM_TRANSFER
:playerManager.addSupportedMediaCommands( cast.framework.messages.Command.STREAM_TRANSFER, true);
- Opcionalmente, substitua os interceptors de mensagem
SESSION_STATE
eRESUME_SESSION
, conforme descrito em Preservar o estado da sessão. Só substitua esses valores se os dados personalizados precisarem ser armazenados como parte do snapshot da sessão. Caso contrário, a implementação padrão para preservar os estados de sessão vai oferecer suporte à transferência de stream.
Preservar o estado da sessão
O SDK do Web Receiver oferece uma implementação padrão para que os apps do Web Receiver preservem os estados da sessão fazendo uma captura de tela do status atual da mídia, convertendo o status em uma solicitação de carregamento e retomando a sessão com a solicitação de carregamento.
A solicitação de carga gerada pelo receptor da Web pode ser substituída no
interceptor 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 oferece suporte ao pré-carregamento de itens de mídia após o item de reprodução atual na fila.
A operação de pré-carregamento faz o pré-download de vários segmentos dos itens futuros. A especificação é feita no valor preloadTime no objeto QueueItem (padrão de 20 segundos se não for fornecido). O tempo é expresso em segundos, em relação ao fim do item que está sendo reproduzido . Somente valores positivos são válidos. Por exemplo, se o valor for 10 segundos, esse item será pré-carregado 10 segundos antes do item anterior terminar. Se o tempo para pré-carregar for maior do que o tempo restante no currentItem, o pré-carregamento vai acontecer assim que possível. Portanto, se um valor muito grande de pré-carregamento for especificado no queueItem, poderemos 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 para o desenvolvedor, já que esse valor pode afetar a largura de banda e o desempenho de streaming do item em reprodução.
O pré-carregamento vai funcionar para conteúdo HLS, DASH e Smooth Streaming por padrão.
Os arquivos de áudio e vídeo MP4 comuns, como MP3, não serão pré-carregados, já que os dispositivos Cast oferecem suporte a apenas um elemento de mídia e não podem ser usados para pré-carregar enquanto um item de conteúdo ainda está sendo reproduzido.
Mensagens personalizadas
A troca de mensagens é o principal método de interação para aplicativos de Web Receiver.
Um remetente emite mensagens para um receptor da Web usando as APIs do remetente para a
plataforma em execução (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 de receptor da Web pode escolher ouvir mensagens em um namespace especificado. Por isso, o aplicativo do receptor da Web é compatível com esse protocolo de namespace. Cabe a qualquer remetente conectado que queira se comunicar nesse namespace usar o protocolo apropriado.
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
".
Este é um snippet de código para que o receptor da Web ouça 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 do Web Receiver podem manter os remetentes informados sobre o estado
do Web Receiver enviando mensagens para os remetentes conectados. Um aplicativo de receptor da Web
pode enviar mensagens usando
sendCustomMessage(namespace, senderId, message)
em
CastReceiverContext
.
Um receptor da Web pode enviar mensagens para um remetente específico, seja em resposta a
uma mensagem recebida ou devido a uma mudança de 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 para receber suporte para reprodução apenas de áudio.
Android TV
Esta seção discute 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 converte a entrada das
entradas de controle do dispositivo (ou seja, o 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. O
app precisa oferecer suporte a essas mensagens para controlar a reprodução de mídia
do app e permitir o controle básico de reprodução nas entradas de
controle do Android TV.
Diretrizes para compatibilidade com o Android TV
Confira algumas recomendações e armadilhas comuns que você precisa evitar para garantir que seu app 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 indica um usuário de dispositivo móvel.
- A pilha de mídia do Android pode usar GZIP transparente para buscar dados. Confira 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 ocultos no Chromecast.
- Ao atualizar a mídia, use eventos relacionados à mídia acionados por elementos
<audio>/<video>
, comotimeupdate
,pause
ewaiting
. Evite usar eventos relacionados à rede, comoprogress
,suspend
estalled
, porque eles tendem a ser dependentes da plataforma. Consulte Eventos de mídia para mais informações sobre como processar eventos de mídia no receptor. - Ao configurar os certificados HTTPS do site do destinatário, inclua certificados intermediários de AC. Consulte a página de teste de SSL do Qualsys para verificar se o caminho de certificação confiável do seu site inclui um certificado de AC com a etiqueta "download extra". Se ele não for carregado em plataformas com base no Android, o problema pode estar relacionado a isso.
- Enquanto o Chromecast exibe a página do receptor em um plano gráfico de 720p, outras plataformas de transmissão, incluindo o Android TV, podem exibir a página em até 1080p. Verifique se a página do receptor é dimensionada corretamente em diferentes resoluções.