Tehnologia WebRTC: chat audio și video în browser. Chat video P2P bazat pe WebRTC WebRTC de către un dezvoltator web

Majoritatea materialului pe WebRTC se concentrează pe nivelul aplicației de scriere a codului și nu contribuie la înțelegerea tehnologiei. Să încercăm să mergem mai adânc și să aflăm cum are loc conexiunea, care este descriptorul de sesiune și candidații, care sunt STUNși ÎNTOARCE Server.

WebRTC

Introducere

WebRTC este o tehnologie bazată pe browser care vă permite să conectați doi clienți pentru transmiterea datelor video. Principalele caracteristici sunt suportul intern pentru browser (nu este nevoie de tehnologii încorporate terță parte, cum ar fi adobe flash) și capacitatea de a conecta clienți fără a utiliza servere suplimentare - conexiune de la persoană la persoană(Mai departe, p2p).

Stabiliți o conexiune p2p- o sarcină destul de dificilă, deoarece computerele nu au întotdeauna public IP adrese, adică adrese de pe Internet. Datorită cantității mici IPv4 adresează (și din motive de securitate) a fost dezvoltat un mecanism NAT, care vă permite să creați rețele private, de exemplu, pentru uz casnic. Multe routere de acasă acceptă acum NATși datorită acestui fapt, toate dispozitivele de acasă au acces la Internet, deși furnizorii de internet oferă de obicei unul IP abordare. public IP Adresele sunt unice pe Internet, dar adresele private nu. Deci conectează-te p2p- dificil.

Pentru a înțelege mai bine acest lucru, luați în considerare trei situații: ambele noduri sunt în aceeași rețea (Imaginea 1), ambele noduri sunt în rețele diferite (unul în privat, celălalt în public) (Imaginea 2)și ambele noduri sunt în rețele private diferite cu același IP adrese (Figura 3).

Figura 1: Ambele noduri din aceeași rețea

Figura 2: Noduri pe diferite rețele (unul în privat, unul în public)

Figura 3: Noduri în rețele private diferite, dar cu adrese egale numeric

În figurile de mai sus, prima literă din notația cu două caractere indică tipul de nod (p = egal, r = router). În prima figură, situația este favorabilă: nodurile din rețeaua lor sunt complet identificate prin rețea IP adrese și, prin urmare, se pot conecta direct între ele. În a doua figură, avem două rețele diferite care au numere de noduri similare. Aici apar routerele (routere), care au două interfețe de rețea - în interiorul rețelei și în afara rețelei lor. Prin urmare au două IP adrese. Nodurile obișnuite au o singură interfață prin care pot comunica doar pe propria lor rețea. Dacă transmit date către cineva din afara rețelei lor, atunci numai cu ajutorul lui NATîn interiorul routerului (routerului) și, prin urmare, vizibil celorlalți sub IP adresa routerului este a lor extern IP abordare. Astfel, nodul p1 există interior IP = 192.168.0.200 și extern IP = 10.50.200.5 , ultima adresă fiind și externă tuturor celorlalte gazde din rețeaua sa. Situația este similară pentru nod p2. Prin urmare, conexiunea lor este imposibilă dacă doar lor internă (proprie) IP adrese. Puteți utiliza adrese externe, adică adrese ale routerelor, dar deoarece toate nodurile din aceeași rețea privată au aceeași adresă externă, acest lucru este destul de dificil. Această problemă este rezolvată prin mecanism NAT

Ce se va întâmpla dacă totuși decidem să conectăm nodurile prin adresele lor interne? Datele nu vor părăsi rețeaua. Pentru a spori efectul, vă puteți imagina situația prezentată în ultima figură - ambele noduri au aceleași adrese interne. Dacă le folosesc pentru a comunica, atunci fiecare nod va comunica cu el însuși.

WebRTC face față cu succes unor astfel de probleme folosind protocolul GHEAŢĂ, care, totuși, necesită utilizarea de servere suplimentare ( STUN, ÎNTOARCE). Toate acestea mai jos.

Două faze ale WebRTC

Pentru a conecta două noduri printr-un protocol WebRTC(sau pur și simplu RTC dacă două sunt conectate iPhone„a) trebuie luate niște pași preliminari pentru a stabili o conexiune. Aceasta este prima fază - stabilirea unei conexiuni. A doua fază este transmiterea datelor video.

Ar trebui spus imediat că, deși tehnologie WebRTC folosește o varietate de metode de comunicare în munca sa ( TCPși UDP) și are comutare flexibilă între ele, această tehnologie nu are un protocol pentru transmiterea datelor de conexiune. Nu este surprinzător, deoarece conectați două noduri p2p nu asa de usor. Prin urmare, este necesar să aveți câteva adiţional metoda de transfer de date, care nu are legătură cu WebRTC. Poate fi un transfer de socket, un protocol http, poate fi chiar un protocol SMTP sau Poșta Rusă. Acest mecanism de transmisie primar se numesc date semnal. Nu trebuie transferate prea multe informații. Toate datele sunt transmise ca text și sunt împărțite în două tipuri - SDPși Candidat de gheață. Primul tip este folosit pentru a stabili o conexiune logică, iar al doilea pentru una fizică. Mai multe despre asta mai târziu, dar pentru moment, este important să ne amintim asta WebRTC ne va oferi câteva informații care vor trebui transmise la un alt nod. Odată ce am transmis toate informațiile necesare, nodurile se vor putea conecta și nu va mai fi nevoie de ajutorul nostru. Deci mecanismul de semnalizare pe care trebuie să îl implementăm separat, va fi folosit numai atunci când este conectat, și nu va fi folosit la transmiterea datelor video.

Deci, să ne uităm la prima fază, faza de configurare a conexiunii. Este format din mai multe articole. Luați în considerare această fază mai întâi pentru nodul care inițiază conexiunea și apoi pentru cel în așteptare.

  • Inițiator (apelant - apelant):
    1. Oferă pentru a începe transmisia de date video (createOffer)
    2. Obținerea dvs SDP SDP)
    3. Obținerea dvs Candidat de gheață Candidat de gheață)
  • Apel în așteptare ( apelat):
    1. Obținerea unui flux media local (propriu) și setarea acestuia pentru transmisie (getUserMediaStream)
    2. Primiți o ofertă pentru a începe un transfer de date video și creați un răspuns (createAnswer)
    3. Obținerea dvs SDP obiect și trecerea acestuia prin mecanismul de semnalizare ( SDP)
    4. Obținerea dvs Candidat de gheață obiecte și transmiterea lor prin mecanismul de semnalizare ( Candidat de gheață)
    5. Primirea unui flux media de la distanță (străin) și afișarea lui pe ecran (onAddStream)

Singura diferență este în al doilea paragraf.

În ciuda complexității aparente a pașilor, există de fapt trei dintre ei: trimiterea propriului flux media (p. 1), setarea parametrilor de conectare (p. 2-4), primirea fluxului media altcuiva (p. 5). Cel mai dificil este al doilea pas, deoarece este format din două părți: stabilirea fizicși logic conexiuni. Primul indică cale, de-a lungul căruia trebuie să treacă pachetele pentru a ajunge de la un nod de rețea la altul. Al doilea indică parametri video/audio- ce calitate să folosești, ce codecuri să folosești.

Stadiul mental createOffer sau createRăspuns trebuie conectat la etapele de transfer SDPși Candidat de gheață obiecte.

Entități de bază

Fluxuri media (MediaStream)

Entitatea principală este fluxul media, adică fluxul de date video și audio, imagine și sunet. Există două tipuri de fluxuri media - locale și la distanță. Cel local primește date de la dispozitivele de intrare (cameră, microfon), iar cel la distanță prin rețea. Astfel, fiecare nod are atât un fir local, cât și unul la distanță. LA WebRTC există o interfață pentru fluxuri fluxul mediași există și o subinterfață LocalMediaStream special pentru thread-ul local. LA JavaScriptîl poți întâlni doar pe primul și dacă îl folosești lib jingle, atunci poate fi întâlnit și al doilea.

LA WebRTC există o ierarhie destul de confuză în cadrul firului. Fiecare flux poate consta din mai multe piese media ( pistă media), care la rândul său poate consta din mai multe canale media ( MediaChannel). Și pot exista, de asemenea, mai multe fluxuri media în sine.

Să considerăm totul în ordine. Pentru a face acest lucru, să ținem cont de un exemplu. Să spunem că vrem să transmitem nu doar un videoclip cu noi înșine, ci și un videoclip al mesei noastre, pe care se află o bucată de hârtie pe care urmează să scriem ceva. Vom avea nevoie de două videoclipuri (noi + tabel) și unul audio (noi). Este clar că noi și tabelul ar trebui să fim împărțiți în fire diferite, deoarece aceste date sunt probabil puțin dependente unele de altele. Prin urmare, vom avea două fluxul media‘a – unul pentru noi și unul pentru masă. Primul va conține atât date video, cât și audio, iar al doilea va conține doar video (Figura 4).

Figura 4: Două fluxuri media diferite. Unul pentru noi, unul pentru masa noastră

Este imediat clar că fluxul media ar trebui să includă cel puțin capacitatea de a conține date de diferite tipuri - video și audio. Acest lucru este luat în considerare în tehnologie și, prin urmare, fiecare tip de date este implementat printr-o pistă media. pistă media. Piesa media are o proprietate specială drăguț, care determină ce este în fața noastră - video sau audio (Figura 5)

Figura 5: Fluxurile media sunt formate din piese media

Cum va merge totul în program? Vom crea două fluxuri media. Apoi vom crea două piese video și o pistă audio. Să obținem acces la camere și un microfon. Să spunem fiecărei piese ce dispozitiv să folosească. Să adăugăm o pistă video și audio la primul flux media și o pistă video de la o altă cameră la al doilea flux media.

Dar cum distingem fluxurile media de la celălalt capăt al conexiunii? Pentru a face acest lucru, fiecare flux media are o proprietate eticheta– eticheta fluxului, numele acestuia (Figura 6). Piesele media au aceeași proprietate. Deși la prima vedere pare că videoclipul poate fi distins de sunet în alte moduri.

Figura 6: Fluxurile și melodiile media sunt identificate prin etichete

Deci, și dacă melodiile media pot fi identificate printr-o etichetă, atunci de ce trebuie să folosim două fluxuri media pentru exemplul nostru, în loc de unul? La urma urmei, puteți transfera un flux media și puteți utiliza diferite piese în el. Am ajuns la o proprietate importantă a fluxurilor media - ei sincroniza piese media. Diferitele fluxuri media nu sunt sincronizate între ele, dar în cadrul fiecărui flux media toate piesele jucat în același timp.

Astfel, dacă vrem ca cuvintele noastre, emoțiile noastre de pe față și bucata noastră de hârtie să fie redate în același timp, atunci merită să folosim un flux media. Dacă acest lucru nu este atât de important, atunci este mai profitabil să folosiți diferite fluxuri - imaginea va fi mai netedă.

Dacă o pistă trebuie dezactivată în timpul transmisiei, atunci puteți folosi proprietatea activat piese media.

În cele din urmă, ar trebui să vă gândiți la sunetul stereo. După cum știți, sunetul stereo este două sunete diferite. Și, de asemenea, trebuie trimise separat. Canalele sunt folosite pentru aceasta. MediaChannel. O pistă media audio poate avea mai multe canale (de exemplu, 6 dacă aveți nevoie de 5+1 audio). În interiorul piesei media, canale, desigur, de asemenea sincronizate. Pentru video, de obicei este folosit un singur canal, dar mai multe pot fi folosite, de exemplu, pentru suprapuneri publicitare.

A rezuma: folosim un flux media pentru a transmite date video și audio. În cadrul fiecărui flux media, datele sunt sincronizate. Putem folosi mai multe fluxuri media dacă nu avem nevoie de sincronizare. În fiecare flux media există două tipuri de piese media - pentru video și pentru audio. De obicei, nu există mai mult de două piese, dar pot fi mai multe dacă trebuie să transferați mai multe videoclipuri diferite (ale interlocutorului și a mesei sale). Fiecare piesă poate consta din mai multe canale, care este de obicei folosit doar pentru sunet stereo.

În cea mai simplă situație de chat video, vom avea un flux media local, care va consta din două piese - o pistă video și o pistă audio, fiecare dintre acestea fiind compusă dintr-un canal principal. Piesa video este responsabilă pentru cameră, pista audio este pentru microfon, iar fluxul media este containerul ambelor.

Descriptor de sesiune (SDP)

Calculatoarele diferite vor avea întotdeauna camere, microfoane, plăci video și alte echipamente diferite. Există multe opțiuni pe care le au. Toate acestea trebuie coordonate pentru transferul de date media între două noduri de rețea. WebRTC face acest lucru automat și creează un obiect special - handle-ul de sesiune SDP. Treceți acest obiect către alt nod și puteți trimite date media. Numai că nu există încă nicio legătură cu un alt nod.

Pentru aceasta, se folosește orice mecanism de semnalizare. SDP poate fi transmis chiar și prin prize, chiar și de către o persoană (spuneți-l unui alt nod prin telefon), chiar și prin Russian Post. Totul este foarte simplu - vi se va da un gata făcut SDPși trebuie trimis. Și la primire pe cealaltă parte - transfer la departament WebRTC. Gândul de sesiune este stocat ca text și îl puteți modifica în aplicațiile dvs., dar de obicei nu este necesar. De exemplu, atunci când conectați desktop↔telefon, uneori trebuie să forțați selectarea codecului audio dorit.

De obicei, atunci când stabiliți o conexiune, trebuie să specificați o adresă, de exemplu URL. Nu este nevoie de acest lucru aici, deoarece tu însuți vei trimite datele către destinație prin mecanismul de semnalizare. A indica WebRTC ce vrem să instalăm p2p conexiune trebuie să apelați funcția createOffer. După ce a apelat această funcție și i-ai dat un special sună din nou‘a va fi creat SDP obiect și a trecut la același sună din nou. Tot ceea ce vă este necesar este să transferați acest obiect prin rețea către un alt nod (interlocutor). După aceea, la celălalt capăt, datele vor veni prin mecanismul de semnalizare și anume acesta SDP un obiect. Acest descriptor de sesiune este străin acestui nod și, prin urmare, conține informații utile. Primirea acestui obiect este un semnal de pornire a conexiunii. Prin urmare, trebuie să fiți de acord cu acest lucru și să apelați funcția createAnswer. Este un analog complet al createOffer . Înapoi la dvs sună din nou va trece un descriptor de sesiune local și va trebui să fie transmis înapoi prin mecanismul de semnalizare.

Este de remarcat faptul că puteți apela funcția createAnswer numai după ce ați primit-o pe a altcuiva SDP obiect. De ce? Pentru că local SDP obiectul care va fi generat când este apelat createAnswer trebuie să se bazeze pe telecomandă SDP un obiect. Numai în acest caz este posibil să vă coordonați setările video cu setările interlocutorului. De asemenea, nu apelați createAnswer și createOffer până când nu este primit fluxul media local - nu vor avea nimic în care să scrie SDP un obiect .

Din moment ce în WebRTC se poate edita SDP obiect, apoi după obținerea unui handle local, acesta trebuie setat. Poate părea puțin ciudat să treacă WebRTC ce ne-a dat ea însăși, dar ăsta e protocolul. Când primiți un mâner de la distanță, trebuie să îl setați și pe acesta. Prin urmare, trebuie să instalați doi descriptori pe un singur nod - al dvs. și al altcuiva (adică, local și la distanță).

Dupa asa ceva strângeri de mână nodurile știu unul despre dorințele celuilalt. De exemplu, dacă nodul 1 acceptă codecuri Ași B, și nodul 2 acceptă codecuri Bși C, atunci, deoarece fiecare nod își cunoaște descriptorii proprii și ai altuia, ambele noduri vor alege un codec B(Figura 7). Logica de conectare este acum stabilită și fluxurile media pot fi transmise, dar există o altă problemă - nodurile sunt încă conectate doar printr-un mecanism de semnalizare.


Figura 7: Negocierea codecului

Candidați (candidați Ice)

Tehnologie WebRTCîncercând să ne confunde cu noua lui metodologie. La stabilirea unei conexiuni nu este specificată adresa nodului cu care doriți să vă conectați. Instalat mai întâi logic conexiune, nu fizic, deși întotdeauna s-a făcut invers. Dar acest lucru nu va părea ciudat, dacă nu uităm că folosim un mecanism de semnalizare terță parte.

Deci, conexiunea a fost deja stabilită (conexiune logică), dar nu există încă nicio modalitate ca nodurile rețelei să transmită date. Nu este chiar atât de simplu, dar să începem simplu. Lăsați nodurile să fie în aceeași rețea privată. După cum știm deja, se pot conecta cu ușurință unul la altul prin intermediul lor intern IP adrese (sau poate altele, dacă nu sunt utilizate TCP/IP).

Prin unele sună din nou'și WebRTC spune-ne Candidat de gheață obiecte. Ele vin, de asemenea, în formă textuală și, la fel ca în cazul descriptorilor de sesiune, trebuie doar să fie trimise prin mecanismul de semnalizare. Dacă descriptorul de sesiune conținea informații despre setările noastre la nivel de cameră și microfon, atunci candidații conțin informații despre locația noastră în rețea. Treceți-le la un alt nod și el se va putea conecta fizic la noi și, deoarece are deja un descriptor de sesiune, se poate conecta logic și datele vor „fluge”. Dacă nu uită să ne trimită obiectul său candidat, adică informații despre locul în care se află în rețea, atunci vom putea să ne conectăm cu el. Observăm aici încă o diferență față de interacțiunea clasică client-server. Comunicarea cu serverul HTTP are loc conform schemei cerere-răspuns, clientul trimite date către server, care le prelucrează și le trimite prin adresa specificată în pachetul de solicitare. LA WebRTC Trebuie să știu două adreseși conectați-le pe ambele părți.

Diferența față de mânerele de sesiune este că trebuie setate doar candidații la distanță. Editarea este interzisă aici și nu poate aduce niciun beneficiu. În unele implementări WebRTC candidații trebuie setat numai după ce au fost setate mânerele de sesiune.

Și de ce a existat un singur descriptor de sesiune, dar pot fi mulți candidați? Deoarece locația în rețea poate fi determinată nu numai de interiorul acesteia IP adresa, dar și adresa externă a routerului, și nu neapărat una, precum și adresele ÎNTOARCE servere. Restul paragrafului va fi dedicat unei discuții detaliate despre candidați și despre modul de conectare a nodurilor din diferite rețele private.

Deci, două noduri sunt în aceeași rețea (Figura 8). Cum să le identificăm? Prin utilizarea IP adrese. Nici o alta cale. Adevărat, puteți folosi în continuare mijloace de transport diferite ( TCPși UDP) și diferite porturi. Acestea sunt informațiile conținute în obiectul candidat - IP, PORT, TRANSPORT si altele. Să folosim, de exemplu UDP transport si 531 port.

Figura 8: Două noduri sunt în aceeași rețea

Atunci dacă ne aflăm într-un nod p1, apoi WebRTC ne va oferi un astfel de obiect candidat - . Acesta nu este un format exact, ci doar o diagramă. Dacă suntem într-un nod p2, atunci candidatul este . Prin mecanismul de semnalizare p1 va primi un candidat p2(adică locația nodului p2, anume a lui IPși PORT). Apoi p1 se poate conecta cu p2 direct. Mai corect, p1 va trimite datele la adresa 10.50.150.3:531 în speranţa că vor ajunge p2. Nu contează dacă această adresă aparține unui nod p2 sau vreun intermediar. Singurul lucru important este că datele vor fi trimise prin această adresă și pot ajunge p2.

Atâta timp cât nodurile sunt în aceeași rețea - totul este simplu și ușor - fiecare nod are un singur obiect candidat (însemnând întotdeauna propriul său, adică locația sa în rețea). Dar vor fi mult mai mulți candidați atunci când nodurile vor fi introduse diferit retelelor.

Să trecem la un caz mai complicat. Un nod va fi în spatele routerului (mai precis, în spatele NAT), iar al doilea nod va fi în aceeași rețea cu acest router (de exemplu, pe Internet) (Figura 9).

Figura 9: O gazdă în spatele NAT, alta nu

Acest caz are o soluție specială la problemă, pe care acum o luăm în considerare. Un router de acasă conține de obicei un tabel NAT. Acesta este un mecanism special conceput pentru a permite nodurilor din rețeaua privată a routerului să acceseze, de exemplu, site-uri web.

Să presupunem că serverul web este conectat direct la Internet, adică are un public IP* abordare. Să fie un nod p2. Nod p1(client web) trimite o solicitare la adresa 10.50.200.10 . În primul rând, datele merg către router r1, sau mai bine zis pe a lui interior interfata 192.168.0.1 . După aceea, routerul își amintește adresa sursă (adresa p1) și îl introduce într-un tabel special NAT, apoi schimbă adresa sursă cu propria ( p1 r1). Mai departe, conform extern interfață, routerul trimite date direct către serverul web p2. Serverul web prelucrează datele, generează un răspuns și le trimite înapoi. Se trimite la router r1, deoarece el este cel care se află în adresa de retur (routerul a schimbat adresa în propria sa). Routerul primește date, se uită la tabel NATși trimite datele către nod p1. Routerul acţionează ca un intermediar aici.

Dar ce se întâmplă dacă mai multe noduri din rețeaua internă accesează rețeaua externă în același timp? Cum va înțelege routerul cui să trimită răspunsul înapoi? Această problemă se rezolvă cu porturi. Când routerul înlocuiește adresa gazdă cu propria sa, înlocuiește și portul. Dacă două noduri accesează Internetul, atunci routerul își înlocuiește porturile sursă cu variat. Apoi, când pachetul de la serverul web revine la router, routerul va înțelege prin portul căruia i-a fost alocat acest pachet. Un exemplu este mai jos.

Înapoi la Tehnologie WebRTC, sau mai degrabă, la partea sa care folosește GHEAŢĂ protocol (deci Gheaţă candidați). Nod p2 are un candidat (locația sa în rețea - 10.50.200.10 ), și nodul p1, care se află în spatele unui router cu NAT, va avea doi candidați - local ( 192.168.0.200 ) și router candidat ( 10.50.200.5 ). Primul nu este util, dar este totuși generat, din moment ce WebRTC nu știe încă nimic despre gazda la distanță - poate fi sau nu în aceeași rețea. Al doilea candidat va veni la îndemână și, după cum știm deja, portul va juca un rol important (pentru a trece NAT).

Intrare la tabel NAT generate numai atunci când datele ies din rețeaua internă. Prin urmare, nodul p1 trebuie mai întâi să transmită datele și abia după aceea datele nodului p2 poate ajunge la nod p1.

La practică ambele noduri va fi în urmă NAT. Pentru a crea o intrare într-un tabel NAT fiecare router, nodurile trebuie să trimită ceva către nodul de la distanță, dar de data aceasta nici primul nu poate ajunge la al doilea și nici invers. Acest lucru se datorează faptului că nodurile nu își cunosc exteriorul IP adrese, iar trimiterea datelor către adrese interne este inutilă.

Cu toate acestea, dacă adresele externe sunt cunoscute, atunci conexiunea se va stabili cu ușurință. Dacă primul nod trimite date către routerul celui de-al doilea nod, atunci routerul le va ignora, deoarece tabelul său NATîn timp ce este gol. Cu toate acestea, în routerul primului nod din tabel NAT era nevoie de o înregistrare. Dacă acum al doilea nod trimite date către routerul primului nod, atunci routerul le va transmite cu succes către primul nod. Acum masa NAT al doilea router are datele de care ai nevoie.

Problema este că pentru a-ți cunoaște exteriorul IP adresa, aveți nevoie de un nod situat într-o rețea comună. Pentru a rezolva această problemă, sunt folosite servere suplimentare care sunt conectate direct la Internet. Cu ajutorul lor, sunt create și înregistrările prețuite din tabel. NAT.

Servere STUN și TURN

La inițializare WebRTC disponibil STUNși ÎNTOARCE servere, la care ne vom referi ca GHEAŢĂ servere. Dacă serverele nu sunt specificate, atunci numai nodurile din aceeași rețea (conectate la aceasta fără NAT). Trebuie remarcat imediat că pt 3g-trebuie folosite rețele ÎNTOARCE servere.

STUN Server este pur și simplu un server de pe Internet care returnează o adresă de retur, adică adresa gazdei expeditorului. Nodul din spatele routerului accesează STUN server pe care să îl parcurgeți NAT. Pachetul la care a venit STUN server, conține adresa sursă - adresa routerului, adică adresa externă a nodului nostru. Această adresă STUN server și trimite înapoi. Astfel, nodul își capătă exteriorul IP adresa si portul prin care este accesibil din retea. Mai departe, WebRTC folosind această adresă se creează un candidat suplimentar (adresa ruterului extern și port). Acum în tabel NAT routerul are o intrare care trece pachetele trimise către router pe portul necesar către nodul nostru.

Să ne uităm la acest proces cu un exemplu.

Exemplu (operare server STUN)

STUN serverul va fi notat cu s1. Router, ca înainte, prin r1, iar nodul prin p1. De asemenea, va trebui să urmați tabelul NAT- să-l notăm ca r1_nat. Mai mult, acest tabel conține de obicei multe intrări de la diferite noduri de subrețea - acestea nu vor fi date.

Deci, la început avem o masă goală r1_nat.

Tabelul 2: Antetul pachetului

Nod p1 trimite acest pachet către router r1(indiferent cum, diferite tehnologii pot fi utilizate în diferite subrețele). Routerul trebuie să înlocuiască adresa sursă src IP, deoarece adresa specificată în pachet cu siguranță nu este potrivită pentru subrețeaua externă, în plus, adresele din acest interval sunt rezervate și nici o singură adresă de pe Internet nu are o astfel de adresă. Routerul face o înlocuire în pachet și creează o nouă intrare în tabelul său r1_nat. Pentru a face acest lucru, trebuie să vină cu un număr de port. Amintiți-vă că, deoarece mai multe noduri dintr-o subrețea pot accesa o rețea externă, atunci în tabel NAT trebuie stocate informații suplimentare, astfel încât routerul să poată determina pentru care dintre aceste mai multe gazde este destinat pachetul de returnare de la server. Lasă routerul să vină cu un port 888 .

Antetul pachetului modificat:

Tabelul 4: Tabelul NAT a fost actualizat cu o nouă intrare

Aici IP adresa și portul pentru subrețea sunt exact aceleași cu pachetul original. Într-adevăr, la postback, trebuie să avem o modalitate de a le restaura complet. IP adresa pentru reteaua externa este adresa routerului, iar portul s-a schimbat in cel inventat de router.

Portul real către care nodul p1 acceptă o conexiune - aceasta, desigur, 35777 , dar serverul trimite date către fictiv port 888 , care va fi schimbat de router în cel real 35777 .

Deci, routerul a schimbat adresa sursă și portul din antetul pachetului și a adăugat o intrare în tabel NAT. Acum pachetul este trimis prin rețea către server, adică către nod s1. la intrare, s1 are acest pachet:

src IP Src PORT Dest IP PORT DEST
10.50.200.5 888 12.62.100.200 6000

Tabelul 5: Serverul STUN a primit un pachet

Total STUN serverul stie ca a primit un pachet de la adresa 10.50.200.5:888 . Acum serverul trimite această adresă înapoi. Merită să ne oprim aici și să revedem ceea ce tocmai am considerat. Tabelele de mai sus fac parte din antet pachet, deloc din el conţinut. Nu am vorbit despre conținut, deoarece nu este atât de important - este cumva descris în protocol STUN. Acum vom lua în considerare pe lângă titlu și conținutul. Va fi simplu și va conține adresa routerului - 10.50.200.5:888 deși am luat-o de la antet pachet. Acest lucru nu se face des, de obicei protocoalelor nu le pasă de informațiile despre adresele nodurilor, important este doar ca pachetele să fie livrate la destinație. Aici luăm în considerare un protocol care stabilește o cale între două noduri.

Deci acum avem un al doilea lot care merge în direcția opusă:

Tabelul 7: Serverul STUN trimite un pachet cu acest conținut

În continuare, pachetul călătorește prin rețea până când ajunge la interfața externă a routerului r1. Routerul înțelege că pachetul nu este destinat lui. Cum înțelege el? Acesta poate fi găsit doar de port. Port 888 el nu folosește în scopuri personale, ci folosește pentru mecanism NAT. Prin urmare, routerul se uită în acest tabel. Uită-te la coloană PORT externși caută un șir care se potrivește PORT DEST din pachetul primit, adică 888 .

IP intern PORT intern IP extern PORT extern
192.168.0.200 35777 10.50.200.5 888

Tabelul 8: Tabelul NAT

Suntem norocoși că există o astfel de linie. Dacă nu ar avea noroc, atunci pachetul ar fi pur și simplu aruncat. Acum trebuie să înțelegeți care dintre nodurile de subrețea ar trebui să trimită acest pachet. Să nu ne grăbim, să recapitulăm importanța porturilor în acest mecanism. În același timp, două noduri de pe subrețea ar putea trimite cereri către rețeaua externă. Apoi, dacă pentru primul nod routerul a venit cu un port 888 , apoi pentru al doilea ar veni cu un port 889 . Să presupunem că s-a întâmplat asta, adică tabelul r1_nat arata asa:

Tabelul 10: Adresa receptorului de falsificare a routerului

src IP Src PORT Dest IP PORT DEST
12.62.100.200 6000 192.168.0.200 35777

Tabelul 11: Routerul a schimbat adresa receptorului

Pachetul ajunge cu succes la nod p1și uitându-se la conținutul pachetului, nodul învață despre exteriorul acestuia IP adresa, adică adresa routerului din rețeaua externă. De asemenea, cunoaște portul prin care trece routerul NAT.

Ce urmeaza? La ce folosesc toate astea? Beneficiul este o intrare în tabel r1_nat. Dacă acum cineva va trimite la router r1 pachet port 888 , apoi routerul va redirecționa acest pachet către gazdă p1. Astfel, a fost creat un mic pasaj îngust către nodul ascuns p1.

Din exemplul de mai sus, vă puteți face o idee despre cum funcționează. NATși esență STUN Server. În general, mecanismul GHEAŢĂși STUN/TURN serverele au ca scop doar depășirea restricțiilor NAT.

Pot exista mai multe routere între nod și server, dar mai multe. În acest caz, nodul va primi adresa router-ului care este primul care intră în aceeași rețea ca și serverul. Cu alte cuvinte, obținem adresa routerului la care este conectat STUN Server. Pentru p2p comunicarea este exact ceea ce avem nevoie, dacă nu uităm faptul că în fiecare router linia de care avem nevoie va fi adăugată la tabel NAT. Așa că drumul înapoi va fi din nou la fel de lin.

ÎNTOARCE serverul este îmbunătățit STUN Server. Din aceasta rezultă imediat că oricare ÎNTOARCE serverul poate funcționa și cum STUN Server. Cu toate acestea, există și beneficii. În cazul în care un p2p comunicarea nu este posibilă (ca în 3g rețele), apoi serverul trece în modul repetitor ( releu), adică funcționează ca intermediar. Desigur, despre orice p2p atunci nu este o întrebare, ci în afara cadrului mecanismului GHEAŢĂ nodurile cred că comunică direct.

În ce cazuri este necesar ÎNTOARCE Server? De ce nu este suficient STUN servere? Faptul este că există mai multe tipuri NAT. Îl înlocuiesc pe același IP adresa și portul, dar unele dintre ele au încorporată protecție suplimentară împotriva „falsificării”. De exemplu, în simetric masa NATÎncă 2 parametri sunt salvați - IPși portul gazdei de la distanță. Un pachet din rețeaua externă trece prin NAT către rețeaua internă numai dacă adresa sursă și portul se potrivesc cu cele înregistrate în tabel. Prin urmare, focalizarea STUN serverul eșuează - tabel NAT stochează adresa și portul STUN server și când routerul primește un pachet de la WebRTC interlocutor, îl aruncă, deoarece este „falsificat”. El nu a venit din STUN Server.

În acest fel ÎNTOARCE este nevoie de un server când ambii interlocutori sunt în urmă simetric NAT(fiecare pentru el).

Rezumat scurt

Iată câteva afirmații despre entități WebRTC care trebuie ținut mereu în minte. Ele sunt descrise în detaliu mai sus. Dacă vreuna dintre afirmații nu vi se pare complet clară, recitiți paragrafele relevante.

  • fluxul media
    • Datele video și audio sunt împachetate în fluxuri media
    • Fluxurile media sincronizează melodiile media care alcătuiesc
    • Diferitele fluxuri media nu sunt sincronizate
    • Fluxurile media pot fi locale și la distanță, o cameră și un microfon sunt de obicei conectate la cel local, cele la distanță primesc date din rețea în formă criptată
    • Există două tipuri de piese media - pentru video și pentru audio.
    • Piesele media au capacitatea de a activa/dezactiva
    • Piesele media sunt formate din canale media
    • Piesele media sincronizează canalele media care alcătuiesc
    • Fluxurile media și melodiile media au etichete prin care pot fi distinse
  • Mânerul de sesiune
    • Descriptorul de sesiune este folosit pentru a conecta logic două noduri de rețea
    • Descriptorul de sesiune stochează informații despre metodele de codificare disponibile pentru datele video și audio.
    • WebRTC folosește un mecanism de semnalizare extern - sarcina de a transmite descriptori de sesiune ( sdp) cade asupra cererii
    • Mecanismul de conectare logică constă din două etape - o propunere ( oferi) și răspuns ( Răspuns)
    • Generarea descriptorului de sesiune nu este posibilă fără utilizarea unui flux media local în cazul unei oferte ( oferi) și nu este posibil fără utilizarea unui descriptor de sesiune la distanță în cazul unui răspuns ( Răspuns)
    • Descriptorul rezultat trebuie dat implementării WebRTC, și nu contează dacă acest handle este obținut de la distanță sau local din aceeași implementare WebRTC
    • Este posibil să editați ușor descriptorul de sesiune
  • Candidați
    • Candidat ( Candidat de gheață) este adresa nodului din rețea
    • Adresa nodului poate fi propria dvs. sau poate fi adresa unui router sau ÎNTOARCE servere
    • Întotdeauna sunt mulți candidați
    • Candidatul este format din IP adresa, portul si tipul de transport ( TCP sau UDP)
    • Candidații sunt folosiți pentru a stabili o conexiune fizică între două noduri dintr-o rețea
    • De asemenea, candidații trebuie să fie trimiși prin mecanismul de semnalizare
    • De asemenea, candidații trebuie să treacă implementările WebRTC, dar numai la distanță
    • În unele implementări WebRTC Candidații pot fi promovați numai după ce a fost setat descriptorul de sesiune
  • STUN/TURN/ICE/NAT
    • NAT– un mecanism pentru asigurarea accesului la o rețea externă
    • Routerele de acasă suportă o masă specială NAT
    • Routerul înlocuiește adresele din pachete - adresa sursă cu propria sa, dacă pachetul merge la rețeaua externă, iar adresa de destinație cu adresa gazdă în rețeaua internă, dacă pachetul a venit din rețeaua externă
    • Pentru a oferi acces multicanal la o rețea externă NAT folosește porturi
    • GHEAŢĂ- mecanism de bypass NAT
    • STUNși ÎNTOARCE servere - servere de ajutor pentru ocolire NAT
    • STUN serverul vă permite să creați intrările necesare în tabel NAT, și returnează, de asemenea, adresa externă a nodului
    • ÎNTOARCE serverul generalizează STUN mecanism și îl face să funcționeze mereu
    • În cele mai rele cazuri ÎNTOARCE serverul este folosit ca intermediar ( releu), acesta este p2p se transformă într-o conexiune client-server-client.

Utilizatorii de internet europeni sunt împărțiți în două părți: conform unui sondaj al Institutului pentru Analiza Opiniei Publice din Allenbach (Germania), Skype, sistemele de chat și de mesagerie instant au devenit parte integrantă a vieții de zi cu zi pentru 16,5 milioane de adulți și copii, 9 milioane folosesc aceste servicii de la caz la caz, iar 28 de milioane nu le ating.

Situația se poate schimba, deoarece acum Firefox este integrat tehnologie de comunicare în timp real (WebRTC), precum și clientul însuși. Pornirea unui chat audio și video nu este acum mai dificilă decât deschiderea unui site web. Servicii precum Facebook și Skype, pe de altă parte, se bazează pe soluții care folosesc un client separat și creează un cont.

WebRTC nu este doar ușor de utilizat. Această metodă vă permite chiar să setați conexiune directă între două browsere. În acest fel, datele audio și video nu trec printr-un server unde poate apărea congestie sau unde administratorul nu este deosebit de sensibil la confidențialitate sau protecția datelor. Cu o conexiune directă, WebRTC nu necesită înregistrare sau un cont la niciun serviciu.

Pentru a începe o conversație, trebuie doar să urmați linkul. Comunicarea rămâne privată deoarece fluxul de date este criptat. Comunicarea în timp real prin browser, Google a început să se implice activ în 2011, când a publicat codul sursă al implementării sale WebRTC.

La scurt timp după aceea, Chrome și Firefox și-au primit propriile motoare WebRTC. În prezent, versiunile lor mobile sunt echipate atât cu această tehnologie, cât și cu motorul WebView 3.6 instalat cu Android 5.0, care este folosit de aplicații.

Pentru comunicarea în timp real, interfețele JavaScript corespunzătoare trebuie implementate în vizualizatorul web. Cu GetUserMedia, software-ul permite capturarea din surse audio și video, adică webcam și microfon. RTCPeerConnection este responsabil pentru stabilirea conexiunii, precum și pentru comunicarea în sine.

În paralel cu integrarea browserului, grupul de lucru World Wide Web Consortium (W3C) a promovat procesul de standardizare WebRTC. Ar trebui finalizat în 2015.

WebRTC se mulțumește cu puțin

Utilizarea serviciului WebRTC nu necesită multe resurse, deoarece serverul conectează doar prietenii. Stabilirea unei conexiuni nu este, de asemenea, deosebit de dificilă. În primul rând, browserul semnalează serverului WebRTC că intenționează să inițieze un apel. Primește o legătură HTTPS de la server - conexiunea este criptată. Utilizatorul trimite acest link interlocutorului său. Browserul cere apoi utilizatorului permisiunea de a accesa camera web și microfon.

Pentru a stabili o conexiune directă de streaming cu cealaltă parte, browserul primește adresa sa IP și datele de configurare de la serviciul WebRTC. Browserul web al prietenului face același lucru.

Pentru ca conexiunea de streaming să funcționeze fără probleme și de bună calitate, trei motoare funcționează în browser. Două dintre ele optimizează și comprimă datele audio și video, al treilea este responsabil de transportul lor. Trimite date prin Protocolul SRTP(Secure Real-time Transport Protocol), care permite streaming criptat în timp real.

Dacă o conexiune directă eșuează, WebRTC caută o altă cale. De exemplu, acest lucru se întâmplă atunci când setările de rețea împiedică serverul STUN să poată raporta adresa IP. Standardul WebRTC prevede că în acest caz conversația va avea loc, dar cu includerea intermediară a serverului TURN (Traversal Using Relays around NAT). Deci, pe site-ul netscan.co, puteți verifica dacă WebRTC este implementat pe computer și cu accesul dvs. la Web.

Cum se face legătura

Mai întâi trebuie să înregistrați o conversație (1). Serviciul WebRTC oferă o legătură care trebuie trimisă interlocutorului. Browserul, folosind STUNserver, află propria sa adresă IP (2), o trimite către serviciu și primește IP-ul partenerului pentru a stabili o conexiune directă (3). Dacă STUN eșuează, conversația este redirecționată folosind serverul TURN (4).

Comunicarea folosind tehnologia WebRTC în browser este lansată folosind codul JavaScript. După aceea, trei motoare sunt responsabile de comunicare: motoarele de voce și video colectează date multimedia de la camera web și microfon, iar motorul de transport combină informațiile și trimite fluxul în formă criptată folosind Secure Real-time Protocol (SRTP).

Ce browsere funcționează cu WebRTC

Chrome și Firefox sunt echipate cu un motor WebRTC care utilizează servicii precum talky.io. Browserul Mozilla poate funcționa direct cu propriul client.

Google și Mozilla continuă să dezvolte ideea comunicării în timp real: Chrome poate găzdui o conferință WebRTC cu mai mulți participanți, iar noul client Hello în Firefox este dezvoltat cu ajutorul unei subsidiare a gigantului de telecomunicații Telefonica. Apple rămâne deocamdată pe margine, nu ar trebui să vă așteptați încă la WebRTC în Safari. Cu toate acestea, există o mulțime de aplicații și plugin-uri alternative iOS pentru Safari.

Microsoft urmează un curs ușor diferit. În calitate de proprietar al serviciului competitiv Skype, această companie nu va capitula atât de ușor în fața WebRTC. În schimb, Microsoft dezvoltă o tehnologie numită ORTC (Object Real-Time Communications) pentru Internet Explorer.

Diferențele față de WebRTC, cum ar fi diferite codecuri și protocoale pentru stabilirea contactului cu serverul, sunt minore și, în timp, cel mai probabil, vor deveni în plus față de standardul WebRTC, care va include aceste diferențe. Astfel, doar Apple rămâne în urmă - ca de obicei.

O fotografie: Companii de productie; goodluz/Photolia.com

Tehnologiile de apelare din browser sunt vechi de mulți ani: Java, ActiveX, Adobe Flash... În ultimii ani, a devenit clar că plug-in-urile și mașinile virtuale lăsate nu strălucesc de comoditate (de ce ar trebui să instalez ceva la toate?) și, cel mai important, securitatea. Ce să fac? Există o ieșire!

Până de curând, pe rețelele IP au fost folosite mai multe protocoale pentru telefonie IP sau video: SIP, cel mai comun protocol care iese din scenă, H.323 și MGCP, Jabber/Jingle (utilizat în Gtalk), Adobe RTMP* semi-deschis. și, desigur, Skype închis. Proiectul WebRTC, inițiat de Google, încearcă să transforme lumea IP și a telefoniei web, făcând ca toate telefoanele soft, inclusiv Skype, să fie învechite. WebRTC nu doar implementează toate capabilitățile de comunicare direct în interiorul browserului, care acum este instalat pe aproape fiecare dispozitiv, ci încearcă simultan să rezolve o sarcină mai generală de comunicare între utilizatorii browserului (schimb de date diverse, difuzare pe ecran, colaborare cu documente și mult mai mult).

WebRTC de la un dezvoltator web

Din punctul de vedere al unui dezvoltator web, WebRTC constă din două părți principale:

  • gestionarea fluxurilor media din resursele locale (cameră, microfon sau ecranul computerului local) este implementată prin metoda navigator.getUserMedia, care returnează un obiect MediaStream;
  • comunicații peer-to-peer între dispozitive care generează fluxuri media, inclusiv definirea metodelor de comunicare și transmiterea lor directă - obiecte RTCPeerConnection (pentru trimiterea și primirea fluxurilor audio și video) și RTCDataChannel (pentru trimiterea și primirea datelor din browser).

Ce facem?

Ne vom da seama cum să organizăm cel mai simplu chat video multiplayer între browsere bazat pe WebRTC folosind socket-uri web. Să începem să experimentăm în Chrome/Chromium, ca fiind cele mai avansate browsere în ceea ce privește WebRTC, deși Firefox 22, lansat pe 24 iunie, aproape i-a prins din urmă. Trebuie spus că standardul nu a fost încă adoptat, iar API-ul se poate schimba de la o versiune la alta. Toate exemplele au fost testate în Chromium 28. Pentru simplitate, nu vom monitoriza curățenia codului și compatibilitatea între browsere.

fluxul media

Prima și cea mai simplă componentă WebRTC este MediaStream. Oferă browserului acces la fluxurile media de la camera și microfonul computerului local. În Chrome, aceasta necesită apelarea funcției navigator.webkitGetUserMedia() (deoarece standardul nu este încă finalizat, toate funcțiile vin cu un prefix, iar în Firefox aceeași funcție se numește navigator.mozGetUserMedia()). Când este apelat, utilizatorului i se va cere să permită accesul la cameră și microfon. Va fi posibilă continuarea apelului numai după ce utilizatorul își dă acordul. Parametrii fluxului media necesar și două funcții de apel invers sunt trecuți ca parametri acestei funcție: primul va fi apelat în cazul accesului cu succes la cameră/microfon, al doilea - în cazul unei erori. Mai întâi, să creăm un fișier HTML rtctest1.html cu un buton și un element

WebRTC - prima cunoștință

Microsoft CU-RTC-Web

Microsoft nu ar fi Microsoft dacă, ca răspuns la inițiativa Google, nu ar lansa imediat propria variantă personalizată incompatibilă numită CU-RTC-Web (html5labs.interoperabilitybridges.com/cu-rtc-web/cu-rtc-web. htm). Deși ponderea IE, deja mică, continuă să scadă, numărul utilizatorilor Skype îi dă Microsoft speranță de a împinge Google și se poate presupune că acest standard va fi folosit în versiunea de browser a Skype. Standardul Google se concentrează în primul rând pe comunicarea de la un browser la altul; în același timp, cea mai mare parte a traficului de voce rămâne în continuare în rețeaua de telefonie convențională, iar gateway-uri între aceasta și rețelele IP sunt necesare nu numai pentru ușurință în utilizare sau distribuție mai rapidă, ci și ca mijloc de monetizare care va permite mai multor jucători să dezvolta-le. Apariția unui alt standard poate duce nu numai la o nevoie neplăcută pentru dezvoltatori de a suporta două tehnologii incompatibile simultan, dar și în viitor să ofere utilizatorului o gamă mai largă de funcționalități posibile și soluții tehnice disponibile. Așteaptă și vezi.

Activați firul local

Etichetele din interiorÎn fișierul nostru HTML, să declarăm o variabilă globală pentru fluxul media:

VarlocalStream = nul;

Primul parametru al metodei getUserMedia este de a specifica parametrii fluxului media solicitat - de exemplu, activați pur și simplu audio sau video:

Var streamConstraints = ( „audio”: adevărat, „video”: adevărat); // Solicită acces atât la audio, cât și la video

Sau specificați opțiuni suplimentare:

Var streamConstraints = ( „audio”: adevărat, „video”: ( „obligatoriu”: ( „maxWidth”: „320”, „maxHeight”: „240”, „maxFrameRate”: „5” ), „opțional”: ) );

Al doilea parametru al metodei getUserMedia este de a transmite o funcție de apel invers care va fi apelată dacă are succes:

Funcția getUserMedia_success(stream) ( console.log("getUserMedia_success():", flux); localVideo1.src = URL.createObjectURL(stream); // Atașați fluxul media la elementul HTML

Al treilea parametru este o funcție de apel invers, un handler de erori care va fi apelat în cazul unei erori.

Funcția getUserMedia_error(eroare) ( console.log("getUserMedia_error():", eroare); )

Apelul propriu-zis la metoda getUserMedia - solicitarea accesului la microfon și cameră atunci când este apăsat primul buton

Funcția getUserMedia_click() ( console.log ("getUserMedia_click()"); navigator.webkitGetUserMedia(streamConstraints, getUserMedia_success, getUserMedia_error); )

Nu este posibil să accesați fluxul media dintr-un fișier deschis local. Dacă încercăm să facem acest lucru, obținem o eroare:

NavigatorUserMediaError (cod: 1, PERMISSION_DENIED: 1)"

Să încărcăm fișierul rezultat pe server, să îl deschidem în browser și, ca răspuns la solicitarea care apare, să permitem accesul la cameră și microfon.

Puteți selecta ce dispozitive va accesa Chrome în Setări, Afișați linkul pentru setări avansate, secțiunea Confidențialitate, butonul Conținut. În browserele Firefox și Opera, dispozitivele sunt selectate din lista derulantă direct atunci când accesul este acordat.

Când utilizați protocolul HTTP, permisiunea va fi solicitată de fiecare dată când este accesat un flux media după încărcarea paginii. Trecerea la HTTPS vă va permite să afișați cererea o dată, doar la primul acces la fluxul media.

Acordați atenție cercului pulsatoriu din pictograma de pe filă și pictogramei camerei din partea dreaptă a barei de adrese:

RTCMediaConnection

RTCMediaConnection - un obiect conceput pentru a stabili și a transfera fluxuri media prin rețea între participanți. În plus, acest obiect este responsabil pentru generarea unei descriere a sesiunii media (SDP), obținerea de informații despre candidații ICE pentru trecerea prin NAT sau firewall-uri (locale și folosind STUN) și interacțiunea cu serverul TURN. Fiecare participant trebuie să aibă o RTCMediaConnection per conexiune. Fluxurile media sunt transmise prin protocolul SRTP criptat.

Servere TURN

Există trei tipuri de candidați ICE: gazdă, srflx și releu. Gazda conține informații obținute local, srflx este ceea ce arată gazda pentru un server extern (STUN), iar releul este informații pentru transmiterea traficului prin serverul TURN. Dacă nodul nostru se află în spatele unui NAT, atunci candidații gazdă vor conține adrese locale și vor fi inutili, candidații srflx vor ajuta doar cu anumite tipuri de NAT și releul va fi ultima speranță de a trece traficul printr-un server intermediar.

Un exemplu de candidat ICE de tip gazdă, cu adresa 192.168.1.37 și portul udp/34022:

A=candidat:337499441 2 udp 2113937151 192.168.1.37 34022 tip generație gazdă 0

Format general pentru specificarea serverelor STUN/TURN:

Var servere = ( "iceServers": [ ( "url": "stun:stun.stunprotocol.org:3478"), ( "url": "turn: [email protected]:port”, „credential”: „parolă” ) ]);

Există multe servere publice STUN pe Internet. O listă mare, de exemplu, este . Din păcate, ele rezolvă prea puține probleme. Practic nu există servere TURN publice, spre deosebire de STUN. Acest lucru se datorează faptului că serverul TURN trece prin el însuși fluxuri media, care pot încărca semnificativ atât canalul de rețea, cât și serverul însuși. Prin urmare, cel mai simplu mod de a vă conecta la serverele TURN este să îl instalați singur (evident, veți avea nevoie de un IP public). Dintre toate serverele, în opinia mea, cel mai bun este rfc5766-turn-server . Sub ea, există chiar și o imagine gata făcută pentru Amazon EC2.

Cu TURN, nu totul este la fel de bine pe cât ne-am dori, dar o dezvoltare activă este în plină desfășurare și aș dori să sper că după ceva timp WebRTC, dacă nu va ajunge din urmă Skype în ceea ce privește calitatea trecerii prin traducerea adresei ( NAT) și firewall-uri, apoi se apropie cel puțin vizibil.

RTCMediaConnection are nevoie de un mecanism suplimentar de schimb de informații de control pentru a stabili o conexiune - deși generează aceste date, nu le transmite, iar transmisia de către alți participanți trebuie implementată separat.


Alegerea metodei de transmitere este responsabilitatea dezvoltatorului - cel puțin manual. De îndată ce datele necesare sunt schimbate, RTCMediaConnection va configura automat fluxuri media (dacă este posibil, desigur).

model ofertă-răspuns

Pentru stabilirea și modificarea fluxurilor media, se utilizează modelul ofertă/răspuns (ofertă/răspuns; descris în RFC3264) și protocolul SDP (Session Description Protocol). Ele sunt, de asemenea, utilizate de protocolul SIP. În acest model, se disting doi agenți: Ofertantul - cel care generează o descriere de sesiune SDP pentru a crea una nouă sau pentru a modifica una existentă (Ofertă SDP) și Răspundetor - cel care primește o descriere a sesiunii SDP de la un alt agent și răspunde la aceasta cu propria sa descriere a sesiunii (Răspuns SDP). În același timp, specificația necesită un protocol de nivel superior (de exemplu, SIP sau propriul său peste socket-uri web, ca în cazul nostru), care este responsabil pentru transferul SDP între agenți.

Ce date trebuie transmise între două RTCMediaConnections, astfel încât acestea să poată stabili cu succes fluxuri media:

  • Prima parte care inițiază conexiunea formează o Ofertă în care transmite o structură de date SDP (același protocol este folosit în același scop în SIP) care descrie posibilele caracteristici ale fluxului media pe care urmează să-l transmită. Acest bloc de date trebuie transferat celui de-al doilea participant. Al doilea participant generează un răspuns cu SDP-ul său și îl trimite primului.
  • Atât primul, cât și al doilea participant efectuează procedura de determinare a posibililor candidați ICE, cu ajutorul căreia al doilea participant le poate transfera fluxul media. Pe măsură ce candidații sunt identificați, informațiile despre aceștia ar trebui să fie transferate unui alt participant.

Formarea ofertei

Pentru a forma o Ofertă, avem nevoie de două funcții. Primul va fi chemat în cazul formării sale cu succes. Al doilea parametru al metodei createOffer() este o funcție de apel invers apelată în cazul unei erori în timpul execuției sale (cu condiția ca fluxul local să fie deja disponibil).

În plus, sunt necesari doi handlere de evenimente: onicecandidate când se definește un nou candidat ICE și onaddstream când se conectează un flux media din partea îndepărtată. Să revenim la dosarul nostru. Adăugați la HTML după linii cu elemente

Și după linia cu elementul


De asemenea, la începutul codului JavaScript, vom declara o variabilă globală pentru RTCPeerConnection:

varpc1;

Când apelați constructorul RTCPeerConnection, trebuie să specificați serverele STUN/TURN. Consultați bara laterală pentru mai multe detalii; atâta timp cât toți participanții sunt în aceeași rețea, aceștia nu sunt necesari.

var servers = null;

Opțiuni pentru Aprovizionare Oferta SDP

var offerConstraints = ();

Primul parametru al metodei createOffer() este o funcție de apel invers apelată la formarea cu succes a unei oferte

Funcția pc1_createOffer_success(desc) ( console.log("pc1_createOffer_success(): \ndesc.sdp:\n"+desc.sdp+"desc:", desc); pc1.setLocalDescription(desc); // Setați RTCPeerConnection generat de Oferiți metoda setLocalDescription SDP. // Când partea îndepărtată își trimite SDP-ul de răspuns, va trebui să fie setată folosind metoda setRemoteDescription // Până când a doua parte este implementată, nu faceți nimic // pc2_receivedOffer(desc); )

Al doilea parametru este o funcție de apel invers care va fi apelată în cazul unei erori

Funcția pc1_createOffer_error(eroare)( console.log("pc1_createOffer_success_error(): eroare:", eroare); )

Și vom declara o funcție de apel invers care va primi candidaților ICE așa cum sunt definiți:

Funcția pc1_onicecandidate(event)( if (event.candidate) ( console.log("pc1_onicecandidate():\n"+ event.candidate.candidate.replace("\r\n", ""), event.candidate); // Nu faceți nimic până când a doua parte este implementată // pc2.addIceCandidate(new RTCIceCandidate(event.candidate)); ) )

Precum și o funcție de apel invers pentru adăugarea unui flux media din partea îndepărtată (pentru viitor, deoarece până acum avem o singură conexiune RTCPeer):

Funcția pc1_onaddstream(event) ( console.log("pc_onaddstream()"); remoteVideo1.src = URL.createObjectURL(event.stream); )

Când faceți clic pe butonul „createOffer”, creați o RTCPeerConnection, setați metodele onicecandidate și onaddstream și solicitați formarea unui SDP Offer apelând metoda createOffer():

Funcția createOffer_click() ( console.log("createOffer_click()"); pc1 = new webkitRTCPeerConnection(servere); // Creați o RTCPeerConnection pc1.onicecandidate = pc1_onicecandidate; // Funcția de apel invers pentru a procesa candidații ICE pc1.onaddstream = pc1.onaddstream; /1_onaddstream; / Funcția de apel invers apelată când există un flux media din partea îndepărtată, acesta nu există încă pc1.addStream(localStream); // Transmite fluxul media local (presupunând că a fost deja primit) pc1.createOffer(// Și de fapt solicita formarea Ofertei pc1_createOffer_success , pc1_createOffer_error, offerConstraints); )

Să salvăm fișierul ca rtctest2.html, să îl punem pe server, să îl deschidem într-un browser și să vedem în consolă ce date sunt generate în timpul funcționării sale. Al doilea videoclip nu va apărea încă, deoarece există un singur participant. Amintiți-vă că SDP este o descriere a parametrilor sesiunii media, codecurile disponibile, fluxurile media și candidații ICE sunt opțiuni posibile pentru conectarea la acest participant.

Formarea Answer SDP și schimbul de candidați ICE

Atât Oferta SDP, cât și fiecare dintre candidații ICE trebuie să fie transmise către cealaltă parte, iar acolo, după ce le primiți de la RTCPeerConnection, apelați metodele setRemoteDescription pentru Oferta SDP și addIceCandidate pentru fiecare candidat ICE primit din partea îndepărtată; în mod similar, invers pentru candidații Answer SDP și la distanță ICE. Răspunsul SDP în sine este format în mod similar cu Oferta; diferența este că nu este apelată metoda createOffer, ci metoda createAnswer, iar înainte de această RTCPeerConnection, metoda setRemoteDescription trece SDP-ul Offer primit de la apelant.

Să adăugăm un alt element video la HTML:

Și o variabilă globală pentru a doua RTCPeerConnection sub declarația primei:

Varpc2;

Procesarea ofertei și a răspunsului SDP

Formarea unui răspuns SDP este foarte asemănătoare cu o ofertă. În funcția de apel invers apelată la formarea cu succes a Răspunsului, în mod similar cu Oferta, vom oferi o descriere locală și vom transmite SDP-ul de răspuns primit primului participant:

Funcția pc2_createAnswer_success(desc) ( pc2.setLocalDescription(desc); console.log("pc2_createAnswer_success()", desc.sdp); pc1.setRemoteDescription(desc); )

Funcția de apel invers apelată în cazul unei erori la generarea Răspunsului este complet similară cu Oferta:

Funcția pc2_createAnswer_error(eroare) ( console.log("pc2_createAnswer_error():", eroare); )

Parametri pentru generarea răspunsului SDP:

Var answerConstraints = ( "obligatoriu": ( "OferToReceiveAudio":true, "OfferToReceiveVideo":true) );

Când al doilea participant primește o ofertă, creați o RTCPeerConnection și formați un răspuns în același mod ca și oferta:

Funcția pc2_receivedOffer(desc) ( console.log("pc2_receiveOffer()", desc); // Creați un obiect RTCPeerConnection pentru al doilea participant similar cu primul pc2 = new webkitRTCPeerConnection(servere); pc2.onicecandidate = pc2_onicecandidate; // Setați handlerul de evenimente când candidatul ICE pc2.onaddstream = pc_onaddstream; // Când apare un flux, conectați-l la HTML

Pentru a transfera Oferta SDP de la primul participant la al doilea, ca parte a exemplului nostru, decomentați funcția pc1 createOfferșir de apel succes():

Pc2_receivedOffer(desc);

Pentru a implementa procesarea candidaților ICE, anulați comentariul în gestionarea evenimentului de pregătire a candidatului ICE al primului participant pc1_onicecandidate() transmiterea acestuia către al doilea:

Pc2.addIceCandidate(nou RTCIceCandidate(event.candidate));

Managerul de evenimente de pregătire a candidatului ICE al celui de-al doilea participant este asemănător cu primul:

Funcția pc2_onicecandidate(event) ( if (event.candidate) ( console.log("pc2_onicecandidate():", event.candidate.candidate); pc1.addIceCandidate(nou RTCIceCandidate(event.candidate)); ) )

Funcția de apel invers pentru adăugarea unui flux media de la primul participant:

Funcția pc2_onaddstream(event) ( console.log("pc_onaddstream()"); remoteVideo2.src = URL.createObjectURL(event.stream); )

Încheierea unei conexiuni

Să adăugăm un alt buton în HTML

Și o funcție pentru a încheia conexiunea

Funcția btnHangupClick() ( // Dezactivează videoclipul local din elementele HTML

Să-l salvăm ca rtctest3.html, să-l punem pe server și să-l deschidem în browser. Acest exemplu implementează fluxul media bidirecțional între două conexiuni RTCPeerConnections din aceeași filă de browser. Pentru a organiza schimbul de oferte și răspunsuri SDP, candidați ICE între participanți și alte informații prin intermediul rețelei, va fi necesar să se implementeze schimbul între participanți folosind un fel de transport, în cazul nostru, prize web, în ​​locul unui apel direct către proceduri.

Difuzare pe ecran

Cu funcția getUserMedia, puteți, de asemenea, captura ecranul și transmite în flux ca MediaStream, specificând următorii parametri:

Var mediaStreamConstraints = ( audio: fals, video: ( obligatoriu: ( chromeMediaSource: "ecran" ), opțional: ) );

Pentru accesul cu succes la ecran, trebuie îndeplinite mai multe condiții:

  • activați semnalizarea capturii de ecran în getUserMedia() în chrome://flags/,chrome://flags/;
  • fișierul sursă trebuie descărcat prin HTTPS (origine SSL);
  • fluxul audio nu trebuie solicitat;
  • cererile multiple nu trebuie făcute în aceeași filă de browser.

Biblioteci pentru WebRTC

Deși WebRTC nu este încă complet, mai multe biblioteci bazate pe acesta au apărut deja. JsSIP este conceput pentru a crea telefoane software bazate pe browser care funcționează cu comutatoare SIP, cum ar fi Asterisk și Camalio. PeerJS va simplifica crearea de rețele P2P pentru schimbul de date, iar Holla va reduce cantitatea de dezvoltare necesară pentru comunicarea P2P din browsere.

Node.js și socket.io

Pentru a organiza schimbul de candidați SDP și ICE între două RTCPeerConnections prin rețea, folosim Node.js cu modulul socket.io.

Este descrisă instalarea celei mai recente versiuni stabile a Node.js (pentru Debian/Ubuntu).

$ sudo apt-get install python-software-properties python g++ make $ sudo add-apt-repository ppa:chris-lea/node.js $ sudo apt-get update $ sudo apt-get install nodejs

Este descrisă instalarea pentru alte sisteme de operare

Sa verificam:

$ echo "sys=require("util"); sys.puts("Mesaj de testare");" > nodetest1.js $ nodejs nodetest1.js

Folosind npm (Node Package Manager) instalați socket.io și modulul expres suplimentar:

$ npm instalează socket.io express

Să verificăm prin crearea unui fișier nodetest2.js pentru partea serverului:

$ nano nodetest2.js var app = require("express")() , server = require("http").createServer(app) , io = require("socket.io").listen(server); server.listen(80); // Dacă portul 80 este gratuit app.get("/", funcția (req, res) ( // Când accesați pagina rădăcină res.sendfile(__dirname + "/nodetest2.html"); // dați fișierul HTML ) ); io.sockets.on(„conexiune”, funcția (socket) ( // La conexiune socket.emit(„eveniment server”, ( salut: „lume”)); // trimite mesaj socket.on(„eveniment client”, funcția (date) ( // și declara un handler de evenimente când sosește un mesaj de la consola client.log(data); )); ));

Și nodetest2.html pentru partea client:

$nano nodetest2.html

Să pornim serverul:

$ sudo nodejs nodetest2.js

și deschideți pagina http://localhost:80 (dacă rulează local pe portul 80) într-un browser. Dacă totul are succes, în consola JavaScript a browserului vom vedea schimbul de evenimente între browser și server la conectare.

Schimb de informații între RTCPeerConnection prin intermediul socket-urilor web

Partea clientului

Să salvăm exemplul nostru principal (rtcdemo3.html) sub noul nume rtcdemo4.html. Includeți biblioteca socket.io în elementul:

Și la începutul scriptului JavaScript - conexiune web socket:

var socket = io.connect ("http://localhost");

Să înlocuim un apel direct la funcțiile altui participant trimițându-i un mesaj prin intermediul socket-urilor web:

Funcția createOffer_success(desc) ( ... // pc2_receivedOffer(desc); socket.emit("ofertă", desc); ... ) function pc2_createAnswer_success(desc) ( ... // pc1.setRemoteDescription(desc); socket .emit("răspuns", desc); ) funcția pc1_onicecandidate(eveniment) ( ... // pc2.addIceCandidate(nou RTCIceCandidate(event.candidate)); socket.emit("ice1", event.candidate); .. . ) funcția pc2_onicecandidate(eveniment) ( ... // pc1.addIceCandidate(nou RTCIceCandidate(event.candidate)); socket.emit("ice2", event.candidate); ... )

În funcția hangup(), în loc să apelăm direct funcțiile celui de-al doilea participant, vom trimite un mesaj prin intermediul socket-urilor web:

Funcția btnHangupClick() ( ... // remoteVideo2.src = ""; pc2.close(); pc2 = null; socket.emit ("închidere", ()); )

Și adăugați handlere de primire a mesajelor:

Socket.on("ofertă", funcție (date) ( console.log ("socket.on("ofertă"):", date); pc2_receivedOffer(date); )); socket.on(„răspuns”, funcție (date) (e console.log(„socket.on(„răspuns”):”, date); pc1.setRemoteDescription(noua RTCSessionDescription(date)); )); socket.on("ice1", funcția (date) ( console.log ("socket.on("ice1"):", date); pc2.addIceCandidate(nou RTCIceCandidate(date)); )); socket.on("ice2", function (date) ( console.log ("socket.on("ice2"):", data); pc1.addIceCandidate(new RTCIceCandidate(data)); )); socket.on("închidere", funcție (date) ( console.log ("socket.on("închidere")):", date); remoteVideo2.src = ""; pc2.close(); pc2 = null; ) );

Partea serverului

Pe partea de server, salvați fișierul nodetest2 sub noul nume rtctest4.js și în interiorul funcției io.sockets.on(„connection”, function (socket) ( ... ) adăugați primirea și trimiterea mesajelor client:

Socket.on("ofertă", funcție (date) ( // Când primiți un mesaj "ofertă", // deoarece există o singură conexiune client în acest exemplu, // trimite mesajul înapoi prin aceeași socket socket.emit( "ofertă" , date); // Dacă a fost necesar să redirecționați mesajul pe toate conexiunile // cu excepția expeditorului: // socket.broadcast.emit("ofertă", date); )); socket.on(„răspuns”, funcția (date) ( socket.emit(„răspuns”, date); )); socket.on("ice1", function (data) ( socket.emit ("ice1", data); )); socket.on("ice2", function (data) ( socket.emit ("ice2", data); )); socket.on(„închidere”, funcția (date) ( socket.emit(„închidere”, date); ));

În plus, schimbați numele fișierului HTML:

// res.sendfile(__dirname + "/nodetest2.html"); // Trimite fișierul HTML res.sendfile(__dirname + "/rtctest4.html");

Pornirea serverului:

$ sudo nodejs nodetest2.js

În ciuda faptului că codul ambilor clienți rulează în aceeași filă de browser, toată interacțiunea dintre participanții din exemplul nostru se desfășoară complet prin rețea și nu mai este dificil să „răspândești” participanții. Totuși, ceea ce am făcut a fost și foarte simplu - aceste tehnologii sunt bune pentru ușurința lor de utilizare. Deși uneori înșelător. În special, să nu uităm că fără serverele STUN/TURN, exemplul nostru nu va putea funcționa în prezența traducerii adreselor și a firewall-urilor.

Concluzie

Exemplul rezultat este foarte condiționat, dar dacă universalizăm ușor handlerele de evenimente, astfel încât să nu difere între părțile apelante și cele chemate, în loc de două obiecte pc1 și pc2, facem o matrice RTCPeerConnection și implementăm crearea și ștergerea dinamică a elementelor.

Se poate presupune că foarte curând, datorită WebRTC, va avea loc o revoluție nu numai în înțelegerea noastră a comunicațiilor vocale și video, ci și în modul în care percepem Internetul ca întreg. WebRTC este poziționat nu numai ca o tehnologie de apel de la browser la browser, ci și ca o tehnologie de comunicare în timp real. Comunicarea video, pe care am analizat-o, este doar o mică parte din opțiunile posibile de utilizare. Există deja exemple de partajare a ecranului (partajarea ecranului) și colaborare, și chiar o rețea de livrare de conținut P2P bazată pe browser, folosind RTCDataChannel.

WebRTC (Web Real Time Communications) este un standard care descrie transferul de date audio în flux, date video și conținut din browser și către browser în timp real, fără a instala pluginuri sau alte extensii. Standardul vă permite să transformați browserul într-un terminal de videoconferință, doar deschideți o pagină web pentru a începe comunicarea.

Ce este WebRTC?

În acest articol, vom acoperi tot ce este de știut despre tehnologia WebRTC pentru utilizatorul obișnuit. Să luăm în considerare avantajele și dezavantajele proiectului, să dezvăluim câteva secrete, să vă spunem cum funcționează, unde și pentru ce este folosit WebRTC.

Ce trebuie să știți despre WebRTC?

Evoluția standardelor și tehnologiilor video

Sergey Yutsaitis, Cisco, Video+Conference 2016

Cum funcționează WebRTC

Pe partea clientului

  • Utilizatorul deschide o pagină care conține o etichetă HTML5
  • Browserul solicită acces la camera web și la microfonul utilizatorului.
  • Codul JavaScript de pe pagina de utilizator controlează parametrii de conectare (adresele IP și porturile serverului WebRTC sau alți clienți WebRTC) pentru a ocoli NAT și Firewall.
  • Când primește informații despre interlocutor sau despre fluxul cu conferința mixtă pe server, browserul începe să negocieze codecurile audio și video folosite.
  • Începe procesul de codificare și streaming de date între clienții WebRTC (în cazul nostru, între browser și server).

Pe partea de server WebRTC

Nu este necesar un server video pentru schimbul de date între doi participanți, dar dacă doriți să combinați mai mulți participanți într-o conferință, este necesar un server.



Serverul video va primi trafic media din diverse surse, îl va converti și îl va trimite utilizatorilor care folosesc WebRTC ca terminal.

Serverul WebRTC va primi, de asemenea, trafic media de la colegii WebRTC și îl va transmite participanților la conferință folosind aplicații desktop sau mobile, dacă există.

Beneficiile standardului

  • Nu este necesară instalarea de software.
  • Calitate foarte înaltă a comunicării datorită:
    • Utilizarea de codecuri video moderne (VP8, H.264) și audio (Opus).
    • Reglarea automată a calității fluxului la condițiile de conectare.
    • Anularea ecouului și a zgomotului încorporată.
    • Control automat al nivelului microfoanelor participanților (AGC).
  • Nivel ridicat de securitate: toate conexiunile sunt sigure și criptate conform protocoalelor TLS și SRTP.
  • Există un mecanism încorporat pentru captarea conținutului, cum ar fi desktopul.
  • Abilitatea de a implementa orice interfață de control bazată pe HTML5 și JavaScript.
  • Abilitatea de a integra interfața cu orice sisteme back-end folosind WebSockets.
  • Un proiect open source - îl puteți încorpora în produsul sau serviciul dvs.
  • Adevărat multiplatformă: aceeași aplicație WebRTC va funcționa la fel de bine pe orice sistem de operare, desktop sau mobil, cu condiția ca browserul să accepte WebRTC. Acest lucru economisește o mulțime de resurse pentru dezvoltarea de software.

Dezavantajele standardului

  • Pentru a organiza conferințe audio și video de grup, este necesar un server de videoconferință care să combine video și audio de la participanți, deoarece browserul nu știe cum să sincronizeze mai multe fluxuri de intrare între ele.
  • Toate soluțiile WebRTC sunt incompatibile între ele, deoarece standardul descrie numai metode de transmitere video și sunet, lăsând implementarea metodelor de adresare a abonaților, urmărirea disponibilității acestora, schimbul de mesaje și fișiere, programare și alte lucruri pentru furnizor.
  • Cu alte cuvinte, nu veți putea apela de la o aplicație WebRTC a unui dezvoltator la o aplicație WebRTC a altui dezvoltator.
  • Mixarea conferințelor de grup necesită o mulțime de resurse de calcul, așa că acest tip de comunicare video necesită achiziționarea unui abonament plătit sau investiții în infrastructura sa, unde fiecare conferință necesită 1 nucleu fizic al unui procesor modern.

Secretele WebRTC: Cum beneficiază furnizorii de tehnologia web disruptivă


Tzachi Levent-Levi, Bloggeek.me, Video+Conference 2015

WebRTC pentru piața videoconferințelor

Creșterea numărului de terminale de videoconferință

Tehnologia WebRTC a avut un impact puternic asupra dezvoltării pieței videoconferințelor. După lansarea primelor browsere cu suport WebRTC în 2013, numărul potențial de terminale de videoconferință din întreaga lume a crescut imediat cu 1 miliard de dispozitive. De fapt, fiecare browser a devenit un terminal de videoconferință care nu este inferior omologilor săi hardware în ceea ce privește calitatea comunicației.

Utilizare în soluții specializate

Utilizarea diferitelor biblioteci JavaScript și API-uri pentru servicii cloud cu suport WebRTC facilitează adăugarea de suport video la orice proiecte web. În trecut, transmisia de date în timp real cerea dezvoltatorilor să învețe cum funcționau protocoalele și să folosească munca altor companii, care de cele mai multe ori necesitau licențiere suplimentară, ceea ce crește costurile. WebRTC este deja utilizat activ în servicii precum „Apel de pe site”, „Chat de asistență online”, etc.

Foști utilizatori Skype pentru Linux

În 2014, Microsoft a anunțat încetarea suportului pentru proiectul Skype pentru Linux, ceea ce a provocat o mare supărare în rândul profesioniștilor IT. Tehnologia WebRTC nu este legată de sistemul de operare, ci este implementată la nivel de browser, de exemplu. Utilizatorii Linux vor putea vedea produsele și serviciile bazate pe WebRTC ca un înlocuitor cu drepturi depline pentru Skype.

Concurență cu Flash

WebRTC și HTML5 au fost o lovitură de moarte pentru tehnologia Flash, care trecea deja prin cei departe de cei mai buni ani. Din 2017, browserele de top au încetat oficial să mai suporte Flash, iar tehnologia a dispărut în sfârșit de pe piață. Dar trebuie să acordați credit Flash, pentru că el a creat piața de conferințe web și a oferit capabilitățile tehnice pentru comunicarea live în browsere.

Prezentări video WebRTC

Dmitri Odintsov, TrueConf, Video+Conference octombrie 2017

Codecuri în WebRTC

Codecuri audio

Pentru a comprima traficul audio în WebRTC, se folosesc codecuri Opus și G.711.

G.711- cel mai vechi codec de voce cu o rată de biți mare (64 kbps), care este cel mai des folosit în sistemele tradiționale de telefonie. Principalul avantaj este sarcina de calcul minimă datorită utilizării algoritmilor de compresie ușoare. Codecul are un nivel scăzut de compresie a semnalelor vocale și nu introduce întârziere audio suplimentară în timpul comunicării între utilizatori.

G.711 este acceptat de un număr mare de dispozitive. Sistemele care folosesc acest codec sunt mai ușor de utilizat decât cele bazate pe alte codecuri audio (G.723, G.726, G.728 etc.). În ceea ce privește calitatea, G.711 a primit un scor de 4,2 la testarea MOS (un scor de 4-5 este cel mai mare și înseamnă calitate bună, similar cu calitatea traficului de voce în ISDN și chiar mai mare).

Opus este un codec cu latență scăzută de codare (de la 2,5 ms la 60 ms), suport pentru rată de biți variabilă și compresie ridicată, care este ideal pentru streaming audio pe rețele cu lățime de bandă variabilă. Opus este o soluție hibridă care combină cele mai bune caracteristici ale codecurilor SILK (comprimarea vocii, eliminarea distorsiunii vorbirii umane) și CELT (codarea datelor audio). Codecul este disponibil gratuit, dezvoltatorii care îl folosesc nu trebuie să plătească drepturi de autor deținătorilor de drepturi de autor. În comparație cu alte codecuri audio, Opus câștigă cu siguranță în multe feluri. A eclipsat codecuri destul de populare cu rate de biți scăzute, cum ar fi MP3, Vorbis, AAC LC. Opus restabilește „imaginea” sunetului mai aproape de original decât AMR-WB și Speex. Acest codec este viitorul, motiv pentru care creatorii tehnologiei WebRTC l-au inclus în gama obligatorie de standarde audio acceptate.

Codecuri video

Problemele de alegere a unui codec video pentru WebRTC au luat dezvoltatorilor câțiva ani, în cele din urmă au decis să folosească H.264 și VP8. Aproape toate browserele moderne acceptă ambele codecuri. Serverele de videoconferință trebuie să accepte doar unul pentru a funcționa cu WebRTC.

VP8 este un codec video gratuit cu o licență deschisă, cu viteză mare de decodare a fluxului video și rezistență crescută la pierderea cadrelor. Codecul este universal, este ușor de implementat în platformele hardware, astfel încât dezvoltatorii de sisteme de videoconferință îl folosesc adesea în produsele lor.

Codec video plătit H.264 a devenit cunoscut mult mai devreme decât fratele său. Acesta este un codec cu un grad ridicat de compresie a fluxului video, menținând în același timp o calitate video înaltă. Prevalența ridicată a acestui codec printre sistemele hardware de videoconferință sugerează utilizarea sa în standardul WebRTC.

Google și Mozilla promovează în mod activ codecul VP8, în timp ce Microsoft, Apple și Cisco promovează activ H.264 (pentru a asigura compatibilitatea cu sistemele tradiționale de videoconferință). Și aici apare o problemă foarte mare pentru dezvoltatorii de soluții WebRTC bazate pe cloud, deoarece dacă toți participanții la conferință folosesc un singur browser, atunci este suficient să amestecați conferința o dată cu un singur codec, iar dacă browserele sunt diferite și printre ele există este Safari/Edge, atunci conferința va trebui să fie codificată de două ori codecuri diferite, ceea ce va dubla cerințele de sistem pentru serverul media și, ca urmare, costul abonamentelor la serviciile WebRTC.

API-ul WebRTC

Tehnologia WebRTC se bazează pe trei API-uri principale:

  • (responsabil ca browserul web să primească semnale audio și video de la camere sau desktopul utilizatorului).
  • RTCPeerConnection(responsabil pentru conexiunea dintre browsere pentru a „schimba” date media primite de la cameră, microfon și desktop. De asemenea, „datoriile” acestui API includ procesarea semnalului (curățarea acestuia de zgomote străine, reglarea volumului microfonului) și controlul asupra codecuri audio și video utilizate) .
  • Canal de date RTC(oferă transfer bidirecțional de date printr-o conexiune stabilită).

Înainte de a accesa microfonul și camera utilizatorului, browserul solicită această permisiune. În Google Chrome, puteți preconfigura accesul în secțiunea „Setări”, în Opera și Firefox, alegerea dispozitivelor se realizează direct în momentul accesării, din lista derulantă. Solicitarea de permisiune va apărea întotdeauna când utilizați protocolul HTTP și o dată dacă utilizați HTTPS:


RTCPeerConnection. Fiecare browser care participă la o conferință WebRTC trebuie să aibă acces la acest obiect. Datorită utilizării RTCPeerConnection, datele media de la un browser la altul pot trece chiar prin NAT și firewall-uri. Pentru a transmite cu succes fluxuri media, participanții trebuie să facă schimb de următoarele date folosind un transport, cum ar fi socket-urile web:

  • participantul inițiator trimite celui de-al doilea participant o Oferta-SDP (structură de date, cu caracteristicile fluxului media pe care îl va transmite);
  • al doilea participant generează un „răspuns” - Answer-SDP și îl trimite inițiatorului;
  • apoi, se organizează un schimb de candidați ICE între participanți, dacă se găsesc (dacă participanții sunt în spatele NAT sau firewall-uri).

După finalizarea cu succes a acestui schimb între participanți, transferul fluxurilor media (audio și video) este organizat direct.

Canal de date RTC. Suportul pentru protocolul Data Channel a apărut în browsere relativ recent, așa că acest API poate fi luat în considerare numai în cazurile în care WebRTC este utilizat în browserele Mozilla Firefox 22+ și Google Chrome 26+. Cu acesta, participanții pot face schimb de mesaje text în browser.

Conexiune WebRTC

Browsere desktop acceptate

  • Google Chrome (17+) și toate browserele bazate pe motorul Chromium;
  • Mozilla Firefox (18+);
  • Opera (12+);
  • Safari (11+);

Browsere mobile acceptate pentru Android

  • Google Chrome (28+);
  • Mozilla Firefox (24+);
  • Opera Mobile (12+);
  • Safari (11+).

WebRTC, Microsoft și Internet Explorer

De foarte mult timp, Microsoft a tăcut cu privire la suportul WebRTC în Internet Explorer și în noul său browser Edge. Băieților de la Redmond nu prea le place să pună tehnologia în mâinile utilizatorilor pe care ei nu îi controlează, asta e genul de politică. Dar treptat lucrurile au decolat, pentru că. Nu a mai fost posibil să se ignore WebRTC, iar proiectul ORTC, derivat din standardul WebRTC, a fost anunțat.

Potrivit dezvoltatorilor, ORTC este o extensie a standardului WebRTC cu un set îmbunătățit de API-uri bazate pe JavaScript și HTML5, ceea ce, tradus în limbaj obișnuit, înseamnă că totul va fi la fel, doar Microsoft, nu Google, va controla standardul. si dezvoltarea acesteia. Setul de codecuri a fost extins cu suport pentru H.264 și unele codecuri audio din seria G.7XX utilizate în sistemele de telefonie și videoconferință hardware. Poate că va exista suport încorporat pentru RDP (pentru transferul de conținut) și mesagerie. Apropo, utilizatorii de Internet Explorer nu au noroc, suportul ORTC va fi doar în Edge. Și, desigur, un astfel de set de protocoale și codecuri se potrivește cu Skype for Business cu puțin sânge, ceea ce deschide și mai multe aplicații de afaceri pentru WebRTC.

WebRTC este un API furnizat de browser care vă permite să organizați o conexiune P2P și să transferați date direct între browsere. Există destul de multe tutoriale pe Internet despre cum să vă scrieți propriul chat video folosind WebRTC. De exemplu, iată un articol despre Habré. Cu toate acestea, toate sunt limitate la conectarea a doi clienți. În acest articol, voi încerca să vorbesc despre cum să organizăm o conexiune și un schimb de mesaje între trei sau mai mulți utilizatori folosind WebRTC.

Interfața RTCPeerConnection este o conexiune peer-to-peer între două browsere. Pentru a conecta trei sau mai mulți utilizatori, va trebui să organizăm o rețea mesh (o rețea în care fiecare nod este conectat la toate celelalte noduri).
Vom folosi următoarea schemă:

  1. La deschiderea paginii, verificăm prezența ID-ului camerei în locație.hash
  2. Dacă nu este specificat ID-ul camerei, generați unul nou
  3. Trimitem unui server de semnalizare „un mesaj că vrem să ne alăturăm camerei specificate
  4. Serverul de semnalizare trimite o nouă notificare de utilizator altor clienți din această cameră
  5. Clienții care sunt deja în sală trimit o ofertă SDP noului venit
  6. Noul venit răspunde ofertei „s

0. Server de semnalizare

După cum știți, deși WebRTC oferă posibilitatea conexiunii P2P între browsere, necesită totuși un transport suplimentar pentru schimbul de mesaje de serviciu. În acest exemplu, transportul este un server WebSocket scris în Node.JS folosind socket.io:

var socket_io = require("socket.io"); module.exports = function (server) ( var utilizatori = (); var io = socket_io(server); io.on("conexiune", function(socket) ( // Doresc ca un nou utilizator să se alăture camerei socket.on( "room", function(message) ( var json = JSON. parse(message); // Adăugați socket-ul la lista de utilizatori utilizatori = socket; if (socket.room !== nedefinit) ( // Dacă socket-ul este deja într-o cameră, lăsați-o socket.leave(socket.room); ) // Introduceți camera solicitată socket.room = json.room; socket.join(socket.room); socket.user_id = json.id; // Trimiteți altor clienți această sală are un mesaj despre alăturarea unui nou participant socket.broadcast.to(socket.room).emit("new", json.id); )); // Mesaj asociat WebRTC (ofertă SDP, răspuns SDP sau candidat ICE) socket.on("webrtc", function(mesaj) ( var json = JSON.parse(mesaj); if (json.to !== nedefinit && utilizatori !== nedefinit) ( // Dacă mesajul are un destinatar și acest destinatar cunoscut de server, trimit un mesaj numai lui... utilizatorii.emit("webrtc", mesaj); ) else ( // ...altfel considerați mesajul ca pe un socket de difuzare.difuzare.la(socket.room).emit("webrtc", mesaj); ) )); // Cineva a deconectat socket.on("disconnect", function() ( // Când un client se deconectează, notificați pe alții socket.broadcast.to(socket.room).emit("leave", socket.user_id); delete users; )); )); );

1. index.html

Codul sursă al paginii în sine este destul de simplu. În mod deliberat, nu am acordat atenție aspectului și altor lucruri frumoase, deoarece acest articol nu este despre asta. Dacă cineva vrea să o facă frumoasă, nu va fi greu.

WebRTC Chat Demo

conectat la 0 colegii

2.principal.js

2.0. Obținerea de link-uri către elementele paginii și interfețele WebRTC
var chatlog = document.getElementById("chatlog"); var mesaj = document.getElementById("mesaj"); var connection_num = document.getElementById("connection_num"); var room_link = document.getElementById("room_link");

Încă trebuie să folosim prefixele browserului pentru a accesa interfețele WebRTC.

Var PeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection; var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription; var IceCandidate = window.mozRTCIceCandidate || fereastra.RTCIceCandidate;

2.1. Determinarea ID-ului camerei

Aici avem nevoie de o funcție pentru a genera o cameră unică și un ID de utilizator. Vom folosi UUID în acest scop.

Funcția uuid () ( var s4 = function() ( return Math.floor(Math.random() * 0x10000).toString(16); ); return s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4(); )

Acum să încercăm să extragem ID-ul camerei din adresă. Dacă nu este setat, vom genera unul nou. Vom afișa pe pagină un link către camera actuală și, în același timp, vom genera un identificator pentru utilizatorul actual.

VarROOM = location.hash.substr(1); if (!ROOM) ( ROOM = uuid(); ) room_link.innerHTML = "Link catre camera"; varME = uuid();

2.2. priza web

Imediat după deschiderea paginii, ne vom conecta la serverul nostru de semnalizare, vom trimite o cerere de intrare în cameră și vom specifica operatori de mesaje.

// Precizăm că atunci când mesajul este închis, trebuie să trimitem o notificare către server despre acest var socket = io.connect("", ("sync deconectare la descărcare": true)); socket.on("webrtc", socketReceived); socket.on(„nou”, socketNewPeer); // Trimiteți imediat o solicitare de intrare în camera socket.emit("room", JSON.stringify((id: ME, room: ROOM))); // Funcție de ajutor pentru trimiterea de mesaje de adresă legate de funcția WebRTC sendViaSocket(type, message, to) ( socket.emit("webrtc", JSON.stringify((id: ME, to: to, type: type, data: message ) )); )

2.3. Setări de conexiune peer

Majoritatea furnizorilor de servicii de internet oferă conectivitate la internet prin NAT. Din această cauză, o conexiune directă nu devine atât de banală. Când creăm o conexiune, trebuie să specificăm o listă de servere STUN și TURN pe care browserul va încerca să le folosească pentru a ocoli NAT. Vom indica, de asemenea, câteva opțiuni suplimentare pentru conectare.

Var server = ( iceServers: [ (url: "stun:23.21.150.121"), (url: "stun:stun.l.google.com:19302"), (url: "turn:numb.viagenie.ca", acreditare: "parola dvs. merge aici", nume de utilizator: " [email protected]") ] ); opțiunile var = ( opțional: [ (DtlsSrtpKeyAgreement: true), // necesar pentru conexiunea între Chrome și Firefox (RtpDataChannels: true) // necesar în Firefox pentru a utiliza API-ul DataChannels ] )

2.4. Conectarea unui utilizator nou

Când un nou peer este adăugat în cameră, serverul ne trimite un mesaj nou. Conform gestionarilor de mesaje de mai sus, funcția va fi apelată socketNewPeer.

var peers = (); function socketNewPeer(data) (peers = (candidateCache:); // Creați o nouă conexiune var pc = new PeerConnection(server, opțiuni); // Inițializați-o initConnection(pc, data, "ofer"); // Stocați peer-ul în listă peers peers.connection = pc; // Creați un DataChannel prin care vor fi schimbate mesajele var channel = pc.createDataChannel("mychannel", ()); channel.owner = data; peers.channel = channel; // Instalați handlere de evenimente bindEvents(canal); // Creați o ofertă SDP pc.createOffer(function(offer) ( pc.setLocalDescription(offer); )); ) function initConnection(pc, id, sdpType) ( pc.onicecandidate = function ( eveniment) ( if (event.candidate) ( // Când este găsit un nou candidat ICE, adăugați-l la listă pentru trimitere ulterioară peers.candidateCache.push(event.candidate); ) else ( // Când descoperirea candidaților este finalizat, handlerul va fi apelat din nou, dar fără candidat // În acest caz, trimitem mai întâi colegului o ofertă SDP, sau Răspunsul SDP (în funcție de parametrul funcției)... sendViaSocket(sdpType, pc.localDescription, id); // ...și apoi toți candidații ICE găsiți anterior pentru (var i = 0; i< peers.candidateCache.length; i++) { sendViaSocket("candidate", peers.candidateCache[i], id); } } } pc.oniceconnectionstatechange = function (event) { if (pc.iceConnectionState == "disconnected") { connection_num.innerText = parseInt(connection_num.innerText) - 1; delete peers; } } } function bindEvents (channel) { channel.onopen = function () { connection_num.innerText = parseInt(connection_num.innerText) + 1; }; channel.onmessage = function (e) { chatlog.innerHTML += "

Peer spune: " + e.data + "
"; }; }

2.5. Oferta SDP, răspuns SDP, candidat ICE

Când se primește unul dintre aceste mesaje, apelăm la manipulatorul de mesaje corespunzător.

Funcția socketReceived(data) ( var json = JSON.parse(data); comutator (json.type) (case „candidat”: remoteCandidateReceived(json.id, json.data); break; case „ofertă”: remoteOfferReceived(json. id, json.data); pauză; caz „răspuns”: remoteAnswerReceived (json.id, json.data); pauză; ) )

2.5.0 Oferta SDP
function remoteOfferReceived(id, data) ( createConnection(id); var pc = peers.connection; pc.setRemoteDescription(new SessionDescription(date)); pc.createAnswer(function(answer) ( pc.setLocalDescription(answer); )); ) funcția createConnection(id) ( if (peers === nedefinit) ( peers = (candidateCache: ); var pc = nou PeerConnection(server, opțiuni); initConnection(pc, id, „răspuns”); peers.connection = pc ; pc.ondatachannel = function(e) ( peers.channel = e.channel; peers.channel.owner = id; bindEvents(peers.channel); ) ) )
2.5.1 Răspuns SDP
funcția remoteAnswerReceived(id, data) (var pc = peers.connection; pc.setRemoteDescription(new SessionDescription(date)); )
2.5.2 Candidatul ICE
funcția remoteCandidateReceived(id, data) ( createConnection(id); var pc = peers.connection; pc.addIceCandidate(new IceCandidate(data)); )
2.6. Trimiterea unui mesaj

Prin apăsarea butonului trimite funcția este numită Trimite mesaj. Tot ce face este să treacă prin lista de colegi și să încerce să trimită mesajul specificat tuturor.