La API heredada de WebRTC getStats()
se quitará en Chrome 117, por lo que las apps que la usen deberán migrar a la API estándar. En este artículo, se explica cómo migrar tu código y qué hacer si necesitas más tiempo para realizar este cambio.
Históricamente, hubo dos versiones en competencia de la API de getStats()
de WebRTC. La API heredada getStats(), que es anterior al proceso de estandarización y toma un argumento de devolución de llamada, y la API estandarizada y ampliamente admitida que muestra una promesa.
La API estándar tiene más funciones y métricas bien definidas documentadas públicamente en la especificación del W3C Identifiers for WebRTC's Statistics API. La especificación incluye descripciones de cada métrica que se menciona en esta guía y muchas más.
A partir de Chrome 117, la API heredada de getStats()
arrojará una excepción en el canal de versiones estables (la excepción se lanzará de forma gradual). Sigue esta guía para facilitar la transición a la API estándar.
Tipos de estadísticas heredados frente a estándares
Para ver la lista completa de los tipos de estadísticas estándar, consulta la enumeración RTCStatsType en la especificación. Esto incluye qué definición del diccionario de estadísticas describe las métricas recopiladas para cada tipo.
Todos los objetos de estadísticas tienen un atributo id que identifica de forma única el objeto subyacente en varias llamadas a getStats()
. El mismo objeto tendrá el mismo ID cada vez que se llame al método. Esto es útil para calcular la tasa de cambio de las métricas (hay un ejemplo en la siguiente sección). Los IDs también forman relaciones de referencias. Por ejemplo, el objeto de estadísticas outbound-rtp
hace referencia al objeto de estadísticas media-source
asociado a través del atributo outbound-rtp.mediaSourceId
. Si dibujas todas las relaciones ...Id
, obtienes un gráfico.
La API heredada tiene los siguientes tipos de estadísticas, que corresponden a los tipos estándar de la siguiente manera:
Tipo heredado |
Tipo estándar |
---|---|
ssrc
|
Representación de una transmisión RTP y métricas sobre el MediaStreamTrack asociadoLos tipos estándar para esto son inbound-rtp (para recibir transmisiones de RTP y su MediaStreamTrack remoto asociado), outbound-rtp (para enviar transmisiones de RTP) y media-source (para métricas de MediaStreamTrack locales asociadas con una transmisión de RTP de envío). Las métricas de flujo de RTP también contienen información sobre el codificador o decodificador que usa el flujo de RTP. |
VideoBwe
|
Métricas de estimación de ancho de banda, tasa de bits objetivo, tasa de bits del codificador y tasa de bits real. Estos tipos de métricas forman parte de las métricas de RTP ( outbound-rtp y inbound-rtp ) y de las métricas de par candidato de ICE (candidate-pair ). |
googComponent
|
Representación del transporte (ICE y DTLS) La versión estándar es transport . |
localcandidate and remotecandidate
|
Representación de un candidato de ICE. La versión estándar es local-candidate y remote-candidate . |
googCandidatePair
|
Representación de un par de candidatos de ICE, que es una vinculación de un candidato local y uno remoto. La versión estándar es candidate-pair . |
googCertificate
|
Representa un certificado que usa el transporte DTLS. La versión estándar es certificate . |
googLibjingleSession
|
Representa el RTCPeerConnection . Si bien su contenido no se asigna a nada en el estándar, este tiene un tipo asociado con RTCPeerConnection : peer-connection . |
Falta en la API heredada |
Estos tipos de estadísticas se agregaron a la API estándar que no tiene ningún tipo heredado correspondiente:
|
Asignación de métricas heredadas a métricas estándares
El objetivo de esta asignación es ayudar a los desarrolladores a encontrar qué métrica heredada corresponde a qué métrica estándar, pero ten en cuenta que la métrica correspondiente puede usar unidades diferentes o expresarse como un contador total en lugar de un valor instantáneo. Consulta la especificación para ver las definiciones de las métricas.
La API estándar prefiere exponer contadores totales en lugar de tasas. Esto significa que, para obtener la tasa correspondiente (por ejemplo, la tasa de bits) como en la API heredada, la app debe calcular la tasa promedio tomando el delta entre dos llamadas a getStats()
. Por ejemplo:
// 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;
Tener que calcular las tarifas y los promedios por tu cuenta de esta manera puede parecer un paso adicional engorroso, pero tiene la ventaja de permitirte obtener promedios en cualquier intervalo de tiempo que desees. Llamar a la API estándar con menos frecuencia de la que podrías haber hecho con la API heredada tiene algunos beneficios de rendimiento.
Métrica heredada
googCertificate |
Correspondencia estándar
certificate |
---|---|
.googFingerprint
|
.fingerprint
|
.googFingerprintAlgorithm
|
.fingerprintAlgorithm
|
.googDerBase64
|
.base64Certificate
|
Métrica heredada
googComponent |
Correspondencia estándar
transport |
---|---|
.localCertificateId
|
.localCertificateId
|
.remoteCertificateId
|
.remoteCertificateId
|
.selectedCandidatePairId
|
.selectedCandidatePairId
|
.dtlsCipher
|
.dtlsCipher
|
.srtpCipher
|
.srtpCipher
|
Métrica heredada
localcandidate |
Correspondencia estándar
local-candidate o candidate-pair |
---|---|
.stunKeepaliveRequestsSent
|
candidate-pair.requestsSent (búsqueda inversa candidate-pair a través de 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 heredada
remotecandidate |
Correspondencia estándar
remote-candidate |
---|---|
Igual que en localcandidate anterior. |
Igual que en local-candidate anterior. |
Métrica heredada
googCandidatePair |
Correspondencia estándar
candidate-pair |
---|---|
.responsesSent
|
candidate-pair.responsesSent
|
.requestsReceived
|
candidate-pair.requestsReceived
|
.googRemoteCandidateType
|
remote-candidate.candidateType (búsqueda de remote-candidate a través de candidate-pair.remoteCandidateId ) |
.googReadable
|
googReadable es un valor booleano que refleja si incrementamos recientemente candidate-pair.requestsReceived o candidate-pair.responsesReceived .
|
.googLocalAddress
|
local-candidate.address (búsqueda de local-candidate a través de candidate-pair.localCandidateId ) |
.consentRequestsSent
|
candidate-pair.consentRequestsSent
|
.googTransportType
|
Igual que local-candidate.protocol y remote-candidate.protocol . |
.googChannelId
|
candidate-pair.transportId
|
.googLocalCandidateType
|
local-candidate.candidateType
|
.googWritable
|
googWritable es un valor booleano que refleja si incrementamos candidate-pair.responsesReceived recientemente o no.
|
.googRemoteAddress
|
remote-candidate.address
|
.googRtt
|
candidate-pair.currentRoundTripTime
|
.googActiveConnection
|
La conexión activa hace referencia al par candidato que el transporte selecciona actualmente, como en el caso de 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 heredada
ssrc |
Correspondencia estándar
inbound-rtp , outbound-rtp , media-source |
---|---|
.audioInputLevel
|
media-source.audioLevel . La métrica heredada está en el rango [0..32768], pero la métrica estándar está en el rango [0..1]. |
.audioOutputLevel
|
inbound-rtp.audioLevel . La métrica heredada está en el rango [0..32768], pero la métrica estándar está en el rango [0..1]. |
.packetsLost
|
inbound-rtp.packetsLost
|
.googTrackId
|
media-source.trackIdentifier para MediaStreamTrack locales y inbound-rtp.trackIdentifier para MediaStreamTrack remotos |
.googRtt
|
remote-inbound-rtp.roundTripTime (consulta outbound-rtp.remoteId ) |
.googEchoCancellationReturnLossEnhancement
|
inbound-rtp.echoReturnLossEnhancement
|
.googCodecName
|
El nombre del códec es el subtipo del tipo de MIME "type/subtype", codec.mimeType (consulta inbound-rtp.codecId y outbound-rtp.codecId ). |
.transportId
|
inbound-rtp.transportId y outbound-rtp.transportId |
.mediaType
|
inbound-rtp.kind y outbound-rtp.kind o media-source.kind
|
.googEchoCancellationReturnLoss
|
inbound-rtp.echoReturnLoss
|
.totalAudioEnergy
|
inbound-rtp.totalAudioEnergy y media-source.totalAudioEnergy
|
ssrc.totalSamplesDuration
|
inbound-rtp.totalSamplesDuration y media-source.totalSamplesDuration
|
.ssrc
|
inbound-rtp.ssrc y outbound-rtp.ssrc
|
.googJitterReceived
|
inbound-rtp.jitter
|
.packetsSent
|
outbound-rtp.packetsSent
|
.bytesSent
|
outbound-rtp.bytesSent
|
.googContentType
|
inbound-rtp.contentType y outbound-rtp.contentType |
.googFrameWidthInput
|
media-source.width
|
.googFrameHeightInput
|
media-source.height
|
.googFrameRateInput
|
media-source.framesPerSecond
|
.googFrameWidthSent
|
outbound-rtp.frameWidth
|
.googFrameHeightSent
|
outbound-rtp.frameHeight
|
.googFrameRateSent
|
Si bien los FPS de envío son la tasa de cambio de outbound-rtp.framesSent , en realidad se implementan como outbound-rtp.framesPerSecond , que codifica los FPS. |
.googFrameWidthReceived
|
inbound-rtp.frameWidth
|
.googFrameHeightReceived
|
inbound-rtp.frameHeight
|
.googFrameRateDecoded
|
La tasa de cambio de inbound-rtp.framesDecoded |
.googFrameRateOutput
|
La tasa de cambio de inbound-rtp.framesDecoded - inbound-rtp.framesDropped |
.hugeFramesSent
|
outbound-rtp.hugeFramesSent
|
.qpSum
|
|
.framesEncoded
|
outbound-rtp.framesEncoded
|
.googAvgEncodeMs
|
|
.codecImplementationName
|
|
.googCpuLimitedResolution
|
Verdadero si outbound-rtp.qualityLimitationReason == "cpu" |
.googBandwidthLimitedResolution
|
Verdadero si outbound-rtp.qualityLimitationReason == "bandwidth" |
.googAdaptationChanges
|
La métrica heredada cuenta la cantidad de veces que cambió la resolución o la velocidad de fotogramas por motivos relacionados con qualityLimitationReason . Esto se podría deducir de otras métricas (p.ej., la resolución de envío o la velocidad de fotogramas es diferente de la resolución o la velocidad de fotogramas de origen), pero la duración a la que nos limitamos, outbound-rtp.qualityLimitationDurations , puede ser más útil que la frecuencia con la que se volvió a configurar la resolución o la velocidad de fotogramas. |
.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
|
La proporción reciente de paquetes que contienen corrección de errores: inbound-rtp.fecPacketsReceived - inbound-rtp.fecPacketsDiscarded |
.packetsReceived
|
inbound-rtp.packetsReceived
|
.googJitterBufferMs
|
inbound-rtp.jitterBufferDelay /inbound-rtp.jitterBufferEmittedCount
|
.googTargetDelayMs (video) |
inbound-rtp.jitterBufferTargetDelay /inbound-rtp.jitterBufferEmittedCount
|
.googPreferredJitterBufferMs (audio) |
inbound-rtp.jitterBufferTargetDelay /inbound-rtp.jitterBufferEmittedCount
|
.googExpandRate
|
La proporción reciente de muestras ocultas: inbound-rtp.concealedSamples / inbound-rtp.totalSamplesReceived |
.googSpeechExpandRate
|
La proporción reciente de muestras ocultas mientras la transmisión no estaba en silencio: (inbound-rtp.concealedSamples - inbound-rtp.silentConcealedSamples ) / inbound-rtp.concealedSamples |
.googAccelerateRate
|
La proporción reciente de muestras que se descartaron para acelerar la velocidad de reproducción: inbound-rtp.removedSamplesForAcceleration / inbound-rtp.totalSamplesReceived |
.googPreemptiveExpandRate
|
La proporción reciente de muestras que se sintetizaron para desacelerar la velocidad de reproducción: 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
|
Es la única métrica de goog que queda. inbound-rtp.googTimingFrameInfo |
.framesDecoded
|
inbound-rtp.framesDecoded
|
Métrica heredada
VideoBwe |
Correspondencia estándar
outbound-rtp y candidate-pair |
---|---|
.googTargetEncBitrate
|
outbound-rtp.targetBitrate como un valor instantáneo o outbound-rtp.totalEncodedBytesTarget / outbound-rtp.framesEncoded como un promedio |
.googActualEncBitrate
|
Los bytes que produce el codificador son los bytes de carga útil, sin incluir las retransmisiones: la tasa de cambio de outbound-rtp.bytesSent - outbound-rtp.retransmittedBytesSent |
.googBucketDelay
|
outbound-rtp.totalPacketSendDelay /outbound-rtp.packetsSent
|
.googTransmitBitrate
|
La tasa de cambio de outbound-rtp.headerBytesSent + outbound-rtp.bytesSent para la tasa de bits de la transmisión por RTP, candidate-pair.bytesSent para la tasa de bits por candidato de ICE o transport.bytesSent para la tasa de bits por transporte |
.googRetransmitBitrate
|
El rango de cambio de outbound-rtp.retransmittedBytesSent |
.googAvailableSendBandwidth
|
candidate-pair.availableOutgoingBitrate
|
.googAvailableReceiveBandwidth
|
candidate-pair.availableIncomingBitrate
|
La API estándar es compatible con la transmisión simultánea.
Si usas la transmisión simultánea, es posible que hayas notado que la API heredada solo informa un SSRC único, incluso cuando usas la transmisión simultánea para enviar (por ejemplo) tres transmisiones RTP a través de tres SSRC independientes.
La API estándar no comparte esta limitación y mostrará tres objetos de estadísticas outbound-rtp
, uno para cada uno de los SSRC. Esto significa que puedes analizar cada flujo de RTP de forma individual, pero también significa que, para obtener la tasa de bits total de todos los flujos de envío de RTP, deberás agregarlos por tu cuenta.
Por otro lado, las transmisiones SVC o RTP con varias capas espaciales configuradas a través de la API de scalabilityMode
aún aparecen como una sola outbound-rtp
porque se envían a través de un solo SSRC.
Si necesitas más tiempo para la migración
Cuando se quite la API heredada en Chrome 117, usarla generará una excepción. Si no puedes migrar tu código a tiempo, la prueba de origen para la API de getStats() basada en devoluciones de llamada de RTCPeerConnection les brinda a los sitios web registrados más tiempo para migrar. Con un token de prueba de origen, la API heredada de getStats() se podrá seguir usando hasta la versión 121 de Chrome.