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

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

איתות

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

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

// Set up an asynchronous communication channel that will be
// used during the peer connection setup
const signalingChannel = new SignalingChannel(remoteClientId);
signalingChannel.addEventListener('message', message => {
    // New message from remote client received
});

// Send an asynchronous message to the remote client
signalingChannel.send('Hello!');

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

יצירת קשרים עם אפליקציות להשוואה

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

אחרי יצירת RTCPeerConnection, עלינו ליצור מבצע SDP או נשאלת השאלה הבאה: לאחר ה-SDP נוצרת הצעה או תשובה, ויש לשלוח אותה לעמית המרוחק באמצעות ערוץ שונה. העברת אובייקטים של SDP לעמיתים מרחוק נקראת איתות לא מכוסה במפרט WebRTC.

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

async function makeCall() {
    const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]}
    const peerConnection = new RTCPeerConnection(configuration);
    signalingChannel.addEventListener('message', async message => {
        if (message.answer) {
            const remoteDesc = new RTCSessionDescription(message.answer);
            await peerConnection.setRemoteDescription(remoteDesc);
        }
    });
    const offer = await peerConnection.createOffer();
    await peerConnection.setLocalDescription(offer);
    signalingChannel.send({'offer': offer});
}

בצד המקבל, אנחנו מחכים להצעה נכנסת לפני שאנחנו יוצרים את מופע אחד (RTCPeerConnection). אחרי זה, אנחנו מגדירים את המבצע שהתקבל באמצעות setRemoteDescription() בשלב הבא נתקשר למספר createAnswer() כדי לתת תשובה למבצע שהתקבל. תשובה זו מוגדרת כתיאור מקומי באמצעות setLocalDescription() ואז נשלח לצד המתקשרים באמצעות האיתות שלנו השרת.

const peerConnection = new RTCPeerConnection(configuration);
signalingChannel.addEventListener('message', async message => {
    if (message.offer) {
        peerConnection.setRemoteDescription(new RTCSessionDescription(message.offer));
        const answer = await peerConnection.createAnswer();
        await peerConnection.setLocalDescription(answer);
        signalingChannel.send({'answer': answer});
    }
});

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

מועמדים ל-ICE

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

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

טריקים ICE

אחרי יצירת אובייקט RTCPeerConnection, ה-framework הבסיסי משתמש ב- סופקו שרתי ICE כדי לאסוף מועמדים לתשתית הקישוריות (ICE) מועמדים בבחירות). האירוע icegatheringstatechange ב-RTCPeerConnection אותות באיזה מצב נמצא איסוף ה-ICE (new, gathering או complete).

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

כדי לאסוף מועמדי ICE, אפשר פשוט להוסיף מאזינים לאירוע icecandidate. ה-RTCPeerConnectionIceEvent שהופץ עבור המאזינים הזה יכיל המאפיין candidate שמייצג מועמד חדש שיש לשלוח אל אפליקציה להשוואה מרחוק (יש לעיין באיתות).

// Listen for local ICE candidates on the local RTCPeerConnection
peerConnection.addEventListener('icecandidate', event => {
    if (event.candidate) {
        signalingChannel.send({'new-ice-candidate': event.candidate});
    }
});

// Listen for remote ICE candidates and add them to the local RTCPeerConnection
signalingChannel.addEventListener('message', async message => {
    if (message.iceCandidate) {
        try {
            await peerConnection.addIceCandidate(message.iceCandidate);
        } catch (e) {
            console.error('Error adding received ice candidate', e);
        }
    }
});

החיבור נוצר

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

// Listen for connectionstatechange on the local RTCPeerConnection
peerConnection.addEventListener('connectionstatechange', event => {
    if (peerConnection.connectionState === 'connected') {
        // Peers connected!
    }
});

ממשק API של RTCPeerConnection תיעוד