WebRTC: przewodnik po migracji starszej wersji getStats()

Henrik Boström
Henrik Boström

Starszy interfejs getStats() WebRTC API zostanie usunięty w Chrome 117, dlatego korzystające z niego aplikacje będą musiały przejść na standardowy interfejs API. Z tego artykułu dowiesz się, jak przenieść kod i co zrobić, jeśli potrzebujesz więcej czasu na wprowadzenie tej zmiany.

W przeszłości istniały 2 rywalizujące wersje interfejsu API WebRTC getStats(). Starsza wersja interfejsu API getStats(), która jest znana przed procesem standaryzacji i przyjmuje argument wywołania zwrotnego, oraz standardowy i powszechnie obsługiwany interfejs API, który zwraca obietnicę.

Standardowy interfejs API ma więcej funkcji i ma dobrze zdefiniowane dane publicznie udokumentowane w identyfikatorze interfejsu API WebRTC specyfikacji W3C. Specyfikacja zawiera opisy wszystkich wskaźników wymienionych w tym przewodniku i wiele innych.

Od wersji Chrome 117 starsza wersja interfejsu API getStats() będzie zgłaszać wyjątek w kanale wersji stabilnej (zrzucanie wyjątków będzie wdrażane stopniowo). Ten przewodnik ułatwi Ci przejście na standardowy interfejs API.

Starsze i standardowe typy statystyk

Pełną listę standardowych typów statystyk można znaleźć na wyliczeniu RTCStatsType w specyfikacji. Obejmuje to definicja słownika statystyk opisująca dane zbierane dla poszczególnych typów.

Wszystkie obiekty statystyczne mają atrybut id, który jednoznacznie identyfikuje bazowy obiekt w wielu wywołaniach getStats(). Przy każdym wywołaniu metody ten sam obiekt będzie miał ten sam identyfikator. Przydaje się to do obliczania częstotliwości zmian danych (przykład znajdziesz w następnej sekcji). Identyfikatory tworzą także relacje między odwołaniami. Na przykład obiekt statystyk outbound-rtp odwołuje się do powiązanego obiektu statystyk media-source za pomocą atrybutu outbound-rtp.mediaSourceId. Jeśli narysujesz wszystkie relacje typu ...Id, otrzymasz wykres.

Starszy interfejs API ma 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 to inbound-rtp (do odbierania strumieni RTP i powiązanych z nimi zdalnych MediaStreamTrack), outbound-rtp (do wysyłania strumieni RTP) i media-source (w przypadku lokalnych danych MediaStreamTrack powiązanych ze strumieniem RTP wysyłania). Dane strumienia RTP zawierają też informacje o koderze lub dekoderze używanym przez strumień RTP.
VideoBwe
Dane o szacowaniu przepustowości, docelowej i rzeczywistej szybkości transmisji bitów. Te rodzaje danych są częścią danych RTP (outbound-rtp i inbound-rtp) oraz danych pary kandydatów ICE (candidate-pair).
googComponent
Reprezentuje transport (ICE i DTLS). Wersja standardowa to transport.
localcandidate and remotecandidate
Reprezentuje kandydata do ICE. Wersja standardowa to local-candidate i remote-candidate.
googCandidatePair
Reprezentuje parę kandydatów z ICE, czyli parę kandydatów lokalnych i zdalnych. Wersja standardowa to candidate-pair.
googCertificate
Reprezentuje certyfikat używany przez transport DTLS. Wersja standardowa to certificate.
googLibjingleSession
Reprezentuje obiekt RTCPeerConnection. Choć jego treść nie odpowiada żadnemu elementowi standardu, ma on jednak przypisany do niego typ (RTCPeerConnection): peer-connection.

Brak w starszej wersji interfejsu API

Te typy statystyk zostały dodane do standardowego interfejsu API, który nie ma odpowiadającego mu 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łanym przez ten punkt końcowy (outbound-rtp). Jest mierzony w zdalnym punkcie końcowym i raportowany w raporcie dotyczącym odbiornika RTCP (RR) lub w rozszerzonym raporcie RTCP (XR).
  • remote-outbound-rtp: wychodzący strumień RTP zdalnego punktu końcowego odpowiadający przychodzącemu strumieniowi RTP odbieranym przez ten punkt końcowy (inbound-rtp). Jest mierzony w zdalnym punkcie końcowym i raportowany w raporcie nadawcy RTCP.
  • media-playout: dane o wyświetlaniu zdalnego elementu MediaStreamTrack powiązanego z przychodzącym strumieniem RTP (inbound-rtp).
  • data-channel: reprezentuje obiekt RTCDataChannel.

Mapowanie danych ze starszej wersji na standardowe

Mapowanie ma pomóc deweloperom w znalezieniu, które starsze dane odpowiadają określonym standardowym danym. Pamiętaj jednak, że odpowiednie dane mogą mieć inne jednostki lub być wyrażone jako licznik sumy, a nie wartość błyskawiczna. Definicje danych znajdziesz w specyfikacji.
Standardowy interfejs API preferuje ujawnianie sumy liczników zamiast współczynników. Oznacza to, że aby uzyskać odpowiednią szybkość (np. szybkość transmisji bitów) jak w starszym interfejsie API, aplikacja musi obliczyć średnią szybkość, uwzględniają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;

Konieczność samodzielnego obliczania współczynników i średnich może wydawać się uciążliwa, jednak w takiej sytuacji umożliwia uzyskanie średnich wartości w dowolnym przedziale czasu. Wywołując standardowy interfejs API rzadziej niż w przypadku starszego interfejsu API ma to pewne zalety w zakresie wydajności.

Starszy wskaźnik
googCertificate
Standardowa korespondencja
certificate
.googFingerprint .fingerprint
.googFingerprintAlgorithm .fingerprintAlgorithm
.googDerBase64 .base64Certificate
Starszy wskaźnik
googComponent
Standardowa korespondencja
transport
.localCertificateId .localCertificateId
.remoteCertificateId .remoteCertificateId
.selectedCandidatePairId .selectedCandidatePairId
.dtlsCipher .dtlsCipher
.srtpCipher .srtpCipher
Starszy wskaźnik
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
Starszy wskaźnik
remotecandidate
Standardowa korespondencja
remote-candidate
Taka sama jak w tabeli localcandidate powyżej. Taka sama jak w tabeli local-candidate powyżej.
Starszy wskaźnik
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 liczbę candidate-pair.requestsReceived lub candidate-pair.responsesReceived
.googLocalAddress local-candidate.address
(wyszukiwanie local-candidate przez
candidate-pair.localCandidateId)
.consentRequestsSent candidate-pair.consentRequestsSent
.googTransportType Taka sama funkcja jak w przypadku local-candidate.protocol i remote-candidate.protocol.
.googChannelId candidate-pair.transportId
.googLocalCandidateType local-candidate.candidateType
.googWritable googWritable to wartość logiczna wskazująca, czy ostatnio zwiększyliśmy liczbę candidate-pair.responsesReceived
.googRemoteAddress remote-candidate.address
.googRtt candidate-pair.currentRoundTripTime
.googActiveConnection Aktywne połączenie odnosi się do pary kandydatów, która jest obecnie wybrana przez transport, na przykład gdzie 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
Starszy wskaźnik
ssrc
Standardowa korespondencja
inbound-rtp, outbound-rtp, media-source
.audioInputLevel media-source.audioLevel. Starsza wartość mieści się w zakresie [0..32768], ale standardowy obszar miejski mieści się w zakresie [0..1].
.audioOutputLevel
inbound-rtp.audioLevel Starsza wartość mieści się w zakresie [0..32768], ale standardowy obszar miejski mieści się w zakresie [0..1].
.packetsLost inbound-rtp.packetsLost
.googTrackId media-source.trackIdentifier dla lokalnych MediaStreamTrack i inbound-rtp.trackIdentifier dla zdalnych MediaStreamTrack
.googRtt remote-inbound-rtp.roundTripTime (zobacz outbound-rtp.remoteId)
.googEchoCancellationReturnLossEnhancement inbound-rtp.echoReturnLossEnhancement
.googCodecName Nazwa kodeka to podtyp MIME typu „typ/podtyp”, codec.mimeType (patrz 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
FPS przy wysyłaniu to szybkość zmian wartości outbound-rtp.framesSent, ale w rzeczywistości ta wartość jest zaimplementowane jako outbound-rtp.framesPerSecond, która koduje FPS.
.googFrameWidthReceived inbound-rtp.frameWidth
.googFrameHeightReceived inbound-rtp.frameHeight
.googFrameRateDecoded
Tempo zmian wartości inbound-rtp.framesDecoded
.googFrameRateOutput
Tempo zmian wartości z okresu 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ą liczbę zmian rozdzielczości lub liczby klatek z qualityLimitationReason powodów. Można to usunąć z innych danych (np. rozdzielczość wysyłania lub liczba klatek różni się od rozdzielczości źródła lub liczby klatek), ale okres, w którym wprowadziliśmy 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 z poprawką błędów: inbound-rtp.fecPacketsReceivedinbound-rtp.fecPacketsDiscarded
.packetsReceived inbound-rtp.packetsReceived
.googJitterBufferMs inbound-rtp.jitterBufferDelay / inbound-rtp.jitterBufferEmittedCount
.googTargetDelayMs (film) inbound-rtp.jitterBufferTargetDelay / inbound-rtp.jitterBufferEmittedCount
.googPreferredJitterBufferMs (dźwięk) 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 wyświetlania: inbound-rtp.removedSamplesForAcceleration / inbound-rtp.totalSamplesReceived
.googPreemptiveExpandRate
Ostatni współczynnik próbek zsyntetyzowanych w celu spowolnienia odtwarzania: inbound-rtp.insertedSamplesForDeceleration / inbound-rtp.totalSamplesReceived
.googSecondaryDiscardedRate inbound-rtp.fecPacketsDiscarded
.bytesReceived inbound-rtp.bytesReceived
s.googCurrentDelayMs inbound-rtp.jitterBufferDelay + media-playout.totalPlayoutOpóźnienie
.googDecodeMs inbound-rtp.totalDecodeTime / inbound-rtp.framesDecoded
.googTimingFrameInfo
Jedyne pozostałe dane dotyczące goog. inbound-rtp.googTimingFrameInfo
.framesDecoded inbound-rtp.framesDecoded
Starszy wskaźnik
VideoBwe
Standardowa korespondencja
outbound-rtp i candidate-pair
.googTargetEncBitrate
outbound-rtp.targetBitrate jako wartość chwilową lub outbound-rtp.totalEncodedBytesTarget / outbound-rtp.framesEncoded jako wartość średnią.
.googActualEncBitrate Bajty wygenerowane przez koder to bajty ładunku, z wyłączeniem ponownych transmisji – szybkość zmian z przedziału outbound-rtp.bytesSentoutbound-rtp.retransmittedBytesSent
.googBucketDelay outbound-rtp.totalPacketSendDelay / outbound-rtp.packetsSent
.googTransmitBitrate Szybkość zmiany szybkości transmisji bitów (outbound-rtp.headerBytesSent + outbound-rtp.bytesSent) na szybkość transmisji bitów strumienia (RTP), candidate-pair.bytesSent – szybkość transmisji bitów kandydującej na ICE lub transport.bytesSent dla szybkości transmisji bitów na transport
.googRetransmitBitrate Zakres zmian wartości outbound-rtp.retransmittedBytesSent
.googAvailableSendBandwidth candidate-pair.availableOutgoingBitrate
.googAvailableReceiveBandwidth candidate-pair.availableIncomingBitrate

Standardowy interfejs API jest wykorzystujący funkcję simulcast

Jeśli używasz narzędzia simulcast, możesz zauważyć, że starsza wersja interfejsu API zgłasza tylko jeden kod SSRC, nawet jeśli używasz tej metody do wysyłania (np.) 3 strumieni RTP za pomocą 3 osobnych kodów SSRC.

Standardowy interfejs API nie ma tego ograniczenia i zwraca 3 obiekty statystyk outbound-rtp, po jednym dla każdego kodu SSRC. Oznacza to, że możesz analizować każdy strumień RTP oddzielnie, ale oznacza to również, że aby uzyskać łączną szybkość transmisji bitów wszystkich strumieni RTP, musisz je zagregować samodzielnie.

Strumienie SVC lub RTP z wieloma warstwami przestrzennymi skonfigurowanymi za pomocą interfejsu API scalabilityMode z drugiej strony nadal wyświetlają się jako pojedynczy element outbound-rtp, ponieważ są one wysyłane przez pojedynczy kod SSRC.

Jeśli potrzebujesz więcej czasu na migrację

Po usunięciu starszej wersji interfejsu API w Chrome 117 użycie go spowoduje wygenerowanie wyjątku. Jeśli nie możesz przeprowadzić migracji kodu na czas, okres próbny źródła dla interfejsu API getStats() opartego na wywołaniach zwrotnych RTCPeerConnection daje zarejestrowanych witrynom więcej czasu na migrację. W przypadku tokena próbnego origin starszy interfejs API getStats() może być nadal używany do wersji Chrome 121.