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

RTCPeerConnection.removeTrack()

Methode

Beendet das Senden von Medien über den angegebenen <code>RTCRtpSender</code>, ohne den Sender aus der Verbindung zu entfernen, und löst eine Neuverhandlung aus.

seit JavaScript Baseline: alle modernen Browser (Chrome 64+, Firef Kategorie: webapi

Signatur

RTCPeerConnection.prototype.removeTrack(sender)

Beschreibung

Mit removeTrack() teilst du dem lokalen Ende einer RTCPeerConnection mit, dass über einen bestimmten RTCRtpSender keine Medien mehr gesendet werden sollen. Als Argument erwartet die Methode den Sender, also nicht den MediaStreamTrack. Den Sender bekommst du als Rückgabewert von addTrack() oder über getSenders().

Der Sender bleibt dabei in der Verbindung erhalten. Die Methode setzt sender.track auf null und ändert die Richtung (direction) des zugehörigen RTCRtpTransceiver: aus sendrecv wird recvonly, aus sendonly wird inactive. Weil sich damit die Sitzungsbeschreibung ändert, gilt die Verbindung als „negotiation needed“ und löst das Ereignis negotiationneeded aus. Erst nach einem neuen Angebot-/Antwort-Austausch (Offer/Answer) erfährt die Gegenseite von der Änderung. Dort wird der entfernte Track stummgeschaltet (mute), und im zugehörigen MediaStream feuert removetrack.

Typische Anwendungsfälle sind: Bildschirmfreigabe beenden, die Kamera abschalten, während der Ton weiterläuft, oder einen Track komplett aus einem Gespräch nehmen. Willst du nur die Quelle austauschen, zum Beispiel von der Frontkamera auf die Rückkamera wechseln, ist RTCRtpSender.replaceTrack() meist besser, weil dabei keine Neuverhandlung nötig ist.

Parameter

Name Typ Default Beschreibung
$sender Pflicht RTCRtpSender Der RTCRtpSender, dessen Übertragung beendet werden soll. Er muss zu genau dieser RTCPeerConnection gehören.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined).

Beispiele

Kamera-Track entfernen und neu verhandeln

const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });

// Sender merken – removeTrack() braucht den Sender, nicht den Track
const senders = stream.getTracks().map((track) => pc.addTrack(track, stream));

pc.addEventListener('negotiationneeded', async () => {
  await pc.setLocalDescription();
  // signaling.send({ description: pc.localDescription });
  console.log('Neues Angebot erstellt:', pc.localDescription.type);
});

// Später: Video abschalten, Ton bleibt
const videoSender = senders.find((s) => s.track?.kind === 'video');
const videoTrack = videoSender.track;
pc.removeTrack(videoSender);
videoTrack.stop(); // Kamera wirklich freigeben
console.log(videoSender.track); // null
null Neues Angebot erstellt: offer

Bildschirmfreigabe über getSenders() beenden

const stopScreenShare = (pc, screenTrack) => {
  const sender = pc.getSenders().find((s) => s.track === screenTrack);
  if (!sender) return false;
  pc.removeTrack(sender);
  screenTrack.stop();
  return true;
};

const pc = new RTCPeerConnection();
const screen = await navigator.mediaDevices.getDisplayMedia({ video: true });
const [screenTrack] = screen.getVideoTracks();
pc.addTrack(screenTrack, screen);

// Wenn der Nutzer die Freigabe über die Browser-Leiste beendet
screenTrack.addEventListener('ended', () => stopScreenShare(pc, screenTrack));
console.log(stopScreenShare(pc, screenTrack));
true

Auswirkung auf den Transceiver prüfen

const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const sender = pc.addTrack(stream.getAudioTracks()[0], stream);

const transceiver = pc.getTransceivers().find((t) => t.sender === sender);
console.log(transceiver.direction);

pc.removeTrack(sender);
console.log(transceiver.direction);
console.log(pc.getSenders().includes(sender)); // Sender bleibt erhalten
sendrecv recvonly true

// Wichtig · Fallstricke

  • Sender statt Track übergeben: pc.removeTrack(track) wirft einen TypeError. Gehört der Sender zu einer anderen Verbindung, wird ein InvalidAccessError geworfen.
  • Ist die Verbindung geschlossen (signalingState === 'closed'), wird ein InvalidStateError geworfen.
  • Die Methode stoppt den Track nicht. Kamera und Mikrofon bleiben aktiv, und die Aufnahme-Anzeige im Browser leuchtet weiter, bis du track.stop() aufrufst.
  • Ohne einen Handler für negotiationneeded und einen neuen Angebot-/Antwort-Austausch bemerkt die Gegenseite die Änderung nicht.
  • Der Transceiver bleibt bestehen. Ein späteres addTrack() derselben Medienart kann ihn wiederverwenden. Wenn du ihn endgültig loswerden willst, nutze transceiver.stop().
  • Nur für einen Quellwechsel ist sender.replaceTrack() effizienter, weil keine Neuverhandlung nötig ist.
  • Ältere Browser hatten stattdessen die veraltete Methode removeStream(). Wenn du alte Versionen unterstützen musst, hilft adapter.js.