WebRTC: guia de migração legado do getStats()

Henrik Boström
Henrik Boström

A API WebRTC getStats() legada será removida no Chrome 117. Os apps que a usam precisarão migrar para a API padrão. Neste artigo, explicamos como migrar seu código e o que fazer se você precisar de mais tempo para fazer essa alteração.

Historicamente, há duas versões concorrentes da API getStats() do WebRTC. A API getStats() legada, que é anterior ao processo de padronização e aceita um argumento de callback, e a API padronizada e amplamente compatível que retorna uma promessa.

A API padrão é mais repleta de recursos e tem métricas bem definidas e documentadas publicamente na especificação do W3C Identificadores para a API Statistics do WebRTC (em inglês). A especificação inclui descrições de cada métrica listada neste guia e muito mais.

No Chrome 117, a API getStats() legada gera uma exceção no canal de lançamento Stable. A geração da exceção será lançada gradualmente. Siga este guia e facilite a transição para a API padrão.

Tipos de estatísticas legados versus padrão

A lista completa dos tipos de estatísticas padrão pode ser encontrada no enum RTCStatsType na especificação. Isso inclui a definição do dicionário de estatísticas que descreve as métricas coletadas para cada tipo.

Todos os objetos de estatísticas têm um atributo de ID que identifica exclusivamente o objeto subjacente em várias chamadas de getStats(). O mesmo objeto terá o mesmo ID sempre que o método for chamado. Isso é útil para calcular a taxa de mudança de métricas (há um exemplo na próxima seção). Os IDs também formam relações de referências. Por exemplo, o objeto de estatísticas outbound-rtp faz referência ao objeto de estatísticas media-source associado usando o atributo outbound-rtp.mediaSourceId. Ao desenhar todas as relações ...Id, você recebe um gráfico.

A API legada tem os seguintes tipos de estatísticas, que correspondem aos tipos padrão da seguinte forma:


Tipo legado

Tipo padrão
ssrc
Representa um stream RTP e métricas sobre o MediaStreamTrack associado.


Os tipos padrão para isso são inbound-rtp (para streams de RTP recebidos e o MediaStreamTrack remoto associado a eles), outbound-rtp (para streams de RTP de envio) e media-source (para métricas locais de MediaStreamTrack associadas a um stream de RTP de envio). Elas também contêm informações sobre o codificador ou decodificador usado pelo stream RTP.
VideoBwe
Métricas de estimativa de largura de banda, taxa de bits desejada, taxa de bits do codificador e taxa de bits real. Esses tipos de métricas fazem parte das métricas de RTP (outbound-rtp e inbound-rtp) e de pares de candidatos ICE (candidate-pair).
googComponent
Representa o transporte (ICE e DTLS). A versão padrão é transport.
localcandidate and remotecandidate
Representa um candidato ICE. A versão padrão é local-candidate e remote-candidate.
googCandidatePair
Representa um par de candidatos ICE, que é um par de candidatos locais e remotos. A versão padrão é candidate-pair.
googCertificate
Representa um certificado usado pelo transporte DTLS. A versão padrão é certificate.
googLibjingleSession
Representa o RTCPeerConnection. Embora o conteúdo dele não seja mapeado para nada no padrão, ele tem um tipo associado ao RTCPeerConnection: peer-connection.

Ausência da API legada

Estes tipos de estatísticas foram adicionados à API padrão e não têm nenhum tipo legado correspondente:
  • codec: um codec que está sendo usado no momento por um stream RTP, seja para codificação ou decodificação. Esse é um subconjunto dos codecs que foram negociados no SDP.
  • remote-inbound-rtp: um stream RTP de entrada de um endpoint remoto correspondente a um stream RTP de saída que esse endpoint está enviando (outbound-rtp). Ela é medida no endpoint remoto e relatada em um relatório do receptor RTCP (RR, na sigla em inglês) ou em um relatório estendido do RTCP (XR, na sigla em inglês).
  • remote-outbound-rtp: um stream RTP de saída de um endpoint remoto correspondente a um stream RTP de entrada que esse endpoint está recebendo (inbound-rtp). Ele é medido no endpoint remoto e relatado em um relatório do remetente (SR, na sigla em inglês) do RTCP.
  • media-playout: métricas sobre a exibição de um MediaStreamTrack remoto associado a um stream de RTP de entrada (inbound-rtp).
  • data-channel: representa um RTCDataChannel.

Mapeamento de métricas legadas para padrão

O objetivo desse mapeamento é ajudar os desenvolvedores a descobrir qual métrica legada corresponde a qual métrica padrão. No entanto, a métrica correspondente pode usar unidades diferentes ou ser expressa como um contador total em vez de um valor instantâneo. Consulte a especificação para definições de métrica.
A API padrão prefere expor o total de contadores em vez de taxas. Isso significa que, para conseguir a taxa correspondente (por exemplo, taxa de bits), como na API legada, o app precisa calcular a taxa média usando o delta entre duas chamadas getStats(). Exemplo:

// Periodically (e.g. every second or every 10 seconds)...
const currReport = await pc.getStats();
// Calculate bitrate since the last getStats() call.
// Handling of undefined is omitted for clarity.
const currOutboundRtp = currReport.values().find(s => s.type == 'outbound-rtp');
const prevOutboundRtp = prevReport.get(currOutboundRtp.id);
const deltaBits = (currOutboundRtp.bytesSent - prevOutboundRtp.bytesSent) * 8;
const deltaSeconds = (currOutboundRtp.timestamp - prevOutboundRtp.timestamp) / 1000;
logBitrateMeasurement(deltaBits / deltaSeconds);
// Remember the report for next time.
prevReport = currReport;

Calcular as taxas e médias dessa forma pode parecer uma etapa adicional complicada, mas permite que você obtenha médias em qualquer intervalo de tempo desejado. Chamar a API padrão com menos frequência do que com a API legada gera alguns benefícios de desempenho.

Métrica legada
e googCertificate
Correspondência padrão
e certificate
.googFingerprint .fingerprint
.googFingerprintAlgorithm .fingerprintAlgorithm
.googDerBase64 .base64Certificate
Métrica legada
e googComponent
Correspondência padrão
e transport
.localCertificateId .localCertificateId
.remoteCertificateId .remoteCertificateId
.selectedCandidatePairId .selectedCandidatePairId
.dtlsCipher .dtlsCipher
.srtpCipher .srtpCipher
Métrica legada
e localcandidate
Correspondência padrão
local-candidate ou candidate-pair
.stunKeepaliveRequestsSent candidate-pair.requestsSent (pesquisa reversa de candidate-pair via candidate-pair.localCandidateId)
.portNumber local-candidate.port
.networkType local-candidate.networkType
.ipAddress local-candidate.address
.stunKeepaliveResponsesReceived candidate-pair.responsesReceived
.stunKeepaliveRttTotal candidate-pair.totalRoundTripTime
.transport local-candidate.protocol
.candidateType local-candidate.candidateType
.priority local-candidate.priority
Métrica legada
e remotecandidate
Correspondência padrão
e remote-candidate
Igual à localcandidate acima. Igual à local-candidate acima.
Métrica legada
e googCandidatePair
Correspondência padrão
e candidate-pair
.responsesSent candidate-pair.responsesSent
.requestsReceived candidate-pair.requestsReceived
.googRemoteCandidateType remote-candidate.candidateType
(pesquisa remote-candidate via
candidate-pair.remoteCandidateId)
.googReadable googReadable é um booleano que reflete se recentemente incrementamos candidate-pair.requestsReceived ou candidate-pair.responsesReceived
.googLocalAddress local-candidate.address
(pesquisa local-candidate via
candidate-pair.localCandidateId)
.consentRequestsSent candidate-pair.consentRequestsSent
.googTransportType Igual a local-candidate.protocol e remote-candidate.protocol.
.googChannelId candidate-pair.transportId
.googLocalCandidateType local-candidate.candidateType
.googWritable googWritable é um booleano que reflete se incrementamos candidate-pair.responsesReceived recentemente ou não.
.googRemoteAddress remote-candidate.address
.googRtt candidate-pair.currentRoundTripTime
.googActiveConnection A conexão ativa se refere ao par candidato selecionado no momento pelo transporte, como candidate-pair.id == transport.selectedCandidatePairId.
.packetsDiscardedOnSend candidate-pair.packetsDiscardedOnSend
.bytesReceived candidate-pair.bytesReceived
.responsesReceived candidate-pair.responsesReceived
.remoteCandidateId candidate-pair.remoteCandidateId
.localCandidateId candidate-pair.localCandidateId
.bytesSent candidate-pair.bytesSent
.packetsSent candidate-pair.packetsSent
.bytesReceived candidate-pair.bytesReceived
.bytesReceived candidate-pair.bytesReceived
Métrica legada
e ssrc
Correspondência padrão
inbound-rtp, outbound-rtp e media-source
.audioInputLevel media-source.audioLevel. A métrica legada está no intervalo [0..32768], mas a métrica padrão está no intervalo [0..1].
.audioOutputLevel
inbound-rtp.audioLevel. A métrica legada está no intervalo [0..32768], mas a métrica padrão está no intervalo [0..1].
.packetsLost inbound-rtp.packetsLost
.googTrackId media-source.trackIdentifier para MediaStreamTracks locais e inbound-rtp.trackIdentifier para MediaStreamTracks remotos
.googRtt remote-inbound-rtp.roundTripTime (consulte outbound-rtp.remoteId)
.googEchoCancellationReturnLossEnhancement inbound-rtp.echoReturnLossEnhancement
.googCodecName O nome do codec é o subtipo de "tipo/subtipo" tipo MIME, codec.mimeType (consulte inbound-rtp.codecId e outbound-rtp.codecId)
.transportId inbound-rtp.transportId e outbound-rtp.transportId
.mediaType inbound-rtp.kind e outbound-rtp.kind ou media-source.kind
.googEchoCancellationReturnLoss inbound-rtp.echoReturnLoss
.totalAudioEnergy inbound-rtp.totalAudioEnergy e media-source.totalAudioEnergy
ssrc.totalSamplesDuration inbound-rtp.totalSamplesDuration e media-source.totalSamplesDuration
.ssrc inbound-rtp.ssrc e outbound-rtp.ssrc
.googJitterReceived inbound-rtp.jitter
.packetsSent outbound-rtp.packetsSent
.bytesSent outbound-rtp.bytesSent
.googContentType inbound-rtp.contentType e outbound-rtp.contentType
.googFrameWidthInput media-source.width
.googFrameHeightInput media-source.height
.googFrameRateInput media-source.framesPerSecond
.googFrameWidthSent outbound-rtp.frameWidth
.googFrameHeightSent outbound-rtp.frameHeight
.googFrameRateSent
Embora o QPS de envio seja a taxa de mudança de outbound-rtp.framesSent, isso é implementado como outbound-rtp.framesPerSecond, que codifica QPS.
.googFrameWidthReceived inbound-rtp.frameWidth
.googFrameHeightReceived inbound-rtp.frameHeight
.googFrameRateDecoded
A taxa de mudança de inbound-rtp.framesDecoded
.googFrameRateOutput
Taxa de mudança de inbound-rtp.framesDecoded - inbound-rtp.framesDropped
.hugeFramesSent outbound-rtp.hugeFramesSent
.qpSum

inbound-rtp.qpSum e outbound-rtp.qpSum

.framesEncoded outbound-rtp.framesEncoded
.googAvgEncodeMs

outbound-rtp.totalEncodeTime / outbound-rtp.framesEncoded

.codecImplementationName

inbound-rtp.decoderImplementation e outbound-rtp.encoderImplementation

.googCpuLimitedResolution
Verdadeiro se outbound-rtp.qualityLimitationReason == "cpu"
.googBandwidthLimitedResolution
Verdadeiro se outbound-rtp.qualityLimitationReason == "bandwidth"
.googAdaptationChanges
A métrica legada conta quantas vezes a resolução ou o frame rate mudou por motivos relacionados ao qualityLimitationReason. Isso pode ser deduzido de outras métricas (por exemplo, se a resolução de envio ou o frame rate são diferentes da resolução da origem ou do frame rate), mas a duração limitada, outbound-rtp.qualityLimitationDurations, pode ser mais útil do que a frequência com que a resolução ou o frame rate alterado foi reconfigurado.
.googNacksReceived inbound-rtp.nackCount
.googNacksSent inbound-rtp.nackCount
.googPlisReceived inbound-rtp.pliCount
.googPlisSent inbound-rtp.pliCount
.googFirsReceived inbound-rtp.firCount
.googFirsSent inbound-rtp.firCount
.googSecondaryDecodedRate
A proporção recente de pacotes que contêm correção de erro: inbound-rtp.fecPacketsReceived - inbound-rtp.fecPacketsDiscarded
.packetsReceived inbound-rtp.packetsReceived
.googJitterBufferMs inbound-rtp.jitterBufferDelay / inbound-rtp.jitterBufferEmittedCount
.googTargetDelayMs (vídeo) inbound-rtp.jitterBufferTargetDelay / inbound-rtp.jitterBufferEmittedCount
.googPreferredJitterBufferMs (áudio) inbound-rtp.jitterBufferTargetDelay / inbound-rtp.jitterBufferEmittedCount
.googExpandRate
A proporção recente de amostras ocultas: inbound-rtp.concealedSamples / inbound-rtp.totalSamplesReceived
.googSpeechExpandRate A proporção recente de amostras ocultas enquanto o stream não estava silencioso: de (inbound-rtp.concealedSamples - inbound-rtp.silentConcealedSamples) / inbound-rtp.concealedSamples
.googAccelerateRate É a proporção recente de amostras que foram descartadas para acelerar a velocidade de reprodução: inbound-rtp.removedSamplesForAcceleration / inbound-rtp.totalSamplesReceived
.googPreemptiveExpandRate
É a proporção recente de amostras sintetizadas para desacelerar a velocidade da reprodução: inbound-rtp.insertedSamplesForDeceleration / inbound-rtp.totalSamplesReceived.
.googSecondaryDiscardedRate inbound-rtp.fecPacketsDiscarded
.bytesReceived inbound-rtp.bytesReceived
s.googCurrentDelayMs inbound-rtp.jitterBufferDelay + media-playout.totalPlayoutDelay
.googDecodeMs inbound-rtp.totalDecodeTime / inbound-rtp.framesDecoded
.googTimingFrameInfo
A única métrica do goog restante. inbound-rtp.googTimingFrameInfo
.framesDecoded inbound-rtp.framesDecoded
Métrica legada
e VideoBwe
Correspondência padrão
outbound-rtp e candidate-pair
.googTargetEncBitrate
outbound-rtp.targetBitrate como um valor instantâneo ou outbound-rtp.totalEncodedBytesTarget / outbound-rtp.framesEncoded como uma média
.googActualEncBitrate Os bytes produzidos pelo codificador são os bytes do payload, excluindo retransmissões: a taxa de mudança de outbound-rtp.bytesSent - outbound-rtp.retransmittedBytesSent
.googBucketDelay outbound-rtp.totalPacketSendDelay / outbound-rtp.packetsSent
.googTransmitBitrate A taxa de mudança de outbound-rtp.headerBytesSent + outbound-rtp.bytesSent para taxa de bits de stream por RTP, candidate-pair.bytesSent para taxa de bits de candidato por ICE ou transport.bytesSent para taxa de bits por transporte
.googRetransmitBitrate O intervalo da mudança de outbound-rtp.retransmittedBytesSent
.googAvailableSendBandwidth candidate-pair.availableOutgoingBitrate
.googAvailableReceiveBandwidth candidate-pair.availableIncomingBitrate

A API padrão reconhece transmissões simultâneas

Se você usa a transmissão simultânea, pode ter notado que a API legada só informa um único SSRC, mesmo quando você a usa para enviar (por exemplo) três streams de RTP em três SSRCs separados.

A API padrão não compartilha essa limitação e retorna três objetos de estatísticas outbound-rtp, um para cada um dos SSRCs. Isso significa que é possível analisar cada stream de RTP individualmente, mas também é necessário agregar todos eles para conseguir a taxa de bits total de todos os streams de RTP.

Por outro lado, os streams SVC ou RTP com várias camadas espaciais configuradas pela API scalabilityMode ainda aparecem como um único outbound-rtp porque são enviados por um único SSRC.

Se você precisar de mais tempo para a migração

Quando a API legada for removida no Chrome 117, o uso dela vai gerar uma exceção. Se você não conseguir migrar seu código a tempo, o teste de origem da API getStats() baseada em callback do RTCPeerConnection oferecerá mais tempo para a migração dos sites registrados. Com um token de teste de origem, a API getStats() legada pode continuar sendo usada até o Chrome 121.