WebRTC: 従来の getStats() 移行ガイド

Henrik Boström
Henrik Boström

従来の getStats() WebRTC API は Chrome 117 で削除されるため、この API を使用しているアプリは標準 API に移行する必要があります。この記事では、コードを移行する方法と、この変更にさらに時間が必要になった場合の対処方法について説明します。

これまで、WebRTC getStats() API には競合する 2 つのバージョンがありました。標準化プロセスより前のコールバック引数を受け取る従来の getStats() API と、標準化され広くサポートされている Promise を返す API です。

標準 API は機能が豊富で、W3C 仕様 Identifiers for WebRTC's Statistics API で公開されている明確に定義された指標があります。この仕様には、このガイドで説明する各指標の説明など、多くの情報が含まれています。

Chrome 117 以降、以前の getStats() API は Stable リリース チャンネルで例外をスローします(例外のスローは段階的にロールアウトされます)。このガイドに沿って、標準 API への移行をスムーズに進めてください。

レガシー統計情報と標準統計情報の違い

標準の統計情報の種類の一覧については、仕様の RTCStatsType 列挙型をご覧ください。これには、各タイプで収集された指標を記述する統計ディクショナリ定義が含まれます。

統計情報オブジェクトにはすべて、複数の getStats() 呼び出しで基になるオブジェクトを一意に識別する id 属性があります。メソッドが呼び出されるたびに、同じオブジェクトに同じ 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-rtpinbound-rtp)と ICE 候補ペア指標(candidate-pair)の一部です。
googComponent
トランスポート(ICE と DTLS)を表します。標準バージョンは transport です。
localcandidate and remotecandidate
ICE 候補を表します。標準バージョンは local-candidateremote-candidate です。
googCandidatePair
ローカル候補とリモート候補のペアである ICE 候補ペアを表します。標準バージョンは candidate-pair です。
googCertificate
DTLS トランスポートで使用される証明書を表します。標準バージョンは certificate です。
googLibjingleSession
RTCPeerConnection を表します。内容は標準のどの項目にもマッピングされていませんが、標準には RTCPeerConnection に関連付けられた型(peer-connection)があります。

従来の API にはありません

以下の統計情報の種類は、対応する以前のタイプがない標準 API に追加されました。
  • codec: エンコードまたはデコードのために RTP ストリームで現在使用されているコーデック。これは、SDP でネゴシエートされたコーデックのサブセットです。
  • remote-inbound-rtp: このエンドポイントが送信しているアウトバウンド RTP ストリーム(outbound-rtp)に対応するリモート エンドポイントのインバウンド RTP ストリーム。リモート エンドポイントで測定され、RTCP レシーバ レポート(RR)または RTCP 拡張レポート(XR)で報告されます。
  • remote-outbound-rtp: このエンドポイントが受信しているインバウンド RTP ストリーム(inbound-rtp)に対応するリモート エンドポイントのアウトバウンド RTP ストリーム。リモート エンドポイントで測定され、RTCP Sender Report(SR)で報告されます。
  • media-playout: インバウンド RTP ストリーム(inbound-rtp)に関連付けられたリモート MediaStreamTrack の再生に関する指標。
  • data-channel: RTCDataChannel を表します。

従来指標と標準指標のマッピング

このマッピングは、どのレガシー指標がどの標準指標に対応しているかをデベロッパーが把握できるようにすることを目的としています。ただし、対応する指標で異なる単位が使用されている場合や、瞬間値ではなく合計カウンタとして表されている場合があります。指標の定義については、仕様をご覧ください。
標準 API では、レートではなく合計カウンタを公開することをおすすめします。つまり、従来の API と同様に対応するレート(ビットレートなど)を取得するには、2 つの 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.requestsSentcandidate-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.protocolremote-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-rtpoutbound-rtpmedia-source
.audioInputLevel media-source.audioLevel。従来の指標の範囲は [0..32768] ですが、標準指標の範囲は [0..1] です。
.audioOutputLevel
inbound-rtp.audioLevel。従来の指標の範囲は [0..32768] ですが、標準指標の範囲は [0..1] です。
.packetsLost inbound-rtp.packetsLost
.googTrackId ローカル MediaStreamTrack の場合は media-source.trackIdentifier、リモート MediaStreamTrack の場合は inbound-rtp.trackIdentifier
.googRtt remote-inbound-rtp.roundTripTimeoutbound-rtp.remoteId を参照)
.googEchoCancellationReturnLossEnhancement inbound-rtp.echoReturnLossEnhancement
.googCodecName コーデック名は、「type/subtype」MIME タイプ codec.mimeType のサブタイプです(inbound-rtp.codecIdoutbound-rtp.codecId を参照)。
.transportId inbound-rtp.transportIdoutbound-rtp.transportId
.mediaType inbound-rtp.kindoutbound-rtp.kind、または 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 は outbound-rtp.framesSent の変化率ですが、実際には FPS をエンコードする outbound-rtp.framesPerSecond として実装されます。
.googFrameWidthReceived inbound-rtp.frameWidth
.googFrameHeightReceived inbound-rtp.frameHeight
.googFrameRateDecoded
inbound-rtp.framesDecoded の変化率
.googFrameRateOutput
inbound-rtp.framesDecoded - inbound-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
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-rtpcandidate-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 RTP ストリームごとのビットレートの場合は outbound-rtp.headerBytesSent + outbound-rtp.bytesSent、ICE 候補ごとのビットレートの場合は candidate-pair.bytesSent、トランスポートごとのビットレートの場合は transport.bytesSent の変化率
.googRetransmitBitrate outbound-rtp.retransmittedBytesSent の変化範囲
.googAvailableSendBandwidth candidate-pair.availableOutgoingBitrate
.googAvailableReceiveBandwidth candidate-pair.availableIncomingBitrate

標準 API はシミュラキャストに対応しています

シミュラキャストを使用している場合、シミュラキャストを使用して 3 つの個別の SSRC を介して 3 つの RTP ストリームを送信している場合でも、以前の API では 1 つの SSRC しか報告されないことに気づいたかもしれません。

標準 API にはこの制限はなく、SSRC ごとに 1 つずつ、3 つの outbound-rtp 統計情報オブジェクトが返されます。つまり、各 RTP ストリームを個別に分析できますが、すべての RTP 送信ストリームの合計ビットレートを取得するには、それらを自分で集計する必要があります。

一方、scalabilityMode API で複数の空間レイヤが構成された SVC ストリームまたは RTP ストリームは、単一の SSRC 経由で送信されるため、引き続き単一の outbound-rtp として表示されます。

移行にさらに時間が必要な場合

Chrome 117 で以前の API が削除されると、その API を使用すると例外が発生します。コードを期限までに移行できない場合は、RTCPeerConnection コールバック ベースの getStats() API のオリジン トライアルを利用すると、登録済みのウェブサイトは移行期間を延長できます。オリジン トライアル トークンを使用すると、従来の getStats() API は Chrome 121 まで引き続き使用できます。