Signatur
Beschreibung
Die Eigenschaft lastPacketReceivedTimestamp gehört zum Wörterbuch RTCIceCandidatePairStats, also zu den Statistikobjekten vom Typ "candidate-pair". Diese liefert RTCPeerConnection.getStats(). Der Wert ist ein DOMHighResTimeStamp in Millisekunden und gibt an, wann über dieses Kandidatenpaar zuletzt ein Paket empfangen wurde. Gezählt werden Pakete aller Art, also Medien- und Datenpakete ebenso wie STUN-Pakete zur Verbindungsprüfung.
Nützlich ist die Eigenschaft vor allem, um ausbleibende eingehende Pakete zu erkennen. Liegt der Zeitstempel deutlich hinter dem Zeitstempel des Berichts (stats.timestamp), kommt auf diesem Pfad nichts mehr an. Das kann ein Zeichen für einen Netzwerkausfall sein, für einen stummgeschalteten Sender oder für einen bevorstehenden ICE-Neustart.
Wie alle Statistik-Zeitstempel bezieht sich der Wert auf die Performance-Zeitbasis. Vergleichen solltest du ihn deshalb mit stats.timestamp oder performance.now() und nicht mit Date.now(). Wurde noch kein Paket empfangen, fehlt die Eigenschaft meist ganz.
Rückgabewert
undefined, wenn noch kein Paket empfangen wurde oder der Browser die Eigenschaft nicht unterstützt.Beispiele
Letzten Paketempfang des aktiven Kandidatenpaars auslesen
const logLastReceived = async (pc) => {
const report = await pc.getStats();
report.forEach((stats) => {
if (stats.type === 'candidate-pair' && stats.nominated && stats.state === 'succeeded') {
const ts = stats.lastPacketReceivedTimestamp;
if (ts === undefined) {
console.log('Noch kein Paket empfangen oder nicht unterstützt');
return;
}
const ageMs = stats.timestamp - ts;
console.log(`Letztes Paket vor ${ageMs.toFixed(0)} ms empfangen`);
}
});
};
// Aufruf mit einer bestehenden Verbindung:
// await logLastReceived(peerConnection);
Verbindungsabbruch per Watchdog erkennen
const watchIncoming = (pc, thresholdMs = 3000) => {
const timer = setInterval(async () => {
if (pc.connectionState === 'closed') {
clearInterval(timer);
return;
}
const report = await pc.getStats();
for (const stats of report.values()) {
if (stats.type !== 'candidate-pair' || !stats.nominated) continue;
const last = stats.lastPacketReceivedTimestamp;
if (last !== undefined && stats.timestamp - last > thresholdMs) {
console.warn('Seit über 3 s keine Pakete – ICE-Neustart wird eingeleitet');
pc.restartIce();
}
}
}, 1000);
return () => clearInterval(timer);
};
// const stopWatch = watchIncoming(peerConnection);
Empfang und Versand vergleichen
const compareTraffic = async (pc) => {
const report = await pc.getStats();
for (const s of report.values()) {
if (s.type === 'candidate-pair' && s.nominated) {
console.table({
zuletztEmpfangen: s.lastPacketReceivedTimestamp,
zuletztGesendet: s.lastPacketSentTimestamp,
bytesEmpfangen: s.bytesReceived,
bytesGesendet: s.bytesSent
});
}
}
};
// Wichtig · Fallstricke
- Browser-Kompatibilität: Chromium-Browser und Safari unterstützen die Eigenschaft, Firefox liefert sie derzeit nicht. Prüfe deshalb immer auf
undefined. - Zeitbasis: Der Wert ist ein
DOMHighResTimeStamp. Vergleiche ihn mitstats.timestampund nicht mitDate.now(), sonst entstehen völlig falsche Differenzen. - Richtiges Paar wählen: Ein Bericht kann mehrere
candidate-pair-Einträge enthalten. Für den aktiven Pfad filterst du nachnominatedundstate === "succeeded"oder folgstRTCTransportStats.selectedCandidatePairId. - STUN-Verbindungsprüfungen (Keepalives) aktualisieren den Wert ebenfalls. Ein frischer Zeitstempel bedeutet also nicht, dass auch Mediendaten ankommen. Dafür eignen sich
RTCInboundRtpStreamStatswielastPacketReceivedTimestampoderpacketsReceived. getStats()in kurzen Abständen abzufragen kostet CPU. Ein Intervall von 1 s ist für die Überwachung meist ausreichend.