WebRTC: Legacy-Migrationsanleitung für getStats()

Henrik Boström
Henrik Boström

Die alte getStats() WebRTC API wird in Chrome 117 entfernt. Apps, die sie verwenden, müssen daher zur Standard API migriert werden. In diesem Artikel erfahren Sie, wie Sie Ihren Code migrieren und was Sie tun können, wenn Sie mehr Zeit für diese Änderung benötigen.

Bisher gab es zwei konkurrierende Versionen der WebRTC getStats() API. Die alte getStats()-API, die vor dem Standardisierungsprozess datiert ist und ein Callback-Argument annimmt, und die standardisierte und weit verbreitete API, die ein Promise zurückgibt.

Die Standard-API bietet mehr Funktionen und klar definierte Messwerte, die öffentlich in der W3C-Spezifikation Identifiers for WebRTC's Statistics API dokumentiert sind. Die Spezifikation enthält Beschreibungen aller in diesem Handbuch aufgeführten Messwerte und viele weitere.

Ab Chrome 117 löst die alte getStats() API eine Ausnahme in der stabilen Release-Version aus. Die Ausnahme wird nach und nach eingeführt. Befolgen Sie diese Anleitung, um Ihnen die Umstellung auf die Standard-API zu erleichtern.

Legacy- und Standard-Statistiktypen

Die vollständige Liste der Standard-Statistiktypen findest du unter dem Enum RTCStatsType in der Spezifikation. Dazu gehört auch, welche Statistikwörterbuchdefinition die für jeden Typ erfassten Messwerte beschreibt.

Alle Statistikobjekte haben ein ID-Attribut, das das zugrunde liegende Objekt in mehreren getStats()-Aufrufen eindeutig identifiziert. Dasselbe Objekt hat bei jedem Aufruf der Methode dieselbe ID. Dies ist nützlich, um die Änderungsrate von Messwerten zu berechnen (ein Beispiel finden Sie im nächsten Abschnitt). Die IDs bilden auch Beziehungen von Referenzen. Das Statistikobjekt outbound-rtp verweist beispielsweise über das Attribut outbound-rtp.mediaSourceId auf das zugehörige Statistikobjekt media-source. Wenn Sie alle ...Id-Beziehungen zeichnen, erhalten Sie ein Diagramm.

Die Legacy-API hat die folgenden Statistiktypen, die den folgenden Standardtypen entsprechen:


Legacy-Typ

Standardtyp
ssrc
Stellt einen RTP-Stream und Messwerte zur zugehörigen MediaStreamTrack dar.


Die Standardtypen hierfür sind inbound-rtp (für RTP-Empfangs-Streams und die zugehörigen Remote-MediaStreamTrack), outbound-rtp (zum Senden von RTP-Streams) und media-source (für lokale MediaStreamTrack-Messwerte, die mit einem RTP-Stream verknüpft sind). RTP-Stream-Messwerte enthalten auch Informationen zum Encoder oder Decoder, der vom RTP-Stream verwendet wird.
VideoBwe
Messwerte zur Bandbreitenschätzung, Zielbitrate, Encoder-Bitrate und tatsächliche Bitrate. Diese Messwerttypen sind Teil der RTP-Messwerte (outbound-rtp und inbound-rtp) und der ICE-Kandidatenpaare (candidate-pair).
googComponent
Stellt den Transport (ICE und DTLS) dar. Die Standardversion ist transport.
localcandidate and remotecandidate
Stellt einen ICE-Kandidaten dar. Die Standardversion ist local-candidate und remote-candidate.
googCandidatePair
Ein ICE-Kandidatenpaar, das ein Paar aus einem lokalen und einem Remote-Kandidaten ist. Die Standardversion ist candidate-pair.
googCertificate
Stellt ein Zertifikat dar, das vom DTLS-Transport verwendet wird. Die Standardversion ist certificate.
googLibjingleSession
Stellt das RTCPeerConnection dar. Der Inhalt lässt sich zwar nicht mit dem Standard im Standard verknüpfen, der RTCPeerConnection ist jedoch mit einem Typ verknüpft: peer-connection.

Fehlt in der alten API

Die folgenden Statistiktypen wurden der Standard-API hinzugefügt, für die es keinen entsprechenden Legacy-Typ gibt:
<ph type="x-smartling-placeholder">
    </ph>
  • codec: Ein Codec, der derzeit von einem RTP-Stream zum Codieren oder Decodieren verwendet wird. Dies ist eine Teilmenge der Codecs, die im SDP verhandelt wurden.
  • remote-inbound-rtp: Der eingehende RTP-Stream eines Remote-Endpunkts, der einem ausgehenden RTP-Stream entspricht, den dieser Endpunkt sendet (outbound-rtp). Sie wird am Remote-Endpunkt gemessen und in einem RTCP Receiver Report (RR) oder RTCP Extended Report (XR) gemeldet.
  • remote-outbound-rtp: Der ausgehende RTP-Stream eines Remote-Endpunkts, der einem eingehenden RTP-Stream entspricht, den dieser Endpunkt empfängt (inbound-rtp). Sie wird am Remote-Endpunkt gemessen und in einem RTCP-Senderbericht (SR) gemeldet.
  • media-playout: Messwerte zur Wiedergabe eines Remote-MediaStreamTrack, der mit einem eingehenden RTP-Stream verknüpft ist (inbound-rtp).
  • data-channel: Steht für ein RTCDataChannel.

Zuordnung von Legacy- zu Standard-Messwerten

Diese Zuordnung soll Entwicklern helfen, herauszufinden, welcher alte Messwert zu welchem Standardmesswert gehört. Der entsprechende Messwert kann jedoch andere Einheiten verwenden oder als Summenzähler und nicht als sofortiger Wert ausgedrückt werden. Messwertdefinitionen finden Sie in der Spezifikation.
Bei der Standard-API werden lieber Gesamtzähler anstelle von Raten bereitgestellt. Das bedeutet, dass die App wie bei der Legacy-API die durchschnittliche Rate anhand des Deltas zwischen zwei getStats()-Aufrufen berechnen muss, um die entsprechende Rate (z. B. Bitrate) zu ermitteln. Beispiel:

// 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;

Raten und Durchschnittswerte selbst so berechnen zu müssen, mag wie ein lästiger zusätzlicher Schritt erscheinen, hat aber den Vorteil, dass Sie Durchschnittswerte für jedes gewünschte Zeitintervall ermitteln können. Wenn Sie die Standard-API seltener aufrufen als mit der Legacy-API, ergeben sich einige Leistungsvorteile.

Alter Messwert
googCertificate
Standardmäßige Korrespondenz
certificate
.googFingerprint .fingerprint
.googFingerprintAlgorithm .fingerprintAlgorithm
.googDerBase64 .base64Certificate
Alter Messwert
googComponent
Standardmäßige Korrespondenz
transport
.localCertificateId .localCertificateId
.remoteCertificateId .remoteCertificateId
.selectedCandidatePairId .selectedCandidatePairId
.dtlsCipher .dtlsCipher
.srtpCipher .srtpCipher
Alter Messwert
localcandidate
Standardmäßige Korrespondenz
local-candidate oder candidate-pair
.stunKeepaliveRequestsSent candidate-pair.requestsSent (Reverse-Lookup candidate-pair über 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
Alter Messwert
remotecandidate
Standardmäßige Korrespondenz
remote-candidate
Wie bei localcandidate oben. Wie bei local-candidate oben.
Alter Messwert
googCandidatePair
Standardmäßige Korrespondenz
candidate-pair
.responsesSent candidate-pair.responsesSent
.requestsReceived candidate-pair.requestsReceived
.googRemoteCandidateType remote-candidate.candidateType
(remote-candidate über
candidate-pair.remoteCandidateId suchen)
.googReadable googReadable ist ein boolescher Wert, der angibt, ob candidate-pair.requestsReceived oder candidate-pair.responsesReceived vor Kurzem erhöht wurde
.googLocalAddress local-candidate.address
(local-candidate über
candidate-pair.localCandidateId suchen)
.consentRequestsSent candidate-pair.consentRequestsSent
.googTransportType Wie bei local-candidate.protocol und remote-candidate.protocol.
.googChannelId candidate-pair.transportId
.googLocalCandidateType local-candidate.candidateType
.googWritable googWritable ist ein boolescher Wert, der angibt, ob candidate-pair.responsesReceived vor Kurzem erhöht wurde
.googRemoteAddress remote-candidate.address
.googRtt candidate-pair.currentRoundTripTime
.googActiveConnection Die aktive Verbindung bezieht sich auf das Kandidatenpaar, das derzeit durch den Transport ausgewählt wird, z. B. wenn 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
Alter Messwert
ssrc
Standardmäßige Korrespondenz
, inbound-rtp, outbound-rtp, media-source
.audioInputLevel media-source.audioLevel. Der Legacy-Messwert liegt im Bereich [0–32768], der Standard-Messwert jedoch im Bereich [0–1].
.audioOutputLevel
inbound-rtp.audioLevel. Der Legacy-Messwert liegt im Bereich [0...32768], aber der Standard-Messwert liegt im Bereich [0–1].
.packetsLost inbound-rtp.packetsLost
.googTrackId media-source.trackIdentifier für lokale MediaStreamTrack und inbound-rtp.trackIdentifier für entfernte MediaStreamTracks
.googRtt remote-inbound-rtp.roundTripTime (siehe outbound-rtp.remoteId)
.googEchoCancellationReturnLossEnhancement inbound-rtp.echoReturnLossEnhancement
.googCodecName Der Codec-Name ist der Subtyp von "type/subtype". MIME-Typ, codec.mimeType (siehe inbound-rtp.codecId und outbound-rtp.codecId)
.transportId inbound-rtp.transportId und outbound-rtp.transportId
.mediaType inbound-rtp.kind und outbound-rtp.kind oder media-source.kind
.googEchoCancellationReturnLoss inbound-rtp.echoReturnLoss
.totalAudioEnergy inbound-rtp.totalAudioEnergy und media-source.totalAudioEnergy
ssrc.totalSamplesDuration inbound-rtp.totalSamplesDuration und media-source.totalSamplesDuration
.ssrc inbound-rtp.ssrc und outbound-rtp.ssrc
.googJitterReceived inbound-rtp.jitter
.packetsSent outbound-rtp.packetsSent
.bytesSent outbound-rtp.bytesSent
.googContentType inbound-rtp.contentType und outbound-rtp.contentType
.googFrameWidthInput media-source.width
.googFrameHeightInput media-source.height
.googFrameRateInput media-source.framesPerSecond
.googFrameWidthSent outbound-rtp.frameWidth
.googFrameHeightSent outbound-rtp.frameHeight
.googFrameRateSent
Während die Sende-fps die Änderungsrate von outbound-rtp.framesSent ist, wird sie tatsächlich als outbound-rtp.framesPerSecond implementiert, das die Framerate codiert.
.googFrameWidthReceived inbound-rtp.frameWidth
.googFrameHeightReceived inbound-rtp.frameHeight
.googFrameRateDecoded
Die Änderungsrate von inbound-rtp.framesDecoded
.googFrameRateOutput
Änderungsrate von inbound-rtp.framesDecoded bis inbound-rtp.framesDropped
.hugeFramesSent outbound-rtp.hugeFramesSent
.qpSum

inbound-rtp.qpSum und outbound-rtp.qpSum

.framesEncoded outbound-rtp.framesEncoded
.googAvgEncodeMs

outbound-rtp.totalEncodeTime/outbound-rtp.framesEncoded

.codecImplementationName

inbound-rtp.decoderImplementation und outbound-rtp.encoderImplementation

.googCpuLimitedResolution
„True“, wenn outbound-rtp.qualityLimitationReason == "cpu"
.googBandwidthLimitedResolution
„True“, wenn outbound-rtp.qualityLimitationReason == "bandwidth"
.googAdaptationChanges
Mit dem alten Messwert wird gezählt, wie oft die Auflösung oder Framerate aus qualityLimitationReason-bezogenen Gründen geändert wurde. Dies könnte aus anderen Messwerten abgeleitet werden (z.B. wenn sich die Auflösung oder Framerate für das Senden von der Auflösung oder Framerate der Quelle unterscheidet), aber die Dauer, die wir beschränkt haben (outbound-rtp.qualityLimitationDurations), kann nützlicher sein als die Häufigkeit, mit der Auflösung oder Framerate geändert wurde.
.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
Das aktuelle Verhältnis von Paketen mit Fehlerkorrektur: inbound-rtp.fecPacketsReceivedinbound-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
Das aktuelle Verhältnis der ausgeblendeten Stichproben: inbound-rtp.concealedSamples / inbound-rtp.totalSamplesReceived
.googSpeechExpandRate Das aktuelle Verhältnis der verborgenen Samples, während der Stream nicht stummgeschaltet war: (inbound-rtp.concealedSamplesinbound-rtp.silentConcealedSamples) / inbound-rtp.concealedSamples
.googAccelerateRate Das aktuelle Verhältnis der Samples, die verworfen wurden, um die Wiedergabegeschwindigkeit zu erhöhen: inbound-rtp.removedSamplesForAcceleration / inbound-rtp.totalSamplesReceived
.googPreemptiveExpandRate
Das aktuelle Verhältnis von Samples, die synthetisiert wurden, um die Wiedergabegeschwindigkeit zu verlangsamen: 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
Der einzige verbleibende goog-Messwert. inbound-rtp.googTimingFrameInfo
.framesDecoded inbound-rtp.framesDecoded
Alter Messwert
VideoBwe
Standardmäßige Korrespondenz
outbound-rtp und candidate-pair
.googTargetEncBitrate
outbound-rtp.targetBitrate als momentaner Wert oder outbound-rtp.totalEncodedBytesTarget / outbound-rtp.framesEncoded als Durchschnittswert
.googActualEncBitrate Die vom Encoder erzeugten Byte sind die Nutzlastbyte ohne erneute Übertragungen: die Änderungsrate von outbound-rtp.bytesSent zu outbound-rtp.retransmittedBytesSent.
.googBucketDelay outbound-rtp.totalPacketSendDelay/outbound-rtp.packetsSent
.googTransmitBitrate Die Änderungsrate von outbound-rtp.headerBytesSent + outbound-rtp.bytesSent für die Bitrate pro RTP-Stream, candidate-pair.bytesSent für die Bitrate pro ICE-Kandidat oder transport.bytesSent für die Bitrate pro Transportunternehmen
.googRetransmitBitrate Änderungsbereich von outbound-rtp.retransmittedBytesSent
.googAvailableSendBandwidth candidate-pair.availableOutgoingBitrate
.googAvailableReceiveBandwidth candidate-pair.availableIncomingBitrate

Die Standard-API ist simulcast-fähig.

Wenn Sie Simulcast verwenden, haben Sie vielleicht bemerkt, dass die alte API nur einen einzelnen SSRC meldet, selbst wenn Sie mithilfe von Simulcast drei RTP-Streams über drei separate SSRCs senden.

Die Standard-API nutzt diese Einschränkung nicht und gibt drei outbound-rtp-Statistikobjekte zurück, eines für jeden der SSRCs. Das bedeutet, dass Sie jeden RTP-Stream einzeln analysieren können. Es bedeutet aber auch, dass Sie die Gesamtbitrate aller RTP-Sendestreams selbst aggregieren müssen, um die Gesamtbitrate aller RTP-Sendestreams zu ermitteln.

SVC- oder RTP-Streams mit mehreren räumlichen Ebenen, die über die scalabilityMode API konfiguriert wurden, werden hingegen als eine einzelne outbound-rtp angezeigt, da sie über einen einzelnen SSRC gesendet werden.

Wenn Sie mehr Zeit für die Migration benötigen

Wenn die alte API in Chrome 117 entfernt wird, wird bei ihrer Verwendung eine Ausnahme generiert. Wenn Sie Ihren Code nicht rechtzeitig migrieren können, gibt der Ursprungstest für die RTCPeerConnection-Callback-basierte getStats() API registrierten Websites mehr Zeit für die Migration. Mit einem Ursprungstesttoken kann die alte getStats() API bis Chrome 121 weiterhin verwendet werden.