sgcWebRTC ist ein neues Paket für Delphi und C++ Builder, das Ihrer Anwendung eine vollständige WebRTC-Engine hinzufügt: echtes SDP-Offer/Answer-Signalling, ICE-Konnektivität mit STUN und TURN, DTLS-SRTP-verschlüsselten Transport, SCTP-Datenkanäle sowie Audio- und Videospuren mit Opus, G.711, VP8 und H.264.
Es läuft als reines Object Pascal. Es gibt kein eingebettetes Chromium, kein TWebBrowser- oder TEdgeBrowser-Steuerelement und keine JavaScript-Brücke im Prozess. Das ist der Unterschied zu den meisten anderen Wegen, WebRTC aus Delphi heraus zu nutzen, die eine Browser-Engine hosten und deren JavaScript-Stack von Pascal aus ansteuern. Hier ist die Peer-Verbindung kompilierter Code, der das Betriebssystem direkt aufruft, deshalb läuft sie auch auf Android und iOS sowie innerhalb eines Windows-Dienstes ohne Oberfläche oder auf einem Kiosk-Gerät, auf dem überhaupt kein Browser installiert ist.
sgcWebRTC ist ein Add-on zu sgcWebSockets Enterprise und ist im All-Access-Bundle enthalten.
Eine Komponente, die gesamte Peer-Verbindung
sgcWebRTC legt keine neuen Komponenten in die Palette. Es schaltet den Rest der W3C-förmigen Oberfläche auf derselben Klasse TsgcRTCPeerConnection frei, die bereits mit sgcWebSockets Enterprise ausgeliefert wird. Enterprise gibt Ihnen diese Komponente für ICE- und TURN-Konnektivität und für Signalling über ein WebSocket-Relay. sgcWebRTC ergänzt darauf den SDP-Zustandsautomaten, die SCTP-Assoziation, die RTP-Sitzungen und die SRTP-Verschlüsselung, sodass ein einziges Objekt Signalling, Konnektivität, Verschlüsselung, Datenkanäle und Medien besitzt.
Eine Peer-Verbindung entsteht in vier Schritten. Zuerst das Signalling, bei dem die beiden Peers Sitzungsbeschreibungen über einen Kanal austauschen, den Sie bereits haben. Dann das Verbinden, bei dem ICE ermittelt, welche Adresse und welcher Port die Gegenseite tatsächlich erreichen. Dann das Absichern, bei dem ein DTLS-Handshake über das nominierte Kandidatenpaar die SRTP-Schlüssel ableitet. Und schließlich das Kommunizieren, bei dem Daten und Medien direkt zwischen den Peers fließen, ohne Server dazwischen.
Signalling: echtes SDP, damit der andere Peer ein Browser sein kann
CreateOffer, CreateAnswer, SetLocalDescription, SetRemoteDescription und AddIceCandidate erzeugen und verarbeiten standardkonformes SDP nach dem JSEP-Zustandsautomaten von RFC 8829. Der Peer am anderen Ende kann eine weitere Delphi-Anwendung, eine mobile App oder ein Browser-Tab sein. Sie transportieren die Beschreibung und die Kandidaten über einen beliebigen Signalling-Kanal, einen WebSocket, einen HTTP-Endpunkt oder eine Nachrichtenwarteschlange, genau so, wie eine Browser-Anwendung sie über ihren eigenen Signalling-Server transportiert.
Das ist die anbietende Seite. Setzen Sie einen ICE-Server, hängen Sie die beiden Signalling-Ereignisse ein, öffnen Sie einen Datenkanal und erzeugen Sie dann das Offer.
uses
sgcP2P;
var
oRTC: TsgcRTCPeerConnection;
begin
oRTC := TsgcRTCPeerConnection.Create(nil);
oRTC.RTCOptions.ICEServers.AddURL('stun:stun.l.google.com:19302');
oRTC.OnLocalDescription := OnLocalDescriptionHandler;
oRTC.OnICECandidate := OnICECandidateHandler;
oRTC.OnConnectionStateChange := OnConnectionStateChangeHandler;
oRTC.OnDataChannel := OnDataChannelHandler;
oRTC.TrickleICE := True;
oRTC.CreateDataChannel('chat'); // forces RTCOptions.DTLS on
oRTC.CreateOffer; // gathers candidates and builds the SDP offer
end;
procedure TForm1.OnLocalDescriptionHandler(Sender: TObject;
const aType, aSDP: string);
begin
// aType is 'offer' or 'answer'. Send both fields to the remote peer
// over your own signalling channel.
MySignalling.SendDescription(aType, aSDP);
end;
procedure TForm1.OnICECandidateHandler(Sender: TObject;
const aCandidate, aSdpMid: string; aSdpMLineIndex: Integer);
begin
// With TrickleICE on, candidates arrive one by one while the offer
// is already on its way to the other peer.
MySignalling.SendCandidate(aCandidate, aSdpMid, aSdpMLineIndex);
end;
Die antwortende Seite verarbeitet, was ankommt, und antwortet. Sonst ändert sich nichts.
// the remote description arrived over your signalling channel
oRTC.SetRemoteDescription('offer', vSDP);
oRTC.CreateAnswer; // raises OnLocalDescription with 'answer'
// and every remote candidate as it arrives
oRTC.AddIceCandidate(vCandidate, vSdpMid, vSdpMLineIndex);
Renegotiation, ICE-Restart und die W3C-Regel der Perfect Negotiation gegen Glare sind eingebaut. Fügen Sie einer bestehenden Sitzung eine Spur hinzu, wird NegotiationNeeded wahr, OnNegotiationNeeded wird ausgelöst und das nächste Offer trägt die neue m-line. Bieten beide Peers gleichzeitig an, nimmt derjenige, dessen Eigenschaft Polite True ist, sein eigenes Offer zurück und beantwortet das entfernte, sodass die Sitzung die Kollision überlebt, statt sich zu verklemmen.
Verbinden: ICE, STUN und TURN
Das Sammeln der Kandidaten folgt RFC 8445. Host-Kandidaten stammen von den lokalen Schnittstellen, serverreflexive Kandidaten stammen aus einem STUN-Binding-Request, und weitergeleitete Kandidaten stammen aus einer TURN-Allocation, wenn die beiden Peers hinter NATs sitzen, die sie einander nicht direkt erreichen lassen. ICE paart dann jeden lokalen Kandidaten mit jedem entfernten und prüft die Paare, bis eines funktioniert.
oRTC.RTCOptions.ICEServers.AddURL('stun:stun.l.google.com:19302');
oRTC.RTCOptions.ICEServers.AddURL('turn:turn.example.com:3478',
'username', 'credential');
OnConnectionStateChange meldet den Transport, während er durch Gathering, Connecting und Connected wandert, und SelectedLocalCandidate und SelectedRemoteCandidate sagen Ihnen, welches Paar gewonnen hat, was der schnellste Weg ist, um zu sehen, ob ein Anruf direkt oder über das Relay lief.
procedure TForm1.OnConnectionStateChangeHandler(Sender: TObject;
aState: TsgcRTCConnectionState);
begin
case aState of
rtccsGathering: DoLog('gathering candidates');
rtccsConnecting: DoLog('checking candidate pairs');
rtccsConnected: DoLog('connected: ' + oRTC.SelectedRemoteCandidate);
rtccsDisconnected: DoLog('disconnected');
rtccsFailed: DoLog('failed, try RestartIce');
end;
end;
Zwei Optionen sind wichtig, wenn der andere Peer ein Browser ist. TrickleICE veröffentlicht Kandidaten, sobald sie gefunden werden, statt auf das Ende des Gatherings zu warten, und TrickleICEAuto schaltet das automatisch ein, wenn die entfernte Beschreibung es ankündigt. Jeder Browser trickelt, also geht eine Antwort auf ein Browser-Offer sofort hinaus statt erst nach dem Gathering-Timeout.
Absichern: DTLS-SRTP, nicht optional
Medienverschlüsselung ist zwingend, dasselbe Modell, das auch ein Browser erzwingt. Ein DTLS-Handshake läuft über das nominierte ICE-Paar, daraus werden die SRTP-Schlüssel abgeleitet, und jedes RTP-, RTCP- und SCTP-Paket auf der Verbindung ist ab dem ersten Paket verschlüsselt. Die Gegenstelle wird über den Zertifikats-Fingerprint authentifiziert, der im SDP mitgeführt wird, und genau deshalb braucht WebRTC dafür keine Zertifizierungsstelle.
Datenkanäle über SCTP
CreateDataChannel öffnet einen RTCDataChannel über SCTP-over-DTLS, mit dem DCEP-Open-Handshake von RFC 8832. Der Kanal kann geordnet oder ungeordnet sein, vollständig zuverlässig oder teilweise zuverlässig mit einer Grenze für Neuübertragungen oder einer Grenze für die Lebensdauer, was genau das ist, was Sie für Telemetrie oder Spielzustände wollen, wo ein verspätetes Paket weniger wert ist als ein frisches.
uses
sgcP2P, sgcP2P_DataChannel;
var
vChat, vTelemetry: TsgcRTCDataChannel;
begin
// ordered and reliable, the default
vChat := oRTC.CreateDataChannel('chat');
vChat.OnOpen := OnChannelOpen;
vChat.OnMessage := OnChannelMessage;
// unordered, no retransmissions: drop it rather than deliver it late
vTelemetry := oRTC.CreateDataChannel('telemetry', False, 0);
end;
procedure TForm1.OnChannelOpen(Sender: TObject);
begin
TsgcRTCDataChannel(Sender).Send('hello');
end;
procedure TForm1.OnChannelMessage(Sender: TObject; const aText: string);
begin
DoLog('remote said: ' + aText);
end;
// a channel the remote peer opened arrives here
procedure TForm1.OnDataChannelHandler(Sender: TObject;
aChannel: TsgcRTCDataChannel);
begin
aChannel.OnMessage := OnChannelMessage;
aChannel.OnMessageBinary := OnChannelMessageBinary;
end;
Send überträgt Text und SendBytes überträgt binäre Nutzdaten. BufferedAmount sagt Ihnen, wie viel noch in der Warteschlange steht, sodass eine Dateiübertragung sich selbst takten kann, statt die Assoziation zu überfluten.
Audio, Video und Bildschirmfreigabe
AddTrack hängt eine Medienspur an die Verbindung und gibt sie zurück. Die Spur besitzt ihren Encoder und Decoder, Sie schieben also rohe Samples oder Frames hinein, und das kodierte, verschlüsselte RTP geht hinaus. Was vom entfernten Peer ankommt, kommt dekodiert über die Ereignisse der Spur zurück.
uses
sgcP2P, sgcP2P_RTC_Media, sgcP2P_Codec_Types;
var
vAudio, vVideo: TsgcRTCTrack;
begin
vAudio := oRTC.AddTrack(rtctkAudio, cctAudioOpus);
vVideo := oRTC.AddTrack(rtctkVideo, cctVideoH264);
// what the remote peer sends, already decoded
vAudio.OnAudio := OnRemoteAudio;
vVideo.OnVideoFrame := OnRemoteVideoFrame;
oRTC.CreateOffer;
end;
// push captured microphone samples into the audio track
procedure TForm1.OnMicrophoneCapture(Sender: TObject; const aPCM: TBytes;
aSamplesPerChannel: Integer);
begin
vAudio.SendPCM(aPCM, aSamplesPerChannel);
end;
// push captured camera or desktop frames into the video track
procedure TForm1.OnCameraCapture(Sender: TObject;
const aFrame: TsgcVideoFrame);
begin
vVideo.SendVideoFrame(aFrame);
end;
// draw what the remote peer sends
procedure TForm1.OnRemoteVideoFrame(Sender: TObject;
const aFrame: TsgcVideoFrame);
begin
MyRenderer.Render(aFrame);
end;
Eine Spur, die der entfernte Peer hinzugefügt hat statt Sie selbst, kommt über OnTrack an, mit denselben Ereignissen, die bereits an den ausgehandelten Codec gebunden sind.
Audio ist Opus oder G.711 in den Varianten u-law und A-law, wenn Sie mit Telefonie zusammenarbeiten müssen. Video ist VP8 über eine libvpx-Anbindung, H.264 über den Hardware-Encoder, den die Plattform bereitstellt, Media Foundation unter Windows, VideoToolbox unter macOS und iOS, MediaCodec unter Android, und Motion JPEG unter Windows für die Fälle, in denen ein einfacher, rein intracodierter Pfad genügt.
Mikrofonaufnahme und Lautsprecherwiedergabe werden für Windows, Linux, macOS, iOS und Android ausgeliefert. Kameraaufnahme, Desktopaufnahme und Videodarstellung werden für Windows ausgeliefert, wo TsgcScreenCapture_Win den gesamten Desktop, einen einzelnen Monitor, ein einzelnes Fenster oder einen Bereich aufnimmt, mit oder ohne Mauszeiger. Auf den anderen Plattformen arbeiten die Codecs und der Transport genauso, und Sie geben Frames über SendVideoFrame hinein und zeichnen das, was aus OnVideoFrame ankommt, mit den Mitteln, die Ihnen die Plattform bietet.
Bestehen in einem echten Netzwerk
Eine Peer-Verbindung, die nur in einem ruhigen LAN funktioniert, nützt wenig. sgcWebRTC bringt denselben Werkzeugkasten für Robustheit mit, den auch ein Browser nutzt, und jedes Teil ist ein Schalter an RTCOptions.Media, der nur dann ausgehandelt wird, wenn die entfernte Beschreibung ihn ebenfalls zeigt.
oRTC.RTCOptions.Media.CongestionControl := True; // transport-cc, REMB fallback
oRTC.RTCOptions.Media.Pacing := True; // smooth the outgoing packets
oRTC.RTCOptions.Media.RTX := True; // RFC 4588 retransmission on NACK
oRTC.RTCOptions.Media.FEC := True; // RED / ULPFEC forward error correction
Ein verzögerungsbasierter Bandbreitenschätzer im Stil von Google Congestion Control beobachtet die Verbindung und steuert die Ziel-Bitrate des Video-Encoders, sodass das Bild sanft an Qualität verliert, wenn die Verbindung schmaler wird, statt stehen zu bleiben. RTCP-NACK- und PLI-Feedback, Neuübertragung nach RFC 4588 und RED/ULPFEC decken den Paketverlust darunter ab.
Die Server werden mitgeliefert
Eine Peer-Verbindung braucht einen Signalling-Kanal, um die beiden Peers einander vorzustellen, und normalerweise einen STUN-Server sowie einen TURN-Server für die Fälle, in denen sonst nichts durchkommt. Alle drei werden als Delphi-Komponenten in sgcWebSockets Enterprise ausgeliefert, sodass Sie den gesamten Stack selbst betreiben können, statt die Infrastruktur zu mieten: TsgcWSPServer_WebRTC als Signalling-Relay, TsgcSTUNServer und TsgcTURNServer für die Konnektivität. Nichts hindert Sie daran, den Client stattdessen auf einen öffentlichen STUN-Server oder einen gehosteten TURN-Dienst zu richten, es ist in beiden Fällen dasselbe Standardprotokoll.
Standards
sgcWebRTC ist eine standardbasierte Engine, kein proprietärer Transport. Sie implementiert RFC 8445 und RFC 8489 für ICE und STUN, RFC 8656 für TURN, RFC 8827 und RFC 5764 für DTLS und DTLS-SRTP, RFC 3550 und RFC 3711 für RTP und SRTP, RFC 8831 und RFC 8832 für Datenkanäle, RFC 8829 für den JSEP-Offer/Answer-Zustandsautomaten und RFC 4588 für Neuübertragungen. Genau das erlaubt es einem Delphi-Peer, ohne Übersetzungsschicht dazwischen mit einem Browser-Peer zu sprechen.
Demos
Vier Demos werden mit dem Paket ausgeliefert, jede mit vollständigem Quellcode. Demos\35.P2P\05.RTCPeerConnection verbindet zwei Peers und enthält einen kleinen WebSocket-Signalling-Server, den Sie lokal ausführen können. Demos\35.P2P\06.DataChannel öffnet einen SCTP-Datenkanal und sendet Text- und Binärnutzdaten darüber. Demos\30.WebRTC_Protocol\03.AudioCall und Demos\30.WebRTC_Protocol\02.VideoCall sind die Mediendemos, Mikrofon zu Lautsprecher und Kamera zu Bildschirm.
Verfügbarkeit
sgcWebRTC ist ein Add-on zu sgcWebSockets Enterprise. Für die Editionen Standard und Professional ist es nicht verfügbar, und es ist im All-Access-Bundle enthalten. Single-, Team- und Site-Lizenzen sind erhältlich, alle mit vollständigem Quellcode und einem Jahr Updates.
Es unterstützt Delphi 7 bis Delphi 13 Florence und die passenden C++ Builder-Versionen, unter Windows, Linux, macOS, iOS und Android. Es gibt keinen separaten Download, das Trial-Installationsprogramm für Ihre IDE-Version enthält es bereits.
Die Medien-Engine gibt es nur für Delphi und C++ Builder. Die .NET-Portierung von sgcWebSockets enthält TsgcWSProtocol_WebRTC_Server, ein WebSocket-Signalling-Relay für das klassische Browser-zu-Browser-Szenario, aber es gibt kein .NET-Äquivalent zu TsgcRTCPeerConnection.
Produktseite · Funktionsübersicht · Testversion herunterladen · Preise
Fragen oder Feedback? Nehmen Sie Kontakt auf, Sie erhalten eine Antwort von den Leuten, die den Code geschrieben haben.
