পিয়ার সংযোগ হলো WebRTC স্পেসিফিকেশনের অংশ যা পিয়ার-টু-পিয়ার প্রোটোকল ব্যবহার করে যোগাযোগের জন্য বিভিন্ন কম্পিউটারে দুটি অ্যাপ্লিকেশনকে সংযুক্ত করার সাথে সম্পর্কিত। পিয়ারদের মধ্যে যোগাযোগ ভিডিও, অডিও বা ইচ্ছামত বাইনারি ডেটা হতে পারে ( RTCDataChannel API সমর্থনকারী ক্লায়েন্টদের জন্য)। দুটি পিয়ার কীভাবে সংযোগ করতে পারে তা আবিষ্কার করার জন্য, উভয় ক্লায়েন্টকে একটি ICE সার্ভার কনফিগারেশন প্রদান করতে হবে। এটি হয় একটি STUN অথবা একটি TURN-সার্ভার, এবং তাদের ভূমিকা হল প্রতিটি ক্লায়েন্টকে ICE প্রার্থী প্রদান করা যা পরে দূরবর্তী পিয়ারে স্থানান্তরিত হয়। ICE প্রার্থীদের এই স্থানান্তরকে সাধারণত সিগন্যালিং বলা হয়।
সংকেত
WebRTC স্পেসিফিকেশনে একটি ICE (ইন্টারনেট কানেক্টিভিটি এস্টাবলিশমেন্ট) সার্ভারের সাথে যোগাযোগের জন্য API অন্তর্ভুক্ত থাকে, কিন্তু সিগন্যালিং উপাদানটি এর অংশ নয়। দুটি পিয়ার কীভাবে সংযোগ করবে তা ভাগ করে নেওয়ার জন্য সিগন্যালিং প্রয়োজন। সাধারণত এটি একটি নিয়মিত HTTP-ভিত্তিক ওয়েব API (অর্থাৎ, একটি REST পরিষেবা বা অন্যান্য RPC প্রক্রিয়া) এর মাধ্যমে সমাধান করা হয় যেখানে ওয়েব অ্যাপ্লিকেশনগুলি পিয়ার সংযোগ শুরু হওয়ার আগে প্রয়োজনীয় তথ্য রিলে করতে পারে।
নিম্নলিখিত কোড স্নিপেটটি দেখায় যে কীভাবে এই কাল্পনিক সিগন্যালিং পরিষেবাটি অ্যাসিঙ্ক্রোনাসভাবে বার্তা প্রেরণ এবং গ্রহণ করতে ব্যবহার করা যেতে পারে। প্রয়োজনে এই নির্দেশিকার বাকি উদাহরণগুলিতে এটি ব্যবহার করা হবে।
// 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 তৈরি হয়ে গেলে আমাদের একটি SDP অফার বা উত্তর তৈরি করতে হবে, যা নির্ভর করে আমরা কলিং পিয়ার নাকি রিসিভিং পিয়ার তার উপর। SDP অফার বা উত্তর তৈরি হয়ে গেলে, এটি একটি ভিন্ন চ্যানেলের মাধ্যমে রিমোট পিয়ারের কাছে পাঠাতে হবে। রিমোট পিয়ারের কাছে SDP অবজেক্ট পাঠানোকে সিগন্যালিং বলা হয় এবং এটি WebRTC স্পেসিফিকেশনের আওতাভুক্ত নয়।
কলিং পাশ থেকে পিয়ার কানেকশন সেটআপ শুরু করার জন্য, আমরা একটি RTCPeerConnection অবজেক্ট তৈরি করি এবং তারপর createOffer() কল করে একটি RTCSessionDescription অবজেক্ট তৈরি করি। এই সেশনের বর্ণনাটি 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 প্রার্থীদের সংগ্রহ করতে হবে এবং (সিগন্যালিং চ্যানেলের মাধ্যমে) অন্য পিয়ারে স্থানান্তর করতে হবে।
আইসিই প্রার্থীরা
WebRTC ব্যবহার করে দুইজন সহকর্মী যোগাযোগ করার আগে, তাদের সংযোগ তথ্য বিনিময় করতে হবে। যেহেতু নেটওয়ার্কের অবস্থা বিভিন্ন কারণের উপর নির্ভর করে পরিবর্তিত হতে পারে, তাই সাধারণত একটি সহকর্মীর সাথে সংযোগ স্থাপনের জন্য সম্ভাব্য প্রার্থীদের খুঁজে বের করার জন্য একটি বহিরাগত পরিষেবা ব্যবহার করা হয়। এই পরিষেবাটিকে ICE বলা হয় এবং এটি একটি STUN অথবা একটি TURN সার্ভার ব্যবহার করে। STUN মানে NAT-এর জন্য Session Traversal Utilities, এবং সাধারণত বেশিরভাগ WebRTC অ্যাপ্লিকেশনে পরোক্ষভাবে ব্যবহৃত হয়।
TURN (Traversal Using Relay NAT) হল আরও উন্নত সমাধান যা STUN প্রোটোকলগুলিকে অন্তর্ভুক্ত করে এবং বেশিরভাগ বাণিজ্যিক WebRTC ভিত্তিক পরিষেবাগুলি পিয়ারদের মধ্যে সংযোগ স্থাপনের জন্য একটি TURN সার্ভার ব্যবহার করে। WebRTC API সরাসরি STUN এবং TURN উভয়কেই সমর্থন করে এবং এটি আরও সম্পূর্ণ ইন্টারনেট সংযোগ স্থাপনের অধীনে সংগ্রহ করা হয়। একটি WebRTC সংযোগ তৈরি করার সময়, আমরা সাধারণত RTCPeerConnection অবজেক্টের জন্য কনফিগারেশনে এক বা একাধিক ICE সার্ভার সরবরাহ করি।
ট্রিকল আইসিই
একবার একটি RTCPeerConnection অবজেক্ট তৈরি হয়ে গেলে, অন্তর্নিহিত ফ্রেমওয়ার্কটি সংযোগ স্থাপনের জন্য প্রার্থীদের (ICE প্রার্থীদের) সংগ্রহ করতে প্রদত্ত ICE সার্ভার ব্যবহার করে। RTCPeerConnection এ icegatheringstatechange ইভেন্টটি ICE সংগ্রহটি কোন অবস্থায় রয়েছে ( new , gathering বা complete ) তা নির্দেশ করে।
যদিও একজন পিয়ারের পক্ষে ICE সংগ্রহ সম্পূর্ণ না হওয়া পর্যন্ত অপেক্ষা করা সম্ভব, তবে সাধারণত "ট্রিকল আইস" কৌশল ব্যবহার করা এবং প্রতিটি ICE প্রার্থীকে আবিষ্কৃত হওয়ার সাথে সাথে দূরবর্তী পিয়ারে প্রেরণ করা অনেক বেশি কার্যকর। এটি পিয়ার সংযোগের জন্য সেটআপ সময় উল্লেখযোগ্যভাবে হ্রাস করবে এবং কম বিলম্বের সাথে একটি ভিডিও কল শুরু করার অনুমতি দেবে।
ICE প্রার্থীদের সংগ্রহ করতে, কেবল 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);
}
}
});
সংযোগ স্থাপন করা হয়েছে
ICE প্রার্থীদের গ্রহণের পর, আমাদের আশা করা উচিত যে আমাদের পিয়ার সংযোগের অবস্থা অবশেষে একটি সংযুক্ত অবস্থায় পরিবর্তিত হবে। এটি সনাক্ত করার জন্য, আমরা আমাদের RTCPeerConnection এ একটি শ্রোতা যোগ করি যেখানে আমরা connectionstatechange ইভেন্টগুলি শুনি।
// Listen for connectionstatechange on the local RTCPeerConnection
peerConnection.addEventListener('connectionstatechange', event => {
if (peerConnection.connectionState === 'connected') {
// Peers connected!
}
});