Signatur
Beschreibung
Die Eigenschaft estimatedPlayoutTimestamp gehört zu den Statistiken eines eingehenden RTP-Streams (type: "inbound-rtp"), die du über RTCPeerConnection.getStats() oder RTCRtpReceiver.getStats() abrufst. Sie gibt an, an welcher Stelle der Wiedergabe sich der Track gerade befindet, und zwar als Zeitstempel auf der NTP-Uhr des Senders.
Ermittelt wird der Wert aus dem letzten abspielbaren Audio-Sample bzw. Videoframe, dessen RTP-Zeitstempel sich über einen RTCP-Sender-Report (SR) einer NTP-Zeit zuordnen lässt. Dazu kommt die Zeit, die vergangen ist, seit dieses Sample oder dieser Frame zur Wiedergabe bereit war. Man kann den Wert also als „aktuelle Zeit“ des Tracks aus Sicht des Senders verstehen. Er kann auch dann vorhanden sein, wenn gerade kein Ton zu hören ist.
Am meisten bringt die Eigenschaft bei der Messung der Lippensynchronität: Wenn Audio- und Video-Track von derselben Quelle stammen (also dieselbe Sender-Uhr nutzen), zeigt die Differenz audioStats.estimatedPlayoutTimestamp - videoStats.estimatedPlayoutTimestamp ungefähr, wie weit Ton und Bild auseinanderlaufen. Nützlich ist das für Überwachung, Fehlersuche und Qualitätsmetriken in Videokonferenz- oder Streaming-Anwendungen.
Rückgabewert
DOMHighResTimeStamp in Millisekunden, bezogen auf die NTP-Epoche des Senders (1. Januar 1900). Er ist undefined, solange noch kein RTCP-Sender-Report empfangen wurde oder wenn der Browser die Eigenschaft nicht unterstützt.Beispiele
Wiedergabezeit eines empfangenen Tracks auslesen
// pc ist eine bestehende, verbundene RTCPeerConnection
const logPlayoutTimestamps = async (pc) => {
const stats = await pc.getStats();
stats.forEach((report) => {
if (report.type === 'inbound-rtp') {
console.log(
`${report.kind}: estimatedPlayoutTimestamp =`,
report.estimatedPlayoutTimestamp ?? 'noch nicht verfügbar'
);
}
});
};
await logPlayoutTimestamps(pc);
Versatz zwischen Audio und Video (Lippensynchronität) messen
const measureAvSync = async (pc) => {
const stats = await pc.getStats();
let audio, video;
for (const report of stats.values()) {
if (report.type !== 'inbound-rtp') continue;
if (report.kind === 'audio') audio = report;
if (report.kind === 'video') video = report;
}
if (audio?.estimatedPlayoutTimestamp === undefined ||
video?.estimatedPlayoutTimestamp === undefined) {
console.warn('Wiedergabe-Zeitstempel nicht verfügbar');
return null;
}
// Positiv: Audio läuft dem Video voraus
const offsetMs = audio.estimatedPlayoutTimestamp - video.estimatedPlayoutTimestamp;
console.log(`A/V-Versatz: ${offsetMs.toFixed(1)} ms`);
return offsetMs;
};
await measureAvSync(pc);
Synchronität regelmäßig überwachen und bei großem Versatz warnen
const THRESHOLD_MS = 80;
const startSyncMonitor = (pc, intervalMs = 2000) => {
const id = setInterval(async () => {
const stats = await pc.getStats();
const byKind = {};
stats.forEach((r) => {
if (r.type === 'inbound-rtp') byKind[r.kind] = r.estimatedPlayoutTimestamp;
});
if (byKind.audio != null && byKind.video != null) {
const diff = Math.abs(byKind.audio - byKind.video);
if (diff > THRESHOLD_MS) {
console.warn(`Lippensynchronität gestört: ${diff.toFixed(0)} ms`);
}
}
}, intervalMs);
// Beim Schließen der Verbindung aufräumen
pc.addEventListener('connectionstatechange', () => {
if (pc.connectionState === 'closed') clearInterval(id);
});
return () => clearInterval(id);
};
const stopMonitor = startSyncMonitor(pc);
// Wichtig · Fallstricke
- Browser-Kompatibilität: Die Eigenschaft wird vor allem von Chromium-basierten Browsern geliefert. Firefox und Safari stellen sie teilweise gar nicht bereit. Prüfe deshalb immer auf
undefined, bevor du den Wert verwendest. - Kein lokaler Zeitstempel: Der Wert stammt von der NTP-Uhr des Senders. Ein direkter Vergleich mit
performance.now(),Date.now()oder dem Feldtimestampdesselben Berichts ist nicht sinnvoll. Zudem beginnt die NTP-Epoche 1900 und nicht 1970 wie die Unix-Zeit. - Nur Tracks derselben Quelle vergleichen: Die A/V-Differenz ist nur dann aussagekräftig, wenn beide Tracks von derselben Sender-Uhr stammen, also typischerweise aus demselben
MediaStreamdesselben Teilnehmers. - Anlaufphase: Solange noch kein RTCP-Sender-Report angekommen ist, fehlt der Wert. Das ist in den ersten Sekunden einer Verbindung normal.
- Näherungswert: Es handelt sich um eine Schätzung. Jitter-Buffer, Decoder-Verzögerung und Rendering können den tatsächlichen Wiedergabezeitpunkt leicht verschieben. Für Trendanalysen solltest du mehrere Messwerte mitteln.
- Leistung:
getStats()ist asynchron und nicht kostenlos. Frage die Statistik nicht öfter als etwa einmal pro Sekunde ab.