Jak stworzyć aplikację do streamingu wideo i na żywo z WebRTC?
Published: 2024-02-08 05:10:33

Czym jest strumieniowanie wideo WebRTC?
---------------------------------------

Strumieniowanie wideo WebRTC to darmowy i otwarty projekt, który umożliwia przeglądarkom internetowym i urządzeniom mobilnym, takim jak iOS i Android, komunikację w czasie rzeczywistym. Funkcjonalność ta umożliwia łatwą integrację funkcji aplikacji, takich jak wideokonferencje peer-to-peer, ze stroną internetową. Dzięki strumieniowaniu wideo WebRTC, czat wideo oparty na przeglądarce można szybko zaprojektować za pomocą HTML i JavaScript, bez konieczności stosowania kodu zaplecza. Jest to kluczowy element [angażowania odbiorców na żywo](https://www.pubnub.com/solutions/live-audience-engagement/) i rozwiązań do [współpracy z wieloma użytkownikami](https://www.pubnub.com/solutions/multiuser-collaboration/), poprawiający wrażenia użytkowników na platformach takich jak media społecznościowe, aplikacje do strumieniowego przesyłania wideo na żywo i sieci dostarczania treści. Adaptowalność WebRTC sprawia, że jest to niezbędne narzędzie do tworzenia aplikacji, obsługujące szeroką gamę aplikacji, od usług chmurowych Amazon po wideo na żądanie Netflix, platformę streamingową Twitch, Facebook Live i interaktywne funkcje w Hulu, Spotify i urządzeniach Apple.

![](https://www.pubnub.com/cdn/3prze68gbwl1/3zeNU3Nn3bvFIa3CxPAK0H/ac3b96f11d8b13ae8157150e39a4b910/webrtc-video-call-chatengine.jpg)

Jak działa strumieniowanie wideo WebRTC?
----------------------------------------

WebRTC umożliwia użytkownikom strumieniowe przesyłanie audio i wideo w trybie peer-to-peer w nowoczesnych przeglądarkach internetowych. Ta funkcja jest obsługiwana przez najnowsze wersje Chrome, FireFox, Edge, Safari i Opera na komputerach stacjonarnych, a także natywne przeglądarki internetowe iOS i Android. Jest to podstawa rozwiązań do [strumieniowego przesyłania danych](https://www.pubnub.com/solutions/data-streaming/) dostarczanych przez PubNub.

Uczynienie urządzenia użytkownika klientem WebRTC jest tak proste, jak zainicjowanie nowego obiektu `RTCPeerConnection()` w interfejsie JavaScript.

Architektura transmisji na żywo WebRTC
--------------------------------------

Czat wideo jest nawiązywany na dwóch lub więcej urządzeniach klienckich przy użyciu protokołu WebRTC. Połączenie można nawiązać w jednym z dwóch trybów. Pierwszy tryb to peer-to-peer, co oznacza, że pakiety audio i wideo są przesyłane strumieniowo bezpośrednio od klienta do klienta z [konfiguracją RTC](https://developer.mozilla.org/en-US/docs/Web/API/RTCConfiguration). Ta konfiguracja działa tak długo, jak oba urządzenia mają adres IP, który jest dostępny w publicznym Internecie.

Jednak poleganie na połączeniach peer-to-peer w przypadku czatów wideo i konferencji w przeglądarce nie jest rozsądne w aplikacjach produkcyjnych. Często zdarza się, że struktura Interactive Connectivity Establishment lub ICE nie nawiązuje połączenia między dwoma użytkownikami, gdy jeden lub obaj znajdują się za zaawansowanymi zabezpieczeniami sieci LAN.

Aby złagodzić ten problem, można ustawić konfigurację RTCC tak, aby najpierw próbować nawiązać połączenie peer-to-peer, a następnie powrócić do połączenia przekazywanego, jeśli peer-to-peer nie powiedzie się.

![](https://www.pubnub.com/cdn/3prze68gbwl1/asset-17suaysk1qa1jcu/afcb88a1d7f5aaaaebe8c91413347091/webrtc-p2p-stun-pubnub.png)

Jeśli publicznie dostępne adresy IP nie są opcją, połączenie WebRTC musi zostać nawiązane za pośrednictwem serwera TURN. Struktura ICE zdecyduje, czy jest to konieczne, gdy użytkownicy będą próbowali się połączyć.

Nie twórz serwera sygnalizacyjnego WebRTC do transmisji na żywo - użyj PubNub
-----------------------------------------------------------------------------

WebRTC pomija bardzo ważny element strumieniowania rozmów wideo. Klient musi korzystać z usługi sygnalizacyjnej, aby komunikować się ze swoim peerem lub peerami. PubNub pozwala deweloperowi w pełni i tanio zaimplementować funkcje takie jak usługa sygnalizacyjna WebRTC. Ułatwia to obszerna [dokumentacja](https://www.pubnub.com/docs) PubNub dotycząca konfigurowania konta i wysyłania/odbierania wiadomości.

### Przykłady przesyłania strumieniowego czatu wideo za pomocą WebRTC

Wiadomości te dotyczą zdarzeń takich jak:

-   Ja, Użytkownik A, chciałbym zadzwonić do Ciebie, Użytkownika B
    
-   Użytkownik A próbuje obecnie nawiązać połączenie z użytkownikiem B
    
-   Ja, użytkownik B, akceptuję połączenie Użytkownik A
    
-   Ja, użytkownik B, odrzucam połączenie Użytkownik A
    
-   Ja, użytkownik B, chciałbym zakończyć naszą rozmowę Użytkownik A
    
-   Ja, użytkownik A, chcę zakończyć połączenie Użytkownik B
    
-   Komunikatory tekstowe, takie jak Slack, Google Hangouts, Skype, Facebook Messenger itp.
    
-   Kodek audio/wideo sesji i dane dotyczące łączności użytkownika.
    

Komunikaty te są częścią **przepływu transakcji** sygnalizacyjnych, który jest opisany w [dokumentacji Mozilla Developer Network dla WebRTC](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Signaling_and_video_calling). Serwer sygnalizacyjny WebRTC jest pojęciem abstrakcyjnym. Wiele usług może stać się tym "serwerem sygnalizacyjnym", takim jak WebSockets, Socket.IO lub PubNub. Jeśli masz za zadanie stworzyć rozwiązanie w tym zakresie, w końcu zadasz sobie pytanie: Zbudować czy kupić?

### Dlaczego PubNub: Rozszerzenia logiczne, takie jak strumieniowanie wideo WebRTC jeden do wielu

PubNub pozwala deweloperowi takiemu jak ty w pełni i tanio wdrożyć usługę sygnalizacyjną WebRTC. [Biblioteka Open Source Web](https://github.com/stephenlb/webrtc-sdk) RTC wykorzystująca PubNub jest dostępna na GitHub. Poniższe rozwiązanie do strumieniowego przesyłania danych PubNub jest jednak jeszcze szybsze niż tworzenie za pomocą WebRTC SDK, ponieważ nasza platforma umożliwia szybkie i łatwe tworzenie aplikacji obsługujących strumieniowanie jeden do wielu w dowolnej skali.

Pakiet wspierany przez społeczność dla połączeń wideo WebRTC
------------------------------------------------------------

PubNub jest jak globalny CDN dla danych w czasie rzeczywistym. Programiści mogą korzystać z jego [IaaS](https://www.pubnub.com/learn/glossary/what-is-infrastructure-as-a-service-iaas/) do tworzenia wysokiej jakości platform streamingowych w czasie rzeczywistym, aplikacji mobilnych i wielu innych. Dostępne są zestawy SDK PubNub dla każdego języka programowania i urządzenia, umożliwiające niezawodne połączenia pub/sub, dostarczanie danych i kontrolowanie sieci; wszystko to jest możliwe w kilku linijkach kodu.

Samouczek aplikacji do strumieniowego przesyłania wideo WebRTC z wykorzystaniem Javascript, HTML, CSS
-----------------------------------------------------------------------------------------------------

W tym samouczku użyjemy JavaScript, HTML i CSS do zbudowania naszej aplikacji do czatu wideo. Jeśli jednak chcesz użyć nowoczesnego frameworka front-end, takiego jak Vue, [React](https://www.pubnub.com/docs/chat/sdks/messages/sending-messages) lub Angular, możesz sprawdzić zaktualizowaną [stronę z samouczkami PubNub](https://www.pubnub.com/blog/category/build/) lub [PubNub Chat Resource Center](https://www.pubnub.com/docs/chat/overview). Dysponujemy również rozbudowanym zespołem programistów, który służy konsultacjami.

Na początek możesz użyć [HTML](https://github.com/ajb413/pubnub-js-webrtc/blob/master/example/index.html) i [CSS](https://github.com/ajb413/pubnub-js-webrtc/blob/master/example/style.css) z mojego przykładowego projektu. Pliki te przedstawiają bardzo ogólny interfejs użytkownika aplikacji czatu wideo. Przykładowa aplikacja ma tylko 1 czat globalny i nie ma prywatnych czatów 1:1, chociaż są one łatwe do wdrożenia.

HTML aplikacji do strumieniowego przesyłania wideo WebRTC
---------------------------------------------------------

Otwórz plik **index.** html za pomocą ulubionego edytora tekstu . **Zastąp** znaczniki skryptów pod znacznikiem body pliku HTML tymi 2 skryptami CDN. Pozostaw trzeci znacznik skryptu, który odnosi się do **app.js**. Napiszemy ten plik razem.

```js
<script type="text/javascript" src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.32.0.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pubnub-js-webrtc@latest/dist/pubnub-js-webrtc.js"></script>
```

Następnym krokiem jest utworzenie własnego pliku app.js w tym samym katalogu co plik index.html. Powodem, dla którego musimy utworzyć nowy app.js jest to, że skrypt w moim przykładzie używa [Xirsys](https://xirsys.com/). Moje prywatne konto jest podłączone do mojego serwera Functions. Będziesz musiał utworzyć własny serwer zaplecza i konto, jeśli chcesz korzystać z dostawcy TURN, takiego jak Xirsys. Mój następny wpis na blogu będzie zawierał samouczek dotyczący tworzenia aplikacji WebRTC z TURN.

Skrypt app.js, który wspólnie napiszemy, będzie używał tylko darmowych połączeń peer-to-peer WebRTC. Jeśli spróbujesz wykonać połączenie wideo na żywo z 2 urządzeniami w tej samej sieci LAN, Twoja aplikacja będzie działać. Nie ma pewności, że połączenie wideo można nawiązać z klientami w oddzielnych sieciach (ze względu na zabezpieczenia NAT). Dlatego tak ważne jest dobre zrozumienie protokołów przesyłania strumieniowego.

### Aplikacja do strumieniowego przesyłania wideo WebRTC w javascript

Najpierw utworzymy odniesienia do wszystkich elementów DOM z pliku index.html. Gdy będziemy mogli odwoływać się do nich w naszym kodzie JavaScript, będziemy mogli manipulować nimi programowo.

```js
const chatInterface = document.getElementById('chat-interface');
const myVideoSample = document.getElementById('my-video-sample');
const myVideo = document.getElementById('my-video');
const remoteVideo = document.getElementById('remote-video');
const videoModal = document.getElementById('video-modal');
const closeVideoButton = document.getElementById('close-video');
const brokenMyVideo = document.getElementById('broken-my-video');
const brokenSampleVideo = document.getElementById('broken-sample-video');
const usernameModal = document.getElementById('username-input-modal');
const usernameInput = document.getElementById('username-input');
const joinButton = document.getElementById('join-button');
const callConfirmModal = document.getElementById('call-confirm-modal');
const callConfirmUsername = document.getElementById('call-confirm-username');
const yesCallButton = document.getElementById('yes-call');
const noCallButton = document.getElementById('no-call');
const incomingCallModal = document.getElementById('incoming-call-modal');
const callFromSpan = document.getElementById('call-from');
const acceptCallButton = document.getElementById('accept-call');
const rejectCallButton = document.getElementById('reject-call');
const onlineList = document.getElementById('online-list');
const chat = document.getElementById('chat');
const log = document.getElementById('log');
const messageInput = document.getElementById('message-input');
const submit = document.getElementById('submit');
```

Następnie dodamy kilka zmiennych, które przechowują nazwę klasy CSS, globalne informacje o aplikacji i informacje o konfiguracji WebRTC. W słowniku RTCConfiguration dodamy informacje o serwerach STUN i TURN dla wywołań WebRTC. Jest to kluczowy krok dla wysokiej jakości treści wideo w usłudze przesyłania strumieniowego.

```js
const hide = 'hide';
// PubNub Channel for sending/receiving global chat messages
//     also used for user presence with Presence
const globalChannel = 'global-channel';
let webRtcPhone;
let pubnub;
// An RTCConfiguration dictionary from the browser WebRTC API
// Add STUN and TURN server information here for WebRTC calling
const rtcConfig = {};
let username; // User's name in the app
let myAudioVideoStream; // Local audio and video stream
let noVideoTimeout; // Used to check if a video connection succeeded
const noVideoTimeoutMS = 5000; // Error alert if the video fails to connect
```

Teraz przejdziemy do części niezbędnego kodu klienta dla funkcjonalności pakietu WebRTC. W tym miejscu do gry wkracza aspekt czasu rzeczywistego platformy strumieniowania wideo.

```js
// Init the audio and video stream on this client
getLocalStream().then((localMediaStream) => {
    myAudioVideoStream = localMediaStream;
    myVideoSample.srcObject = myAudioVideoStream;
    myVideo.srcObject = myAudioVideoStream;
}).catch(() => {
    myVideo.classList.add(hide);
    myVideoSample.classList.add(hide);
    brokenMyVideo.classList.remove(hide);
    brokenSampleVideo.classList.remove(hide);
});
// Prompt the user for a username input
getLocalUserName().then((myUsername) => {
    username = myUsername;
    usernameModal.classList.add(hide);
    initWebRtcApp();
});
// Send a chat message when Enter key is pressed
messageInput.addEventListener('keydown', (event) => {
    if (event.keyCode === 13 && !event.shiftKey) {
        event.preventDefault();
        sendMessage();
        return;
    }
});
// Send a chat message when the submit button is clicked
submit.addEventListener('click', sendMessage);
const closeVideoEventHandler = (event) => {
    videoModal.classList.add(hide);
    chatInterface.classList.remove(hide);
    clearTimeout(noVideoTimeout);
    webRtcPhone.disconnect(); // disconnects the current phone call
}
// Register a disconnect event handler when the close video button is clicked
closeVideoButton.addEventListener('click', closeVideoEventHandler);
```

Nowy kod, który właśnie dodaliśmy:

-   Pyta przeglądarkę, czy może uzyskać dostęp do kamery internetowej i mikrofonu komputera, i przechowuje obiekt strumienia w zmiennej globalnej.
    
-   Pyta użytkownika o "nazwę użytkownika" w aplikacji przed zainicjowaniem części WebRTC aplikacji.
    
-   Rejestruje programy obsługi zdarzeń dla wiadomości czatu, takich jak kliknięcie przez użytkownika przycisku przesyłania lub naciśnięcie klawisza Enter.
    
-   Tworzy kolejną obsługę zdarzeń, gdy użytkownik zamyka czat wideo.
    

Następnie dodamy kod inicjalizacyjny dla części WebRTC aplikacji internetowej. W tej części inicjalizujemy naszą instancję PubNub z najnowszą wersją SDK 4.32.0.

```js
const initWebRtcApp = () => {
    // WebRTC phone object event for when the remote peer's video becomes available.
    const onPeerStream = (webRTCTrackEvent) => {
        console.log('Peer audio/video stream now available');
        const peerStream = webRTCTrackEvent.streams[0];
        window.peerStream = peerStream;
        remoteVideo.srcObject = peerStream;
    };
    // WebRTC phone object event for when a remote peer attempts to call you.
    const onIncomingCall = (fromUuid, callResponseCallback) => {
        let username = document.getElementById(fromUuid).children[1].innerText;
        incomingCall(username).then((acceptedCall) => {
            if (acceptedCall) {
                // End an already open call before opening a new one
                webRtcPhone.disconnect();
                videoModal.classList.remove(hide);
                chatInterface.classList.add(hide);
                noVideoTimeout = setTimeout(noVideo, noVideoTimeoutMS);
            }
            callResponseCallback({ acceptedCall });
        });
    };
    // WebRTC phone object event for when the remote peer responds to your call request.
    const onCallResponse = (acceptedCall) => {
        console.log('Call response: ', acceptedCall ? 'accepted' : 'rejected');
        if (acceptedCall) {
            videoModal.classList.remove(hide);
            chatInterface.classList.add(hide);
            noVideoTimeout = setTimeout(noVideo, noVideoTimeoutMS);
        }
    };
    // WebRTC phone object event for when a call disconnects or timeouts.
    const onDisconnect = () => {
        console.log('Call disconnected');
        videoModal.classList.add(hide);
        chatInterface.classList.remove(hide);
        clearTimeout(noVideoTimeout);
    };
    // Lists the online users in the UI and registers a call method to the click event
    //     When a user clicks a peer's name in the online list, the app calls that user.
    const addToOnlineUserList = (occupant) => {
        const userId = occupant.uuid;
        const name = occupant.state ? occupant.state.name : null;
        if (!name) return;
        const userListDomElement = createUserListItem(userId, name);
        const alreadyInList = document.getElementById(userId);
        const isMe = pubnub.getUUID() === userId;
        if (alreadyInList) {
            removeFromOnlineUserList(occupant.uuid);
        } 
        if (isMe) {
            return;
        }
        onlineList.appendChild(userListDomElement);
        userListDomElement.addEventListener('click', (event) => {
            const userToCall = userId;
            confirmCall(name).then((yesDoCall) => {
                if (yesDoCall) {
                    webRtcPhone.callUser(userToCall, {
                        myStream: myAudioVideoStream
                    });
                }
            });
        });
    }
    const removeFromOnlineUserList = (uuid) => {
        const div = document.getElementById(uuid);
        if (div) div.remove();
    };
    pubnub = new PubNub({
        publishKey : '_YOUR_PUBNUB_PUBLISH_API_KEY_HERE_',
        subscribeKey : '_YOUR_PUBNUB_SUBSCRIBE_API_KEY_HERE_'
    });
    // This PubNub listener powers the text chat and online user list population.
    pubnub.addListener({
        message: function(event) {
            // Render a global chat message in the UI
            if (event.channel === globalChannel) {
                renderMessage(event);
            }
        },
        status: function(statusEvent) {
            if (statusEvent.category === "PNConnectedCategory") {
                pubnub.setState({
                    state: {
                        name: username
                    },
                    channels: [globalChannel],
                    uuid: pubnub.getUUID()
                });
                pubnub.hereNow({
                    channels: [globalChannel],
                    includeUUIDs: true,
                    includeState: true
                },
                (status, response) => {
                    response.channels[globalChannel].occupants
                        .forEach(addToOnlineUserList);
                });
            }
        },
        presence: (status, response) => {
            if (status.error) {
                console.error(status.error);
            } else if (status.channel === globalChannel) {
                if (status.action === "join") {
                    addToOnlineUserList(status, response);
                } else if (status.action === "state-change") {
                    addToOnlineUserList(status, response);
                } else if (status.action === "leave") {
                    removeFromOnlineUserList(status.uuid);
                } else if (status.action === "timeout") {
                    removeFromOnlineUserList(response.uuid);
                }
            }
        }
    });
    pubnub.subscribe({
        channels: [globalChannel],
        withPresence: true
    });
    window.ismyuuid = pubnub.getUUID();
    // Disconnect PubNub before a user navigates away from the page
    window.onbeforeunload = (event) => {
        pubnub.unsubscribe({
            channels: [globalChannel]
        });
    };
    // WebRTC phone object configuration.
    let config = {
        rtcConfig,
        ignoreNonTurn: false,
        myStream: myAudioVideoStream,
        onPeerStream,   // is required
        onIncomingCall, // is required
        onCallResponse, // is required
        onDisconnect,   // is required
        pubnub          // is required
    };
    webRtcPhone = new WebRtcPhone(config);
};
```

W kodzie inicjalizacyjnym dla części WebRTC aplikacji internetowej dokonaliśmy pewnych aktualizacji, aby odzwierciedlić najnowsze funkcje oferowane przez PubNub. Jest to kluczowa część zapewnienia zgodności aplikacji do strumieniowego przesyłania wideo z najnowszymi trendami technologicznymi.

Kod, który właśnie dodaliśmy do app.js, jest wykonywany po wprowadzeniu przez użytkownika jego "nazwy użytkownika":

-   Deklaruje wszystkie programy obsługi zdarzeń wtyczki dla zdarzeń połączeń WebRTC.
    
-   Dodaje i usuwa elementy listy użytkowników online, gdy użytkownicy włączają się i wyłączają w aplikacji
    
-   Rejestruje program obsługi zdarzeń, aby nawiązać nowe połączenie wideo z użytkownikiem za każdym razem, gdy jego nazwa zostanie kliknięta w interfejsie użytkownika listy użytkowników.
    
-   Rejestruje obsługę zdarzeń w celu renderowania nowych wiadomości czatu za każdym razem, gdy jedna z nich zostanie wysłana na czat globalny, w czasie rzeczywistym.
    
-   Konfiguruje PubNub do wysyłania i nasłuchiwania wiadomości w czasie rzeczywistym za pomocą [wzorca komunikatów Pub/Sub](https://www.pubnub.com/products/pubnub-platform/).
    
-   Inicjalizuje pakiet WebRTC i przekazuje obiekt konfiguracyjny do instancji.
    

Zanim przejdziemy dalej, ważne jest, aby pamiętać, że musimy wstawić nasze bezpłatne klucze PubNub API do tej funkcji. Możemy uzyskać klucze na zawsze za darmo, korzystając z poniższego formularza rejestracyjnego. Klucze te są bezpłatne do 1 miliona transakcji miesięcznie, co jest świetnym rozwiązaniem dla hobbystów lub profesjonalnych aplikacji typu proof-of-concept.

Klucze API Pub/Sub klienta można wstawić do pliku app.js w obiekcie inicjalizacyjnym PubNub, jak widać we wcześniejszym fragmencie kodu.

```js
pubnub = new PubNub({
    publishKey : 'PUBLISH_KEY',
    subscribeKey : 'SUBSCRIBE_KEY',
    uuid: "UUID"
});
```

Musimy włączyć **funkcję Presence** w panelu administracyjnym PubNub. Podczas tworzenia zestawu kluczy PubNub funkcja obecności jest domyślnie wyłączona dla klucza. Możemy ją włączyć dla klucza, przechodząc do PubNub Admin [Dashboard](https://dashboard.pubnub.com/) i klikając przełącznik. Aby dowiedzieć się więcej o funkcji Presence i jej możliwościach, zapoznaj się z naszą [dokumentacją](https://www.pubnub.com/docs/general/presence/overview).

Przykładowa aplikacja wykorzystuje [obecność](https://www.pubnub.com/docs/general/presence/overview), aby pokazać, którzy użytkownicy są online w aplikacji. Używamy identyfikatora UUID użytkownika PubNub, aby zachować unikalne odniesienia do każdego użytkownika w aplikacji. Kiedy wykonujemy operację połączenia wideo WebRTC, używamy identyfikatora UUID, aby obaj użytkownicy mogli wyświetlić odpowiednią nazwę użytkownika w swoim interfejsie użytkownika.

Następnie będziemy potrzebować kilku metod narzędziowych do wykonywania funkcji specyficznych dla interfejsu użytkownika. Nie są one specyficzne dla wszystkich aplikacji WebRTC, są one przeznaczone tylko do uruchamiania tego konkretnego interfejsu użytkownika, który zaprojektowałem. Dodaj ten kod na dole pliku app.js.

```js
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// UI Render Functions
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function renderMessage(message) {
    const messageDomNode = createMessageHTML(message);
    log.append(messageDomNode);
    // Sort messages in chat log based on their timetoken (value of DOM id)
    sortNodeChildren(log, 'id');
    chat.scrollTop = chat.scrollHeight;
}
function incomingCall(name) {
    return new Promise((resolve) => {
        acceptCallButton.onclick = function() {
            incomingCallModal.classList.add(hide);
            resolve(true);
        }
        rejectCallButton.onclick = function() {
            incomingCallModal.classList.add(hide);
            resolve(false);
        }
        callFromSpan.innerHTML = name;
        incomingCallModal.classList.remove(hide);
    });
}
function confirmCall(name) {
    return new Promise((resolve) => {
        yesCallButton.onclick = function() {
            callConfirmModal.classList.add(hide);
            resolve(true);
        }
        noCallButton.onclick = function() {
            callConfirmModal.classList.add(hide);
            resolve(false);
        }
        callConfirmUsername.innerHTML = name;
        callConfirmModal.classList.remove(hide);
    });
}
function getLocalUserName() {
    return new Promise((resolve) => {
        usernameInput.focus();
        usernameInput.value = '';
        usernameInput.addEventListener('keyup', (event) => {
            const nameLength = usernameInput.value.length;
            if (nameLength > 0) {
                joinButton.classList.remove('disabled');
            } else {
                joinButton.classList.add('disabled');
            }
            if (event.keyCode === 13 && nameLength > 0) {
                resolve(usernameInput.value);
            }
        });
        joinButton.addEventListener('click', (event) => {
            const nameLength = usernameInput.value.length;
            if (nameLength > 0) {
                resolve(usernameInput.value);
            }
        });
    });
}
function getLocalStream() {
    return new Promise((resolve, reject) => {
        navigator.mediaDevices
        .getUserMedia({
            audio: true,
            video: true
        })
        .then((avStream) => {
            resolve(avStream);
        })
        .catch((err) => {
            alert('Cannot access local camera or microphone.');
            console.error(err);
            reject();
        });
    });
}
function createUserListItem(userId, name) {
    const div = document.createElement('div');
    div.id = userId;
    const img = document.createElement('img');
    img.src = './phone.png';
    const span = document.createElement('span');
    span.innerHTML = name;
    div.appendChild(img);
    div.appendChild(span);
    return div;
}
function createMessageHTML(messageEvent) {
    const text = messageEvent.message.text;
    const jsTime = parseInt(messageEvent.timetoken.substring(0,13));
    const dateString = new Date(jsTime).toLocaleString();
    const senderUuid = messageEvent.publisher;
    const senderName = senderUuid === pubnub.getUUID()
        ? username
        : document.getElementById(senderUuid).children[1].innerText;
    const div = document.createElement('div');
    const b = document.createElement('b');
    div.id = messageEvent.timetoken;
    b.innerHTML = `${senderName} (${dateString}): `;
    div.appendChild(b);
    div.innerHTML += text;
    return div;
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Utility Functions
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function sendMessage() {
    const messageToSend = messageInput.value.replace(/?
|/g, '');
    const trimmed = messageToSend.replace(/(\s)/g, '');
    if (trimmed.length > 0) {
        pubnub.publish({
            channel: globalChannel,
            message: {
                text: messageToSend
            }
        });
    }
    messageInput.value = '';
}
// Sorts sibling HTML elements based on an attribute value
function sortNodeChildren(parent, attribute) {
    const length = parent.children.length;
    for (let i = 0; i < length-1; i++) {
        if (parent.children[i+1][attribute] < parent.children[i][attribute]) {
            parent.children[i+1].parentNode
                .insertBefore(parent.children[i+1], parent.children[i]);
            i = -1;
        }
    }
}
function noVideo() {
    const message = 'No peer connection made.
' +
        'Try adding a TURN server to the WebRTC configuration.';
    if (remoteVideo.paused) {
        alert(message);
        closeVideoEventHandler();
    }
}
```

### **CSS aplikacji do strumieniowego przesyłania wideo WebRTC**

Potrzebujemy stylów CSS w naszej aplikacji, aby uzyskać ładny i przyjemny interfejs użytkownika. Plik index.html zawiera już odniesienie do pliku style.css, więc dodaj go do tego samego folderu. [Plik](https://github.com/ajb413/pubnub-js-webrtc/blob/master/example/style.css) style.css dla tej aplikacji WebRTC jest dostępny w repozytorium GitHub.

Gotowe! Teraz możesz wdrożyć swoje statyczne pliki internetowe front-end na platformie hostingowej, takiej jak WordPress lub [strony GitHub](https://pages.github.com/). Twoja aplikacja czatu WebRTC będzie dostępna do użytku przez każdego na świecie. Kod jest kompatybilny z urządzeniami mobilnymi, co oznacza, że najnowsze przeglądarki internetowe na iOS i Androida będą w stanie uruchomić aplikację do wideo twarzą w twarz!

**Pakiet streamingowy WebRTC FAQ**
----------------------------------

### **Czy pakiet WebRTC jest oficjalnie częścią PubNub?**

Nie. Jest to projekt open-source wspierany przez społeczność. Jeśli masz pytania lub potrzebujesz pomocy, skontaktuj się z [devrel@pubnub.com](mailto:devrel@pubnub.com). Jeśli chcesz zgłosić błąd, zrób to na [stronie GitHub Issues](https://github.com/ajb413/pubnub-js-webrtc/issues).

### **Czy PubNub przesyła strumieniowo dane audio lub wideo za pomocą WebRTC?**

Nie. PubNub bardzo dobrze współpracuje z WebRTC jako usługa sygnalizacyjna. Oznacza to, że PubNub sygnalizuje zdarzenia od klienta do klienta za pomocą komunikatów Pub/Sub. Zdarzenia te obejmują:

-   Ja, użytkownik A, chciałbym zadzwonić do ciebie, użytkownika B
    
-   Użytkownik A próbuje obecnie nawiązać połączenie z użytkownikiem B
    
-   Ja, użytkownik B, akceptuję połączenie Użytkownik A
    
-   Ja, użytkownik B, odrzucam połączenie Użytkownik A
    
-   Ja, użytkownik B, chciałbym zakończyć naszą rozmowę Użytkownik A
    
-   Ja, użytkownik A, chcę zakończyć połączenie Użytkownik B
    
-   Komunikatory tekstowe, takie jak Slack, Google Hangouts, Skype, Facebook Messenger itp.
    

### **Czy mogę nawiązać połączenie grupowe z więcej niż 2 uczestnikami przy użyciu WebRTC i PubNub?**

Połączenia grupowe są możliwe do opracowania przy użyciu WebRTC i PubNub, jednak obecny pakiet PubNub JS WebRTC może połączyć tylko 2 użytkowników w prywatnym połączeniu, a nie symulację obsługiwaną przez WebRTC od więcej niż 2 użytkowników. Społeczność może rozwinąć tę funkcję w przyszłości, ale na razie nie ma planów rozwoju.

**Pierwsze kroki z PubNub dla aplikacji WebRTC**
------------------------------------------------

Rozwój oprogramowania przy użyciu PubNub dla aplikacji do transmisji strumieniowej na żywo. Zapewnij niskie opóźnienia i koszty rozwoju, po prostu rejestrując bezpłatne konto i integrując nasze interfejsy API z aplikacją WebRTC. Szybko uzyskasz MVP swojej aplikacji do czatowania. Dzięki PubNub będziesz mieć dostęp do [wielu narzędzi i zasobów](https://www.pubnub.com/docs) które pomogą ci zbudować solidną i skalowalną aplikację do czatowania.

Aby rozpocząć, wykonaj poniższe kroki:

-   [Zarejestruj bezpłatne konto PubNub.](https://admin.pubnub.com/#/register)
    
-   [Postępuj zgodnie z](https://www.pubnub.com/tutorials/) krok po kroku, aby skonfigurować i zbudować aplikację czatu za pomocą PubNub SDK.
    
-   [Dodaj funkcje, takie jak mobilne powiadomienia push](https://www.pubnub.com/tutorials/) do aplikacji czatu na iOS lub Androida, postępując zgodnie ze [szczegółowego samouczka](https://www.pubnub.com/tutorials/).
    

[Odwiedź nasze Dokumenty, aby dowiedzieć się więcej o](https://www.pubnub.com/docs) tworzenia aplikacji czatu w czasie rzeczywistym.

Jak PubNub może ci pomóc?
=========================

Ten artykuł został pierwotnie opublikowany na [PubNub.com](https://www.pubnub.com/blog/integrating-video-calling-in-chat-with-webrtc-and-pubnub/)

Nasza platforma pomaga programistom tworzyć, dostarczać i zarządzać interaktywnością w czasie rzeczywistym dla aplikacji internetowych, aplikacji mobilnych i urządzeń IoT.

Fundamentem naszej platformy jest największa w branży i najbardziej skalowalna sieć przesyłania wiadomości w czasie rzeczywistym. Dzięki ponad 15 punktom obecności na całym świecie obsługującym 800 milionów aktywnych użytkowników miesięcznie i niezawodności na poziomie 99,999%, nigdy nie będziesz musiał martwić się o przestoje, limity współbieżności lub jakiekolwiek opóźnienia spowodowane skokami ruchu.

Poznaj PubNub
-------------

Sprawdź [Live Tour](https://www.pubnub.com/tour/introduction/), aby zrozumieć podstawowe koncepcje każdej aplikacji opartej na PubNub w mniej niż 5 minut.

Rozpocznij konfigurację
-----------------------

Załóż [konto](https://admin.pubnub.com/signup/) PubNub, aby uzyskać natychmiastowy i bezpłatny dostęp do kluczy PubNub.

Rozpocznij
----------

[Dokumenty](https://www.pubnub.com/docs) PubNub pozwolą Ci rozpocząć pracę, niezależnie od przypadku użycia lub [zestawu SDK](https://www.pubnub.com/docs).