Einführung in das Real-time Transport Protocol (RTP)
Das Real-time Transport Protocol (RTP), definiert in RFC 3550, ist ein IETF-Standardprotokoll, das Echtzeitverbindungen ermöglicht, um Daten auszutauschen, die Echtzeitpriorität erfordern. Dieser Artikel bietet einen Überblick darüber, was RTP ist und wie es im Kontext von WebRTC funktioniert.
Hinweis: WebRTC verwendet tatsächlich SRTP (Secure Real-time Transport Protocol), um sicherzustellen, dass die ausgetauschten Daten entsprechend gesichert und authentifiziert sind.
Die Minimierung der Latenz ist besonders wichtig für WebRTC, da die Kommunikation von Angesicht zu Angesicht mit so wenig Latenz wie möglich erfolgen muss. Je mehr Zeitverzögerung zwischen dem Sprechen eines Benutzers und dem Hören eines anderen besteht, desto wahrscheinlicher kommt es zu Übersprechen und anderen Verwirrungen.
Hauptmerkmale von RTP
Bevor wir den Einsatz von RTP in WebRTC-Kontexten untersuchen, ist es nützlich, eine allgemeine Vorstellung davon zu haben, was RTP bietet und was nicht. RTP ist ein Datenübertragungsprotokoll, dessen Aufgabe es ist, Daten so effizient wie möglich zwischen zwei Endpunkten zu transportieren, abhängig von den aktuellen Bedingungen. Diese Bedingungen können durch alles von den zugrunde liegenden Schichten des Netzwerkstapels bis zur physischen Netzwerkverbindung, den vermittelten Netzwerken, der Leistung des entfernten Endpunkts, den Rauschpegeln, den Verkehrspegeln usw. beeinflusst werden.
Da RTP ein Datenübertragungsprotokoll ist, wird es durch das eng verwandte RTP Control Protocol (RTCP), das in RFC 3550, Abschnitt 6 definiert ist, ergänzt. RTCP fügt Funktionen wie Quality of Service (QoS)-Überwachung, Teilnehmerinformationsaustausch und Ähnliches hinzu. Es ist nicht ausreichend für die vollständige Verwaltung von Benutzern, Mitgliedschaften, Berechtigungen usw., bietet aber die notwendigen Grundlagen für eine uneingeschränkte Kommunikation in einer Mehrbenutzer-Sitzung.
Die Tatsache, dass RTCP im selben RFC wie RTP definiert ist, deutet darauf hin, wie eng miteinander verbunden diese beiden Protokolle sind.
Fähigkeiten von RTP
Die Hauptvorteile von RTP im Hinblick auf WebRTC umfassen:
- Allgemein geringe Latenz.
- Pakete sind mit einer Sequenznummer und einem Zeitstempel versehen, um sie bei einer falschen Reihenfolge wieder zusammenzusetzen. Dies ermöglicht, dass mit RTP gesendete Daten auf Übertragungen geliefert werden können, die keine Reihenfolge oder gar keine Lieferung garantieren.
- Dies bedeutet, dass RTP über UDP verwendet werden kann — aber nicht muss —, sowohl wegen seiner Leistung als auch wegen seiner Multiplex- und Prüfsummenfunktionen.
- RTP unterstützt Multicast; obwohl dies für WebRTC derzeit noch nicht wichtig ist, wird es in Zukunft von Bedeutung sein, wenn WebRTC (hoffentlich) um die Unterstützung von Mehrbenutzer-Konversationen erweitert wird.
- RTP ist nicht auf die audiovisuelle Kommunikation beschränkt. Es kann für jede Form der kontinuierlichen oder aktiven Datenübertragung verwendet werden, einschließlich Daten-Streaming, aktiven Badges oder Statusanzeigeaktualisierungen oder Steuerungs- und Messinformationsübertragung.
Dinge, die RTP nicht macht
RTP selbst bietet nicht jede mögliche Funktion, weshalb WebRTC auch andere Protokolle verwendet. Einige der bemerkenswerten Dinge, die RTP nicht umfasst:
- RTP garantiert nicht Quality-of-Service (QoS).
- Obwohl RTP für den Einsatz in latenzkritischen Szenarien vorgesehen ist, bietet es von sich aus keine Funktionen, die QoS sicherstellen. Stattdessen bietet es nur die Informationen, die erforderlich sind, um QoS an anderer Stelle im Stapel zu implementieren.
- RTP behandelt nicht die Zuweisung oder Reservierung von Ressourcen, die möglicherweise benötigt werden.
Wo dies für WebRTC wichtig ist, werden diese Punkte an verschiedenen Orten innerhalb der WebRTC-Infrastruktur behandelt. Zum Beispiel verarbeitet RTCP die QoS-Überwachung.
RTCPeerConnection und RTP
Jede RTCPeerConnection
verfügt über Methoden, die Zugriff auf die Liste der RTP-Transporte bieten, die die Peer-Verbindung bedienen. Diese entsprechen den folgenden drei Arten von Transporten, die von RTCPeerConnection
unterstützt werden:
RTCRtpSender
-
RTCRtpSender
verarbeitet die Codierung und Übertragung vonMediaStreamTrack
-Daten zu einem entfernten Peer. Die Sender für eine gegebene Verbindung können durch Aufrufen vonRTCPeerConnection.getSenders()
erhalten werden. RTCRtpReceiver
-
RTCRtpReceiver
bietet die Möglichkeit, eingehendeMediaStreamTrack
-Daten zu inspizieren und Informationen darüber zu erhalten. Die Empfänger einer Verbindung können durch Aufrufen vonRTCPeerConnection.getReceivers()
abgerufen werden. RTCRtpTransceiver
-
Ein
RTCRtpTransceiver
ist ein Paar aus einem RTP-Sender und einem RTP-Empfänger, die ein gemeinsames SDPmid
-Attribut teilen, was bedeutet, dass sie die gleiche SDP-Medienzeile (die einen bidirektionalen SRTP-Stream darstellt) teilen. Diese werden durch die MethodeRTCPeerConnection.getTransceivers()
zurückgegeben, und jedesmid
und der Transceiver teilen eine Eins-zu-eins-Beziehung, wobei dasmid
für jedeRTCPeerConnection
einzigartig ist.
RTP zur Implementierung einer "Halten"-Funktion nutzen
Da die Streams für eine RTCPeerConnection
mit RTP und den oben genannten Schnittstellen implementiert werden, können Sie den Zugang, den Ihnen diese zum Inneren der Streams gewähren, nutzen, um Anpassungen vorzunehmen. Zu den einfachsten Dingen, die Sie tun können, gehört, eine "Halten"-Funktion zu implementieren, bei der ein Teilnehmer an einem Anruf auf eine Taste klicken kann, um sein Mikrofon auszuschalten, statt dessen Musik an den anderen Teilnehmer zu senden und den Empfang eingehender Audiosignale zu stoppen.
Hinweis: Dieses Beispiel nutzt moderne JavaScript-Funktionen, einschließlich Async-Funktionen und der await
-Ausdruck. Dadurch wird der Code, der sich mit den von WebRTC-Methoden zurückgegebenen Versprechen beschäftigt, enorm vereinfacht und lesbarer gemacht.
In den untenstehenden Beispielen werden wir den Peer, der den "Halten"-Modus ein- und ausschaltet, als den lokalen Peer bezeichnen und den Benutzer, der in den Haltemodus versetzt wird, als den entfernten Peer.
Halten-Modus aktivieren
Lokaler Peer
Wenn der lokale Benutzer beschließt, den Halten-Modus zu aktivieren, wird die untenstehende Methode enableHold()
aufgerufen. Sie akzeptiert als Eingabe einen MediaStream
, der die Audioinhalte enthält, die abgespielt werden sollen, während der Anruf auf Halten ist.
async function enableHold(audioStream) {
try {
await audioTransceiver.sender.replaceTrack(audioStream.getAudioTracks()[0]);
audioTransceiver.receiver.track.enabled = false;
audioTransceiver.direction = "sendonly";
} catch (err) {
/* handle the error */
}
}
Die drei Codezeilen im try
Block führen die folgenden Schritte aus:
- Ersetzen Sie ihre ausgehende Audiospur durch eine
MediaStreamTrack
, die Musik enthält. - Deaktivieren Sie die eingehende Audiospur.
- Schalten Sie den Audio-Transceiver in den Nur-Sende-Modus.
Dies löst die Neuverhandlung der RTCPeerConnection
aus, indem sie ein negotiationneeded
-Ereignis sendet, auf das Ihr Code reagiert, indem er ein SDP-Angebot mit RTCPeerConnection.createOffer
erstellt und über den Signalisierungsserver an den entfernten Peer sendet.
Der audioStream
, der das anstelle des Mikrofonaudios des lokalen Peers abzuspielende Audio enthält, kann von überall stammen. Eine Möglichkeit ist, ein verborgenes <audio>
-Element zu haben und HTMLAudioElement.captureStream()
zu verwenden, um seinen Audiostream abzurufen.
Entfernte Peer
Beim entfernten Peer, wenn wir ein SDP-Angebot mit der auf "sendonly"
gesetzten Richtung erhalten, bearbeiten wir es mit der Methode holdRequested()
, die als Eingabe einen SDP-Angebotsstring akzeptiert.
async function holdRequested(offer) {
try {
await peerConnection.setRemoteDescription(offer);
await audioTransceiver.sender.replaceTrack(null);
audioTransceiver.direction = "recvonly";
await sendAnswer();
} catch (err) {
/* handle the error */
}
}
Die hier durchgeführten Schritte sind:
- Legen Sie die Remote-Beschreibung auf das angegebene
offer
fest, indem SieRTCPeerConnection.setRemoteDescription()
aufrufen. - Ersetzen Sie die Spur des
RTCRtpSender
des Audio-Transceivers durchnull
, was bedeutet, dass keine Spur gesendet wird. Dies stoppt das Senden von Audio auf dem Transceiver. - Setzen Sie die
direction
-Eigenschaft des Audio-Transceivers auf"recvonly"
, wodurch der Transceiver angewiesen wird, nur Audio zu empfangen und nicht zu senden. - Die SDP-Antwort wird generiert und mit einer Methode namens
sendAnswer()
gesendet, die die Antwort mitcreateAnswer()
erzeugt und das resultierende SDP über den Signaldienst an den anderen Peer sendet.
Halten-Modus deaktivieren
Lokaler Peer
Wenn der lokale Benutzer auf das Oberflächenelement klickt, um den Halten-Modus zu deaktivieren, wird die Methode disableHold()
aufgerufen, um den normalen Betrieb wiederherzustellen.
async function disableHold(micStream) {
await audioTransceiver.sender.replaceTrack(micStream.getAudioTracks()[0]);
audioTransceiver.receiver.track.enabled = true;
audioTransceiver.direction = "sendrecv";
}
Dies kehrt die in enableHold()
durchgeführten Schritte wie folgt um:
- Die Spur des
RTCRtpSender
des Audio-Transceivers wird durch die erste Audiospur des angegebenen Streams ersetzt. - Die eingehende Audiospur des Transceivers wird wieder aktiviert.
- Die Richtung des Audio-Transceivers wird auf
"sendrecv"
gesetzt, was bedeutet, dass er wieder sowohl Audio senden als auch empfangen soll, anstatt nur zu senden.
Wie bei der Aktivierung des Halten-Modus löst dies erneut eine Verhandlung aus, was dazu führt, dass Ihr Code ein neues Angebot an den entfernten Peer sendet.
Entfernte Peer
Wenn das "sendrecv"
-Angebot vom entfernten Peer empfangen wird, ruft es seine holdEnded()
-Methode auf:
async function holdEnded(offer, micStream) {
try {
await peerConnection.setRemoteDescription(offer);
await audioTransceiver.sender.replaceTrack(micStream.getAudioTracks()[0]);
audioTransceiver.direction = "sendrecv";
await sendAnswer();
} catch (err) {
/* handle the error */
}
}
Die im try
-Block durchgeführten Schritte sind:
- Das empfangene Angebot wird durch Aufruf von
setRemoteDescription()
als Remote-Beschreibung gespeichert. - Die Methode
replaceTrack()
desRTCRtpSender
des Audio-Transceivers wird verwendet, um die ausgehende Audiospur auf die erste Spur des Mikrofon-Audiostreams zu setzen. - Die Richtung des Transceivers wird auf
"sendrecv"
gesetzt, was bedeutet, dass er das Senden und Empfangen von Audio wieder aufnehmen soll.
Ab diesem Punkt wird das Mikrofon wieder aktiviert und der entfernte Benutzer kann den lokalen Benutzer hören und ihn ansprechen.