Signatur
Beschreibung
Die schreibgeschützte Eigenschaft timestamp eines RTCInboundRtpStreamStats-Objekts (Eintrag mit type === "inbound-rtp" in einem RTCStatsReport) gibt an, wann die Werte in diesem Objekt erfasst wurden. Der Wert ist ein DOMHighResTimeStamp, also eine Zahl in Millisekunden (mit Nachkommastellen). Laut Spezifikation bezieht er sich auf die Unix-Epoche (1. Januar 1970, UTC).
Wichtig ist die Eigenschaft vor allem für Berechnungen über die Zeit. Kennzahlen wie bytesReceived, packetsReceived, packetsLost oder framesDecoded sind Zähler, die nur ansteigen. Eine Rate wie Bitrate, Paketverlust pro Sekunde oder Bildrate bekommt man erst, wenn man die Differenz zweier Messungen durch die Differenz ihrer timestamp-Werte teilt.
Man sollte immer timestamp aus dem Bericht verwenden und nicht die eigene Uhrzeit beim Aufruf von getStats() (z. B. Date.now()). Zwischen dem Erfassen der Werte und dem Auflösen des Promise kann einige Zeit vergehen, und Browser liefern Statistiken teilweise aus einem Zwischenspeicher.
Rückgabewert
Beispiele
Zeitstempel eines eingehenden Streams auslesen
// pc ist eine verbundene RTCPeerConnection
const logInboundTimestamps = async (pc) => {
const report = await pc.getStats();
report.forEach((stats) => {
if (stats.type === 'inbound-rtp') {
console.log(stats.kind, stats.timestamp, new Date(stats.timestamp).toISOString());
}
});
};
logInboundTimestamps(pc);
Empfangs-Bitrate aus zwei Messungen berechnen
const previous = new Map(); // Stats-ID -> letzte Messung
const measureBitrate = async (pc) => {
const report = await pc.getStats();
for (const stats of report.values()) {
if (stats.type !== 'inbound-rtp') continue;
const prev = previous.get(stats.id);
if (prev) {
const deltaMs = stats.timestamp - prev.timestamp;
// Ohne neue Messung (Zwischenspeicher) nicht durch 0 teilen
if (deltaMs > 0) {
const bits = (stats.bytesReceived - prev.bytesReceived) * 8;
const kbps = bits / deltaMs; // Bit pro ms = kbit/s
console.log(`${stats.kind}: ${kbps.toFixed(1)} kbit/s`);
}
}
previous.set(stats.id, stats);
}
};
const timer = setInterval(() => measureBitrate(pc), 1000);
// später: clearInterval(timer);
Bildrate und Paketverlustrate pro Sekunde
let last = null;
const sampleVideo = async (receiver) => {
// Statistiken nur für einen RTCRtpReceiver abfragen
const report = await receiver.getStats();
const inbound = [...report.values()].find((s) => s.type === 'inbound-rtp');
if (!inbound) return;
if (last && inbound.timestamp > last.timestamp) {
const seconds = (inbound.timestamp - last.timestamp) / 1000;
const fps = (inbound.framesDecoded - last.framesDecoded) / seconds;
const lostPerSec = (inbound.packetsLost - last.packetsLost) / seconds;
console.log({ fps: Math.round(fps), lostPerSec: lostPerSec.toFixed(2) });
}
last = inbound;
};
const [videoReceiver] = pc.getReceivers().filter((r) => r.track.kind === 'video');
setInterval(() => sampleVideo(videoReceiver), 2000);
// Wichtig · Fallstricke
- Delta auf 0 prüfen: Browser speichern Statistiken teilweise kurz zwischen. Zwei schnelle
getStats()-Aufrufe können deshalb denselbentimestampliefern. Vor dem Teilen immer aufdeltaMs > 0prüfen. - Nicht mit
performance.now()mischen: Der Wert bezieht sich auf die Unix-Epoche, nicht aufperformance.timeOrigin. Zum Vergleich mitperformance.now()muss manperformance.timeOriginaddieren. Ältere Browserversionen hatten hier teils andere Bezugspunkte. Am sichersten ist es, nur Zeitstempel aus derselben Quelle voneinander abzuziehen. - Nicht mit
remoteTimestampverwechseln:remoteTimestampinRTCRemoteOutboundRtpStreamStatsist die Uhrzeit der Gegenstelle. Die ist nicht mit der lokalen Uhr abgeglichen. - Einträge über ihre
idzuordnen: Beim Berechnen von Raten Messungen überstats.idzuordnen, nicht über ihre Position im Bericht. Wenn Streams neu verhandelt werden, können Einträge wegfallen oder neu hinzukommen. - Browserunterstützung: Die Eigenschaft ist in allen aktuellen Browsern mit WebRTC vorhanden. Welche anderen Felder von
inbound-rtpes gibt, unterscheidet sich aber je nach Browser.