ساختن سرویس‌های پس‌زمینه برنامه WebRTC

تاریخ انتشار: ۴ نوامبر ۲۰۱۳

WebRTC ارتباط همتا به همتا را فعال می‌کند. این فناوری به سرورهایی نیاز دارد تا کلاینت‌ها بتوانند فراداده‌ها را مبادله کنند و ارتباطات را ازطریق فرایندی به‌نام سیگنال‌دهی هماهنگ کنند. سرورها همچنین به مشتریان کمک می‌کنند با مترجم‌های نشانی شبکه (NAT) و دیوارهای آتش کنار بیایند.

در اینجا، نحوه ساختن سرویس سیگنال‌دهی و مقابله با مشکلات اتصال در دنیای واقعی با سرورهای STUN و TURN را یاد می‌گیرید. همچنین متوجه خواهید شد که چگونه برنامه‌های WebRTC می‌توانند تماس‌های چندطرفه را مدیریت کنند و با سرویس‌هایی مانند VoIP و PSTN (که به عنوان تلفن نیز شناخته می‌شوند) تعامل داشته باشند.

سیگنال‌دهی چیست؟

سیگنال‌دهی فرایند هماهنگ‌سازی ارتباط است. برای اینکه برنامه WebRTC بتواند تماسی را برقرار کند، کارخواه‌های آن باید اطلاعات زیر را مبادله کنند:

  • پیام‌های کنترل جلسه که برای باز یا بسته کردن ارتباط استفاده می‌شود
  • پیام‌های خطا
  • فراداده‌های رسانه، مثل کدک‌ها، تنظیمات کدک، پهنای باند، و انواع رسانه
  • داده‌های کلیدی که برای برقراری اتصال‌های امن استفاده می‌شود
  • داده‌های شبکه، مانند نشانی IP و درگاه میزبان که از دید دنیای خارج دیده می‌شود

این فرایند سیگنال‌دهی به روشی نیاز دارد تا کارخواه‌ها بتوانند پیام‌ها را ردوبدل کنند. این سازوکار توسط میاناهای برنامه‌سازی کاربردی WebRTC پیاده‌سازی نشده است. درعوض، باید خودتان آن را بسازید.

چرا سیگنال‌دهی توسط WebRTC تعریف نشده است؟

برای جلوگیری از افزونگی و به‌حداکثر رساندن سازگاری با فناوری‌های تثبیت‌شده، روش‌ها و پروتکل‌های سیگنال‌دهی توسط استانداردهای WebRTC مشخص نشده‌اند. این رویکرد توسط پروتکل ایجاد جلسه جاوا اسکریپت (JSEP) مشخص شده است:

معماری JSEP همچنین از نیاز مرورگر به ذخیره وضعیت جلوگیری می‌کند، یعنی به‌عنوان یک ماشین وضعیت سیگنال‌دهی عمل می‌کند. این امر می‌تواند مشکل‌ساز باشد، برای مثال، اگر داده‌های سیگنال‌دهی هر بار که صفحه بارگیری مجدد می‌شود ازبین برود. درعوض، وضعیت سیگنال‌دهی را می‌توان در سرور ذخیره کرد.

نمودار معماری JSEP

JSEP به تبادل بین همتاهای پیشنهاد و پاسخ، فراداده رسانه، نیاز دارد. پیشنهادها و پاسخ‌ها در قالب «پروتکل شرح جلسه» (SDP) ردوبدل می‌شوند که به این شکل است:

v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
...

می‌خواهید بدانید معنی واقعی این اصطلاحات پیچیده SDP چیست؟ به نمونه‌های «کارگروه مهندسی اینترنت» (IETF) نگاهی بیندازید.

به‌خاطر داشته باشید که WebRTC به‌گونه‌ای طراحی شده است که پیشنهاد یا پاسخ را می‌توان قبل‌از تنظیم به‌عنوان شرح محلی یا ازراه‌دور با ویرایش مقادیر در نوشتار SDP تغییر داد. برای مثال، از تابع preferAudioCodec() در appr.tc می‌توان برای تنظیم کدک و نرخ بیت پیش‌فرض استفاده کرد. دستکاری SDP با جاوا اسکریپت تا حدودی دشوار است و بحث‌هایی درباره اینکه آیا نسخه‌های آینده WebRTC باید به‌جای آن از JSON استفاده کنند وجود دارد، اما مزایایی برای ادامه استفاده از SDP وجود دارد.

RTCPeerConnection میانای برنامه‌سازی کاربردی و سیگنال‌دهی: پیشنهاد، پاسخ، و کاندیدا

RTCPeerConnection میانای برنامه‌سازی کاربردی‌ای است که برنامه‌های WebRTC برای ایجاد اتصال بین همتاها و انتقال صدا و ویدیو استفاده می‌کنند.

برای راه‌اندازی این فرایند، RTCPeerConnection دو وظیفه دارد:

  • شرایط رسانه محلی، مانند وضوح و قابلیت‌های کدک را مشخص کنید. این فراداده‌ای است که برای سازوکار پیشنهاد و پاسخ استفاده می‌شود.
  • نشانی‌های شبکه احتمالی را برای میزبان برنامه دریافت می‌کند که به آن نامزدها می‌گویند.

وقتی این داده‌های محلی مشخص شد، باید ازطریق سازوکار سیگنال‌دهی با همتای راه دور تبادل شود.

فرض کنید آلیس می‌خواهد با ایو تماس بگیرد. در اینجا سازوکار کامل پاسخ با تمام جزئیات آورده شده است:

  1. Alice یک شیء RTCPeerConnection ایجاد می‌کند.
  2. آلیس بااستفاده از روش RTCPeerConnection createOffer() پیشنهادی (شرح جلسه SDP) ایجاد می‌کند.
  3. آلیس با پیشنهادش با setLocalDescription() تماس می‌گیرد.
  4. آلیس پیشنهاد را به رشته تبدیل می‌کند و از سازوکار سیگنال‌دهی برای ارسال آن به ایو استفاده می‌کند.
  5. ایو با پیشنهاد آلیس با setRemoteDescription() تماس می‌گیرد تا RTCPeerConnection او از راه‌اندازی آلیس مطلع شود.
  6. Eve با createAnswer() تماس می‌گیرد و فراخوانی موفقیت‌آمیز برای این کار، شرح جلسه محلی (پاسخ Eve) را ارسال می‌کند.
  7. ایو با فراخوانی setLocalDescription()، پاسخ خود را به‌عنوان شرح محلی تنظیم می‌کند.
  8. سپس، ایو از سازوکار سیگنال‌دهی برای ارسال پاسخ رشته‌ای‌شده خود به آلیس استفاده می‌کند.
  9. آلیس پاسخ ایو را بااستفاده از setRemoteDescription() به‌عنوان شرح جلسه ازراه‌دور تنظیم می‌کند.

آلیس و ایو نیز باید اطلاعات شبکه را مبادله کنند. عبارت «یافتن نامزدها» به فرایند یافتن میاناهای شبکه و درگاه‌ها بااستفاده از چارچوب ICE اشاره دارد.

  1. آلیس یک شیء RTCPeerConnection با یک گرداننده onicecandidate ایجاد می‌کند.
  2. وقتی نامزدهای شبکه دردسترس قرار می‌گیرند، کنترل‌کننده فراخوانده می‌شود.
  3. در گرداننده، آلیس داده‌های نامزد رشته‌ای‌شده را ازطریق کانال سیگنال‌دهی به ایو ارسال می‌کند.
  4. وقتی Eve پیام نامزد را از Alice دریافت می‌کند، addIceCandidate() را فراخوانی می‌کند تا نامزد را به شرح همتای راه دور اضافه کند.

JSEP از ICE Candidate Trickling پشتیبانی می‌کند که به تماس‌گیرنده اجازه می‌دهد پس‌از پیشنهاد اولیه، نامزدها را به‌صورت افزایشی به تماس‌گیرنده ارائه دهد و به تماس‌گیرنده اجازه می‌دهد بدون منتظر ماندن برای رسیدن همه نامزدها، اقدام روی تماس را شروع کند و اتصال برقرار کند.

کد WebRTC برای سیگنال‌دهی

تکه‌کد زیر یک نمونه کد W3C است که فرایند کامل سیگنال‌دهی را خلاصه می‌کند. کد فرض می‌کند که نوعی سازوکار سیگنال‌دهی وجود دارد، SignalingChannel. سیگنال‌دهی در ادامه با جزئیات بیشتری مورد بحث قرار می‌گیرد.

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // send the offer to the other peer
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

برای دیدن فرایندهای پیشنهاد-پاسخ و تبادل-نامزد در عمل، به simpl.info RTCPeerConnection مراجعه کنید و گزارش کنسول را برای نمونه گپ تصویری تک‌صفحه‌ای ببینید. می‌توانید یک نسخه کامل از سیگنال‌دهی و آمار WebRTC را از صفحه about://webrtc-internals در Google Chrome یا صفحه opera://webrtc-internals در Opera بارگیری کنید.

اکتشاف همتا

این روشی جالب برای پرسیدن این سؤال است: «چگونه کسی را برای صحبت کردن پیدا کنم؟»

برای تماس‌های تلفنی، شماره تلفن و دفترچه تلفن دارید. برای گپ تصویری و پیام‌رسانی آنلاین، به سیستم‌های مدیریت هویت و حضور و ابزاری برای شروع جلسات توسط کاربران نیاز دارید. برنامه‌های WebRTC به روشی نیاز دارند تا کارخواه‌ها بتوانند به یکدیگر علامت دهند که می‌خواهند تماسی را شروع کنند یا به آن بپیوندند.

سازوکارهای کشف همتا توسط WebRTC تعریف نشده‌اند و شما وارد گزینه‌ها در اینجا نمی‌شوید. این فرایند می‌تواند به سادگی ارسال ایمیل یا پیام حاوی نشانی وب باشد. برای برنامه‌های گپ ویدیویی، مثل Talky،‏ tawk.to و Browser Meeting، افراد را با هم‌رسانی پیوند سفارشی به تماس دعوت می‌کنید. کریس بال، توسعه‌دهنده، یک آزمایش جالب WebRTC بدون سرور ساخته است که به شرکت‌کنندگان تماس WebRTC امکان می‌دهد فراداده را ازطریق هر سرویس پیام‌رسانی که دوست دارند، مانند پیام‌رسانی فوری، ایمیل، یا کبوتر نامه‌بر، مبادله کنند.

چگونه می‌توانید سرویس سیگنال‌دهی بسازید؟

برای تکرار، پروتکل‌ها و مکانیزم‌های سیگنال‌دهی توسط استانداردهای WebRTC تعریف نشده‌اند. هرکدام را که انتخاب کنید، به سرور واسطه‌ای برای تبادل پیام‌های سیگنال‌دهی و داده‌های برنامه بین کارخواه‌ها نیاز دارید. متأسفانه، برنامه وب نمی‌تواند در اینترنت فریاد بزند «من را به دوستم وصل کن!»

خوشبختانه پیام‌های سیگنال‌دهی کوچک هستند و بیشتر در شروع تماس ردوبدل می‌شوند. در آزمایش با appr.tc برای یک جلسه گپ تصویری، در مجموع حدود ۳۰ تا ۴۵ پیام توسط سرویس سیگنال‌دهی با اندازه کل حدود ۱۰ کیلوبایت برای همه پیام‌ها مدیریت شد.

سرویس‌های علامت‌دهی WebRTC علاوه‌بر اینکه ازنظر پهنای باند نسبتاً کم‌مصرف هستند، پردازش یا حافظه زیادی مصرف نمی‌کنند زیرا فقط باید پیام‌ها را رله کنند و مقدار کمی از داده‌های وضعیت جلسه را حفظ کنند، مانند اینکه کدام کارخواه‌ها متصل هستند.

ارسال پیام از سرور به کارخواه

Browser Support

  • Chrome: 6.
  • Edge: 79.
  • Firefox: 6.
  • Safari: 5.

Source

سرویس پیام برای سیگنال‌دهی باید دوطرفه باشد: کارخواه به سرور و سرور به کارخواه. ارتباط دوطرفه برخلاف مدل درخواست/پاسخ کارخواه/سرور HTTP است، اما ترفندهای مختلفی مانند نظرسنجی طولانی در طول سال‌ها توسعه یافته‌اند تا داده‌ها را از سرویسی که روی سرور وب اجرا می‌شود به برنامه وبی که در مرورگر اجرا می‌شود ارسال کنند.

EventSource API رویدادهای ارسال‌شده از سرور را فعال می‌کند، داده‌هایی که از سرور وب به مشتری مرورگر ازطریق HTTP ارسال می‌شوند. EventSource برای پیام‌رسانی یک‌طرفه طراحی شده است، اما می‌توان از آن در ترکیب با XHR برای ساختن سرویسی برای تبادل پیام‌های سیگنال‌دهی استفاده کرد. سرویس سیگنال‌دهی پیامی را از تماس‌گیرنده، که با درخواست XHR ارسال شده است، با ارسال آن ازطریق EventSource به گیرنده تماس منتقل می‌کند.

Browser Support

  • Chrome: 5.
  • Edge: 12.
  • Firefox: 11.
  • Safari: 5.

Source

WebSocket برای ارتباط دوطرفه کامل کارخواه-سرور طراحی شده است، یعنی پیام‌ها می‌توانند به‌طور هم‌زمان در هر دو جهت جریان داشته باشند. یکی‌از مزایای سرویس سیگنال‌دهی ساخته‌شده با WebSocket خالص یا رویدادهای ارسال‌شده از سرور (EventSource) این است که باطن این APIها را می‌توان در انواع چارچوب‌های وب رایج در اکثر بسته‌های میزبانی وب برای زبان‌هایی مانند PHP،‏ Python، و Ruby پیاده‌سازی کرد.

همه مرورگرهایی که از WebRTC پشتیبانی می‌کنند از WebSocket نیز پشتیبانی می‌کنند. TLS باید برای همه اتصال‌ها استفاده شود تا اطمینان حاصل شود که پیام‌ها به‌صورت رمزگذاری‌نشده رهگیری نمی‌شوند و همچنین برای کاهش مشکلات مربوط به پیمایش پراکسی. برای اطلاعات بیشتر درباره WebSocket و پیمایش پراکسی، فصل WebRTC را در شبکه‌سازی مرورگر با عملکرد بالا نوشته ایلیا گریگوریک بخوانید.

می‌توانید با وادار کردن کلاینت‌های WebRTC به نظرسنجی مکرر از سرور پیام‌رسانی ازطریق Ajax، سیگنال‌دهی را مدیریت کنید، اما این کار منجر به درخواست‌های شبکه زائد زیادی می‌شود که به‌ویژه برای دستگاه‌های همراه مشکل‌ساز است. حتی پس‌از برقراری جلسه، همتایان باید پیام‌های سیگنال‌دهی را درصورت تغییر یا پایان جلسه توسط همتایان دیگر نظرسنجی کنند. نمونه برنامه WebRTC Book این گزینه را با برخی بهینه‌سازی‌ها برای بسامد نظرسنجی انتخاب می‌کند.

سیگنال‌دهی مقیاس

اگرچه سرویس سیگنال‌دهی پهنای باند و CPU نسبتاً کمی برای هر مشتری مصرف می‌کند، سرورهای سیگنال‌دهی برای یک برنامه محبوب ممکن است مجبور باشند پیام‌های زیادی را از مکان‌های مختلف با سطوح بالای همزمانی مدیریت کنند. برنامه‌های WebRTC که ترافیک زیادی دریافت می‌کنند به سرورهای سیگنال‌دهی نیاز دارند که بتوانند بار قابل‌توجهی را مدیریت کنند. در اینجا وارد جزئیات نمی‌شوید، اما گزینه‌های متعددی برای پیام‌رسانی با حجم بالا و عملکرد بالا وجود دارد، ازجمله موارد زیر:

  • پروتکل حضور و پیام‌رسانی توسعه‌پذیر (XMPP) پروتکلی است که برای پیام‌رسانی فوری توسعه یافته است و می‌تواند برای سیگنال‌دهی استفاده شود. پیاده‌سازی‌های سرور شامل ejabberd و Openfire است. کارخواه‌های جاوا اسکریپت، مانند Strophe.js، از BOSH برای شبیه‌سازی جاری‌سازی دوطرفه استفاده می‌کنند، اما BOSH ممکن است در مقایسه با WebSocket ناکارآمد باشد و مقیاس‌پذیری ضعیفی داشته باشد.

  • کتابخانه‌های متن‌باز، مانند ZeroMQ (همان‌طور که توسط TokBox برای سرویس Rumour استفاده می‌شود) و OpenMQ (NullMQ مفاهیم ZeroMQ را در پلاتفرم‌های وب بااستفاده از پروتکل STOMP روی WebSocket اعمال می‌کند.)

  • پلاتفرم‌های پیام‌رسانی ابری تجاری که از WebSocket استفاده می‌کنند (هرچند ممکن است به نظرسنجی طولانی برگردند)، مانند Pusher و Kaazing.

  • پلاتفرم‌های تجاری WebRTC، مانند vLine

ساختن سرویس سیگنال‌دهی با Socket.io در Node

کد زیر مربوط به برنامه وبی است که از سرویس نشان‌دهی ساخته‌شده با Socket.io در Node استفاده می‌کند. طراحی Socket.io ساختن سرویسی برای تبادل پیام را آسان‌تر می‌کند و Socket.io به‌دلیل مفهوم داخلی اتاق‌ها، به‌طور خاص برای نشان‌دهی WebRTC مناسب است. این مثال برای تعداد نسبتاً کمی از کاربران طراحی شده است، نه برای استفاده در تولید.

‫Socket.io از WebSocket با گزینه‌های جایگزین استفاده می‌کند: نظرسنجی طولانی AJAX، جاری‌سازی چندبخشی AJAX،‏ Forever Iframe، و نظرسنجی JSONP. این کتابخانه به زیرینه‌های مختلفی منتقل شده است، اما شاید بیشتر به‌خاطر نسخه Node آن که در این مثال استفاده شده است شناخته شده باشد.

در این مثال، WebRTC وجود ندارد. این نمونه برای نشان دادن نحوه ایجاد سیگنال‌دهی در برنامه وب طراحی شده است. برای دیدن اتفاقاتی که هنگام پیوستن کارخواه‌ها به اتاق و تبادل پیام رخ می‌دهد، گزارش کنسول را مشاهده کنید. این WebRTC codelab دستورالعمل‌های گام‌به‌گام برای نحوه ادغام این مورد در یک برنامه گپ تصویری WebRTC کامل ارائه می‌دهد.

این کارخواه index.html است:

<!DOCTYPE html>
<html>
  <head>
    <title>WebRTC client</title>
  </head>
  <body>
    <script src='/socket.io/socket.io.js'></script>
    <script src='js/main.js'></script>
  </body>
</html>

در اینجا فایل جاوا اسکریپت main.js ارجاع‌شده در کارخواه آمده است:

const isInitiator;

room = prompt('Enter room name:');

const socket = io.connect();

if (room !== '') {
  console.log('Joining room ' + room);
  socket.emit('create or join', room);
}

socket.on('full', (room) => {
  console.log('Room ' + room + ' is full');
});

socket.on('empty', (room) => {
  isInitiator = true;
  console.log('Room ' + room + ' is empty');
});

socket.on('join', (room) => {
  console.log('Making request to join room ' + room);
  console.log('You are the initiator!');
});

socket.on('log', (array) => {
  console.log.apply(console, array);
});

برنامه سرور کامل در اینجا آورده شده است:

const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
  file.serve(req, res);
}).listen(2013);

const io = require('socket.io').listen(app);

io.sockets.on('connection', (socket) => {

  // Convenience function to log server messages to the client
  function log(){
    const array = ['>>> Message from server: '];
    for (const i = 0; i < arguments.length; i++) {
      array.push(arguments[i]);
    }
      socket.emit('log', array);
  }

  socket.on('message', (message) => {
    log('Got message:', message);
    // For a real app, would be room only (not broadcast)
    socket.broadcast.emit('message', message);
  });

  socket.on('create or join', (room) => {
    const numClients = io.sockets.clients(room).length;

    log('Room ' + room + ' has ' + numClients + ' client(s)');
    log('Request to create or join room ' + room);

    if (numClients === 0){
      socket.join(room);
      socket.emit('created', room);
    } else if (numClients === 1) {
      io.sockets.in(room).emit('join', room);
      socket.join(room);
      socket.emit('joined', room);
    } else { // max two clients
      socket.emit('full', room);
    }
    socket.emit('emit(): client ' + socket.id +
      ' joined room ' + room);
    socket.broadcast.emit('broadcast(): client ' + socket.id +
      ' joined room ' + room);

  });

});

برای اجرای این برنامه در میزبان محلی، باید Node.js، Socket.IO، و node-static داشته باشید. برای نصب Socket.IO و node-static،‏ npm را از پایانه در فهرست راهنمای برنامه‌تان اجرا کنید:

npm install socket.io
npm install node-static

برای راه‌اندازی سرور، فرمان زیر را از پایانه در فهرست راهنمای برنامه‌تان اجرا کنید:

node server.js

از مرورگرتان، localhost:2013 را باز کنید. برگه یا پنجره جدیدی در هر مرورگری باز کنید و localhost:2013 را دوباره باز کنید. برای دیدن آنچه درحال رخ دادن است، کنسول را بررسی کنید. در Chrome و Opera، می‌توانید ازطریق «ابزارهای توسعه‌دهنده Google Chrome» با Ctrl+Shift+J (یا Command+Option+J در Mac) به کنسول دسترسی پیدا کنید.

هر رویکردی را که برای سیگنال‌دهی انتخاب کنید، برنامه مشتری و پسای شما باید خدماتی مشابه این نمونه ارائه دهند.

مشکلات احتمالی سیگنال

  • RTCPeerConnection تا زمانی که setLocalDescription() فراخوانی نشود، جمع‌آوری نامزدها را شروع نخواهد کرد. این مورد در پیش‌نویس JSEP IETF الزامی شده است.
  • از Trickle ICE بهره ببرید. به‌محض رسیدن نامزدها، با addIceCandidate() تماس بگیرید.

سرورهای سیگنال آماده

اگر نمی‌خواهید خودتان این کار را انجام دهید، چندین سرور سیگنال‌دهی WebRTC دردسترس است که مانند مثال قبلی از Socket.IO استفاده می‌کنند و با کتابخانه‌های جاوا اسکریپت کارخواه WebRTC ادغام شده‌اند:

  • webRTC.io یکی از اولین کتابخانه‌های انتزاعی برای WebRTC است.
  • Signalmaster سرور سیگنال‌دهی است که برای استفاده با کتابخانه کارخواه جاوا اسکریپت SimpleWebRTC ایجاد شده است.

اگر نمی‌خواهید هیچ کدی بنویسید، پلاتفرم‌های تجاری کامل WebRTC از شرکت‌هایی مانند vLine، OpenTok، و Asterisk دردسترس هستند.

برای ثبت در سوابق، Ericsson در روزهای اولیه WebRTC، سرور سیگنال‌دهی بااستفاده از PHP در Apache ساخت. این روش اکنون تاحدودی منسوخ شده است، اما اگر قصد دارید چیزی مشابه بسازید، ارزش دارد که به کد آن نگاهی بیندازید.

امنیت سیگنال

رمزگذاری برای همه مؤلفه‌های WebRTC اجباری است.

بااین‌حال، سازوکارهای سیگنال‌دهی توسط استانداردهای WebRTC تعریف نشده‌اند، بنابراین ایمن کردن سیگنال‌دهی برعهده شما است. اگر مهاجمی بتواند سیگنال‌دهی را برباید، می‌تواند جلسه‌ها را متوقف کند، اتصال‌ها را تغییر مسیر دهد، و محتوا را ضبط، تغییر، یا تزریق کند.

مهم‌ترین عامل در ایمن‌سازی سیگنال‌دهی، استفاده از پروتکل‌های امن است: HTTPS و WSS، مانند TLS. این کار تضمین می‌کند که پیام‌ها به‌صورت رمزگذاری‌نشده رهگیری نشوند. همچنین، مراقب باشید پیام‌های سیگنال‌دهی را به‌گونه‌ای پخش نکنید که سایر تماس‌گیرندگانی که از همان سرور سیگنال‌دهی استفاده می‌کنند بتوانند به آن‌ها دسترسی داشته باشند.

مقابله با NAT و دیوارهای آتش

برای سیگنال‌دهی فراداده، برنامه‌های WebRTC از سرور واسطه استفاده می‌کنند، اما برای جاری‌سازی واقعی رسانه و داده پس‌از برقراری جلسه، RTCPeerConnection تلاش می‌کند کارخواه‌ها را مستقیماً یا همتا‌به‌همتا متصل کند.

در دنیایی ساده‌تر، هر نقطه پایانی WebRTC نشانی منحصربه‌فردی دارد که می‌تواند آن را با همتایان دیگر مبادله کند تا مستقیماً ارتباط برقرار کند.

اتصال همتا به همتای ساده
دنیایی بدون NAT و دیوار آتش

در واقعیت، اکثر دستگاه‌ها پشت یک یا چند لایه NAT قرار دارند، برخی دارای نرم‌افزار ضدویروس هستند که درگاه‌ها و پروتکل‌های خاصی را مسدود می‌کند، و بسیاری پشت پراکسی‌ها و دیوارهای آتش شرکتی قرار دارند. دیوار آتش و NAT ممکن است درواقع توسط یک دستگاه، مثلاً رهیاب Wi-Fi خانگی، پیاده‌سازی شوند.

همتایان پشت NAT و دیواره‌های آتش
دنیای واقعی

برنامه‌های WebRTC می‌توانند از چارچوب ICE برای غلبه بر پیچیدگی‌های شبکه‌سازی در دنیای واقعی استفاده کنند. برای فعال کردن این ویژگی، برنامه‌تان باید نشانی‌های وب سرور ICE را به RTCPeerConnection ارسال کند.

ICE تلاش می‌کند بهترین مسیر را برای اتصال همتاها پیدا کند. این مدل همه احتمالات را به‌طور موازی امتحان می‌کند و کارآمدترین گزینه‌ای را که کار می‌کند انتخاب می‌کند. ICE ابتدا سعی می‌کند بااستفاده از نشانی میزبان که از سیستم‌عامل و کارت شبکه دستگاه دریافت شده است، اتصال برقرار کند. اگر این کار ناموفق باشد (که برای دستگاه‌های پشت NAT ناموفق خواهد بود)، ICE بااستفاده از سرور STUN نشانی خارجی دریافت می‌کند و اگر این کار ناموفق باشد، ترافیک ازطریق سرور رله TURN هدایت می‌شود.

به‌عبارت دیگر، از سرور STUN برای دریافت نشانی شبکه خارجی استفاده می‌شود و از سرورهای TURN برای رله کردن ترافیک درصورت ناموفق بودن اتصال مستقیم (رایانه به رایانه) استفاده می‌شود.

همه سرورهای TURN از STUN پشتیبانی می‌کنند. سرور TURN یک سرور STUN با عملکرد رله داخلی اضافی است. ICE همچنین با پیچیدگی‌های راه‌اندازی NAT مقابله می‌کند. در واقعیت، NAT hole-punching ممکن است به چیزی بیشتر از نشانی IP:port عمومی نیاز داشته باشد.

نشانی‌های وب برای سرورهای STUN و TURN (اختیاراً) توسط برنامه WebRTC در شیء پیکربندی iceServers که اولین آرگومان برای سازنده RTCPeerConnection است مشخص می‌شوند. برای appr.tc، این مقدار به این شکل است:

{
  'iceServers': [
    {
      'urls': 'stun:stun.l.google.com:19302'
    },
    {
      'urls': 'turn:192.158.29.39:3478?transport=udp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    },
    {
      'urls': 'turn:192.158.29.39:3478?transport=tcp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    }
  ]
}

وقتی RTCPeerConnection این اطلاعات را داشته باشد، جادوی ICE به‌طور خودکار اتفاق می‌افتد. RTCPeerConnection از چارچوب ICE برای یافتن بهترین مسیر بین همتاها استفاده می‌کند و درصورت لزوم با سرورهای STUN و TURN کار می‌کند.

STUN

NAT نشانی IP را برای استفاده در شبکه محلی خصوصی به دستگاه ارائه می‌دهد، اما این نشانی را نمی‌توان به‌صورت خارجی استفاده کرد. بدون نشانی عمومی، همتاهای WebRTC نمی‌توانند با یکدیگر ارتباط برقرار کنند. برای حل این مشکل، WebRTC از STUN استفاده می‌کند.

سرورهای STUN در اینترنت عمومی قرار دارند و یک وظیفه دارند: بررسی نشانی IP:درگاه درخواست ورودی (از برنامه‌ای که پشت NAT اجرا می‌شود) و ارسال آن نشانی به‌عنوان پاسخ. به عبارت دیگر، برنامه از سرور STUN برای کشف IP:درگاه خود از دیدگاه عمومی استفاده می‌کند. این فرایند به همتای WebRTC امکان می‌دهد نشانی‌ای را که به‌طور عمومی دردسترس است برای خودش دریافت کند و سپس آن را ازطریق سازوکار سیگنال‌دهی به همتای دیگری منتقل کند تا پیوند مستقیمی راه‌اندازی شود.

سرورهای STUN لازم نیست کار زیادی انجام دهند یا چیز زیادی را به‌خاطر بسپارند، بنابراین سرورهای STUN با مشخصات نسبتاً پایین می‌توانند تعداد زیادی درخواست را مدیریت کنند.

اکثر تماس‌های WebRTC بااستفاده از STUN اتصال موفقی برقرار می‌کنند، هرچند ممکن است این تعداد برای تماس‌های بین همتاهای پشت دیواره‌های آتش و پیکربندی‌های پیچیده NAT کمتر باشد.

اتصال همتا به همتا بااستفاده از سرور STUN
استفاده از سرورهای STUN برای دریافت نشانی‌های IP:درگاه عمومی

پیچ

RTCPeerConnection تلاش می‌کند ارتباط مستقیم بین همتایان را ازطریق UDP راه‌اندازی کند. اگر این کار ناموفق باشد، RTCPeerConnection به TCP متوسل می‌شود. اگر این کار ناموفق باشد، می‌توان از سرورهای TURN به‌عنوان جایگزین استفاده کرد که داده‌ها را بین نقاط پایانی رله می‌کنند.

فقط برای تأکید مجدد، از TURN برای رله کردن جاری‌سازی صدا، ویدیو، و داده بین همتاها استفاده می‌شود، نه برای نشان‌دهی داده!

سرورهای TURN نشانی‌های عمومی دارند، بنابراین همتاها می‌توانند با آن‌ها تماس بگیرند، حتی اگر همتاها پشت دیوارهای آتش یا پراکسی‌ها باشند. سرورهای TURN یک وظیفه دارند: رله کردن جاری‌سازی. برخلاف سرورهای STUN، این سرورها ذاتاً پهنای باند زیادی مصرف می‌کنند.

اتصال همتا به همتا بااستفاده از سرور STUN
The full Monty: STUN, TURN, and signaling

این نمودار TURN را در عمل نشان می‌دهد. STUN خالص موفقیت‌آمیز نبود، بنابراین هر همتا به استفاده از سرور TURN متوسل می‌شود.

پیاده‌سازی سرورهای STUN و TURN

برای آزمایش، Google یک سرور STUN عمومی، stun.l.google.com:19302، را اجرا می‌کند، که توسط appr.tc استفاده می‌شود. برای سرویس STUN/TURN تولید، از rfc5766-turn-server استفاده کنید. کد منبع برای سرورهای STUN و TURN در GitHub دردسترس است، که در آنجا می‌توانید پیوندهایی به چندین منبع اطلاعاتی درباره نصب سرور پیدا کنید. تصویر VM برای Amazon Web Services نیز دردسترس است.

سرور TURN جایگزین restund است که به‌صورت کد منبع و همچنین برای AWS دردسترس است. می‌توانید restund را در Compute راه‌اندازی کنید :

  1. دیوار آتش را درصورت نیاز برای tcp=443،‏ udp/tcp=3478 باز کنید.
  2. چهار نمونه ایجاد کنید، یکی برای هر IP عمومی، تصویر استاندارد Ubuntu 12.06.
  3. پیکربندی دیوار آتش محلی را راه‌اندازی کنید (اجازه دادن به ANY از ANY).
  4. نصب ابزارها: shell sudo apt-get install make sudo apt-get install gcc
  5. libre را از creytiv.com/re.html نصب کنید.
  6. restund را از creytiv.com/restund.html واکشی کنید و از حالت فشرده خارج کنید.
  7. wget hancke.name/restund-auth.patch و با patch -p1 < restund-auth.patch اعمال کنید.
  8. ‫make، sudo make install را برای libre و restund اجرا کنید.
  9. restund.conf را با نیازهایتان تطبیق دهید (نشانی‌های IP را جایگزین کنید و مطمئن شوید که حاوی همان رمز مشترک است) و در /etc کپی کنید.
  10. restund/etc/restund را در /etc/init.d/ کپی کنید.
  11. پیکربندی restund:
    1. LD_LIBRARY_PATH تنظیم شد.
    2. restund.conf را در /etc/restund.conf کپی کنید.
    3. ‫restund.conf را طوری تنظیم کنید که از ۱۰ سمت راست استفاده کند. نشانی IP.
  12. اجرای restund
  13. آزمایش بااستفاده از کارخواه stund از دستگاه راه دور: ./client IP:port

WebRTC چندطرفه

همچنین می‌توانید به استاندارد IETF پیشنهادی جاستین اوبرتی برای REST API برای دسترسی به سرویس‌های TURN نگاهی بیندازید.

موارد استفاده متعددی برای جاری‌سازی رسانه وجود دارد که فراتر از تماس یک‌به‌یک است. برای مثال، کنفرانس ویدیویی بین گروهی از همکاران یا رویدادی عمومی با یک سخنران و صدها یا میلیون‌ها بیننده.

برنامه WebRTC می‌تواند از چند RTCPeerConnection استفاده کند تا هر نقطه پایانی به هر نقطه پایانی دیگر در پیکربندی مش متصل شود. این رویکردی است که توسط برنامه‌هایی مانند talky.io اتخاذ شده است و برای تعداد کمی از همتایان به‌طور قابل‌توجهی خوب کار می‌کند. فراتر از آن، پردازش و مصرف پهنای باند بیش‌ازحد می‌شود، به‌ویژه برای کارخواه‌های تلفن همراه.

توری: تماس چندطرفه کوچک
توپولوژی توری کامل: همه به همه متصل هستند

یا اینکه برنامه WebRTC می‌تواند یک نقطه پایانی را برای توزیع جاری‌سازی‌ها به همه نقاط پایانی دیگر در پیکربندی ستاره‌ای انتخاب کند. همچنین می‌توان یک نقطه پایانی WebRTC را روی سرور اجرا کرد و مکانیزم توزیع مجدد خود را ساخت (یک نمونه برنامه مشتری توسط webrtc.org ارائه شده است).

MediaStream از یک RTCPeerConnection می‌تواند به‌عنوان ورودی برای دیگری استفاده شود. این کار می‌تواند معماری‌های انعطاف‌پذیرتری را فعال کند زیرا به برنامه وب امکان می‌دهد با انتخاب همتای دیگری که باید به آن متصل شود، مسیریابی تماس را مدیریت کند. برای دیدن این مورد در عمل، رله اتصال همتا در نمونه‌های WebRTC و اتصال‌های همتای چندگانه در نمونه‌های WebRTC را ببینید.

واحد کنترل چندنقطه‌ای

گزینه بهتر برای تعداد زیادی از نقاط پایانی استفاده از واحد کنترل چندنقطه‌ای (MCU) است. این سروری است که به‌عنوان پلی برای توزیع رسانه بین تعداد زیادی از شرکت‌کنندگان عمل می‌کند. «واحد کنترل چندنقطه‌ای» می‌تواند با وضوح‌ها، کدک‌ها، و نرخ‌های فریم مختلف در کنفرانس ویدیویی کنار بیاید؛ تراتبدیل را مدیریت کند؛ بازفرستی انتخابی جاری‌سازی را انجام دهد؛ و صدا و ویدیو را ترکیب یا ضبط کند. برای تماس‌های چندطرفه، مسائل متعددی وجود دارد که باید درنظر گرفته شود، به‌ویژه نحوه نمایش چندین ورودی ویدیو و ترکیب صدا از منابع متعدد. پلاتفرم‌های ابری، مانند vLine، نیز تلاش می‌کنند تا مسیریابی ترافیک را بهینه‌سازی کنند.

می‌توانید بسته سخت‌افزاری کامل MCU را بخرید یا بسته خودتان را بسازید.

نمای عقب Cisco MCU5300
پشت Cisco MCU

چندین گزینه نرم‌افزار MCU متن‌باز دردسترس است. برای مثال، Licode (که قبلاً با نام Lynckia شناخته می‌شد) یک MCU متن‌باز برای WebRTC تولید می‌کند. OpenTok دارای Mantis است.

فراتر از مرورگرها: VoIP، تلفن، و پیام‌رسانی

ماهیت استاندارد WebRTC امکان برقراری ارتباط بین برنامه WebRTC درحال اجرا در مرورگر و دستگاه یا پلاتفرمی را که روی پلاتفرم ارتباطی دیگری (مثل تلفن یا سیستم کنفرانس ویدیویی) اجرا می‌شود فراهم می‌کند.

SIP پروتکل سیگنال‌دهی است که سیستم‌های کنفرانس ویدیویی و VoIP از آن استفاده می‌کنند. برای فعال کردن ارتباط بین برنامه وب WebRTC و کلاینت SIP، مانند سیستم کنفرانس ویدیویی، WebRTC به یک سرور پراکسی برای میانجی‌گری نشان‌دهی نیاز دارد. سیگنال‌دهی باید ازطریق دروازه جریان یابد، اما پس‌از برقراری ارتباط، ترافیک SRTP (ویدیو و صدا) می‌تواند به‌صورت همتا‌به‌همتا جریان یابد.

شبکه عمومی تلفن (PSTN) شبکه مدارگزینی همه تلفن‌های آنالوگ «قدیمی ساده» است. برای تماس بین برنامه‌های وب WebRTC و تلفن‌ها، ترافیک باید ازطریق درگاه PSTN انجام شود. به‌همین ترتیب، برنامه‌های وب WebRTC برای برقراری ارتباط با نقاط پایانی Jingle مانند کلاینت‌های پیام‌رسانی فوری، به یک سرور واسطه XMPP نیاز دارند. ‫Jingle توسط Google به‌عنوان افزونه‌ای برای XMPP توسعه داده شد تا صدا و ویدیو را برای سرویس‌های پیام‌رسانی فعال کند. پیاده‌سازی‌های فعلی WebRTC براساس کتابخانه C++ libjingle است، پیاده‌سازی Jingle که در ابتدا برای Talk توسعه یافته بود.

تعدادی از برنامه‌ها، کتابخانه‌ها، و پلاتفرم‌ها از توانایی WebRTC برای برقراری ارتباط با دنیای خارج استفاده می‌کنند. برای مثال:

  • jsSIP: کتابخانه SIP جاوا اسکریپت
  • Phono: میانای برنامه‌سازی کاربردی تلفن جاوا اسکریپت با منبع باز که به‌عنوان افزونه ساخته شده است
  • Twilio: صدا و پیام‌رسانی

دریافت اطلاعات بیشتر

کتاب ۳۵۰ صفحه‌ای WebRTC: APIs and RTCWEB Protocols of the HTML5 Real-Time Web جزئیات زیادی درباره مسیرهای داده و سیگنال‌دهی ارائه می‌دهد و شامل تعدادی نمودار دقیق از توپولوژی شبکه است.