شروع با اتصالات همتا

اتصالات همتا بخشی از مشخصات WebRTC است که با اتصال دو برنامه در رایانه های مختلف برای برقراری ارتباط با استفاده از پروتکل همتا به همتا سروکار دارد. ارتباط بین همتایان می تواند ویدئویی، صوتی یا داده های باینری دلخواه باشد (برای مشتریانی که از RTCDataChannel API پشتیبانی می کنند). برای کشف نحوه اتصال دو همتا، هر دو سرویس گیرنده باید یک پیکربندی ICE Server ارائه دهند. این یا یک STUN یا یک سرور TURN است، و نقش آنها ارائه کاندیدهای ICE به هر مشتری است که سپس به همتای راه دور منتقل می شود. این انتقال نامزدهای ICE معمولاً سیگنالینگ نامیده می شود.

سیگنالینگ

مشخصات WebRTC شامل APIهایی برای ارتباط با یک سرور ICE (ایجاد اتصال به اینترنت) است، اما جزء سیگنالینگ بخشی از آن نیست. سیگنالینگ مورد نیاز است تا دو همتا بتوانند نحوه اتصال خود را به اشتراک بگذارند. معمولاً این مشکل از طریق یک Web API معمولی مبتنی بر HTTP (به عنوان مثال، یک سرویس 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 را در هر همتا جمع آوری کنیم و (از طریق کانال سیگنالینگ) به همتای دیگر منتقل کنیم.

نامزدهای ICE

قبل از اینکه دو همتا بتوانند با استفاده از WebRTC ارتباط برقرار کنند، نیاز به تبادل اطلاعات اتصال دارند. از آنجایی که شرایط شبکه می تواند بسته به عوامل متعددی متفاوت باشد، معمولاً از یک سرویس خارجی برای کشف نامزدهای احتمالی برای اتصال به همتا استفاده می شود. این سرویس ICE نام دارد و از سرور STUN یا TURN استفاده می کند. STUN مخفف Session Traversal Utilities برای NAT است و معمولاً به طور غیر مستقیم در اکثر برنامه های WebRTC استفاده می شود.

TURN (Traversal Using Relay NAT) راه حل پیشرفته تری است که پروتکل های STUN را در خود جای داده است و اکثر سرویس های تجاری مبتنی بر WebRTC از سرور TURN برای ایجاد ارتباط بین همتایان استفاده می کنند. WebRTC API از STUN و TURN به طور مستقیم پشتیبانی می کند و تحت عنوان کاملتر ایجاد اتصال به اینترنت جمع آوری شده است. هنگام ایجاد یک اتصال WebRTC، ما معمولا یک یا چند سرور ICE را در پیکربندی برای شی RTCPeerConnection می کنیم.

قطره یخ

هنگامی که یک شی RTCPeerConnection ایجاد می شود، چارچوب زیربنایی از سرورهای ICE ارائه شده برای جمع آوری نامزدها برای ایجاد اتصال (کاندیداهای ICE) استفاده می کند. رویداد icegatheringstatechange در RTCPeerConnection سیگنال می‌دهد که تجمع 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!
    }
});

اسناد RTCPeerConnection API