La API de WebRTC de getStats()
heredada 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, ha habido dos versiones de la API de WebRTC getStats()
de la competencia. La API heredada de getStats() es anterior al proceso de estandarización y toma un argumento de devolución de llamada, y la API estandarizada y ampliamente compatible que devuelve una promesa.
La API estándar cuenta con más funciones y tiene métricas bien definidas que se documentan públicamente en la especificación W3C Identificadores para la API de estadísticas de WebRTC. La especificación incluye descripciones de cada métrica enumerada 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 estable (el lanzamiento de excepciones se lanzará de forma gradual). Sigue esta guía para facilitar tu transición a la API estándar.
Tipos de estadísticas heredadas y estándar
La lista completa de los tipos de estadísticas estándar se puede encontrar en 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 de 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 ID 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 mediante el atributo outbound-rtp.mediaSourceId
. Si extraes todas las relaciones ...Id
, se obtiene un gráfico.
La API heredada tiene los siguientes tipos de estadísticas, que corresponden a los tipos estándar, como se indica a continuación:
Tipo heredado |
Tipo estándar |
---|---|
ssrc
|
Representa una transmisión de RTP y las métricas sobre el MediaStreamTrack asociado.Los tipos estándar son inbound-rtp (para recibir transmisiones RTP y su MediaStreamTrack remoto asociado), outbound-rtp (para enviar transmisiones RTP) y media-source (para métricas MediaStreamTrack locales asociadas con una transmisión de RTP de envío). Las métricas de transmisión de RTP también contienen información acerca del codificador o decodificador utilizado por la transmisión de RTP. |
VideoBwe
|
Métricas de estimación del 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 par de candidatos de ICE (candidate-pair ). |
googComponent
|
Representa el transporte (ICE y DTLS). La versión estándar es transport . |
localcandidate and remotecandidate
|
Representa a un candidato de ICE. La versión estándar es local-candidate y remote-candidate . |
googCandidatePair
|
Representa 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, el estándar 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 tienen ningún tipo heredado correspondiente:
|
Asignación de métricas heredada a estándar
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 diferentes unidades o expresarse como un contador total en lugar de un valor instantáneo. Consulta la especificación para obtener definiciones de métricas.
La API estándar prefiere exponer los contadores totales en lugar de las tasas. Esto significa que, para obtener la tarifa 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 tasas y los promedios por tu cuenta puede parecer un paso adicional engorroso, pero tiene la ventaja de permitirte obtener promedios durante cualquier intervalo de tiempo deseado. Llamar a la API estándar con menos frecuencia de la que tendrías que ver 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 mediante 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 localcandidate más arriba. |
Igual que local-candidate más arriba. |
Métrica heredada
googCandidatePair |
Correspondencia estándar
candidate-pair |
---|---|
.responsesSent
|
candidate-pair.responsesSent
|
.requestsReceived
|
candidate-pair.requestsReceived
|
.googRemoteCandidateType
|
remote-candidate.candidateType (búsqueda remote-candidate a través de candidate-pair.remoteCandidateId ) |
.googReadable
|
googReadable es un valor booleano que refleja si recientemente aumentamos candidate-pair.requestsReceived o candidate-pair.responsesReceived .
|
.googLocalAddress
|
local-candidate.address (búsqueda 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 aumentamos o no candidate-pair.responsesReceived recientemente.
|
.googRemoteAddress
|
remote-candidate.address
|
.googRtt
|
candidate-pair.currentRoundTripTime
|
.googActiveConnection
|
La conexión activa hace referencia al par de candidatos que el transporte selecciona en este momento, por ejemplo, en el 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 heredada
ssrc |
Correspondencia estándar
inbound-rtp , outbound-rtp , media-source |
---|---|
.audioInputLevel
|
media-source.audioLevel . La métrica heredada está dentro del rango [0..32768], pero el metrc estándar está dentro del rango [0..1]. |
.audioOutputLevel
|
inbound-rtp.audioLevel La métrica heredada está dentro del rango [0..32768], pero el metrc estándar está dentro del 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 "tipo/subtipo", 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 es la codificación de FPS. |
.googFrameWidthReceived
|
inbound-rtp.frameWidth
|
.googFrameHeightReceived
|
inbound-rtp.frameHeight
|
.googFrameRateDecoded
|
La tasa de cambio de inbound-rtp.framesDecoded |
.googFrameRateOutput
|
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 podría deducirse a partir de otras métricas (p.ej., que la resolución de envío o la velocidad de fotogramas sean diferentes de la resolución de origen o la velocidad de fotogramas), pero la duración por la que estuvimos limitado, outbound-rtp.qualityLimitationDurations , puede ser más útil que la frecuencia con la que se reconfiguraron 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
|
Proporción reciente de muestras ocultas mientras la transmisión no estaba en silencio: de (inbound-rtp.concealedSamples a 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
|
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 valor instantáneo o outbound-rtp.totalEncodedBytesTarget / outbound-rtp.framesEncoded como 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 a outbound-rtp.retransmittedBytesSent |
.googBucketDelay
|
outbound-rtp.totalPacketSendDelay /outbound-rtp.packetsSent
|
.googTransmitBitrate
|
Tasa de cambio de outbound-rtp.headerBytesSent + outbound-rtp.bytesSent para la tasa de bits de transmisión por RTP, candidate-pair.bytesSent para la tasa de bits por candidato por ICE y 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 admite la transmisión simultánea
Si utilizas Simulcast, es posible que hayas notado que la API heredada solo informa un único SSRC, incluso cuando usas Simulcast para enviar (por ejemplo) tres transmisiones RTP a través de tres SSRC distintas.
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 transmisión de RTP de manera individual, pero también significa que tendrás que agregar las transmisiones de RTP para obtener la tasa de bits total de todas.
Por otro lado, las transmisiones de SVC o RTP con varias capas espaciales configuradas a través de la API de scalabilityMode
aún se muestran como un único outbound-rtp
porque se envían a través de un único SSRC.
Si necesitas más tiempo para la migración
Cuando se quite la API heredada en Chrome 117, su uso 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 la migración. Con un token de prueba de origen, es posible que se siga usando la API heredada de getStats() hasta Chrome 121.