ממשק ה-API הקודם של WebRTC getStats()
יוסר ב-Chrome 117, ולכן אפליקציות שמשתמשות בו יצטרכו לעבור ל-API הסטנדרטי. במאמר הזה נסביר איך להעביר את הקוד ואיך לפעול אם אתם זקוקים לזמן נוסף לביצוע השינוי.
בעבר היו שתי גרסאות מתחרות של ממשק ה-API getStats()
של WebRTC. ממשק ה-API הקודם getStats(), שקדם לתהליך הסטנדרטיזציה ומקבל ארגומנט של קריאה חוזרת (callback), וממשק ה-API הסטנדרטי שנתמך באופן נרחב ומחזיר הבטחה (promise).
ה-API הסטנדרטי עשיר יותר בתכונות, ויש לו מדדים מוגדרים היטב שמתועדים באופן ציבורי במפרט W3C מזהי Statistics API של WebRTC. המפרט כולל תיאורים של כל המדדים שמפורטים במדריך הזה ועוד רבים.
החל מגרסה Chrome 117, ממשק ה-API הקודם getStats()
יגרום להשלכת חריגה בערוץ הגרסה היציבה (השלכת החריגה תושק בהדרגה). כדי להקל על המעבר ל-API הרגיל, כדאי לפעול לפי המדריך הזה.
סוגי נתונים סטטיסטיים מדור קודם לעומת סוגי נתונים סטטיסטיים רגילים
הרשימה המלאה של סוגי הנתונים הסטנדרטיים מופיעה ב-enum 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 הסטנדרטי, ואין להם סוג תואם מדור קודם:
|
מיפוי מדדים מדור קודם למדדים רגילים
המיפוי הזה נועד לעזור למפתחים למצוא איזה מדד מדור קודם תואם לכל מדד רגיל, אבל חשוב לזכור שבמדד התואם עשויות להיות יחידות מידה שונות או שהוא עשוי להתבטא כמספר מצטבר במקום כערך מיידי. ההגדרות של המדדים מפורטות במפרט.
ב-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 (lookup remote-candidate via candidate-pair.remoteCandidateId ) |
.googReadable
|
googReadable הוא ערך בוליאני שמשקף אם העלינו לאחרונה את הערך של candidate-pair.requestsReceived או candidate-pair.responsesReceived או לא.
|
.googLocalAddress
|
local-candidate.address (lookup local-candidate via 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
|
קצב הפריימים לשליחה הוא קצב השינוי של outbound-rtp.framesSent , אבל הוא מיושם בפועל כ-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
|
|
.framesEncoded
|
outbound-rtp.framesEncoded
|
.googAvgEncodeMs
|
|
.codecImplementationName
|
|
.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.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 הרגיל מודע לשידור סימולטני
אם אתם משתמשים בשידור סימולטני, יכול להיות שמתם לב ש-API הקודם מדווח רק על SSRC יחיד, גם אם אתם משתמשים בשידור סימולטני כדי לשלוח (לדוגמה) שלושה מקורות נתונים של RTP דרך שלושה SSRC נפרדים.
ב-API הסטנדרטי אין את המגבלה הזו, והוא יחזיר שלושה אובייקטים סטטיסטיים מסוג outbound-rtp
, אחד לכל אחד מ-SSRC. המשמעות היא שאפשר לנתח כל שידור RTP בנפרד, אבל גם שצריך לצבור אותם בעצמכם כדי לקבל את קצב הנתונים הכולל של כל השידורים של RTP.
לעומת זאת, שידורי SVC או שידורי RTP עם כמה שכבות מרחביות שהוגדרו דרך ה-API של scalabilityMode
עדיין מופיעים כ-outbound-rtp
יחיד, כי הם נשלחים דרך SSRC יחיד.
אם אתם זקוקים לזמן נוסף להעברה
כשממשק ה-API הקודם יוסר ב-Chrome 117, השימוש בו יגרום ליצירת חריגה. אם אין לכם אפשרות להעביר את הקוד בזמן, תקופת הניסיון למקור של ממשק ה-API getStats() שמבוסס על קריאה חוזרת (callback) של RTCPeerConnection מעניקה לאתרים רשומים יותר זמן להעברה. באמצעות אסימון לגרסת המקור לניסיון, אפשר להמשיך להשתמש ב-API הקודם getStats() עד Chrome 121.