1. Introduzione
WebRTC è un progetto open source che consente la comunicazione in tempo reale di audio, video e dati in app web e native.
WebRTC ha diverse API JavaScript. Fai clic sui link per visualizzare le demo.
getUserMedia(): acquisisci audio e video.MediaRecorder: registra audio e video.RTCPeerConnection: riproduci in streaming audio e video tra gli utenti.RTCDataChannel: trasmetti dati in streaming tra gli utenti.
Dove posso utilizzare WebRTC?
In Firefox, Opera e in Chrome su computer e Android. WebRTC è disponibile anche per le app native su iOS e Android.
Che cos'è la segnalazione?
WebRTC utilizza RTCPeerConnection per comunicare i dati di streaming tra i browser, ma ha anche bisogno di un meccanismo per coordinare la comunicazione e inviare messaggi di controllo, un processo noto come segnalazione. I metodi e i protocolli di segnalazione non sono specificati da WebRTC. In questo codelab utilizzerai Socket.IO per la messaggistica, ma esistono molte alternative.
Cosa sono STUN e TURN?
WebRTC è progettato per funzionare peer-to-peer, in modo che gli utenti possano connettersi tramite il percorso più diretto possibile. Tuttavia, WebRTC è progettato per gestire il networking nel mondo reale: le applicazioni client devono attraversare gateway NAT e firewall e il networking peer-to-peer ha bisogno di fallback in caso di errore di connessione diretta. Nell'ambito di questo processo, le API WebRTC utilizzano i server STUN per ottenere l'indirizzo IP del tuo computer e i server TURN per fungere da server di inoltro nel caso in cui la comunicazione peer-to-peer non vada a buon fine. (WebRTC nel mondo reale spiega in modo più dettagliato.)
WebRTC è sicuro?
La crittografia è obbligatoria per tutti i componenti WebRTC e le relative API JavaScript possono essere utilizzate solo da origini sicure (HTTPS o localhost). I meccanismi di segnalazione non sono definiti dagli standard WebRTC, quindi spetta a te assicurarti di utilizzare protocolli sicuri.
2. Panoramica
Crea un'app per acquisire video e scattare istantanee con la webcam e condividerli peer-to-peer tramite WebRTC. Lungo il percorso imparerai a utilizzare le API WebRTC di base e a configurare un server di messaggistica utilizzando Node.js.
Obiettivi didattici
- Ottenere video dalla webcam
- Trasmettere video in streaming con RTCPeerConnection
- Trasmettere dati in streaming con RTCDataChannel
- Configurare un servizio di segnalazione per scambiare messaggi
- Combinare la connessione peer e la segnalazione
- Scatta una foto e condividila tramite un canale di dati
Che cosa ti serve
- Chrome 47 o versioni successive
- Web Server for Chrome o utilizza il tuo web server preferito.
- Il codice campione
- Un editor di testo
- Conoscenza di base di HTML, CSS e JavaScript
3. recupera il codice campione
Scarica il codice
Se hai familiarità con Git, puoi scaricare il codice per questo codelab da GitHub clonandolo:
git clone https://github.com/googlecodelabs/webrtc-web
In alternativa, fai clic sul pulsante seguente per scaricare un file ZIP del codice:
Apri il file ZIP scaricato. Verrà estratta una cartella del progetto (adaptive-web-media) che contiene una cartella per ogni passaggio di questo codelab, insieme a tutte le risorse necessarie.
Tutto il lavoro di codifica verrà svolto nella directory denominata work.
Le cartelle step-nn contengono una versione completata per ogni passaggio di questo codelab. Sono presenti a scopo di riferimento.
Installa e verifica il server web
Sebbene tu possa utilizzare il tuo server web, questo codelab è progettato per funzionare bene con Chrome Web Server. Se non l'hai ancora installata, puoi farlo dal Chrome Web Store.

Dopo aver installato l'app Web Server for Chrome, fai clic sul collegamento alle app di Chrome dalla barra dei preferiti, da una pagina Nuova scheda o da Avvio app:

Fai clic sull'icona del server web:

Successivamente, vedrai questa finestra di dialogo, che ti consente di configurare il server web locale:

Fai clic sul pulsante SCEGLI CARTELLA e seleziona la cartella work appena creata. In questo modo potrai visualizzare il tuo lavoro in corso in Chrome tramite l'URL evidenziato nella finestra di dialogo del server web nella sezione URL del server web.
Nella sezione Opzioni, seleziona la casella accanto a Mostra automaticamente index.html, come mostrato di seguito:

Poi arresta e riavvia il server spostando il pulsante etichettato Web Server: STARTED verso sinistra e poi di nuovo verso destra.

Ora visita il tuo sito di lavoro nel browser web facendo clic sull'URL del server web evidenziato. Dovresti visualizzare una pagina simile a questa, che corrisponde a work/index.html:

Ovviamente, questa app non fa ancora nulla di interessante: finora è solo una struttura di base che utilizziamo per assicurarci che il server web funzioni correttamente. Aggiungerai funzionalità e layout nei passaggi successivi.
4. Eseguire lo streaming video dalla webcam
Obiettivi didattici
In questo passaggio scoprirai come:
- Ricevere uno stream video dalla webcam.
- Manipolare la riproduzione dello stream.
- Utilizza CSS e SVG per manipolare i video.
Una versione completa di questo passaggio è disponibile nella cartella step-01.
Un pizzico di HTML…
Aggiungi un elemento video e un elemento script a index.html nella directory work:
<!DOCTYPE html>
<html>
<head>
<title>Realtime communication with WebRTC</title>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<h1>Realtime communication with WebRTC</h1>
<video autoplay playsinline></video>
<script src="js/main.js"></script>
</body>
</html>
...e un pizzico di JavaScript
Aggiungi quanto segue a main.js nella cartella js:
'use strict';
// On this codelab, you will be streaming only video (video: true).
const mediaStreamConstraints = {
video: true,
};
// Video element where stream will be placed.
const localVideo = document.querySelector('video');
// Local stream that will be reproduced on the video.
let localStream;
// Handles success by adding the MediaStream to the video element.
function gotLocalMediaStream(mediaStream) {
localStream = mediaStream;
localVideo.srcObject = mediaStream;
}
// Handles error by logging a message to the console with the error message.
function handleLocalMediaStreamError(error) {
console.log('navigator.getUserMedia error: ', error);
}
// Initializes media stream.
navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
.then(gotLocalMediaStream).catch(handleLocalMediaStreamError);
Prova
Apri index.html nel browser e dovresti vedere qualcosa di simile (con la visualizzazione della webcam, ovviamente):

Come funziona
Dopo la chiamata getUserMedia(), il browser chiede all'utente l'autorizzazione per accedere alla fotocamera (se è la prima volta che viene richiesto l'accesso alla fotocamera per l'origine corrente). Se l'operazione ha esito positivo, viene restituito un MediaStream, che può essere utilizzato da un elemento multimediale tramite l'attributo srcObject:
navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
.then(gotLocalMediaStream).catch(handleLocalMediaStreamError);
}
function gotLocalMediaStream(mediaStream) {
localVideo.srcObject = mediaStream;
}
L'argomento constraints consente di specificare i contenuti multimediali da recuperare. In questo esempio, solo video, poiché l'audio è disattivato per impostazione predefinita:
const mediaStreamConstraints = {
video: true,
};
Puoi utilizzare i vincoli per requisiti aggiuntivi, ad esempio la risoluzione video:
const hdConstraints = {
video: {
width: {
min: 1280
},
height: {
min: 720
}
}
}
La specifica MediaTrackConstraints elenca tutti i potenziali tipi di vincoli, anche se non tutte le opzioni sono supportate da tutti i browser. Se la risoluzione richiesta non è supportata dalla videocamera attualmente selezionata, getUserMedia() verrà rifiutato con un OverconstrainedError e all'utente non verrà chiesto di concedere l'autorizzazione per accedere alla videocamera.
Se getUserMedia() ha esito positivo, lo stream video della webcam viene impostato come origine dell'elemento video:
function gotLocalMediaStream(mediaStream) {
localVideo.srcObject = mediaStream;
}
Punti bonus
- L'oggetto
localStreampassato agetUserMedia()è nell'ambito globale, quindi puoi ispezionarlo dalla console del browser: apri la console, digita stream e premi Invio. Per visualizzare la console in Chrome, premi Ctrl-Maiusc-J o Comando-Opzione-J se utilizzi un Mac. - Che cosa restituisce
localStream.getVideoTracks()? - Prova a chiamare il numero
localStream.getVideoTracks()[0].stop(). - Esamina l'oggetto constraints: cosa succede se lo modifichi in
{audio: true, video: true}? - Qual è la dimensione dell'elemento video? Come puoi ottenere le dimensioni naturali del video da JavaScript, anziché le dimensioni di visualizzazione? Utilizza Chrome DevTools per eseguire il controllo.
- Prova ad aggiungere filtri CSS all'elemento video. Ad esempio:
video {
filter: blur(4px) invert(1) opacity(0.5);
}
- Prova ad aggiungere filtri SVG. Ad esempio:
video {
filter: hue-rotate(180deg) saturate(200%);
}
Che cosa hai imparato
In questo passaggio hai imparato a:
- Ottenere video dalla webcam.
- Imposta i vincoli dei contenuti multimediali.
- Modifica l'elemento video.
Una versione completa di questo passaggio è disponibile nella cartella step-01.
Suggerimenti
- Non dimenticare l'attributo
autoplaynell'elementovideo. In caso contrario, vedrai solo un singolo fotogramma. - Esistono molte altre opzioni per i vincoli di
getUserMedia(). Dai un'occhiata alla demo all'indirizzo webrtc.github.io/samples/src/content/peerconnection/constraints. Come vedrai, su questo sito sono disponibili molti esempi interessanti di WebRTC.
Best practice
- Assicurati che l'elemento video non superi i limiti del contenitore. Abbiamo aggiunto
widthemax-widthper impostare una dimensione preferita e una dimensione massima per il video. Il browser calcolerà automaticamente l'altezza:
video {
max-width: 100%;
width: 320px;
}
Prossimo
Hai il video, ma come lo riproduci in streaming? Scopri di più nel passaggio successivo.
5. Trasmettere video in streaming con RTCPeerConnection
Obiettivi didattici
In questo passaggio scoprirai come:
- Astrai le differenze del browser con lo shim WebRTC, adapter.js.
- Utilizza l'API RTCPeerConnection per lo streaming video.
- Controllare l'acquisizione e lo streaming dei contenuti multimediali.
Una versione completa di questo passaggio è disponibile nella cartella step-2.
Che cos'è RTCPeerConnection?
RTCPeerConnection è un'API per effettuare chiamate WebRTC per lo streaming di video e audio e lo scambio di dati.
Questo esempio configura una connessione tra due oggetti RTCPeerConnection (noti come peer) nella stessa pagina.
Non ha un utilizzo pratico, ma è utile per capire come funziona RTCPeerConnection.
Aggiungere elementi video e pulsanti di controllo
In index.html sostituisci il singolo elemento video con due elementi video e tre pulsanti:
<video id="localVideo" autoplay playsinline></video>
<video id="remoteVideo" autoplay playsinline></video>
<div>
<button id="startButton">Start</button>
<button id="callButton">Call</button>
<button id="hangupButton">Hang Up</button>
</div>
Un elemento video mostrerà lo stream di getUserMedia() e l'altro mostrerà lo stesso video trasmesso in streaming tramite RTCPeerconnection. In un'applicazione reale, un elemento video visualizzerebbe lo stream locale e l'altro lo stream remoto.
Aggiungere lo shim adapter.js
Aggiungi un link alla versione attuale di adapter.js sopra il link a main.js:
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
Ora il file Index.html dovrebbe avere il seguente aspetto:
<!DOCTYPE html>
<html>
<head>
<title>Realtime communication with WebRTC</title>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<h1>Realtime communication with WebRTC</h1>
<video id="localVideo" autoplay playsinline></video>
<video id="remoteVideo" autoplay playsinline></video>
<div>
<button id="startButton">Start</button>
<button id="callButton">Call</button>
<button id="hangupButton">Hang Up</button>
</div>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="js/main.js"></script>
</body>
</html>
Installa il codice RTCPeerConnection
Sostituisci main.js con la versione nella cartella step-02.
Effettuare la chiamata
Apri index.html, fai clic sul pulsante Avvia per ottenere il video dalla webcam e fai clic su Chiama per stabilire la connessione peer. Dovresti vedere lo stesso video (della webcam) in entrambi gli elementi video. Visualizza la console del browser per vedere la registrazione WebRTC.
Come funziona
Questo passaggio fa molto...
WebRTC utilizza l'API RTCPeerConnection per configurare una connessione per lo streaming video tra i client WebRTC, noti come peer.
In questo esempio, i due oggetti RTCPeerConnection si trovano nella stessa pagina: pc1 e pc2. Non ha un utilizzo pratico, ma è utile per dimostrare il funzionamento delle API.
La configurazione di una chiamata tra peer WebRTC prevede tre attività:
- Crea un oggetto RTCPeerConnection per ogni estremità della chiamata e, a ogni estremità, aggiungi lo stream locale da
getUserMedia(). - Ottenere e condividere informazioni sulla rete: i potenziali endpoint di connessione sono noti come candidati ICE.
- Recupera e condividi descrizioni locali e remote: metadati sui contenuti multimediali locali in formato SDP.
Immagina che Alice e Bob vogliano utilizzare RTCPeerConnection per configurare una videochiamata.
Per prima cosa, Alice e Bob si scambiano le informazioni di rete. L'espressione "trovare candidati" si riferisce al processo di ricerca di interfacce di rete e porte utilizzando il framework ICE.
- Alice crea un oggetto RTCPeerConnection con un gestore
onicecandidate (addEventListener('icecandidate')). Ciò corrisponde al seguente codice di main.js:
let localPeerConnection;
localPeerConnection = new RTCPeerConnection(servers);
localPeerConnection.addEventListener('icecandidate', handleConnection);
localPeerConnection.addEventListener(
'iceconnectionstatechange', handleConnectionChange);
- Alice chiama
getUserMedia()e aggiunge lo stream passato a questo:
navigator.mediaDevices.getUserMedia(mediaStreamConstraints).
then(gotLocalMediaStream).
catch(handleLocalMediaStreamError);
function gotLocalMediaStream(mediaStream) {
localVideo.srcObject = mediaStream;
localStream = mediaStream;
trace('Received local stream.');
callButton.disabled = false; // Enable call button.
}
localPeerConnection.addStream(localStream);
trace('Added local stream to localPeerConnection.');
- Il gestore
onicecandidatedel passaggio 1 viene chiamato quando diventano disponibili candidati di rete. - Alice invia a Bob i dati serializzati dei candidati. In un'applicazione reale, questo processo (noto come segnalazione) avviene tramite un servizio di messaggistica. Scoprirai come farlo in un passaggio successivo. Naturalmente, in questo passaggio i due oggetti RTCPeerConnection si trovano sulla stessa pagina e possono comunicare direttamente senza bisogno di messaggistica esterna.
- Quando Bob riceve un messaggio candidato da Alice, chiama
addIceCandidate()per aggiungere il candidato alla descrizione del peer remoto:
function handleConnection(event) {
const peerConnection = event.target;
const iceCandidate = event.candidate;
if (iceCandidate) {
const newIceCandidate = new RTCIceCandidate(iceCandidate);
const otherPeer = getOtherPeer(peerConnection);
otherPeer.addIceCandidate(newIceCandidate)
.then(() => {
handleConnectionSuccess(peerConnection);
}).catch((error) => {
handleConnectionFailure(peerConnection, error);
});
trace(`${getPeerName(peerConnection)} ICE candidate:\n` +
`${event.candidate.candidate}.`);
}
}
Anche i peer WebRTC devono trovare e scambiare informazioni sui contenuti multimediali audio e video locali e remoti, come la risoluzione e le funzionalità dei codec. La segnalazione per lo scambio di informazioni sulla configurazione dei contenuti multimediali avviene tramite lo scambio di blob di metadati, noti come offerta e risposta, utilizzando il formato Session Description Protocol, noto come SDP:
- Alice esegue il metodo RTCPeerConnection
createOffer(). La promessa restituita fornisce un RTCSessionDescription: la descrizione della sessione locale di Alice:
trace('localPeerConnection createOffer start.');
localPeerConnection.createOffer(offerOptions)
.then(createdOffer).catch(setSessionDescriptionError);
- Se l'operazione va a buon fine, Alice imposta la descrizione locale utilizzando
setLocalDescription()e poi invia questa descrizione della sessione a Bob tramite il canale di segnalazione. - Bob imposta la descrizione che Alice gli ha inviato come descrizione remota utilizzando
setRemoteDescription(). - Bruno esegue il metodo RTCPeerConnection
createAnswer(), trasmettendo la descrizione remota ricevuta da Alice, in modo che possa essere generata una sessione locale compatibile con la sua. La promessacreateAnswer()passa una RTCSessionDescription: Bob la imposta come descrizione locale e la invia ad Alice. - Quando Alice riceve la descrizione della sessione di Bob, la imposta come descrizione remota con
setRemoteDescription().
// Logs offer creation and sets peer connection session descriptions.
function createdOffer(description) {
trace(`Offer from localPeerConnection:\n${description.sdp}`);
trace('localPeerConnection setLocalDescription start.');
localPeerConnection.setLocalDescription(description)
.then(() => {
setLocalDescriptionSuccess(localPeerConnection);
}).catch(setSessionDescriptionError);
trace('remotePeerConnection setRemoteDescription start.');
remotePeerConnection.setRemoteDescription(description)
.then(() => {
setRemoteDescriptionSuccess(remotePeerConnection);
}).catch(setSessionDescriptionError);
trace('remotePeerConnection createAnswer start.');
remotePeerConnection.createAnswer()
.then(createdAnswer)
.catch(setSessionDescriptionError);
}
// Logs answer to offer creation and sets peer connection session descriptions.
function createdAnswer(description) {
trace(`Answer from remotePeerConnection:\n${description.sdp}.`);
trace('remotePeerConnection setLocalDescription start.');
remotePeerConnection.setLocalDescription(description)
.then(() => {
setLocalDescriptionSuccess(remotePeerConnection);
}).catch(setSessionDescriptionError);
trace('localPeerConnection setRemoteDescription start.');
localPeerConnection.setRemoteDescription(description)
.then(() => {
setRemoteDescriptionSuccess(localPeerConnection);
}).catch(setSessionDescriptionError);
}
- Ping.
Punti bonus
- Dai un'occhiata a chrome://webrtc-internals. In questo modo vengono fornite statistiche WebRTC e dati di debug. Un elenco completo degli URL di Chrome è disponibile all'indirizzo chrome://about.
- Applica uno stile alla pagina con CSS:
- Metti i video uno accanto all'altro.
- Rendi i pulsanti della stessa larghezza, con un testo più grande.
- Assicurati che il layout funzioni sui dispositivi mobili.
- Nella console Chrome DevTools, esamina
localStream,localPeerConnectioneremotePeerConnection. - Nella console, guarda
localPeerConnectionpc1.localDescription. Che aspetto ha il formato SDP?
Che cosa hai imparato
In questo passaggio hai imparato a:
- Astrai le differenze del browser con lo shim WebRTC, adapter.js.
- Utilizza l'API RTCPeerConnection per lo streaming video.
- Controllare l'acquisizione e lo streaming dei contenuti multimediali.
- Condividi informazioni su media e rete tra peer per abilitare una chiamata WebRTC.
Una versione completa di questo passaggio è disponibile nella cartella step-2.
Suggerimenti
- In questo passaggio c'è molto da imparare. Per trovare altre risorse che spiegano RTCPeerConnection in modo più dettagliato, visita webrtc.org. Questa pagina include suggerimenti per i framework JavaScript, se vuoi utilizzare WebRTC, ma non vuoi gestire le API.
- Scopri di più sullo shim adapter.js nel repository GitHub di adapter.js.
- Vuoi vedere l'app di videochiamate migliore al mondo? Dai un'occhiata ad AppRTC, l'app canonica del progetto WebRTC per le chiamate WebRTC: app, codice. Il tempo di configurazione della chiamata è inferiore a 500 ms.
Best practice
- Per rendere il tuo codice a prova di futuro, utilizza le nuove API basate su Promise e attiva la compatibilità con i browser che non le supportano utilizzando adapter.js.
Prossimo
Questo passaggio mostra come utilizzare WebRTC per lo streaming video tra peer, ma questo codelab riguarda anche i dati.
Nel passaggio successivo scopri come trasmettere in streaming dati arbitrari utilizzando RTCDataChannel.
6. Utilizzare RTCDataChannel per scambiare dati
Obiettivi didattici
- Come scambiare dati tra endpoint WebRTC (peer).
Una versione completa di questo passaggio è disponibile nella cartella step-03.
Aggiornare l'HTML
Per questo passaggio, utilizzerai i canali di dati WebRTC per inviare testo tra due elementi textarea nella stessa pagina. Non è molto utile, ma dimostra come WebRTC possa essere utilizzato per condividere dati e video in streaming.
Rimuovi gli elementi video e pulsante da index.html e sostituiscili con il seguente codice HTML:
<textarea id="dataChannelSend" disabled
placeholder="Press Start, enter some text, then press Send."></textarea>
<textarea id="dataChannelReceive" disabled></textarea>
<div id="buttons">
<button id="startButton">Start</button>
<button id="sendButton">Send</button>
<button id="closeButton">Stop</button>
</div>
Un'area di testo verrà utilizzata per inserire il testo, l'altra per visualizzarlo in streaming tra i peer.
Il file index.html ora dovrebbe avere questo aspetto:
<!DOCTYPE html>
<html>
<head>
<title>Realtime communication with WebRTC</title>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<h1>Realtime communication with WebRTC</h1>
<textarea id="dataChannelSend" disabled
placeholder="Press Start, enter some text, then press Send."></textarea>
<textarea id="dataChannelReceive" disabled></textarea>
<div id="buttons">
<button id="startButton">Start</button>
<button id="sendButton">Send</button>
<button id="closeButton">Stop</button>
</div>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="js/main.js"></script>
</body>
</html>
Aggiornare JavaScript
Sostituisci main.js con i contenuti di step-03/js/main.js.
Prova a trasmettere dati in streaming tra peer: apri index.html, premi Start per configurare la connessione peer, inserisci del testo nel textarea a sinistra, quindi fai clic su Send per trasferire il testo utilizzando i canali di dati WebRTC.
Come funziona
Questo codice utilizza RTCPeerConnection e RTCDataChannel per consentire lo scambio di messaggi di testo.
Gran parte del codice di questo passaggio è uguale a quello dell'esempio RTCPeerConnection.
Le funzioni sendData() e createConnection() contengono la maggior parte del nuovo codice:
function createConnection() {
dataChannelSend.placeholder = '';
var servers = null;
pcConstraint = null;
dataConstraint = null;
trace('Using SCTP based data channels');
// For SCTP, reliable and ordered delivery is true by default.
// Add localConnection to global scope to make it visible
// from the browser console.
window.localConnection = localConnection =
new RTCPeerConnection(servers, pcConstraint);
trace('Created local peer connection object localConnection');
sendChannel = localConnection.createDataChannel('sendDataChannel',
dataConstraint);
trace('Created send data channel');
localConnection.onicecandidate = iceCallback1;
sendChannel.onopen = onSendChannelStateChange;
sendChannel.onclose = onSendChannelStateChange;
// Add remoteConnection to global scope to make it visible
// from the browser console.
window.remoteConnection = remoteConnection =
new RTCPeerConnection(servers, pcConstraint);
trace('Created remote peer connection object remoteConnection');
remoteConnection.onicecandidate = iceCallback2;
remoteConnection.ondatachannel = receiveChannelCallback;
localConnection.createOffer().then(
gotDescription1,
onCreateSessionDescriptionError
);
startButton.disabled = true;
closeButton.disabled = false;
}
function sendData() {
var data = dataChannelSend.value;
sendChannel.send(data);
trace('Sent Data: ' + data);
}
La sintassi di RTCDataChannel è volutamente simile a WebSocket, con un metodo send() e un evento message.
Nota l'uso di dataConstraint. I canali di dati possono essere configurati per abilitare diversi tipi di condivisione dei dati, ad esempio dando la priorità alla distribuzione affidabile rispetto alle prestazioni. Per saperne di più sulle opzioni, visita la Mozilla Developer Network.
Punti bonus
- Con SCTP, il protocollo utilizzato dai canali di dati WebRTC, il recapito dei dati affidabile e ordinato è attivo per impostazione predefinita. In quali casi RTCDataChannel deve garantire l'affidabilità della trasmissione dei dati e in quali casi le prestazioni sono più importanti, anche se ciò significa perdere alcuni dati?
- Utilizza CSS per migliorare il layout della pagina e aggiungi un attributo segnaposto all'area di testo "dataChannelReceive".
- Prova la pagina su un dispositivo mobile.
Che cosa hai imparato
In questo passaggio hai imparato a:
- Stabilisci una connessione tra due peer WebRTC.
- Scambia dati di testo tra i peer.
Una versione completa di questo passaggio è disponibile nella cartella step-03.
Scopri di più
- Canali di dati WebRTC (un paio di anni fa, ma vale comunque la pena leggerlo)
- Perché è stato selezionato SCTP per il canale di dati di WebRTC?
Prossimo
Hai imparato a scambiare dati tra peer sulla stessa pagina, ma come si fa tra macchine diverse? Innanzitutto, devi configurare un canale di segnalazione per scambiare messaggi di metadati. Scopri come nel passaggio successivo.
7. Configurare un servizio di segnalazione per scambiare messaggi
Obiettivi didattici
In questo passaggio, scoprirai come:
- Utilizza
npmper installare le dipendenze del progetto come specificato in package.json - Esegui un server Node.js e utilizza node-static per pubblicare file statici.
- Configura un servizio di messaggistica su Node.js utilizzando Socket.IO.
- Utilizzalo per creare "stanze" e scambiare messaggi.
Una versione completa di questo passaggio si trova nella cartella step-04.
Concetti
Per configurare e mantenere una chiamata WebRTC, i client WebRTC (peer) devono scambiarsi metadati:
- Informazioni sul candidato (rete).
- Messaggi di offerta e risposta che forniscono informazioni sui media, come risoluzione e codec.
In altre parole, è necessario uno scambio di metadati prima che possa avvenire lo streaming peer-to-peer di audio, video o dati. Questa procedura è chiamata segnalazione.
Nei passaggi precedenti, gli oggetti RTCPeerConnection del mittente e del destinatario si trovano nella stessa pagina, quindi la "segnalazione" consiste semplicemente nel passare i metadati tra gli oggetti.
In un'applicazione reale, le RTCPeerConnection del mittente e del destinatario vengono eseguite in pagine web su dispositivi diversi ed è necessario un modo per comunicare i metadati.
A questo scopo, utilizzi un server di segnalazione: un server in grado di trasmettere messaggi tra client WebRTC (peer). I messaggi effettivi sono in testo normale: oggetti JavaScript convertiti in stringa.
Prerequisito: installa Node.js
Per eseguire i passaggi successivi di questo codelab (cartelle da step-04 a step-06), dovrai eseguire un server su localhost utilizzando Node.js.
Puoi scaricare e installare Node.js da questo link o tramite il tuo package manager preferito.
Una volta installato, potrai importare le dipendenze necessarie per i passaggi successivi (esecuzione di npm install), nonché eseguire un piccolo server localhost per eseguire il codelab (esecuzione di node index.js). Questi comandi verranno indicati in un secondo momento, quando saranno necessari.
Informazioni sull'app
WebRTC utilizza un'API JavaScript lato client, ma per l'utilizzo nel mondo reale richiede anche un server di segnalazione (messaggistica), nonché server STUN e TURN. Puoi scoprire di più qui.
In questo passaggio creerai un semplice server di segnalazione Node.js utilizzando il modulo Node.js Socket.IO e la libreria JavaScript per la messaggistica. L'esperienza con Node.js e Socket.IO sarà utile, ma non fondamentale; i componenti di messaggistica sono molto semplici.
In questo esempio, il server (l'applicazione Node.js) è implementato in index.js, mentre il client che viene eseguito (l'app web) è implementato in index.html.
L'applicazione Node.js in questo passaggio ha due attività.
Innanzitutto, funge da relè per i messaggi:
socket.on('message', function (message) {
log('Got message: ', message);
socket.broadcast.emit('message', message);
});
In secondo luogo, gestisce le "stanze" di chat video WebRTC:
if (numClients === 0) {
socket.join(room);
socket.emit('created', room, socket.id);
} else if (numClients === 1) {
socket.join(room);
socket.emit('joined', room, socket.id);
io.sockets.in(room).emit('ready');
} else { // max two clients
socket.emit('full', room);
}
La nostra semplice applicazione WebRTC consente a un massimo di due peer di condividere una stanza.
HTML e JavaScript
Aggiorna index.html in modo che abbia il seguente aspetto:
<!DOCTYPE html>
<html>
<head>
<title>Realtime communication with WebRTC</title>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<h1>Realtime communication with WebRTC</h1>
<script src="/socket.io/socket.io.js"></script>
<script src="js/main.js"></script>
</body>
</html>
In questo passaggio non vedrai nulla sulla pagina: tutti i log vengono inviati alla console del browser. Per visualizzare la console in Chrome, premi Ctrl-Maiusc-J o Comando-Opzione-J se utilizzi un Mac.
Sostituisci js/main.js con quanto segue:
'use strict';
var isInitiator;
window.room = prompt("Enter room name:");
var socket = io.connect();
if (room !== "") {
console.log('Message from client: Asking to join room ' + room);
socket.emit('create or join', room);
}
socket.on('created', function(room, clientId) {
isInitiator = true;
});
socket.on('full', function(room) {
console.log('Message from client: Room ' + room + ' is full :^(');
});
socket.on('ipaddr', function(ipaddr) {
console.log('Message from client: Server IP address is ' + ipaddr);
});
socket.on('joined', function(room, clientId) {
isInitiator = false;
});
socket.on('log', function(array) {
console.log.apply(console, array);
});
Configura Socket.IO per l'esecuzione su Node.js
Nel file HTML, potresti aver notato che stai utilizzando un file Socket.IO:
<script src="/socket.io/socket.io.js"></script>
Al livello superiore della directory work, crea un file denominato package.json con i seguenti contenuti:
{
"name": "webrtc-codelab",
"version": "0.0.1",
"description": "WebRTC codelab",
"dependencies": {
"node-static": "^0.7.10",
"socket.io": "^1.2.0"
}
}
Si tratta di un manifest dell'app che indica a Node Package Manager (npm) quali dipendenze del progetto installare.
Per installare le dipendenze (ad esempio /socket.io/socket.io.js), esegui il seguente comando dal terminale della riga di comando nella directory work:
npm install
Dovresti visualizzare un log di installazione che termina in questo modo:

Come puoi vedere, npm ha installato le dipendenze definite in package.json.
Crea un nuovo file index.js nel livello superiore della directory work (non nella directory js) e aggiungi il seguente codice:
'use strict';
var os = require('os');
var nodeStatic = require('node-static');
var http = require('http');
var socketIO = require('socket.io');
var fileServer = new(nodeStatic.Server)();
var app = http.createServer(function(req, res) {
fileServer.serve(req, res);
}).listen(8080);
var io = socketIO.listen(app);
io.sockets.on('connection', function(socket) {
// convenience function to log server messages on the client
function log() {
var array = ['Message from server:'];
array.push.apply(array, arguments);
socket.emit('log', array);
}
socket.on('message', function(message) {
log('Client said: ', message);
// for a real app, would be room-only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', function(room) {
log('Received request to create or join room ' + room);
var clientsInRoom = io.sockets.adapter.rooms[room];
var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
log('Room ' + room + ' now has ' + numClients + ' client(s)');
if (numClients === 0) {
socket.join(room);
log('Client ID ' + socket.id + ' created room ' + room);
socket.emit('created', room, socket.id);
} else if (numClients === 1) {
log('Client ID ' + socket.id + ' joined room ' + room);
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room, socket.id);
io.sockets.in(room).emit('ready');
} else { // max two clients
socket.emit('full', room);
}
});
socket.on('ipaddr', function() {
var ifaces = os.networkInterfaces();
for (var dev in ifaces) {
ifaces[dev].forEach(function(details) {
if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
socket.emit('ipaddr', details.address);
}
});
}
});
});
Dal terminale della riga di comando, esegui questo comando nella directory work:
node index.js
Dal browser, apri localhost:8080.
Ogni volta che apri questo URL, ti verrà chiesto di inserire un nome per la stanza. Per entrare nella stessa stanza, scegli ogni volta lo stesso nome, ad esempio "foo".
Apri una nuova pagina della scheda e apri di nuovo localhost:8080. Scegli lo stesso nome della stanza.
Apri localhost:8080 in una terza scheda o finestra. Scegli di nuovo lo stesso nome della stanza.
Controlla la console in ciascuna scheda: dovresti visualizzare la registrazione del JavaScript riportato sopra.
Punti bonus
- Quali meccanismi di messaggistica alternativi potrebbero essere possibili? Quali problemi potresti riscontrare utilizzando WebSocket "puro"?
- Quali problemi potrebbero essere coinvolti nel ridimensionamento di questa applicazione? Puoi sviluppare un metodo per testare migliaia o milioni di richieste di stanze simultanee?
- Questa app utilizza una richiesta JavaScript per ottenere il nome di una stanza. Trova un modo per ottenere il nome della stanza dall'URL. Ad esempio, localhost:8080/foo restituirebbe il nome della stanza
foo.
Che cosa hai imparato
In questo passaggio hai imparato a:
- Utilizza npm per installare le dipendenze del progetto come specificato in package.json
- Esegui un server Node.js per pubblicare file statici.
- Configura un servizio di messaggistica su Node.js utilizzando socket.io.
- Utilizzalo per creare "stanze" e scambiare messaggi.
Una versione completa di questo passaggio si trova nella cartella step-04.
Scopri di più
- Repository di esempio di chat Socket.io
- WebRTC nel mondo reale: STUN, TURN e segnalazione
- Il termine "segnalazione" in WebRTC
Prossimo
Scopri come utilizzare la segnalazione per consentire a due utenti di stabilire una connessione peer.
8. Combinare la connessione peer e la segnalazione
Obiettivi didattici
In questo passaggio scoprirai come:
- Esegui un servizio di segnalazione WebRTC utilizzando Socket.IO in esecuzione su Node.js
- Utilizza questo servizio per scambiare metadati WebRTC tra peer.
Una versione completa di questo passaggio si trova nella cartella step-05.
Sostituisci HTML e JavaScript
Sostituisci i contenuti di index.html con quanto segue:
<!DOCTYPE html>
<html>
<head>
<title>Realtime communication with WebRTC</title>
<link rel="stylesheet" href="/css/main.css" />
</head>
<body>
<h1>Realtime communication with WebRTC</h1>
<div id="videos">
<video id="localVideo" autoplay muted></video>
<video id="remoteVideo" autoplay></video>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="js/main.js"></script>
</body>
</html>
Sostituisci js/main.js con i contenuti di step-05/js/main.js.
Esegui il server Node.js
Se non stai seguendo questo codelab dalla directory work, potresti dover installare le dipendenze per la cartella step-05 o per la cartella di lavoro corrente. Esegui questo comando dalla directory di lavoro:
npm install
Una volta installato, se il server Node.js non è in esecuzione, avvialo chiamando il seguente comando nella directory work:
node index.js
Assicurati di utilizzare la versione di index.js del passaggio precedente che implementa Socket.IO. Per ulteriori informazioni su Node e Socket IO, consulta la sezione "Configura un servizio di segnalazione per lo scambio di messaggi".
Dal browser, apri localhost:8080.
Apri di nuovo localhost:8080 in una nuova scheda o finestra. Un elemento video mostrerà lo stream locale di getUserMedia() e l'altro mostrerà il video "remoto" trasmesso in streaming tramite RTCPeerconnection.
Visualizza la registrazione nella console del browser.
Punti bonus
- Questa applicazione supporta solo le videochiamate individuali. Come potresti modificare il design per consentire a più persone di condividere la stessa sala di chat video?
- L'esempio ha il nome della stanza foo codificato. Qual è il modo migliore per attivare altri nomi di stanze?
- In che modo gli utenti condividerebbero il nome della stanza? Prova a creare un'alternativa alla condivisione dei nomi delle stanze.
- Come potresti cambiare l'app
Che cosa hai imparato
In questo passaggio hai imparato a:
- Esegui un servizio di segnalazione WebRTC utilizzando Socket.IO in esecuzione su Node.js.
- Utilizza questo servizio per scambiare metadati WebRTC tra peer.
Una versione completa di questo passaggio si trova nella cartella step-05.
Suggerimenti
- Le statistiche e i dati di debug di WebRTC sono disponibili all'indirizzo chrome://webrtc-internals.
- test.webrtc.org può essere utilizzato per controllare l'ambiente locale e testare la videocamera e il microfono.
- Se riscontri problemi insoliti con la memorizzazione nella cache, prova a effettuare le seguenti operazioni:
- Esegui un aggiornamento forzato tenendo premuto Ctrl e facendo clic sul pulsante Ricarica.
- Riavviare il browser
- Esegui
npm cache cleandalla riga di comando.
Prossimo
Scopri come scattare una foto, ottenere i dati dell'immagine e condividerli tra peer remoti.
9. Scatta una foto e condividila tramite un canale di dati
Obiettivi didattici
In questo passaggio imparerai a:
- Scatta una foto e ottieni i dati utilizzando l'elemento canvas.
- Scambia dati delle immagini con un utente remoto.
Una versione completa di questo passaggio si trova nella cartella step-06.
Come funziona
In precedenza hai imparato a scambiare messaggi di testo utilizzando RTCDataChannel.
Questo passaggio consente di condividere interi file: in questo esempio, le foto acquisite tramite getUserMedia().
Le parti principali di questo passaggio sono le seguenti:
- Crea un canale di dati. Tieni presente che in questo passaggio non aggiungi flussi multimediali alla connessione peer.
- Acquisire il video stream della webcam dell'utente con
getUserMedia():
var video = document.getElementById('video');
function grabWebCamVideo() {
console.log('Getting user media (video) ...');
navigator.mediaDevices.getUserMedia({
video: true
})
.then(gotStream)
.catch(function(e) {
alert('getUserMedia() error: ' + e.name);
});
}
- Quando l'utente fa clic sul pulsante Snap, acquisisci un'istantanea (un frame video) dallo stream video e visualizzala in un elemento
canvas:
var photo = document.getElementById('photo');
var photoContext = photo.getContext('2d');
function snapPhoto() {
photoContext.drawImage(video, 0, 0, photo.width, photo.height);
show(photo, sendBtn);
}
- Quando l'utente fa clic sul pulsante Invia, converti l'immagine in byte e inviali tramite un canale di dati:
function sendPhoto() {
// Split data channel message in chunks of this byte length.
var CHUNK_LEN = 64000;
var img = photoContext.getImageData(0, 0, photoContextW, photoContextH),
len = img.data.byteLength,
n = len / CHUNK_LEN | 0;
console.log('Sending a total of ' + len + ' byte(s)');
dataChannel.send(len);
// split the photo and send in chunks of about 64KB
for (var i = 0; i < n; i++) {
var start = i * CHUNK_LEN,
end = (i + 1) * CHUNK_LEN;
console.log(start + ' - ' + (end - 1));
dataChannel.send(img.data.subarray(start, end));
}
// send the reminder, if any
if (len % CHUNK_LEN) {
console.log('last ' + len % CHUNK_LEN + ' byte(s)');
dataChannel.send(img.data.subarray(n * CHUNK_LEN));
}
}
- Il lato ricevente converte i byte del messaggio del canale di dati in un'immagine e la mostra all'utente:
function receiveDataChromeFactory() {
var buf, count;
return function onmessage(event) {
if (typeof event.data === 'string') {
buf = window.buf = new Uint8ClampedArray(parseInt(event.data));
count = 0;
console.log('Expecting a total of ' + buf.byteLength + ' bytes');
return;
}
var data = new Uint8ClampedArray(event.data);
buf.set(data, count);
count += data.byteLength;
console.log('count: ' + count);
if (count === buf.byteLength) {
// we're done: all data chunks have been received
console.log('Done. Rendering photo.');
renderPhoto(buf);
}
};
}
function renderPhoto(data) {
var canvas = document.createElement('canvas');
canvas.width = photoContextW;
canvas.height = photoContextH;
canvas.classList.add('incomingPhoto');
// trail is the element holding the incoming images
trail.insertBefore(canvas, trail.firstChild);
var context = canvas.getContext('2d');
var img = context.createImageData(photoContextW, photoContextH);
img.data.set(data);
context.putImageData(img, 0, 0);
}
Ottieni il codice
Sostituisci i contenuti della cartella work con i contenuti di step-06. Il file index.html in work ora dovrebbe avere il seguente aspetto**:**
<!DOCTYPE html>
<html>
<head>
<title>Realtime communication with WebRTC</title>
<link rel="stylesheet" href="/css/main.css" />
</head>
<body>
<h1>Realtime communication with WebRTC</h1>
<h2>
<span>Room URL: </span><span id="url">...</span>
</h2>
<div id="videoCanvas">
<video id="camera" autoplay></video>
<canvas id="photo"></canvas>
</div>
<div id="buttons">
<button id="snap">Snap</button><span> then </span><button id="send">Send</button>
<span> or </span>
<button id="snapAndSend">Snap & Send</button>
</div>
<div id="incoming">
<h2>Incoming photos</h2>
<div id="trail"></div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="js/main.js"></script>
</body>
</html>
Se non segui questo codelab dalla directory work, potresti dover installare le dipendenze per la cartella step-06 o per la cartella di lavoro corrente. Basta eseguire il seguente comando dalla directory di lavoro:
npm install
Una volta installato, se il server Node.js non è in esecuzione, avvialo chiamando il seguente comando dalla directory work:
node index.js
Assicurati di utilizzare la versione di index.js che implementa Socket.IO e ricordati di riavviare il server Node.js se apporti modifiche. Per ulteriori informazioni su Node e Socket IO, consulta la sezione "Configura un servizio di segnalazione per lo scambio di messaggi".
Se necessario, fai clic sul pulsante Consenti per consentire all'app di utilizzare la webcam.
L'app creerà un ID stanza casuale e lo aggiungerà all'URL. Apri l'URL dalla barra degli indirizzi in una nuova scheda o finestra del browser.
Fai clic sul pulsante Scatta e invia, quindi guarda l'area In arrivo nell'altra scheda in fondo alla pagina. L'app trasferisce le foto tra le schede.
Il risultato dovrebbe essere simile a questo:

Punti bonus
- Come puoi modificare il codice per consentire la condivisione di qualsiasi tipo di file?
Scopri di più
- API MediaStream Image Capture: un'API per scattare fotografie e controllare le fotocamere, in arrivo a breve in un browser vicino a te.
- L'API MediaRecorder, per la registrazione di audio e video: demo, documentazione.
Che cosa hai imparato
- Come scattare una foto e ottenere i dati utilizzando l'elemento canvas.
- Come scambiare questi dati con un utente remoto.
Una versione completa di questo passaggio si trova nella cartella step-06.
10. Complimenti
Hai creato un'app per lo streaming video e lo scambio di dati in tempo reale.
Che cosa hai imparato
In questo codelab hai imparato a:
- Ottenere video dalla webcam.
- Trasmetti video in streaming con RTCPeerConnection.
- Trasmetti dati in streaming con RTCDataChannel.
- Configura un servizio di segnalazione per scambiare messaggi.
- Combina la connessione peer e la segnalazione.
- Scatta una foto e condividila tramite un canale di dati.
Passaggi successivi
- Esamina il codice e l'architettura dell'applicazione di chat WebRTC canonica AppRTC: app, codice.
- Prova le demo live disponibili su github.com/webrtc/samples.
Scopri di più
- Una serie di risorse per iniziare a utilizzare WebRTC sono disponibili su webrtc.org.