Observabilidade do cliente: Android
O SDK de vídeo da Vonage disponibiliza métricas detalhadas sobre a qualidade do fluxo por meio de uma API de estatísticas de alto nível — recomendada para a maioria dos casos de uso —, que fornece estatísticas de áudio, vídeo, rede e do lado do remetente de forma unificada e sensível à sessão, mantendo-se estável durante as transições entre conexões entre pares. Para depuração avançada, o SDK também oferece acesso ao relatório bruto de estatísticas do WebRTC, que reflete dados não processados das conexões entre pares.
O SDK também disponibiliza métricas de condição de rede que oferecem uma avaliação geral do estado da conexão, tanto para emissores quanto para assinantes. Essas métricas incluem uma pontuação de condição de rede, o motivo por trás dessa pontuação e — para os assinantes — uma fonte de degradação que indica qual lado da conexão é responsável por quaisquer problemas observados. Consulte Condição da rede e fonte de degradação para mais detalhes.
API de estatísticas de links de áudio, vídeo e mídia
O SDK do Vonage Video para Android envia estatísticas periódicas de áudio, vídeo e links de mídia tanto para editores quanto para assinantes. Essas estatísticas incluem contagem de pacotes, taxas de bits, dados de taxa de quadros, métricas de pausa/congelamento, informações sobre codecs e métricas de rede no nível de transporte, como estimativa de largura de banda e pontuação das condições da rede.
As estatísticas são fornecidas por meio de ouvintes separados:
Editora:
PublisherKit.VideoStatsListener— estatísticas de vídeo e eventos relacionados à qualidade do vídeoPublisherKit.AudioStatsListener— estatísticas de áudioPublisherKit.MediaLinkStatsListener— estatísticas de link de mídia (nível de transporte)
Assinante:
SubscriberKit.VideoStatsListener— estatísticas de vídeo e eventos relacionados à qualidade do vídeoSubscriberKit.AudioStatsListener— estatísticas de áudioSubscriberKit.MediaLinkStatsListener— estatísticas de link de mídia (nível de transporte)
Ativação das estatísticas para editores
Estatísticas do vídeo
publisher.setVideoStatsListener(new PublisherKit.VideoStatsListener() {
@Override
public void onVideoStats(PublisherKit publisher, PublisherKit.PublisherVideoStats[] statsArray) {
if (statsArray != null && statsArray.length > 0) {
// For routed sessions, first element is sufficient.
// For relayed sessions, iterate all statsArray elements to get per-subscriber info.
PublisherKit.PublisherVideoStats stats = statsArray[0];
String connectionId = (stats.connectionId != null && !stats.connectionId.isEmpty())
? stats.connectionId
: "<none>";
String subscriberId = (stats.subscriberId != null && !stats.subscriberId.isEmpty())
? stats.subscriberId
: "<none>";
Log.d("VideoStats", "Publisher Video Stats for connectionId: " + connectionId
+ ", subscriberId: " + subscriberId);
Log.d("VideoStats", "Video bytes sent: " + stats.videoBytesSent);
Log.d("VideoStats", "Video packets sent: " + stats.videoPacketsSent);
Log.d("VideoStats", "Video packets lost: " + stats.videoPacketsLost);
Log.d("VideoStats", "Stats timestamp: " + stats.timeStamp + " ms");
if (stats.videoLayers != null) {
for (PublisherKit.VideoLayerStats layer : stats.videoLayers) {
Log.d("VideoStats", "Layer: " + layer.width + "x" + layer.height);
Log.d("VideoStats", " Encoded FPS: " + layer.encodedFrameRate);
Log.d("VideoStats", " Bitrate: " + layer.bitrate + " bps");
Log.d("VideoStats", " Total bitrate (incl. RTP overhead): " + layer.totalBitrate + " bps");
Log.d("VideoStats", " Codec: " + (layer.codec != null ? layer.codec : "unknown"));
Log.d("VideoStats", " Scalability mode: " + (layer.scalabilityMode != null ? layer.scalabilityMode : "none"));
Log.d("VideoStats", " Quality limitation: " + layer.qualityLimitationReason);
}
}
}
}
@Override
public void onVideoQualityChanged(PublisherKit publisher, PublisherKit.PublisherVideoStats stats, String reason) {
Log.d("Stats", "Publisher video quality event: " + reason);
}
});
Estatísticas de áudio
publisher.setAudioStatsListener(new PublisherKit.AudioStatsListener() {
@Override
public void onAudioStats(PublisherKit publisher, PublisherKit.PublisherAudioStats[] statsArray) {
if (statsArray != null && statsArray.length > 0) {
// For routed sessions, first element is sufficient.
// For relayed sessions, iterate all statsArray elements to get per-subscriber info.
PublisherKit.PublisherAudioStats stats = statsArray[0];
String connectionId = (stats.connectionId != null && !stats.connectionId.isEmpty())
? stats.connectionId
: "<none>";
String subscriberId = (stats.subscriberId != null && !stats.subscriberId.isEmpty())
? stats.subscriberId
: "<none>";
Log.d("AudioStats", "Publisher Audio Stats for connectionId: " + connectionId
+ ", subscriberId: " + subscriberId);
Log.d("AudioStats", "Audio bytes sent: " + stats.audioBytesSent);
Log.d("AudioStats", "Audio packets sent: " + stats.audioPacketsSent);
Log.d("AudioStats", "Audio packets lost: " + stats.audioPacketsLost);
Log.d("AudioStats", "Stats timestamp: " + stats.timeStamp + " ms");
}
}
});
Estatísticas de links de mídia
publisher.setMediaLinkStatsListener(new PublisherKit.MediaLinkStatsListener() {
@Override
public void onMediaLinkStats(PublisherKit publisher, PublisherKit.PublisherMediaLinkStats[] mediaLinkStats) {
if (mediaLinkStats != null && mediaLinkStats.length > 0) {
PublisherKit.PublisherMediaLinkStats stats = mediaLinkStats[0];
if (stats.transport != null) {
Log.d("MediaLinkStats", "Uplink bandwidth: " + stats.transport.getConnectionEstimatedBandwidth() + " bps");
Log.d("MediaLinkStats", "Network condition: " + stats.transport.networkCondition);
Log.d("MediaLinkStats", "Condition reason: " + stats.transport.networkConditionReason);
}
}
}
@Override
public void onNetworkConditionChanged(PublisherKit publisher, PublisherKit.PublisherMediaLinkStats mediaLinkStats, String reason) {
if (mediaLinkStats.transport != null) {
Log.d("Stats", "Publisher network condition: " + mediaLinkStats.transport.networkCondition);
Log.d("Stats", "Reason: " + mediaLinkStats.transport.networkConditionReason);
}
}
});
Veja Condição da rede e fonte de degradação para obter mais detalhes sobre como interpretar as pontuações e os motivos relativos às condições da rede.
Para um editor em uma sessão roteada (aquela que utiliza o Roteador de mídia de vídeo da Vonage), a matriz `stats` inclui um objeto, definindo as estatísticas para o fluxo único de mídia de áudio ou vídeo enviado ao Vonage Video Media Router. Em uma sessão retransmitida, a matriz `stats` inclui um objeto para cada assinante do fluxo publicado.
Ativação de estatísticas para assinantes
Estatísticas do vídeo
subscriber.setVideoStatsListener(new SubscriberKit.VideoStatsListener() {
@Override
public void onVideoStats(SubscriberKit subscriber, SubscriberKit.SubscriberVideoStats stats) {
Log.d("Stats", "Video bytes received: " + stats.videoBytesReceived);
}
@Override
public void onVideoQualityChanged(SubscriberKit subscriber, SubscriberKit.SubscriberVideoStats stats, String reason) {
Log.d("Stats", "Subscriber video quality event: " + reason);
}
});
Estatísticas de áudio
subscriber.setAudioStatsListener(new SubscriberKit.AudioStatsListener() {
@Override
public void onAudioStats(SubscriberKit subscriber, SubscriberKit.SubscriberAudioStats stats) {
Log.d("Stats", "Audio packets received: " + stats.audioPacketsReceived);
}
});
Estatísticas de links de mídia
subscriber.setMediaLinkStatsListener(new SubscriberKit.MediaLinkStatsListener() {
@Override
public void onMediaLinkStats(SubscriberKit subscriber, SubscriberKit.SubscriberMediaLinkStats mediaLinkStats) {
if (mediaLinkStats.transport != null) {
Log.d("MediaLinkStats", "Downlink bandwidth: " + mediaLinkStats.transport.getConnectionEstimatedBandwidth() + " bps");
}
if (mediaLinkStats.remotePublisherTransport != null) {
Log.d("MediaLinkStats", "Remote publisher uplink bandwidth: " + mediaLinkStats.remotePublisherTransport.getConnectionEstimatedBandwidth() + " bps");
}
Log.d("MediaLinkStats", "Degradation source: " + mediaLinkStats.networkDegradationSource);
}
@Override
public void onNetworkConditionChanged(SubscriberKit subscriber, SubscriberKit.SubscriberMediaLinkStats mediaLinkStats, String reason) {
if (mediaLinkStats.transport != null) {
Log.d("Stats", "Local network condition: " + mediaLinkStats.transport.networkCondition);
}
if (mediaLinkStats.remotePublisherTransport != null) {
Log.d("Stats", "Remote publisher network condition: " + mediaLinkStats.remotePublisherTransport.networkCondition);
}
Log.d("Stats", "Degradation source: " + mediaLinkStats.networkDegradationSource);
}
});
Veja Condição da rede e fonte de degradação para obter mais detalhes sobre como interpretar as pontuações e os motivos relativos às condições da rede.
Estruturas de dados estatísticos
Esta seção descreve as estruturas e propriedades fornecidas pela API de estatísticas de áudio e vídeo do Android. Embora todas as plataformas do SDK de vídeo apresentem o mesmo conjunto de estatísticas, pode haver pequenas diferenças na forma como cada plataforma estrutura ou nomeia os campos individuais. Essas variações refletem convenções de design do SDK específicas de cada plataforma, e não diferenças nas métricas subjacentes.
Para obter uma explicação independente de plataforma sobre as estatísticas disponíveis e o que elas representam, consulte Visão geral da observabilidade do cliente.
TransportStats
Representa métricas compartilhadas no nível do transporte.
connectionEstimatedBandwidth– Largura de banda estimada disponível para conexão (bps).networkCondition– Pontuação atual do estado da rede (NETWORK_CONDITION_UNKNOWN,NETWORK_CONDITION_CRITICAL,NETWORK_CONDITION_WARNING,NETWORK_CONDITION_FAIR,NETWORK_CONDITION_GOOD, ouNETWORK_CONDITION_EXCELLENT).networkConditionReason– Principal motivo que afeta o estado da rede (NETWORK_CONDITION_REASON_NONE,NETWORK_CONDITION_REASON_UNKNOWN,NETWORK_CONDITION_REASON_BANDWIDTH, ouNETWORK_CONDITION_REASON_PACKET_LOSS).
PublisherKit.PublisherVideoStats
Fornece estatísticas sobre a trilha de vídeo de um editor. Inclui:
connectionId– Em uma sessão retransmitida, o ID de conexão do cliente que está assinando o fluxo. Não definido em uma sessão roteada.subscriberId– Em uma sessão retransmitida, o ID de assinatura do cliente que está assinando o fluxo. Não definido em uma sessão roteada.videoPacketsLost– Estimativa de pacotes de vídeo perdidos.videoPacketsSent– Pacotes de vídeo enviados.videoBytesSent– Bytes de vídeo enviados.timeStamp– Carimbo de data/hora do Unix, em milissegundos, no momento em que as estatísticas foram coletadas.startTime– O carimbo de data e hora, em milissegundos desde a época Unix, a partir do qual os totais acumulados começaram a ser calculados.videoLayers– A matriz de estatísticas da camada de vídeo (consulteOTPublisherKitVideoLayerStats).
PublisherKit.PublisherAudioStats
Fornece estatísticas sobre a faixa de áudio de um editor. Inclui:
connectionId– Em uma sessão retransmitida, o ID de conexão do cliente que está assinando o fluxo. Não definido em uma sessão roteada.subscriberId– Em uma sessão retransmitida, o ID de assinatura do cliente que está assinando o fluxo. Não definido em uma sessão roteada.audioPacketsLost– Estimativa de pacotes perdidos.audioPacketsSent– Pacotes de áudio enviados.audioBytesSent– Trechos de áudio enviados.timeStamp– Carimbo de data/hora do Unix em milissegundos.startTime– O carimbo de data e hora, em milissegundos desde a época Unix, a partir do qual os totais acumulados começaram a ser calculados.
PublisherKit.VideoLayerStats
Representa uma camada de transmissão simultânea ou uma camada SVC.
width– Largura do quadro codificado.height– Altura do quadro codificado.encodedFrameRate– Quadros codificados por segundo.bitrate– Taxa de bits da camada (bps).totalBitrate– Taxa de bits da camada, incluindo a sobrecarga do RTP (bps).scalabilityMode– Descritor SVC/escalabilidade (por exemplo, “L3T3”).qualityLimitationReason– Motivo da limitação de qualidade (largura de banda, CPU, codec, resolução ou mudança de camada).codec– O codec utilizado por essa camada de vídeo.
SubscriberKit.SenderStats
Métricas de estimativa do lado do remetente (aplicadas tanto ao áudio quanto ao vídeo).
connectionMaxAllocatedBitrate– Taxa de bits máxima estimada para a conexão do remetente.connectionEstimatedBandwidth– Estimativa da largura de banda atual (bps).
SubscriberKit.SubscriberVideoStats
Fornece estatísticas sobre a trilha de vídeos de um assinante. Inclui:
videoPacketsLost– Estimativa de pacotes de vídeo perdidos.videoPacketsReceived– Pacotes de vídeo recebidos.videoBytesReceived– Bytes de vídeo recebidos.timeStamp– Carimbo de data/hora do Unix, em milissegundos, no momento em que as estatísticas foram coletadas.senderStats– Métricas do lado do remetente (opcional).width– Largura do quadro decodificado em pixels.height– Altura do quadro decodificado em pixels.decodedFrameRate– Quadros por segundo decodificados.bitrate– Taxa de bits do vídeo (bps).totalBitrate– Taxa de bits, incluindo a sobrecarga do RTP (bps).pauseCount– Número de pausas (mais de 5 s desde o último quadro). Inclui desativações intencionais e casos de recurso alternativo de áudio.totalPausesDuration– Duração total da pausa (ms).freezeCount– Contagem de congelamentos (evento de congelamento definido pelo WebRTC).totalFreezesDuration– Duração total do congelamento (ms).codec– Codec atual do decodificador.
SubscriberKit.SubscriberAudioStats
Fornece estatísticas sobre a trilha de áudio de um assinante. Inclui:
audioPacketsLost– Estimativa de pacotes perdidos.audioPacketsReceived– Pacotes recebidos.audioBytesReceived– Bytes recebidos.timeStamp– Carimbo de data/hora do Unix em milissegundos.senderStats– Métricas do lado do remetente (opcional).
PublisherKit.PublisherMediaLinkStats
Fornece estatísticas no nível do transporte para a conexão de um editor.
transport– Estatísticas de tráfego para esta editora (verTransportStats)
SubscriberKit.SubscriberMediaLinkStats
Fornece estatísticas no nível de transporte para as conexões de um assinante, incluindo visibilidade do desempenho da rede do editor remoto. Isso permite que as Applications diagnostiquem se os problemas de conexão se originam do downlink do assinante ou do uplink do editor.
transport– Estatísticas de transporte local e de rede para este assinante. Podem estar limitadas caso as estatísticas do lado do remetente e/ou o recurso de fallback de áudio estejam desativados.remotePublisherTransport– Estatísticas de transporte e de rede do editor remoto. Podem estar limitadas caso as estatísticas do lado do remetente e/ou o recurso alternativo de áudio estejam desativados.networkDegradationSource– Indica a origem da degradação da rede, se houver (NetworkDegradationSource.NONE,NetworkDegradationSource.LOCAL,NetworkDegradationSource.REMOTE, ouNetworkDegradationSource.BOTH_OR_UNCLEAR).
Estatísticas do lado do remetente
Veja o Visão geral das estatísticas do lado do remetente.
Ativação das estatísticas do remetente
As estatísticas do remetente são recebidas pelos assinantes. Para receber essas estatísticas, habilite-as para o editor do fluxo definindo o senderStatisticsTrack propriedade para true ao criar o editor:
Publisher publisher = new Publisher.Builder(context)
.senderStatsTrack(true) // Enable sender-side stats
.build();
Se senderStatsTrack Se não estiver habilitado, nenhum canal de estatísticas do remetente será publicado para esse editor. O valor padrão é false.
Recebimento de estatísticas do lado do remetente
Se o editor tiver ativado as estatísticas do lado do remetente, os assinantes as recebem automaticamente por meio dos callbacks de estatísticas de vídeo e áudio descrito acima. O senderStats propriedade em ambos SubscriberKit.SubscriberVideoStats e SubscriberKit.SubscriberAudioStats apresenta duas métricas:
connectionMaxAllocatedBitrate— A taxa de bits máxima que pode ser estimada para a conexãoconnectionEstimatedBandwidth— A largura de banda estimada atual para a conexão
Essas métricas são calculadas por pacote de áudio e vídeo; portanto, os mesmos valores aparecem tanto nas estatísticas de vídeo quanto nas de áudio.
subscriber.setVideoStatsListener((subscriber, stats) -> {
if (stats.senderStats != null) {
Log.d(TAG, "Connection max allocated bitrate: " + stats.senderStats.connectionMaxAllocatedBitrate);
Log.d(TAG, "Connection current estimated bandwidth: " + stats.senderStats.connectionEstimatedBandwidth);
}
});
Condição da rede e fonte de degradação
O SDK fornece métricas em tempo real sobre as condições da rede tanto para editores quanto para assinantes, incluindo uma pontuação de condição, o motivo por trás dessa pontuação e a origem da degradação para os assinantes. Para obter uma explicação completa sobre o modelo de condições da rede, as pontuações, os motivos e como ativá-lo, consulte o Visão geral da observabilidade do cliente.
Os dados sobre o estado da rede estão disponíveis por meio de dois canais:
- Estatísticas periódicas: As estatísticas de eventos de links de mídia incluem métricas de transporte com
networkConditionenetworkConditionReason. Para os assinantes, as estatísticas dos links de mídia também incluemremotePublisherTransportenetworkDegradationSource. - Eventos relacionados a alterações nas condições da rede: Callbacks dedicados em ambos editora e assinante são acionados quando é detectada uma mudança significativa nas condições da rede.
O exemplo a seguir mostra como usar os dados de condição da rede do assinante para identificar a origem da degradação:
@Override
public void onNetworkConditionChanged(SubscriberKit subscriber, SubscriberKit.SubscriberMediaLinkStats mediaLinkStats, String reason) {
int localCondition = mediaLinkStats.transport != null ? mediaLinkStats.transport.networkCondition : TransportStats.NETWORK_CONDITION_UNKNOWN;
int remoteCondition = mediaLinkStats.remotePublisherTransport != null ? mediaLinkStats.remotePublisherTransport.networkCondition : TransportStats.NETWORK_CONDITION_UNKNOWN;
int source = mediaLinkStats.networkDegradationSource;
if (source == NetworkDegradationSource.LOCAL) {
Log.d("Stats", "Local network is degraded (condition: " + localCondition + ")");
} else if (source == NetworkDegradationSource.REMOTE) {
Log.d("Stats", "Remote publisher network is degraded (condition: " + remoteCondition + ")");
} else if (source == NetworkDegradationSource.BOTH_OR_UNCLEAR) {
Log.d("Stats", "Degradation source unclear — local: " + localCondition + ", remote: " + remoteCondition);
}
}
Relatório de Estatísticas da RTC
Para obter estatísticas de conexão entre pares de baixo nível para um editor, use o PublisherKit.getRtcStatsReport() método. Isso fornece relatórios de estatísticas RTC para o fluxo de mídia. Trata-se de uma operação assíncrona. Chame o PublisherKit.setRtcStatsReportListener(PublisherKit.PublisherRtcStatsReportListener listener) método e, em seguida, implementar o PublisherKit.PublisherRtcStatsReportListener.onRtcStatsReport(PublisherKit publisher, PublisherKit.PublisherRtcStats[] stats) método antes de chamar PublisherKit.getRtcStatsReport().
Quando as estatísticas estiverem disponíveis, a implementação do PublisherKit.PublisherRtcStatsReportListener.onRtcStatsReport(PublisherKit publisher, PublisherKit.PublisherRtcStats[] stats) o método é chamado.
Uma variedade de PublisherRtcStats objetos são passados para esse método. O PublisherRtcStats O objeto inclui um jsonArrayOfReports propriedade. Trata-se de um array JSON de relatórios de estatísticas do RTC, cujo formato é semelhante ao do objeto RtcStatsReport implementado nos navegadores da web (consulte esses documentos da Mozilla).
Para obter estatísticas de conexão entre pares de baixo nível para um assinante, use o SubscriberKit.getRtcStatsReport() método. Isso fornece um relatório de estatísticas RTC para o fluxo de mídia.
Esta é uma operação assíncrona. Chame a SubscriberKit.setRtcStatsReportListener(SubscriberKit.SubscriberRtcStatsReportListener listener) método e, em seguida, implementar o SubscriberKit.SubscriberRtcStatsReportListener.onRtcStatsReport(SubscriberKit subscriber, java.lang.String jsonArrayOfReports) método antes de chamar SubscriberKit.getRtcStatsReport().
Quando as estatísticas estiverem disponíveis, a implementação do SubscriberKit.SubscriberRtcStatsReportListener.onRtcStatsReport(SubscriberKit subscriber, java.lang.String jsonArrayOfReports) método é chamado. O jsonArrayOfReports O parâmetro é um array JSON de relatórios de estatísticas do RTC, cujo formato é semelhante ao do objeto RtcStatsReport implementado nos navegadores da web (consulte esses documentos da Mozilla).
Veja também esta documentação do W3C.