Pierwsze kroki z połączeniami równorzędnymi

Połączenia równorzędne to część specyfikacji WebRTC, która obejmuje łącząc dwie aplikacje na różnych komputerach w celu komunikacji przez protokół peer-to-peer. Komunikacja między sobą może polegać na komunikacji wideo, audio lub dowolne dane binarne (w przypadku klientów obsługujących interfejs API RTCDataChannel). W aby ustalić, w jaki sposób można nawiązać współpracę, obaj klienci muszą przedstawić ICE Konfiguracja serwera. Jest to serwer STUN lub TURN, a jego rola to przedstawianie kandydatów ICE każdemu klientowi, które są następnie przekazywane do zdalnego w porównaniu z innymi wydawcami. Takie przekazywanie kandydatów z ICE jest powszechnie nazywane sygnalizowaniem.

Wysyłanie sygnałów

Specyfikacja WebRTC zawiera interfejsy API do komunikacji z ICE (internet) serwer połączenia), ale komponent sygnalizujący nie jest częścią . Sygnały są potrzebne, aby 2 równorzędne osoby mogły powiedzieć, jak powinny się połączyć. Zwykle do rozwiązania tego problemu używa się zwykłego internetowego interfejsu API opartego na protokole HTTP (np.REST). lub innym mechanizmem RPC), w którym aplikacje internetowe mogą przekazywać niezbędne informacje przed nawiązaniem połączenia z peerem.

Fragment kodu poniżej pokazuje, jak za pomocą tej fikcyjnej usługi sygnalizacji wysyłać i odbierać wiadomości w sposób asynchroniczny. Użyjemy go w pozostałej podanych w tym przewodniku.

// Set up an asynchronous communication channel that will be
// used during the peer connection setup
const signalingChannel = new SignalingChannel(remoteClientId);
signalingChannel.addEventListener('message', message => {
    // New message from remote client received
});

// Send an asynchronous message to the remote client
signalingChannel.send('Hello!');

Sygnalizowanie można zaimplementować na wiele różnych sposobów, a WebRTC nie preferuje żadnego konkretnego rozwiązania.

Inicjowanie połączeń równorzędnych

Każde połączenie równorzędne jest obsługiwane przez obiekt RTCPeerConnection. Konstruktor dla tej klasy przyjmuje pojedynczy obiekt RTCConfiguration jako parametr. Ten obiekt określa sposób konfiguracji połączenia z peerem i powinien zawierać informacje o serwerach ICE, które mają być używane.

Po utworzeniu RTCPeerConnection musimy utworzyć ofertę SDP lub w zależności od tego, czy dzwonimy do elementu równorzędnego, czy też go odbieramy. Gdy dostawca SDP została utworzona oferta lub odpowiedź, musi zostać wysłana do zdalnego peera za pomocą do innego kanału. Przekazywanie obiektów SDP do zdalnych połączeń jest nazywane sygnalizacją nie jest ujęte w specyfikacji WebRTC.

Aby zainicjować konfigurację połączenia z peerem po stronie wywołującego, tworzymy RTCPeerConnection, a następnie wywołaj createOffer(), by utworzyć RTCSessionDescription obiekt. Ten opis sesji jest ustawiony jako lokalny opis za pomocą setLocalDescription(), a następnie jest on przesyłany przez nasz sygnał kanału w stronę odbiorcy. Skonfigurowaliśmy też nasłuchujący sygnały, kanału, w którym odpowiedź na opis naszej sesji została otrzymana od po stronie odbiorcy.

async function makeCall() {
    const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]}
    const peerConnection = new RTCPeerConnection(configuration);
    signalingChannel.addEventListener('message', async message => {
        if (message.answer) {
            const remoteDesc = new RTCSessionDescription(message.answer);
            await peerConnection.setRemoteDescription(remoteDesc);
        }
    });
    const offer = await peerConnection.createOffer();
    await peerConnection.setLocalDescription(offer);
    signalingChannel.send({'offer': offer});
}

Czekamy na przychodzącą ofertę, zanim utworzymy RTCPeerConnection instancja. Następnie ustawiamy otrzymaną ofertę za pomocą setRemoteDescription() Następnie dzwonimy pod numer createAnswer(), aby utworzyć odpowiedź otrzymaną ofertę. Ta odpowiedź jest ustawiona jako opis lokalny za pomocą funkcji setLocalDescription(), a następnie został wysłany do rozmówcy przez nasz sygnalizowanie serwera.

const peerConnection = new RTCPeerConnection(configuration);
signalingChannel.addEventListener('message', async message => {
    if (message.offer) {
        peerConnection.setRemoteDescription(new RTCSessionDescription(message.offer));
        const answer = await peerConnection.createAnswer();
        await peerConnection.setLocalDescription(answer);
        signalingChannel.send({'answer': answer});
    }
});

Gdy 2 koleżanki utworzą opis sesji lokalnej i zdalnej, poznaj możliwości zdalnego peera. Nie oznacza to, że połączenie jest gotowy. Aby to zadziałało, musimy zebrać dane ICE kandydatów z każdego z nich i przekazują (przez kanał sygnału) innym w porównaniu z innymi wydawcami.

Kandydaci ICE

Zanim 2 osoby będą mogły komunikować się za pomocą WebRTC, muszą wymienić się informacje o połączeniach. Ponieważ warunki sieci mogą się różnić w zależności od wielu czynników do wykrycia potencjalnych kandydatów do połączenia się z innymi. Jest to usługa ICE. przy użyciu serwera STUN lub TURN. STUN to skrót od Session Traversal Narzędzia dla NAT i zwykle są używane pośrednio w większości aplikacji WebRTC.

TURN (Traversal Using Relay NAT) to bardziej zaawansowane rozwiązanie, które obejmuje protokoły STUN i większość komercyjnych usług opartych na WebRTC korzysta z serwera TURN budowania relacji między rówieśnikami. Interfejs WebRTC API obsługuje zarówno protokół STUN, i TURN, a dane te zbierane są pod szybszym określeniem hasła Internet: Nawiązywanie połączenia. Przy tworzeniu połączenia WebRTC co najmniej jeden serwer ICE w konfiguracji RTCPeerConnection obiekt.

Krople ICE

Po utworzeniu obiektu RTCPeerConnection podstawowa platforma używa metody udostępnia serwery ICE w celu zbierania kandydatów do instytucji łączności (ICE) ). Zdarzenie icegatheringstatechange w przypadku RTCPeerConnection sygnałów w jakim stanie jest zbiór danych ICE (new, gathering czy complete).

Można by poczekać na zakończenie zbierania danych przez ICE, jest zwykle dużo bardziej skuteczny, jeśli używasz „kosmetyku lodowego”. technika i transmisja z każdym kandydatem ICE do zdalnego peera. Dzięki temu znacznie skrócić czas konfiguracji połączenia z innymi wydawcami i umożliwić przesyłanie filmów zadzwoń, by zacząć z mniejszym opóźnieniem.

Aby zebrać kandydatów ICE, po prostu dodaj detektor zdarzenia icecandidate. Pole RTCPeerConnectionIceEvent emitowane przez ten detektor zawiera candidate reprezentującą nowego kandydata, który należy wysłać do zdalny element równorzędny (patrz Sygnały).

// Listen for local ICE candidates on the local RTCPeerConnection
peerConnection.addEventListener('icecandidate', event => {
    if (event.candidate) {
        signalingChannel.send({'new-ice-candidate': event.candidate});
    }
});

// Listen for remote ICE candidates and add them to the local RTCPeerConnection
signalingChannel.addEventListener('message', async message => {
    if (message.iceCandidate) {
        try {
            await peerConnection.addIceCandidate(message.iceCandidate);
        } catch (e) {
            console.error('Error adding received ice candidate', e);
        }
    }
});

Połączenie zostało nawiązane

Po otrzymaniu kandydatów z ICE należy się spodziewać, że stan pozostałych kandydatów stan połączenia zmieni się w stan połączenia. Aby to wykryć, dodajemy parametr słuchawka RTCPeerConnection, w której słuchamy przez: connectionstatechange zdarzeń.

// Listen for connectionstatechange on the local RTCPeerConnection
peerConnection.addEventListener('connectionstatechange', event => {
    if (peerConnection.connectionState === 'connected') {
        // Peers connected!
    }
});

Interfejs API RTCPeerConnection dokumentacja