Signatur
Beschreibung
Beim Aufbau einer WebRTC-Verbindung löst RTCPeerConnection ein track-Ereignis aus, sobald die Gegenstelle einen neuen eingehenden Medientrack aushandelt. Das zugehörige RTCTrackEvent enthält neben track, streams und transceiver die Eigenschaft receiver. Sie verweist auf den RTCRtpReceiver, der die RTP-Pakete dieses Tracks empfängt und dekodiert.
Über den Receiver kommst du an Informationen und Funktionen, die über den reinen MediaStreamTrack hinausgehen:
receiver.getStats(): Empfangsstatistiken wie Paketverlust, Jitter und Bitratereceiver.getParameters(): ausgehandelte Codecs und Header-Erweiterungenreceiver.getSynchronizationSources()bzw.getContributingSources(): Audio-Pegel und SSRC/CSRC-Infos, z. B. um den aktiven Sprecher zu erkennenreceiver.transport: den zugrunde liegendenRTCDtlsTransport- Einstellungen wie
jitterBufferTargetund Encoded Transforms (receiver.transform)
Der Wert ist immer derselbe wie event.transceiver.receiver, und event.receiver.track ist identisch mit event.track. Die Eigenschaft ist schreibgeschützt. Ein eigenes RTCTrackEvent mit dem Konstruktor zu erzeugen ist nur mit einem vorhandenen Receiver möglich, deshalb ist sie dort Pflicht.
Rückgabewert
RTCRtpReceiver, der die Medien für event.track empfängt. Ist nie null.Beispiele
Receiver im track-Ereignis auslesen
const pc = new RTCPeerConnection();
pc.addEventListener('track', (event) => {
const { receiver, track } = event;
console.log('Neuer Track:', track.kind);
console.log('Receiver gehört zum Track:', receiver.track === track);
console.log('Gleicher Receiver wie im Transceiver:', receiver === event.transceiver.receiver);
const video = document.querySelector('#remoteVideo');
video.srcObject = event.streams[0] ?? new MediaStream([track]);
});
Empfangsstatistiken regelmäßig abfragen
const pc = new RTCPeerConnection();
pc.ontrack = ({ receiver, track }) => {
const timer = setInterval(async () => {
const stats = await receiver.getStats();
stats.forEach((report) => {
if (report.type === 'inbound-rtp') {
console.log(`${track.kind}: ${report.packetsReceived} Pakete, ${report.packetsLost} verloren, Jitter ${report.jitter}s`);
}
});
}, 2000);
// Abfrage beenden, wenn der Track endet
track.addEventListener('ended', () => clearInterval(timer));
};
Aktiven Sprecher über den Audio-Pegel erkennen
const pc = new RTCPeerConnection();
pc.addEventListener('track', ({ receiver, track }) => {
if (track.kind !== 'audio') return;
const checkLevel = () => {
const [source] = receiver.getSynchronizationSources();
if (source?.audioLevel > 0.1) {
console.log(`SSRC ${source.source} spricht (Pegel ${source.audioLevel.toFixed(2)})`);
}
if (track.readyState === 'live') requestAnimationFrame(checkLevel);
};
checkLevel();
});
Ausgehandelte Codecs prüfen und Jitter-Puffer anpassen
const pc = new RTCPeerConnection();
pc.ontrack = ({ receiver }) => {
const { codecs } = receiver.getParameters();
console.log('Codecs:', codecs.map((c) => c.mimeType).join(', '));
// Kürzere Latenz auf Kosten der Stabilität (nicht überall unterstützt)
if ('jitterBufferTarget' in receiver) {
receiver.jitterBufferTarget = 50; // Millisekunden
}
};
// Wichtig · Fallstricke
- Timing: Das
track-Ereignis und damit der Receiver erscheint schon währendsetRemoteDescription(), also bevor Medien fließen.getStats()kann deshalb anfangs leere oder unvollständige Berichte liefern. - Wiederverwendung: Bei einer Neuverhandlung kann derselbe Receiver bzw. Transceiver wiederverwendet werden. Nimm nicht an, dass jedes
track-Ereignis ein neues Objekt bringt. Wird die Gegenstelle entfernt, endet der Track nicht zwangsläufig; dann feuert auf dem Stream das Ereignisremovetrack, odertrack.mutedwird gesetzt. - Kompatibilität: Die Eigenschaft selbst ist überall verfügbar. Einige Receiver-Funktionen sind nicht überall unterstützt oder heißen je nach Browser anders, z. B.
jitterBufferTarget,transform(in Chrome frühercreateEncodedStreams()) undgetSynchronizationSources()(in älteren Firefox-Versionen). Prüfe sie daher vorher im Code. - Legacy: Das veraltete
addstream-Ereignis bot keinen Zugriff auf den Receiver. Nutze stattdessen immerontrackbzw.addEventListener('track', …).