Signatur
Beschreibung
replaceTrack() tauscht die Medienquelle eines bestehenden RTCRtpSender im laufenden Betrieb aus. Typische Fälle sind der Wechsel zwischen Front- und Rückkamera, das Umschalten von Kamera auf Bildschirmfreigabe oder der Wechsel des Mikrofons. Die Gegenseite empfängt die neuen Medien nahtlos über denselben Transceiver.
Der große Vorteil gegenüber removeTrack() und anschließendem addTrack(): Es ist keine neue SDP-Aushandlung nötig. Es wird also kein negotiationneeded-Ereignis ausgelöst und kein Offer/Answer-Austausch über den Signalisierungskanal. Das spart Zeit und vermeidet Aussetzer.
Die neue Spur muss dieselbe kind haben wie die bisherige ("audio" oder "video"). Mit null hört der Sender auf zu senden, ohne dass der Transceiver entfernt wird. So lässt sich z. B. „Kamera aus“ umsetzen, und die Spur kann später wieder eingesetzt werden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $newTrack Pflicht | MediaStreamTrack | null | Die neue Spur, die gesendet werden soll. Sie muss dieselbe kind wie die bisherige Spur haben. Mit null wird das Senden beendet, der Sender bleibt aber bestehen. |
Rückgabewert
InvalidModificationError (neue Aushandlung wäre nötig), InvalidStateError (Verbindung geschlossen) oder TypeError (falsche kind).Beispiele
Zwischen Front- und Rückkamera wechseln
const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'user' } });
const [videoTrack] = stream.getVideoTracks();
pc.addTrack(videoTrack, stream);
const switchCamera = async (facingMode) => {
const newStream = await navigator.mediaDevices.getUserMedia({ video: { facingMode } });
const [newTrack] = newStream.getVideoTracks();
const sender = pc.getSenders().find((s) => s.track?.kind === 'video');
const oldTrack = sender.track;
await sender.replaceTrack(newTrack);
oldTrack?.stop(); // alte Kamera freigeben
console.log('Kamera gewechselt:', newTrack.label);
};
await switchCamera('environment');
Bildschirmfreigabe statt Kamera senden
const shareScreen = async (pc) => {
const screen = await navigator.mediaDevices.getDisplayMedia({ video: true });
const [screenTrack] = screen.getVideoTracks();
const sender = pc.getSenders().find((s) => s.track?.kind === 'video');
const cameraTrack = sender.track;
await sender.replaceTrack(screenTrack);
// Beendet der Nutzer die Freigabe über die Browser-UI, zurück zur Kamera
screenTrack.addEventListener('ended', async () => {
await sender.replaceTrack(cameraTrack);
console.log('Zurück zur Kamera');
});
};
Kamera stummschalten ohne Neuverhandlung
const toggleVideo = async (sender, track, enabled) => {
try {
await sender.replaceTrack(enabled ? track : null);
console.log(enabled ? 'Video an' : 'Video aus');
} catch (err) {
console.error('replaceTrack fehlgeschlagen:', err.name);
}
};
// const sender = pc.getSenders()[0];
// await toggleVideo(sender, cameraTrack, false);
// Wichtig · Fallstricke
- Gleiche Art nötig: Eine Audio-Spur kann keine Video-Spur ersetzen und umgekehrt. Das führt zu einem
TypeError. - Alte Spur nicht automatisch gestoppt:
replaceTrack()beendet die bisherige Spur nicht. RufeoldTrack.stop()selbst auf, sonst bleiben Kamera oder Mikrofon aktiv (inklusive Aufnahme-Anzeige des Browsers). - Neue Parameter: Weichen Auflösung oder Bildrate stark ab, oder bräuchte die neue Spur einen anderen Codec, kann das Promise mit
InvalidModificationErrorverworfen werden. Dann bleibt nurremoveTrack()/addTrack()mit neuer Aushandlung. - Lokale Vorschau: Das lokale
<video>-Element wird nicht automatisch aktualisiert. SetzesrcObjectselbst neu. nullvs.track.enabled = false: Mitenabled = falsewerden schwarze Bilder bzw. Stille weitergesendet, mitnullwird gar nichts gesendet.- Wird in allen modernen Browsern unterstützt. Ältere Safari-Versionen (vor 11) und der alte Edge hatten Einschränkungen.