Signatur
Beschreibung
Die Eigenschaft bytesReceived des Wörterbuchs RTCInboundRtpStreamStats enthält die Gesamtzahl der Bytes, die bisher von der zugehörigen Synchronisationsquelle (SSRC) empfangen wurden. Gezählt wird nur die Nutzlast (Payload): RTP-Header und Padding-Bytes sind nicht enthalten. Der Wert beginnt bei 0 und steigt während der Lebensdauer des Streams stetig an.
Die Statistik erhält man über RTCPeerConnection.getStats(), RTCRtpReceiver.getStats() oder die Übergabe eines MediaStreamTrack an getStats(). Der zurückgegebene RTCStatsReport ist eine Map-ähnliche Struktur; die relevanten Einträge haben type === "inbound-rtp".
Typische Einsatzgebiete sind die Berechnung der Empfangs-Bitrate (Differenz zweier Messungen geteilt durch die Zeitdifferenz aus timestamp), Verbindungsqualitäts-Anzeigen in Videokonferenz-Anwendungen sowie das Erkennen eingefrorener Streams (Wert steigt nicht mehr). Da es sich um einen kumulativen Zähler handelt, ist ein Einzelwert allein meist wenig aussagekräftig – interessant ist die Veränderung über die Zeit.
Rückgabewert
unsigned long long) mit der Anzahl empfangener Nutzdaten-Bytes seit Beginn des Streams. Nur lesbar.Beispiele
Empfangene Bytes aller eingehenden Streams ausgeben
// pc ist eine bestehende, verbundene RTCPeerConnection
const logBytesReceived = async (pc) => {
const report = await pc.getStats();
report.forEach((stats) => {
if (stats.type === 'inbound-rtp') {
console.log(`${stats.kind} (SSRC ${stats.ssrc}): ${stats.bytesReceived} Bytes`);
}
});
};
await logBytesReceived(pc);
Empfangs-Bitrate eines Video-Receivers messen
const measureBitrate = (receiver, intervalMs = 1000) => {
let last = null;
return setInterval(async () => {
const report = await receiver.getStats();
for (const stats of report.values()) {
if (stats.type !== 'inbound-rtp') continue;
if (last) {
const bytes = stats.bytesReceived - last.bytesReceived;
const seconds = (stats.timestamp - last.timestamp) / 1000;
const kbps = (bytes * 8) / seconds / 1000;
console.log(`Bitrate: ${kbps.toFixed(1)} kbit/s`);
}
last = stats;
}
}, intervalMs);
};
const videoReceiver = pc.getReceivers().find((r) => r.track.kind === 'video');
const timerId = measureBitrate(videoReceiver);
// später: clearInterval(timerId);
Eingefrorenen Stream erkennen
const watchForStall = (pc, onStall, intervalMs = 3000) => {
const previous = new Map();
return setInterval(async () => {
const report = await pc.getStats();
report.forEach((s) => {
if (s.type !== 'inbound-rtp') return;
const before = previous.get(s.id);
if (before !== undefined && s.bytesReceived === before) {
onStall(s);
}
previous.set(s.id, s.bytesReceived);
});
}, intervalMs);
};
watchForStall(pc, (s) => console.warn(`Keine Daten mehr auf ${s.kind}-Stream ${s.ssrc}`));
// Wichtig · Fallstricke
- Nur Nutzlast: RTP-Header, Header-Erweiterungen und Padding werden nicht mitgezählt. Für die Header-Bytes gibt es separat
headerBytesReceived; für die tatsächlich über das Netz übertragene Datenmenge beide addieren (plus UDP/IP/SRTP-Overhead, der nirgends enthalten ist). - Kumulativer Zähler: Für Raten immer zwei Messungen vergleichen und die Zeitdifferenz aus
timestamp(Millisekunden) statt aus dem Timer-Intervall verwenden – das ist genauer. - Die Zählung kann Pakete enthalten, die später verworfen werden (z. B. verspätete Pakete im Jitter-Buffer); verlorene Pakete (
packetsLost) sind naturgemäß nicht enthalten. - Bei Simulcast, Neuverhandlung oder SSRC-Wechsel kann ein neuer
inbound-rtp-Eintrag mit neueridentstehen, dessen Zähler wieder bei0beginnt. Werte daher immer proidvergleichen. - Der Wert kann größer als
Number.MAX_SAFE_INTEGERwerden – in der Praxis bei normalen Sitzungsdauern aber nicht relevant. - Kompatibilität: In allen modernen Browsern verfügbar; ältere Implementierungen (vor der Spezifikation) lieferten ähnliche Werte über den veralteten Callback-basierten
getStats()bzw. untertype: "ssrc"(Chrome, legacy).