旧版 getStats()
WebRTC API 将在 Chrome 117 中移除,因此使用该 API 的应用需要迁移到标准 API。本文介绍了如何迁移代码,以及如果您需要更多时间来进行更改,该怎么做。
WebRTC getStats()
API 在过去有两个竞争版本。旧版 getStats() API(该 API 早于标准化过程并采用回调参数),以及受到广泛支持的标准化 API(会返回 promise)。
该标准 API 的功能更加丰富,并且具有明确定义的指标,详见 W3C 规范 WebRTC Statistics API 标识符。该规范包含对本指南中列出的每个指标的说明以及许多其他内容。
从 Chrome 117 开始,旧版 getStats()
API 会在稳定发布版本中抛出异常(异常抛出将逐步推出)。请按照本指南操作,轻松转换为标准 API。
旧版统计信息类型与标准统计信息类型
通过查看规范中的 RTCStatsType 枚举,可找到标准统计数据类型的完整列表。这包括哪个统计信息字典定义描述了为每种类型收集的指标。
统计信息对象都具有一个 id 属性,该属性可用于在多个 getStats()
调用中唯一地标识底层对象。每次调用该方法时,同一对象都将具有相同的 ID。这对于计算指标的变化率非常有用(我们将在下一部分中提供示例)。ID 还构成引用关系。例如,outbound-rtp
统计信息对象通过 outbound-rtp.mediaSourceId
属性引用关联的 media-source
统计信息对象。如果您绘制所有 ...Id
关系,则会得到一个图表。
旧版 API 具有以下统计信息类型,与标准类型相对应:
旧版类型 |
标准类型 |
---|---|
ssrc
|
表示 RTP 流和与关联的 MediaStreamTrack 相关的指标。标准类型为 inbound-rtp (用于接收 RTP 流及其关联的远程 MediaStreamTrack )、outbound-rtp (用于发送 RTP 流)和 media-source (用于与发送 RTP 流相关联的本地 MediaStreamTrack 指标)。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 中,它们没有任何对应的旧版类型:
|
旧版指标到标准指标的映射
此映射旨在帮助开发者找到哪个旧版指标与哪个标准指标相对应,但请注意,对应的指标可能会使用不同的单位,或者可能表示为总计数器,而不是瞬时值。如需了解指标定义,请参阅规范。
标准 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.localCandidateId 反向查找 candidate-pair ) |
.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 (通过 candidate-pair.remoteCandidateId 查找remote-candidate ) |
.googReadable
|
googReadable 是一个布尔值,表示我们最近是否递增了 candidate-pair.requestsReceived 或 candidate-pair.responsesReceived 。
|
.googLocalAddress
|
local-candidate.address (通过 candidate-pair.localCandidateId 查找local-candidate ) |
.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
|
编解码器名称是“type/subtype”MIME 类型 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.framesDecoded - inbound-rtp.framesDropped 的变化率 |
.hugeFramesSent
|
outbound-rtp.hugeFramesSent
|
.qpSum
|
|
.framesEncoded
|
outbound-rtp.framesEncoded
|
.googAvgEncodeMs
|
|
.codecImplementationName
|
|
.googCpuLimitedResolution
|
如果 outbound-rtp.qualityLimitationReason == "cpu" ,则为 true |
.googBandwidthLimitedResolution
|
如果 outbound-rtp.qualityLimitationReason == "bandwidth" ,则为 true |
.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.fecPacketsReceived - inbound-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
|
在音频流未静默期间,已隐藏样本的最近比率:(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
|
剩下的唯一一个 Google 指标。 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 具有联播感知能力
如果您使用联播,您可能已经注意到,即使您使用联播通过三个单独的 SSRC 发送(举例)三个 RTP 流,旧版 API 也只报告一个 SSRC。
标准 API 没有这种限制,会返回三个 outbound-rtp
统计信息对象,每个 SSRC 一个对象。这意味着您可以单独分析每个 RTP 流,但这也意味着要获取所有 RTP 发送流的总比特率,您需要自行聚合它们。
另一方面,带有通过 scalabilityMode
API 配置多个空间层的 SVC 流或 RTP 流仍显示为单个 outbound-rtp
,因为这些流通过单个 SSRC 发送。
如果您需要更多时间进行迁移
在 Chrome 117 中移除旧版 API 后,使用旧版 API 会引发异常。如果您无法及时迁移代码,不妨通过基于 RTCPeerConnection 回调的 getStats() API 的源试用为已注册网站留出更多时间进行迁移。借助源试用令牌,可在 Chrome 121 之前继续使用旧版 getStats() API。