旧版 getStats()
WebRTC API 将在 Chrome 117 中移除,因此使用该 API 的应用需要迁移到标准 API。本文介绍了如何迁移代码,以及如果您需要更多时间来进行此更改,该怎么做。
历史上,WebRTC getStats()
API 有两个相互竞争的版本。旧版 getStats() API(早于标准化流程,并接受回调参数),以及标准化且广泛受支持的 API(会返回 Promise)。
标准 API 功能更丰富,并且在 W3C 规范 WebRTC 统计信息 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
|
仅剩的 goog-metric。 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 发送的。
如果您需要更多时间进行迁移
当旧版 API 在 Chrome 117 中被移除后,使用该 API 将会生成异常。如果您无法及时迁移代码,基于 RTCPeerConnection 回调的 getStats() API 的源代码试用可让已注册的网站有更多时间进行迁移。在 Chrome 121 之前,您可以使用源试用令牌继续使用旧版 getStats() API。