sgcWebRTC è un nuovo pacchetto per Delphi e C++ Builder che aggiunge alla tua applicazione un motore WebRTC completo: signalling SDP offer/answer reale, connettività ICE con STUN e TURN, trasporto cifrato DTLS-SRTP, data channel SCTP e tracce audio e video con Opus, G.711, VP8 e H.264.
Funziona come puro Object Pascal. Non c'è nessun Chromium incorporato, nessun controllo TWebBrowser o TEdgeBrowser e nessun bridge JavaScript nel processo. È questa la differenza rispetto alla maggior parte degli altri modi di usare WebRTC da Delphi, che funzionano ospitando un motore di browser e pilotandone lo stack JavaScript da Pascal. Qui la peer connection è codice compilato che chiama direttamente il sistema operativo, quindi gira anche su Android e iOS, e dentro un servizio Windows headless o un dispositivo kiosk senza alcun browser installato.
sgcWebRTC è un add-on di sgcWebSockets Enterprise ed è incluso nel bundle All-Access.
Un solo componente, l'intera peer connection
sgcWebRTC non aggiunge nuovi componenti alla palette. Sblocca il resto della superficie in stile W3C sulla stessa classe TsgcRTCPeerConnection già presente in sgcWebSockets Enterprise. Enterprise ti dà quel componente per la connettività ICE e TURN e per il signalling attraverso un relay WebSocket. sgcWebRTC vi aggiunge sopra la macchina a stati SDP, l'associazione SCTP, le sessioni RTP e la cifratura SRTP, così un unico oggetto gestisce signalling, connettività, cifratura, data channel e media.
Una peer connection si costruisce in quattro passi. Prima il signalling, dove i due peer si scambiano le session description su un canale che hai già. Poi la connessione, dove ICE individua quale indirizzo e quale porta riescono davvero a raggiungere l'altro lato. Poi la messa in sicurezza, dove un handshake DTLS sulla coppia di candidati nominata deriva le chiavi SRTP. E infine la comunicazione, dove dati e media viaggiano direttamente tra i peer senza alcun server nel mezzo.
Signalling: SDP reale, così l'altro peer può essere un browser
CreateOffer, CreateAnswer, SetLocalDescription, SetRemoteDescription e AddIceCandidate costruiscono e consumano SDP standard seguendo la macchina a stati JSEP di RFC 8829. Il peer all'altro capo può essere un'altra applicazione Delphi, un'app mobile o una scheda del browser. La description e i candidati li trasporti sul canale di signalling che preferisci, un WebSocket, un endpoint HTTP o una coda di messaggi, esattamente come un'applicazione browser li trasporta attraverso il proprio server di signalling.
Questo è il lato che invia l'offer. Imposta un ICE server, aggancia i due eventi di signalling, apri un data channel, poi crea l'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;
Il lato che risponde consuma ciò che arriva e replica. Non cambia nient'altro.
// 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);
Rinegoziazione, ICE restart e la regola W3C della perfect negotiation per i conflitti sono già integrate. Aggiungi una traccia a una sessione stabilita e NegotiationNeeded diventa true, OnNegotiationNeeded viene sollevato e l'offer successiva porta con sé la nuova m-line. Se entrambi i peer inviano un'offer nello stesso momento, quello che ha la proprietà Polite a True annulla la propria offer e risponde a quella remota, così la sessione sopravvive alla collisione invece di bloccarsi.
Connessione: ICE, STUN e TURN
La raccolta dei candidati segue RFC 8445. I candidati host arrivano dalle interfacce locali, i candidati server-reflexive arrivano da una STUN binding request e i candidati relayed arrivano da un'allocazione TURN quando i due peer si trovano dietro NAT che non permettono loro di raggiungersi direttamente. ICE accoppia poi ogni candidato locale con ogni candidato remoto e prova le coppie finché una non funziona.
oRTC.RTCOptions.ICEServers.AddURL('stun:stun.l.google.com:19302');
oRTC.RTCOptions.ICEServers.AddURL('turn:turn.example.com:3478',
'username', 'credential');
OnConnectionStateChange riporta lo stato del trasporto mentre attraversa gathering, connecting e connected, e SelectedLocalCandidate e SelectedRemoteCandidate ti dicono quale coppia ha vinto, che è il modo più rapido per capire se una chiamata è andata diretta o attraverso il relay.
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;
Due opzioni contano quando l'altro peer è un browser. TrickleICE pubblica i candidati mano a mano che vengono trovati invece di aspettare la fine del gathering, e TrickleICEAuto la attiva automaticamente quando la remote description la dichiara. Tutti i browser fanno trickle, quindi una answer a un'offer del browser parte subito anziché dopo il timeout del gathering.
Messa in sicurezza: DTLS-SRTP, non opzionale
La cifratura dei media è obbligatoria, lo stesso modello che impone un browser. Un handshake DTLS viene eseguito sulla coppia ICE nominata, da esso vengono derivate le chiavi SRTP e ogni pacchetto RTP, RTCP e SCTP della connessione è cifrato fin dal primo pacchetto. L'estremo remoto viene autenticato dal fingerprint del certificato trasportato nell'SDP, ed è per questo che WebRTC non ha bisogno di un'autorità di certificazione.
Data channel su SCTP
CreateDataChannel apre un RTCDataChannel su SCTP-over-DTLS, con l'handshake di apertura DCEP di RFC 8832. Il canale può essere ordinato o non ordinato, completamente affidabile oppure parzialmente affidabile con un limite di ritrasmissioni o un limite di durata, che è quello che serve per la telemetria o per lo stato di gioco, dove un pacchetto in ritardo vale meno di uno appena generato.
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 invia testo e SendBytes invia payload binari. BufferedAmount ti dice quanto è ancora in coda, così un trasferimento di file può regolare il proprio ritmo invece di inondare l'associazione.
Audio, video e condivisione dello schermo
AddTrack collega una traccia media alla connessione e la restituisce. La traccia possiede il proprio encoder e il proprio decoder, quindi tu inserisci campioni o frame grezzi ed esce RTP codificato e cifrato. Quello che arriva dal peer remoto torna decodificato attraverso gli eventi della traccia.
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;
Una traccia aggiunta dal peer remoto, invece che creata da te, arriva attraverso OnTrack con gli stessi eventi già collegati al codec negoziato.
L'audio è Opus, oppure G.711 nelle sue varianti u-law e A-law quando devi interoperare con la telefonia. Il video è VP8 tramite un binding a libvpx, H.264 tramite l'encoder hardware fornito dalla piattaforma, Media Foundation su Windows, VideoToolbox su macOS e iOS, MediaCodec su Android, e Motion JPEG su Windows per i casi in cui basta un percorso semplice solo intra.
La cattura dal microfono e la riproduzione sugli altoparlanti sono disponibili per Windows, Linux, macOS, iOS e Android. La cattura dalla camera, la cattura del desktop e il rendering video sono disponibili per Windows, dove TsgcScreenCapture_Win cattura l'intero desktop, un singolo monitor, una singola finestra o una regione, con o senza il cursore. Sulle altre piattaforme i codec e il trasporto funzionano allo stesso modo, e i frame li inserisci con SendVideoFrame e disegni quello che arriva da OnVideoFrame con gli strumenti che la piattaforma ti mette a disposizione.
Reggere su una rete reale
Una peer connection che funziona solo su una LAN tranquilla non serve a molto. sgcWebRTC porta con sé la stessa cassetta degli attrezzi per la resilienza che usa un browser, e ogni pezzo è un interruttore su RTCOptions.Media, negoziato solo quando anche la remote description lo dichiara.
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
Uno stimatore di banda basato sul ritardo, nello stile di Google Congestion Control, osserva il collegamento e pilota il bitrate obiettivo dell'encoder video, così l'immagine si degrada in modo graduale quando la connessione si restringe, invece di bloccarsi. Il feedback RTCP NACK e PLI, la ritrasmissione RFC 4588 e RED/ULPFEC coprono la perdita di pacchetti che sta sotto.
Anche i server sono inclusi
Una peer connection ha bisogno di un canale di signalling che presenti i due peer, e di solito di un server STUN, e di un server TURN per i casi in cui nient'altro riesce a passare. Tutti e tre sono forniti come componenti Delphi in sgcWebSockets Enterprise, così puoi far girare in casa l'intero stack invece di affittare l'infrastruttura: TsgcWSPServer_WebRTC come relay di signalling, TsgcSTUNServer e TsgcTURNServer per la connettività. Nulla ti impedisce di puntare invece il client a un server STUN pubblico o a un servizio TURN gestito, in entrambi i casi il protocollo è quello standard.
Standard
sgcWebRTC è un motore basato sugli standard, non un trasporto proprietario. Implementa RFC 8445 e RFC 8489 per ICE e STUN, RFC 8656 per TURN, RFC 8827 e RFC 5764 per DTLS e DTLS-SRTP, RFC 3550 e RFC 3711 per RTP e SRTP, RFC 8831 e RFC 8832 per i data channel, RFC 8829 per la macchina a stati JSEP offer/answer, e RFC 4588 per la ritrasmissione. È questo che permette a un peer Delphi di parlare con un peer browser senza uno strato di traduzione nel mezzo.
Demo
Con il pacchetto sono forniti quattro demo, ciascuno con il codice sorgente completo. Demos\35.P2P\05.RTCPeerConnection collega due peer e include un piccolo server di signalling WebSocket che puoi eseguire in locale. Demos\35.P2P\06.DataChannel apre un data channel SCTP e vi invia payload testuali e binari. Demos\30.WebRTC_Protocol\03.AudioCall e Demos\30.WebRTC_Protocol\02.VideoCall sono i demo multimediali, dal microfono all'altoparlante e dalla camera allo schermo.
Disponibilità
sgcWebRTC è un add-on di sgcWebSockets Enterprise. Non è disponibile per le edizioni Standard o Professional, ed è incluso nel bundle All-Access. Sono disponibili licenze Single, Team e Site, tutte con il codice sorgente completo e un anno di aggiornamenti.
Supporta da Delphi 7 fino a Delphi 13 Florence e le versioni corrispondenti di C++ Builder, su Windows, Linux, macOS, iOS e Android. Non c'è un download separato, l'installer di prova per la tua versione dell'IDE lo contiene già.
Il motore multimediale è solo per Delphi e C++ Builder. Il port .NET di sgcWebSockets include TsgcWSProtocol_WebRTC_Server, un relay di signalling WebSocket per il classico scenario da browser a browser, ma non esiste un equivalente .NET di TsgcRTCPeerConnection.
Pagina del prodotto · Dettaglio delle funzionalità · Scarica la versione di prova · Prezzi
Domande o commenti? Contattaci, riceverai una risposta dalle persone che hanno scritto il codice.
