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

WebRTC הוא חזית חדשה במלחמה הארוכה על רשת פתוחה ולא מבוקרת.

ברנדן אייש, ממציא ה-JavaScript

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

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

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

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

התחלה מהירה

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

לחלופין, אפשר להיכנס ישירות ל-WebRTC codelab, מדריך מפורט שמסביר איך לבנות אפליקציית וידאו צ'אט מלאה, כולל שרת איתות פשוט.

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

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

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

וידאו צ'אט ב-Gmail הפך לפופולרי בשנת 2008, ובשנת 2011 השיקה Google את Hangouts, שבו נעשה שימוש ב-Google Talk (כמו גם Gmail). Google רכשה את GIPS, חברה שפיתחה רכיבים רבים שנדרשים ל-RTC, כמו קודק ושיטות לביטול הד. Google השתמשה בקוד פתוח בטכנולוגיות שפותחו על ידי GIPS ועבדה עם גופי תקנים רלוונטיים ב-Internet Engineering Task Force (IETF) וב-World Wide Web Consortium (W3C) כדי להבטיח הסכמה רחבה בענף. במאי 2011, אריקסון יצר את היישום הראשון של 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, ספריית JavaScript שמנוהלת על ידי Google בעזרת קהילת WebRTC, כדי לצמצם את ההבדלים בדפדפנים ואת השינויים במפרטים.

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

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

ה-WebRTC הראשון שלך

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

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

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

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

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

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

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

סביר להניח שהדרך הקלה ביותר להבין את MediaStream API היא לבחון אותו באופן כללי:

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

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

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

לכל MediaStream יש label, למשל 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'. מערך של MediaStreamTrack מוחזר על ידי השיטות 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);
});

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

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

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

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

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

מגבלות

ניתן להשתמש באילוצים כדי להגדיר ערכים לרזולוציית וידאו עבור 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, וכל ערוץ תקשורת דו-כיווני מתאים (דו-כיווני). בדוגמה של appr.tc נעשה שימוש ב-XHR וב-Channel API בתור מנגנון האות. ב-codelab נעשה שימוש ב-Socket.io שפועל על שרת צמתים.

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

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

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

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

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

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

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

RTCPeerConnection

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

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

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

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

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

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

RTCPeerConnection ללא שרתים

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

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

מתקשר

  1. יוצרים RTCPeerConnection חדש ומוסיפים את מקור הנתונים מ-getUserMedia(): ```js // 'שרתים' הוא קובץ תצורה אופציונלי. (ראו בהמשך את הדיון בנושא TURN ו-STUN). pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().for גישה((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; }

API של RTCPeerConnection עם שרתים

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

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

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

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

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

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

מתבצע חיפוש של הצעות לחיבור
חיפוש הצעות לחיבור

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

מסלולי נתונים של WebRTC
מסלולי נתונים של WebRTC

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

לקוח פשוט לווידאו צ'אט

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

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

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

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

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

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

הדגמה של Tethr/Tropo ב-Google I/O 2012
Tethr/Tropo: הודעות על אסונות בתיק מסמכים

API של RTCDataChannel<

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

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

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

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

ה-API כולל כמה תכונות שמאפשרות להפיק את המקסימום מ-RTCPeerConnection ולאפשר תקשורת אפקטיבית וגמישה מקצה לקצה (P2P):

  • שימוש בהגדרת הסשן של 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, גם אם צריך שרת ממסר כדי להתמודד עם חומות אש ואסימוני NAT.

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

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

אבטחה

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

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

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

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

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

לסיכום

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

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

כפי שכתוב על ידי הבלוגר פיל אדהולם , "יכול להיות ש-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 ואילך

ממשק API של RTCPeerConnection

  • 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 ואילך

ממשק API של RTCDataChannel

  • גרסה ניסיונית ב-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.