पीयर कनेक्शन, WebRTC की खास बातों का हिस्सा है. यह अलग-अलग कंप्यूटर पर मौजूद दो ऐप्लिकेशन को कनेक्ट करने से जुड़ा है, ताकि वे पीयर-टू-पीयर प्रोटोकॉल का इस्तेमाल करके कम्यूनिकेट कर सकें. पीयर के बीच बातचीत वीडियो, ऑडियो या आर्बिट्ररी बाइनरी डेटा (RTCDataChannel एपीआई के साथ काम करने वाले क्लाइंट के लिए) के ज़रिए हो सकती है. दो पियर कैसे कनेक्ट हो सकते हैं, यह जानने के लिए दोनों क्लाइंट को ICE सर्वर कॉन्फ़िगरेशन देना होगा. यह STUN या TURN-server होता है. इसकी भूमिका हर क्लाइंट को ICE कैंडिडेट उपलब्ध कराना है. इसके बाद, इसे रिमोट पीयर को ट्रांसफ़र कर दिया जाता है. आईसीई कैंडिडेट को ट्रांसफ़र करने की इस प्रोसेस को आम तौर पर सिग्नलिंग कहा जाता है.
सिग्नलिंग
WebRTC स्पेसिफ़िकेशन में, ICE (इंटरनेट कनेक्टिविटी इस्टैब्लिशमेंट) सर्वर से कम्यूनिकेट करने के लिए एपीआई शामिल हैं. हालांकि, सिग्नलिंग कॉम्पोनेंट इसका हिस्सा नहीं है. सिग्नलिंग की मदद से, दो पीयर यह तय करते हैं कि उन्हें कैसे कनेक्ट करना है. आम तौर पर, इस समस्या को एचटीटीपी पर आधारित सामान्य वेब एपीआई (जैसे, REST सेवा या अन्य आरपीसी मेकेनिज़्म) के ज़रिए हल किया जाता है. इसमें वेब ऐप्लिकेशन, पीयर कनेक्शन शुरू होने से पहले ज़रूरी जानकारी को रिले कर सकते हैं.
नीचे दिए गए कोड स्निपेट में दिखाया गया है कि इस काल्पनिक सिग्नलिंग सेवा का इस्तेमाल, मैसेज को एसिंक्रोनस तरीके से भेजने और पाने के लिए कैसे किया जा सकता है. इस गाइड में दिए गए बाकी उदाहरणों में, जहां ज़रूरी होगा वहां इसका इस्तेमाल किया जाएगा.
// 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!');
सिग्नलिंग को कई अलग-अलग तरीकों से लागू किया जा सकता है. साथ ही, WebRTC स्पेसिफ़िकेशन किसी खास समाधान को प्राथमिकता नहीं देता है.
पीयर कनेक्शन शुरू करना
हर पीयर कनेक्शन को RTCPeerConnection ऑब्जेक्ट मैनेज करता है. इस क्लास के कंस्ट्रक्टर में, RTCConfiguration ऑब्जेक्ट को पैरामीटर के तौर पर लिया जाता है. यह ऑब्जेक्ट तय करता है कि पीयर कनेक्शन कैसे सेट अप किया जाता है. इसमें इस्तेमाल किए जाने वाले ICE सर्वर के बारे में जानकारी होनी चाहिए.
RTCPeerConnection बन जाने के बाद, हमें एसडीपी ऑफ़र या जवाब बनाना होगा. यह इस बात पर निर्भर करता है कि हम कॉल करने वाले पीयर हैं या कॉल पाने वाले पीयर. एसडीपी ऑफ़र या जवाब बनाने के बाद, इसे किसी दूसरे चैनल के ज़रिए रिमोट पीयर को भेजना होगा. एसडीपी ऑब्जेक्ट को रिमोट पीयर को पास करने की प्रोसेस को सिग्नलिंग कहा जाता है. यह WebRTC स्पेसिफ़िकेशन में शामिल नहीं है.
कॉल करने वाले व्यक्ति के डिवाइस पर पीयर कनेक्शन सेटअप करने के लिए, हम RTCPeerConnection ऑब्जेक्ट बनाते हैं. इसके बाद, RTCSessionDescription ऑब्जेक्ट बनाने के लिए createOffer() को कॉल करते हैं. इस सेशन के ब्यौरे को setLocalDescription() का इस्तेमाल करके, स्थानीय ब्यौरे के तौर पर सेट किया जाता है. इसके बाद, इसे सिग्नल भेजने वाले हमारे चैनल के ज़रिए, पाने वाले पक्ष को भेजा जाता है. हम अपने सिग्नलिंग चैनल के लिए एक लिसनर भी सेट अप करते हैं. इससे हमें यह पता चलता है कि सेशन के ब्यौरे के बारे में, दूसरी पार्टी से जवाब कब मिला.
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});
}
ऑफ़र पाने वाले पक्ष के तौर पर, हम इनकमिंग ऑफ़र का इंतज़ार करते हैं. इसके बाद ही, हम अपना RTCPeerConnection इंस्टेंस बनाते हैं. इसके बाद, हम setRemoteDescription() का इस्तेमाल करके, मिले हुए ऑफ़र को सेट करते हैं. इसके बाद, मिले हुए ऑफ़र का जवाब देने के लिए, हम createAnswer() को कॉल करते हैं. इस जवाब को setLocalDescription() का इस्तेमाल करके, स्थानीय जानकारी के तौर पर सेट किया जाता है. इसके बाद, इसे कॉलर को हमारे सिग्नलिंग सर्वर के ज़रिए भेजा जाता है.
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});
}
});
जब दोनों पीयर, लोकल और रिमोट सेशन के ब्यौरे सेट कर लेते हैं, तब उन्हें रिमोट पीयर की क्षमताओं के बारे में पता चल जाता है. इसका मतलब यह नहीं है कि पीयर के बीच कनेक्शन तैयार है. इसके लिए, हमें हर पीयर पर ICE कैंडिडेट इकट्ठा करने होंगे. साथ ही, उन्हें सिग्नलिंग चैनल के ज़रिए दूसरे पीयर को ट्रांसफ़र करना होगा.
ICE के उम्मीदवार
WebRTC का इस्तेमाल करके दो पियर के बीच कम्यूनिकेशन शुरू करने से पहले, उन्हें कनेक्टिविटी की जानकारी शेयर करनी होती है. नेटवर्क की स्थितियां कई फ़ैक्टर के आधार पर अलग-अलग हो सकती हैं. इसलिए, आम तौर पर किसी बाहरी सेवा का इस्तेमाल, पीयर से कनेक्ट करने के लिए संभावित कैंडिडेट का पता लगाने के लिए किया जाता है. इस सेवा को ICE कहा जाता है. यह STUN या TURN सर्वर का इस्तेमाल करती है. STUN का मतलब है Session Traversal Utilities for NAT. इसका इस्तेमाल आम तौर पर, ज़्यादातर WebRTC ऐप्लिकेशन में सीधे तौर पर नहीं किया जाता.
टर्न (ट्रैवर्सल यूज़िंग रिले एनएटी), एक बेहतर समाधान है. इसमें STUN प्रोटोकॉल शामिल होते हैं. साथ ही, WebRTC पर आधारित ज़्यादातर कमर्शियल सेवाएं, पीयर के बीच कनेक्शन बनाने के लिए TURN सर्वर का इस्तेमाल करती हैं. WebRTC API, STUN और TURN, दोनों को सीधे तौर पर सपोर्ट करता है. साथ ही, इसे इंटरनेट कनेक्टिविटी इस्टैब्लिशमेंट के ज़्यादा सटीक शब्द के तहत इकट्ठा किया जाता है. WebRTC कनेक्शन बनाते समय, हम आम तौर पर RTCPeerConnection ऑब्जेक्ट के कॉन्फ़िगरेशन में एक या कई ICE सर्वर उपलब्ध कराते हैं.
ट्रिकल आईसीई
RTCPeerConnection ऑब्जेक्ट बन जाने के बाद, कनेक्टिविटी सेट अप करने के लिए, फ़्रेमवर्क दिए गए ICE सर्वर का इस्तेमाल करता है. इससे कनेक्टिविटी के लिए कैंडिडेट (ICE कैंडिडेट) इकट्ठा किए जाते हैं. RTCPeerConnection पर मौजूद icegatheringstatechange इवेंट से पता चलता है कि आईसीई गैदरिंग किस स्थिति में है (new, gathering या complete).
कोई पीयर, आईसीई गैदरिंग पूरी होने तक इंतज़ार कर सकता है. हालांकि, "ट्रिकल आईसीई" तकनीक का इस्तेमाल करना ज़्यादा असरदार होता है. इस तकनीक में, हर आईसीई कैंडिडेट को खोजे जाने के बाद, रिमोट पीयर को ट्रांसमिट किया जाता है. इससे पीयर कनेक्टिविटी को सेट अप करने में लगने वाला समय काफ़ी कम हो जाएगा. साथ ही, वीडियो कॉल को कम समय में शुरू किया जा सकेगा.
आईसीई कैंडिडेट इकट्ठा करने के लिए, icecandidate इवेंट के लिए लिसनर जोड़ें.
उस लिसनर पर RTCPeerConnectionIceEvent एमिट किए गए इवेंट में candidate प्रॉपर्टी शामिल होगी. यह प्रॉपर्टी, एक नए कैंडिडेट को दिखाती है जिसे रिमोट पीयर को भेजा जाना चाहिए (सिग्नलिंग देखें).
// 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);
}
}
});
कनेक्शन स्थापित
आईसीई कैंडिडेट मिलने के बाद, हमें उम्मीद करनी चाहिए कि हमारे पीयर कनेक्शन की स्थिति, कनेक्ट की गई स्थिति में बदल जाएगी. इसका पता लगाने के लिए, हम अपने RTCPeerConnection में एक लिसनर जोड़ते हैं. यहां हम connectionstatechange इवेंट सुनते हैं.
// Listen for connectionstatechange on the local RTCPeerConnection
peerConnection.addEventListener('connectionstatechange', event => {
if (peerConnection.connectionState === 'connected') {
// Peers connected!
}
});
RTCPeerConnection API के बारे में जानकारी देने वाला दस्तावेज़