Signatur
Beschreibung
Die Eigenschaft streams des RTCTrackEvent liefert ein schreibgeschütztes Array von MediaStream-Objekten. Jeder Eintrag steht für einen Stream, zu dem der neu empfangene Track (event.track) gehört. Das Event wird am RTCPeerConnection ausgelöst, sobald die Gegenstelle per SDP-Aushandlung einen neuen Track ankündigt.
Hauptzweck ist es, Remote-Tracks einfach in einem <video>- oder <audio>-Element darzustellen: Da Audio- und Video-Track desselben Streams jeweils ein eigenes track-Event auslösen, aber auf dasselbe MediaStream-Objekt verweisen, genügt meist video.srcObject = event.streams[0]. So bleiben Audio und Video synchron (Lip-Sync), weil sie derselben Stream-ID zugeordnet sind.
Welche Streams im Array landen, bestimmt der Sender: Beim Aufruf von pc.addTrack(track, ...streams) auf der Gegenseite werden die angegebenen Streams über die a=msid-Zeilen im SDP übertragen. Wurde addTrack() ohne Stream-Argument aufgerufen, ist streams ein leeres Array. Ein Track kann auch mehreren Streams gleichzeitig angehören.
Rückgabewert
MediaStream-Objekten, die den empfangenen Track enthalten. Kann leer sein, wenn der Sender keinem Stream zugeordnet hat.Beispiele
Remote-Stream an ein Video-Element binden
const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });
const remoteVideo = document.querySelector('#remoteVideo');
pc.addEventListener('track', (event) => {
const [remoteStream] = event.streams;
// Audio- und Video-Track teilen sich denselben Stream – nur einmal zuweisen
if (remoteStream && remoteVideo.srcObject !== remoteStream) {
remoteVideo.srcObject = remoteStream;
console.log('Remote-Stream verbunden:', remoteStream.id);
}
});
Fallback bei leerem streams-Array
const pc = new RTCPeerConnection();
const remoteVideo = document.querySelector('#remoteVideo');
let fallbackStream = null;
pc.ontrack = ({ track, streams }) => {
if (streams.length > 0) {
remoteVideo.srcObject = streams[0];
return;
}
// Sender hat addTrack() ohne Stream aufgerufen – eigenen Stream aufbauen
fallbackStream ??= new MediaStream();
fallbackStream.addTrack(track);
remoteVideo.srcObject = fallbackStream;
console.log(`Track ${track.kind} ohne Stream empfangen – Fallback genutzt`);
};
Mehrere Teilnehmer anhand der Stream-ID verwalten
const pc = new RTCPeerConnection();
const container = document.querySelector('#participants');
const videos = new Map(); // stream.id -> HTMLVideoElement
pc.addEventListener('track', (event) => {
for (const stream of event.streams) {
if (videos.has(stream.id)) continue;
const video = document.createElement('video');
video.autoplay = true;
video.playsInline = true;
video.srcObject = stream;
container.append(video);
videos.set(stream.id, video);
// Aufräumen, wenn der Stream seinen letzten Track verliert
stream.addEventListener('removetrack', () => {
if (stream.getTracks().length === 0) {
video.remove();
videos.delete(stream.id);
}
});
}
console.log('Aktive Teilnehmer:', videos.size);
});
// Wichtig · Fallstricke
- Leeres Array möglich: Ruft die Gegenseite
addTrack(track)ohne Stream auf, istevent.streamsleer –event.streams[0]ist dannundefined. Immer prüfen oder mitevent.trackeinen eigenenMediaStreamaufbauen. - Mehrfache Events: Für jeden Track (Audio, Video) wird ein eigenes
track-Event ausgelöst. WersrcObjectjedes Mal neu setzt, kann Ruckler oder abgebrocheneplay()-Promises verursachen – vorher auf Gleichheit prüfen. - Stream-IDs: Die
iddes Remote-Streams entspricht der vom Sender gewählten msid, nicht zwingend der lokalen Stream-ID auf der Senderseite in allen älteren Implementierungen. - Schreibgeschützt: Das Array ist eingefroren;
push()o. Ä. wirft im Strict Mode einenTypeError. - Kompatibilität: In allen modernen Browsern verfügbar. Das veraltete
addstream-Event bzw.onaddstreamsollte nicht mehr verwendet werden; ältere Safari-Versionen vor 11 unterstützenontracknicht. - Autoplay-Richtlinien beachten: Für Video mit Ton ist oft eine Nutzerinteraktion nötig;
mutedundplaysInlinehelfen besonders auf iOS.