WebRTC uygulaması için gereken arka uç hizmetlerini derleme

Sinyal verme nedir?

Sinyal verme, iletişimi koordine etme sürecidir. Bir WebRTC uygulamasının arama başlatabilmesi için istemcilerinin aşağıdaki bilgileri paylaşması gerekir:

  • İletişimi açmak veya kapatmak için kullanılan oturum kontrolü mesajları
  • Hata mesajları
  • Codec'ler, codec ayarları, bant genişliği ve medya türleri gibi medya meta verileri
  • Güvenli bağlantılar oluşturmak için kullanılan önemli veriler
  • Bir ana makinenin dış dünya tarafından görünen IP adresi ve bağlantı noktası gibi ağ verileri

Bu sinyal verme sürecinde, istemcilerin mesajları ileri geri iletmesi gerekir. Bu mekanizma, WebRTC API'leri tarafından uygulanmaz. Bu özelliği kendiniz oluşturmanız gerekir. Bu makalenin ilerleyen kısımlarında, sinyal hizmeti oluşturma yöntemlerini öğreneceksiniz. Ancak önce biraz bağlam bilgisi vermemiz gerekiyor.

Sinyalleşme neden WebRTC tarafından tanımlanmıyor?

Gereksiz tekrarları önlemek ve yerleşik teknolojilerle uyumluluğu en üst düzeye çıkarmak için sinyal yöntemleri ve protokolleri WebRTC standartlarında belirtilmez. Bu yaklaşım, JavaScript Oturum Oluşturma Protokolü (JSEP) ile özetlenmiştir:

JSEP'in mimarisi, tarayıcının durumu kaydetmesini (yani sinyal durumu makinesi olarak çalışmasını) de önler. Örneğin, bir sayfa her yeniden yüklendiğinde sinyal verileri kaybolursa bu durum sorun yaratır. Bunun yerine sinyal durumu bir sunucuya kaydedilebilir.

JSEP mimari şeması
JSEP mimarisi

JSEP, yukarıda bahsedilen medya meta verileri olan offer ve answer'ın eşler arasında değiştirilmesini gerektirir. Teklifler ve yanıtlar, oturum açıklaması protokolü (SDP) biçiminde iletilir. Bu biçim şu şekildedir:

v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2

Tüm bu SDP jargonunun ne anlama geldiğini öğrenmek ister misiniz? Internet Engineering Task Force (IETF) örneklerine göz atın.

WebRTC'nin, SDP metnindeki değerler düzenlenerek teklif veya yanıtın yerel ya da uzak açıklama olarak ayarlanmadan önce değiştirilebilecek şekilde tasarlandığını unutmayın. Örneğin, appr.tc'deki preferAudioCodec() işlevi, varsayılan codec'i ve bit hızını ayarlamak için kullanılabilir. SDP'nin JavaScript ile işlenmesi biraz zahmetlidir ve WebRTC'nin gelecekteki sürümlerinde bunun yerine JSON kullanılıp kullanılmaması gerektiği tartışılmaktadır. Ancak SDP'yi kullanmaya devam etmenin bazı avantajları vardır.

RTCPeerConnection API ve sinyal: Teklif, yanıt ve aday

RTCPeerConnection, WebRTC uygulamalarının eşler arasında bağlantı oluşturmak ve ses ile video iletişimi kurmak için kullandığı API'dir.

Bu işlemi başlatmak için RTCPeerConnection iki görev gerçekleştirir:

  • Çözünürlük ve codec özellikleri gibi yerel medya koşullarını belirleyin. Bu, teklif ve yanıt mekanizması için kullanılan meta verilerdir.
  • Uygulamanın ana makinesi için adaylar olarak bilinen olası ağ adreslerini alın.

Bu yerel veriler belirlendikten sonra, bir sinyal mekanizması aracılığıyla uzak eşle değiştirilmelidir.

Alice'in Eve'i aradığını düşünelim. İşte tüm ayrıntılarıyla eksiksiz teklif/yanıt mekanizması:

  1. Ayşe bir RTCPeerConnection nesnesi oluşturur.
  2. Alev, RTCPeerConnection createOffer() yöntemiyle bir teklif (SDP oturum açıklaması) oluşturur.
  3. Ayşe, teklifiyle birlikte setLocalDescription()'ı arar.
  4. Ayla, teklifi dizeleştirir ve bunu Elif'e göndermek için bir sinyal mekanizması kullanır.
  5. Eve, Alice'in teklifini setRemoteDescription() ile görüşür. Böylece RTCPeerConnection, Alice'in kurulumu hakkında bilgi sahibi olur.
  6. Eve, createAnswer() işlevini çağırır ve bu işlevin başarılı geri çağırma işlevine yerel bir oturum açıklaması (Eve'in yanıtı) iletilir.
  7. Eve, setLocalDescription() numaralı telefonu arayarak yanıtını yerel açıklama olarak ayarlıyor.
  8. Ardından Eve, dizgeleştirilmiş yanıtını Alice'e göndermek için sinyal mekanizmasını kullanır.
  9. Alice, setRemoteDescription() kullanarak Eve'in yanıtını uzaktan oturum açıklaması olarak ayarlar.

Alice ve Eve'in de ağ bilgilerini paylaşması gerekir. "Aday bulma" ifadesi, ICE çerçevesi kullanılarak ağ arayüzlerinin ve bağlantı noktalarının bulunması sürecini ifade eder.

  1. Ayşe, onicecandidate işleyicisi olan bir RTCPeerConnection nesnesi oluşturur.
  2. Ağ adayları kullanıma sunulduğunda işleyici çağrılır.
  3. İşleyici içinde Alice, sinyal kanalı üzerinden Eve'e dizeleştirilmiş aday verilerini gönderir.
  4. Ece, Ayşe'den aday mesajı aldığında addIceCandidate() işlevini çağırarak adayı uzak eş açıklamasına ekler.

JSEP, ICE Candidate Trickling'i destekler. Bu özellik, arayan kullanıcının ilk tekliften sonra aranan kullanıcıya kademeli olarak adaylar sağlamasına ve aranan kullanıcının tüm adayların gelmesini beklemeden aramayı işleme almaya başlamasına ve bağlantı kurmasına olanak tanır.

Sinyal için WebRTC kodunu kullanma

Aşağıdaki kod snippet'i, tam sinyal sürecini özetleyen bir W3C kod örneğidir. Kod, SignalingChannel gibi bir sinyal mekanizmasının varlığını varsayar. Sinyal verme konusu daha sonra ayrıntılı olarak ele alınacaktır.

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // send the offer to the other peer
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

Teklif/yanıt ve aday değişimi süreçlerinin nasıl çalıştığını görmek için simpl.info RTCPeerConnection sayfasına gidip tek sayfalık bir görüntülü sohbet örneğinin konsol günlüğüne bakın. Daha fazla bilgi edinmek isterseniz Google Chrome'daki about://webrtc-internals sayfasından veya Opera'daki opera://webrtc-internals sayfasından WebRTC sinyalleşmesi ve istatistiklerinin tam dökümünü indirebilirsiniz.

Eş keşfi

Bu, "Konuşacak birini nasıl bulabilirim?" sorusunu sormanın havalı bir yoludur.

Telefon aramaları için telefon numaraları ve rehberleriniz vardır. Online görüntülü sohbet ve mesajlaşma için kimlik ve varlık yönetimi sistemlerinin yanı sıra kullanıcıların oturum başlatabileceği bir yöntem gerekir. WebRTC uygulamalarının, istemcilerin birbirlerine görüşme başlatmak veya görüşmeye katılmak istediklerini bildirmeleri için bir yöntem gerekir.

Benzer bulma mekanizmaları WebRTC tarafından tanımlanmaz ve burada seçeneklere girmezsiniz. Bu işlem, bir URL'yi e-posta veya mesaj yoluyla göndermek kadar basit olabilir. Talky, tawk.to ve Browser Meeting gibi görüntülü sohbet uygulamalarında, özel bir bağlantı paylaşarak kullanıcıları görüşmeye davet edersiniz. Geliştirici Chris Ball, WebRTC görüşmesi katılımcılarının anlık mesajlaşma, e-posta veya güvercin gibi istedikleri mesajlaşma hizmetiyle meta veri alışverişi yapmasını sağlayan ilgi çekici bir serverless-webrtc denemesi geliştirdi.

Nasıl bir sinyal hizmeti oluşturabilirsiniz?

Tekrar belirtmek gerekirse sinyal protokolleri ve mekanizmaları WebRTC standartlarıyla tanımlanmaz. Ne seçerseniz seçin, istemciler arasında sinyal mesajları ve uygulama verileri alışverişi yapmak için bir aracı sunucuya ihtiyacınız vardır. Ne yazık ki bir web uygulaması internete "Beni arkadaşıma bağla!" diye bağıramaz.

Neyse ki sinyal mesajları küçüktür ve çoğunlukla aramanın başında gönderilir. Görüntülü sohbet oturumu için appr.tc ile yapılan testte, sinyal hizmeti tarafından toplamda yaklaşık 30-45 mesaj işlendi. Tüm mesajların toplam boyutu yaklaşık 10 KB'tı.

WebRTC sinyal hizmetleri, bant genişliği açısından nispeten az kaynak gerektirmesinin yanı sıra yalnızca mesajları iletmeleri ve hangi istemcilerin bağlı olduğu gibi küçük bir oturum durumu verisi miktarını saklamaları gerektiğinden çok fazla işlem gücü veya bellek tüketmez.

Sunucudan istemciye anlık mesaj gönderme

Sinyal verme için kullanılan mesajlaşma hizmeti çift yönlü olmalıdır: istemciden sunucuya ve sunucudan istemciye. Çift yönlü iletişim, HTTP istemci/sunucu istek/yanıt modeline aykırıdır ancak bir web sunucusunda çalışan bir hizmetten tarayıcıda çalışan bir web uygulamasına veri göndermek için uzun yıllar boyunca uzun yoklama gibi çeşitli çözümler geliştirilmiştir.

Daha yakın bir zamanda ise EventSource API'si yaygın olarak uygulanmaya başlandı. Bu, sunucu tarafından gönderilen etkinlikleri (bir web sunucusundan HTTP aracılığıyla bir tarayıcı istemcisine gönderilen veriler) etkinleştirir. EventSource, tek yönlü mesajlaşma için tasarlanmıştır ancak sinyal mesajları alışverişi için bir hizmet oluşturmak üzere XHR ile birlikte kullanılabilir. Bir sinyal hizmeti, XHR isteğiyle teslim edilen bir mesajı arayandan alıp EventSource üzerinden arayana iletir.

WebSocket, aynı anda iki yönde de akabilen mesajlar olan tam çift yönlü istemci-sunucu iletişimi için tasarlanmış daha doğal bir çözümdür. Tamamen WebSocket veya sunucu tarafından gönderilen etkinliklerle (EventSource) oluşturulan bir sinyal hizmetinin avantajlarından biri, bu API'lerin arka ucunun PHP, Python ve Ruby gibi diller için çoğu web barındırma paketinde yaygın olan çeşitli web çerçevelerinde uygulanabilmesidir.

Opera Mini hariç tüm modern tarayıcılar WebSocket'i destekler. Daha da önemlisi, WebRTC'yi destekleyen tüm tarayıcılar hem masaüstünde hem de mobil cihazlarda WebSocket'i destekler. İletilerin şifrelenmeden yakalanamaması ve proxy geçişiyle ilgili sorunların azaltılması için tüm bağlantılarda TLS kullanılmalıdır. (WebSocket ve proxy geçişi hakkında daha fazla bilgi için Ilya Grigorik'in High Performance Browser Networking adlı kitabındaki WebRTC bölümüne bakın.)

WebRTC istemcilerinin Ajax üzerinden bir mesajlaşma sunucusunu tekrar tekrar yoklamasını sağlayarak sinyalleşmeyi yönetmek de mümkündür ancak bu, özellikle mobil cihazlar için sorunlu olan çok sayıda gereksiz ağ isteğine yol açar. Bir oturum oluşturulduktan sonra bile, diğer eşler tarafından yapılan değişiklikler veya oturum sonlandırma durumunda eşlerin sinyal mesajları için yoklama yapması gerekir. WebRTC Book uygulama örneği, yoklama sıklığı için bazı optimizasyonlarla bu seçeneği kullanır.

Ölçek sinyali

Sinyal hizmeti, istemci başına nispeten az bant genişliği ve CPU tüketse de popüler bir uygulamanın sinyal sunucularının, farklı konumlardan gelen çok sayıda mesajı yüksek eşzamanlılık düzeyleriyle işlemesi gerekebilir. Çok fazla trafik alan WebRTC uygulamaları, önemli yükleri kaldırabilecek sinyal sunucularına ihtiyaç duyar. Burada ayrıntıya girilmemiştir ancak aşağıdakiler de dahil olmak üzere yüksek hacimli ve yüksek performanslı mesajlaşma için çeşitli seçenekler vardır:

  • Başlangıçta Jabber olarak bilinen Genişletilebilir Mesajlaşma ve Mevcudiyet Protokolü (XMPP), sinyalizasyon için kullanılabilen anlık mesajlaşma için geliştirilmiş bir protokoldür (Sunucu uygulamaları arasında ejabberd ve Openfire bulunur). Strophe.js gibi JavaScript istemcileri, çift yönlü akışı taklit etmek için BOSH'u kullanır ancak çeşitli nedenlerden dolayı BOSH, WebSocket kadar verimli olmayabilir ve aynı nedenlerden dolayı iyi ölçeklenmeyebilir.) (Konuyla ilgili olmasa da Jingle, ses ve videoyu etkinleştirmek için kullanılan bir XMPP uzantısıdır. WebRTC projesi, Jingle'ın C++ uygulaması olan libjingle kitaplığındaki ağ ve aktarım bileşenlerini kullanır.

  • ZeroMQ (TokBox'ın Rumour hizmetinde kullandığı gibi) ve OpenMQ (NullMQ, WebSocket üzerinden STOMP protokolünü kullanarak ZeroMQ kavramlarını web platformlarına uygular) gibi açık kaynak kitaplıklar.

  • WebSocket kullanan ticari bulut mesajlaşma platformları (uzun yoklamaya geri dönebilirler), örneğin Pusher, Kaazing ve PubNub (PubNub'ın WebRTC için API'si de vardır).

  • vLine gibi ticari WebRTC platformları

(Geliştirici Phil Leggetter'ın Real-Time Web Technologies Guide adlı kılavuzunda, mesajlaşma hizmetleri ve kitaplıklarının kapsamlı bir listesi yer almaktadır.)

Node'da Socket.io ile sinyal hizmeti oluşturma

Aşağıda, Node üzerinde Socket.io ile oluşturulmuş bir sinyal hizmeti kullanan basit bir web uygulamasına ait kod yer almaktadır. Socket.io'nun tasarımı, mesaj alışverişi için hizmet oluşturmayı kolaylaştırır. Socket.io, yerleşik oda kavramı sayesinde özellikle WebRTC sinyalleşmesi için uygundur. Bu örnek, üretim düzeyinde bir sinyal hizmeti olarak ölçeklenecek şekilde tasarlanmamıştır ancak nispeten az sayıda kullanıcı için anlaşılması kolaydır.

Socket.io, geri dönüşlerle WebSocket kullanır: AJAX uzun yoklama, AJAX çok parçalı akış, Forever Iframe ve JSONP yoklama. Çeşitli arka uçlara taşınmış olsa da belki de en çok bu örnekte kullanılan Node sürümüyle tanınır.

Bu örnekte WebRTC yoktur. Bu örnek yalnızca bir web uygulamasına sinyal oluşturma özelliğinin nasıl ekleneceğini göstermek için tasarlanmıştır. İstemciler bir odaya katıldığında ve mesaj alışverişinde bulunduğunda neler olduğunu görmek için konsol günlüğünü görüntüleyin. Bu WebRTC codelab'inde, bu özelliği eksiksiz bir WebRTC görüntülü sohbet uygulamasına entegre etme konusunda adım adım talimatlar verilmektedir.

Müşteri index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>WebRTC client</title>
  </head>
  <body>
    <script src='/socket.io/socket.io.js'></script>
    <script src='js/main.js'></script>
  </body>
</html>

İstemcide referans verilen JavaScript dosyası main.js:

const isInitiator;

room = prompt('Enter room name:');

const socket = io.connect();

if (room !== '') {
  console.log('Joining room ' + room);
  socket.emit('create or join', room);
}

socket.on('full', (room) => {
  console.log('Room ' + room + ' is full');
});

socket.on('empty', (room) => {
  isInitiator = true;
  console.log('Room ' + room + ' is empty');
});

socket.on('join', (room) => {
  console.log('Making request to join room ' + room);
  console.log('You are the initiator!');
});

socket.on('log', (array) => {
  console.log.apply(console, array);
});

Tam sunucu uygulaması aşağıda verilmiştir:

const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
  file.serve(req, res);
}).listen(2013);

const io = require('socket.io').listen(app);

io.sockets.on('connection', (socket) => {

  // Convenience function to log server messages to the client
  function log(){
    const array = ['>>> Message from server: '];
    for (const i = 0; i < arguments.length; i++) {
      array.push(arguments[i]);
    }
      socket.emit('log', array);
  }

  socket.on('message', (message) => {
    log('Got message:', message);
    // For a real app, would be room only (not broadcast)
    socket.broadcast.emit('message', message);
  });

  socket.on('create or join', (room) => {
    const numClients = io.sockets.clients(room).length;

    log('Room ' + room + ' has ' + numClients + ' client(s)');
    log('Request to create or join room ' + room);

    if (numClients === 0){
      socket.join(room);
      socket.emit('created', room);
    } else if (numClients === 1) {
      io.sockets.in(room).emit('join', room);
      socket.join(room);
      socket.emit('joined', room);
    } else { // max two clients
      socket.emit('full', room);
    }
    socket.emit('emit(): client ' + socket.id +
      ' joined room ' + room);
    socket.broadcast.emit('broadcast(): client ' + socket.id +
      ' joined room ' + room);

  });

});

(Bu işlem için node-static hakkında bilgi edinmeniz gerekmez. Bu örnekte yalnızca bu değer kullanılmıştır.)

Bu uygulamayı localhost'ta çalıştırmak için Node, Socket.IO ve node-static yüklü olmalıdır. Node, Node.js adresinden indirilebilir (kurulum kolay ve hızlıdır). Socket.IO ve node-static'i yüklemek için uygulama dizininizdeki bir terminalden Node Package Manager'ı çalıştırın:

npm install socket.io
npm install node-static

Sunucuyu başlatmak için uygulama dizininizdeki bir terminalden aşağıdaki komutu çalıştırın:

node server.js

Tarayıcınızda localhost:2013 adresini açın. Herhangi bir tarayıcıda yeni bir sekme veya pencere açın ve localhost:2013 simgesini tekrar açın. Ne olduğunu görmek için konsolu kontrol edin. Chrome ve Opera'da, Ctrl+Shift+J (veya Mac'te Command+Option+J) tuşlarına basarak Google Chrome Geliştirici Araçları üzerinden konsola erişebilirsiniz.

Sinyal verme için hangi yaklaşımı seçerseniz seçin, arka ucunuz ve istemci uygulamanız en azından bu örneğe benzer hizmetler sağlamalıdır.

Sinyalle ilgili dikkat edilmesi gereken noktalar

  • RTCPeerConnection, setLocalDescription() çağrılana kadar adayları toplamaya başlamaz. Bu, JSEP IETF taslağında zorunlu kılınmıştır.
  • Trickle ICE'dan yararlanın. Adaylar geldiğinde addIceCandidate() numaralı telefonu arayın.

Hazır sinyal sunucuları

Kendi sunucunuzu oluşturmak istemiyorsanız önceki örnekteki gibi Socket.IO kullanan ve WebRTC istemci JavaScript kitaplıklarıyla entegre olan çeşitli WebRTC sinyal sunucuları mevcuttur:

  • webRTC.io, WebRTC için ilk soyutlama kitaplıklarından biridir.
  • Signalmaster, SimpleWebRTC JavaScript istemci kitaplığıyla kullanılmak üzere oluşturulmuş bir sinyal sunucusudur.

Hiç kod yazmak istemiyorsanız vLine, OpenTok ve Asterisk gibi şirketlerin sunduğu eksiksiz ticari WebRTC platformlarını kullanabilirsiniz.

Ericsson, WebRTC'nin ilk günlerinde Apache'de PHP kullanarak bir sinyal sunucusu oluşturmuştu. Bu yöntem artık biraz eski olsa da benzer bir şey düşünüyorsanız koda göz atmanız faydalı olabilir.

Sinyal güvenliği

"Güvenlik, hiçbir şeyin olmamasını sağlama sanatıdır."

Salman Rushdie

Şifreleme, tüm WebRTC bileşenleri için zorunludur.

Ancak sinyal mekanizmaları WebRTC standartlarıyla tanımlanmadığından sinyalleşmeyi güvenli hale getirmek sizin sorumluluğunuzdadır. Saldırganlar sinyalleri ele geçirmeyi başarırsa oturumları durdurabilir, bağlantıları yönlendirebilir ve içerikleri kaydedebilir, değiştirebilir veya ekleyebilir.

Sinyalleşmenin güvenliğini sağlamanın en önemli faktörü, iletilerin şifrelenmeden yakalanamamasını sağlayan güvenli protokoller (ör. TLS) olan HTTPS ve WSS'yi kullanmaktır. Ayrıca, sinyal mesajlarını aynı sinyal sunucusunu kullanan diğer arayanlar tarafından erişilebilecek şekilde yayınlamamaya dikkat edin.

Sinyalden sonra: NAT'ler ve güvenlik duvarlarıyla başa çıkmak için ICE'yi kullanma

WebRTC uygulamaları, meta veri sinyalleri için bir aracı sunucu kullanır. Ancak bir oturum oluşturulduktan sonra gerçek medya ve veri akışı için RTCPeerConnection, istemcileri doğrudan veya eşler arası olarak bağlamaya çalışır.

Daha basit bir dünyada, her WebRTC uç noktasının doğrudan iletişim kurmak için diğer eşlerle değiştirebileceği benzersiz bir adresi olurdu.

Basit eşler arası bağlantı
NAT'lerin ve güvenlik duvarlarının olmadığı bir dünya

Gerçekte çoğu cihaz bir veya daha fazla NAT katmanının arkasında bulunur. Bazılarında belirli bağlantı noktalarını ve protokolleri engelleyen virüsten koruma yazılımları vardır. Birçoğu da proxy'lerin ve kurumsal güvenlik duvarlarının arkasındadır. Güvenlik duvarı ve NAT, evdeki kablosuz yönlendirici gibi aynı cihaz tarafından uygulanabilir.

NAT&#39;lerin ve güvenlik duvarlarının arkasındaki eşler
Gerçek dünya

WebRTC uygulamaları, gerçek dünyadaki ağ oluşturmanın karmaşıklıklarının üstesinden gelmek için ICE çerçevesini kullanabilir. Bunun gerçekleşmesi için uygulamanızın, bu makalede açıklandığı gibi ICE sunucu URL'lerini RTCPeerConnection'ya iletmesi gerekir.

ICE, eşleri bağlamak için en iyi yolu bulmaya çalışır. Tüm olasılıkları paralel olarak dener ve işe yarayan en verimli seçeneği belirler. ICE, önce bir cihazın işletim sisteminden ve ağ kartından alınan ana makine adresini kullanarak bağlantı kurmaya çalışır. Bu işlem başarısız olursa (NAT'ların arkasındaki cihazlarda başarısız olur) ICE, STUN sunucusu kullanarak harici bir adres alır. Bu işlem de başarısız olursa trafik, TURN geçiş sunucusu üzerinden yönlendirilir.

Diğer bir deyişle, STUN sunucusu harici bir ağ adresi almak için kullanılır ve doğrudan (eşler arası) bağlantı başarısız olursa trafiği yönlendirmek için TURN sunucuları kullanılır.

Her TURN sunucusu STUN'u destekler. TURN sunucusu, ek yerleşik yönlendirme işlevine sahip bir STUN sunucusudur. ICE, NAT kurulumlarının karmaşıklığıyla da başa çıkar. Gerçekte, NAT delme işlemi için herkese açık IP:bağlantı noktası adresinden daha fazlası gerekebilir.

STUN ve/veya TURN sunucularının URL'leri, iceServers yapılandırma nesnesinde (isteğe bağlı olarak) bir WebRTC uygulaması tarafından belirtilir. Bu nesne, RTCPeerConnection oluşturucusunun ilk bağımsız değişkenidir. appr.tc için bu değer şu şekilde görünür:

{
  'iceServers': [
    {
      'urls': 'stun:stun.l.google.com:19302'
    },
    {
      'urls': 'turn:192.158.29.39:3478?transport=udp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    },
    {
      'urls': 'turn:192.158.29.39:3478?transport=tcp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    }
  ]
}

RTCPeerConnection bu bilgilere sahip olduğunda ICE otomatik olarak gerçekleşir. RTCPeerConnection, STUN ve TURN sunucularıyla gerektiği şekilde çalışarak eşler arasındaki en iyi yolu belirlemek için ICE çerçevesini kullanır.

STUN

NAT'ler, bir cihaza özel bir yerel ağda kullanılmak üzere IP adresi sağlar ancak bu adres harici olarak kullanılamaz. Herkese açık adres olmadan WebRTC eşlerinin iletişim kurması mümkün değildir. WebRTC, bu sorunu çözmek için STUN kullanır.

STUN sunucuları, herkese açık internette bulunur ve tek bir basit görevi vardır: Gelen bir isteğin (NAT'ın arkasında çalışan bir uygulamadan) IP:bağlantı noktası adresini kontrol edip bu adresi yanıt olarak geri göndermek. Diğer bir deyişle, uygulama IP:bağlantı noktasını genel bir bakış açısıyla keşfetmek için bir STUN sunucusu kullanır. Bu işlem, bir WebRTC eşinin kendisi için herkese açık bir adres almasını ve ardından doğrudan bağlantı oluşturmak üzere bu adresi bir sinyal mekanizması aracılığıyla başka bir eşe iletmesini sağlar. (Uygulamada, farklı NAT'ler farklı şekillerde çalışır ve birden fazla NAT katmanı olabilir ancak prensip aynıdır.)

STUN sunucularının çok fazla işlem yapması veya çok fazla şey hatırlaması gerekmez. Bu nedenle, nispeten düşük özellikli STUN sunucuları çok sayıda isteği işleyebilir.

Webrtcstats.com'a göre WebRTC görüşmelerinin çoğu (%86) STUN kullanarak başarılı bir şekilde bağlantı kurar. Ancak bu oran, güvenlik duvarlarının ve karmaşık NAT yapılandırmalarının arkasındaki eşler arasındaki görüşmelerde daha düşük olabilir.

STUN sunucusu kullanarak eşler arası bağlantı
Genel IP:bağlantı noktası adreslerini almak için STUN sunucularını kullanma

TURN

RTCPeerConnection, UDP üzerinden eşler arasında doğrudan iletişim kurmaya çalışır. Bu başarısız olursa RTCPeerConnection, TCP'ye başvurur. Bu başarısız olursa TURN sunucuları, uç noktalar arasında veri aktararak yedek olarak kullanılabilir.

Tekrar hatırlatmak gerekirse TURN, sinyal verileri için değil, eşler arasında ses, görüntü ve veri akışını aktarmak için kullanılır.

TURN sunucularının herkese açık adresleri vardır. Bu nedenle, eşler güvenlik duvarlarının veya proxy'lerin arkasında olsa bile eşler tarafından iletişime geçilebilir. TURN sunucularının kavramsal olarak basit bir görevi vardır: akışı aktarmak. Ancak STUN sunucularının aksine, doğası gereği çok fazla bant genişliği tüketirler. Yani TURN sunucularının daha güçlü olması gerekir.

STUN sunucusu kullanarak eşler arası bağlantı
The full Monty: STUN, TURN, and signaling

Bu şemada TURN'ün nasıl çalıştığı gösterilmektedir. Salt STUN başarılı olmadığından her eş, TURN sunucusu kullanmaya başvurur.

STUN ve TURN sunucularını dağıtma

Google, test için appr.tc tarafından kullanılan stun.l.google.com:19302 adlı herkese açık bir STUN sunucusu çalıştırır. Üretim STUN/TURN hizmeti için rfc5766-turn-server'ı kullanın. STUN ve TURN sunucularının kaynak kodunu GitHub'da bulabilirsiniz. Sunucu kurulumuyla ilgili çeşitli bilgi kaynaklarına bağlantılar da burada yer alır. Amazon Web Services için VM görüntüsü de mevcuttur.

Alternatif bir TURN sunucusu olan restund, kaynak kodu olarak ve AWS için kullanılabilir. Aşağıda, Compute Engine'de restund'un nasıl ayarlanacağına ilişkin talimatlar verilmiştir.

  1. Gerekirse tcp=443, udp/tcp=3478 için güvenlik duvarını açın.
  2. Her biri herkese açık IP için olmak üzere dört örnek oluşturun (Standart Ubuntu 12.06 görüntüsü).
  3. Yerel güvenlik duvarı yapılandırmasını ayarlayın (HERHANGİ BİRİNDEN HERHANGİ BİRİNE izin verin).
  4. Yükleme araçları: shell sudo apt-get install make sudo apt-get install gcc
  5. Libre'yi creytiv.com/re.html adresinden yükleyin.
  6. creytiv.com/restund.html adresinden restund'u getirin ve dosyayı açın.
  7. wget hancke.name/restund-auth.patch adresine gidin ve patch -p1 < restund-auth.patch ile uygulayın.
  8. Libre ve restund için make, sudo make install komutlarını çalıştırın.
  9. restund.conf öğesini ihtiyaçlarınıza göre uyarlayın (IP adreslerini değiştirin ve aynı paylaşılan gizli diziyi içerdiğinden emin olun) ve /etc öğesine kopyalayın.
  10. restund/etc/restund dosyasını /etc/init.d/ klasörüne kopyalayın.
  11. restund'u yapılandırın:
    1. LD_LIBRARY_PATH olarak ayarlayın.
    2. restund.conf dosyasını /etc/restund.conf klasörüne kopyalayın.
    3. Doğru 10'u kullanmak için restund.conf öğesini ayarlayın. IP adresi.
  12. restund'u çalıştırma
  13. Uzak makineden stund istemcisini kullanarak test edin: ./client IP:port

Bire bir görüşmenin ötesinde: Çok taraflı WebRTC

Justin Uberti'nin TURN hizmetlerine erişim için REST API ile ilgili IETF standardı önerisine de göz atmak isteyebilirsiniz.

Medya akışının, basit bir bire bir görüşmenin ötesine geçen kullanım alanlarını hayal etmek kolaydır. Örneğin, bir grup iş arkadaşı arasındaki video konferans veya bir konuşmacının yer aldığı ve yüzlerce ya da milyonlarca izleyicinin katıldığı herkese açık bir etkinlik.

Bir WebRTC uygulaması, her uç noktanın bir örgü yapılandırmasında diğer her uç noktaya bağlanması için birden fazla RTCPeerConnection kullanabilir. talky.io gibi uygulamalar bu yaklaşımı kullanır ve az sayıda kişiyle oldukça iyi çalışır. Bunun dışında, özellikle mobil istemciler için işleme ve bant genişliği tüketimi aşırı hale gelir.

Örgü: Küçük N taraflı görüşme
Tam örgü topolojisi: Herkes herkesle bağlantılıdır

Alternatif olarak, bir WebRTC uygulaması, akışları yıldız yapılandırmasındaki diğer tüm uç noktalara dağıtmak için bir uç nokta seçebilir. Ayrıca, bir sunucuda WebRTC uç noktası çalıştırabilir ve kendi yeniden dağıtım mekanizmanızı oluşturabilirsiniz (webrtc.org tarafından örnek bir istemci uygulaması sağlanır).

Chrome 31 ve Opera 18'den itibaren bir RTCPeerConnection'den gelen MediaStream, başka bir RTCPeerConnection için giriş olarak kullanılabilir. Bu, bir web uygulamasının hangi diğer eşe bağlanacağını seçerek çağrı yönlendirmeyi yönetmesini sağladığından daha esnek mimarilere olanak tanıyabilir. Bunu uygulamada görmek için WebRTC örnekleri Eş bağlantı aktarımı ve WebRTC örnekleri Birden fazla eş bağlantı bölümlerini inceleyin.

Çok Noktalı Kontrol Birimi

Çok sayıda uç nokta için daha iyi bir seçenek, Çok Noktalı Kontrol Birimi (MCU) kullanmaktır. Bu, çok sayıda katılımcı arasında medyayı dağıtmak için köprü görevi gören bir sunucudur. MCU'lar, bir video konferansta farklı çözünürlükler, codec'ler ve kare hızlarıyla başa çıkabilir; kod dönüştürmeyi yönetebilir; seçici akış yönlendirme yapabilir; ses ve videoyu karıştırabilir veya kaydedebilir. Çok taraflı görüşmelerde dikkate alınması gereken çeşitli sorunlar vardır. Özellikle birden fazla video girişinin nasıl görüntüleneceği ve birden fazla kaynaktan gelen seslerin nasıl karıştırılacağı bu sorunlar arasındadır. vLine gibi bulut platformları da trafik yönlendirmeyi optimize etmeye çalışır.

İsterseniz eksiksiz bir MCU donanım paketi satın alabilir, isterseniz kendi paketinizi oluşturabilirsiniz.

Cisco MCU5300&#39;ün arka görünümü
Cisco MCU'nun arka tarafı

Çeşitli açık kaynak MCU yazılım seçenekleri mevcuttur. Örneğin, Licode (önceki adı Lynckia), WebRTC için açık kaynaklı bir MCU üretir. OpenTok'ta Mantis bulunur.

Tarayıcıların ötesinde: VoIP, telefonlar ve mesajlaşma

WebRTC'nin standartlaştırılmış yapısı, tarayıcıda çalışan bir WebRTC uygulaması ile başka bir iletişim platformunda (ör. telefon veya video konferans sistemi) çalışan bir cihaz ya da platform arasında iletişim kurulmasını mümkün kılar.

SIP, VoIP ve video konferans sistemleri tarafından kullanılan bir sinyal protokolüdür. WebRTC web uygulaması ile video konferans sistemi gibi bir SIP istemcisi arasında iletişimi etkinleştirmek için WebRTC'nin sinyalleşmeye aracılık edecek bir proxy sunucusuna ihtiyacı vardır. Sinyalizasyon, ağ geçidinden geçmelidir ancak iletişim kurulduktan sonra SRTP trafiği (video ve ses) doğrudan eşler arası olarak akabilir.

Sabit telefon şebekesi (PSTN), tüm "normal" analog telefonların devre anahtarlamalı ağıdır. WebRTC web uygulamaları ile telefonlar arasındaki aramalarda trafiğin PSTN ağ geçidinden geçmesi gerekir. Aynı şekilde, WebRTC web uygulamalarının da Jingle uç noktaları (ör. anlık mesajlaşma istemcileri) ile iletişim kurmak için bir aracı XMPP sunucusuna ihtiyacı vardır. Jingle, Google tarafından XMPP'ye ek olarak geliştirilmiş olup mesajlaşma hizmetlerinde ses ve video özelliklerini etkinleştirir. Mevcut WebRTC uygulamaları, başlangıçta Talk için geliştirilen bir Jingle uygulaması olan C++ libjingle kitaplığına dayanmaktadır.

Birçok uygulama, kitaplık ve platform, WebRTC'nin dış dünyayla iletişim kurma özelliğinden yararlanır:

  • sipML5: Açık kaynaklı bir JavaScript SIP istemcisi
  • jsSIP: JavaScript SIP kitaplığı
  • Phono: Eklenti olarak oluşturulmuş açık kaynaklı JavaScript telefon API'si
  • Zingaya: yerleştirilebilir bir telefon widget'ı
  • Twilio: Ses ve mesajlaşma
  • Uberconference: konferans

sipML5 geliştiricileri, webrtc2sip ağ geçidini de oluşturmuştur. Tethr ve Tropo, WebRTC aracılığıyla özellikli telefonlar ve bilgisayarlar arasında iletişimi sağlamak için OpenBTS hücresini kullanarak afet iletişimi için bir çerçeve "bir evrak çantasında" gösterdi. Bu, operatörsüz telefon iletişimidir.

Daha fazla bilgi

WebRTC codelab'i, Node üzerinde çalışan bir Socket.io sinyal hizmetini kullanarak video ve metin sohbet uygulaması oluşturmayla ilgili adım adım talimatlar sağlar.

WebRTC teknik yöneticisi Justin Uberti ile 2013'teki Google I/O WebRTC sunumu

Chris Wilson'ın SFHTML5 sunumu - Introduction to WebRTC Apps (WebRTC Uygulamalarına Giriş)

350 sayfalık WebRTC: APIs and RTCWEB Protocols of the HTML5 Real-Time Web adlı kitapta veri ve sinyal yolları hakkında birçok ayrıntı verilmekte ve ayrıntılı ağ topolojisi diyagramları yer almaktadır.

WebRTC ve Sinyalleşme: İki Yılda Ne Öğrendik? - Sinyalleşmeyi spesifikasyonun dışında bırakmanın neden iyi bir fikir olduğuna dair TokBox blog yayını

Ben Strong'un A Practical Guide to Building WebRTC Apps (WebRTC Uygulamaları Oluşturmayla İlgili Pratik Bir Kılavuz) adlı kitabı, WebRTC topolojileri ve altyapısı hakkında birçok bilgi sunar.

Ilya Grigorik'in High Performance Browser Networking adlı kitabındaki WebRTC bölümünde WebRTC mimarisi, kullanım alanları ve performansı ayrıntılı olarak ele alınıyor.