Start · Sprachen · JavaScript · Referenz · RTCPeerConnection.addTrack()

RTCPeerConnection.addTrack()

Methode

Fügt einen <code>MediaStreamTrack</code> zu den Tracks hinzu, die an den entfernten Peer gesendet werden, und gibt den zugehörigen <code>RTCRtpSender</code> zurück.

seit JavaScript Baseline: alle modernen Browser (seit ca. 2017/201 Kategorie: webapi

Signatur

RTCPeerConnection.prototype.addTrack(track, ...streams)

Beschreibung

addTrack() meldet einen lokalen Medientrack (Audio oder Video) bei einer RTCPeerConnection an, damit er an den anderen Peer übertragen wird. Typischerweise stammt der Track aus navigator.mediaDevices.getUserMedia() oder getDisplayMedia(), er kann aber auch aus einem <canvas>- oder <video>-Element per captureStream() kommen.

Die Methode verwendet einen vorhandenen, noch ungenutzten RTCRtpTransceiver derselben Medienart wieder oder legt einen neuen an. Sie gibt den RTCRtpSender zurück, über den du den Track später mit replaceTrack() austauschen, Kodierungsparameter per setParameters() ändern oder ihn mit removeTrack() wieder entfernen kannst.

Die optional übergebenen MediaStream-Objekte werden in der SDP-Beschreibung signalisiert. Auf der Gegenseite landen sie im Array event.streams des track-Events. So kann der Empfänger zusammengehörige Audio- und Video-Tracks gruppieren und synchron abspielen.

Wenn sich die Menge der Tracks ändert, löst die Verbindung negotiationneeded aus. Danach musst du ein neues Offer/Answer austauschen. Rufe addTrack() daher am besten vor createOffer() auf oder behandle das Event sauber (Muster „Perfect Negotiation“).

Parameter

Name Typ Default Beschreibung
$track Pflicht MediaStreamTrack Der Audio- oder Videotrack, der an den entfernten Peer gesendet werden soll.
$...streams MediaStream Null oder mehr MediaStream-Objekte, zu denen der Track gehört. Die Gegenseite bekommt sie im Array event.streams des track-Events. Ohne Stream ist event.streams beim Empfänger leer.

Rückgabewert

Typ
RTCRtpSender
Beschreibung
Der RTCRtpSender, der den Track überträgt. Mit ihm kannst du den Track später per replaceTrack() austauschen oder per removeTrack() entfernen.

Beispiele

Kamera und Mikrofon an den Peer senden

const pc = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});

const startCall = async () => {
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
  document.querySelector('#local').srcObject = stream;

  // Jeden Track zusammen mit seinem Stream hinzufügen
  for (const track of stream.getTracks()) {
    const sender = pc.addTrack(track, stream);
    console.log(`${track.kind}-Track hinzugefügt`, sender instanceof RTCRtpSender);
  }

  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);
  // offer über den Signalisierungskanal an den Peer senden …
};

startCall();
audio-Track hinzugefügt true video-Track hinzugefügt true

Empfangene Tracks auf der Gegenseite anzeigen

const pc = new RTCPeerConnection();
const remoteVideo = document.querySelector('#remote');

pc.addEventListener('track', (event) => {
  // event.streams enthält die Streams, die der Sender an addTrack() übergeben hat
  const [remoteStream] = event.streams;
  if (remoteVideo.srcObject !== remoteStream) {
    remoteVideo.srcObject = remoteStream;
    console.log('Remote-Stream verbunden:', remoteStream.id);
  }
});
Remote-Stream verbunden: 3f2a…

Kamera durch Bildschirmfreigabe ersetzen (ohne Neuverhandlung)

const pc = new RTCPeerConnection();

const setup = async () => {
  const camStream = await navigator.mediaDevices.getUserMedia({ video: true });
  const [camTrack] = camStream.getVideoTracks();
  const videoSender = pc.addTrack(camTrack, camStream);

  document.querySelector('#share').addEventListener('click', async () => {
    const screen = await navigator.mediaDevices.getDisplayMedia({ video: true });
    const [screenTrack] = screen.getVideoTracks();
    // Den Sender von addTrack() weiterverwenden, das spart ein neues Offer
    await videoSender.replaceTrack(screenTrack);
    camTrack.stop();
    console.log('Bildschirm wird übertragen');
  });
};

setup();
Bildschirm wird übertragen

Track wieder entfernen

const pc = new RTCPeerConnection();

const run = async () => {
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  const [audioTrack] = stream.getAudioTracks();
  const sender = pc.addTrack(audioTrack, stream);

  pc.addEventListener('negotiationneeded', () => console.log('Neuverhandlung nötig'));

  // Später: Senden beenden
  pc.removeTrack(sender);
  audioTrack.stop();
  console.log('Sender-Track:', sender.track);
};

run();
Sender-Track: null Neuverhandlung nötig

// Wichtig · Fallstricke

  • Fehler: Wurde die Verbindung bereits mit close() geschlossen, wirft die Methode InvalidStateError. Wird derselbe Track zweimal hinzugefügt, wirft sie InvalidAccessError.
  • Neuverhandlung: Jeder Aufruf kann negotiationneeded auslösen. Ohne neues Offer/Answer kommt der Track beim Peer nicht an. Willst du nur einen Track austauschen, ist RTCRtpSender.replaceTrack() meist besser, weil es ohne Neuverhandlung auskommt.
  • Streams angeben: Ohne stream-Argument ist event.streams beim Empfänger leer. Dann musst du selbst einen new MediaStream([event.track]) bauen. Außerdem wird die Lippensynchronität zwischen Audio und Video nur für Tracks im selben Stream sichergestellt.
  • Veraltete API: addStream() ist veraltet und wird nicht mehr überall unterstützt. Verwende addTrack() oder addTransceiver(), wenn du Richtung oder Simulcast-Kodierungen genauer steuern willst.
  • Kompatibilität: Alle aktuellen Browser (Chrome, Firefox, Safari, Edge) unterstützen die Methode. In Node.js steht WebRTC nicht nativ bereit, dafür brauchst du Bibliotheken wie wrtc oder werift. getUserMedia() funktioniert nur in sicheren Kontexten (HTTPS oder localhost).
  • Aufräumen: removeTrack() stoppt die Aufnahme nicht. Rufe zusätzlich track.stop() auf, damit Kamera und Mikrofon freigegeben werden.