Signatur
Beschreibung
Die Eigenschaft retransmittedBytesSent eines RTCOutboundRtpStreamStats-Objekts gibt an, wie viele Nutzlast-Bytes (ohne RTP-Header und Padding) für die mit diesem Stream verknüpfte SSRC bisher erneut übertragen wurden. Retransmissions entstehen typischerweise, wenn der Empfänger per RTCP-NACK verlorene Pakete anfordert und der Sender sie über einen RTX-Stream oder dieselbe SSRC neu sendet.
Der Wert ist eine Teilmenge von bytesSent: Die erneut gesendeten Bytes werden auch dort mitgezählt. Das Verhältnis retransmittedBytesSent / bytesSent ist deshalb eine gute Kennzahl dafür, wie viel Bandbreite durch Paketverlust „verschwendet“ wird. Zusammen mit retransmittedPacketsSent lässt sich die Qualität der Netzwerkverbindung aus Sicht des Senders beurteilen.
Man erhält das Objekt über RTCPeerConnection.getStats() oder RTCRtpSender.getStats(); relevant sind die Einträge mit type === "outbound-rtp". Da es sich um einen kumulativen Zähler handelt, muss man für Raten (z. B. Bytes pro Sekunde) die Differenz zwischen zwei Messungen durch die Differenz der timestamp-Werte teilen.
Rückgabewert
undefined, wenn der Browser die Kennzahl nicht liefert (z. B. keine RTX-Aushandlung oder fehlende Unterstützung).Beispiele
Retransmissions aller ausgehenden Streams auslesen
const logRetransmissions = async (pc) => {
const report = await pc.getStats();
report.forEach((stats) => {
if (stats.type === "outbound-rtp") {
console.log(
`${stats.kind} (SSRC ${stats.ssrc}): ` +
`${stats.retransmittedBytesSent ?? 0} von ${stats.bytesSent} Bytes erneut gesendet`
);
}
});
};
// pc ist eine verbundene RTCPeerConnection
await logRetransmissions(pc);
Retransmission-Anteil pro Sender berechnen
const retransmissionRatio = async (sender) => {
const report = await sender.getStats();
for (const stats of report.values()) {
if (stats.type === "outbound-rtp" && stats.bytesSent > 0) {
const ratio = (stats.retransmittedBytesSent ?? 0) / stats.bytesSent;
return Math.round(ratio * 10000) / 100; // Prozent, 2 Nachkommastellen
}
}
return null;
};
const [videoSender] = pc.getSenders().filter((s) => s.track?.kind === "video");
console.log(`Retransmission-Anteil: ${await retransmissionRatio(videoSender)} %`);
Retransmission-Rate in kbit/s überwachen
const monitorRetransmitRate = (sender, intervalMs = 2000) => {
let previous = null;
return setInterval(async () => {
const report = await sender.getStats();
const stats = [...report.values()].find((s) => s.type === "outbound-rtp");
if (!stats || stats.retransmittedBytesSent === undefined) return;
if (previous) {
const bytes = stats.retransmittedBytesSent - previous.retransmittedBytesSent;
const seconds = (stats.timestamp - previous.timestamp) / 1000;
const kbps = (bytes * 8) / 1000 / seconds;
console.log(`Retransmissions: ${kbps.toFixed(1)} kbit/s`);
if (kbps > 100) console.warn("Hoher Paketverlust – Bitrate reduzieren?");
}
previous = stats;
}, intervalMs);
};
const timer = monitorRetransmitRate(pc.getSenders()[0]);
// später: clearInterval(timer);
// Wichtig · Fallstricke
- Kumulativer Zähler: Der Wert wächst nur an. Für Raten immer die Differenz zweier Messungen bilden und durch die
timestamp-Differenz (Millisekunden) teilen. - Teilmenge von
bytesSent: Nicht zubytesSentaddieren – die Bytes sind dort bereits enthalten. Header- und Padding-Bytes sind in beiden Werten nicht enthalten (sieheheaderBytesSent). - Nur bei aktiver Retransmission: Ohne ausgehandeltes RTX bzw. NACK-Unterstützung (bei Audio meist der Fall) bleibt der Wert
0oder fehlt ganz. Defensiv mit?? 0auslesen. - Browser-Kompatibilität: Unterstützt in Chromium-basierten Browsern und Safari; Firefox liefert die Eigenschaft derzeit nicht. Vor der Nutzung auf
undefinedprüfen. - Bei Simulcast gibt es pro Layer (
rid) einen eigenenoutbound-rtp-Eintrag – für Gesamtwerte die Einträge aufsummieren.