Signatur
Beschreibung
Die Eigenschaft targetBitrate des Wörterbuchs RTCOutboundRtpStreamStats enthält die Bitrate, die der Codec des ausgehenden Streams gerade anstrebt. Die Angabe erfolgt in Bit pro Sekunde als Gleitkommazahl. Dieser Wert ist ein Sollwert. Er beschreibt also, auf welches Datenvolumen der Encoder hinarbeitet, und nicht, wie viele Daten tatsächlich gesendet werden.
Den Wert bestimmen die Staukontrolle des Browsers (z. B. GCC bzw. Transport-CC), die verfügbare Bandbreite und Vorgaben wie maxBitrate aus RTCRtpSender.setParameters(). Deshalb schwankt targetBitrate während einer Verbindung: Bei Paketverlust oder wenig Bandbreite sinkt der Wert, bei guter Verbindung steigt er.
Nützlich ist die Eigenschaft für Qualitätsanzeigen, Diagnose-Dashboards und Tests für adaptives Streaming. Wer die Ziel-Bitrate mit der tatsächlich gesendeten Bitrate vergleicht, erkennt, ob der Encoder sein Ziel erreicht. Die tatsächliche Bitrate berechnet man aus der Differenz von bytesSent zwischen zwei Messungen. Den Wert erhält man über RTCPeerConnection.getStats() oder RTCRtpSender.getStats(), und zwar an Einträgen mit type === "outbound-rtp".
Rückgabewert
undefined, wenn der Browser den Wert nicht liefert.Beispiele
Ziel-Bitrate aller ausgehenden Streams auslesen
// pc ist eine verbundene RTCPeerConnection
const logTargetBitrates = async (pc) => {
const report = await pc.getStats();
report.forEach((stats) => {
if (stats.type === 'outbound-rtp' && stats.targetBitrate !== undefined) {
console.log(`${stats.kind}: ${(stats.targetBitrate / 1000).toFixed(0)} kbit/s`);
}
});
};
await logTargetBitrates(pc);
Ziel-Bitrate mit tatsächlicher Senderate vergleichen
const monitorSender = (sender, intervalMs = 1000) => {
let lastBytes = 0;
let lastTimestamp = 0;
return setInterval(async () => {
const report = await sender.getStats();
for (const stats of report.values()) {
if (stats.type !== 'outbound-rtp') continue;
if (lastTimestamp) {
// timestamp ist in Millisekunden
const seconds = (stats.timestamp - lastTimestamp) / 1000;
const actual = ((stats.bytesSent - lastBytes) * 8) / seconds;
const target = stats.targetBitrate ?? NaN;
console.log(
`Ziel: ${Math.round(target / 1000)} kbit/s, ` +
`Ist: ${Math.round(actual / 1000)} kbit/s`
);
}
lastBytes = stats.bytesSent;
lastTimestamp = stats.timestamp;
}
}, intervalMs);
};
const [videoSender] = pc.getSenders().filter((s) => s.track?.kind === 'video');
const timer = monitorSender(videoSender);
// später: clearInterval(timer);
Wirkung von maxBitrate auf targetBitrate prüfen
const limitVideoBitrate = async (sender, maxBitrate) => {
const params = sender.getParameters();
if (!params.encodings?.length) params.encodings = [{}];
params.encodings[0].maxBitrate = maxBitrate;
await sender.setParameters(params);
// Dem Encoder etwas Zeit zur Anpassung geben
await new Promise((resolve) => setTimeout(resolve, 3000));
const report = await sender.getStats();
const outbound = [...report.values()].find((s) => s.type === 'outbound-rtp');
console.log('Neue Ziel-Bitrate:', outbound?.targetBitrate);
};
await limitVideoBitrate(videoSender, 500_000);
// Wichtig · Fallstricke
- Einheit: Der Wert wird in Bit pro Sekunde angegeben, nicht in Byte. Wer ihn mit
bytesSentvergleichen will, muss die Bytes mit 8 multiplizieren. - Sollwert, kein Messwert:
targetBitratesagt nichts darüber, was tatsächlich übertragen wird. Die tatsächliche Senderate liegt oft etwas darunter, etwa bei statischen Bildinhalten, oder schwankt kurzzeitig darüber. - Simulcast/SVC: Bei Simulcast gibt es für jede Encoding-Schicht einen eigenen
outbound-rtp-Eintrag mit eigenertargetBitrate. Die einzelnen Schichten unterscheidet man überrid. - Kompatibilität: Chromium-Browser und Safari unterstützen die Eigenschaft. In Firefox ist die Unterstützung eingeschränkt oder neu. Vor der Nutzung sollte man deshalb immer auf
undefinedprüfen, z. B. mit??. - Nach dem Verbindungsaufbau: Direkt nach dem Verbindungsaufbau ist der Wert meist niedrig. Er steigt erst, wenn die Bandbreitenschätzung hochläuft. Einzelmessungen am Anfang sind daher wenig aussagekräftig.