Inscrever-se em canais — Web
Depois de conectado a uma sessão, você pode se inscrever em transmissões na sessão. Ao se inscrever em uma transmissão, o vídeo dessa transmissão aparece na página do cliente e o áudio é reproduzido.
Este tópico inclui as seguintes seções:
- Detectar quando novos fluxos são criados
- Inscrever-se em um canal
- Cancelar a inscrição em um stream
- Reconexão automática
- Restrição da taxa de quadros de uma transmissão assinada
- Detectar quando os fluxos saem de uma sessão
- Detectar quando o áudio de um assinante está bloqueado ou desbloqueado
- Detectar quando o vídeo de um assinante está desativado
- Detectar quando as dimensões do vídeo de uma transmissão mudam
- Obter informações sobre um fluxo
- Como definir a taxa de quadros e a resolução preferidas
- Aplicação de filtros e efeitos a arquivos de áudio e vídeo inscritos
- Detecção de alterações na qualidade de áudio e vídeo
- Solução de problemas
- Implementação de novas tentativas de assinatura de sessão
Detectar quando fluxos são criados em uma sessão
O objeto Session despacha um streamCreated evento que ocorre quando um novo fluxo (que não seja o seu) é criado em uma sessão. Um fluxo é criado quando um cliente publica um fluxo para a sessão. O streamCreated O evento também é disparado para cada stream existente na sessão quando você se conecta pela primeira vez. Esse evento é definido pela classe `StreamEvent`, que possui um stream propriedade, que representa o fluxo que foi criado:
session.on("streamCreated", function (event) {
console.log("New stream in the session: " + event.stream.streamId);
});
// Replace with a valid token:
session.connect(token);
Você pode se inscrever em qualquer canal. Consulte a próxima seção.
Inscrever-se em um canal
Para se inscrever em um stream, passe o objeto Stream para o subscribe método do objeto Session:
session.subscribe(stream, replacementElementId);
O subscribe() O método recebe os seguintes parâmetros:
-
stream—O objeto Stream. -
targetElement— (Opcional) Define o elemento DOM que o vídeo do Assinante substitui. -
properties— (Opcional) Um conjunto de propriedades que personalizam a aparência da visualização do Assinante na página HTML (consulte Personalização da interface do usuário) e selecione se deseja se inscrever para receber áudio e vídeo (consulte Ajustando o áudio e o vídeo). -
completionHandler— (Opcional) Uma função que é chamada de forma assíncrona quando a chamada para osubscribe()o método é executado com sucesso ou falha. Se a chamada para osubscribe()Se o método falhar, o manipulador de conclusão recebe um objeto de erro. Esse objeto possui umcodeemessagepropriedades que descrevem o erro.
O código a seguir assina todos os fluxos, exceto aqueles publicados pelo seu cliente:
session.on("streamCreated", function(event) {
session.subscribe(event.stream);
});
// Replace with your API key and token:
session.connect(token, function (error) {
if(error) {
// failed to connect
}
});
O insertMode propriedade do properties parâmetro do Session.subscribe() O método especifica como o objeto Publisher será inserido no DOM HTML, em relação ao targetElement parâmetro. É possível definir esse parâmetro com um dos seguintes valores:
"replace"— O objeto `Subscriber` substitui o conteúdo do `targetElement`. Esse é o comportamento padrão."after"— O objeto `Subscriber` é um novo elemento inserido após o `targetElement` no DOM HTML. (Tanto o `Subscriber` quanto o `targetElement` têm o mesmo elemento pai.)"before"— O objeto `Subscriber` é um novo elemento inserido antes do `targetElement` no DOM HTML. (Tanto o `Subscriber` quanto o `targetElement` têm o mesmo elemento pai.)"append"— O objeto Subscriber é um novo elemento adicionado como filho do targetElement. Se houver outros elementos filhos, o Publisher é anexado como o último elemento filho do targetElement.
Por exemplo, o código a seguir adiciona um novo objeto Subscriber como filho de um subscriberContainer Elemento DOM:
session.on('streamCreated', function(event) {
var subscriberProperties = {insertMode: 'append'};
var subscriber = session.subscribe(event.stream,
'subscriberContainer',
subscriberProperties,
function (error) {
if (error) {
console.log(error);
} else {
console.log('Subscriber added.');
}
});
});
O objeto `Subscriber` possui um element propriedade, que é definida como o elemento DOM HTML que a contém.
Se você não quiser usar a interface de usuário padrão, acesse o Video elemento para o Assinante (ver esse assunto). Você também pode usar o seu próprio Video elemento para exibir o vídeo do assinante e use o objeto MediaStream do assinante como fonte de mídia para esse Video elemento (ver esse assunto).
Cancelar a inscrição em um stream
Para interromper a reprodução de um stream do qual você é assinante, passe o objeto `Subscriber` para o unsubscribe() método do objeto Session:
session.unsubscribe(subscriber);
O objeto `Subscriber` é destruído, e a exibição do fluxo é removida do DOM HTML.
Detectar quando os fluxos saem de uma sessão
Quando um stream, que não seja o seu, sai de uma sessão, o objeto Session dispara um streamDestroyed evento:
session.on("streamDestroyed", function (event) {
console.log("Stream stopped. Reason: " + event.reason);
});
Quando um fluxo publicado sai de uma sessão, o objeto Publisher dispara um streamDestroyed evento:
var publisher = OT.initPublisher();
publisher.on("streamDestroyed", function (event) {
console.log("Stream stopped. Reason: " + event.reason);
});
O streamDestroyed O evento é definido pela classe StreamEvent. O evento inclui um reason propriedade, que explica por que a transmissão foi encerrada. Esses motivos incluem "clientDisconnected", "forceDisconnected", "forceUnpublished", ou "networkDisconnected". Para mais detalhes, consulte StreamEvent.
Por padrão, quando um streamDestroyed Quando um evento é disparado para um fluxo ao qual você está inscrito, os objetos Subscriber correspondentes (pode haver mais de um) são destruídos e removidos do DOM HTML. Você pode impedir esse comportamento padrão chamando o preventDefault() método do objeto StreamEvent:
session.on("streamDestroyed", function (event) {
event.preventDefault();
var subscribers = session.getSubscribersForStream(event.stream);
// Now you can adjust the DOM elements around each
// subscriber to the stream, and then delete it yourself.
});
Observe que o getSubscribersForStream() O método de um objeto Session retorna todos os objetos Subscriber de um Stream.
Talvez você queira impedir o comportamento padrão e manter o Subscriber, caso deseje ajustar os elementos DOM relacionados antes de excluir o Subscriber por conta própria. Em seguida, você pode excluir o objeto Subscriber (e seu elemento DOM) chamando o destroy() método do objeto Subscriber.
Um objeto Subscriber despacha um destroyed evento que ocorre quando o objeto é removido do DOM HTML. Em resposta a esse evento, você pode optar por ajustar (ou remover) os elementos do DOM relacionados ao assinante que foi removido.
Reconexão automática
Se um cliente perder a conexão com um fluxo assinado (por exemplo, devido a uma queda na conectividade de rede em qualquer um dos clientes), ele tentará se reconectar automaticamente ao fluxo. Quando a conexão com o fluxo é perdida e o cliente tenta se reconectar, o objeto Subscriber dispara um disconnected evento. Quando o fluxo é restaurado, o objeto Subscriber dispara um connected evento. Se o cliente não conseguir restaurar o fluxo, o objeto Subscriber dispara um destroyed evento.
Em resposta a esses eventos, seu aplicativo pode (opcionalmente) exibir notificações na interface do usuário indicando os estados de desconexão temporária, reconexão e destruição:
subscriber.on(
disconnected: function() {
// Display a user interface notification.
},
connected: function() {
// Adjust user interface.
},
destroyed: function() {
// Adjust user interface.
}
);
Restrição da taxa de quadros de uma transmissão assinada
Você também pode restringir a taxa de quadros do fluxo de vídeo de um assinante. Para restringir a taxa de quadros de um assinante, chame a função restrictFrameRate() método do objeto Subscriber, passando true:
subscriber.restrictFrameRate(true);
Passe para false e a taxa de quadros do fluxo de vídeo não é limitada:
subscriber.restrictFrameRate(false);
Quando a taxa de quadros é limitada, o quadro de vídeo do Assinante será atualizado uma vez ou menos por segundo.
Esse recurso está disponível apenas em sessões que utilizam o OpenTok Media Router (sessões com o modo de mídia (definido como “routed”), e não em sessões com o modo de mídia definido como “relayed”. Em sessões “relayed”, a chamada a este método não produz nenhum efeito.
A restrição da taxa de quadros do assinante traz os seguintes benefícios:
- Isso reduz o uso da CPU.
- Isso reduz a largura de banda da rede consumida pelo aplicativo.
- Isso permite que você assine mais canais simultaneamente.
A redução da taxa de quadros de um assinante não afeta a taxa de quadros do vídeo em outros clientes.
Detectar quando o áudio de um assinante está bloqueado ou desbloqueado
Alguns navegadores bloqueiam automaticamente a reprodução de áudio, exigindo um click evento que ocorre antes do início da reprodução de áudio para os assinantes. Esses navegadores incluem o Safari, o Firefox 66+ e o Chrome 71+.
O objeto Subscriber exibe um botão de reprodução de áudio caso a reprodução esteja bloqueada. É possível desativar o botão padrão de reprodução de áudio do Subscriber e exibir seu próprio elemento de interface do usuário, no qual o usuário clicará para iniciar a reprodução de áudio. Consulte Exibição de um elemento de interface do usuário personalizado quando o áudio do assinante estiver bloqueado.
Quando o áudio do assinante é bloqueado, o objeto `Subscriber` dispara um audioBlocked evento e dispara um audioUnblocked evento quando o áudio é desbloqueado:
subscriber.on({
audioBlocked: function(event) {
console.log("Subscriber audio is blocked.")
},
audioUnblocked: function(event) {
console.log("Subscriber audio is unblocked.")
}
});
Além disso, o Assinante inclui um isAudioBlocked() que retorna true se o áudio estiver bloqueado ou false se não for.
O áudio do assinante é desbloqueado quando ocorre qualquer uma das seguintes situações:
- O usuário clica no ícone padrão de reprodução de áudio do assinante
- O OT.unblockAudio() O método é chamado em resposta a um elemento HTML que dispara um
clickevento (caso você tenha desativado o ícone padrão de reprodução de áudio) - O cliente local obtém acesso à câmera ou ao microfone (por exemplo, em resposta a uma chamada bem-sucedida para
OT.initPublisher()).
Para obter mais informações, consulte este artigo da Mozilla sobre a reprodução automática no Firefox e este artigo do Google sobre a reprodução automática no Chrome.
Detectar quando o vídeo de um assinante está desativado
Quando o vídeo do assinante é desativado, o objeto Subscriber dispara um videoDisabled evento:
subscriber.on("videoDisabled", function(event) {
// You may want to hide the subscriber video element:
domElement = document.getElementById(subscriber.id);
domElement.style["visibility"] = "hidden";
// You may want to add or adjust other UI.
});
Quando o OpenTok Media Router, ou um editor com a função de fallback ativada, desativa o vídeo de um assinante, talvez seja necessário ajustar a interface do usuário relacionada a esse assinante.
O reason propriedade do videoDisabled O objeto de evento define o motivo pelo qual o vídeo foi desativado. Ele pode ser definido com um dos seguintes valores:
-
"publishVideo"— A editora interrompeu a publicação de vídeos por meio de uma ligaçãopublishVideo(false). -
"quality"— O OpenTok Media Router, ou o cliente de publicação, se opção alternativa de áudio do editor Quando ativada, essa função interrompe o envio de vídeo ao assinante com base em alterações na qualidade do stream. Esse recurso do OpenTok Media Router faz com que o assinante interrompa o stream de vídeo quando a conectividade se deteriora. (O assinante continua recebendo o stream de áudio, se houver.) O recurso de fallback de áudio do editor faz com que o editor interrompa a transmissão do fluxo de vídeo quando a conectividade do editor se deteriora e, consequentemente, o assinante interrompe o fluxo de vídeo.Antes de enviar esse evento, quando a qualidade do stream do Assinante se deteriora, ou quando a qualidade do stream de um editor com a função de fallback ativada se deteriora, a um nível baixo o suficiente para que o stream de vídeo corra o risco de ser desativado, o Assinante envia um
videoDisableWarningevento.Se a conectividade melhorar a ponto de permitir novamente a exibição de vídeo, o objeto Subscriber dispara um
videoEnabledevento, e o assinante volta a receber o vídeo.Por padrão, o Subscriber exibe um indicador de vídeo desativado quando um
videoDisabledO evento com esse motivo é acionado e remove o indicador quando ovideoDisabledO evento com esse motivo é acionado. Você pode controlar a exibição desse ícone chamando osetStyle()método do Assinante, definindo ovideoDisabledDisplayModepropriedade; ou você pode definir o estilo ao chamar oSession.subscribe()método, definindo ostylepropriedade dopropertiesparâmetro.Esse recurso está disponível apenas em sessões que utilizam o OpenTok Media Router (sessões com o modo de mídia (configurado como “routed”) ou em sessões com um editor com fallback ativado. Consulte a seção “Fallback ativado no editor” documentos.
Ao publicar uma transmissão, você pode evitar que o vídeo seja desativado devido à qualidade da transmissão. Defina
audioFallbackEnabledparafalsenopropertiesobjeto passado para o OT.initPublisher() método (esse recurso será descontinuado) ou definirsubscriberparafalsenoaudioFallbackobjeto passado como opropertiesparâmetro do OT.initPublisher() método. -
"subscribeToVideo"— O assinante ativou ou cancelou a assinatura do serviço de vídeo por meio de uma ligaçãosubscribeToVideo(false). -
"codecNotSupported"— O assinante interrompeu a assinatura do vídeo devido a um codec incompatível (consulte o Codecs de vídeo (guia do desenvolvedor).
O assinante envia um videoEnabled evento quando o vídeo for retomado:
subscriber.on("videoEnabled", function(event) {
// You may want to display the subscriber video element,
// if it was hidden:
domElement = document.getElementById(subscriber.id);
domElement.style["visibility"] = "visible";
// You may want to add or adjust other UI.
});
O reason propriedade do videoEnabled O objeto de evento define o motivo pelo qual o vídeo foi ativado. Ele pode ser definido com um dos seguintes valores:
-
"publishVideo"— A editora começou a publicar vídeos por meio de uma ligaçãopublishVideo(true). -
"quality"— O OpenTok Media Router, ou o emissor com recurso de fallback ativado, retomou o envio do vídeo ao assinante com base nas mudanças na qualidade do stream. Esse recurso do OpenTok Media Router faz com que o assinante interrompa o stream de vídeo quando a conectividade se deteriora e, em seguida, retome o stream de vídeo caso a qualidade do stream melhore. O recurso de fallback de áudio do emissor faz com que o emissor interrompa a transmissão do vídeo quando a conectividade do emissor piora e, consequentemente, o assinante interrompa a transmissão do vídeo.Esse recurso está disponível apenas em sessões que utilizam o OpenTok Media Router (sessões com o modo de mídia (definido como “routed”), ou em sessões com um emissor com a opção de fallback ativada.
-
"subscribeToVideo"— O assinante ativou ou cancelou a assinatura do serviço de vídeo por meio de uma ligaçãosubscribeToVideo(false). -
"codecChanged"— O vídeo para assinantes foi habilitado após uma mudança de codec, que antes era incompatível (consulte o Codecs de vídeo (guia do desenvolvedor).
Detectar quando as dimensões do vídeo da transmissão de um assinante mudam
As dimensões do vídeo transmitido por um assinante podem mudar se uma transmissão publicada a partir de um dispositivo móvel for redimensionada, devido a uma mudança na orientação do dispositivo. Isso também pode ocorrer se a fonte do vídeo for uma janela de compartilhamento de tela e o usuário que está publicando a transmissão redimensionar a janela que serve de fonte para a transmissão. Quando as dimensões do vídeo mudam, o objeto Subscriber dispara um videoDimensionsChanged evento.
O código a seguir redimensiona um assinante quando as dimensões do vídeo do stream mudam:
subscriber.on('videoDimensionsChanged', function(event) {
subscriber.element.style.width = event.newValue.width + 'px';
subscriber.element.style.height = event.newValue.height + 'px';
// You may want to adjust other UI.
});
Obter informações sobre um fluxo
O objeto Stream possui as seguintes propriedades que definem o fluxo:
connection—O objeto `Connection` correspondente à conexão que está publicando o fluxo. Você pode comparar isso com oconnectionpropriedade do objeto Session para verificar se o fluxo está sendo publicado pela página da web local.creationTime—O carimbo de data/hora (um número) correspondente à criação do fluxo. Esse valor é calculado em milissegundos. É possível converter esse valor em um objeto Date chamandonew Date(stream.creationTime).hasAudio—(Booleano) Indica se o stream possui áudio. Essa propriedade pode mudar se o editor ativar ou desativar o áudio (chamando Publisher.publishAudio()). Quando isso ocorre, o Sessão o objeto despacha umstreamPropertyChangedevento.hasVideo—(Booleano) Se a transmissão contém vídeo.initials—(Booleano) As iniciais do fluxo (caso tenham sido definidas quando o editor do fluxo foi inicializado).name—(String) O nome do fluxo. Por padrão, ele é exibido quando o usuário passa o mouse sobre o Assinante no DOM HTML. No entanto, é possível personalizar a interface do usuário para ocultar o nome ou exibi-lo sem precisar passar o mouse sobre ele.videoDimensions—Este objeto possui duas propriedades:widtheheight. Ambos são números. OwidthA propriedade é a largura do fluxo codificado; oheightEssa propriedade representa a altura do fluxo codificado. (Esses valores são independentes da largura real dos objetos Publisher e Subscriber correspondentes ao fluxo.) Essa propriedade pode mudar se um fluxo publicado a partir de um dispositivo iOS for redimensionado, devido a uma mudança na orientação do dispositivo.videoType—O tipo de vídeo: pode ser “câmera”, “tela”, “personalizado” ou indefinido. Um vídeo do tipo “tela” utiliza o compartilhamento de tela no editor como fonte de vídeo; um vídeo do tipo “personalizado” utiliza um elemento VideoTrack como fonte de vídeo no editor. OvideoTypeéundefinedquando uma transmissão é apenas de voz (consulte o Guia apenas por voz). Essa propriedade pode mudar se uma transmissão publicada a partir de um dispositivo móvel passar de um tipo de vídeo capturado pela câmera para um tipo de vídeo de compartilhamento de tela. Para obter mais informações, consulte Compartilhamento de tela — Web.
O hasAudio, hasVideo, videoDimensions, e videoType as propriedades podem mudar (por exemplo, quando o apresentador liga ou desliga o vídeo). Quando isso ocorre, o Sessão o objeto despacha um streamPropertyChanged evento (ver StreamPropertyChangedEvent.)
O getStats() O método de um objeto Subscriber fornece informações sobre o fluxo do assinante. Para obter estatísticas de baixo nível sobre a conexão entre pares, use o Subscriber.getRtcStatsReport() método. Ele retorna uma promessa que, em caso de sucesso, é resolvida com um RtcStatsReport objeto para o fluxo assinado.
Consulte Guia do desenvolvedor sobre observabilidade do cliente para obter informações detalhadas.
Como definir a taxa de quadros e a resolução preferidas
Ao assinar um stream que utiliza o recurso de vídeo escalável, você tem a opção de definir preferredResolution para "auto" para gerenciar automaticamente a resolução do vídeo do assinante com base no tamanho que está sendo renderizado, a fim de otimizar o uso da rede e da CPU. Para usuários avançados, também é possível definir manualmente a taxa de quadros e a resolução preferidas para a transmissão que o cliente assinante recebe do OpenTok Media Router. Você pode definir esses parâmetros como preferredFrameRate e preferredResolution propriedades do options você entra no [`Session.subscribe()`](/video/sdk-reference/js/Session.html#subscribe) método. Recomendamos definir preferredResolution para "auto". Com o "auto" Com essa configuração, o OpenTok.js seleciona a resolução preferencial com base nas dimensões do vídeo do Assinante no navegador. Você também pode definir a taxa de quadros e a resolução preferenciais após se inscrever em uma transmissão (consulte [`Subscriber.setPreferredFrameRate()`](/opentok/sdks/js/reference/Subscriber.html#setPreferredFrameRate) e Subscriber.setPreferredResolution()).
Observação: O "auto" A configuração de resolução só se aplica quando você usa o elemento “Subscriber Video” padrão criado pelo SDK. Ela não funciona se você criar seu próprio elemento “Video” em resposta ao videoElementCreated evento (ver esse assunto).
Observação: Essas preferências pressupõem que o editor esteja utilizando o layout padrão da camada de escalabilidade. Se o editor tiver definido um modo de escalabilidade de destino diferente do padrão (consulte Definição do modo de escalabilidade alvo), a seleção de camada do Media Router pode não corresponder à resolução ou à taxa de quadros solicitada. Consulte Interação com a resolução e a taxa de quadros preferidas pelo assinante para mais detalhes.
Aplicação de filtros e efeitos a arquivos de áudio e vídeo inscritos
É possível aplicar filtros e efeitos às faixas de áudio ou vídeo de um stream assinado — consulte esse assunto.
Detecção de alterações na qualidade de áudio e vídeo
Se um cliente passar por períodos de conectividade de rede prejudicada, isso pode se refletir na qualidade da chamada do assinante. O objeto Assinante envia um qualityScoreChanged evento que ocorre quando as pontuações MOS calculadas para áudio e vídeo mudam. Essas pontuações são apresentadas como números inteiros entre 1 (pior) e 5 (melhor), correspondendo a ruim, insatisfatório, razoável, bom e excelente. Para mais detalhes, consulte o Assinante qualityScoreChanged evento.
Um objeto Subscriber dispara esse evento somente quando uma das pontuações de qualidade sofre alteração. Cada Subscribe dispara eventos com suas próprias pontuações de qualidade de áudio e vídeo, dependendo se está se inscrevendo para receber áudio, vídeo ou ambos.
Em resposta a esses eventos, seu aplicativo pode (opcionalmente) notificar o cliente sobre as condições da rede que estão causando a degradação da qualidade da chamada:
subscriber.on('qualityScoreChanged', ({qualityScore}) => {
if (qualityScore.audioQualityScore <= 3){
// Alert the user that the remote party is experiencing degraded service
}
if (qualityScore.videoQualityScore <= 3){
// Alert the user that the remote party is experiencing degraded service
}
});
Solução de problemas
Siga as dicas desta seção para evitar problemas de conectividade ao fazer a assinatura. Para obter informações gerais sobre solução de problemas, consulte Depuração — Web.
Tratamento de erros
Lidar com erros ao se inscrever é um pouco mais fácil do que ao publicar. Há apenas uma maneira de se inscrever — com o Session.subscribe() — e praticamente qualquer erro que ocorra durante a assinatura se resume a um problema de rede. Isso pode acontecer se, por exemplo, o usuário estiver em uma conexão de rede muito restritiva que não permita conexões WebRTC (mas a conexão WebSocket funcionou). Se o Assinante não conseguir se conectar, ele simplesmente exibirá sua própria mensagem de erro internamente. Isso não fica muito bom e não é muito informativo para o usuário final. Recomendamos que você mesmo lide com esse caso e exiba uma mensagem ao usuário indicando que a assinatura falhou e que ele deve verificar sua conexão de rede. O tratamento desses erros é feito da seguinte forma:
session.subscribe(event.stream, 'subscriber', {insertMode: 'append'}, function (err) {
if (err) {
showMessage('Streaming connection failed. This could be due to a restrictive firewall.');
}
});
Perda de conectividade
Seu Assinante também pode perder a conexão depois de já ter conseguido se conectar. Na maioria das vezes, isso também fará com que a sessão perca a conexão, mas nem sempre é assim. Além disso, pode ser que o editor do outro lado tenha perdido a conexão, em vez de a conexão ter sido perdida localmente. Você pode lidar com a desconexão do assinante monitorando o streamDestroyed evento na sessão com um reason propriedade definida como “networkDisconnected”, desta forma:
session.on({
streamDestroyed: function (event) {
if (event.reason === 'networkDisconnected') {
event.preventDefault();
var subscribers = session.getSubscribersForStream(event.stream);
if (subscribers.length > 0) {
var subscriber = document.getElementById(subscribers[0].id);
// Display error message inside the Subscriber
subscriber.innerHTML = 'Lost connection. This could be due to your internet connection '
+ 'or because the other party lost their connection.';
event.preventDefault(); // Prevent the Subscriber from being removed
}
}
}
});
Implementação de novas tentativas de assinatura de sessão
Podem ocorrer falhas temporárias na assinatura quando session.subscribe() é chamado e a conexão WebRTC subjacente não pode ser estabelecida a tempo, ou quando uma falha momentânea na rede interrompe a negociação do ICE. Quando session.subscribe() Se falhar, o SDK retorna um erro por meio do callback do manipulador de conclusão. A abordagem recomendada é implementar uma lógica de repetição de tentativa no nível do aplicativo, com um intervalo entre as tentativas.
Observação: Suporte integrado para repetição de tentativas para session.subscribe() está no roteiro do SDK. Até que isso seja lançado, você precisará implementar isso por conta própria.
Por que ocorrem falhas nas assinaturas
As causas principais mais comuns para falhas transitórias na assinatura são:
OT_TIMEOUT(código 1501): A assinatura não foi concluída dentro do intervalo de tempo permitido (30 segundos). Esse é o equivalente, do lado da assinatura, ao tempo limite de publicação e é o erro mais comum que pode ser repetido.- Fracassos nas negociações do ICE (
OT_ICE_WORKFLOW_FAILED): Não foi possível estabelecer a conexão entre pares via WebRTC, geralmente devido a uma rede restritiva ou a um problema temporário de conectividade. - Falhas na criação de conexões entre pares (
OT_CREATE_PEER_CONNECTION_FAILED): Não foi possível criar o objeto de conexão entre pares do WebRTC, o que geralmente é causado por um problema temporário na plataforma ou na rede. - Problemas de rede durante o processo de assinatura: Uma breve interrupção na rede durante a negociação do ICE ou a vinculação de mídia pode fazer com que a assinatura expire sem que ocorra um erro grave.
Erros recuperáveis x erros não recuperáveis
Nem todos session.subscribe() nem todos os erros são iguais. É essencial classificar os erros corretamente antes de tentar novamente — tentar novamente em caso de um erro irrecuperável desperdiça tempo e pode mascarar falhas reais.
Observação: Sempre use o error.name propriedade para identificar erros programaticamente. O valor numérico error.code A propriedade está obsoleta.
Erros irrecuperáveis — Não tente novamente
Esses erros representam restrições rígidas, contexto de chamada inválido ou estados do fluxo do terminal. Repetir a tentativa não resolverá esses erros.
error.name |
Descrição | Ação recomendada |
|---|---|---|
OT_NOT_CONNECTED |
session.subscribe() foi chamada antes que a sessão fosse estabelecida. |
Certifique-se de que session.connect() tenha sido concluído com sucesso antes de se inscrever. |
OT_DISCONNECTED |
A ação falhou porque o cliente não está conectado à sessão. | Aguarde até que a sessão se reconecte antes de tentar novamente. |
OT_INVALID_PARAMETER |
Um ou mais parâmetros passados para session.subscribe() eram inválidos (por exemplo, fluxo nulo ou elemento de destino). |
Corrija a lógica da aplicação. Não tente novamente. |
OT_STREAM_DESTROYED |
A transmissão foi encerrada antes que fosse possível se inscrever nela. | Não tente novamente — o fluxo não existe mais. Remova qualquer estado de assinatura pendente para esse fluxo. |
OT_STREAM_NOT_FOUND |
Não foi possível localizar o stream na sessão. | Não tente novamente — o stream não está mais disponível. |
OT_STREAM_LIMIT_EXCEEDED |
A sessão ultrapassou o limite de transmissões simultâneas. | Informe o usuário. Não tente novamente até que um slot de fluxo fique disponível. |
OT_UNABLE_TO_SUBSCRIBE |
O usuário tentou se inscrever em uma sessão com criptografia de ponta a ponta (E2EE) ativada sem especificar um segredo de criptografia; ou um erro inesperado impediu a inscrição. | Para sessões com criptografia de ponta a ponta (E2EE), certifique-se de que um segredo de criptografia esteja definido por meio de session.setEncryptionSecret() antes de se inscrever. No caso geral, registre o erro e informe o usuário. |
Erros recuperáveis — É seguro tentar novamente
Esses erros são normalmente causados por condições transitórias da rede, tempo limite de sinalização ou indisponibilidade temporária da plataforma.
error.name |
Descrição | Ação recomendada |
|---|---|---|
OT_TIMEOUT (código 1501) |
A assinatura não foi concluída dentro de um prazo razoável. Esse é o erro mais comum na assinatura que pode ser repetido. | Cancele a inscrição e, em seguida, tente novamente com intervalo entre tentativas (até 3 tentativas). |
OT_ICE_WORKFLOW_FAILED |
A negociação ICE falhou — não foi possível estabelecer a conexão entre pares. Isso costuma ocorrer temporariamente em redes restritivas. | Cancele a inscrição e tente novamente. Se o problema persistir após todas as tentativas, informe o usuário sobre um possível problema de rede ou firewall. |
OT_CREATE_PEER_CONNECTION_FAILED |
Não foi possível estabelecer a conexão entre pares via WebRTC. Isso pode indicar um firewall restritivo ou um problema temporário na plataforma. | Cancele a inscrição e tente novamente. Se o problema persistir, sugira que o usuário verifique sua conexão de rede. |
OT_SET_REMOTE_DESCRIPTION_FAILED |
A conexão WebRTC falhou durante setRemoteDescription. Normalmente, trata-se de um problema temporário de sinalização. |
Cancele a inscrição e, em seguida, tente novamente com um intervalo. |
OT_MEDIA_ERR_ABORTED / OT_MEDIA_ERR_NETWORK |
A aquisição da mídia foi cancelada ou interrompida devido a um erro de rede. | Cancele a inscrição e tente novamente após um breve intervalo. |
OT_MEDIA_ERR_DECODE |
Ocorreu um erro de decodificação ao tentar reproduzir o stream no elemento de vídeo. | Cancele a inscrição e tente novamente após um breve intervalo. Se o problema persistir, o formato da mídia pode ser incompatível. |
OT_MEDIA_ERR_SRC_NOT_SUPPORTED |
Foi detectado que o stream não é adequado para reprodução. | Cancele a inscrição e tente novamente uma vez. Se o problema persistir, verifique a configuração do elemento de vídeo do assinante. |
Importante: sempre cancele a inscrição antes de tentar novamente
Ao contrário de session.publish(), onde a instância do editor muitas vezes pode ser reutilizada diretamente, session.subscribe() exige que você ligue session.unsubscribe() e descarte o objeto do assinante antes de tentar novamente. A tentativa de reutilizar uma instância de assinante com falha não funcionará.
async function subscribeWithRetry(session, stream, targetElement, options, attempt = 1) {
const MAX_RETRIES = 3;
const RETRY_DELAY_MS = 3000;
let subscriber = session.subscribe(stream, targetElement, options);
const error = await new Promise((resolve) => {
subscriber.on('subscribeComplete', (err) => resolve(err));
});
if (!error) {
console.log('Subscribed successfully.');
return subscriber;
}
// Always clean up the failed subscriber before retrying
try { session.unsubscribe(subscriber); } catch (e) { /* ignore */ }
// Non-recoverable: do not retry
const nonRetryable = [
'OT_NOT_CONNECTED',
'OT_DISCONNECTED',
'OT_INVALID_PARAMETER',
'OT_STREAM_DESTROYED',
'OT_STREAM_NOT_FOUND',
'OT_STREAM_LIMIT_EXCEEDED',
'OT_UNABLE_TO_SUBSCRIBE',
];
if (nonRetryable.includes(error.name)) {
console.error('Non-retryable subscribe error:', error.name);
handleNonRecoverableError(error);
return null;
}
// Recoverable: retry with backoff
if (attempt < MAX_RETRIES) {
console.warn(`Subscribe attempt ${attempt} failed (${error.name}), retrying...`);
await delay(RETRY_DELAY_MS * attempt);
return subscribeWithRetry(session, stream, targetElement, options, attempt + 1);
}
console.error('All subscribe attempts failed.');
handleSubscribeFailure(session, stream);
return null;
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function handleNonRecoverableError(error) {
// Surface a meaningful message to the user based on error.name
}
function handleSubscribeFailure(session, stream) {
// Inform the user that the stream could not be loaded
}
Modo de uso:
session.on('streamCreated', (event) => {
subscribeWithRetry(session, event.stream, document.getElementById('subscriber'), {});
});
Cenários sensíveis ao tempo
O fluxo é encerrado durante uma tentativa de repetição
Se o fluxo for destruído enquanto uma nova tentativa estiver pendente, o streamDestroyed O evento de sessão será acionado. É necessário cancelar qualquer nova tentativa pendente para esse fluxo, a fim de evitar a assinatura de um fluxo que já não existe.
const pendingRetries = new Map(); // stream.id → timeout handle
session.on('streamDestroyed', (event) => {
const pending = pendingRetries.get(event.stream.id);
if (pending) {
clearTimeout(pending);
pendingRetries.delete(event.stream.id);
console.log(`Cancelled pending retry for destroyed stream: ${event.stream.id}`);
}
});
Reconexão da sessão durante uma nova tentativa de assinatura
Se a sessão estiver se reconectando (por exemplo, após uma queda na conexão de rede), adie a nova tentativa até que a sessão tenha se reconectado. Tentar fazer a assinatura enquanto a sessão estiver se reconectando resultará em falha imediata.
let isSessionReconnecting = false;
session.on('sessionReconnecting', () => { isSessionReconnecting = true; });
session.on('sessionReconnected', () => {
isSessionReconnecting = false;
// Re-trigger any deferred subscriptions here
});
// In your retry logic, check before retrying:
if (isSessionReconnecting) {
// Defer — wait for sessionReconnected before retrying
return;
}
O que NÃO fazer
- Faça não reutilizar uma instância de assinante com falha — sempre chamar
session.unsubscribe()e criar uma nova assinatura na nova tentativa. - Faça não tentar novamente em
OT_STREAM_DESTROYEDouOT_STREAM_NOT_FOUND— o stream não está mais disponível e qualquer nova tentativa sempre falhará. - Faça não tentar novamente em
OT_STREAM_LIMIT_EXCEEDED— trata-se de uma restrição de capacidade no nível da sessão, e não de um erro passageiro. - Faça não tentar novamente indefinidamente — limitar a 3 tentativas e informar o usuário caso todas falhem.
- Faça não tentar novamente enquanto a sessão está se reconectando — adiar até
sessionReconnectedincêndios.
Resumo dos parâmetros recomendados
| Parâmetro | Valor recomendado | Notas |
|---|---|---|
| Número máximo de tentativas | 3 | Em consonância com session.publish() orientações para nova tentativa |
| Atraso entre tentativas | 3 s × tentativa (3 s, 6 s, 9 s) | Um pouco mais longo do que as tentativas de reenvio de publicação — o tempo limite da assinatura é de 30 segundos |
| Em caso de falha em todas as tentativas de repetição | Informar o usuário | Evite encerrar a transmissão sem aviso prévio |
| Erros que não podem ser repetidos | OT_STREAM_DESTROYED, OT_STREAM_NOT_FOUND, OT_STREAM_LIMIT_EXCEEDED |
Falhe rápido nessas |
| Limpeza da lista de assinantes | Sempre session.unsubscribe() antes de tentar novamente |
Obrigatório — ao contrário dos editores, as instâncias de assinantes não podem ser reutilizadas |