Eş bağlantıları, farklı bilgisayarlardaki iki uygulamayı eşler arası protokol kullanarak iletişim kuracak şekilde bağlamayla ilgili WebRTC spesifikasyonlarının bir parçasıdır. Eşler arasındaki iletişim video, ses veya rastgele ikili veriler (RTCDataChannel API'sini destekleyen istemciler için) olabilir. İki eşin nasıl bağlanabileceğini öğrenmek için her iki istemcinin de bir ICE sunucusu yapılandırması sağlaması gerekir. Bu, STUN veya TURN sunucusudur ve rolü, her istemciye ICE adayları sağlamaktır. Bu adaylar daha sonra uzak tarafa aktarılır. ICE adaylarının bu şekilde aktarılmasına genellikle sinyalleşme adı verilir.
Sinyal
WebRTC spesifikasyonu, bir ICE (Internet Connectivity Establishment) sunucusuyla iletişim kurmaya yönelik API'ler içerir ancak sinyal bileşeni bu spesifikasyonun bir parçası değildir. İki eşin nasıl bağlanmaları gerektiğini paylaşabilmeleri için sinyalizasyon gerekir. Bu sorun genellikle, web uygulamalarının eş bağlantısı başlatılmadan önce gerekli bilgileri iletebileceği normal bir HTTP tabanlı Web API'si (ör. REST hizmeti veya başka bir RPC mekanizması) aracılığıyla çözülür.
Aşağıdaki kod snippet'inde, bu kurgusal sinyal hizmetinin mesajları eşzamansız olarak göndermek ve almak için nasıl kullanılabileceği gösterilmektedir. Bu, bu kılavuzdaki diğer örneklerde gerektiğinde kullanılacaktır.
// Set up an asynchronous communication channel that will be
// used during the peer connection setup
const signalingChannel = new SignalingChannel(remoteClientId);
signalingChannel.addEventListener('message', message => {
// New message from remote client received
});
// Send an asynchronous message to the remote client
signalingChannel.send('Hello!');
Sinyalleşme birçok farklı şekilde uygulanabilir ve WebRTC spesifikasyonu belirli bir çözümü tercih etmez.
Eş bağlantıları başlatma
Her eş bağlantısı bir RTCPeerConnection nesnesi tarafından işlenir. Bu sınıfın oluşturucusu, parametre olarak tek bir RTCConfiguration nesnesi alır. Bu nesne, eş bağlantısının nasıl kurulduğunu tanımlar ve kullanılacak ICE sunucuları hakkında bilgi içermelidir.
RTCPeerConnection oluşturulduktan sonra, arayan eş veya alıcı eş olmamıza bağlı olarak bir SDP teklifi ya da yanıtı oluşturmamız gerekir. SDP teklifi veya yanıtı oluşturulduktan sonra farklı bir kanal üzerinden uzak tarafa gönderilmelidir. SDP nesnelerini uzak eşlere iletmeye sinyalleşme denir ve bu işlem WebRTC spesifikasyonunda yer almaz.
Arayan tarafta eşler arası bağlantı kurulumunu başlatmak için RTCPeerConnection nesnesi oluştururuz ve ardından RTCSessionDescription nesnesi oluşturmak için createOffer() işlevini çağırırız. Bu oturum açıklaması, setLocalDescription() kullanılarak yerel açıklama olarak ayarlanır ve ardından sinyal kanalımız üzerinden alıcı tarafa gönderilir. Ayrıca, sunulan oturum açıklamamızın yanıtı alıcı taraftan alındığında sinyal kanalımızı dinleyecek bir dinleyici de ayarladık.
async function makeCall() {
const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]}
const peerConnection = new RTCPeerConnection(configuration);
signalingChannel.addEventListener('message', async message => {
if (message.answer) {
const remoteDesc = new RTCSessionDescription(message.answer);
await peerConnection.setRemoteDescription(remoteDesc);
}
});
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
signalingChannel.send({'offer': offer});
}
Alıcı tarafta, RTCPeerConnection örneğimizi oluşturmadan önce gelen teklifi bekleriz. Bu işlem tamamlandıktan sonra, alınan teklifi setRemoteDescription() kullanarak ayarlıyoruz. Ardından, alınan teklife yanıt oluşturmak için createAnswer() işlevini çağırırız. Bu yanıt, setLocalDescription() kullanılarak yerel açıklama olarak ayarlanır ve ardından sinyal sunucumuz üzerinden arayan tarafa gönderilir.
const peerConnection = new RTCPeerConnection(configuration);
signalingChannel.addEventListener('message', async message => {
if (message.offer) {
peerConnection.setRemoteDescription(new RTCSessionDescription(message.offer));
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
signalingChannel.send({'answer': answer});
}
});
İki eş, hem yerel hem de uzak oturum açıklamalarını ayarladıktan sonra uzak eşin özelliklerini bilir. Bu, eşler arasındaki bağlantının hazır olduğu anlamına gelmez. Bunun çalışması için her eşte ICE adaylarını toplamamız ve diğer eşe (sinyal kanalı üzerinden) aktarmamız gerekir.
ICE adayları
İki eşin WebRTC kullanarak iletişim kurabilmesi için bağlantı bilgilerini paylaşmaları gerekir. Ağ koşulları çeşitli faktörlere bağlı olarak değişebileceğinden, genellikle bir eşe bağlanabilecek olası adayları keşfetmek için harici bir hizmet kullanılır. Bu hizmete ICE adı verilir ve STUN veya TURN sunucusu kullanılır. STUN, NAT için Oturum Geçişi Yardımcı Programları anlamına gelir ve genellikle çoğu WebRTC uygulamasında dolaylı olarak kullanılır.
TURN (Traversal Using Relay NAT), STUN protokollerini içeren daha gelişmiş bir çözümdür ve çoğu ticari WebRTC tabanlı hizmet, eşler arasında bağlantı kurmak için bir TURN sunucusu kullanır. WebRTC API, hem STUN'ı hem de TURN'ü doğrudan destekler ve daha kapsamlı bir terim olan İnternet Bağlantısı Kurma altında toplanır. WebRTC bağlantısı oluştururken genellikle RTCPeerConnection nesnesinin yapılandırmasında bir veya daha fazla ICE sunucusu sağlarız.
Trickle ICE
Bir RTCPeerConnection nesnesi oluşturulduktan sonra temel alınan çerçeve, bağlantı oluşturma için adayları toplamak üzere sağlanan ICE sunucularını (ICE adayları) kullanır. RTCPeerConnection üzerindeki icegatheringstatechange etkinliği, ICE toplamanın hangi durumda olduğunu (new, gathering veya complete) gösterir.
Bir eşin ICE toplama işlemi tamamlanana kadar beklemesi mümkün olsa da genellikle "trickle ice" tekniğini kullanmak ve her ICE adayını keşfedildikçe uzak eşe iletmek çok daha verimlidir. Bu sayede eşler arası bağlantının kurulum süresi önemli ölçüde kısalır ve görüntülü görüşme daha az gecikmeyle başlatılabilir.
ICE adaylarını toplamak için icecandidate etkinliğine bir dinleyici eklemeniz yeterlidir.
Bu dinleyicide yayınlanan RTCPeerConnectionIceEvent, uzak tarafa gönderilmesi gereken yeni bir adayı temsil eden candidate özelliğini içerir (bkz. sinyal).
// Listen for local ICE candidates on the local RTCPeerConnection
peerConnection.addEventListener('icecandidate', event => {
if (event.candidate) {
signalingChannel.send({'new-ice-candidate': event.candidate});
}
});
// Listen for remote ICE candidates and add them to the local RTCPeerConnection
signalingChannel.addEventListener('message', async message => {
if (message.iceCandidate) {
try {
await peerConnection.addIceCandidate(message.iceCandidate);
} catch (e) {
console.error('Error adding received ice candidate', e);
}
}
});
Bağlantı kuruldu
ICE adayları alındıktan sonra, eş bağlantımızın durumunun sonunda bağlı duruma geçmesini beklemeliyiz. Bunu algılamak için RTCPeerConnection öğemize bir dinleyici ekliyoruz. Burada connectionstatechange etkinliklerini dinliyoruz.
// Listen for connectionstatechange on the local RTCPeerConnection
peerConnection.addEventListener('connectionstatechange', event => {
if (peerConnection.connectionState === 'connected') {
// Peers connected!
}
});