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

Henrik Boström
Henrik Boström

A API getStats() WebRTC legada será removida no Chrome 117. Portanto, os apps que a usam vão precisar 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 mudança.

Historicamente, houve duas versões concorrentes da API getStats() do WebRTC. A API legada getStats(), 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 tem mais recursos e métricas bem definidas, documentadas publicamente na especificação do W3C Identifiers for WebRTC's Statistics API (em inglês). 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 estável. A exceção será lançada gradualmente. Siga este guia para facilitar a transição para a API padrão.

Tipos de estatísticas legados e padrão

A lista completa de tipos de estatísticas padrão pode ser encontrada na enumeração 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 id que identifica exclusivamente o objeto em várias chamadas getStats(). O mesmo objeto terá o mesmo ID sempre que o método for chamado. Isso é útil para calcular a taxa de mudança das métricas. Confira 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 pelo atributo outbound-rtp.mediaSourceId. Se você desenhar todas as relações ...Id, vai receber um gráfico.

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


Tipo legado

Padrão
ssrc
Representa um fluxo RTP e métricas sobre o MediaStreamTrack associado.


Os tipos padrão para isso são inbound-rtp (para receber streams RTP e o MediaStreamTrack remoto associado), outbound-rtp (para enviar streams RTP) e media-source (para métricas locais de MediaStreamTrack associadas a um stream RTP de envio). As métricas do fluxo RTP também contêm informações sobre o codificador ou decodificador usado pelo fluxo 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 das métricas de par de candidato 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 candidato ICE, que é um par de candidato local e 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 seja mapeado para 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 tem um tipo legados correspondente:
  • codec: um codec que está sendo usado por um stream RTP para codificação ou decodificação. Esse é um subconjunto dos codecs negociados no SDP.
  • remote-inbound-rtp: o fluxo RTP de entrada de um endpoint remoto correspondente a um fluxo RTP de saída que esse endpoint está enviando (outbound-rtp). Ele é medido no endpoint remoto e informado em um relatório de receptor RTCP (RR) ou um relatório estendido RTCP (XR).
  • remote-outbound-rtp: o fluxo RTP de saída de um endpoint remoto correspondente a um fluxo RTP de entrada que o endpoint está recebendo (inbound-rtp). Ele é medido no endpoint remoto e informado em um relatório do remetente RTCP (SR).
  • media-playout: métricas sobre a reprodução de um MediaStreamTrack remoto associado a um fluxo RTP de entrada (inbound-rtp).
  • data-channel: representa um RTCDataChannel.

Mapeamento de métricas legadas para métricas padrão

O objetivo desse mapeamento é ajudar os desenvolvedores a encontrar qual métrica legada corresponde a qual métrica padrão, mas 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étricas.
A API padrão prefere mostrar 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 dessa forma pode parecer uma etapa adicional complicada, 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 você precisaria fazer 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 a localcandidate acima. Igual a 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
(procurar remote-candidate usando
candidate-pair.remoteCandidateId)
.googReadable googReadable é um booleano que reflete se incrementamos recentemente candidate-pair.requestsReceived ou candidate-pair.responsesReceived
.googLocalAddress local-candidate.address
(procurar local-candidate usando
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
.googRemoteAddress remote-candidate.address
.googRtt candidate-pair.currentRoundTripTime
.googActiveConnection A conexão ativa se refere ao par candidato que está selecionado pelo transporte, como onde 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á 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 do tipo MIME "type/subtype", 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 FPS de envio seja a taxa de mudança de outbound-rtp.framesSent, ele é implementado como outbound-rtp.framesPerSecond, que codifica o FPS.
.googFrameWidthReceived inbound-rtp.frameWidth
.googFrameHeightReceived inbound-rtp.frameHeight
.googFrameRateDecoded
A taxa de mudança de inbound-rtp.framesDecoded
.googFrameRateOutput
A 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 o número de vezes que a resolução ou a taxa de frames mudou por motivos relacionados a qualityLimitationReason. Isso pode ser deduzido de outras métricas (por exemplo, a resolução ou a taxa de frames do envio ser diferente da resolução ou da taxa de frames da origem), mas a duração do limite, outbound-rtp.qualityLimitationDurations, pode ser mais útil do que a frequência com que a resolução ou a taxa de frames foi reconfigurada.
.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 com correção de erros: 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 a transmissão não estava em silêncio: (inbound-rtp.concealedSamples - inbound-rtp.silentConcealedSamples) / inbound-rtp.concealedSamples
.googAccelerateRate A proporção recente de amostras 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 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
A única 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 de payload, excluindo as 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 a taxa de bits por fluxo RTP, candidate-pair.bytesSent para a taxa de bits por candidato ICE ou transport.bytesSent para a 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 é compatível com simulcast

Se você usa a transmissão simultânea, talvez tenha notado que a API legada só informa um único SSRC, mesmo quando você usa a transmissão simultânea para enviar (por exemplo) três streams 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 SSRC. Isso significa que você pode analisar cada stream RTP individualmente, mas também significa que, para conseguir o bitrate total de todos os streams de envio RTP, você precisa agregá-los.

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 não for possível migrar o código a tempo, o teste de origem para a API getStats() com base em callback da RTCPeerConnection dá mais tempo para a migração dos sites registrados. Com um token de teste de origem, a API legada getStats() pode continuar sendo usada até o Chrome 121.