Signatur
Beschreibung
Die schreibgeschützte Eigenschaft timestamp eines RTCOutboundRtpStreamStats-Objekts gibt an, wann die Werte dieses Statistik-Eintrags erfasst wurden. Der Wert ist ein DOMHighResTimeStamp, also eine Zahl in Millisekunden, gemessen ab der UNIX-Epoche (1. Januar 1970, UTC). Er kann Nachkommastellen haben.
Solche Objekte bekommst du über RTCPeerConnection.getStats() oder RTCRtpSender.getStats(). Sie stehen im zurückgegebenen RTCStatsReport unter dem Typ "outbound-rtp". Die Eigenschaft wird vom Basis-Wörterbuch RTCStats geerbt. Deshalb haben auch alle anderen Statistik-Typen (z. B. inbound-rtp oder candidate-pair) einen timestamp.
In der Praxis brauchst du timestamp vor allem, um Raten zu berechnen. Zähler wie bytesSent, packetsSent oder framesEncoded steigen nur an. Erst wenn du den Unterschied zweier Messungen durch den zeitlichen Abstand ihrer timestamp-Werte teilst, erhältst du Bitrate, Paketrate oder Bildrate. Das ist genauer, als mit dem Zeitpunkt des eigenen setInterval-Aufrufs zu rechnen, weil der Browser die Daten nicht genau dann erfasst, wenn du sie abfragst.
Rückgabewert
Beispiele
Zeitstempel aller ausgehenden RTP-Streams ausgeben
// pc ist eine bestehende, verbundene RTCPeerConnection
const logOutboundTimestamps = async (pc) => {
const report = await pc.getStats();
report.forEach((stats) => {
if (stats.type === 'outbound-rtp') {
const zeit = new Date(stats.timestamp).toISOString();
console.log(`${stats.kind} (SSRC ${stats.ssrc}) erfasst um ${zeit}`);
}
});
};
await logOutboundTimestamps(pc);
Sende-Bitrate aus zwei Messungen berechnen
const getOutboundVideo = async (sender) => {
const report = await sender.getStats();
return [...report.values()].find((s) => s.type === 'outbound-rtp');
};
const sender = pc.getSenders().find((s) => s.track?.kind === 'video');
let vorher = await getOutboundVideo(sender);
setInterval(async () => {
const jetzt = await getOutboundVideo(sender);
if (!jetzt || !vorher) return;
const deltaMs = jetzt.timestamp - vorher.timestamp;
const deltaBytes = jetzt.bytesSent - vorher.bytesSent;
if (deltaMs > 0) {
const kbps = (deltaBytes * 8) / deltaMs; // Bit pro ms = kbit/s
console.log(`Sende-Bitrate: ${kbps.toFixed(1)} kbit/s`);
}
vorher = jetzt;
}, 1000);
Bildrate beim Kodieren messen und veraltete Daten erkennen
let letzte = null;
const pruefeEncoder = async () => {
const report = await pc.getStats();
const out = [...report.values()].find(
(s) => s.type === 'outbound-rtp' && s.kind === 'video'
);
if (!out) return;
if (letzte && out.timestamp === letzte.timestamp) {
console.log('Keine neuen Statistikdaten (Cache des Browsers)');
return;
}
if (letzte) {
const sekunden = (out.timestamp - letzte.timestamp) / 1000;
const fps = (out.framesEncoded - letzte.framesEncoded) / sekunden;
console.log(`Kodierte Bilder pro Sekunde: ${fps.toFixed(1)}`);
}
letzte = out;
};
setInterval(pruefeEncoder, 2000);
// Wichtig · Fallstricke
- Bezugspunkt: Der Wert zählt ab der UNIX-Epoche, nicht ab
performance.timeOrigin. Du kannst ihn also direkt annew Date()übergeben. Mitperformance.now()kannst du ihn dagegen nicht direkt vergleichen. - Caching: Browser speichern Statistiken für kurze Zeit zwischen (in Chrome ungefähr bis zu 50 ms). Zwei schnell aufeinanderfolgende Aufrufe von
getStats()können deshalb denselbentimestampliefern. Prüfe vor dem Teilen immer, obdeltaMs > 0ist, sonst teilst du durch null. - Nur Differenzen zwischen denselben Objekten: Vergleiche nur Einträge mit derselben
idbzw.ssrc. Bei Simulcast gibt es mehrereoutbound-rtp-Einträge, einen pro Ebene. Nach einer Neuverhandlung können außerdem die Zähler neu beginnen. - Genauigkeit: Wegen des Schutzes vor Timing-Angriffen kann die Auflösung vergröbert sein. Für Raten im Sekundenbereich spielt das keine Rolle.
- Kompatibilität: Die Eigenschaft funktioniert in allen aktuellen Browsern. Ältere Chrome-Versionen haben mit der veralteten, auf Rückruffunktionen basierenden Variante von
getStats()ein anderes Format geliefert. Nutze die Promise-Variante.