sgcWebRTC to nowy pakiet dla Delphi i C++ Builder, który dodaje do Twojej aplikacji kompletny silnik WebRTC: prawdziwą sygnalizację SDP offer/answer, łączność ICE ze STUN i TURN, szyfrowany transport DTLS-SRTP, kanały danych SCTP oraz ścieżki audio i wideo z Opus, G.711, VP8 i H.264.
Działa jako czysty Object Pascal. Nie ma osadzonego Chromium, nie ma kontrolki TWebBrowser ani TEdgeBrowser, nie ma też mostka JavaScript w procesie. Tym różni się od większości innych sposobów obsługi WebRTC z poziomu Delphi, które działają przez hostowanie silnika przeglądarki i sterowanie jego stosem JavaScript z Pascala. Tutaj połączenie peer to skompilowany kod wywołujący bezpośrednio system operacyjny, więc działa również na Androidzie i iOS, a także wewnątrz usługi Windows bez interfejsu graficznego lub na urządzeniu kiosku, na którym nie ma zainstalowanej żadnej przeglądarki.
sgcWebRTC jest dodatkiem do sgcWebSockets Enterprise i jest zawarty w pakiecie All-Access.
Jeden komponent, całe połączenie peer
sgcWebRTC nie dokłada nowych komponentów do palety. Odblokowuje resztę powierzchni w kształcie W3C w tej samej klasie TsgcRTCPeerConnection, która już jest dostarczana w sgcWebSockets Enterprise. Enterprise daje Ci ten komponent do łączności ICE i TURN oraz do sygnalizacji przez przekaźnik WebSocket. sgcWebRTC dokłada do tego maszynę stanów SDP, asocjację SCTP, sesje RTP i szyfrowanie SRTP, więc jeden obiekt obsługuje sygnalizację, łączność, szyfrowanie, kanały danych i media.
Połączenie peer powstaje w czterech krokach. Najpierw sygnalizacja, w której oba węzły wymieniają opisy sesji kanałem, który już masz. Potem łączenie, w którym ICE ustala, który adres i port naprawdę może dotrzeć do drugiej strony. Potem zabezpieczanie, w którym uzgadnianie DTLS na wybranej parze kandydatów wyprowadza klucze SRTP. I na koniec komunikacja, w której dane i media płyną bezpośrednio między węzłami, bez serwera pośrodku.
Sygnalizacja: prawdziwe SDP, więc drugim węzłem może być przeglądarka
CreateOffer, CreateAnswer, SetLocalDescription, SetRemoteDescription i AddIceCandidate budują i konsumują standardowe SDP zgodnie z maszyną stanów JSEP z RFC 8829. Węzłem po drugiej stronie może być inna aplikacja Delphi, aplikacja mobilna albo karta przeglądarki. Opis i kandydatów przenosisz dowolnym kanałem sygnalizacyjnym, WebSocketem, punktem końcowym HTTP albo kolejką komunikatów, dokładnie tak, jak aplikacja przeglądarkowa przenosi je przez własny serwer sygnalizacyjny.
To jest strona składająca ofertę. Ustaw serwer ICE, podepnij dwa zdarzenia sygnalizacyjne, otwórz kanał danych, a potem utwórz ofertę.
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;
Strona odpowiadająca przyjmuje to, co przychodzi, i odpowiada. Nic więcej się nie zmienia.
// 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);
Renegocjacja, restart ICE oraz reguła kolizji z perfect negotiation W3C są wbudowane. Dodaj ścieżkę do ustanowionej sesji, a NegotiationNeeded przyjmuje wartość true, zgłaszane jest OnNegotiationNeeded, a kolejna oferta niesie nową linię m. Jeśli oba węzły złożą ofertę w tym samym czasie, ten, którego właściwość Polite ma wartość True, wycofuje własną ofertę i odpowiada na zdalną, więc sesja przeżywa kolizję zamiast się zablokować.
Łączenie: ICE, STUN i TURN
Zbieranie kandydatów przebiega zgodnie z RFC 8445. Kandydaci typu host pochodzą z lokalnych interfejsów, kandydaci server-reflexive z żądania binding STUN, a kandydaci relayed z alokacji TURN, kiedy oba węzły siedzą za NAT, które nie pozwalają im dotrzeć do siebie bezpośrednio. ICE następnie paruje każdego lokalnego kandydata z każdym zdalnym i testuje pary, aż któraś zadziała.
oRTC.RTCOptions.ICEServers.AddURL('stun:stun.l.google.com:19302');
oRTC.RTCOptions.ICEServers.AddURL('turn:turn.example.com:3478',
'username', 'credential');
OnConnectionStateChange raportuje stan transportu, kiedy przechodzi on przez zbieranie, łączenie i połączenie, a SelectedLocalCandidate i SelectedRemoteCandidate mówią, która para wygrała, co jest najszybszym sposobem sprawdzenia, czy połączenie poszło bezpośrednio, czy przez przekaźnik.
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;
Dwie opcje mają znaczenie, kiedy drugim węzłem jest przeglądarka. TrickleICE publikuje kandydatów w miarę ich znajdowania, zamiast czekać na koniec zbierania, a TrickleICEAuto włącza to automatycznie, gdy zdalny opis to ogłasza. Każda przeglądarka stosuje trickle, więc odpowiedź na ofertę przeglądarki wychodzi natychmiast, a nie dopiero po upływie limitu czasu zbierania.
Zabezpieczanie: DTLS-SRTP, nie opcjonalnie
Szyfrowanie mediów jest obowiązkowe, taki sam model wymusza przeglądarka. Uzgadnianie DTLS przebiega na wybranej parze ICE, wyprowadzane są z niego klucze SRTP, a każdy pakiet RTP, RTCP i SCTP w połączeniu jest szyfrowany od pierwszego pakietu. Zdalna strona jest uwierzytelniana odciskiem palca certyfikatu przenoszonym w SDP, dlatego WebRTC nie potrzebuje do tego urzędu certyfikacji.
Kanały danych przez SCTP
CreateDataChannel otwiera RTCDataChannel przez SCTP-over-DTLS, z uzgadnianiem otwarcia DCEP z RFC 8832. Kanał może być uporządkowany albo nieuporządkowany, w pełni niezawodny albo częściowo niezawodny, z limitem retransmisji lub limitem czasu życia, czyli dokładnie tym, czego potrzebujesz przy telemetrii albo stanie gry, gdzie spóźniony pakiet wart jest mniej niż świeży.
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 przenosi tekst, a SendBytes ładunki binarne. BufferedAmount mówi, ile jeszcze czeka w kolejce, więc transfer pliku może sam regulować tempo, zamiast zalewać asocjację.
Audio, wideo i udostępnianie ekranu
AddTrack dołącza ścieżkę mediów do połączenia i ją zwraca. Ścieżka ma własny koder i dekoder, więc wpychasz do niej surowe próbki albo klatki, a na zewnątrz wychodzi zakodowany, zaszyfrowany RTP. To, co przychodzi od zdalnego węzła, wraca zdekodowane przez zdarzenia ścieżki.
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;
Ścieżka dodana przez zdalny węzeł, a nie utworzona przez Ciebie, przychodzi przez OnTrack z tymi samymi zdarzeniami już podpiętymi do wynegocjowanego kodeka.
Audio to Opus albo G.711 w odmianach u-law i A-law, kiedy musisz współpracować z telefonią. Wideo to VP8 przez wiązanie libvpx, H.264 przez koder sprzętowy udostępniany przez platformę, Media Foundation w Windows, VideoToolbox w macOS i iOS, MediaCodec w Androidzie, oraz Motion JPEG w Windows na te przypadki, w których wystarczy prosta ścieżka oparta wyłącznie na klatkach intra.
Przechwytywanie z mikrofonu i odtwarzanie przez głośniki są dostarczane dla Windows, Linux, macOS, iOS i Android. Przechwytywanie z kamery, przechwytywanie pulpitu i renderowanie wideo są dostarczane dla Windows, gdzie TsgcScreenCapture_Win przechwytuje cały pulpit, jeden monitor, pojedyncze okno albo obszar, z kursorem lub bez. Na pozostałych platformach kodeki i transport działają tak samo, a klatki podajesz przez SendVideoFrame i rysujesz to, co przychodzi z OnVideoFrame, przy użyciu tego, co daje platforma.
Wytrzymałość w prawdziwej sieci
Połączenie peer, które działa tylko w spokojnej sieci LAN, na niewiele się zda. sgcWebRTC niesie ten sam zestaw narzędzi odpornościowych, z jakiego korzysta przeglądarka, a każdy element jest przełącznikiem w RTCOptions.Media, negocjowanym tylko wtedy, gdy zdalny opis również go pokazuje.
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
Estymator pasma oparty na opóźnieniu, w stylu Google Congestion Control, obserwuje łącze i steruje docelową przepływnością kodera wideo, więc obraz degraduje się łagodnie, kiedy połączenie się zwęża, zamiast się zacinać. Sprzężenie zwrotne RTCP NACK i PLI, retransmisja RFC 4588 oraz RED/ULPFEC pokrywają leżącą pod spodem utratę pakietów.
Serwery też są w zestawie
Połączenie peer potrzebuje kanału sygnalizacyjnego, żeby przedstawić sobie oba węzły, zwykle też serwera STUN, a na wypadek, gdy nic innego nie przechodzi, serwera TURN. Wszystkie trzy są dostarczane jako komponenty Delphi w sgcWebSockets Enterprise, więc możesz uruchomić cały stos u siebie zamiast wynajmować infrastrukturę: TsgcWSPServer_WebRTC jako przekaźnik sygnalizacyjny, TsgcSTUNServer i TsgcTURNServer dla łączności. Nic nie stoi na przeszkodzie, żeby zamiast tego skierować klienta na publiczny serwer STUN albo hostowaną usługę TURN, w obu przypadkach to ten sam standardowy protokół.
Standardy
sgcWebRTC to silnik oparty na standardach, a nie zastrzeżony transport. Implementuje RFC 8445 i RFC 8489 dla ICE i STUN, RFC 8656 dla TURN, RFC 8827 i RFC 5764 dla DTLS i DTLS-SRTP, RFC 3550 i RFC 3711 dla RTP i SRTP, RFC 8831 i RFC 8832 dla kanałów danych, RFC 8829 dla maszyny stanów offer/answer JSEP oraz RFC 4588 dla retransmisji. To właśnie pozwala węzłowi w Delphi rozmawiać z węzłem w przeglądarce bez warstwy tłumaczącej pomiędzy nimi.
Dema
Z pakietem dostarczane są cztery dema, każde z pełnym kodem źródłowym. Demos\35.P2P\05.RTCPeerConnection łączy dwa węzły i zawiera mały serwer sygnalizacyjny WebSocket, który możesz uruchomić lokalnie. Demos\35.P2P\06.DataChannel otwiera kanał danych SCTP i wysyła przez niego ładunki tekstowe i binarne. Demos\30.WebRTC_Protocol\03.AudioCall i Demos\30.WebRTC_Protocol\02.VideoCall to dema mediów, z mikrofonu do głośnika i z kamery na ekran.
Dostępność
sgcWebRTC jest dodatkiem do sgcWebSockets Enterprise. Nie jest dostępny dla edycji Standard ani Professional, a w pakiecie All-Access jest zawarty. Dostępne są licencje Single, Team i Site, wszystkie z pełnym kodem źródłowym i rokiem aktualizacji.
Obsługuje Delphi 7 aż po Delphi 13 Florence oraz odpowiadające im wersje C++ Builder, w Windows, Linux, macOS, iOS i Android. Nie ma osobnego pobierania, instalator wersji próbnej dla Twojej wersji IDE już go zawiera.
Silnik mediów jest dostępny wyłącznie dla Delphi i C++ Builder. Port sgcWebSockets .NET zawiera TsgcWSProtocol_WebRTC_Server, przekaźnik sygnalizacyjny WebSocket dla klasycznego scenariusza przeglądarka do przeglądarki, ale nie ma w nim odpowiednika TsgcRTCPeerConnection w .NET.
Strona produktu · Przegląd funkcji · Pobierz wersję próbną · Cennik
Pytania lub uwagi? Skontaktuj się z nami, otrzymasz odpowiedź od osób, które napisały ten kod.
