Esta página contém snippets de código e descrições dos recursos disponíveis para um app receptor da Web personalizado.
- Um elemento
cast-media-playerque representa a interface do player integrada fornecida com o receptor da Web. - Estilo personalizado semelhante ao CSS para o elemento
cast-media-playerpara estilizar vários elementos da interface, comobackground-image,splash-imageefont-family. - Um elemento de script para carregar o framework do receptor da Web.
- Código JavaScript para interceptar mensagens e processar eventos.
- Fila para reprodução automática.
- Opções para configurar a reprodução.
- Opções para definir o contexto do receptor da Web.
- Opções para definir comandos compatíveis com o app receptor da Web.
- Uma chamada JavaScript para iniciar o aplicativo receptor da Web.
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 subjacentes e processa a inicialização do SDK do receptor da Web. 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 são 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 receptor da Web 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 do receptor da Web oferece uma maneira de configurar variáveis de reprodução,
como informações de
DRM,
configurações de nova tentativa e gerenciadores de solicitações usando
cast.framework.PlaybackConfig.
Essas informações são processadas por
PlayerManager
e avaliadas no momento em que os players 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 no próximo
carregamento de conteúdo. O SDK oferece os seguintes métodos para modificar o
PlaybackConfig.
CastReceiverOptions.playbackConfigpara 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 todos os carregamentos subsequentes ou até que seja substituída novamente.PlayerManager.setMediaPlaybackInfoHandler()para aplicar outras configurações apenas ao item de mídia que está sendo carregado sobre as configurações atuais. O gerenciador é 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 gerenciador é 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 do 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 define o player para
retomar a reprodução do 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 de 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 do receptor da Web permite que o app receptor da Web 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. As 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 receptor da Web permite que o app receptor da Web 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 que deve 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 que o gerenciador de mensagens padrão seja chamado. Consulte Como carregar mídia para mais detalhes.
Por exemplo, se você quiser mudar os dados da solicitação de carregamento, use a seguinte lógica 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 receptor da Web precisa retornar
um
cast.framework.messages.ErrorType
e um
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
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 é mais 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 uma mensagem, intercepte-a e modifique os dados da solicitação.
- A interceptação de mensagens é mais usada para lidar com 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.
- 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 um conteúdo de mídia. Seu aplicativo precisa analisar esse URL e preencher pelo menos um dos outros dois campos. - O
contentUrlcorresponde 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
contentIdpode 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 de reprodução nocontentUrl.
A sugestão é usar entity para armazenar o ID real ou os parâmetros de chave e
usar contentUrl para o URL da mídia. Confira um exemplo disso no
snippet a seguir, 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 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
tipos enumerados especificados para receber o recurso do dispositivo para esse tipo. Os tipos enumerados são
definidos em
cast.framework.system.DeviceCapabilities.
Este exemplo verifica se o dispositivo do receptor da Web é 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 receptor da Web usando aplicativos remetentes (Web, Android e iOS), comandos de voz em dispositivos 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 que o app receptor da Web processe essas interações, atualize a interface do aplicativo usando estados de ação do usuário e, se quiser, 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 orientados pelo
MediaStatus.supportedMediaCommands
para controladores expandidos de remetente iOS e Android, apps de receptor e controle remoto
em execução em dispositivos touchscreen e apps de receptor em dispositivos Android TV. Quando um
Command bit a bit específico é ativado na propriedade, os botões relacionados
a essa ação são ativados. Se o valor não for definido, o botão será
desativado. Esses valores podem ser alterados no receptor da Web:
- Como usar
PlayerManager.setSupportedMediaCommandspara definir oCommandsespecífico. - Como adicionar um novo comando usando
addSupportedMediaCommands - Remover um comando atual 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 remetentes conectados atualizam os botões na IU
de acordo.
Para mais informações sobre comandos de mídia e dispositivos touchscreen 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, como um comando LIKE,
precisam ser processadas pelo aplicativo receptor. O SDK oferece uma série de APIs para lidar com esses tipos de solicitação. Para atender a essas solicitações, é necessário
fazer o seguinte:
- Defina o
MediaInformationuserActionStatescom as preferências do usuário ao carregar um item de mídia. - Interceptar mensagens
USER_ACTIONe determinar a ação solicitada. - Atualize o
MediaInformationUserActionStatepara 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 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 de controles do smart display, 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 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 seguintes comandos de mídia são compatíveis com o SDK do receptor da Web para
dispositivos com 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 | Volte 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 de mídia. |
| Parar | Interrompe a mídia em reprodução. |
| Não repetir | Desativa a repetição de itens de mídia na fila depois que o último item é reproduzido. |
| Repetir uma | Repete a mídia em reprodução indefinidamente. |
| Repetir tudo | Repete todos os itens da fila depois que o último item é reproduzido. |
| Repetir tudo e ordem aleatória | Depois que o último item da fila for reproduzido, embaralhe a fila e repita todos os itens dela. |
| Embaralhar | Embaralha os itens de mídia na fila. |
| Ativar/desativar legendas descritivas | Ativar/desativar as legendas descritivas para sua mídia. A ativação/desativação também está disponível por idioma. |
| Buscar o tempo absoluto | Vai para o horário absoluto especificado. |
| Buscar por tempo relativo ao horário atual | Avança ou retrocede o período especificado em relação ao tempo de reprodução atual. |
| Jogar novamente | Reinicia a mídia em reprodução ou reproduz o último item de mídia reproduzido se nada estiver em reprodução. |
| Definir a velocidade do vídeo | Variar a velocidade do vídeo. Isso deve ser processado por padrão. Use o interceptador de mensagens SET_PLAYBACK_RATE para substituir as solicitações de taxa recebidas. |
Comandos de mídia aceitos por voz
Para evitar que um comando de voz acione um comando de mídia em um dispositivo com o Assistente, primeiro defina os
comandos de mídia compatíveis
que você planeja usar. Em seguida, é preciso aplicar esses comandos ativando
a
propriedade
CastReceiverOptions.enforceSupportedCommands. A interface nos remetentes do SDK do Cast e nos dispositivos com tela touchscreen 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 touchscreen, também será necessário configurar o receptor para refletir essas
configurações. Quando configurados, 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 será
notificado 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 aplicativo do receptor da Web.
Para comandos de mídia que não são compatíveis com o aplicativo, retorne um motivo de erro apropriado, 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 do Cast colocar o som do 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 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, 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 um audiolivro 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 indica 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,
ativar 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 elenco de voz
Embora os comandos de voz sejam processados pelo receptor da Web por padrão, é necessário garantir que os metadados do seu conteúdo estejam completos e precisos. Isso garante que os comandos de voz sejam processados corretamente pelo Assistente e que os metadados apareçam corretamente em novos tipos de interfaces, como o app Google Home e smart displays, como o Google Home Hub.
Transferência de stream
A preservação do estado da sessão é a base da transferência de stream, em que os usuários podem mover 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 origem 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 tocar.
- O aplicativo receptor da Web recebe um comando para salvar o estado atual da mídia.
- O aplicativo receptor da Web é encerrado.
- No dispositivo de destino:
- O aplicativo receptor da Web é carregado.
- O aplicativo receptor da Web recebe um comando para restaurar o estado de mídia salvo.
- A mídia volta a tocar.
Os elementos do estado de 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 dela em uma fila mais ampla (como uma playlist ou rádio de artista).
- O usuário autenticado.
- Estado de reprodução (por exemplo, em reprodução ou pausado).
Ativar a transferência de stream
Para implementar a transferência de stream no seu receptor da Web:
- Atualize
supportedMediaCommandscom o comandoSTREAM_TRANSFER:playerManager.addSupportedMediaCommands( cast.framework.messages.Command.STREAM_TRANSFER, true);
- Se quiser, substitua os interceptadores de mensagens
SESSION_STATEeRESUME_SESSION, conforme descrito em Como preservar o estado da sessão. Substitua-os apenas se os dados do cliente precisarem ser armazenados como parte do snapshot da sessão. Caso contrário, a implementação padrão para preservar os estados da sessão será compatível com a transferência de stream.
Preservação do estado da sessão
O SDK do receptor da Web oferece uma implementação padrão para que os apps receptores da Web preservem os estados da sessão. Para isso, ele faz um snapshot do status de mídia atual, converte o status em uma solicitação de carregamento e retoma a sessão com essa solicitação.
A solicitação de carregamento gerada pelo receptor da Web 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 interceptador 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 receptor da Web é 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é-carregamento faz o download de vários segmentos dos próximos itens. A especificação é feita no valor preloadTime no objeto QueueItem (o padrão é 20 segundos, se não for fornecido). O tempo é expresso em segundos, em relação ao final do item em reprodução . Somente valores positivos são válidos. Por exemplo, se o valor for 10 segundos, esse item será pré-carregado 10 segundos antes do término do item anterior. Se o tempo de pré-carregamento for maior 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, será possível alcançar o efeito de que, sempre que estivermos reproduzindo o item atual, já estaremos pré-carregando o próximo item. No entanto, deixamos a configuração e a escolha disso 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 funciona para conteúdo de streaming HLS, DASH e Smooth por padrão.
Arquivos de vídeo MP4 e de áudio comuns, como MP3, não serão pré-carregados, já que os dispositivos Cast são compatíveis com apenas um elemento de mídia e não podem ser usados para pré-carregar enquanto um item de conteúdo atual ainda está sendo reproduzido.
Mensagens personalizadas
A troca de mensagens é o principal método de interação para aplicativos do receptor da Web.
Um remetente envia mensagens para um receptor da Web usando as APIs de remetente da
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 receptor da Web pode detectar mensagens em um namespace específico. Ao fazer isso, o aplicativo receptor da Web passa a oferecer suporte a esse protocolo de namespace. Em seguida, 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".
Confira um snippet de código para o receptor da Web detectar 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 receptor da Web podem manter os remetentes informados sobre o estado
do receptor da Web enviando mensagens para os remetentes conectados. Um aplicativo receptor da Web pode enviar mensagens usando sendCustomMessage(namespace, senderId, message) em CastReceiverContext.
Um receptor da Web pode enviar mensagens para um remetente individual, 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 receptor da Web também pode transmitir mensagens de transmissão para todos os remetentes conectados.
Dispositivos de áudio para transmissão
Consulte o guia do Google Cast para dispositivos de áudio para saber mais sobre a reprodução somente de áudio.
Android TV
Nesta seção, discutimos como o Receptor da Web do Google usa suas entradas como reprodução e a compatibilidade com o Android TV.
Como integrar o aplicativo ao controle remoto
O Receptor da Web do Google em execução no dispositivo Android TV traduz as entradas de controle 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 o 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 presuma 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 o 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 ela que são acionados por elementos
<audio>/<video>, comotimeupdate,pauseewaiting. Evite usar eventos relacionados à rede, comoprogress,suspendestalled, porque eles costumam depender 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 receptor, inclua certificados de CA intermediários. Consulte a página de teste de SSL da Qualsys para verificar se o caminho de certificação confiável do seu site inclui um certificado de CA rotulado como "download extra". Se incluir, talvez ele não seja carregado em plataformas baseadas no Android.
- Enquanto o Chromecast exibe a página do receptor em um plano gráfico de 720p, outras plataformas do Cast, 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.