WebRTC: دليل نقل بيانات getStats() القديم

Henrik Boström
Henrik Boström

ستتم إزالة واجهة برمجة التطبيقات WebRTC API القديمة في getStats() في الإصدار 117 من Chrome، وبالتالي يجب نقل التطبيقات التي تستخدمها إلى واجهة برمجة التطبيقات العادية. توضح هذه المقالة كيفية نقل الرمز وما يجب فعله إذا كنت بحاجة إلى مزيد من الوقت لإجراء هذا التغيير.

في السابق، كان هناك إصداران متنافسان من واجهة برمجة التطبيقات WebRTC getStats(). واجهة برمجة التطبيقات getStats() القديمة، التي تسبق عملية التوحيد، وتقبل وسيطة معاودة الاتصال، وواجهة برمجة التطبيقات الموحدة والمتوافقة على نطاق واسع التي تعرض وعودًا.

تتميز واجهة برمجة التطبيقات العادية بأكثر الميزات ثراءً وتتضمّن مقاييس محددة جيدًا تم توثيقها علنًا في مواصفات W3C معرّفات واجهة برمجة التطبيقات Statistics API في WebRTC. وتشتمل المواصفات على أوصاف لكل مقياس مذكور في هذا الدليل وغير ذلك الكثير.

بدايةً من Chrome 117، ستطرح واجهة برمجة التطبيقات getStats() القديمة استثناءً في قناة الإصدار الثابتة (سيتم طرح الاستثناء تدريجيًا). يمكنك اتّباع هذا الدليل لتسهيل عملية النقل إلى واجهة برمجة التطبيقات العادية.

أنواع الإحصاءات القديمة في مقابل أنواع الإحصاءات العادية

يمكن العثور على القائمة الكاملة لأنواع الإحصاءات العادية من خلال الاطّلاع على تعداد RTCStatsType في المواصفات. ويشمل ذلك تعريف قاموس الإحصاءات الذي يصف المقاييس التي يتم جمعها لكل نوع.

تحتوي جميع عناصر الإحصاءات على سمة معرّف تحدد العنصر الأساسي بشكل فريد في استدعاءات getStats() متعدّدة. سيكون للكائن نفس المعرف في كل مرة يتم فيها استدعاء الطريقة. وهذا مفيد لحساب معدل تغيير المقاييس (هناك مثال في القسم التالي). تشكل المعرفات أيضًا علاقات من المراجع. على سبيل المثال، يشير عنصر الإحصاءات outbound-rtp إلى كائن الإحصاءات media-source المرتبط من خلال السمة outbound-rtp.mediaSourceId. إذا رسمت كل العلاقات في ...Id، ستحصل على رسم بياني.

تتضمّن واجهة برمجة التطبيقات القديمة أنواع الإحصاءات التالية، والتي تتوافق مع الأنواع العادية على النحو التالي:


النوع القديم

النوع العادي
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.

غير متوفّرة من واجهة برمجة التطبيقات القديمة

تمّت إضافة أنواع الإحصاءات التالية إلى واجهة برمجة التطبيقات العادية التي لا تحتوي على أي نوع قديم مطابق:
  • 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.

ربط المقاييس القديمة بالمقاييس العادية

تهدف عملية الربط هذه إلى مساعدة المطوّرين في العثور على المقياس القديم المناسب لأي مقياس عادي، ولكن يُرجى العلم أنّ المقياس المقابل قد يستخدم وحدات مختلفة أو يتم التعبير عنه كعدّاد إجمالي بدلاً من قيمة لحظية. ارجع إلى مواصفات تعريفات المقاييس.
تفضل واجهة برمجة التطبيقات العادية عرض العدد الإجمالي للعدّادات بدلاً من عرض الأسعار. وهذا يعني أنّه للحصول على المعدّل المقابل (على سبيل المثال، معدل نقل البيانات) كما هو الحال في واجهة برمجة التطبيقات القديمة، يجب أن يحسب التطبيق متوسط المعدّل من خلال نقل قيمة دلتا بين مكالمتَي 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;

قد يبدو الاضطرار إلى حساب المعدلات والمتوسطات بنفسك مثل هذا خطوة إضافية مرهقة، إلا أن له جانبًا إيجابيًا يسمح لك بالحصول على متوسطات خلال أي فترة زمنية مطلوبة. وهناك بعض فوائد طلب البيانات من واجهة برمجة التطبيقات العادية بمعدل أقل مما قد يكون عليك طلبها من واجهة برمجة التطبيقات القديمة.

المقياس القديم
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 "النوع/النوع الفرعي" 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

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
صحيح إذا كانت outbound-rtp.qualityLimitationReason == "cpu"
.googBandwidthLimitedResolution
صحيح إذا كانت 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 الوحيد المتبقي 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 لمعدل نقل البيانات لكل عملية بث في الوقت الفعلي، أو candidate-pair.bytesSent لمعدل نقل البيانات المرشح لكل ICE، أو transport.bytesSent لمعدل نقل البيانات لكل عملية نقل
.googRetransmitBitrate نطاق التغيير في outbound-rtp.retransmittedBytesSent
.googAvailableSendBandwidth candidate-pair.availableOutgoingBitrate
.googAvailableReceiveBandwidth candidate-pair.availableIncomingBitrate

واجهة برمجة التطبيقات العادية تعتمد على تقنية البث المتزامن

إذا كنت تستخدم البث المتزامن، ربما لاحظت أنّ واجهة برمجة التطبيقات القديمة لا تُبلغ إلا عن رمز SSRC واحد حتى إذا كنت تستخدم البث المتزامن لإرسال ثلاثة عمليات بث من بروتوكول النقل في الوقت الفعلي (RTP) عبر ثلاثة رموز SSRC منفصلة (مثلاً).

لا تشارك واجهة برمجة التطبيقات العادية هذا القيد، وستعرِض ثلاثة عناصر لإحصاءات outbound-rtp، أحدها لكل رمز من رموز SSRC. وهذا يعني أنّه بإمكانك تحليل كل بث من بروتوكول RTP على حدة، ولكن عليك أيضًا تجميع هذه البيانات بنفسك للحصول على إجمالي معدل نقل البيانات لكل مجموعات البث التي تستخدم بروتوكول RTP.

أمّا مجموعات بث SVC أو بروتوكول RTP، فيمكنها أن تظهر كطبقات مكانية متعدّدة تم ضبطها عبر واجهة برمجة تطبيقات scalabilityMode باعتبارها outbound-rtp واحدة، لأنّه يتم إرسالها عبر رمز SSRC واحد.

في حال كنت بحاجة إلى مزيد من الوقت لنقل البيانات

عند إزالة واجهة برمجة التطبيقات القديمة في الإصدار 117 من Chrome، سيؤدي استخدامها إلى إنشاء استثناء. إذا لم تتمكّن من نقل الرمز في الوقت المناسب، ستمنح تجربة المصدر لـ RTCPeerConnection API المستندة إلى معاودة الاتصال getStats() المواقع الإلكترونية المُسجَّلة مزيدًا من الوقت لنقل البيانات. باستخدام رمز مميّز لمرحلة التجربة والتقييم، قد يستمر استخدام واجهة برمجة التطبيقات getStats() القديمة حتى إصدار Chrome 121.