WebRTC: руководство по миграции устаревшего метода getStats()

Хенрик Бострем
Henrik Boström

Устаревший API getStats() WebRTC будет удален в Chrome 117, поэтому приложениям, использующим его, необходимо будет перейти на стандартный API. В этой статье объясняется, как перенести код и что делать, если вам нужно больше времени для внесения этого изменения.

Исторически существовало две конкурирующие версии API WebRTC getStats() . Устаревший API getStats(), который предшествует процессу стандартизации и принимает аргумент обратного вызова, а также стандартизированный и широко поддерживаемый API, который возвращает обещание.

Стандартный API более функционален и имеет четко определенные метрики, публично задокументированные в спецификации W3C «Идентификаторы для API статистики WebRTC» . Спецификация включает описания каждой метрики, перечисленной в этом руководстве, и многих других.

Начиная с Chrome 117, устаревший API getStats() будет генерировать исключение в канале стабильной версии (выдача исключений будет постепенно внедряться). Следуйте этому руководству, чтобы облегчить переход на стандартный API.

Устаревшие и стандартные типы статистики

Полный список стандартных типов статистики можно найти, просмотрев перечисление RTCStatsType в спецификации. Сюда входит определение словаря статистики, описывающее метрики, собранные для каждого типа.

Все объекты статистики имеют атрибут id, который однозначно идентифицирует базовый объект при нескольких вызовах getStats() . Один и тот же объект будет иметь один и тот же идентификатор каждый раз при вызове метода. Это полезно для расчета скорости изменения метрик (пример есть в следующем разделе). Идентификаторы также образуют отношения ссылок. Например, объект статистики outbound-rtp ссылается на связанный объект статистики media-source через атрибут outbound-rtp.mediaSourceId . Если вы нарисуете все отношения ...Id вы получите график.

Устаревший API имеет следующие типы статистики, соответствующие стандартным типам:


Устаревший тип

Стандартный тип
ssrc
Представляет поток RTP и метрики связанного MediaStreamTrack .


Стандартными типами для этого являются inbound-rtp (для принимаемых потоков RTP и связанных с ним удаленных потоков MediaStreamTrack ), outbound-rtp (для отправляемых потоков RTP) и media-source (для локальных метрик MediaStreamTrack , связанных с отправляемым потоком RTP). Метрики потока RTP также содержат информацию о кодере или декодере, используемом потоком RTP.
VideoBwe
Метрики оценки пропускной способности, целевой битрейт, битрейт кодера и фактический битрейт. Эти типы метрик являются частью метрик RTP ( outbound-rtp и inbound-rtp ) и метрик пары кандидатов ICE ( candidate-pair ).
googComponent
Представляет транспорт (ICE и DTLS). Стандартная версия – transport .
localcandidate and remotecandidate
Представляет кандидата ICE. Стандартная версия — local-candidate и remote-candidate .
googCandidatePair
Представляет пару кандидатов ICE, которая представляет собой пару локального и удаленного кандидатов. Стандартная версия — candidate-pair .
googCertificate
Представляет сертификат, используемый транспортом DTLS. Стандартная версия — certificate .
googLibjingleSession
Представляет RTCPeerConnection . Хотя его содержимое не соответствует ничему в стандарте, в стандарте есть тип, связанный с RTCPeerConnection : peer-connection .

Отсутствует в устаревшем API

Эти типы статистики были добавлены в стандартный API, у которого нет соответствующего устаревшего типа:
  • codec : кодек, который в данный момент используется потоком RTP для кодирования или декодирования. Это подмножество кодеков, согласованных в SDP.
  • remote-inbound-rtp : входящий поток RTP удаленной конечной точки, соответствующий исходящему потоку RTP, который отправляет эта конечная точка ( outbound-rtp ). Он измеряется в удаленной конечной точке и сообщается в отчете получателя RTCP (RR) или расширенном отчете RTCP (XR).
  • remote-outbound-rtp : исходящий поток RTP удаленной конечной точки, соответствующий входящему потоку RTP, который получает эта конечная точка ( inbound-rtp ). Оно измеряется на удаленной конечной точке и сообщается в отчете отправителя RTCP (SR).
  • media-playout : метрики воспроизведения удаленного MediaStreamTrack , связанного с входящим потоком RTP ( inbound-rtp ).
  • data-channel : представляет RTCDataChannel .

Сопоставление устаревших и стандартных метрик

Это сопоставление призвано помочь разработчикам определить, какая устаревшая метрика соответствует какой стандартной метрике, но учтите, что соответствующая метрика может использовать другие единицы измерения или выражаться в виде общего счетчика, а не мгновенного значения. Определения метрик см. в спецификации.
Стандартный API предпочитает отображать общие счетчики, а не ставки. Это означает, что для получения соответствующей скорости (например, битрейта), как в устаревшем API, приложение должно вычислить среднюю скорость, взяв разницу между двумя вызовами getStats() . Например:

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

Самостоятельное вычисление ставок и средних значений может показаться обременительным дополнительным шагом, но у него есть и положительная сторона: вы можете получить средние значения за любой желаемый интервал времени. Вызов стандартного API реже, чем при использовании устаревшего API, дает некоторые преимущества в производительности.

Устаревшая метрика
googCertificate
Стандартная переписка
certificate
.googFingerprint .fingerprint
.googFingerprintAlgorithm .fingerprintAlgorithm
.googDerBase64 .base64Certificate
Устаревшая метрика
googComponent
Стандартная переписка
transport
.localCertificateId .localCertificateId
.remoteCertificateId .remoteCertificateId
.selectedCandidatePairId .selectedCandidatePairId
.dtlsCipher .dtlsCipher
.srtpCipher .srtpCipher
Устаревшая метрика
localcandidate
Стандартная переписка
local-candidate или candidate-pair
.stunKeepaliveRequestsSent candidate-pair.requestsSent (обратный поиск candidate-pair через 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
Устаревшая метрика
remotecandidate
Стандартная переписка
remote-candidate
То же, что и localcandidate выше. То же, что и local-candidate выше.
Устаревшая метрика
googCandidatePair
Стандартная переписка
candidate-pair
.responsesSent candidate-pair.responsesSent
.requestsReceived candidate-pair.requestsReceived
.googRemoteCandidateType remote-candidate.candidateType
(поиск remote-candidate через
candidate-pair.remoteCandidateId )
.googReadable googReadable — это логическое значение, указывающее, увеличивали ли мы недавно candidate-pair.requestsReceived или candidate-pair.responsesReceived
.googLocalAddress local-candidate.address
(поиск local-candidate через
candidate-pair.localCandidateId )
.consentRequestsSent candidate-pair.consentRequestsSent
.googTransportType То же, что local-candidate.protocol и remote-candidate.protocol .
.googChannelId candidate-pair.transportId
.googLocalCandidateType local-candidate.candidateType
.googWritable googWritable — это логическое значение, отражающее, увеличили ли мы недавно candidate-pair.responsesReceived
.googRemoteAddress remote-candidate.address
.googRtt candidate-pair.currentRoundTripTime
.googActiveConnection Активное соединение относится к паре-кандидату, которая в данный момент выбрана транспортом, например, где 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
Устаревшая метрика
ssrc
Стандартная переписка
inbound-rtp , outbound-rtp , media-source
.audioInputLevel media-source.audioLevel . Устаревшая метрика находится в диапазоне [0..32768], а стандартная метрика — в диапазоне [0..1].
.audioOutputLevel
inbound-rtp.audioLevel . Устаревшая метрика находится в диапазоне [0..32768], а стандартная метрика — в диапазоне [0..1].
.packetsLost inbound-rtp.packetsLost
.googTrackId media-source.trackIdentifier для локальных MediaStreamTrack и inbound-rtp.trackIdentifier для удаленных MediaStreamTrack
.googRtt remote-inbound-rtp.roundTripTime (см. outbound-rtp.remoteId )
.googEchoCancellationReturnLossEnhancement inbound-rtp.echoReturnLossEnhancement
.googCodecName Имя кодека является подтипом mime-типа «type/subtype», codec.mimeType (см. inbound-rtp.codecId и outbound-rtp.codecId ).
.transportId inbound-rtp.transportId и outbound-rtp.transportId
.mediaType inbound-rtp.kind и outbound-rtp.kind или media-source.kind
.googEchoCancellationReturnLoss inbound-rtp.echoReturnLoss
.totalAudioEnergy inbound-rtp.totalAudioEnergy и media-source.totalAudioEnergy
ssrc.totalSamplesDuration inbound-rtp.totalSamplesDuration и media-source.totalSamplesDuration
.ssrc inbound-rtp.ssrc и outbound-rtp.ssrc
.googJitterReceived inbound-rtp.jitter
.packetsSent outbound-rtp.packetsSent
.bytesSent outbound-rtp.bytesSent
.googContentType inbound-rtp.contentType и outbound-rtp.contentType
.googFrameWidthInput media-source.width
.googFrameHeightInput media-source.height
.googFrameRateInput media-source.framesPerSecond
.googFrameWidthSent outbound-rtp.frameWidth
.googFrameHeightSent outbound-rtp.frameHeight
.googFrameRateSent
Хотя FPS отправки — это скорость изменения outbound-rtp.framesSent , на самом деле это реализовано как outbound-rtp.framesPerSecond , который кодирует FPS.
.googFrameWidthReceived inbound-rtp.frameWidth
.googFrameHeightReceived inbound-rtp.frameHeight
.googFrameRateDecoded
Скорость изменения inbound-rtp.framesDecoded
.googFrameRateOutput
Скорость изменения inbound-rtp.framesDecodedinbound-rtp.framesDropped
.hugeFramesSent outbound-rtp.hugeFramesSent
.qpSum

inbound-rtp.qpSum и outbound-rtp.qpSum

.framesEncoded outbound-rtp.framesEncoded
.googAvgEncodeMs

outbound-rtp.totalEncodeTime / outbound-rtp.framesEncoded

.codecImplementationName

inbound-rtp.decoderImplementation и outbound-rtp.encoderImplementation

.googCpuLimitedResolution
True, если outbound-rtp.qualityLimitationReason == "cpu"
.googBandwidthLimitedResolution
True, если outbound-rtp.qualityLimitationReason == "bandwidth"
.googAdaptationChanges
Устаревшая метрика подсчитывает, сколько раз разрешение или частота кадров менялись по причинам, связанным qualityLimitationReason . Это можно вывести из других показателей (например, разрешение отправки или частота кадров отличается от исходного разрешения или частоты кадров), но продолжительность, которую мы ограничили, outbound-rtp.qualityLimitationDurations , может быть более полезной, чем частота разрешения или частоты кадров. изменено было перенастроено.
.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
Недавнее соотношение пакетов, содержащих исправление ошибок: inbound-rtp.fecPacketsReceivedinbound-rtp.fecPacketsDiscarded
.packetsReceived inbound-rtp.packetsReceived
.googJitterBufferMs inbound-rtp.jitterBufferDelay / inbound-rtp.jitterBufferEmittedCount
.googTargetDelayMs (видео) inbound-rtp.jitterBufferTargetDelay / inbound-rtp.jitterBufferEmittedCount
.googPreferredJitterBufferMs (аудио) inbound-rtp.jitterBufferTargetDelay / inbound-rtp.jitterBufferEmittedCount
.googExpandRate
Недавнее соотношение скрытых выборок: inbound-rtp.concealedSamples / inbound-rtp.totalSamplesReceived
.googSpeechExpandRate Недавнее соотношение скрытых выборок, пока поток не молчал: of ( inbound-rtp.concealedSamples - inbound-rtp.silentConcealedSamples ) / inbound-rtp.concealedSamples
.googAccelerateRate Недавнее соотношение семплов, которые были отброшены для ускорения скорости воспроизведения: inbound-rtp.removedSamplesForAcceleration / inbound-rtp.totalSamplesReceived
.googPreemptiveExpandRate
Недавнее соотношение семплов, синтезированных для замедления скорости воспроизведения: 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
Единственная оставшаяся гугл-метрика. inbound-rtp.googTimingFrameInfo
.framesDecoded inbound-rtp.framesDecoded
Устаревшая метрика
VideoBwe
Стандартная переписка
outbound-rtp и candidate-pair
.googTargetEncBitrate
outbound-rtp.targetBitrate как мгновенное значение или outbound-rtp.totalEncodedBytesTarget / outbound-rtp.framesEncoded как среднее значение
.googActualEncBitrate Байты, создаваемые кодировщиком, являются байтами полезной нагрузки, исключая повторные передачи: скорость изменения outbound-rtp.bytesSent - outbound-rtp.retransmittedBytesSent
.googBucketDelay outbound-rtp.totalPacketSendDelay / outbound-rtp.packetsSent
.googTransmitBitrate Скорость изменения outbound-rtp.headerBytesSent + outbound-rtp.bytesSent для битрейта каждого RTP-потока, candidate-pair.bytesSent для битрейта каждого кандидата ICE или transport.bytesSent для каждого транспортного битрейта
.googRetransmitBitrate Диапазон изменения outbound-rtp.retransmittedBytesSent
.googAvailableSendBandwidth candidate-pair.availableOutgoingBitrate
.googAvailableReceiveBandwidth candidate-pair.availableIncomingBitrate

Стандартный API поддерживает одновременную передачу

Если вы используете одновременную рассылку, вы, возможно, заметили, что устаревший API сообщает только об одном SSRC, даже если вы используете одновременную рассылку для отправки (например) трех потоков RTP по трем отдельным SSRC.

Стандартный API не разделяет это ограничение и возвращает три объекта статистики outbound-rtp , по одному для каждого из SSRC. Это означает, что вы можете анализировать каждый поток RTP индивидуально, но это также означает, что для получения общего битрейта всех потоков отправки RTP вам нужно будет агрегировать их самостоятельно.

С другой стороны, потоки SVC или потоки RTP с несколькими пространственными уровнями, настроенными через API scalabilityMode , по-прежнему отображаются как один outbound-rtp , поскольку они отправляются через один SSRC.

Если вам нужно больше времени для миграции

Когда устаревший API будет удален в Chrome 117, его использование приведет к возникновению исключения. Если вы не можете перенести свой код вовремя, пробная версия API getStats() на основе обратного вызова RTCPeerConnection дает зарегистрированным веб-сайтам больше времени для миграции. С пробным токеном происхождения устаревший API getStats() можно продолжать использовать до Chrome 121.