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

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

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

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

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

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

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

התחלה מהירה

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

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

לחלופין, אפשר לעבור ישירות אל codelab של 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 או לנסות את הדוגמאות המדהימות של Chris Wilson, שבהן getUserMedia משמש כקלט של אודיו באינטרנט.

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

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

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

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

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

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

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

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

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

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

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

הדרך הקלה ביותר להבין את ה-API של MediaStream היא להשתמש בו:

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

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

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

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

בדוגמה 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);
});

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

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

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

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

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

אילוצים

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

דוגמה לכך מופיעה בקטע דוגמאות WebRTC getUserMedia: בחירת רזולוציה.

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

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

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

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

איתות: בקרת סשנים, מידע על הרשת ועל המדיה

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

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

האותות משמשים להעברת שלושה סוגים של מידע:

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

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

לדוגמה, נניח שאלי רוצה לתקשר עם בועז. לפניכם דוגמה לקוד ממפרט 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 עם טיפול onicecandidate, שפועל כשמתקבלות רשימות של רשתות זמינות.
  2. עינת שולחת לבועז נתוני מועמדים בסדרה דרך ערוץ האותות שבו הם משתמשים, כמו WebSocket או מנגנון אחר.
  3. כשבועז מקבל הודעת מועמדות מאילנה, הוא קורא לפונקציה addIceCandidate כדי להוסיף את המועמד לתיאור של השותף המרוחק.

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

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

אובייקטים מסוג RTCSessionDescription הם blobs שתואמים ל-Session Description Protocol‏ (פרוטוקול תיאור הסשן), 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 (פרוטוקול ליצירת סשן ב-JavaScript), או JSEP. (יש אנימציה מצוינת שמסבירה את תהליך האותת והסטרימינג בסרטון הדגמה של Ericsson להטמעת WebRTC הראשונה שלה).

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

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

RTCPeerConnection

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

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

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

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

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

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

RTCPeerConnection ללא שרתים

הקוד הבא לקוח מ-WebRTC samples Peer connection, שיש בו RTCPeerConnection מקומי ו מרוחק (וגם וידאו מקומי ומרחוק) בדף אינטרנט אחד. זה לא משהו שימושי במיוחד – מבצע הקריאה והגורם שאליו היא נשלחת נמצאים באותו דף – אבל זה עוזר להבין קצת יותר טוב איך פועל ממשק ה-API של RTCPeerConnection, כי אובייקטי 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 );

מקבל הקריאה החוזרת

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

RTCPeerConnection API ושרתי API

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

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

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

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

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

ICE הוא מסגרת לחיבור בין עמיתים, כמו שני לקוחות של שיחות וידאו. בשלב הראשון, ה-ICE מנסה לחבר בין עמיתים ישירות עם זמן אחזור נמוך ככל האפשר באמצעות UDP. בתהליך הזה, שרתי STUN צריכים לבצע משימה אחת בלבד: לאפשר למארח שמאחורי NAT למצוא את הכתובת והיציאה הציבוריים שלו. (מידע נוסף על STUN ו-TURN זמין במאמר פיתוח שירותי הקצה העורפי הנדרשים לאפליקציית 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, תוסף שמבודד אפליקציות משינויים במפרט ומהבדלים בקידומות.

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

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

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

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

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

הדגמה של Tethr/Tropo ב-Google I/O 2012
Tethr/Tropo: תקשורת במקרי אסון בתיק

RTCDataChannel API<

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

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

יש הרבה תרחישים לדוגמה שבהם אפשר להשתמש ב-API, כולל:

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

לממשק ה-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) כשהחורים נקדחים כדי להתמודד עם חומות אש ו-NATs.

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

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

אבטחה

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

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

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

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

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

לסיכום

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

קשה למצוא טכנולוגיה מרחיקה לכת יותר מזו.

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

כלים למפתחים

מידע נוסף

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

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

ממשקי ה-API של MediaStream ו-getUserMedia

  • 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.