Signatur
Beschreibung
Die schreibgeschützte Eigenschaft bytesSent ist Teil der Statistikobjekte vom Typ "outbound-rtp". Diese Objekte liefert RTCPeerConnection.getStats() bzw. RTCRtpSender.getStats(). Der Wert ist ein Zähler, der nur wächst: Er gibt an, wie viele Bytes an RTP-Nutzlast für die zugehörige SSRC seit Beginn der Übertragung gesendet wurden. Gezählt wird wie beim „sender's octet count“ aus RFC 3550, Abschnitt 6.4.1. RTP-Header und Padding sind also nicht enthalten. Erneut übertragene Pakete (Retransmissions) zählt die Spezifikation dagegen mit.
Anders als die MDN-Kurzbeschreibung vermuten lässt, geht es hier nicht um einen RTCDataChannel. Die Eigenschaft bezieht sich auf einen ausgehenden Audio- oder Videostream (RTP). Für Datenkanäle gibt es die Statistikobjekte vom Typ "data-channel", die ebenfalls eine eigene Eigenschaft bytesSent haben.
Praktisch nutzt man bytesSent vor allem, um die tatsächliche Sende-Bitrate zu berechnen. Dazu fragt man die Statistik in regelmäßigen Abständen ab, bildet die Differenz zweier Messwerte und teilt sie durch die Differenz der timestamp-Werte. So lassen sich Bandbreitenanpassung, Simulcast-Schichten oder Netzwerkprobleme überwachen und in Dashboards darstellen.
Rückgabewert
unsigned long long): die Summe aller bisher für diese SSRC gesendeten Nutzlast-Bytes.Beispiele
Gesendete Bytes aller ausgehenden Streams ausgeben
const logBytesSent = async (pc) => {
const report = await pc.getStats();
report.forEach((stats) => {
if (stats.type === 'outbound-rtp') {
console.log(`${stats.kind} (SSRC ${stats.ssrc}): ${stats.bytesSent} Bytes gesendet`);
}
});
};
// pc ist eine verbundene RTCPeerConnection
await logBytesSent(pc);
Sende-Bitrate pro Sekunde berechnen
const monitorBitrate = (sender, intervalMs = 1000) => {
let last = null;
return setInterval(async () => {
const report = await sender.getStats();
for (const stats of report.values()) {
if (stats.type !== 'outbound-rtp') continue;
if (last) {
const bytes = stats.bytesSent - last.bytesSent;
const seconds = (stats.timestamp - last.timestamp) / 1000;
const kbps = ((bytes * 8) / seconds / 1000).toFixed(1);
console.log(`Aktuelle Bitrate: ${kbps} kbit/s`);
}
last = { bytesSent: stats.bytesSent, timestamp: stats.timestamp };
}
}, intervalMs);
};
const [videoSender] = pc.getSenders().filter((s) => s.track?.kind === 'video');
const timer = monitorBitrate(videoSender);
// später: clearInterval(timer);
Nutzlast, Header und Retransmissions vergleichen
const report = await pc.getStats();
for (const s of report.values()) {
if (s.type === 'outbound-rtp' && s.kind === 'video') {
const total = s.bytesSent + (s.headerBytesSent ?? 0);
console.log({
rid: s.rid ?? '(kein Simulcast)',
nutzlast: s.bytesSent,
header: s.headerBytesSent,
retransmittiert: s.retransmittedBytesSent,
gesamt: total
});
}
}
// Wichtig · Fallstricke
- Nur Nutzlast: RTP-Header und Padding sind in
bytesSentnicht enthalten. Die Header-Bytes stehen inheaderBytesSent. Wer den tatsächlichen Verbrauch auf der Leitung abschätzen will, muss beide Werte addieren. Auch dann fehlen noch der Overhead von UDP, IP und SRTP. - Retransmissions: Laut Spezifikation sind erneut gesendete Bytes enthalten. Die Umsetzung kann je nach Browser abweichen, besonders wenn RTX über eine eigene SSRC läuft. Zur Kontrolle eignet sich
retransmittedBytesSent. - Kein Datenkanal: Für
RTCDataChannelgibt es Statistiken vom Typ"data-channel", nicht"outbound-rtp". - Simulcast: Bei Simulcast gibt es ein eigenes
outbound-rtp-Objekt pro Schicht (unterscheidbar überrid). Die Gesamt-Bitrate ist die Summe aller Schichten. - Zähler statt Rate: Der Wert ist kumulativ. Eine Bitrate ergibt sich nur aus der Differenz zweier Messungen, geteilt durch die Differenz der
timestamp-Werte. Den Zeitstempel aus dem Statistikobjekt verwenden, nichtDate.now(). - Kompatibilität: Wird von allen modernen Browsern unterstützt. Ältere Browser (vor allem ältere Safari-Versionen) lieferten zum Teil abweichende Statistiktypen. Vor dem Zugriff also den
typeprüfen.