WebRTC: przewodnik po migracji starszej wersji getStats()

Henrik Boström
Henrik Boström

Starsza wersja interfejsu WebRTC API getStats() zostanie usunięta w Chrome 117, dlatego aplikacje korzystające z niego będą musiały zostać przeniesione do standardowego interfejsu API. Z tego artykułu dowiesz się, jak przenieść kod i co zrobić, jeśli potrzebujesz więcej czasu na wprowadzenie tej zmiany.

Wcześniej istniały 2 konkurujące wersje interfejsu WebRTC getStats() API. Starsza wersja interfejsu API getStats(), która jest wcześniejszym procesem standaryzacji i przyjmuje argument wywołania zwrotnego, oraz ustandaryzowany i szeroko obsługiwany interfejs API, który zwraca obietnicę.

Standardowy interfejs API jest bardziej rozbudowany i zawiera dobrze zdefiniowane wskaźniki, które zostały publicznie udokumentowane w specyfikacji W3C w sekcji Identifiers for WebRTC's Statistics API. Specyfikacja zawiera opisy poszczególnych danych wymienionych w tym przewodniku i wielu innych.

Od Chrome 117 starszy interfejs API getStats() zgłosi wyjątek w wersji stabilnej (wyjątki będą wdrażane stopniowo). Z tego przewodnika dowiesz się, jak łatwo przejść na standardowy interfejs API.

Porównanie starszych i standardowych typów statystyk

Pełną listę standardowych typów statystyk znajdziesz w wyliczeniu RTCStatsType w specyfikacji. Obejmuje to definicję słownika statystyk, która opisuje wskaźniki zebrane dla każdego typu.

Wszystkie obiekty statystyk mają atrybut id, który jednoznacznie identyfikuje bazowy obiekt w wielu wywołaniach getStats(). Ten sam obiekt będzie mieć taki sam identyfikator przy każdym wywołaniu metody. Jest to przydatne przy obliczaniu tempa zmian danych (przykład znajdziesz w następnej sekcji). Identyfikatory tworzą również relacje odwołań. Na przykład obiekt statystyk outbound-rtp odwołuje się za pomocą atrybutu outbound-rtp.mediaSourceId do powiązanego obiektu statystyk media-source. Jeśli narysujesz wszystkie relacje typu ...Id, pojawi się wykres.

Starsza wersja interfejsu API zawiera następujące typy statystyk odpowiadające typom standardowym:


Starszy typ

Typ standardowy
ssrc
Reprezentuje strumień RTP i dane dotyczące powiązanego elementu MediaStreamTrack.


Standardowe typy tego typu to inbound-rtp (dla odbieranych strumieni RTP i powiązanych z nimi zdalnych MediaStreamTrack), outbound-rtp (do wysyłania strumieni RTP) oraz media-source (lokalne dane MediaStreamTrackzwiązane ze strumieniem RTP wysyłającym). Wskaźniki strumienia RTP zawierają też informacje o koderze lub dekoderze używanym przez strumień RTP.
VideoBwe
Wskaźniki szacowanej przepustowości, docelowej szybkości transmisji bitów, kodera i rzeczywistej szybkości transmisji bitów. Te rodzaje danych są częścią wskaźników RTP (outbound-rtp i inbound-rtp) oraz wskaźników pary kandydatów ICE (candidate-pair).
googComponent
Reprezentuje transport (ICE i DTLS). Wersja standardowa to transport.
localcandidate and remotecandidate
Reprezentuje kandydata ICE. Wersja standardowa to local-candidate i remote-candidate.
googCandidatePair
Reprezentuje parę kandydatów ICE, czyli połączenie kandydata lokalnego i kandydata zdalnego. Wersja standardowa to candidate-pair.
googCertificate
Reprezentuje certyfikat używany przez transport DTLS. Wersja standardowa to certificate.
googLibjingleSession
Reprezentuje element RTCPeerConnection. Chociaż treść standardu nie jest zmapowana na jakiś standard, ma on typ powiązany z elementem RTCPeerConnection: peer-connection.

Brak w starszym interfejsie API

Te typy statystyk zostały dodane do standardowego interfejsu API, które nie mają odpowiedniego starszego typu:
  • codec: kodek używany obecnie przez strumień RTP do kodowania lub dekodowania. Jest to podzbiór kodeków wynegocjowanych w SDP.
  • remote-inbound-rtp: przychodzący strumień RTP zdalnego punktu końcowego odpowiadający wychodzącemu strumieniowi RTP wysyłanemu przez ten punkt końcowy (outbound-rtp). Jest mierzona w zdalnym punkcie końcowym i raportowana w raporcie odbierającym RTCP (RR) lub rozszerzonym raporcie RTCP Extended Report (XR).
  • remote-outbound-rtp: wychodzący strumień RTP zdalnego punktu końcowego odpowiadający przychodzącemu strumieniowi RTP odbieranemu przez ten punkt końcowy (inbound-rtp). Jest mierzona w zdalnym punkcie końcowym i raportowana w raporcie RTCP Sender Report (SR).
  • media-playout: dane dotyczące uruchomienia zdalnego strumienia MediaStreamTrack powiązanego z przychodzącym strumieniem RTP (inbound-rtp).
  • data-channel: reprezentuje element RTCDataChannel.

Mapowanie danych starszego typu na standardowe

To mapowanie ma pomagać deweloperom w znalezieniu starszych danych odpowiadających poszczególnym standardowym danym. Pamiętaj jednak, że odpowiednie dane mogą używać innych jednostek lub być wyrażone w postaci licznika, a nie natychmiastowej wartości. Definicje danych znajdziesz w specyfikacji.
Standardowy interfejs API preferuje ujawnianie łącznej liczby liczników niż współczynniki. Oznacza to, że aby uzyskać odpowiednią szybkość (np. szybkość transmisji bitów) tak jak w starszym interfejsie API, aplikacja musi obliczyć średnią wartość, wykorzystując różnicę między 2 wywołaniami getStats(). Na przykład:

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

Samodzielne obliczanie stawek i średnich może wydawać się dodatkowym uciążliwym zadaniem, a dodatkowo w końcu pojawia się możliwość uzyskania średnich wartości w dowolnym przedziale czasu. Wywołanie standardowego interfejsu API rzadziej niż w przypadku starszej wersji interfejsu API ma pewną poprawę wydajności.

Starsze dane
, googCertificate
Standardowa korespondencja
, certificate
.googFingerprint .fingerprint
.googFingerprintAlgorithm .fingerprintAlgorithm
.googDerBase64 .base64Certificate
Starsze dane
, googComponent
Standardowa korespondencja
, transport
.localCertificateId .localCertificateId
.remoteCertificateId .remoteCertificateId
.selectedCandidatePairId .selectedCandidatePairId
.dtlsCipher .dtlsCipher
.srtpCipher .srtpCipher
Starsze dane
, localcandidate
Standardowa korespondencja
+ local-candidate lub candidate-pair
.stunKeepaliveRequestsSent candidate-pair.requestsSent (odwrotne wyszukiwanie candidate-pair przez 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
Starsze dane
, remotecandidate
Standardowa korespondencja
, remote-candidate
Tak samo jak w przypadku powyższego localcandidate. Tak samo jak w przypadku powyższego local-candidate.
Starsze dane
, googCandidatePair
Standardowa korespondencja
, candidate-pair
.responsesSent candidate-pair.responsesSent
.requestsReceived candidate-pair.requestsReceived
.googRemoteCandidateType remote-candidate.candidateType
(wyszukiwanie remote-candidate przez
candidate-pair.remoteCandidateId)
.googReadable googReadable to wartość logiczna wskazująca, czy ostatnio zwiększyliśmy wartość candidate-pair.requestsReceived lub candidate-pair.responsesReceived.
.googLocalAddress local-candidate.address
(wyszukiwanie local-candidate przez
candidate-pair.localCandidateId)
.consentRequestsSent candidate-pair.consentRequestsSent
.googTransportType Tak samo jak w local-candidate.protocol i remote-candidate.protocol.
.googChannelId candidate-pair.transportId
.googLocalCandidateType local-candidate.candidateType
.googWritable googWritable to wartość logiczna, która wskazuje, czy ostatnio zwiększyliśmy wartość candidate-pair.responsesReceived.
.googRemoteAddress remote-candidate.address
.googRtt candidate-pair.currentRoundTripTime
.googActiveConnection Aktywne połączenie odnosi się do pary kandydującej, która jest obecnie wybrana przez środki transportu, np. 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
Starsze dane
, ssrc
Standardowa korespondencja
inbound-rtp, outbound-rtp, media-source
.audioInputLevel media-source.audioLevel. Starszy wskaźnik mieści się w zakresie [0..32768], ale standardowy metr jest w zakresie [0..1].
.audioOutputLevel
inbound-rtp.audioLevel Starszy wskaźnik mieści się w zakresie [0..32768], ale standardowy metr jest w zakresie [0..1].
.packetsLost inbound-rtp.packetsLost
.googTrackId media-source.trackIdentifier dla lokalnych systemów MediaStreamTrack i inbound-rtp.trackIdentifier dla zdalnych MediaStreamTrack
.googRtt remote-inbound-rtp.roundTripTime (zobacz: outbound-rtp.remoteId)
.googEchoCancellationReturnLossEnhancement inbound-rtp.echoReturnLossEnhancement
.googCodecName Nazwa kodeka jest podtypem „typ/podtyp” typ MIME, codec.mimeType (zobacz inbound-rtp.codecId i outbound-rtp.codecId)
.transportId inbound-rtp.transportIdoutbound-rtp.transportId
.mediaType inbound-rtp.kind i outbound-rtp.kind lub media-source.kind
.googEchoCancellationReturnLoss inbound-rtp.echoReturnLoss
.totalAudioEnergy inbound-rtp.totalAudioEnergymedia-source.totalAudioEnergy
ssrc.totalSamplesDuration inbound-rtp.totalSamplesDurationmedia-source.totalSamplesDuration
.ssrc inbound-rtp.ssrcoutbound-rtp.ssrc
.googJitterReceived inbound-rtp.jitter
.packetsSent outbound-rtp.packetsSent
.bytesSent outbound-rtp.bytesSent
.googContentType inbound-rtp.contentTypeoutbound-rtp.contentType
.googFrameWidthInput media-source.width
.googFrameHeightInput media-source.height
.googFrameRateInput media-source.framesPerSecond
.googFrameWidthSent outbound-rtp.frameWidth
.googFrameHeightSent outbound-rtp.frameHeight
.googFrameRateSent
Chociaż liczba klatek na sekundę podczas wysyłania to szybkość zmian elementu outbound-rtp.framesSent, w rzeczywistości ta wartość jest zaimplementowana jako outbound-rtp.framesPerSecond, co oznacza kodowanie klatek na sekundę.
.googFrameWidthReceived inbound-rtp.frameWidth
.googFrameHeightReceived inbound-rtp.frameHeight
.googFrameRateDecoded
Tempo zmian wartości inbound-rtp.framesDecoded
.googFrameRateOutput
Tempo zmian wartości inbound-rtp.framesDecodedinbound-rtp.framesDropped
.hugeFramesSent outbound-rtp.hugeFramesSent
.qpSum

inbound-rtp.qpSumoutbound-rtp.qpSum

.framesEncoded outbound-rtp.framesEncoded
.googAvgEncodeMs

outbound-rtp.totalEncodeTime/outbound-rtp.framesEncoded

.codecImplementationName

inbound-rtp.decoderImplementationoutbound-rtp.encoderImplementation

.googCpuLimitedResolution
Prawda, jeśli outbound-rtp.qualityLimitationReason == "cpu"
.googBandwidthLimitedResolution
Prawda, jeśli outbound-rtp.qualityLimitationReason == "bandwidth"
.googAdaptationChanges
Starsze dane zliczają zmiany rozdzielczości lub liczby klatek z qualityLimitationReason przyczyn. Można wywnioskować to na podstawie innych danych (np. rozdzielczość wysyłania lub liczba klatek różnią się od rozdzielczości źródłowej czy liczby klatek), ale czas trwania ograniczenia (outbound-rtp.qualityLimitationDurations) może być bardziej przydatny niż częstotliwość zmiany rozdzielczości lub liczby klatek.
.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
Ostatni współczynnik pakietów zawierających korekcję błędów: inbound-rtp.fecPacketsReceivedinbound-rtp.fecPacketsDiscarded
.packetsReceived inbound-rtp.packetsReceived
.googJitterBufferMs inbound-rtp.jitterBufferDelay/inbound-rtp.jitterBufferEmittedCount
.googTargetDelayMs (wideo) inbound-rtp.jitterBufferTargetDelay/inbound-rtp.jitterBufferEmittedCount
.googPreferredJitterBufferMs (audio) inbound-rtp.jitterBufferTargetDelay/inbound-rtp.jitterBufferEmittedCount
.googExpandRate
Ostatni współczynnik ukrytych próbek: inbound-rtp.concealedSamples / inbound-rtp.totalSamplesReceived
.googSpeechExpandRate Ostatni współczynnik ukrytych próbek, gdy strumień nie był wyciszony: z (inbound-rtp.concealedSamplesinbound-rtp.silentConcealedSamples) / inbound-rtp.concealedSamples
.googAccelerateRate Ostatni współczynnik próbek, które zostały odrzucone w celu przyspieszenia odtwarzania: inbound-rtp.removedSamplesForAcceleration / inbound-rtp.totalSamplesReceived
.googPreemptiveExpandRate
Ostatni współczynnik próbek, które zostały zsyntetyzowane w celu zmniejszenia prędkości odtwarzania: 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
Jedyny pozostały wskaźnik goog. inbound-rtp.googTimingFrameInfo
.framesDecoded inbound-rtp.framesDecoded
Starsze dane
, VideoBwe
Standardowa korespondencja
outbound-rtp i candidate-pair
.googTargetEncBitrate
outbound-rtp.targetBitrate jako wartość chwilowa lub outbound-rtp.totalEncodedBytesTarget / outbound-rtp.framesEncoded jako średnią
.googActualEncBitrate Bajty utworzone przez koder to bajty ładunku, z wyłączeniem retransmisji: szybkość zmian outbound-rtp.bytesSentoutbound-rtp.retransmittedBytesSent
.googBucketDelay outbound-rtp.totalPacketSendDelay/outbound-rtp.packetsSent
.googTransmitBitrate Szybkość zmiany: outbound-rtp.headerBytesSent + outbound-rtp.bytesSent w przypadku transmisji bitów w formacie RTP, candidate-pair.bytesSent – szybkość transmisji kandydującej ICE lub transport.bytesSent – szybkość transmisji bitów na transport
.googRetransmitBitrate Zakres zmiany outbound-rtp.retransmittedBytesSent
.googAvailableSendBandwidth candidate-pair.availableOutgoingBitrate
.googAvailableReceiveBandwidth candidate-pair.availableIncomingBitrate

Standardowy interfejs API obsługuje technologię Simulcast.

Jeśli korzystasz z simulcast, możesz zauważyć, że starszy interfejs API zgłasza tylko 1 SSRC, nawet jeśli używasz tej funkcji do wysyłania (np.) 3 strumieni RTP do 3 osobnych SSRC.

Standardowy interfejs API nie udostępnia tego ograniczenia i zwraca 3 obiekty statystyk outbound-rtp, po jednym dla każdego SSRC. Oznacza to, że każdy strumień RTP możesz analizować z osobna, ale aby uzyskać całkowitą szybkość transmisji bitów wszystkich wysyłanych strumieni RTP, musisz je zagregować samodzielnie.

Strumienie SVC lub strumienie RTP z wieloma warstwami przestrzennymi skonfigurowanymi przez interfejs scalabilityMode API są nadal wyświetlane jako pojedynczy element outbound-rtp, ponieważ są przesyłane przez jeden SSRC.

Jeśli potrzebujesz więcej czasu na migrację

Jeśli starszy interfejs API zostanie usunięty w Chrome 117, użycie go spowoduje wygenerowanie wyjątku. Jeśli nie uda Ci się przenieść kodu na czas, testy origin dla interfejsu API getStats() opartego na wywołaniach zwrotnych RTCPeerConnection zapewnią zarejestrowanym witrynom więcej czasu na migrację. Jeśli korzystasz z tokenu testowego origin, możesz korzystać ze starszej wersji interfejsu API getStats() do wersji Chrome 121.