WebRTC - RTCPeerConnection APIs
RTCPeerConnection API เป็นแกนหลักของการเชื่อมต่อแบบเพียร์ทูเพียร์ระหว่างแต่ละเบราว์เซอร์ ในการสร้างวัตถุ RTCPeerConnection เพียงแค่เขียน
var pc = RTCPeerConnection(config);
โดยที่อาร์กิวเมนต์configมีอย่างน้อยในคีย์ iceServers เป็นอาร์เรย์ของอ็อบเจ็กต์ URL ที่มีข้อมูลเกี่ยวกับเซิร์ฟเวอร์ STUN และ TURN ซึ่งใช้ระหว่างการค้นหาผู้สมัคร ICE คุณสามารถดูรายการเซิร์ฟเวอร์ STUN สาธารณะที่ใช้ได้ที่code.google.com
ขึ้นอยู่กับว่าคุณเป็นผู้โทรหรือผู้โทรวัตถุ RTCPeerConnection ถูกใช้ในลักษณะที่แตกต่างกันเล็กน้อยในแต่ละด้านของการเชื่อมต่อ
นี่คือตัวอย่างของขั้นตอนของผู้ใช้ -
ลงทะเบียนตัวจัดการผู้สมัครรายเดียว จะส่งผู้สมัคร ICE ไปยังเพื่อนคนอื่น ๆ ตามที่ได้รับ
ลงทะเบียนตัวจัดการonaddstream จัดการการแสดงสตรีมวิดีโอเมื่อได้รับจากเครื่องระยะไกล
ลงทะเบียนตัวจัดการข้อความ เซิร์ฟเวอร์การส่งสัญญาณของคุณควรมีตัวจัดการสำหรับข้อความที่ได้รับจากเพียร์อื่น ถ้าข้อความมีRTCSessionDescriptionวัตถุก็ควรจะเพิ่มให้กับRTCPeerConnectionวัตถุโดยใช้setRemoteDescription ()วิธีการ ถ้าข้อความมีRTCIceCandidateวัตถุก็ควรจะเพิ่มให้กับRTCPeerConnectionวัตถุโดยใช้addIceCandidate ()วิธีการ
ใช้ประโยชน์getUserMedia ()การตั้งค่าการสตรีมสื่อท้องถิ่นของคุณและเพิ่มไปยังRTCPeerConnectionวัตถุโดยใช้addStream ()วิธีการ
เริ่มกระบวนการเจรจาข้อเสนอ / คำตอบ นี่เป็นขั้นตอนเดียวที่การไหลของผู้โทรแตกต่างจากขั้นตอนของผู้โทร ผู้เรียกเริ่มการเจรจาโดยใช้เมธอด createOffer ()และลงทะเบียนการเรียกกลับที่รับอ็อบเจ็กต์RTCSessionDescription จากนั้นโทรกลับนี้ควรเพิ่มนี้RTCSessionDescriptionวัตถุที่คุณRTCPeerConnectionใช้วัตถุsetLocalDescription () และสุดท้ายผู้โทรควรส่งRTCSessionDescriptionนี้ไปยังเครื่องระยะไกลโดยใช้เซิร์ฟเวอร์การส่งสัญญาณ ผู้ถูกเรียกในที่อื่น ๆ , ลงทะเบียนโทรกลับเหมือนกัน แต่ในcreateAnswer ()วิธีการ สังเกตว่าขั้นตอนการโทรจะเริ่มต้นหลังจากได้รับข้อเสนอจากผู้โทรแล้วเท่านั้น
RTCPeerConnection API
คุณสมบัติ
RTCPeerConnection.iceConnectionState (read only)- ส่งคืน enum RTCIceConnectionState ที่อธิบายสถานะของการเชื่อมต่อ เหตุการณ์ iceconnectionstatechange จะเริ่มทำงานเมื่อค่านี้เปลี่ยนแปลง ค่าที่เป็นไปได้ -
new - ตัวแทน ICE กำลังรอผู้สมัครจากระยะไกลหรือรวบรวมที่อยู่
checking - ตัวแทน ICE มีผู้สมัครจากระยะไกล แต่ยังไม่พบการเชื่อมต่อ
connected - ตัวแทน ICE พบการเชื่อมต่อที่ใช้งานได้ แต่ยังคงตรวจสอบผู้สมัครระยะไกลเพิ่มเติมเพื่อการเชื่อมต่อที่ดีขึ้น
completed - ตัวแทน ICE พบการเชื่อมต่อที่ใช้งานได้และหยุดการทดสอบผู้สมัครระยะไกล
failed - ตัวแทน ICE ได้ตรวจสอบผู้สมัครระยะไกลทั้งหมด แต่ไม่พบรายการที่ตรงกันอย่างน้อยหนึ่งองค์ประกอบ
disconnected - ส่วนประกอบอย่างน้อยหนึ่งส่วนไม่มีชีวิตอีกต่อไป
closed - ตัวแทน ICE ปิด
RTCPeerConnection.iceGatheringState (read only) - ส่งคืน enum RTCIceGatheringState ที่อธิบายสถานะการรวบรวม ICE สำหรับการเชื่อมต่อ -
new - เพิ่งสร้างวัตถุ
gathering - ตัวแทน ICE อยู่ระหว่างการรวบรวมผู้สมัคร
complete ตัวแทน ICE รวบรวมเสร็จแล้ว
RTCPeerConnection.localDescription (read only)- ส่งกลับ RTCSessionDescription ที่อธิบายเซสชันท้องถิ่น อาจเป็นโมฆะได้หากยังไม่ได้ตั้งค่า
RTCPeerConnection.peerIdentity (read only)- ส่งคืน RTCIdentityAssertion ประกอบด้วย idp (ชื่อโดเมน) และชื่อที่แสดงถึงเอกลักษณ์ของรีโมตเพียร์
RTCPeerConnection.remoteDescription (read only)- ส่งคืน RTCSessionDescription ที่อธิบายเซสชันระยะไกล อาจเป็นโมฆะได้หากยังไม่ได้ตั้งค่า
RTCPeerConnection.signalingState (read only)- ส่งคืน enum RTCSignalingState ที่อธิบายสถานะการส่งสัญญาณของการเชื่อมต่อภายในเครื่อง สถานะนี้อธิบายถึงข้อเสนอ SDP เหตุการณ์ signalingstatechange จะเริ่มทำงานเมื่อค่านี้เปลี่ยนแปลง ค่าที่เป็นไปได้ -
stable- สถานะเริ่มต้น ไม่มีข้อเสนอ SDP / การแลกเปลี่ยนคำตอบอยู่ระหว่างดำเนินการ
have-local-offer - ด้านการเชื่อมต่อในพื้นที่ได้ใช้ข้อเสนอ SDP ในพื้นที่
have-remote-offer - ด้านระยะไกลของการเชื่อมต่อได้ใช้ข้อเสนอ SDP ในพื้นที่
have-local-pranswer - มีการใช้ข้อเสนอ SDP ระยะไกลและมีการใช้ตัวเลือก SDP ในพื้นที่
have-remote-pranswer - มีการใช้ SDP ในเครื่องและใช้ตัวส่งสัญญาณ SDP จากระยะไกล
closed - การเชื่อมต่อถูกปิด
ตัวจัดการเหตุการณ์
ส. | ตัวจัดการเหตุการณ์และคำอธิบาย |
---|---|
1 | RTCPeerConnection.onaddstream ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ addstream เริ่มทำงาน เหตุการณ์นี้จะถูกส่งเมื่อ MediaStream ถูกเพิ่มในการเชื่อมต่อนี้โดยเพียร์ระยะไกล |
2 | RTCPeerConnection.ondatachannel ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ช่องข้อมูลเริ่มทำงาน เหตุการณ์นี้ถูกส่งเมื่อมีการเพิ่ม RTCDataChannel ในการเชื่อมต่อนี้ |
3 | RTCPeerConnection.onicecandidate ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ icecandidate เริ่มทำงาน เหตุการณ์นี้ถูกส่งเมื่อมีการเพิ่มวัตถุ RTCIceCandidate ลงในสคริปต์ |
4 | RTCPeerConnection.oniceconnectionstatechange ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ iceconnectionstatechange เริ่มทำงาน เหตุการณ์นี้ถูกส่งเมื่อค่าของ iceConnectionState เปลี่ยนแปลง |
5 | RTCPeerConnection.onidentityresult ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ identityresult เริ่มทำงาน เหตุการณ์นี้จะถูกส่งเมื่อการยืนยันตัวตนถูกสร้างขึ้นในระหว่างการสร้างข้อเสนอหรือคำตอบของทาง getIdentityAssertion () |
6 | RTCPeerConnection.onidpassertionerror ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ idpassertionerror เริ่มทำงาน เหตุการณ์นี้จะถูกส่งเมื่อ IdP (Identitry Provider) พบข้อผิดพลาดขณะสร้างการยืนยันตัวตน |
7 | RTCPeerConnection.onidpvalidation ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ idpvalidationerror เริ่มทำงาน เหตุการณ์นี้จะถูกส่งเมื่อ IdP (Identitry Provider) พบข้อผิดพลาดขณะตรวจสอบความถูกต้องของการยืนยันตัวตน |
8 | RTCPeerConnection.onnegotiationneeded ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ที่จำเป็นจะเริ่มขึ้น กิจกรรมนี้ถูกส่งโดยเบราว์เซอร์เพื่อแจ้งการเจรจาจะต้องดำเนินการในอนาคต |
9 | RTCPeerConnection.onpeeridentity ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ความเป็นเพื่อนถูกไล่ออก ระบบจะส่งเหตุการณ์นี้เมื่อมีการตั้งค่าและยืนยันข้อมูลประจำตัวแบบเพียร์ในการเชื่อมต่อนี้ |
10 | RTCPeerConnection.onremovestream ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ signalingstatechange เริ่มทำงาน เหตุการณ์นี้ถูกส่งเมื่อค่าของ signalingState เปลี่ยนแปลง |
11 | RTCPeerConnection.onsignalingstatechange ตัวจัดการนี้ถูกเรียกเมื่อเหตุการณ์ลบสตรีมเริ่มทำงาน เหตุการณ์นี้จะถูกส่งเมื่อ MediaStream ถูกลบออกจากการเชื่อมต่อนี้ |
วิธีการ
ส. | วิธีการและคำอธิบาย |
---|---|
1 | RTCPeerConnection() ส่งคืนอ็อบเจ็กต์ RTCPeerConnection ใหม่ |
2 | RTCPeerConnection.createOffer() สร้างข้อเสนอ (คำขอ) เพื่อค้นหาเพื่อนระยะไกล สองพารามิเตอร์แรกของวิธีนี้คือความสำเร็จและการเรียกกลับข้อผิดพลาด พารามิเตอร์ตัวเลือกที่สามคือตัวเลือกเช่นการเปิดใช้สตรีมเสียงหรือวิดีโอ |
3 | RTCPeerConnection.createAnswer() สร้างคำตอบสำหรับข้อเสนอที่ได้รับจากเพื่อนระยะไกลในระหว่างขั้นตอนการเจรจาข้อเสนอ / คำตอบ สองพารามิเตอร์แรกของวิธีนี้คือความสำเร็จและการเรียกกลับข้อผิดพลาด พารามิเตอร์ที่สามซึ่งเป็นทางเลือกคือตัวเลือกสำหรับคำตอบที่จะสร้างขึ้น |
4 | RTCPeerConnection.setLocalDescription() เปลี่ยนคำอธิบายการเชื่อมต่อภายใน คำอธิบายกำหนดคุณสมบัติของการเชื่อมต่อ การเชื่อมต่อต้องสามารถรองรับทั้งคำอธิบายเก่าและใหม่ เมธอดใช้พารามิเตอร์สามตัวคืออ็อบเจ็กต์ RTCSessionDescription โทรกลับหากการเปลี่ยนแปลงคำอธิบายสำเร็จให้โทรกลับหากการเปลี่ยนแปลงคำอธิบายล้มเหลว |
5 | RTCPeerConnection.setRemoteDescription() เปลี่ยนคำอธิบายการเชื่อมต่อระยะไกล คำอธิบายกำหนดคุณสมบัติของการเชื่อมต่อ การเชื่อมต่อต้องสามารถรองรับทั้งคำอธิบายเก่าและใหม่ เมธอดใช้พารามิเตอร์สามตัวคืออ็อบเจ็กต์ RTCSessionDescription โทรกลับหากการเปลี่ยนแปลงคำอธิบายสำเร็จโทรกลับหากการเปลี่ยนแปลงคำอธิบายล้มเหลว |
6 | RTCPeerConnection.updateIce() อัปเดตกระบวนการตัวแทน ICE ในการส่ง Ping ผู้สมัครจากระยะไกลและรวบรวมผู้สมัครในพื้นที่ |
7 | RTCPeerConnection.addIceCandidate() จัดเตรียมผู้สมัครระยะไกลให้กับตัวแทน ICE |
8 | RTCPeerConnection.getConfiguration() ส่งคืนวัตถุ RTCConfiguration แสดงถึงการกำหนดค่าของวัตถุ RTCPeerConnection |
9 | RTCPeerConnection.getLocalStreams() ส่งคืนอาร์เรย์ของการเชื่อมต่อ MediaStream ภายในเครื่อง |
10 | RTCPeerConnection.getRemoteStreams() ส่งคืนอาร์เรย์ของการเชื่อมต่อ MediaStream ระยะไกล |
11 | RTCPeerConnection.getStreamById() ส่งคืน MediaStream ในเครื่องหรือระยะไกลตาม ID ที่กำหนด |
12 | RTCPeerConnection.addStream() เพิ่ม MediaStream เป็นแหล่งวิดีโอหรือเสียงในเครื่อง |
13 | RTCPeerConnection.removeStream() ลบ MediaStream เป็นแหล่งวิดีโอหรือเสียงในเครื่อง |
14 | RTCPeerConnection.close() ปิดการเชื่อมต่อ |
15 | RTCPeerConnection.createDataChannel() สร้าง RTCDataChannel ใหม่ |
16 | RTCPeerConnection.createDTMFSender() สร้าง RTCDTMFSender ใหม่ที่เชื่อมโยงกับ MediaStreamTrack เฉพาะ อนุญาตให้ส่งสัญญาณโทรศัพท์ DTMF (Dual-tone multifrequency) ผ่านการเชื่อมต่อ |
17 | RTCPeerConnection.getStats() สร้าง RTCStatsReport ใหม่ที่มีสถิติเกี่ยวกับการเชื่อมต่อ |
18 | RTCPeerConnection.setIdentityProvider() ตั้งค่า IdP ใช้พารามิเตอร์สามตัว ได้แก่ ชื่อโปรโตคอลที่ใช้ในการสื่อสารและชื่อผู้ใช้ที่เป็นทางเลือก |
19 | RTCPeerConnection.getIdentityAssertion() รวบรวมการยืนยันตัวตน ไม่คาดว่าจะจัดการกับวิธีนี้ในแอปพลิเคชัน ดังนั้นคุณอาจเรียกมันอย่างชัดเจนเพื่อคาดการณ์ความจำเป็นเท่านั้น |
การสร้างการเชื่อมต่อ
ตอนนี้ขอสร้างแอปพลิเคชันตัวอย่าง ประการแรกเรียกใช้เซิร์ฟเวอร์การส่งสัญญาณที่เราสร้างขึ้นในบทแนะนำ "เซิร์ฟเวอร์การส่งสัญญาณ" ผ่าน "เซิร์ฟเวอร์โหนด"
จะมีการป้อนข้อความสองรายการในหน้าหนึ่งสำหรับการเข้าสู่ระบบและอีกหนึ่งรายการสำหรับชื่อผู้ใช้ที่เราต้องการเชื่อมต่อ สร้างไฟล์index.htmlและเพิ่มรหัสต่อไปนี้ -
<html lang = "en">
<head>
<meta charset = "utf-8" />
</head>
<body>
<div>
<input type = "text" id = "loginInput" />
<button id = "loginBtn">Login</button>
</div>
<div>
<input type = "text" id = "otherUsernameInput" />
<button id = "connectToOtherUsernameBtn">Establish connection</button>
</div>
<script src = "client2.js"></script>
</body>
</html>
คุณจะเห็นว่าเราได้เพิ่มการป้อนข้อความสำหรับการเข้าสู่ระบบปุ่มเข้าสู่ระบบการป้อนข้อความสำหรับชื่อผู้ใช้เพียร์อื่น ๆ และปุ่มเชื่อมต่อกับเขา ตอนนี้สร้างไฟล์client.jsและเพิ่มรหัสต่อไปนี้ -
var connection = new WebSocket('ws://localhost:9090');
var name = "";
var loginInput = document.querySelector('#loginInput');
var loginBtn = document.querySelector('#loginBtn');
var otherUsernameInput = document.querySelector('#otherUsernameInput');
var connectToOtherUsernameBtn = document.querySelector('#connectToOtherUsernameBtn');
var connectedUser, myConnection;
//when a user clicks the login button
loginBtn.addEventListener("click", function(event){
name = loginInput.value;
if(name.length > 0){
send({
type: "login",
name: name
});
}
});
//handle messages from the server
connection.onmessage = function (message) {
console.log("Got message", message.data);
var data = JSON.parse(message.data);
switch(data.type) {
case "login":
onLogin(data.success);
break;
case "offer":
onOffer(data.offer, data.name);
break;
case "answer":
onAnswer(data.answer);
break;
case "candidate":
onCandidate(data.candidate);
break;
default:
break;
}
};
//when a user logs in
function onLogin(success) {
if (success === false) {
alert("oops...try a different username");
} else {
//creating our RTCPeerConnection object
var configuration = {
"iceServers": [{ "url": "stun:stun.1.google.com:19302" }]
};
myConnection = new webkitRTCPeerConnection(configuration);
console.log("RTCPeerConnection object was created");
console.log(myConnection);
//setup ice handling
//when the browser finds an ice candidate we send it to another peer
myConnection.onicecandidate = function (event) {
if (event.candidate) {
send({
type: "candidate",
candidate: event.candidate
});
}
};
}
};
connection.onopen = function () {
console.log("Connected");
};
connection.onerror = function (err) {
console.log("Got error", err);
};
// Alias for sending messages in JSON format
function send(message) {
if (connectedUser) {
message.name = connectedUser;
}
connection.send(JSON.stringify(message));
};
คุณจะเห็นว่าเราสร้างการเชื่อมต่อซ็อกเก็ตกับเซิร์ฟเวอร์การส่งสัญญาณของเรา เมื่อผู้ใช้คลิกที่ปุ่มเข้าสู่ระบบแอปพลิเคชันจะส่งชื่อผู้ใช้ไปยังเซิร์ฟเวอร์ หากการเข้าสู่ระบบสำเร็จแอปพลิเคชันจะสร้างอ็อบเจ็กต์ RTCPeerConnection และตั้งค่าตัวจัดการ onicecandidate ซึ่งจะส่ง icecandidates ที่พบทั้งหมดไปยังเพียร์อื่น ตอนนี้เปิดหน้าและพยายามเข้าสู่ระบบ คุณควรเห็นเอาต์พุตคอนโซลต่อไปนี้ -
ขั้นตอนต่อไปคือการสร้างข้อเสนอให้กับเพื่อนคนอื่น ๆ เพิ่มรหัสต่อไปนี้ในไฟล์client.jsของคุณ-
//setup a peer connection with another user
connectToOtherUsernameBtn.addEventListener("click", function () {
var otherUsername = otherUsernameInput.value;
connectedUser = otherUsername;
if (otherUsername.length > 0) {
//make an offer
myConnection.createOffer(function (offer) {
console.log();
send({
type: "offer",
offer: offer
});
myConnection.setLocalDescription(offer);
}, function (error) {
alert("An error has occurred.");
});
}
});
//when somebody wants to call us
function onOffer(offer, name) {
connectedUser = name;
myConnection.setRemoteDescription(new RTCSessionDescription(offer));
myConnection.createAnswer(function (answer) {
myConnection.setLocalDescription(answer);
send({
type: "answer",
answer: answer
});
}, function (error) {
alert("oops...error");
});
}
//when another user answers to our offer
function onAnswer(answer) {
myConnection.setRemoteDescription(new RTCSessionDescription(answer));
}
//when we got ice candidate from another user
function onCandidate(candidate) {
myConnection.addIceCandidate(new RTCIceCandidate(candidate));
}
คุณจะเห็นได้ว่าเมื่อผู้ใช้คลิกปุ่ม "สร้างการเชื่อมต่อ" แอปพลิเคชันจะยื่นข้อเสนอ SDP ให้กับเพื่อนอีกคนหนึ่ง นอกจากนี้เรายังตั้งค่าonAnswerและonCandidate handlers โหลดหน้าของคุณใหม่เปิดในสองแท็บล็อกอินด้วยผู้ใช้สองคนและพยายามสร้างการเชื่อมต่อระหว่างกัน คุณควรเห็นเอาต์พุตคอนโซลต่อไปนี้ -
ตอนนี้การเชื่อมต่อแบบเพียร์ทูเพียร์ถูกสร้างขึ้นแล้ว ในบทช่วยสอนถัดไปเราจะเพิ่มสตรีมวิดีโอและเสียงรวมถึงการสนับสนุนการแชทด้วยข้อความ