תחילת השימוש ב-WebRTC

‫WebRTC היא חזית חדשה במלחמה הארוכה למען אינטרנט פתוח וחופשי.

ברנדן אייך (Brendan Eich), ממציא JavaScript

תקשורת בזמן אמת ללא פלאגינים

דמיינו עולם שבו הטלפון, הטלוויזיה והמחשב שלכם יכולים לתקשר בפלטפורמה משותפת. תארו לעצמכם שאפשר להוסיף בקלות צ'אט וידאו ושיתוף נתונים ישירות לאפליקציית האינטרנט. זו המטרה של WebRTC.

רוצים לנסות? פרוטוקול WebRTC זמין במחשבים ובניידים בדפדפנים Google Chrome,‏ Safari,‏ Firefox ו-Opera. אפשר להתחיל עם אפליקציית הווידאו צ'אט הפשוטה בכתובת appr.tc:

  1. פותחים את appr.tc בדפדפן.
  2. לוחצים על הצטרפות כדי להצטרף לחדר צ'אט ולאפשר לאפליקציה להשתמש במצלמת האינטרנט.
  3. פותחים את כתובת ה-URL שמוצגת בסוף הדף בכרטיסייה חדשה, או אפילו טוב יותר, במחשב אחר.

התחלה מהירה

אין לכם זמן לקרוא את המאמר הזה או שאתם רוצים רק את הקוד?

  • כדי לקבל סקירה כללית על WebRTC, אפשר לצפות בסרטון הבא מ-Google I/O או לעיין בסליידים האלה:
  • אם לא השתמשתם ב-getUserMedia API, תוכלו לעיין במאמרים Capture audio and video in HTML5 ו-simpl.info getUserMedia.
  • כדי לקבל מידע על RTCPeerConnection API, אפשר לעיין בדוגמה הבאה ובמאמר 'simpl.info RTCPeerConnection'.
  • כדי ללמוד איך WebRTC משתמש בשרתים לאיתות, ובחומת אש וב-NAT traversal, אפשר לעיין בקוד וביומני המסוף מ-appr.tc.
  • לא רוצים לחכות ורוצים לנסות את WebRTC כבר עכשיו? אפשר לנסות חלק מיותר מ-20 ההדגמות שמשתמשות בממשקי ה-API של WebRTC JavaScript.
  • נתקלתם בבעיות במחשב וב-WebRTC? נכנסים אל פותר הבעיות ב-WebRTC.

אפשר גם לעבור ישירות אל הסדנה ללימוד WebRTC, מדריך מפורט שמסביר איך לבנות אפליקציה מלאה לשיחות וידאו, כולל שרת פשוט לאיתות.

היסטוריה קצרה מאוד של WebRTC

אחד האתגרים הגדולים האחרונים באינטרנט הוא לאפשר תקשורת בין אנשים באמצעות קול ווידאו: תקשורת בזמן אמת, או RTC בקיצור. השימוש ב-RTC באפליקציית אינטרנט צריך להיות טבעי כמו הזנת טקסט בשדה להזנת טקסט. בלי זה, היכולת שלכם לחדש ולפתח דרכים חדשות לאינטראקציה עם אנשים מוגבלת.

בעבר, טכנולוגיית ה-RTC הייתה מורכבת ושימשה בעיקר חברות גדולות. כדי להשתמש בה היה צריך לקבל רישיון לטכנולוגיות אודיו ווידאו יקרות או לפתח אותן באופן עצמאי. שילוב של טכנולוגיית RTC עם תוכן, נתונים ושירותים קיימים היה קשה וגוזל זמן, במיוחד באינטרנט.

צ'אט הווידאו ב-Gmail הפך לפופולרי בשנת 2008, ובשנת 2011 השיקה Google את Hangouts, שמשתמש ב-Talk (כמו Gmail). ‫Google רכשה את GIPS, חברה שפיתחה רכיבים רבים שנדרשים ל-RTC, כמו קודקים וטכניקות לביטול הד. ‫Google פרסמה את הטכנולוגיות שפותחו על ידי GIPS בקוד פתוח, ויצרה קשר עם גופי תקנים רלוונטיים ב-Internet Engineering Task Force‏ (IETF) וב-World Wide Web Consortium‏ (W3C) כדי להבטיח קונצנזוס בתעשייה. במאי 2011, חברת Ericsson יצרה את ההטמעה הראשונה של WebRTC.

‫WebRTC מיישם תקנים פתוחים לתקשורת בזמן אמת של וידאו, אודיו ונתונים ללא צורך בתוספים. הצורך היה אמיתי:

  • שירותי אינטרנט רבים השתמשו ב-RTC, אבל נדרשו הורדות, אפליקציות מקוריות או פלאגינים. האפליקציות האלה כוללות את Skype,‏ Facebook ו-Hangouts.
  • הורדה, התקנה ועדכון של תוספים הם תהליכים מורכבים, שעלולים לגרום לשגיאות ולתסכול.
  • קשה לפרוס, לנפות באגים, לפתור בעיות, לבדוק ולתחזק תוספים – ויכול להיות שיידרש רישוי ושילוב עם טכנולוגיה מורכבת ויקרה. לפעמים קשה לשכנע אנשים להתקין תוספים מלכתחילה.

עקרונות הבסיס של פרויקט WebRTC הם שממשקי ה-API שלו צריכים להיות בקוד פתוח, ללא תשלום, סטנדרטיים, מובנים בדפדפני אינטרנט ויעילים יותר מטכנולוגיות קיימות.

איפה אנחנו עכשיו?

נעשה שימוש ב-WebRTC באפליקציות שונות, כמו Google Meet. ‫WebRTC שולב גם עם WebKitGTK+‎ ועם אפליקציות מקומיות של Qt.

‫WebRTC מטמיע את שלושת ממשקי ה-API האלה: ‫– MediaStream (נקרא גם getUserMedia) ‫– RTCPeerConnection ‫– RTCDataChannel

ממשקי ה-API מוגדרים בשני המפרטים האלה:

כל שלושת ממשקי ה-API נתמכים בנייד ובמחשב על ידי Chrome,‏ Safari,‏ Firefox,‏ Edge ו-Opera.

getUserMedia: דוגמאות וקוד אפשר למצוא בדוגמאות ל-WebRTC או לנסות את הדוגמאות המדהימות של כריס וילסון שמשתמשות ב-getUserMedia כקלט לאודיו באינטרנט.

RTCPeerConnection: כדי לראות הדגמה פשוטה ואפליקציה עם פונקציונליות מלאה של צ'אט וידאו, אפשר לעיין בדוגמאות של WebRTC לחיבור בין עמיתים וב-appr.tc. האפליקציה הזו משתמשת ב-adapter.js, שהוא shim של JavaScript שמתוחזק על ידי Google בעזרת קהילת WebRTC, כדי להסתיר את ההבדלים בין הדפדפנים ואת השינויים במפרט.

RTCDataChannel: כדי לראות את זה בפעולה, אפשר לעיין בדוגמאות ל-WebRTC ולבדוק את אחת ההדגמות של ערוץ הנתונים.

ב-WebRTC codelab מוסבר איך להשתמש בכל שלושת ממשקי ה-API כדי ליצור אפליקציה פשוטה לשיחות וידאו ולשיתוף קבצים.

השיחה הראשונה ב-WebRTC

אפליקציות WebRTC צריכות לבצע כמה פעולות:

  • לקבל סטרימינג של אודיו, וידאו או נתונים אחרים.
  • קבלת מידע על הרשת, כמו כתובות IP ויציאות, והחלפת המידע עם לקוחות WebRTC אחרים (שנקראים עמיתים) כדי לאפשר חיבור, גם דרך NAT וחומות אש.
  • לנהל את התקשורת של האיתות כדי לדווח על שגיאות ולהתחיל או לסיים סשנים.
  • החלפת מידע על מדיה ועל יכולות הלקוח, כמו רזולוציה וקודקים.
  • לשדר אודיו, וידאו או נתונים בסטרימינג.

כדי לקבל נתונים של סטרימינג ולשלוח אותם, WebRTC מטמיע את ממשקי ה-API הבאים:

  • ל-MediaStream יש גישה לזרמי נתונים, כמו מהמצלמה והמיקרופון של המשתמש.
  • RTCPeerConnection מאפשרת לבצע שיחות אודיו או וידאו עם אמצעים להצפנה ולניהול רוחב פס.
  • RTCDataChannel מאפשרת תקשורת ישירה בין משתמשים של נתונים כלליים.

(בהמשך יש דיון מפורט על ההיבטים של הרשת והאיתות ב-WebRTC).

MediaStream API (נקרא גם getUserMedia API)

MediaStream API מייצג זרמים מסונכרנים של מדיה. לדוגמה, לשידור שמוזן ממצלמה ומיקרופון יש רצועות וידאו ואודיו מסונכרנות. (חשוב לא להתבלבל בין MediaStreamTrack לבין האלמנט <track>, שהוא משהו שונה לחלוטין).

הדרך הקלה ביותר להבין את MediaStream API היא לבדוק אותו בפועל:

  1. בדפדפן, עוברים אל WebRTC samples getUserMedia.
  2. פותחים את המסוף.
  3. בודקים את המשתנה stream, שנמצא בהיקף הגלובלי.

לכל MediaStream יש קלט, שיכול להיות MediaStream שנוצר על ידי getUserMedia(), ופלט, שיכול להיות מועבר לרכיב סרטון או ל-RTCPeerConnection.

השיטה getUserMedia() מקבלת פרמטר אובייקט MediaStreamConstraints ומחזירה Promise שמוביל לאובייקט MediaStream.

לכל MediaStream יש label, כמו 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'. מערך של MediaStreamTracks מוחזר על ידי השיטות getAudioTracks() ו-getVideoTracks().

בדוגמה getUserMedia, הפונקציה stream.getAudioTracks() מחזירה מערך ריק (כי אין אודיו), ואם מחוברת מצלמת אינטרנט תקינה, הפונקציה stream.getVideoTracks() מחזירה מערך עם רכיב MediaStreamTrack אחד שמייצג את הזרם ממצלמת האינטרנט. לכל MediaStreamTrack יש סוג ('video' או 'audio'), label (למשל 'FaceTime HD Camera (Built-in)') והוא מייצג ערוץ אחד או יותר של אודיו או וידאו. במקרה הזה, יש רק טראק וידאו אחד ואין אודיו, אבל קל לדמיין תרחישי שימוש שבהם יש יותר, כמו אפליקציית צ'אט שמקבלת סטרימינג מהמצלמה הקדמית, מהמצלמה האחורית, מהמיקרופון ומאפליקציה שמשתפת את המסך שלה.

אפשר לצרף MediaStream לרכיב של סרטון על ידי הגדרת המאפיין srcObject. בעבר, כדי לעשות את זה היה צריך להגדיר את המאפיין src לכתובת URL של אובייקט שנוצרה באמצעות URL.createObjectURL(), אבל האפשרות הזו הוצאה משימוש.

אפשר להשתמש ב-getUserMedia גם כצומת קלט ל-Web Audio API:

// Cope with browser differences.
let audioContext;
if (typeof AudioContext === 'function') {
  audioContext = new AudioContext();
} else if (typeof webkitAudioContext === 'function') {
  audioContext = new webkitAudioContext(); // eslint-disable-line new-cap
} else {
  console.log('Sorry! Web Audio not supported.');
}

// Create a filter node.
var filterNode = audioContext.createBiquadFilter();
// See https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#BiquadFilterNode-section
filterNode.type = 'highpass';
// Cutoff frequency. For highpass, audio is attenuated below this frequency.
filterNode.frequency.value = 10000;

// Create a gain node to change audio volume.
var gainNode = audioContext.createGain();
// Default is 1 (no change). Less than 1 means audio is attenuated
// and vice versa.
gainNode.gain.value = 0.5;

navigator.mediaDevices.getUserMedia({audio: true}, (stream) => {
  // Create an AudioNode from the stream.
  const mediaStreamSource =
    audioContext.createMediaStreamSource(stream);
  mediaStreamSource.connect(filterNode);
  filterNode.connect(gainNode);
  // Connect the gain node to the destination. For example, play the sound.
  gainNode.connect(audioContext.destination);
});

אפשר גם לשלב getUserMedia באפליקציות ובתוספים שמבוססים על Chromium. הוספת audioCapture ו/או videoCapture הרשאות למניפסט מאפשרת לבקש הרשאה ולהעניק אותה רק פעם אחת במהלך ההתקנה. לאחר מכן, המשתמש לא מתבקש לתת הרשאה לגישה למצלמה או למיקרופון.

צריך לתת את ההרשאה ל-getUserMedia() רק פעם אחת. בפעם הראשונה, לחצן ההרשאה מוצג בסרגל המידע של הדפדפן. הגישה ל-HTTP עבור getUserMedia() הוצאה משימוש על ידי Chrome בסוף 2015, כי היא סווגה כתכונה מתקדמת.

המטרה היא לאפשר MediaStream לכל מקור נתונים של סטרימינג, ולא רק למצלמה או למיקרופון. האפשרות הזו תאפשר סטרימינג מנתונים מאוחסנים או ממקורות נתונים שרירותיים, כמו חיישנים או קלטים אחרים.

getUserMedia() באמת מתעורר לחיים בשילוב עם ספריות וממשקי JavaScript API אחרים:

  • Webcam Toy היא אפליקציה לצילום תמונות בתא צילום שמשתמשת ב-WebGL כדי להוסיף לתמונות אפקטים מוזרים ומדהימים שאפשר לשתף או לשמור באופן מקומי.
  • FaceKat הוא משחק שמתבסס על מעקב אחרי הבעות הפנים ונבנה באמצעות headtrackr.js.
  • ASCII Camera משתמשת ב-Canvas API כדי ליצור תמונות ASCII.
תמונה ב-ASCII שנוצרה על ידי idevelop.ro/ascii-camera
gUM ASCII art!

מגבלות

אפשר להשתמש בConstraints כדי להגדיר ערכים לרזולוציית הווידאו עבור getUserMedia(). האפשרות הזו מאפשרת גם תמיכה במגבלות אחרות, כמו יחס גובה-רוחב, מצב צילום (מצלמה קדמית או אחורית), קצב פריימים, גובה ורוחב, ושיטה של applyConstraints().

לדוגמה, אפשר לעיין בדוגמאות ל-WebRTC getUserMedia: בחירת רזולוציה.

הגדרת ערך מוגבל שאסור לשימוש תגרום להחזרת DOMException או OverconstrainedError אם, לדוגמה, הרזולוציה המבוקשת לא זמינה. כדי לראות את זה בפעולה, אפשר לעיין בדוגמאות ל-WebRTC getUserMedia: בחירת רזולוציה.

צילום מסך וכרטיסייה

אפליקציות Chrome מאפשרות גם לשתף סרטון בשידור חי של כרטיסיית דפדפן אחת או של שולחן העבודה כולו באמצעות ממשקי ה-API‏ chrome.tabCapture ו-chrome.desktopCapture. (לצפייה בהדגמה ולקבלת מידע נוסף, אפשר לעיין במאמר שיתוף מסך באמצעות WebRTC). המאמר פורסם לפני כמה שנים, אבל הוא עדיין מעניין.)

אפשר גם להשתמש בצילום מסך כמקור MediaStream ב-Chrome באמצעות האילוץ הניסיוני chromeMediaSource. שימו לב: צילום מסך מחייב HTTPS ומומלץ להשתמש בו רק לצורכי פיתוח, כי הוא מופעל באמצעות דגל בשורת הפקודה, כמו שמוסבר במאמר הזה.

איתות: שליטה בסשן, מידע על הרשת ועל המדיה

‫WebRTC משתמש ב-RTCPeerConnection כדי להעביר נתוני סטרימינג בין דפדפנים (שנקראים גם עמיתים), אבל הוא גם צריך מנגנון לתיאום התקשורת ולשליחת הודעות בקרה. התהליך הזה נקרא איתות. שיטות ופרוטוקולים של איתות לא מוגדרים על ידי WebRTC. האיתות לא נכלל ב-RTCPeerConnection API.

במקום זאת, מפתחי אפליקציות WebRTC יכולים לבחור את פרוטוקול ההודעות המועדף עליהם, כמו SIP או XMPP, וכל ערוץ תקשורת דו-כיווני מתאים. בדוגמה של appr.tc נעשה שימוש ב-XHR וב-Channel API כמנגנון האיתות. בcodelab נעשה שימוש ב-Socket.io שפועל בשרת Node.

האיתות משמש להחלפת שלושה סוגי מידע:

  • הודעות בקרה של סשן: כדי לאתחל או לסגור תקשורת ולדווח על שגיאות.
  • תצורת הרשת: מה כתובת ה-IP והיציאה של המחשב שלכם כלפי העולם החיצוני?
  • יכולות מדיה: אילו קודקים ורזולוציות הדפדפן יכול לטפל בהם, וגם הדפדפן שאיתו הוא רוצה לתקשר?

החלפת המידע באמצעות איתות חייבת להסתיים בהצלחה לפני שמתחיל סטרימינג בין עמיתים.

לדוגמה, נניח שמיכל רוצה לתקשר עם יוסי. בדוגמה הבאה לקוד מתוך מפרט W3C WebRTC אפשר לראות את תהליך האיתות בפעולה. הקוד מניח שקיים מנגנון איתות כלשהו שנוצר בשיטה createSignalingChannel(). חשוב גם לציין שב-Chrome וב-Opera, התו RTCPeerConnection מופיע כרגע עם קידומת.

// 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);
  }
};

// Once 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);
  }
};

קודם כל, מיכל ויוסי מחליפים מידע על הרשת. (המונח מציאת מועמדים מתייחס לתהליך של מציאת ממשקי רשת ויציאות באמצעות מסגרת ICE).

  1. אליס יוצרת אובייקט RTCPeerConnection עם handler של onicecandidate, שמופעל כשמועמדים לרשת הופכים לזמינים.
  2. אליס שולחת לבוב נתונים של מועמדים שעברו סריאליזציה דרך ערוץ האיתות שבו הם משתמשים, כמו WebSocket או מנגנון אחר.
  3. כשבוב מקבל הודעת מועמד מאליס, הוא מתקשר אל addIceCandidate כדי להוסיף את המועמד לתיאור העמית המרוחק.

לקוחות WebRTC (שנקראים גם עמיתים, או אליס ובוב בדוגמה הזו) צריכים גם לקבוע ולהחליף מידע על מדיה של אודיו ווידאו מקומיים ומרוחקים, כמו רזולוציה ויכולות של קודקים. העברת האותות להחלפת מידע על הגדרת המדיה מתבצעת באמצעות החלפה של הצעה ותשובה באמצעות Session Description Protocol ‏ (SDP):

  1. עינת מריצה את ה-method‏ RTCPeerConnection createOffer(). התוצאה שמתקבלת מועברת אל RTCSessionDescription – תיאור הסשן המקומי של אליס.
  2. בפונקציית הקריאה החוזרת, אליס מגדירה את התיאור המקומי באמצעות setLocalDescription() ואז שולחת את תיאור הסשן הזה לבוב דרך ערוץ האיתות שלהם. שימו לב: מערכת RTCPeerConnection לא תתחיל לאסוף מועמדים עד שתתבצע קריאה ל-setLocalDescription(). הדבר הזה מוגדר בטיוטת JSEP IETF.
  3. בוב מגדיר את התיאור שאליס שלחה לו כתיאור מרוחק באמצעות setRemoteDescription().
  4. ירון מריץ את השיטה RTCPeerConnection createAnswer() ומעביר לה את התיאור המרוחק שהוא קיבל מעינת, כדי שאפשר יהיה ליצור סשן מקומי שתואם לסשן שלה. ההתקשרות חזרה createAnswer() מקבלת את RTCSessionDescription. ירון מגדיר את התיאור הזה כתיאור מקומי ושולח אותו לעינת.
  5. כשעינת מקבלת את תיאור הסשן של ירון, היא מגדירה אותו כתיאור המרוחק באמצעות setRemoteDescription.
  6. פינג!

אובייקטים מסוג RTCSessionDescription הם בלובים שתואמים לפרוטוקול תיאור הסשן, ‏ SDP. אובייקט SDP שעבר סריאליזציה נראה כך:

v=0
o=- 3883943731 1 IN IP4 127.0.0.1
s=
t=0 0
a=group:BUNDLE audio video
m=audio 1 RTP/SAVPF 103 104 0 8 106 105 13 126

// ...

a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh810

אפשר לבצע את הרכישה וההחלפה של מידע על הרשת והמדיה בו-זמנית, אבל שני התהליכים צריכים להסתיים לפני שמתחילים להזרים אודיו ווידאו בין עמיתים.

ארכיטקטורת ההצעה/תשובה שתוארה קודם נקראת JavaScript Session Establishment Protocol, או JSEP. (יש אנימציה מצוינת שמסבירה את תהליך האיתות והסטרימינג בסרטון ההדגמה של Ericsson לגבי ההטמעה הראשונה של WebRTC).

תרשים הארכיטקטורה של JSEP
ארכיטקטורת JSEP

אחרי שתהליך האיתות מסתיים בהצלחה, אפשר להזרים נתונים ישירות בין העמיתים, בין המתקשר לבין מקבל השיחה. אם זה לא מצליח, הנתונים מוזרמים דרך שרת ממסר מתווך (מידע נוסף על כך בהמשך). הסטרימינג הוא התפקיד של RTCPeerConnection.

RTCPeerConnection

RTCPeerConnection הוא רכיב WebRTC שמטפל בתקשורת יציבה ויעילה של נתוני סטרימינג בין עמיתים.

התרשים הבא מציג את הארכיטקטורה של WebRTC ואת התפקיד של RTCPeerConnection. כמו שאפשר לראות, החלקים הירוקים מורכבים!

תרשים הארכיטקטורה של WebRTC
ארכיטקטורת WebRTC (מתוך webrtc.org)

מנקודת המבט של JavaScript, הדבר העיקרי שצריך להבין מהתרשים הזה הוא ש-RTCPeerConnection מגן על מפתחי אתרים מפני מורכבויות רבות שמתרחשות מתחת לפני השטח. הקודקים והפרוטוקולים שבהם משתמש WebRTC מבצעים כמות עצומה של עבודה כדי לאפשר תקשורת בזמן אמת, גם ברשתות לא אמינות:

  • הסתרת אובדן מנות
  • ביטול הד
  • התאמה של רוחב הפס
  • מאגר נתונים זמני דינמי של רעידות
  • השגת שליטה באופן אוטומטי
  • הפחתת רעש וביטול רעשים
  • ניקוי תמונות

בדוגמה הקודמת של W3C מוצגת דוגמה פשוטה של WebRTC מנקודת מבט של איתות. בהמשך מפורטים שני תהליכי עבודה של אפליקציות WebRTC תקינות. הראשונה היא דוגמה פשוטה להדגמת RTCPeerConnection, והשנייה היא לקוח צ'אט וידאו שפועל באופן מלא.

‫RTCPeerConnection ללא שרתים

הקוד הבא נלקח מתוך דוגמאות ל-WebRTC של חיבור עמיתים, שכולל וידאו מקומי ומרחוק RTCPeerConnection (וגם מקומי ומרחוק) בדף אינטרנט אחד. הפעולה הזו לא מועילה במיוחד – המתקשר והמקבל נמצאים באותו דף – אבל היא עוזרת להבין טוב יותר את הפעולה של RTCPeerConnection API, כי אובייקטים של RTCPeerConnection בדף יכולים להחליף נתונים והודעות ישירות בלי להשתמש במנגנוני איתות ביניים.

בדוגמה הזו, pc1 מייצג את העמית המקומי (המתקשר) ו-pc2 מייצג את העמית המרוחק (מקבל השיחה).

מתקשר

  1. יוצרים RTCPeerConnection חדש ומוסיפים את הסטרים מ-getUserMedia(): ```js // Servers is an optional configuration file. (בהמשך יש הסבר על TURN ו-STUN). pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
  1. יוצרים מבצע ומגדירים אותו כתיאור מקומי למוצר pc1 וכתיאור מרחוק למוצר pc2. אפשר לעשות את זה ישירות בקוד בלי להשתמש באיתות, כי גם המתקשר וגם מקבל השיחה נמצאים באותו הדף: js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );

Callee

  1. יוצרים pc2 וכשהשידור מ-pc1 מתווסף, מציגים אותו ברכיב וידאו: js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }

RTCPeerConnection API plus servers

בעולם האמיתי, ל-WebRTC נדרשים שרתים, פשוטים ככל שיהיו, כדי שהדברים הבאים יוכלו לקרות:

  • המשתמשים יכולים לגלות אחד את השני ולהחליף פרטים מהעולם האמיתי, כמו שמות.
  • אפליקציות לקוח (עמיתים) של WebRTC מחליפות נתוני רשת.
  • עמיתים מחליפים נתונים על מדיה, כמו פורמט ורזולוציה של סרטונים.
  • אפליקציות לקוח WebRTC עוברות דרך שערי NAT וחומות אש.

במילים אחרות, WebRTC צריך ארבעה סוגים של פונקציונליות בצד השרת:

  • גילוי משתמשים ותקשורת
  • איתות
  • מעבר דרך NAT/חומת אש
  • שרתי ממסר למקרה שהתקשורת בין עמיתים נכשלת

המאמר הזה לא עוסק ב-NAT traversal, ברשתות peer-to-peer ובדרישות לבניית אפליקציית שרת לגילוי משתמשים ולסימון. פרוטוקול STUN וההרחבה שלו, TURN, משמשים את מסגרת ICE כדי לאפשר ל-RTCPeerConnection להתמודד עם מעבר NAT ועם תנודות אחרות ברשת.

‫ICE היא מסגרת לחיבור עמיתים, כמו שני לקוחות של וידאו צ'אט. בשלב הראשון, פרוטוקול ICE מנסה לחבר בין עמיתים ישירות עם השהיה הנמוכה ביותר האפשרית באמצעות UDP. בתהליך הזה, לשרתי STUN יש משימה אחת: לאפשר למחשב עמית מאחורי NAT לגלות את הכתובת והיציאה הציבוריות שלו. (מידע נוסף על STUN ו-TURN זמין במאמר פיתוח שירותי ה-Backend שנדרשים לאפליקציית WebRTC).

חיפוש מקורות מתאימים לקישור
חיפוש מועמדים ליצירת קשר

אם ה-UDP נכשל, פרוטוקול ICE מנסה TCP. אם חיבור ישיר נכשל – במיוחד בגלל מעבר NAT וחומות אש בארגון – פרוטוקול ICE משתמש בשרת TURN מתווך (ממסר). במילים אחרות, פרוטוקול ICE משתמש קודם ב-STUN עם UDP כדי לחבר ישירות בין עמיתים, ואם זה לא מצליח, הוא עובר לשרת ממסר TURN. המונח מציאת מועמדים מתייחס לתהליך של מציאת ממשקי רשת ויציאות.

נתיבי נתונים של WebRTC
נתיבי נתונים של WebRTC

מהנדס WebRTC, ג'סטין אוברטי, מספק מידע נוסף על ICE,‏ STUN ו-TURN במצגת WebRTC של Google I/O משנת 2013. (בשקפים של המצגת יש דוגמאות להטמעות של שרתי TURN ו-STUN).

לקוח פשוט לשיחות וידאו

מקום טוב לנסות את WebRTC, כולל איתות ומעבר NAT/חומת אש באמצעות שרת STUN, הוא הדמו של צ'אט הווידאו בכתובת appr.tc. באפליקציה הזו נעשה שימוש ב-adapter.js, שהוא shim שמבודד אפליקציות משינויים במפרט ומקידומות שונות.

הקוד הוא מפורט בכוונה ביומן הרישום שלו. כדאי לבדוק במסוף את סדר האירועים. בהמשך מופיע הסבר מפורט על הקוד.

טופולוגיות של רשתות

בשלב הזה, WebRTC תומך רק בתקשורת בין שני משתמשים, אבל אפשר להשתמש בו בתרחישי רשת מורכבים יותר, למשל עם כמה עמיתים שמתקשרים אחד עם השני ישירות או דרך יחידת בקרה רב-נקודתית (MCU), שרת שיכול לטפל במספר גדול של משתתפים ולבצע העברה סלקטיבית של סטרימינג, ומיקס או הקלטה של אודיו ווידאו.

דיאגרמת טופולוגיה של יחידת בקרה לכמה נקודות
דוגמה לטופולוגיה של יחידת בקרה של Multipoint

הרבה אפליקציות WebRTC קיימות מדגימות רק תקשורת בין דפדפני אינטרנט, אבל שרתי שער יכולים לאפשר לאפליקציית WebRTC שפועלת בדפדפן ליצור אינטראקציה עם מכשירים, כמו טלפונים (שנקראים גם PSTN) ועם מערכות VOIP. במאי 2012, חברת Doubango Telecom פרסמה קוד פתוח של לקוח SIP‏ sipml5 שנבנה באמצעות WebRTC ו-WebSocket, שמאפשר (בין שימושים פוטנציאליים אחרים) שיחות וידאו בין דפדפנים ואפליקציות שפועלות ב-iOS וב-Android. ב-Google I/O, חברות Tethr ו-Tropo הציגו מסגרת לתקשורת במצבי אסון במזוודה באמצעות תא OpenBTS כדי לאפשר תקשורת בין טלפונים פשוטים ומחשבים דרך WebRTC. תקשורת טלפונית ללא ספק!

Tethr/Tropo demo at Google I/O 2012
Tethr/Tropo: Disaster communications in a briefcase

RTCDataChannel API<

בנוסף לאודיו ולסרטונים, WebRTC תומך בתקשורת בזמן אמת עבור סוגים אחרים של נתונים.

RTCDataChannel API מאפשר החלפת נתונים שרירותיים בין עמיתים עם זמן אחזור נמוך וקצב העברת נתונים גבוה. דוגמאות להדגמות של דפים יחידים ומידע על יצירת אפליקציה פשוטה להעברת קבצים זמינים בדוגמאות של WebRTC ובסדנת הקידוד של WebRTC.

יש הרבה תרחישי שימוש פוטנציאליים ל-API, כולל:

  • משחקים
  • אפליקציות של Remote Desktop
  • צ'אט בטקסט בזמן אמת
  • העברת קבצים
  • רשתות מבוזרות

ל-API יש כמה תכונות שיעזרו לכם להפיק את המרב מ-RTCPeerConnection ולאפשר תקשורת חזקה וגמישה בין עמיתים:

  • שימוש בהגדרת סשן של RTCPeerConnection
  • כמה ערוצים בו-זמנית עם תעדוף
  • סמנטיקה של מסירה אמינה ולא אמינה
  • אבטחה מובנית (DTLS) ובקרת עומס
  • אפשרות להשתמש עם או בלי אודיו או וידאו

התחביר דומה בכוונה ל-WebSocket, עם שיטת send() ואירוע message:

const localConnection = new RTCPeerConnection(servers);
const remoteConnection = new RTCPeerConnection(servers);
const sendChannel =
  localConnection.createDataChannel('sendDataChannel');

// ...

remoteConnection.ondatachannel = (event) => {
  receiveChannel = event.channel;
  receiveChannel.onmessage = onReceiveMessage;
  receiveChannel.onopen = onReceiveChannelStateChange;
  receiveChannel.onclose = onReceiveChannelStateChange;
};

function onReceiveMessage(event) {
  document.querySelector("textarea#send").value = event.data;
}

document.querySelector("button#send").onclick = () => {
  var data = document.querySelector("textarea#send").value;
  sendChannel.send(data);
};

התקשורת מתבצעת ישירות בין הדפדפנים, ולכן RTCDataChannel יכול להיות מהיר יותר מ-WebSocket, גם אם נדרש שרת ממסר (TURN) כשניסיון לחדור לחומות אש ול-NAT נכשל.

RTCDataChannel זמין בדפדפנים Chrome,‏ Safari,‏ Firefox,‏ Opera ו-Samsung Internet. המשחק Cube Slam משתמש ב-API כדי להעביר את מצב המשחק. משחקים עם חבר או עם הדוב! פלטפורמת Sharefest החדשנית אפשרה שיתוף קבצים באמצעות RTCDataChannel, ו-peerCDN הציעה הצצה לאופן שבו WebRTC יכולה לאפשר הפצה של תוכן בין עמיתים.

מידע נוסף על RTCDataChannel זמין בטיוטת מפרט הפרוטוקול של IETF.

אבטחה

יש כמה דרכים שבהן אפליקציה או פלאגין לתקשורת בזמן אמת עלולים לפגוע באבטחה. לדוגמה:

  • יכול להיות שיהיה ניסיון לחבל במדיה או בנתונים לא מוצפנים בין דפדפנים, או בין דפדפן לשרת.
  • יכול להיות שאפליקציה תתעד ותפיץ סרטון או אודיו בלי שהמשתמש יידע על כך.
  • יכול להיות שתוכנות זדוניות או וירוסים מותקנים יחד עם תוסף או אפליקציה שנראים תמימים.

ל-WebRTC יש כמה תכונות שנועדו למנוע את הבעיות האלה:

  • הטמעות של WebRTC משתמשות בפרוטוקולים מאובטחים, כמו DTLS ו-SRTP.
  • הצפנה היא חובה לכל רכיבי WebRTC, כולל מנגנוני איתות.
  • ‫WebRTC הוא לא פלאגין. הרכיבים שלו פועלים בארגז החול של הדפדפן ולא בתהליך נפרד. אין צורך להתקין את הרכיבים בנפרד, והם מתעדכנים בכל פעם שהדפדפן מתעדכן.
  • הגישה למצלמה ולמיקרופון חייבת להינתן באופן מפורש, וכשהמצלמה או המיקרופון פועלים, זה מוצג בבירור בממשק המשתמש.

המאמר הזה לא כולל דיון מלא בנושא האבטחה של סטרימינג של מדיה. מידע נוסף זמין במאמר Proposed WebRTC Security Architecture (ארכיטקטורת אבטחה מוצעת של WebRTC) שהוצע על ידי IETF.

לסיכום

ממשקי ה-API והתקנים של WebRTC יכולים להפוך את הכלים ליצירת תוכן ולתקשורת לנגישים יותר ולמבוזרים יותר, כולל טלפוניה, משחקים, הפקת סרטונים, יצירת מוזיקה ואיסוף חדשות.

אין הרבה טכנולוגיות משבשות יותר מזו.

כפי שכתב בלוגר בשם פיל אדהולם במאמר, "יכול להיות ש-WebRTC ו-HTML5 יאפשרו את אותה טרנספורמציה לתקשורת בזמן אמת, כמו שהדפדפן המקורי עשה למידע".

כלים למפתחים

מידע נוסף

תקנים ופרוטוקולים

סיכום התמיכה ב-WebRTC

MediaStream ו-getUserMedia APIs

  • ‫Chrome למחשב מגרסה 18.0.1008 ואילך; Chrome ל-Android מגרסה 29 ואילך
  • ‫Opera מגרסה 18 ואילך; Opera ל-Android מגרסה 20 ואילך
  • ‫Opera 12, ‏ Opera Mobile 12 (על בסיס מנוע Presto)
  • ‫Firefox מגרסה 17 ומעלה
  • ‫Microsoft Edge מגרסה 16 ואילך
  • ‫Safari מגרסה 11.2 ואילך ב-iOS, ומגרסה 11.1 ואילך ב-MacOS
  • ‫UC מגרסה 11.8 ואילך ב-Android
  • ‫Samsung Internet 4 ואילך

RTCPeerConnection API

  • ‫Chrome למחשב מגרסה 20 ואילך; Chrome ל-Android מגרסה 29 ואילך (ללא דגל)
  • ‫Opera מגרסה 18 ואילך (מופעל כברירת מחדל); Opera ל-Android מגרסה 20 ואילך (מופעל כברירת מחדל)
  • ‫Firefox מגרסה 22 ומעלה (מופעל כברירת מחדל)
  • ‫Microsoft Edge מגרסה 16 ואילך
  • ‫Safari מגרסה 11.2 ואילך ב-iOS, ומגרסה 11.1 ואילך ב-MacOS
  • ‫Samsung Internet 4 ואילך

RTCDataChannel API

  • גרסה ניסיונית ב-Chrome 25, אבל יציבה יותר (עם יכולת פעולה הדדית עם Firefox) ב-Chrome 26 ומעלה; Chrome ל-Android 29 ומעלה
  • גרסה יציבה (עם יכולת פעולה הדדית עם Firefox) ב-Opera 18 ואילך; Opera ל-Android מגרסה 20 ואילך
  • ‫Firefox מגרסה 22 ומעלה (מופעל כברירת מחדל)

מידע מפורט יותר על תמיכה חוצת-פלטפורמות בממשקי API, כמו getUserMedia ו-RTCPeerConnection, זמין באתר caniuse.com ובדף סטטוס הפלטפורמה של Chrome.

ממשקי API מקוריים ל-RTCPeerConnection זמינים גם בתיעוד באתר webrtc.org.