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

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

سیگنال دهی

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

مستندات API RTCPeerConnection

،

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

سیگنال دهی

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

مستندات API RTCPeerConnection