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

Henrik Boström
Henrik Boström

A API WebRTC legada getStats() será removida no Chrome 117. Portanto, os apps que a usam precisarão migrar para a API padrão. Este artigo explica 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 WebRTC getStats(). A API getStats() legada, que antecede o processo de padronização e recebe um argumento de callback, e a API padronizada e amplamente compatível que retorna uma promessa.

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

No Chrome 117 e versões mais recentes, a API getStats() legada vai gerar uma exceção no canal de lançamento Stable (a exceção gerada será lançada gradualmente). Siga este guia para facilitar sua transição para a API padrão.

Tipos de estatísticas legadas e padrão

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

Todos os objetos de estatística têm um atributo id que identifica exclusivamente o objeto subjacente em várias chamadas getStats(). O mesmo objeto terá o mesmo ID todas as vezes que o método for chamado. Isso é útil para calcular a taxa de alteração de métricas (há um exemplo na próxima seção). Os IDs também formam relacionamentos 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. Se você desenhar todas as relações ...Id, um gráfico será gerado.

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


Tipo legado

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


Os tipos padrão para isso são inbound-rtp (para fluxos de RTP de recebimento e os MediaStreamTrack remotos associados), outbound-rtp (para streams de RTP de envio) e media-source (para métricas locais de MediaStreamTrack associadas a um fluxo de RTP de envio). As métricas de fluxo de RTP também contêm informações sobre o codificador ou decodificador usado pelo stream de RTP.
VideoBwe
Métricas de estimativa de largura de banda, taxa de bits de destino, 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 do par de candidatos ICE (candidate-pair).
googComponent
Representa o transporte (ICE e DTLS). A versão padrão é transport.
localcandidate and remotecandidate
Representa um candidato da ICE. A versão padrão é local-candidate e remote-candidate.
googCandidatePair
Representa um par de candidatos ICE, que é um par de um candidato local e um remoto. 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 não mapeie nada no padrão, o padrão tem um tipo associado ao RTCPeerConnection: peer-connection.

Ausente na API legada

Esses tipos de estatísticas foram adicionados à API padrão que não têm tipos legados correspondentes:
  • codec: um codec usado no momento por um stream RTP, seja para codificação ou decodificação. Esse é um subconjunto dos codecs negociados no SDP.
  • remote-inbound-rtp: o stream de RTP de entrada de um endpoint remoto correspondente a um stream de RTP de saída que este endpoint está enviando (outbound-rtp). Ele é medido no endpoint remoto e relatado em um Relatório de receptor RTCP (RR) ou Relatório estendido de RTCP (XR).
  • remote-outbound-rtp: o stream de RTP de saída de um endpoint remoto correspondente a um stream de RTP de entrada que esse endpoint está recebendo (inbound-rtp). Ele é medido no endpoint remoto e informado em um Relatório de Remetente (SR, na sigla em inglês) RTCP.
  • media-playout: métricas sobre a reproduçã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

Esse mapeamento tem como objetivo ajudar os desenvolvedores a encontrar 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 os contadores totais em vez de taxas. Isso significa que, para receber 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;

Ter que calcular taxas e médias por conta própria pode parecer complicado, mas tem a vantagem de permitir que você obtenha médias em qualquer intervalo de tempo desejado. Chamar a API padrão com menos frequência do que poderia ter a ver com a API legada tem alguns benefícios de desempenho.

Métrica legada
googCertificate
Correspondência padrão
certificate
.googFingerprint .fingerprint
.googFingerprintAlgorithm .fingerprintAlgorithm
.googDerBase64 .base64Certificate
Métrica legada
googComponent
Correspondência padrão
transport
.localCertificateId .localCertificateId
.remoteCertificateId .remoteCertificateId
.selectedCandidatePairId .selectedCandidatePairId
.dtlsCipher .dtlsCipher
.srtpCipher .srtpCipher
Métrica legada
localcandidate
Correspondência padrão
local-candidate ou candidate-pair
.stunKeepaliveRequestsSent candidate-pair.requestsSent (pesquisa reversa 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
remotecandidate
Correspondência padrão
remote-candidate
Igual ao localcandidate acima. Igual ao local-candidate acima.
Métrica legada
googCandidatePair
Correspondência padrão
candidate-pair
.responsesSent candidate-pair.responsesSent
.requestsReceived candidate-pair.requestsReceived
.googRemoteCandidateType remote-candidate.candidateType
(consulta remote-candidate por
candidate-pair.remoteCandidateId)
.googReadable googReadable é um booleano que indica se o candidate-pair.requestsReceived ou candidate-pair.responsesReceived foi incrementado recentemente
.googLocalAddress local-candidate.address
(consulta local-candidate por
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 indica se o candidate-pair.responsesReceived foi ou não incrementado recentemente
.googRemoteAddress remote-candidate.address
.googRtt candidate-pair.currentRoundTripTime
.googActiveConnection A conexão ativa se refere ao par candidato atualmente selecionado pelo transporte, como em que 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
ssrc
Correspondência padrão
inbound-rtp, outbound-rtp, media-source
.audioInputLevel media-source.audioLevel. A métrica legada está dentro do intervalo [0..32768], mas a métrica padrão está dentro do intervalo [0..1].
.audioOutputLevel
inbound-rtp.audioLevel A métrica legada está dentro do intervalo [0..32768], mas a métrica padrão está dentro do intervalo [0..1].
.packetsLost inbound-rtp.packetsLost
.googTrackId media-source.trackIdentifier para MediaStreamTracks locais e inbound-rtp.trackIdentifier para MediaStreamTracks remotas
.googRtt remote-inbound-rtp.roundTripTime (consulte outbound-rtp.remoteId)
.googEchoCancellationReturnLossEnhancement inbound-rtp.echoReturnLossEnhancement
.googCodecName O nome do codec é o subtipo do tipo MIME "tipo/subtipo", 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, ele é implementado como outbound-rtp.framesPerSecond, que é a codificação de FPS.
.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 a 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 o número de vezes que a resolução ou o frame rate mudou por motivos relacionados a qualityLimitationReason. Isso pode ser deduzido de outras métricas (por exemplo, a resolução de saída ou o frame rate diferente da resolução da origem ou do frame rate). No entanto, 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 foram reconfigurados.
.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 contendo a 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 em silêncio: 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 que foram sintetizadas para desacelerar a velocidade de 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
O único "goog-metric" restante. inbound-rtp.googTimingFrameInfo
.framesDecoded inbound-rtp.framesDecoded
Métrica legada
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 a outbound-rtp.retransmittedBytesSent
.googBucketDelay outbound-rtp.totalPacketSendDelay / outbound-rtp.packetsSent
.googTransmitBitrate A taxa de mudança de outbound-rtp.headerBytesSent + outbound-rtp.bytesSent para a taxa de bits por RTP, candidate-pair.bytesSent para taxa de bits de candidato a ICE ou transport.bytesSent para taxa de bits por transporte
.googRetransmitBitrate O intervalo de mudança de outbound-rtp.retransmittedBytesSent
.googAvailableSendBandwidth candidate-pair.availableOutgoingBitrate
.googAvailableReceiveBandwidth candidate-pair.availableIncomingBitrate

A API padrão reconhece a transmissão simultânea

Se você usa a transmissão simultânea, talvez a API legada informe apenas uma SSRC, mesmo quando você estiver usando a transmissão simultânea 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 SSRCs. Isso significa que é possível analisar cada stream de RTP individualmente, mas isso também significa que, para obter a taxa de bits total de todos os streams de envio de RTP, você precisará agregá-los por conta própria.

Os streams SVC ou RTP com várias camadas espaciais configuradas pela API scalabilityMode, por outro lado, 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 oferece mais tempo para os sites registrados migrarem. Com um token de teste de origem, a API getStats() legada pode continuar sendo usada até o Chrome 121.