ارتباط بلادرنگ با WebRTC

۱. مقدمه

WebRTC یک پروژه متن‌باز است که امکان ارتباط بلادرنگ صدا، تصویر و داده‌ها را در وب و برنامه‌های بومی فراهم می‌کند.

WebRTC چندین API جاوا اسکریپت دارد - برای دیدن نسخه‌های نمایشی روی لینک‌ها کلیک کنید.

کجا می‌توانم از WebRTC استفاده کنم؟

در فایرفاکس، اپرا و کروم روی دسکتاپ و اندروید. WebRTC همچنین برای برنامه‌های بومی در iOS و اندروید در دسترس است.

سیگنالینگ چیست؟

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

بی‌حس کردن (STUN) و چرخاندن (TURN) چیستند؟

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

آیا وب آر تی سی امن است؟

رمزگذاری برای همه اجزای WebRTC الزامی است و APIهای جاوا اسکریپت آن فقط از منابع امن (HTTPS یا localhost) قابل استفاده هستند. مکانیسم‌های سیگنالینگ توسط استانداردهای WebRTC تعریف نشده‌اند، بنابراین این به شما بستگی دارد که از پروتکل‌های امن استفاده کنید.

۲. مرور کلی

یک برنامه بسازید تا با وب‌کم خود ویدیو بگیرید و عکس بگیرید و آنها را از طریق WebRTC به صورت نظیر به نظیر به اشتراک بگذارید. در طول مسیر، نحوه استفاده از API های اصلی WebRTC و راه‌اندازی یک سرور پیام‌رسان با استفاده از Node.js را خواهید آموخت.

آنچه یاد خواهید گرفت

  • از وب کم خود ویدیو بگیرید
  • پخش ویدئو با RTCPeerConnection
  • پخش داده‌ها با RTCDataChannel
  • راه‌اندازی سرویس سیگنالینگ برای تبادل پیام‌ها
  • ترکیب اتصال همتا و سیگنالینگ
  • عکس بگیرید و از طریق کانال داده به اشتراک بگذارید

آنچه نیاز دارید

  • کروم ۴۷ یا بالاتر
  • وب سرور برای کروم ، یا از وب سرور دلخواه خودتان استفاده کنید.
  • کد نمونه
  • یک ویرایشگر متن
  • دانش پایه در مورد HTML، CSS و جاوا اسکریپت

۳. کد نمونه را دریافت کنید

کد را دانلود کنید

اگر با گیت (git) آشنا هستید، می‌توانید کد این codelab را با کپی کردن آن از گیت‌هاب دانلود کنید:

git clone https://github.com/googlecodelabs/webrtc-web

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

فایل زیپ دانلود شده را باز کنید. این کار پوشه پروژه ( adaptive-web-media ) را از حالت فشرده خارج می‌کند که شامل یک پوشه برای هر مرحله از این codelab به همراه تمام منابع مورد نیاز شماست.

شما تمام کارهای کدنویسی خود را در دایرکتوری به نام work انجام خواهید داد.

پوشه‌های step-nn حاوی نسخه نهایی هر مرحله از این آزمایشگاه کد هستند. آن‌ها برای مرجع در آنجا قرار دارند.

نصب و بررسی وب سرور

اگرچه می‌توانید از وب سرور خودتان استفاده کنید، این codelab طوری طراحی شده است که به خوبی با وب سرور کروم کار کند. اگر هنوز آن برنامه را نصب نکرده‌اید، می‌توانید آن را از فروشگاه وب کروم نصب کنید.

6ddeb4aee53c0f0e.png

پس از نصب برنامه وب سرور برای کروم ، روی میانبر برنامه‌های کروم از نوار نشانک‌ها، صفحه برگه جدید یا از راه‌انداز برنامه کلیک کنید:

۱d2b4aa977ab7e24.png

روی آیکون وب سرور کلیک کنید:

27fce4494f641883.png

در مرحله بعد، این کادر محاوره‌ای را مشاهده خواهید کرد که به شما امکان پیکربندی سرور وب محلی خود را می‌دهد:

اسکرین شات 2016-02-18 ساعت 11.48.14 صبح.png

روی دکمه‌ی «انتخاب پوشه» کلیک کنید و پوشه‌ی کاری که ایجاد کرده‌اید را انتخاب کنید. این کار به شما امکان می‌دهد تا کار در حال انجام خود را در کروم از طریق URL هایلایت شده در کادر محاوره‌ای وب سرور در بخش URL(های) وب سرور مشاهده کنید.

در قسمت Options ، کادر کنار Automatically show index.html را مطابق شکل زیر علامت بزنید:

اسکرین شات 2016-02-18 ساعت 11.56.30 صبح.png

سپس با کشیدن کشوییِ با برچسبِ Web Server: STARTED به سمت چپ و سپس به سمت راست، سرور را متوقف و مجدداً راه‌اندازی کنید.

اسکرین شات 2016-02-18 ساعت 12.22.18 PM.png

اکنون با کلیک بر روی آدرس وب سرور هایلایت شده، از سایت کاری خود در مرورگر وب خود بازدید کنید. باید صفحه‌ای شبیه به این را ببینید که مربوط به work/index.html است:

18a705cb6ccc5181.png

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

۴. پخش ویدئو از وب‌کم

آنچه یاد خواهید گرفت

در این مرحله شما یاد خواهید گرفت که چگونه:

  • از وب کم خود یک جریان ویدیویی دریافت کنید.
  • پخش جریان را دستکاری کنید.
  • برای ویرایش ویدیو از CSS و SVG استفاده کنید.

نسخه کامل این مرحله در پوشه step-01 قرار دارد.

کمی HTML ...

یک عنصر video و یک عنصر script به index.html در دایرکتوری کاری خود اضافه کنید:

<!DOCTYPE html>
<html>

<head>

  <title>Realtime communication with WebRTC</title>

  <link rel="stylesheet" href="css/main.css" />

</head>

<body>

  <h1>Realtime communication with WebRTC</h1>

  <video autoplay playsinline></video>

  <script src="js/main.js"></script>

</body>

</html>

... و کمی جاوا اسکریپت

کد زیر را به main.js در پوشه js خود اضافه کنید:

'use strict';

// On this codelab, you will be streaming only video (video: true).
const mediaStreamConstraints = {
  video: true,
};

// Video element where stream will be placed.
const localVideo = document.querySelector('video');

// Local stream that will be reproduced on the video.
let localStream;

// Handles success by adding the MediaStream to the video element.
function gotLocalMediaStream(mediaStream) {
  localStream = mediaStream;
  localVideo.srcObject = mediaStream;
}

// Handles error by logging a message to the console with the error message.
function handleLocalMediaStreamError(error) {
  console.log('navigator.getUserMedia error: ', error);
}

// Initializes media stream.
navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
  .then(gotLocalMediaStream).catch(handleLocalMediaStreamError);

امتحانش کن.

فایل index.html را در مرورگر خود باز کنید. باید چیزی شبیه به این را ببینید (البته با نمایش تصویر وب‌کم شما!):

۹۲۹۷۰۴۸e۴۳ed۰f۳d.png

چگونه کار می‌کند؟

پس از فراخوانی getUserMedia() ، مرورگر از کاربر درخواست دسترسی به دوربین خود را می‌کند (اگر این اولین باری باشد که دسترسی به دوربین برای مبدا فعلی درخواست می‌شود). در صورت موفقیت، یک MediaStream برگردانده می‌شود که می‌تواند توسط یک عنصر رسانه از طریق ویژگی srcObject مورد استفاده قرار گیرد:

navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
  .then(gotLocalMediaStream).catch(handleLocalMediaStreamError);


}
function gotLocalMediaStream(mediaStream) {
  localVideo.srcObject = mediaStream;
}

آرگومان constraints به شما امکان می‌دهد مشخص کنید چه رسانه‌ای دریافت شود. در این مثال، فقط ویدیو، زیرا صدا به طور پیش‌فرض غیرفعال است:

const mediaStreamConstraints = {
  video: true,
};

شما می‌توانید از قیدها برای الزامات اضافی مانند وضوح تصویر استفاده کنید:

const hdConstraints = {
  video: {
    width: {
      min: 1280
    },
    height: {
      min: 720
    }
  }
}

مشخصات MediaTrackConstraints تمام انواع محدودیت‌های بالقوه را فهرست می‌کند، اگرچه همه گزینه‌ها توسط همه مرورگرها پشتیبانی نمی‌شوند. اگر وضوح درخواستی توسط دوربین انتخاب شده فعلی پشتیبانی نشود، getUserMedia() با یک OverconstrainedError رد می‌شود و از کاربر خواسته نمی‌شود که اجازه دسترسی به دوربین خود را بدهد.

اگر getUserMedia() موفق باشد، جریان ویدئو از وب‌کم به عنوان منبع عنصر ویدئو تنظیم می‌شود:

function gotLocalMediaStream(mediaStream) {
  localVideo.srcObject = mediaStream;
}

امتیازهای ویژه

  • شیء localStream که به getUserMedia() ارسال می‌شود، در محدوده سراسری است، بنابراین می‌توانید آن را از کنسول مرورگر بررسی کنید: کنسول را باز کنید، عبارت stream را تایپ کنید و Return را فشار دهید. (برای مشاهده کنسول در کروم، کلیدهای Ctrl-Shift-J یا اگر از مک استفاده می‌کنید، کلیدهای Command-Option-J را فشار دهید.)
  • تابع localStream.getVideoTracks() چه چیزی را برمی‌گرداند؟
  • سعی کنید تابع localStream.getVideoTracks()[0].stop() را فراخوانی کنید.
  • به شیء قیدها نگاه کنید: وقتی آن را به {audio: true, video: true} تغییر می‌دهید چه اتفاقی می‌افتد؟
  • اندازه عنصر ویدیو چقدر است؟ چگونه می‌توانید اندازه طبیعی ویدیو را از جاوا اسکریپت، برخلاف اندازه نمایش، دریافت کنید؟ برای بررسی از ابزارهای توسعه‌دهندگان کروم استفاده کنید.
  • سعی کنید فیلترهای CSS را به عنصر ویدیو اضافه کنید. برای مثال:
video {
  filter: blur(4px) invert(1) opacity(0.5);
}
  • فیلترهای SVG را اضافه کنید. برای مثال:
video {
   filter: hue-rotate(180deg) saturate(200%);
 }

آنچه آموختید

در این مرحله یاد گرفتید که چگونه:

  • از وب کم خود ویدیو بگیرید.
  • محدودیت‌های رسانه‌ای تعیین کنید.
  • با عنصر ویدیو بهم بریز.

نسخه کامل این مرحله در پوشه step-01 قرار دارد.

نکات

  • ویژگی autoplay را در عنصر video فراموش نکنید. بدون آن، فقط یک فریم خواهید دید!
  • گزینه‌های بسیار بیشتری برای محدودیت‌های getUserMedia() وجود دارد. نگاهی به نسخه آزمایشی در webrtc.github.io/samples/src/content/peerconnection/constraints بیندازید. همانطور که خواهید دید، نمونه‌های جالب زیادی از WebRTC در آن سایت وجود دارد.

بهترین شیوه

  • مطمئن شوید که عنصر ویدیوی شما از ظرف خود سرریز نمی‌کند. ما width و max-width را برای تنظیم اندازه دلخواه و حداکثر اندازه برای ویدیو اضافه کرده‌ایم. مرورگر به طور خودکار ارتفاع را محاسبه می‌کند:
video {
  max-width: 100%;
  width: 320px;
}

بعدی

شما ویدیو دارید، اما چگونه آن را پخش می‌کنید؟ در مرحله بعدی متوجه خواهید شد!

۵. پخش ویدئو با RTCPeerConnection

آنچه یاد خواهید گرفت

در این مرحله شما یاد خواهید گرفت که چگونه:

  • تفاوت‌های مرورگر را با فایل WebRTC، adapter.js، خلاصه کنید.
  • برای پخش ویدئو از API RTCPeerConnection استفاده کنید.
  • ضبط و پخش رسانه را کنترل کنید.

نسخه کامل این مرحله در پوشه مرحله ۲ قرار دارد.

RTCPeerConnection چیست؟

RTCPeerConnection یک API برای برقراری تماس‌های WebRTC جهت پخش ویدئو و صدا و تبادل داده‌ها است.

این مثال اتصالی بین دو شیء RTCPeerConnection (که به عنوان peers شناخته می‌شوند) در یک صفحه برقرار می‌کند.

کاربرد عملی زیادی ندارد، اما برای درک نحوه‌ی کار RTCPeerConnection خوب است.

اضافه کردن عناصر ویدیویی و دکمه‌های کنترلی

در فایل index.html، عنصر video را با دو عنصر video و سه دکمه جایگزین کنید:

<video id="localVideo" autoplay playsinline></video>
<video id="remoteVideo" autoplay playsinline></video>


<div>
  <button id="startButton">Start</button>
  <button id="callButton">Call</button>
  <button id="hangupButton">Hang Up</button>
</div>

یک عنصر ویدیو، استریم دریافتی از getUserMedia() را نمایش می‌دهد و عنصر دیگر، همان ویدیو را که از طریق RTCPeerconnection استریم شده است، نمایش می‌دهد. (در یک برنامه‌ی واقعی، یک عنصر ویدیو، استریم محلی و عنصر دیگر، استریم راه دور را نمایش می‌دهد.)

فایل adapter.js shim را اضافه کنید.

لینکی به نسخه فعلی adapter.js در بالای لینک main.js اضافه کنید:

<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

Index.html اکنون باید به این شکل باشد:

<!DOCTYPE html>
<html>

<head>
  <title>Realtime communication with WebRTC</title>
  <link rel="stylesheet" href="css/main.css" />
</head>

<body>
  <h1>Realtime communication with WebRTC</h1>

  <video id="localVideo" autoplay playsinline></video>
  <video id="remoteVideo" autoplay playsinline></video>

  <div>
    <button id="startButton">Start</button>
    <button id="callButton">Call</button>
    <button id="hangupButton">Hang Up</button>
  </div>

  <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
  <script src="js/main.js"></script>
</body>
</html>

کد RTCPeerConnection را نصب کنید

فایل main.js را با نسخه موجود در پوشه step-02 جایگزین کنید.

تماس بگیرید

فایل index.html را باز کنید، برای دریافت ویدیو از وب‌کم خود روی دکمه‌ی Start کلیک کنید و برای برقراری اتصال همتا روی Call کلیک کنید. باید ویدیوی یکسانی (از وب‌کم خود) را در هر دو عنصر ویدیو ببینید. برای مشاهده‌ی گزارش WebRTC، به کنسول مرورگر مراجعه کنید.

چگونه کار می‌کند؟

این مرحله خیلی تاثیر داره...

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

در این مثال، دو شیء RTCPeerConnection در یک صفحه قرار دارند: pc1 و pc2 . کاربرد عملی زیادی ندارد، اما برای نشان دادن نحوه عملکرد APIها خوب است.

برقراری تماس بین همتایان WebRTC شامل سه کار است:

  • برای هر دو سر تماس، یک RTCPeerConnection ایجاد کنید و در هر سر، جریان محلی را از getUserMedia() اضافه کنید.
  • دریافت و اشتراک‌گذاری اطلاعات شبکه: نقاط انتهایی اتصال بالقوه به عنوان کاندیدهای ICE شناخته می‌شوند.
  • دریافت و اشتراک‌گذاری توضیحات محلی و راه دور: فراداده درباره رسانه‌های محلی با فرمت SDP .

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

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

  1. آلیس یک شیء RTCPeerConnection با یک هندلر onicecandidate (addEventListener('icecandidate')) ایجاد می‌کند. این کد معادل کد زیر از main.js است:
let localPeerConnection;
localPeerConnection = new RTCPeerConnection(servers);
localPeerConnection.addEventListener('icecandidate', handleConnection);
localPeerConnection.addEventListener(
    'iceconnectionstatechange', handleConnectionChange);
  1. آلیس getUserMedia() را فراخوانی می‌کند و جریان ارسالی به آن را اضافه می‌کند:
navigator.mediaDevices.getUserMedia(mediaStreamConstraints).
  then(gotLocalMediaStream).
  catch(handleLocalMediaStreamError);
function gotLocalMediaStream(mediaStream) {
  localVideo.srcObject = mediaStream;
  localStream = mediaStream;
  trace('Received local stream.');
  callButton.disabled = false;  // Enable call button.
}
localPeerConnection.addStream(localStream);
trace('Added local stream to localPeerConnection.');
  1. کنترل‌کننده onicecandidate از مرحله ۱، زمانی فراخوانی می‌شود که کاندیدهای شبکه در دسترس قرار گیرند.
  2. آلیس داده‌های کاندید سریالی شده را برای باب ارسال می‌کند. در یک برنامه واقعی، این فرآیند (که به عنوان سیگنالینگ شناخته می‌شود) از طریق یک سرویس پیام‌رسانی انجام می‌شود - شما نحوه انجام این کار را در مرحله بعدی خواهید آموخت. البته، در این مرحله، دو شیء RTCPeerConnection در یک صفحه قرار دارند و می‌توانند مستقیماً و بدون نیاز به پیام‌رسانی خارجی با هم ارتباط برقرار کنند.
  3. وقتی باب یک پیام کاندید از آلیس دریافت می‌کند، تابع addIceCandidate() را فراخوانی می‌کند تا کاندید را به توضیحات همتای راه دور اضافه کند:
function handleConnection(event) {
  const peerConnection = event.target;
  const iceCandidate = event.candidate;

  if (iceCandidate) {
    const newIceCandidate = new RTCIceCandidate(iceCandidate);
    const otherPeer = getOtherPeer(peerConnection);

    otherPeer.addIceCandidate(newIceCandidate)
      .then(() => {
        handleConnectionSuccess(peerConnection);
      }).catch((error) => {
        handleConnectionFailure(peerConnection, error);
      });

    trace(`${getPeerName(peerConnection)} ICE candidate:\n` +
          `${event.candidate.candidate}.`);
  }
}

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

  1. آلیس متد RTCPeerConnection createOffer() را اجرا می‌کند. مقدار بازگشتی یک RTCSessionDescription ارائه می‌دهد: شرح جلسه محلی آلیس:
trace('localPeerConnection createOffer start.');
localPeerConnection.createOffer(offerOptions)
  .then(createdOffer).catch(setSessionDescriptionError);
  1. در صورت موفقیت، آلیس توضیحات محلی را با استفاده از setLocalDescription() تنظیم می‌کند و سپس این توضیحات جلسه را از طریق کانال سیگنالینگ خود برای باب ارسال می‌کند.
  2. باب با استفاده از setRemoteDescription() توضیحاتی را که آلیس برایش ارسال کرده است، به عنوان توضیحات از راه دور تنظیم می‌کند.
  3. باب متد RTCPeerConnection createAnswer() را اجرا می‌کند و توضیحات راه دور خود را که از آلیس دریافت کرده است، به آن ارسال می‌کند، بنابراین یک جلسه محلی می‌تواند ایجاد شود که با جلسه او سازگار باشد. وعده createAnswer() یک RTCSessionDescription را ارسال می‌کند: باب آن را به عنوان توضیحات محلی تنظیم کرده و برای آلیس ارسال می‌کند.
  4. وقتی آلیس توضیحات جلسه باب را دریافت می‌کند، آن را با استفاده از setRemoteDescription() به عنوان توضیحات از راه دور تنظیم می‌کند.
// Logs offer creation and sets peer connection session descriptions.
function createdOffer(description) {
  trace(`Offer from localPeerConnection:\n${description.sdp}`);

  trace('localPeerConnection setLocalDescription start.');
  localPeerConnection.setLocalDescription(description)
    .then(() => {
      setLocalDescriptionSuccess(localPeerConnection);
    }).catch(setSessionDescriptionError);

  trace('remotePeerConnection setRemoteDescription start.');
  remotePeerConnection.setRemoteDescription(description)
    .then(() => {
      setRemoteDescriptionSuccess(remotePeerConnection);
    }).catch(setSessionDescriptionError);

  trace('remotePeerConnection createAnswer start.');
  remotePeerConnection.createAnswer()
    .then(createdAnswer)
    .catch(setSessionDescriptionError);
}

// Logs answer to offer creation and sets peer connection session descriptions.
function createdAnswer(description) {
  trace(`Answer from remotePeerConnection:\n${description.sdp}.`);

  trace('remotePeerConnection setLocalDescription start.');
  remotePeerConnection.setLocalDescription(description)
    .then(() => {
      setLocalDescriptionSuccess(remotePeerConnection);
    }).catch(setSessionDescriptionError);

  trace('localPeerConnection setRemoteDescription start.');
  localPeerConnection.setRemoteDescription(description)
    .then(() => {
      setRemoteDescriptionSuccess(localPeerConnection);
    }).catch(setSessionDescriptionError);
}
  1. پینگ!

امتیازهای ویژه

  1. نگاهی به chrome://webrtc-internals بیندازید. این آدرس آمار و داده‌های اشکال‌زدایی WebRTC را ارائه می‌دهد. (لیست کاملی از URLهای کروم در chrome://about موجود است.)
  2. استایل دادن به صفحه با CSS:
  • ویدیوها را کنار هم قرار دهید.
  • دکمه‌ها را با عرض یکسان و متن بزرگتر طراحی کنید.
  • مطمئن شوید که طرح‌بندی روی موبایل هم کار می‌کند.
  1. از کنسول Chrome Dev Tools، به localStream ، localPeerConnection و remotePeerConnection نگاه کنید.
  2. از کنسول، به localPeerConnectionpc1.localDescription نگاه کنید. فرمت SDP چگونه است؟

آنچه آموختید

در این مرحله یاد گرفتید که چگونه:

  • تفاوت‌های مرورگر را با فایل WebRTC، adapter.js، خلاصه کنید.
  • برای پخش ویدئو از API RTCPeerConnection استفاده کنید.
  • ضبط و پخش رسانه را کنترل کنید.
  • برای فعال کردن تماس WebRTC، اطلاعات رسانه و شبکه را بین دستگاه‌های همتا به اشتراک بگذارید.

نسخه کامل این مرحله در پوشه مرحله ۲ قرار دارد.

نکات

  • در این مرحله چیزهای زیادی برای یادگیری وجود دارد! برای یافتن منابع دیگری که RTCPeerConnection را با جزئیات بیشتری توضیح می‌دهند، به webrtc.org نگاهی بیندازید. این صفحه شامل پیشنهاداتی برای چارچوب‌های جاوا اسکریپت است - اگر مایل به استفاده از WebRTC هستید، اما نمی‌خواهید با APIها سر و کله بزنید.
  • برای اطلاعات بیشتر در مورد شیم adapter.js به مخزن گیت‌هاب adapter.js مراجعه کنید.
  • می‌خواهید ببینید بهترین برنامه چت تصویری دنیا چه شکلی است؟ نگاهی به AppRTC، برنامه استاندارد پروژه WebRTC برای تماس‌های WebRTC بیندازید: app ، code . زمان راه‌اندازی تماس کمتر از ۵۰۰ میلی‌ثانیه است.

بهترین شیوه

  • برای اینکه کد خود را برای آینده آماده کنید، از APIهای جدید مبتنی بر Promise استفاده کنید و با استفاده از adapter.js سازگاری با مرورگرهایی که از آنها پشتیبانی نمی‌کنند را فعال کنید.

بعدی

این مرحله نحوه استفاده از WebRTC برای پخش ویدیو بین همسالان را نشان می‌دهد - اما این آزمایشگاه کد همچنین در مورد داده‌ها است!

در مرحله بعد، نحوه استریم داده‌های دلخواه با استفاده از RTCDataChannel را خواهید آموخت.

۶. استفاده از RTCDataChannel برای تبادل داده

آنچه یاد خواهید گرفت

  • نحوه تبادل داده بین نقاط پایانی WebRTC (همتاها).

نسخه کامل این مرحله در پوشه step-03 قرار دارد.

HTML خود را به‌روزرسانی کنید

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

عناصر video و button را از index.html حذف کرده و آنها را با کد HTML زیر جایگزین کنید:

<textarea id="dataChannelSend" disabled
    placeholder="Press Start, enter some text, then press Send."></textarea>
<textarea id="dataChannelReceive" disabled></textarea>

<div id="buttons">
  <button id="startButton">Start</button>
  <button id="sendButton">Send</button>
  <button id="closeButton">Stop</button>
</div>

یکی از این ناحیه‌های متنی برای وارد کردن متن خواهد بود و دیگری متن را به صورت جاری بین نظیرها نمایش می‌دهد.

index.html اکنون باید به این شکل باشد:

<!DOCTYPE html>
<html>

<head>

  <title>Realtime communication with WebRTC</title>

  <link rel="stylesheet" href="css/main.css" />

</head>

<body>

  <h1>Realtime communication with WebRTC</h1>

  <textarea id="dataChannelSend" disabled
    placeholder="Press Start, enter some text, then press Send."></textarea>
  <textarea id="dataChannelReceive" disabled></textarea>

  <div id="buttons">
    <button id="startButton">Start</button>
    <button id="sendButton">Send</button>
    <button id="closeButton">Stop</button>
  </div>

  <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
  <script src="js/main.js"></script>

</body>

</html>

جاوا اسکریپت خود را به‌روزرسانی کنید

فایل main.js را با محتوای فایل step-03/js/main.js جایگزین کنید.

پخش داده‌ها بین دستگاه‌های همتا را امتحان کنید: فایل index.html را باز کنید، برای تنظیم اتصال دستگاه همتا، روی «شروع» کلیک کنید، متنی را در textarea سمت چپ وارد کنید، سپس برای انتقال متن با استفاده از کانال‌های داده WebRTC، روی «ارسال» کلیک کنید.

چگونه کار می‌کند؟

این کد از RTCPeerConnection و RTCDataChannel برای فعال کردن تبادل پیام‌های متنی استفاده می‌کند.

بخش عمده‌ای از کد این مرحله مشابه مثال RTCPeerConnection است.

توابع sendData() و createConnection() بیشتر کدهای جدید را دارند:

function createConnection() {
  dataChannelSend.placeholder = '';
  var servers = null;
  pcConstraint = null;
  dataConstraint = null;
  trace('Using SCTP based data channels');
  // For SCTP, reliable and ordered delivery is true by default.
  // Add localConnection to global scope to make it visible
  // from the browser console.
  window.localConnection = localConnection =
      new RTCPeerConnection(servers, pcConstraint);
  trace('Created local peer connection object localConnection');

  sendChannel = localConnection.createDataChannel('sendDataChannel',
      dataConstraint);
  trace('Created send data channel');

  localConnection.onicecandidate = iceCallback1;
  sendChannel.onopen = onSendChannelStateChange;
  sendChannel.onclose = onSendChannelStateChange;

  // Add remoteConnection to global scope to make it visible
  // from the browser console.
  window.remoteConnection = remoteConnection =
      new RTCPeerConnection(servers, pcConstraint);
  trace('Created remote peer connection object remoteConnection');

  remoteConnection.onicecandidate = iceCallback2;
  remoteConnection.ondatachannel = receiveChannelCallback;

  localConnection.createOffer().then(
    gotDescription1,
    onCreateSessionDescriptionError
  );
  startButton.disabled = true;
  closeButton.disabled = false;
}

function sendData() {
  var data = dataChannelSend.value;
  sendChannel.send(data);
  trace('Sent Data: ' + data);
}

سینتکس RTCDataChannel عمداً شبیه به WebSocket است، با یک متد send() و یک رویداد message .

به استفاده از dataConstraint توجه کنید. کانال‌های داده را می‌توان طوری پیکربندی کرد که انواع مختلف اشتراک‌گذاری داده‌ها را فعال کنند - برای مثال، اولویت‌بندی تحویل قابل اعتماد بر عملکرد. می‌توانید اطلاعات بیشتر در مورد گزینه‌ها را در شبکه توسعه‌دهندگان موزیلا بیابید.

امتیازهای ویژه

  1. با SCTP ، پروتکلی که توسط کانال‌های داده WebRTC استفاده می‌شود، تحویل داده قابل اعتماد و مرتب به طور پیش‌فرض فعال است. چه زمانی ممکن است RTCDataChannel نیاز به ارائه تحویل قابل اعتماد داده‌ها داشته باشد و چه زمانی ممکن است عملکرد مهم‌تر باشد - حتی اگر این به معنای از دست دادن مقداری داده باشد؟
  2. از CSS برای بهبود طرح‌بندی صفحه استفاده کنید و یک ویژگی placeholder به ناحیه متنی "dataChannelReceive" اضافه کنید.
  3. صفحه را روی دستگاه تلفن همراه آزمایش کنید.

آنچه آموختید

در این مرحله یاد گرفتید که چگونه:

  • ایجاد ارتباط بین دو همتای WebRTC.
  • تبادل داده‌های متنی بین نظیرها.

نسخه کامل این مرحله در پوشه step-03 قرار دارد.

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

بعدی

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

۷. یک سرویس سیگنالینگ برای تبادل پیام‌ها راه‌اندازی کنید

آنچه یاد خواهید گرفت

در این مرحله، شما یاد خواهید گرفت که چگونه:

  • npm برای نصب وابستگی‌های پروژه طبق آنچه در package.json مشخص شده است استفاده کنید.
  • یک سرور Node.js اجرا کنید و از node-static برای ارائه فایل‌های استاتیک استفاده کنید.
  • با استفاده از Socket.IO یک سرویس پیام‌رسانی روی Node.js راه‌اندازی کنید.
  • از آن برای ایجاد «اتاق» و تبادل پیام استفاده کنید.

نسخه کامل این مرحله در پوشه step-04 قرار دارد.

مفاهیم

برای راه‌اندازی و نگهداری یک تماس WebRTC، کلاینت‌های WebRTC (همتاها) باید فراداده‌ها را تبادل کنند:

  • اطلاعات کاندیدا (شبکه).
  • پیام‌هایی را ارائه دهید و به آنها پاسخ دهید که اطلاعاتی در مورد رسانه، مانند وضوح تصویر و کدک‌ها، ارائه می‌دهند.

به عبارت دیگر، قبل از اینکه پخش نظیر به نظیر صدا، تصویر یا داده بتواند انجام شود، تبادل فراداده (metadata) مورد نیاز است. این فرآیند سیگنالینگ (signaling) نامیده می‌شود.

در مراحل قبلی، اشیاء RTCPeerConnection فرستنده و گیرنده در یک صفحه قرار دارند، بنابراین «سیگنالینگ» صرفاً به معنای انتقال فراداده بین اشیاء است.

در یک برنامه دنیای واقعی، فرستنده و گیرنده RTCPeerConnections در صفحات وب روی دستگاه‌های مختلف اجرا می‌شوند و شما به روشی نیاز دارید که آنها بتوانند فراداده‌ها را با هم تبادل کنند.

برای این کار، شما از یک سرور سیگنالینگ استفاده می‌کنید: سروری که می‌تواند پیام‌ها را بین کلاینت‌های WebRTC (همتاها) منتقل کند. پیام‌های واقعی متن ساده هستند: اشیاء جاوا اسکریپت رشته‌ای.

پیش‌نیاز: نصب Node.js

برای اجرای مراحل بعدی این codelab (پوشه‌های step-04 تا step-06 ) باید یک سرور را روی localhost با استفاده از Node.js اجرا کنید.

می‌توانید Node.js را از این لینک یا از طریق مدیر بسته‌ی مورد نظر خود دانلود و نصب کنید.

پس از نصب، می‌توانید وابستگی‌های مورد نیاز برای مراحل بعدی (اجرای npm install ) را وارد کنید، و همچنین یک سرور محلی کوچک را برای اجرای codelab اجرا کنید (اجرای node index.js ). این دستورات بعداً، در صورت نیاز، نمایش داده خواهند شد.

درباره برنامه

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

در این مرحله، شما یک سرور سیگنالینگ ساده Node.js با استفاده از ماژول Socket.IO Node.js و کتابخانه جاوا اسکریپت برای پیام‌رسانی خواهید ساخت. تجربه کار با Node.js و Socket.IO مفید خواهد بود، اما ضروری نیست؛ اجزای پیام‌رسانی بسیار ساده هستند.

در این مثال، سرور (برنامه Node.js) در index.js پیاده‌سازی شده است و کلاینتی که روی آن اجرا می‌شود (برنامه وب) در index.html پیاده‌سازی شده است.

برنامه Node.js در این مرحله دو وظیفه دارد.

اول، به عنوان یک رله پیام عمل می‌کند:

socket.on('message', function (message) {
  log('Got message: ', message);
  socket.broadcast.emit('message', message);
});

دوم، «اتاق‌های» چت تصویری WebRTC را مدیریت می‌کند:

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

برنامه ساده WebRTC ما به حداکثر دو نفر اجازه می‌دهد تا یک اتاق را به اشتراک بگذارند.

اچ‌تی‌ام‌ال و جاوااسکریپت

فایل index.html را به این صورت به‌روزرسانی کنید:

<!DOCTYPE html>
<html>

<head>

  <title>Realtime communication with WebRTC</title>

  <link rel="stylesheet" href="css/main.css" />

</head>

<body>

  <h1>Realtime communication with WebRTC</h1>

  <script src="/socket.io/socket.io.js"></script>
  <script src="js/main.js"></script>
  
</body>

</html>

در این مرحله چیزی در صفحه نخواهید دید: تمام ثبت وقایع در کنسول مرورگر انجام می‌شود. (برای مشاهده کنسول در کروم، Ctrl-Shift-J یا اگر از مک استفاده می‌کنید، Command-Option-J را فشار دهید.)

js/main.js را با کد زیر جایگزین کنید:

'use strict';

var isInitiator;

window.room = prompt("Enter room name:");

var socket = io.connect();

if (room !== "") {
  console.log('Message from client: Asking to join room ' + room);
  socket.emit('create or join', room);
}

socket.on('created', function(room, clientId) {
  isInitiator = true;
});

socket.on('full', function(room) {
  console.log('Message from client: Room ' + room + ' is full :^(');
});

socket.on('ipaddr', function(ipaddr) {
  console.log('Message from client: Server IP address is ' + ipaddr);
});

socket.on('joined', function(room, clientId) {
  isInitiator = false;
});

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

تنظیم Socket.IO برای اجرا روی Node.js

در فایل HTML، ممکن است دیده باشید که از فایل Socket.IO استفاده می‌کنید:

<script src="/socket.io/socket.io.js"></script>

در بالاترین سطح دایرکتوری کاری خود، فایلی با نام package.json با محتوای زیر ایجاد کنید:

{
  "name": "webrtc-codelab",
  "version": "0.0.1",
  "description": "WebRTC codelab",
  "dependencies": {
    "node-static": "^0.7.10",
    "socket.io": "^1.2.0"
  }
}

این یک مانیفست برنامه است که به Node Package Manager ( npm ) می‌گوید کدام وابستگی‌های پروژه را نصب کند.

برای نصب وابستگی‌ها (مانند /socket.io/socket.io.js )، دستور زیر را از ترمینال خط فرمان، در دایرکتوری کاری خود اجرا کنید:

npm install

شما باید یک گزارش نصب ببینید که چیزی شبیه به این را به پایان می‌رساند:

3ab06b7bcc7664b9.png

همانطور که می‌بینید، npm وابستگی‌های تعریف شده در package.json را نصب کرده است.

یک فایل جدید به نام index.js در بالاترین سطح دایرکتوری کاری خود (نه در دایرکتوری js ) ایجاد کنید و کد زیر را به آن اضافه کنید:

'use strict';

var os = require('os');
var nodeStatic = require('node-static');
var http = require('http');
var socketIO = require('socket.io');

var fileServer = new(nodeStatic.Server)();
var app = http.createServer(function(req, res) {
  fileServer.serve(req, res);
}).listen(8080);

var io = socketIO.listen(app);
io.sockets.on('connection', function(socket) {

  // convenience function to log server messages on the client
  function log() {
    var array = ['Message from server:'];
    array.push.apply(array, arguments);
    socket.emit('log', array);
  }

  socket.on('message', function(message) {
    log('Client said: ', message);
    // for a real app, would be room-only (not broadcast)
    socket.broadcast.emit('message', message);
  });

  socket.on('create or join', function(room) {
    log('Received request to create or join room ' + room);

    var clientsInRoom = io.sockets.adapter.rooms[room];
    var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;

    log('Room ' + room + ' now has ' + numClients + ' client(s)');

    if (numClients === 0) {
      socket.join(room);
      log('Client ID ' + socket.id + ' created room ' + room);
      socket.emit('created', room, socket.id);

    } else if (numClients === 1) {
      log('Client ID ' + socket.id + ' joined room ' + room);
      io.sockets.in(room).emit('join', room);
      socket.join(room);
      socket.emit('joined', room, socket.id);
      io.sockets.in(room).emit('ready');
    } else { // max two clients
      socket.emit('full', room);
    }
  });

  socket.on('ipaddr', function() {
    var ifaces = os.networkInterfaces();
    for (var dev in ifaces) {
      ifaces[dev].forEach(function(details) {
        if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
          socket.emit('ipaddr', details.address);
        }
      });
    }
  });

});

از ترمینال خط فرمان، دستور زیر را در دایرکتوری کاری اجرا کنید:

node index.js

از مرورگر خود، localhost:8080 را باز کنید.

هر بار که این URL را باز می‌کنید، از شما خواسته می‌شود نام اتاق را وارد کنید. برای پیوستن به یک اتاق، هر بار نام اتاق یکسانی را انتخاب کنید، مانند 'foo'.

یک صفحه تب جدید باز کنید و دوباره localhost:8080 را باز کنید. همان نام اتاق را انتخاب کنید.

در تب یا پنجره سوم، localhost:8080 را باز کنید. دوباره همان نام اتاق را انتخاب کنید.

کنسول را در هر یک از تب‌ها بررسی کنید: باید گزارش جاوا اسکریپت بالا را ببینید.

امتیازهای ویژه

  1. چه مکانیسم‌های پیام‌رسانی جایگزینی ممکن است وجود داشته باشد؟ با استفاده از WebSocket «خالص» ممکن است با چه مشکلاتی مواجه شوید؟
  2. چه مشکلاتی ممکن است در مقیاس‌بندی این برنامه وجود داشته باشد؟ آیا می‌توانید روشی برای آزمایش هزاران یا میلیون‌ها درخواست اتاق همزمان ایجاد کنید؟
  3. این برنامه از یک تابع جاوا اسکریپت برای دریافت نام اتاق استفاده می‌کند. راهی برای دریافت نام اتاق از URL پیدا کنید. برای مثال، localhost:8080/foo نام اتاق را foo می‌دهد.

آنچه آموختید

در این مرحله، شما یاد گرفتید که چگونه:

  • از npm برای نصب وابستگی‌های پروژه طبق آنچه در package.json مشخص شده است استفاده کنید.
  • یک سرور Node.js را برای فایل‌های استاتیک سرور اجرا کنید.
  • با استفاده از socket.io یک سرویس پیام‌رسانی روی Node.js راه‌اندازی کنید.
  • از آن برای ایجاد «اتاق» و تبادل پیام استفاده کنید.

نسخه کامل این مرحله در پوشه step-04 قرار دارد.

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

بعدی

بیاموزید که چگونه از سیگنالینگ برای فعال کردن اتصال همتا بین دو کاربر استفاده کنید.

۸. اتصال همتا و سیگنالینگ را ترکیب کنید

آنچه یاد خواهید گرفت

در این مرحله شما یاد خواهید گرفت که چگونه:

  • اجرای یک سرویس سیگنالینگ WebRTC با استفاده از Socket.IO روی Node.js
  • از آن سرویس برای تبادل ابرداده WebRTC بین دستگاه‌های همتا استفاده کنید.

نسخه کامل این مرحله در پوشه step-05 قرار دارد.

جایگزینی HTML و جاوا اسکریپت

محتویات فایل index.html را با موارد زیر جایگزین کنید:

<!DOCTYPE html>
<html>

<head>

  <title>Realtime communication with WebRTC</title>

  <link rel="stylesheet" href="/css/main.css" />

</head>

<body>

  <h1>Realtime communication with WebRTC</h1>

  <div id="videos">
    <video id="localVideo" autoplay muted></video>
    <video id="remoteVideo" autoplay></video>
  </div>

  <script src="/socket.io/socket.io.js"></script>
  <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
  <script src="js/main.js"></script>
  
</body>

</html>

محتوای فایل step-05/js/main.js را جایگزین js/main.js کنید.

سرور Node.js را اجرا کنید

اگر این codelab را از دایرکتوری کاری خود دنبال نمی‌کنید، ممکن است لازم باشد وابستگی‌های پوشه step-05 یا پوشه کاری فعلی خود را نصب کنید. دستور زیر را از دایرکتوری کاری خود اجرا کنید:

npm install

پس از نصب، اگر سرور Node.js شما در حال اجرا نیست، با فراخوانی دستور زیر در دایرکتوری کاری ، آن را راه‌اندازی کنید:

node index.js

مطمئن شوید که از نسخه index.js مرحله قبل که Socket.IO را پیاده‌سازی می‌کند، استفاده می‌کنید. برای اطلاعات بیشتر در مورد Node و Socket IO، بخش «تنظیم یک سرویس سیگنالینگ برای تبادل پیام‌ها» را مرور کنید.

از مرورگر خود، localhost:8080 را باز کنید.

دوباره localhost:8080 را در یک تب یا پنجره جدید باز کنید. یکی از عناصر ویدیو، جریان محلی را از getUserMedia() نمایش می‌دهد و دیگری ویدیوی «از راه دور» را که از طریق RTCPeerconnection پخش شده است، نشان می‌دهد.

مشاهده‌ی لاگین در کنسول مرورگر.

امتیازهای ویژه

  1. این برنامه فقط از چت تصویری یک به یک پشتیبانی می‌کند. چگونه می‌توانید طراحی را تغییر دهید تا بیش از یک نفر بتوانند از یک اتاق چت تصویری مشترک استفاده کنند؟
  2. در این مثال، نام اتاق foo به صورت پیش‌فرض تعریف شده است. بهترین راه برای فعال کردن نام‌های دیگر اتاق‌ها چیست؟
  3. کاربران چگونه می‌توانند نام اتاق را به اشتراک بگذارند؟ سعی کنید جایگزینی برای اشتراک‌گذاری نام اتاق‌ها ایجاد کنید.
  4. چطور تونستی برنامه رو تغییر بدی؟

آنچه آموختید

در این مرحله یاد گرفتید که چگونه:

  • یک سرویس سیگنال‌دهی WebRTC را با استفاده از Socket.IO که روی Node.js اجرا می‌شود، اجرا کنید.
  • از آن سرویس برای تبادل ابرداده WebRTC بین دستگاه‌های همتا استفاده کنید.

نسخه کامل این مرحله در پوشه step-05 قرار دارد.

نکات

  • آمار و داده‌های اشکال‌زدایی WebRTC از chrome://webrtc-internals در دسترس هستند.
  • test.webrtc.org می‌تواند برای بررسی محیط محلی شما و آزمایش دوربین و میکروفون شما مورد استفاده قرار گیرد.
  • اگر با ذخیره سازی (caching) مشکل دارید، موارد زیر را امتحان کنید:
  • با نگه داشتن ctrl و کلیک روی دکمه Reload، یک به‌روزرسانی اساسی انجام دهید.
  • مرورگر را مجدداً راه اندازی کنید
  • npm cache clean از خط فرمان اجرا کنید.

بعدی

بیاموزید که چگونه عکس بگیرید، داده‌های تصویر را دریافت کنید و آن را بین دستگاه‌های از راه دور به اشتراک بگذارید.

۹. عکس بگیرید و آن را از طریق کانال داده به اشتراک بگذارید

آنچه یاد خواهید گرفت

در این مرحله یاد خواهید گرفت که چگونه:

  • یک عکس بگیرید و با استفاده از عنصر canvas، داده‌ها را از آن دریافت کنید.
  • تبادل داده‌های تصویر با یک کاربر از راه دور.

نسخه کامل این مرحله در پوشه step-06 قرار دارد.

چگونه کار می‌کند؟

قبلاً یاد گرفتید که چگونه با استفاده از RTCDataChannel پیام‌های متنی رد و بدل کنید.

این مرحله امکان اشتراک‌گذاری کل فایل‌ها را فراهم می‌کند: در این مثال، عکس‌های گرفته شده از طریق getUserMedia() .

بخش‌های اصلی این مرحله به شرح زیر است:

  1. یک کانال داده ایجاد کنید. توجه داشته باشید که در این مرحله هیچ جریان رسانه‌ای به اتصال همتا اضافه نمی‌کنید.
  2. ضبط جریان ویدیوی وب‌کم کاربر با getUserMedia() :
var video = document.getElementById('video');

function grabWebCamVideo() {
  console.log('Getting user media (video) ...');
  navigator.mediaDevices.getUserMedia({
    video: true
  })
  .then(gotStream)
  .catch(function(e) {
    alert('getUserMedia() error: ' + e.name);
  });
}
  1. وقتی کاربر روی دکمه‌ی Snap کلیک می‌کند، یک snapshot (یک فریم ویدیویی) از جریان ویدیو گرفته می‌شود و در یک عنصر canvas نمایش داده می‌شود:
var photo = document.getElementById('photo');
var photoContext = photo.getContext('2d');

function snapPhoto() {
  photoContext.drawImage(video, 0, 0, photo.width, photo.height);
  show(photo, sendBtn);
}
  1. وقتی کاربر روی دکمه ارسال کلیک می‌کند، تصویر به بایت تبدیل شده و از طریق یک کانال داده ارسال می‌شود:
function sendPhoto() {
  // Split data channel message in chunks of this byte length.
  var CHUNK_LEN = 64000;
  var img = photoContext.getImageData(0, 0, photoContextW, photoContextH),
    len = img.data.byteLength,
    n = len / CHUNK_LEN | 0;

  console.log('Sending a total of ' + len + ' byte(s)');
  dataChannel.send(len);

  // split the photo and send in chunks of about 64KB
  for (var i = 0; i < n; i++) {
    var start = i * CHUNK_LEN,
      end = (i + 1) * CHUNK_LEN;
    console.log(start + ' - ' + (end - 1));
    dataChannel.send(img.data.subarray(start, end));
  }

  // send the reminder, if any
  if (len % CHUNK_LEN) {
    console.log('last ' + len % CHUNK_LEN + ' byte(s)');
    dataChannel.send(img.data.subarray(n * CHUNK_LEN));
  }
}
  1. طرف گیرنده، بایت‌های پیام کانال داده را به یک تصویر تبدیل کرده و تصویر را به کاربر نمایش می‌دهد:
function receiveDataChromeFactory() {
  var buf, count;

  return function onmessage(event) {
    if (typeof event.data === 'string') {
      buf = window.buf = new Uint8ClampedArray(parseInt(event.data));
      count = 0;
      console.log('Expecting a total of ' + buf.byteLength + ' bytes');
      return;
    }

    var data = new Uint8ClampedArray(event.data);
    buf.set(data, count);

    count += data.byteLength;
    console.log('count: ' + count);

    if (count === buf.byteLength) {
      // we're done: all data chunks have been received
      console.log('Done. Rendering photo.');
      renderPhoto(buf);
    }
  };
}

function renderPhoto(data) {
  var canvas = document.createElement('canvas');
  canvas.width = photoContextW;
  canvas.height = photoContextH;
  canvas.classList.add('incomingPhoto');
  // trail is the element holding the incoming images
  trail.insertBefore(canvas, trail.firstChild);

  var context = canvas.getContext('2d');
  var img = context.createImageData(photoContextW, photoContextH);
  img.data.set(data);
  context.putImageData(img, 0, 0);
}

کد را دریافت کنید

محتویات پوشه work خود را با محتویات مرحله 6 جایگزین کنید. فایل index.html شما در work اکنون باید به شکل زیر باشد**:**

<!DOCTYPE html>
<html>

<head>

  <title>Realtime communication with WebRTC</title>

  <link rel="stylesheet" href="/css/main.css" />

</head>

<body>

  <h1>Realtime communication with WebRTC</h1>

  <h2>
    <span>Room URL: </span><span id="url">...</span>
  </h2>

  <div id="videoCanvas">
    <video id="camera" autoplay></video>
    <canvas id="photo"></canvas>
  </div>

  <div id="buttons">
    <button id="snap">Snap</button><span> then </span><button id="send">Send</button>
    <span> or </span>
    <button id="snapAndSend">Snap &amp; Send</button>
  </div>

  <div id="incoming">
    <h2>Incoming photos</h2>
    <div id="trail"></div>
  </div>

  <script src="/socket.io/socket.io.js"></script>
  <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
  <script src="js/main.js"></script>

</body>

</html>

اگر این codelab را از دایرکتوری کاری خود دنبال نمی‌کنید، ممکن است لازم باشد وابستگی‌های پوشه step-06 یا پوشه کاری فعلی خود را نصب کنید. کافیست دستور زیر را از دایرکتوری کاری خود اجرا کنید:

npm install

پس از نصب، اگر سرور Node.js شما در حال اجرا نیست، با فراخوانی دستور زیر از دایرکتوری کاری خود، آن را راه‌اندازی کنید:

node index.js

مطمئن شوید که از نسخه‌ای از index.js استفاده می‌کنید که Socket.IO را پیاده‌سازی می‌کند و به یاد داشته باشید که در صورت ایجاد تغییرات، سرور Node.js خود را مجدداً راه‌اندازی کنید. برای اطلاعات بیشتر در مورد Node و Socket IO، بخش «تنظیم یک سرویس سیگنالینگ برای تبادل پیام‌ها» را مرور کنید.

در صورت لزوم، روی دکمه‌ی «مجاز» کلیک کنید تا به برنامه اجازه دهید از وب‌کم شما استفاده کند.

برنامه یک شناسه اتاق تصادفی ایجاد می‌کند و آن شناسه را به URL اضافه می‌کند. URL را از نوار آدرس در یک برگه یا پنجره جدید مرورگر باز کنید.

روی دکمه‌ی «Snap & Send» کلیک کنید و سپس به قسمت «Incoming» در تب دیگر در پایین صفحه نگاه کنید. این برنامه عکس‌ها را بین تب‌ها منتقل می‌کند.

شما باید چیزی شبیه به این را ببینید:

۹۱۱b40f36ba6ba8.png

امتیازهای ویژه

  1. چگونه می‌توان کد را تغییر داد تا امکان اشتراک‌گذاری هر نوع فایلی فراهم شود؟

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

آنچه آموختید

  • نحوه گرفتن عکس و دریافت داده‌ها از آن با استفاده از عنصر canvas.
  • چگونه آن داده‌ها را با یک کاربر از راه دور تبادل کنیم.

نسخه کامل این مرحله در پوشه step-06 قرار دارد.

۱۰. تبریک

شما یک اپلیکیشن برای پخش زنده ویدیو و تبادل داده ساختید!

آنچه آموختید

در این آزمایشگاه کد یاد گرفتید که چگونه:

  • از وب کم خود ویدیو بگیرید.
  • پخش ویدئو با RTCPeerConnection.
  • داده‌ها را با RTCDataChannel پخش کنید.
  • یک سرویس سیگنالینگ برای تبادل پیام راه‌اندازی کنید.
  • اتصال همتا و سیگنالینگ را ترکیب کنید.
  • عکس بگیرید و آن را از طریق کانال داده به اشتراک بگذارید.

مراحل بعدی

بیشتر بدانید

  • طیف وسیعی از منابع برای شروع کار با WebRTC در webrtc.org موجود است.