WebRTC to nowy front w długiej wojnie o otwartą i nieograniczoną sieć.
Brendan Eich, twórca JavaScriptu
Komunikacja w czasie rzeczywistym bez wtyczek
Wyobraź sobie świat, w którym telefon, telewizor i komputer mogłyby komunikować się na wspólnej platformie. Wyobraź sobie, że dodanie czatu wideo i udostępnianie danych peer-to-peer w aplikacji internetowej jest bardzo proste. To właśnie zakłada WebRTC.
Chcesz spróbować? WebRTC jest dostępny na komputerach i urządzeniach mobilnych w przeglądarkach Google Chrome, Safari, Firefox i Opera. Na początek możesz skorzystać z prostej aplikacji do wideoczatu na stronie appr.tc:
- Otwórz appr.tc w przeglądarce.
- Kliknij Dołącz, aby dołączyć do pokoju czatu i zezwolić aplikacji na korzystanie z Twojej kamery internetowej.
- Otwórz adres URL wyświetlany na końcu strony w nowej karcie lub, co jeszcze lepsze, na innym komputerze.
Krótkie wprowadzenie
Nie masz czasu na przeczytanie tego artykułu lub interesuje Cię tylko kod?
- Aby zapoznać się z WebRTC, obejrzyj ten film z Google I/O lub te slajdy:
- Jeśli nie używasz interfejsu API
getUserMedia
, zapoznaj się z artykułami Rejestrowanie dźwięku i obrazu w HTML5 oraz simpl.info getUserMedia. - Aby dowiedzieć się więcej o interfejsie
RTCPeerConnection
API, zapoznaj się z tym przykładem i artykułem „simpl.info RTCPeerConnection”. - Aby dowiedzieć się, jak WebRTC używa serwerów do sygnalizacji oraz do przechodzenia przez zaporę sieciową i NAT, zapoznaj się z kodem oraz logami konsoli z appr.tc.
- Nie możesz się doczekać i chcesz od razu wypróbować WebRTC? Wypróbuj ponad 20 demo, które wykorzystują interfejsy WebRTC JavaScript.
- Masz problemy z komputerem i WebRTC? Otwórz narzędzie do rozwiązywania problemów z WebRTC.
Możesz też przejść bezpośrednio do ćwiczenia z programowania WebRTC, w którym znajdziesz szczegółowe instrukcje tworzenia kompletnej aplikacji do czatu wideo, w tym prostego serwera sygnalizacyjnego.
Krótka historia WebRTC
Jednym z ostatnich dużych wyzwań dla internetu jest umożliwienie komunikacji głosowej i wideo, czyli komunikacji w czasie rzeczywistym (RTC). RTC powinien być tak samo naturalny w aplikacji internetowej jak wpisywanie tekstu w polu tekstowym. Bez niego ogranicza się Twoja zdolność do wprowadzania innowacji i rozwijania nowych sposobów interakcji z użytkownikami.
W przeszłości RTC było złożonym rozwiązaniem korporacyjnym, które wymagało licencjonowania drogich technologii audio i wideo lub ich samodzielnego opracowania. Integracja technologii RTC z istniejącymi treściami, danymi i usługami była trudna i czasochłonna, zwłaszcza w przypadku internetu.
Rozmowy wideo w Gmailu stały się popularne w 2008 r., a w 2011 r. Google wprowadził Hangouts, który korzysta z Talk (podobnie jak Gmail). Google kupiło GIPS, firmę, która opracowała wiele komponentów potrzebnych do RTC, takich jak kodeki i techniki redukcji echa. Google udostępniła jako oprogramowanie open source technologie opracowane przez GIPS i współpracowała z odpowiednimi organami standaryzacyjnymi w ramach grupy roboczej IETF (Internet Engineering Task Force) i konsorcjum W3C (World Wide Web Consortium), aby uzyskać konsensus branży. W maju 2011 r. firma Ericsson stworzyła pierwszą implementację WebRTC.
WebRTC wdrożył otwarte standardy do komunikacji w czasie rzeczywistym, bez wtyczek, dotyczących obrazu, dźwięku i danych. Potrzebowaliśmy tego:
- Wiele usług internetowych używało RTC, ale wymagało pobierania, aplikacji natywnych lub wtyczek. Dotyczyło to Skype, Facebooka i Hangouts.
- Pobieranie, instalowanie i aktualizowanie wtyczek jest skomplikowane, podatne na błędy i irytujące.
- Wdrożenie, debugowanie, rozwiązywanie problemów, testowanie i utrzymanie wtyczek jest trudne, a ich stosowanie może wymagać licencjonowania i integracji ze złożoną, kosztowną technologią. Często trudno jest przekonać użytkowników do zainstalowania wtyczek.
Projekt WebRTC opiera się na następujących zasadach: interfejsy API powinny być typu open source, bezpłatne, standardowe, wbudowane w przeglądarki internetowe i wydajniejsze niż istniejące technologie.
Gdzie jesteśmy?
WebRTC jest używany w różnych aplikacjach, takich jak Google Meet. WebRTC został też zintegrowany z aplikacją natywną WebKitGTK+ i Qt.
WebRTC implementuje te 3 interfejsy API: – MediaStream
(znany też jako getUserMedia
) – RTCPeerConnection
– RTCDataChannel
Interfejsy API są zdefiniowane w tych 2 specyfikacjach:
Wszystkie 3 interfejsy API są obsługiwane na urządzeniach mobilnych i komputerach w przypadku przeglądarek Chrome, Safari, Firefox, Edge i Opera.
getUserMedia
: wersje demonstracyjne i kod znajdziesz w próbkach WebRTC. Możesz też wypróbować niesamowite przykłady Chrisa Wilsona, które wykorzystują getUserMedia
jako dane wejściowe do dźwięku w internecie.
RTCPeerConnection
: proste demo i w pełni funkcjonalną aplikację do wideokonferencji znajdziesz odpowiednio w próbnych implementacjach WebRTC Peer Connection i appr.tc. Aplikacja ta korzysta z pliku adapter.js, który jest dodatkiem JavaScriptu obsługiwanym przez Google przy wsparciu społeczności WebRTC. Pozwala ona pominąć różnice między przeglądarkami i zmiany specyfikacji.
RTCDataChannel
: aby zobaczyć to w działaniu, otwórz próbki WebRTC i obejrzyj jeden z demo kanału danych.
Ćwiczenia z programowania dotyczące WebRTC pokazują, jak użyć wszystkich 3 interfejsów API do utworzenia prostej aplikacji do czatu wideo i udostępniania plików.
Pierwsze spotkanie WebRTC
Aplikacje WebRTC muszą:
- strumieniowe odtwarzanie dźwięku, obrazu lub innych danych;
- Pobieranie informacji o sieci, takich jak adresy IP i porty, oraz wymiana tych informacji z innymi klientami WebRTC (zwanymi peerami) w celu umożliwienia połączenia nawet przez NAT i zapory sieciowe.
- koordynować sygnalizację, aby zgłaszać błędy i inicjować lub zamykać sesje;
- wymieniać informacje o multimediach i możliwościach klienta, takie jak rozdzielczość i kodeki;
- przesyłać strumieniowo dźwięk, wideo lub dane;
Aby pozyskiwać i przesyłać dane strumieniowe, WebRTC implementuje te interfejsy API:
MediaStream
uzyskuje dostęp do strumieni danych, np. z aparatu i mikrofonu użytkownika.RTCPeerConnection
umożliwia prowadzenie rozmów audio i wideo z szyfrowaniem oraz zarządzaniem przepustowością.RTCDataChannel
umożliwia komunikację peer-to-peer danych ogólnych.
(szczegółowe informacje o aspektach sieci i sygnalizacji WebRTC znajdziesz w następnych sekcjach).
Interfejs API MediaStream
(znany też jako interfejs API getUserMedia
)
Interfejs MediaStream
API reprezentuje zsynchronizowane strumienie multimediów. Na przykład strumień z wejścia z aparatu i mikrofonu zawiera zsynchronizowane ścieżki wideo i dźwięku. (Nie myl MediaStreamTrack
z elementem <track>
, który jest czymś zupełnie innym).
Najłatwiej zrozumieć interfejs API MediaStream
, korzystając z niego w praktyce:
- W przeglądarce otwórz Przykłady WebRTC
getUserMedia
. - Otwórz konsolę.
- Sprawdź zmienną
stream
, która ma zakres globalny.
Każdy element MediaStream
ma dane wejściowe, które mogą być generowane przez element MediaStream
, oraz dane wyjściowe, które mogą być przekazywane do elementu wideo lub elementu RTCPeerConnection
.getUserMedia()
Metoda getUserMedia()
przyjmuje parametr obiektu MediaStreamConstraints
i zwraca obiekt Promise
, który jest rozwiązywany do obiektu MediaStream
.
Każdy element MediaStream
ma element label
, np. 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'
. Metody getAudioTracks()
i getVideoTracks()
zwracają tablicę wartości MediaStreamTrack
.
W przypadku przykładu getUserMedia
funkcja stream.getAudioTracks()
zwraca pusty tablicowy (ponieważ nie ma dźwięku), a zakładając, że podłączona jest działająca kamera internetowa, funkcja stream.getVideoTracks()
zwraca tablicowy z jednym elementem MediaStreamTrack
reprezentującym strumień z kamery internetowej. Każdy MediaStreamTrack
ma rodzaj ('video'
lub 'audio'
), label
(coś w rodzaju 'FaceTime HD Camera (Built-in)'
) i reprezentuje co najmniej 1 kanał audio lub wideo. W tym przypadku jest tylko 1 ścieżka wideo i brak dźwięku, ale łatwo sobie wyobrazić przypadki użycia, w których jest ich więcej, np. aplikacja do czatowania, która przesyła strumienie z przedniego aparatu, tylnego aparatu i mikrofonu, oraz aplikacja udostępniająca ekran.
Do elementu wideo można dołączyć MediaStream
, ustawiając atrybut srcObject
. Wcześniej było to możliwe dzięki ustawieniu atrybutu src
na adres URL obiektu utworzonego za pomocą funkcji URL.createObjectURL()
, ale ta funkcja została wycofana.
getUserMedia
może też służyć jako węzeł wejściowy dla Web Audio API:
// Cope with browser differences.
let audioContext;
if (typeof AudioContext === 'function') {
audioContext = new AudioContext();
} else if (typeof webkitAudioContext === 'function') {
audioContext = new webkitAudioContext(); // eslint-disable-line new-cap
} else {
console.log('Sorry! Web Audio not supported.');
}
// Create a filter node.
var filterNode = audioContext.createBiquadFilter();
// See https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#BiquadFilterNode-section
filterNode.type = 'highpass';
// Cutoff frequency. For highpass, audio is attenuated below this frequency.
filterNode.frequency.value = 10000;
// Create a gain node to change audio volume.
var gainNode = audioContext.createGain();
// Default is 1 (no change). Less than 1 means audio is attenuated
// and vice versa.
gainNode.gain.value = 0.5;
navigator.mediaDevices.getUserMedia({audio: true}, (stream) => {
// Create an AudioNode from the stream.
const mediaStreamSource =
audioContext.createMediaStreamSource(stream);
mediaStreamSource.connect(filterNode);
filterNode.connect(gainNode);
// Connect the gain node to the destination. For example, play the sound.
gainNode.connect(audioContext.destination);
});
Aplikacje i rozszerzenia oparte na Chromium również mogą zawierać getUserMedia
. Dodanie do pliku manifestu uprawnień audioCapture
lub videoCapture
umożliwia proszenie o uprawnienia i przyznawanie ich tylko raz podczas instalacji. Następnie użytkownik nie jest proszony o pozwolenie na dostęp do aparatu ani mikrofonu.
Uprawnienia należy przyznać tylko raz.getUserMedia()
Gdy po raz pierwszy otwierasz stronę, na infobar przeglądarki wyświetla się przycisk Zezwól. Pod koniec 2015 r. Chrome wycofał dostęp HTTP do usługi getUserMedia()
, ponieważ została ona sklasyfikowana jako potężna funkcja.
Chodzi o to, aby umożliwić MediaStream
dla dowolnego źródła danych strumieniowych, a nie tylko aparatu czy mikrofonu. Umożliwiłoby to przesyłanie strumieniowe z przechowywanych danych lub dowolnych źródeł danych, takich jak czujniki czy inne dane wejściowe.
getUserMedia()
naprawdę błyszczy w połączeniu z innymi interfejsami API i bibliotekami JavaScriptu:
- Webcam Toy to aplikacja do robienia zdjęć, która wykorzystuje WebGL do dodawania dziwnych i cudownych efektów do zdjęć, które można udostępniać lub zapisywać lokalnie.
- FaceKat to gra śledząca twarz, która została stworzona za pomocą headtrackr.js.
- Aparat ASCII generuje obrazy ASCII za pomocą interfejsu Canvas API.
Ograniczenia
Ograniczenia można używać do ustawiania wartości rozdzielczości filmów w getUserMedia()
. Umożliwia to też obsługę innych ograniczeń, takich jak format obrazu, kierunek (przednia lub tylna kamera), szybkość, wysokość i szerokość klatki oraz metoda applyConstraints()
.
Przykład znajdziesz w przykładach kodu WebRTC: getUserMedia
wybierz rozdzielczość.
Ustawienie niedozwolonej wartości ograniczeń powoduje wyświetlenie wartości DOMException
lub OverconstrainedError
, jeśli na przykład żądana rozdzielczość jest niedostępna. Aby zobaczyć to w działaniu, wybierz próbki WebRTC: getUserMedia
wybierz rozdzielczość.
Zrzuty ekranu i kart
Aplikacje w Chrome umożliwiają też udostępnianie obrazu wideo z pojedynczej karty przeglądarki lub całego pulpitu za pomocą interfejsów API chrome.tabCapture
i chrome.desktopCapture
. (Demo i więcej informacji znajdziesz w artykule Udostępnianie ekranu za pomocą WebRTC. Artykuł ma już kilka lat, ale nadal jest interesujący.)
W Chrome możesz też użyć jako źródła MediaStream
zrzutu ekranu, korzystając z eksperymentalnego ograniczenia chromeMediaSource
. Pamiętaj, że przechwytywanie ekranu wymaga HTTPS i należy go używać tylko do celów programistycznych, ponieważ jest włączane za pomocą flagi wiersza poleceń, jak opisano w tym poście.
sygnalizacja: informacje o sterowaniu sesją, sieci i multimediach;
WebRTC używa RTCPeerConnection
do przesyłania danych strumieniowych między przeglądarkami (zwanymi też peerami), ale potrzebuje też mechanizmu do koordynowania komunikacji i wysyłania komunikatów sterujących, czyli procesu znanego jako sygnalizacja. Metody i protokoły sygnalizacji nie są określone przez WebRTC. Sygnalizacja nie jest częścią interfejsu API RTCPeerConnection
.
Zamiast tego deweloperzy aplikacji WebRTC mogą wybrać dowolny preferowany protokół przesyłania wiadomości, np. SIP lub XMPP, oraz dowolny odpowiedni kanał komunikacji dwukierunkowej. Przykład appr.tc używa XHR i Channel API jako mechanizmu sygnalizacji. Ćwiczenie z programowania korzysta z Socket.io działającego na serwerze Node.js.
Sygnalizowanie służy do wymiany 3 rodzajów informacji:
- komunikaty sterujące sesją: do inicjowania i zamykania komunikacji oraz zgłaszania błędów;
- Konfiguracja sieci: jakie są adres IP i port komputera w oczach świata zewnętrznego?
- Możliwości multimedialne: jakie kodeki i rozdzielczości może obsługiwać Twoja przeglądarka i przeglądarka, z którą chce się komunikować?
Zanim rozpocznie się strumieniowe przesyłanie danych peer-to-peer, wymiana informacji za pomocą sygnalizacji musi zostać zakończona.
Załóżmy, że Alicja chce się komunikować z Robertem. Oto przykładowy kod ze specyfikacji W3C WebRTC, który pokazuje proces sygnalizacji w akcji. Kod zakłada istnienie pewnego mechanizmu sygnalizacji utworzonego w ramach metody createSignalingChannel()
. Pamiętaj też, że w Chrome i Operze przedrostek RTCPeerConnection
jest obecnie dodawany.
// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);
// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});
// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
try {
await pc.setLocalDescription(await pc.createOffer());
// Send the offer to the other peer.
signaling.send({desc: pc.localDescription});
} catch (err) {
console.error(err);
}
};
// Once remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
// Don't set srcObject again if it is already set.
if (remoteView.srcObject) return;
remoteView.srcObject = event.streams[0];
};
// Call start() to initiate.
async function start() {
try {
// Get local stream, show it in self-view, and add it to be sent.
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
selfView.srcObject = stream;
} catch (err) {
console.error(err);
}
}
signaling.onmessage = async ({desc, candidate}) => {
try {
if (desc) {
// If you get an offer, you need to reply with an answer.
if (desc.type === 'offer') {
await pc.setRemoteDescription(desc);
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
await pc.setLocalDescription(await pc.createAnswer());
signaling.send({desc: pc.localDescription});
} else if (desc.type === 'answer') {
await pc.setRemoteDescription(desc);
} else {
console.log('Unsupported SDP type.');
}
} else if (candidate) {
await pc.addIceCandidate(candidate);
}
} catch (err) {
console.error(err);
}
};
Najpierw Alicja i Robert wymieniają się informacjami o sieci. (wyrażenie znajdowanie kandydatów odnosi się do procesu znajdowania interfejsów sieciowych i portów za pomocą ramki ICE).
- Alice tworzy obiekt
RTCPeerConnection
z obsługąonicecandidate
, która jest wykonywana, gdy stają się dostępne kandydackie sieci. - Alice wysyła zserializowane dane kandydata do Boba za pomocą dowolnego kanału sygnalizacyjnego, takiego jak WebSocket lub inny mechanizm.
- Gdy Bob otrzyma od Alice wiadomość od kandydata, zadzwoni pod numer
addIceCandidate
, aby dodać kandydata do opisu zdalnego peera.
Klienci WebRTC (zwani też peerami lub Alicją i Bobem w tym przykładzie) muszą też ustalać i wymieniać informacje o lokalnych i zdalnych nośnikach audio i wideo, takie jak rozdzielczość i możliwości kodeków. Sygnalizowanie wymiany informacji o konfiguracji mediów odbywa się poprzez wymianę oferty i odpowiedzi za pomocą protokołu SDP (Session Description Protocol):
- Alicja wykonuje metodę
RTCPeerConnection
createOffer()
. Zwracana wartość jest przekazywana doRTCSessionDescription
– opisu sesji lokalnej Alice. - W wywołaniu zwrotnym Alice ustawia lokalny opis za pomocą
setLocalDescription()
, a potem wysyła opis sesji do Boba przez kanał sygnalizacyjny. Pamiętaj, żeRTCPeerConnection
nie zacznie zbierać kandydatów, dopóki nie zostanie wywołana funkcjasetLocalDescription()
. Jest to ujęte w projekcie JSEP IETF. - Robert ustawia opis wysłany przez Alicję jako opis zdalny za pomocą atrybutu
setRemoteDescription()
. - Robert wykonuje metodę
RTCPeerConnection
createAnswer()
, przekazując do niej zdalny opis otrzymany od Alicji, aby można było wygenerować lokalną sesję zgodną z jej sesją. Wywołanie zwrotnecreateAnswer()
otrzymuje argumentRTCSessionDescription
. Robert ustawia go jako opis lokalny i wysyła do Alicji. - Gdy Alicja otrzyma opis sesji Roberta, ustawi go jako opis zdalny za pomocą
setRemoteDescription
. - Ping!
Obiekty RTCSessionDescription
to bloby zgodne z protokołem opisu sesji (SDP). Obiekt SDP w postaci ciągu wygląda tak:
v=0
o=- 3883943731 1 IN IP4 127.0.0.1
s=
t=0 0
a=group:BUNDLE audio video
m=audio 1 RTP/SAVPF 103 104 0 8 106 105 13 126
// ...
a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh810
Pozyskiwanie i wymiana informacji o sieci i mediach mogą odbywać się jednocześnie, ale oba procesy muszą zostać ukończone, zanim rozpocznie się strumieniowe przesyłanie dźwięku i obrazu między peerami.
Opisywana wcześniej architektura oferty/odpowiedzi nosi nazwę JavaScript Session Establishment Protocol (JSEP). W filmie demonstracyjnym firmy Ericsson dotyczącym pierwszej implementacji WebRTC znajdziesz świetną animację, która wyjaśnia proces sygnalizacji i strumieniowania.
Po zakończeniu procesu sygnalizacji dane mogą być przesyłane strumieniowo bezpośrednio między urządzeniami, między osobą dzwoniącą a osobą odbierającą połączenie, lub w razie niepowodzenia przez pośredniczący serwer przekaźnikowy (więcej informacji na ten temat znajdziesz poniżej). Streaming to zadanie RTCPeerConnection
.
RTCPeerConnection
RTCPeerConnection
to komponent WebRTC, który zapewnia stabilną i wydajną komunikację danych strumieniowych między urządzeniami.
Poniżej znajduje się diagram architektury WebRTC pokazujący rolę RTCPeerConnection
. Jak widać, zielone części są skomplikowane.
Z tego diagramu wynika, że RTCPeerConnection
chroni programistów stron internetowych przed mnóstwem złożonych elementów, które kryją się pod spodem. Kodeki i protokoły używane przez WebRTC wykonują ogromną ilość pracy, aby umożliwić komunikację w czasie rzeczywistym nawet w niepewnych sieciach:
- Ukrywanie utraty pakietów
- usuwanie echa;
- dostosowywanie się do przepustowości,
- Dynamiczne buforowanie jittera
- Automatyczna kontrola wzmocnienia
- Redukcja i eliminacja szumów
- Czyszczenie obrazu
Poprzedni kod W3C pokazuje uproszczony przykład WebRTC z perspektywy sygnalizacji. Poniżej znajdziesz instrukcje dotyczące 2 działających aplikacji WebRTC. Pierwszy to prosty przykład pokazujący RTCPeerConnection
, a drugi to w pełni działający klient czatu wideo.
RTCPeerConnection bez serwerów
Poniższy kod pochodzi z próbek kodu WebRTC dotyczących połączenia peer-to-peer, które zawiera lokalny i zdalny RTCPeerConnection
(oraz lokalny i zdalny film) na jednej stronie internetowej. Nie jest to bardzo przydatne – wywołujący i wywoływany znajdują się na tej samej stronie – ale pozwala nieco lepiej zrozumieć działanie interfejsu API RTCPeerConnection
, ponieważ obiekty RTCPeerConnection
na stronie mogą wymieniać dane i wiadomości bezpośrednio bez konieczności korzystania z pośrednich mechanizmów sygnalizacji.
W tym przykładzie pc1
reprezentuje lokalny punkt końcowy (wywołujący), a pc2
reprezentuje zdalny punkt końcowy (wywoływany).
Rozmówca
- Utwórz nowe
RTCPeerConnection
i dodaj strumień zgetUserMedia()
:```js // Servers to opcjonalny plik konfiguracji. (patrz dalej sekcja dotycząca protokołów TURN i STUN) pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
- Utwórz ofertę i ustaw ją jako lokalny opis dla
pc1
oraz jako opis zdalny dlapc2
. Można to zrobić bezpośrednio w kodzie bez używania sygnalizacji, ponieważ zarówno dzwoniący, jak i odbiorca są na tej samej stronie:js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );
Wywoływany
- Utwórz
pc2
, a gdy dodasz strumień zpc1
, wyświetl go w elemencie wideo:js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }
RTCPeerConnection
API plus serwery
W rzeczywistych zastosowaniach WebRTC wymaga serwerów, nawet jeśli są proste, więc mogą wystąpić takie sytuacje:
- Użytkownicy mogą się nawzajem znajdować i wymieniać prawdziwe dane, takie jak imiona i nazwiska.
- Aplikacje klienckie WebRTC (peers) wymieniają informacje o sieci.
- Urządzenia wymieniają się danymi o multimediach, takimi jak format i rozdzielczość wideo.
- Aplikacje klienckie WebRTC przechodzą przez bramy NAT i zapory sieciowe.
Innymi słowy, WebRTC wymaga 4 typów funkcji po stronie serwera:
- Wyszukiwanie użytkowników i komunikacja
- Wysyłanie sygnałów
- Omijanie zapory sieciowej lub bramy NAT
- serwery pośredniczące na wypadek, gdyby komunikacja peer-to-peer nie powiodła się;
Ten artykuł nie dotyczy pokonywania NAT, sieci typu peer-to-peer ani wymagań dotyczących tworzenia aplikacji serwera na potrzeby wykrywania użytkowników i sygnalizacji. Wystarczy powiedzieć, że protokół STUN i jego rozszerzenie TURN są używane przez platformę ICE, aby umożliwić RTCPeerConnection
radzenie sobie z przekierowywaniem NAT i innymi kaprysami sieci.
ICE to framework do łączenia urządzeń, np. dwóch klientów rozmów wideo. Na początku ICE próbuje połączyć peerów bezpośrednio z najmniejszym możliwym opóźnieniem przez UDP. W ramach tego procesu serwery STUN mają tylko jedno zadanie: umożliwić peerowi za NAT-em znalezienie jego adresu publicznego i portu. (Więcej informacji o protokołach STUN i TURN znajdziesz w artykule Tworzenie usług backendowych potrzebnych do aplikacji WebRTC).
Jeśli UDP się nie powiedzie, ICE spróbuje użyć TCP. Jeśli połączenie bezpośrednie się nie powiedzie, zwłaszcza z powodu korporacyjnych zapory sieciowej i przekierowania NAT, ICE używa pośredniego serwera TURN. Inaczej mówiąc, ICE najpierw używa STUN z UDP do bezpośredniego łączenia peerów, a jeśli to się nie uda, przełącza się na serwer przekaźnika TURN. Wyrażenie znajdowanie kandydatów odnosi się do procesu znajdowania interfejsów i portów sieciowych.
Inżynier ds. WebRTC Justin Uberti podaje więcej informacji o protokołach ICE, STUN i TURN w prezentacji WebRTC z Google I/O 2013. (slajdy z prezentacją zawierają przykłady implementacji serwera TURN i STUN).
Prosty klient do obsługi czatu wideo
Aby wypróbować WebRTC z użyciem sygnalizacji i przechodzenia przez NAT/firewall za pomocą serwera STUN, możesz skorzystać z demo czatu wideo na stronie appr.tc. Ta aplikacja używa pliku adapter.js, który chroni aplikacje przed zmianami specyfikacji i różnicami w prefiksach.
Kod celowo jest wyczerpujący w logowaniu. Aby poznać kolejność zdarzeń, sprawdź konsolę. Poniżej znajdziesz szczegółowy opis kodu.
Topologie sieci
W obecnej implementacji WebRTC obsługuje tylko komunikację jeden-do-jednego, ale może być używany w bardziej złożonych scenariuszach sieciowych, np. w przypadku wielu punktów końcowych, z których każdy komunikuje się bezpośrednio lub za pomocą jednostki sterującej wielopunktowej (MCU), czyli serwera, który może obsługiwać dużą liczbę uczestników i wykonywć selektywną transmisję strumieniową oraz miksowanie lub nagrywanie dźwięku i obrazu.
Wiele istniejących aplikacji WebRTC demonstruje tylko komunikację między przeglądarkami, ale serwery bramy mogą umożliwić aplikacji WebRTC działającej w przeglądarce interakcję z urządzeniami, takimi jak telefony (znane też jako PSTN) i systemy VOIP. W maju 2012 r. firma Doubango Telecom udostępniła na licencji open source klienta SIP sipml5, który został stworzony na podstawie WebRTC i WebSocket. Pozwala on (między innymi) na prowadzenie rozmów wideo między przeglądarkami i aplikacjami na iOS i Androida. Na konferencji Google I/O firmy Tethr i Tropo zaprezentowały ramy do komunikacji w przypadku katastrof w walizce, korzystając z komórki OpenBTS, aby umożliwić komunikację między telefonami z podstawową przeglądarką a komputerami za pomocą WebRTC. Komunikacja telefoniczna bez operatora
RTCDataChannel
API<
Oprócz dźwięku i obrazu WebRTC obsługuje komunikację w czasie rzeczywistym dla innych typów danych.
Interfejs API RTCDataChannel
umożliwia wymianę dowolnych danych z małym opóźnieniem i dużą przepustowością. Demonstracje jednostronicowe i informacje o tworzeniu prostej aplikacji do przesyłania plików znajdziesz odpowiednio w przykładach WebRTC i ćwiczeniach z programowania poświęconych WebRTC.
Interfejs API ma wiele zastosowań, m.in.:
- Gry
- Aplikacje pulpitu zdalnego
- Czat tekstowy w czasie rzeczywistym
- Przesyłanie plików
- Sieci zdecentralizowane
Interfejs API zawiera kilka funkcji, które umożliwiają optymalne wykorzystanie RTCPeerConnection
i zapewniają zaawansowaną i elastyczna komunikację peer-to-peer:
- Korzystanie z konfiguracji sesji
RTCPeerConnection
- Wiele kanałów jednocześnie z uwzględnieniem priorytetów
- niezawodna i nierzetelna semantyka dostawy,
- Wbudowane zabezpieczenia (DTLS) i kontrola natężenia
- Możliwość korzystania z nich z dźwiękiem lub bez niego
Składnia jest celowo podobna do WebSocket z metodą send()
i zdarzeniem message
:
const localConnection = new RTCPeerConnection(servers);
const remoteConnection = new RTCPeerConnection(servers);
const sendChannel =
localConnection.createDataChannel('sendDataChannel');
// ...
remoteConnection.ondatachannel = (event) => {
receiveChannel = event.channel;
receiveChannel.onmessage = onReceiveMessage;
receiveChannel.onopen = onReceiveChannelStateChange;
receiveChannel.onclose = onReceiveChannelStateChange;
};
function onReceiveMessage(event) {
document.querySelector("textarea#send").value = event.data;
}
document.querySelector("button#send").onclick = () => {
var data = document.querySelector("textarea#send").value;
sendChannel.send(data);
};
Komunikacja odbywa się bezpośrednio między przeglądarkami, więc RTCDataChannel
może być znacznie szybsza niż WebSocket, nawet jeśli serwer przekazujący (TURN) jest wymagany, gdy nie udaje się wykonać dziurkowania, aby poradzić sobie z zaporami sieciowymi i NAT.
RTCDataChannel
jest dostępna w przeglądarkach Chrome, Safari, Firefox, Opera i Samsung Internet. Gra Cube Slam używa interfejsu API do komunikowania stanu gry. Możesz zagrać rolę przyjaciela lub niedźwiedzia. Innowacyjna platforma Sharefest umożliwiała udostępnianie plików za pomocą RTCDataChannel
, a peerCDN dawała możliwość zapoznania się z możliwościami WebRTC w zakresie dystrybucji treści peer-to-peer.
Więcej informacji o RTCDataChannel
znajdziesz w projektie specyfikacji protokołu IETF.
Bezpieczeństwo
Aplikacja do komunikacji w czasie rzeczywistym lub wtyczka mogą naruszać bezpieczeństwo na kilka sposobów. Na przykład:
- Niezaszyfrowane multimedia lub dane mogą zostać przechwycone między przeglądarkami lub między przeglądarką a serwerem.
- Aplikacja może nagrywać i rozpowszechniać filmy lub dźwięk bez wiedzy użytkownika.
- Złośliwe oprogramowanie lub wirusy mogą zostać zainstalowane wraz z pozornie nieszkodliwym wtyczką lub aplikacją.
WebRTC zawiera kilka funkcji, które zapobiegają tym problemom:
- Implementacje WebRTC korzystają z bezpiecznych protokołów, takich jak DTLS i SRTP.
- Szyfrowanie jest wymagane w przypadku wszystkich komponentów WebRTC, w tym mechanizmów sygnalizacji.
- WebRTC nie jest wtyczką. Jego komponenty działają w piaskownicy przeglądarki, a nie w osobnym procesie. Komponenty nie wymagają osobnej instalacji i są aktualizowane przy każdej aktualizacji przeglądarki.
- Dostęp do aparatu i mikrofonu musi być wyraźnie przyznany, a w przypadku włączonego aparatu lub mikrofonu musi być wyraźnie widoczny w interfejsie.
Ten artykuł nie zawiera pełnej dyskusji na temat zabezpieczeń mediów strumieniowych. Więcej informacji znajdziesz w proponowanej architekturze zabezpieczeń WebRTC opracowanej przez IETF.
Podsumowanie
Interfejsy API i standardy WebRTC mogą demokratyzować i decentralizować narzędzia do tworzenia treści i komunikacji, w tym telefonii, gier, produkcji filmów, tworzenia muzyki i gromadzenia wiadomości.
Trudno wyobrazić sobie bardziej rewolucyjną technologię.
Jak powiedział bloger Phil Edholm, „WebRTC i HTML5 mogą umożliwić tę samą przemianę komunikacji w czasie rzeczywistym, jaką pierwotna przeglądarka wprowadziła w przypadku informacji”.
Narzędzia dla programistów
- Statystyki WebRTC dotyczące bieżącej sesji znajdziesz tutaj:
- about://webrtc-internals w Chrome
- opera://webrtc-internals w Operze
- about:webrtc w Firefoksie
- Uwagi dotyczące interoperacyjności
- adapter.js to skrypt JavaScriptu dla WebRTC, który jest utrzymywany przez Google z pomocą społeczności WebRTC i zawiera abstrakcyjne prefiksy dostawców, różnice w przeglądarkach i zmiany specyfikacji.
- Aby dowiedzieć się więcej o procesach sygnalizacji WebRTC, sprawdź dane wyjściowe z pliku appr.tc w konsoli.
- Jeśli to wszystko jest zbyt dużo, możesz użyć ramy WebRTC lub nawet pełnej usługi WebRTC.
- Zawsze chętnie przyjmujemy raporty o błędach i prośby o dodanie funkcji:
Więcej informacji
- Prezentacja Justina Ubertiego na temat WebRTC na konferencji Google I/O 2012
- Alan B. Johnston i Daniel C. Burnett prowadzi stronę webrtcbook.com, na której można znaleźć trzecią edycję książki o WebRTC w wersji drukowanej i jako e-book.
- Witryna webrtc.org zawiera wszystkie informacje o WebRTC, w tym prezentacje, dokumentację i dyskusje.
- discuss-webrtc to grupa dyskusyjna Google poświęcona technicznym aspektom WebRTC.
- @webrtc
- Więcej informacji o przechodzeniu przez NAT, STUN, serwerach przekaźnikowych i zbieraniu kandydatów znajdziesz w dokumentacji Talk dla deweloperów Google.
- WebRTC w GitHubie
- Stack Overflow to dobre miejsce na szukanie odpowiedzi i zadawanie pytań na temat WebRTC.
Standardy i protokoły
- Projekt W3C WebRTC (edytowany)
- Projekt W3C: przechwytywanie i przesyłanie multimediów (znany też jako
getUserMedia
) - Statut grupy roboczej IETF
- IETF WebRTC Data Channel Protocol Draft
- Draft IETF JSEP
- Proponowany przez IETF standard ICE
- IETF RTCWEB Working Group Internet-Draft: Web Real-Time Communication Use-cases and Requirements
Podsumowanie obsługi WebRTC
Interfejsy MediaStream
i getUserMedia
API
- Chrome na komputerze w wersji 18.0.1008 lub nowszej; Chrome na Androida w wersji 29 lub nowszej
- Opera 18 lub nowsza; Opera na Androida 20 lub nowsza
- Opera 12, Opera Mobile 12 (oparte na silniku Presto)
- Firefox 17 lub nowsza
- Microsoft Edge w wersji 16 lub nowszej
- Safari w wersji 11.2 lub nowszej w systemie iOS oraz w wersji 11.1 lub nowszej w systemie macOS
- UC 11.8 lub nowsza na Androida
- Samsung Internet 4 lub nowsza
RTCPeerConnection
interfejs API
- Chrome na komputery w wersji 20 lub nowszej; Chrome na Androida w wersji 29 lub nowszej (bez flagi)
- Opera 18 lub nowsza (włączona domyślnie); Opera na Androida 20 lub nowsza (włączona domyślnie)
- Firefox 22 lub nowsza (włączona domyślnie)
- Microsoft Edge w wersji 16 lub nowszej
- Safari w wersji 11.2 lub nowszej w systemie iOS oraz w wersji 11.1 lub nowszej w systemie macOS
- Samsung Internet 4 lub nowsza
RTCDataChannel
interfejs API
- Wersja eksperymentalna w Chrome 25, ale bardziej stabilna (i z współdziałaniem z Firefoxem) w Chrome 26 i nowszych; Chrome na Androida 29 i nowszych.
- stabilna wersja (z współdziałaniem z Firefoxem) w Opera 18 lub nowszej; Opera na Androida 20 lub nowszej
- Firefox 22 lub nowsza (włączona domyślnie)
Więcej informacji o obsługiwaniu interfejsów API na różnych platformach, takich jak getUserMedia
i RTCPeerConnection
, znajdziesz na stronie caniuse.com i w dokumentacji stanu platformy Chrome.
Natywna wersja interfejsu API dla RTCPeerConnection
jest też dostępna w dokumentacji na stronie webrtc.org.