RTCPeerConnection: Methode addTrack()
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.
Die addTrack()
-Methode der RTCPeerConnection
-Schnittstelle fügt eine neue Media-Tracks zu der Menge von Tracks hinzu, die an den anderen Peer übertragen werden.
Hinweis:
Das Hinzufügen eines Tracks zu einer Verbindung löst eine Neuverhandlung aus, indem ein negotiationneeded
-Ereignis ausgelöst wird.
Siehe Beginn der Verhandlung für Details.
Syntax
addTrack(track)
addTrack(track, stream1)
addTrack(track, stream1, stream2)
addTrack(track, stream1, stream2, /* …, */ streamN)
Parameter
track
-
Ein
MediaStreamTrack
-Objekt, das den Media-Track darstellt, der zur Peer-Verbindung hinzugefügt werden soll. stream1
, …,streamN
Optional-
Ein oder mehrere lokale
MediaStream
-Objekte, zu denen der Track hinzugefügt werden soll.
Der angegebene track
muss nicht notwendigerweise bereits Teil eines der angegebenen stream
s sein.
Vielmehr sind die stream
s eine Möglichkeit, Tracks auf der Empfangsseite der Verbindung zu gruppieren und sicherzustellen, dass sie synchronisiert werden.
Alle Tracks, die auf derselben Seite der Verbindung zu demselben Stream hinzugefügt werden, befinden sich auf dem Remote-Ende im selben Stream.
Rückgabewert
Das RTCRtpSender
-Objekt, welches zur Übertragung der Mediendaten verwendet wird.
Hinweis:
Jeder RTCRtpSender
ist mit einem RTCRtpReceiver
gepaart, um einen RTCRtpTransceiver
zu bilden.
Der zugehörige Empfänger ist stummgeschaltet (was anzeigt, dass er keine Pakete liefern kann), bis und sofern nicht ein oder mehrere Streams von dem Remote-Peer zum Empfänger hinzugefügt werden.
Ausnahmen
InvalidAccessError
DOMException
-
Wird ausgelöst, wenn der angegebene Track (oder alle seine zugrundeliegenden Streams) bereits Teil der
RTCPeerConnection
ist. InvalidStateError
DOMException
-
Wird ausgelöst, wenn die
RTCPeerConnection
geschlossen ist.
Nutzungsnotizen
Tracks zu mehreren Streams hinzufügen
Nach dem track
-Parameter können Sie optional ein oder mehrere MediaStream
-Objekte angeben, zu denen der Track hinzugefügt werden soll.
Es werden nur Tracks von einem Peer zum anderen gesendet, nicht Streams.
Da Streams spezifisch für jeden Peer sind, bedeutet das Angeben eines oder mehrerer Streams, dass der andere Peer einen entsprechenden Stream (oder Streams) automatisch am anderen Ende der Verbindung erstellt und dann den empfangenen Track zu diesen Streams hinzufügt.
Streamlose Tracks
Wenn keine Streams angegeben werden, ist der Track streamlos.
Dies ist völlig akzeptabel, obwohl es dem Remote-Peer obliegt, zu entscheiden, in welchen Stream der Track eingefügt werden soll, falls überhaupt.
Dies ist eine sehr gängige Weise, addTrack()
zu verwenden, wenn viele Arten von einfachen Anwendungen erstellt werden, bei denen nur ein Stream benötigt wird.
Zum Beispiel, wenn Sie dem Remote-Peer nur einen einzelnen Stream mit einem Audio- und einem Videotrack teilen, brauchen Sie sich nicht darum zu kümmern, welchen Track in welchem Stream verwaltet werden soll. Sie können also den Transceiver dies für Sie erledigen lassen.
Hier ist ein Beispiel, das eine Funktion zeigt, die getUserMedia()
verwendet, um einen Stream von der Kamera und dem Mikrofon eines Benutzers zu erhalten und dann jeden Track aus dem Stream zur Peer-Verbindung hinzuzufügen, ohne für jeden Track einen Stream anzugeben:
async function openCall(pc) {
const gumStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});
for (const track of gumStream.getTracks()) {
pc.addTrack(track);
}
}
Das Ergebnis ist, dass eine Reihe von Tracks an den Remote-Peer gesendet wird, ohne dass Stream-Zuordnungen vorliegen.
Der Handler für das track
-Ereignis auf dem Remote-Peer ist dafür verantwortlich, zu bestimmen, in welchen Stream jeder Track hinzugefügt wird, selbst wenn das bedeutet, sie alle zu demselben Stream hinzuzufügen.
Der ontrack
-Handler könnte so aussehen:
let inboundStream = null;
pc.ontrack = (ev) => {
if (ev.streams && ev.streams[0]) {
videoElem.srcObject = ev.streams[0];
} else {
if (!inboundStream) {
inboundStream = new MediaStream();
videoElem.srcObject = inboundStream;
}
inboundStream.addTrack(ev.track);
}
};
Hier fügt der track
-Ereignishandler den Track dem ersten vom Ereignis angegebenen Stream hinzu, falls ein Stream angegeben ist.
Andernfalls wird beim ersten Aufruf von ontrack
ein neuer Stream erstellt und dem Videoelement angefügt, und dann wird der Track dem neuen Stream hinzugefügt.
Ab diesem Zeitpunkt werden neue Tracks zu diesem Stream hinzugefügt.
Sie könnten auch einfach für jeden empfangenen Track einen neuen Stream erstellen:
pc.ontrack = (ev) => {
if (ev.streams && ev.streams[0]) {
videoElem.srcObject = ev.streams[0];
} else {
let inboundStream = new MediaStream(ev.track);
videoElem.srcObject = inboundStream;
}
};
Zuordnung von Tracks zu bestimmten Streams
Durch die Angabe eines Streams und das zulassen von RTCPeerConnection
, Streams für Sie zu erstellen, werden die Tracks' Zuordnungen zu Streams automatisch von der WebRTC-Infrastruktur für Sie verwaltet.
Dies umfasst Dinge wie Änderungen der direction
des Transceivers und Tracks, die mit removeTrack()
gestoppt werden.
Betrachten Sie zum Beispiel diese Funktion, die eine Anwendung verwenden könnte, um das Streaming von Kamera- und Mikrofoneingaben eines Geräts über eine RTCPeerConnection
zu einem Remote-Peer zu beginnen:
async function openCall(pc) {
const gumStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});
for (const track of gumStream.getTracks()) {
pc.addTrack(track, gumStream);
}
}
Der Remote-Peer könnte dann einen track
-Ereignishandler verwenden, der so aussieht:
pc.ontrack = ({ streams: [stream] }) => (videoElem.srcObject = stream);
Dieser setzt den aktuellen Stream des Videoelements auf den, der den zur Verbindung hinzugefügten Track enthält.
Wiederverwendete Sender
Diese Methode gibt entweder einen neuen RTCRtpSender
oder eine bestehende Instanz zur Wiederverwendung zurück.
Eine RTCRtpSender
-Instanz ist nur dann zur Wiederverwendung kompatibel, wenn sie die folgenden Kriterien erfüllt:
- Es ist kein Track bereits mit dem Sender verknüpft.
- Der mit dem Sender verknüpfte
RTCRtpTransceiver
verfügt über einenRTCRtpReceiver
, dessentrack
-Eigenschaft eineMediaStreamTrack
angibt, derenkind
demkind
des beim Aufruf vonRTCPeerConnection.addTrack()
angegebenentrack
-Parameters entspricht. Dies stellt sicher, dass ein Transceiver nur Audio oder Video und niemals beides behandelt. - Die
RTCRtpTransceiver.currentDirection
-Eigenschaft ist nicht"stopped"
. - Der
RTCRtpSender
, der in Betracht gezogen wird, wurde nie verwendet, um Daten zu senden. Wenn diecurrentDirection
des Transceivers jemals"sendrecv"
oder"sendonly"
war, kann der Sender nicht wiederverwendet werden.
Wenn all diese Kriterien erfüllt sind, wird der Sender wiederverwendet, was dazu führt, dass diese Änderungen am bestehenden RTCRtpSender
und seinem RTCRtpTransceiver
erfolgen:
- Der
RTCRtpSender
'strack
wird auf den angegebenen Track gesetzt. - Die Menge der dem Sender zugeordneten Streams wird auf die Liste der Streams gesetzt, die in diese Methode übergeben werden,
stream...
. - Der zugehörige
RTCRtpTransceiver
hat seinecurrentDirection
aktualisiert, um anzuzeigen, dass er sendet; wenn sein aktueller Wert"recvonly"
ist, wird er zu"sendrecv"
und wenn sein aktueller Wert"inactive"
ist, wird er zu"sendonly"
.
Neue Sender
Wenn kein vorhandener und wiederverwendbarer Sender existiert, wird ein neuer erstellt. Dies führt ebenfalls zur Erstellung der zugehörigen Objekte, die existieren müssen. Der Prozess zur Erstellung eines neuen Senders führt zu diesen Änderungen:
- Der neue
RTCRtpSender
wird mit dem angegebenen Track und der Menge an Stream(s) erstellt. - Ein neuer
RTCRtpReceiver
wird mit einem neuenMediaStreamTrack
als seinertrack
-Eigenschaft erstellt (nicht der beim Aufruf vonaddTrack()
angegebene Track). Dieser Track'skind
wird so eingestellt, dass er demkind
des als Eingabeparameter bereitgestellten Tracks entspricht. - Ein neuer
RTCRtpTransceiver
wird erstellt und mit dem neuen Sender und Empfänger verknüpft. - Die
direction
(RTCRtpTransceiver/direction
) des neuen Transceivers wird auf"sendrecv"
gesetzt. - Der neue Transceiver wird zur Menge der Transceiver der
RTCPeerConnection
hinzugefügt.
Beispiele
Dieses Beispiel stammt aus dem im Artikel Signalisierung und Videotelefonie vorgestellten Code und seinem dazugehörigen Beispielcode.
Es stammt aus der Methode handleVideoOfferMsg()
, die aufgerufen wird, wenn eine Angebotsnachricht vom Remote-Peer empfangen wird.
const mediaConstraints = {
audio: true, // We want an audio track
video: true, // And we want a video track
};
const desc = new RTCSessionDescription(sdp);
pc.setRemoteDescription(desc)
.then(() => navigator.mediaDevices.getUserMedia(mediaConstraints))
.then((stream) => {
previewElement.srcObject = stream;
stream.getTracks().forEach((track) => pc.addTrack(track, stream));
});
Dieser Code nimmt SDP, die vom Remote-Peer empfangen wurde, und erstellt eine neue RTCSessionDescription
, die an setRemoteDescription()
übergeben werden soll.
Sobald dies erfolgreich ist, verwendet er MediaDevices.getUserMedia()
, um Zugriff auf die lokale Webcam und das Mikrofon zu erhalten.
Wenn das erfolgreich ist, wird der resultierende Stream als Quelle für ein <video>
-Element zugewiesen, das durch die Variable previewElement
referenziert wird.
Der letzte Schritt besteht darin, das lokale Video über die Peer-Verbindung an den Anrufer zu senden.
Dies geschieht, indem jeder Track im Stream hinzugefügt wird, indem über die Liste iteriert wird, die von MediaStream.getTracks()
zurückgegeben wird, und sie an addTrack()
zusammen mit dem stream
, dessen Bestandteil sie sind, übergeben wird.
Spezifikationen
Specification |
---|
WebRTC: Real-Time Communication in Browsers # dom-rtcpeerconnection-addtrack |
Browser-Kompatibilität
BCD tables only load in the browser