เข้ามาบ้าง. จากบทความเก่าและที่ถูกละทิ้งไปแล้ว ฉันเขียนเกี่ยวกับวิธีการออกอากาศวิดีโอจาก Canvas ผ่านเว็บซ็อกเก็ตได้อย่างง่ายดายและเป็นธรรมชาติ ในบทความนั้น ผมได้พูดคุยสั้นๆ เกี่ยวกับวิธีการถ่ายวิดีโอจากกล้องและเสียงจากไมโครโฟนโดยใช้ วิธีเข้ารหัสสตรีมที่ได้รับและส่งผ่านเว็บซ็อกเก็ตไปยังเซิร์ฟเวอร์ อย่างไรก็ตาม ในความเป็นจริงพวกเขาไม่ได้ทำเช่นนี้ สำหรับการออกอากาศพวกเขาใช้ซอฟต์แวร์พิเศษที่จำเป็นต้องติดตั้งและกำหนดค่า: ทันที สิ่งนี้สามารถทำได้ หรือใช้ WebRTC ซึ่งใช้งานได้ทันทีนั่นคือไม่จำเป็นต้องติดตั้งปลั๊กอิน a la flash player ใด ๆ ซึ่งจะถูกตัดออกจากเบราว์เซอร์ Chromium ในเดือนธันวาคม
วันนี้เราจะมาพูดถึง WebRTC
การสื่อสารแบบเรียลไทม์ผ่านเว็บ (WebRTC) ไม่ใช่โปรโตคอลเดียว แต่เป็นการรวบรวมมาตรฐาน โปรโตคอล และ JavaScript API ทั้งหมดที่ให้การสื่อสารผ่านวิดีโอและเสียงแบบเรียลไทม์แบบเพียร์ทูเพียร์ และยังสามารถใช้เพื่อถ่ายโอนข้อมูลใดๆ ก็ได้ ข้อมูลไบนารี โดยปกติแล้วเบราว์เซอร์จะทำหน้าที่เป็นเพียร์ แต่ก็สามารถเป็นแอปพลิเคชันมือถือได้เช่นกัน เพื่อจัดระเบียบการสื่อสาร p2p ระหว่างไคลเอนต์ จำเป็นต้องมีการรองรับเบราว์เซอร์สำหรับการเข้ารหัสวิดีโอและเสียงประเภทต่าง ๆ รองรับโปรโตคอลเครือข่ายที่หลากหลาย รับรองการทำงานร่วมกันของฮาร์ดแวร์กับเบราว์เซอร์ (ผ่านเลเยอร์ OS): เว็บแคม การ์ดเสียง การผสมผสานเทคโนโลยีทั้งหมดนี้ซ่อนอยู่หลังนามธรรม JavaScript API เพื่อความสะดวกของนักพัฒนา
ทั้งหมดนั้นแบ่งออกเป็นสาม API:
- เราแยกมันออกจากกันเมื่อครั้งที่แล้ว วันนี้ฉันจะเขียนเพิ่มเติมเกี่ยวกับเรื่องนี้อีกเล็กน้อย ทำหน้าที่รับสตรีมวิดีโอ / เสียงจากฮาร์ดแวร์
— ให้การสื่อสารระหว่างลูกค้าสองราย (p2p)
- ทำหน้าที่ถ่ายโอนข้อมูลโดยพลการระหว่างไคลเอนต์สองราย
การเตรียมสตรีมเสียงและวิดีโอสำหรับการส่งสัญญาณ
ทุกอย่างเริ่มต้นด้วยการ "จับภาพ" สตรีมสื่อของเว็บแคมและไมโครโฟน แน่นอนว่าสตรีมแบบดิบไม่เหมาะสำหรับการจัดการประชุมทางไกล แต่ละสตรีมจะต้องได้รับการประมวลผล: ปรับปรุงคุณภาพ ซิงโครไนซ์เสียงกับวิดีโอ วางเครื่องหมายการซิงโครไนซ์ในสตรีมวิดีโอ และตรวจสอบให้แน่ใจว่าบิตเรตสอดคล้องกับแบนด์วิดท์ที่เปลี่ยนแปลงตลอดเวลาของช่องสัญญาณ . เบราว์เซอร์จะดูแลทั้งหมดนี้ นักพัฒนาไม่จำเป็นต้องกังวลเกี่ยวกับการเข้ารหัสสำหรับสตรีมสื่อด้วยซ้ำ ภายในเบราว์เซอร์สมัยใหม่ มีเลเยอร์ซอฟต์แวร์สำหรับจับภาพ ปรับปรุงคุณภาพ (ลบเสียงสะท้อนและเสียงออกจากเสียง ปรับปรุงภาพ) การเข้ารหัสวิดีโอและเสียง โครงร่างเลเยอร์จะแสดงในรูป 1:
ข้าว. 1. เลเยอร์ของการประมวลผลเสียงและวิดีโอในเบราว์เซอร์
การประมวลผลทั้งหมดเกิดขึ้นโดยตรงในเบราว์เซอร์เอง ไม่มีการเพิ่มเติม ไม่ต้องใช้ปลั๊กอิน อย่างไรก็ตาม สิ่งต่างๆ ยังคงไม่สดใสนักในปี 2020 มีเบราว์เซอร์ที่ยังไม่รองรับอย่างสมบูรณ์ คุณสามารถไปตามลิงก์และดูตารางความเข้ากันได้ที่ด้านล่างสุด โดยเฉพาะ IE น่าผิดหวังอีกครั้ง
คุณสามารถทำสิ่งที่น่าสนใจมากกับสตรีมที่ได้รับ: คุณสามารถโคลน เปลี่ยนความละเอียดของวิดีโอ จัดการคุณภาพเสียง คุณสามารถนำและ "แนบ" สตรีม Media Stream ไปที่ แท็กและดูตัวเองในหน้า html หรือคุณสามารถวาดสตรีมบนผืนผ้าใบ และตั้งค่า WebGL หรือ CSS3 และใช้ตัวกรองต่างๆ กับวิดีโอ จับภาพวิดีโอที่ประมวลผลจาก Canvas แล้วส่งผ่านเครือข่ายไปยังเซิร์ฟเวอร์ แปลงรหัสและเผยแพร่ให้กับทุกคน (สวัสดี bigo live, twitch และคนอื่น ๆ). ที่นี่ฉันจะไม่วิเคราะห์ว่าสิ่งต่าง ๆ เสร็จสิ้นอย่างไร ฉันจะยกตัวอย่างสองสามตัวอย่างที่พบในเว็บ:
- พวกเขากำลังทำ CV แบบเรียลไทม์ใน Javascript พวกเขามีทั้ง ไลบรารี js ต่างๆ สำหรับการทำงานกับสตรีมวิดีโอบนผืนผ้าใบ: การตรวจจับใบหน้า วัตถุ การใช้ตัวกรอง (มาสก์ เช่น ใน Instagram) ฯลฯ ตัวอย่างที่ยอดเยี่ยมของวิธีที่คุณสามารถประมวลผลวิดีโอแบบเรียลไทม์ได้โดยตรงในเบราว์เซอร์โดยไม่ต้องใช้ปลั๊กอินเพิ่มเติม
- เอกสารประกอบ API สำหรับการจับภาพวิดีโอสตรีมจากแคนวาส รองรับ Chrome, Opera และ Firefox แล้ว
RTCPeerConnection
ดังนั้นเราจึงมาถึงประเด็น แต่จะถ่ายโอนวิดีโอไปยังผู้ใช้รายอื่นได้อย่างไร มาถึงเบื้องหน้าแล้ว . กล่าวโดยสรุป ในขั้นตอนนี้คุณจะต้องสร้างออบเจ็กต์ RTCPeerConnection:
const peerConnection = new RTCPeerConnection({
iceServers: [{
urls: 'stun:stun.l.google.com:19302'
}]
});เราระบุ iceServers เป็นหนึ่งในตัวเลือก - นี่คือเซิร์ฟเวอร์ที่ช่วยในการเชื่อมต่อระหว่างเบราว์เซอร์สองตัวที่อยู่เบื้องหลัง NAT'om นั่นคือปัญหาได้รับการแก้ไขที่นี่: จะทราบ ip ของคู่สนทนาได้อย่างไรว่าเขาอยู่เบื้องหลัง NAT ของผู้ให้บริการของเขาหรือไม่? โปรโตคอล ICE มาช่วยแล้ว อันที่จริง ICE ใช้ไม่ได้กับ WebRTC เลย แต่จะเพิ่มเติมในภายหลัง
ก่อนหน้านี้ เรามีสตรีม Usermedia:
navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => {
// Usermedia-потоки, обычно это видео и аудио
const tracks = stream.getTracks();
for (const track of tracks) {
// каждый трек присоединяем к peerConnection
peerConnection.addTrack(track);
}
}).catch(console.error);ถัดไป เหตุการณ์ที่จำเป็นต้องมีการเจรจาจะเริ่มทำงานบน peerConnection ในตัวจัดการที่เราต้องสร้างข้อเสนอ (ในแง่ของ SDP - Session Description Protocol) และกำหนดให้กับ peerConnection ผ่านเมธอด setLocalDescription เกี่ยวกับ SDP - คืออะไร และเกี่ยวกับรูปแบบข้อเสนอและคำตอบ - เราจะพูดคุยเพิ่มเติม
หลังจากกำหนด LocalDescription peerConnection แล้ว เบราว์เซอร์จะ "รวบรวม" ตัวเลือกน้ำแข็ง กล่าวคือ ค้นหาวิธีต่างๆ ในการสื่อสารผ่าน NAT เหตุการณ์ onicegatheringstatechange เริ่มทำงาน ในตัวจัดการ onicegatheringstatechange เราอนุญาตให้เชื่อมต่อกับสตรีม webrtc-signaling-server เพื่อแลกเปลี่ยนคำอธิบายเซสชันระหว่างเพียร์:
peerConnection.oniceconnectionstatechange = (event) => {
console.log('Connection state: ', peerConnection.iceConnectionState);
if (peerConnection.iceConnectionState === 'connected') {
// Можем активировать кнопку Start broadcast
setBroadcasting(true);
setBroadcastingBtnActive(true);
}
};
// Событие срабатывает сразу, как только добавился медаиапоток в peerConnection
peerConnection.onnegotiationneeded = (event) => {
// Создаем и назначаем SDP offer
peerConnection.createOffer().
then((offer) => peerConnection.setLocalDescription(offer)).
catch(console.error);
};
// Событие срабатывает каждый раз, как появляется ICE кандидат
peerConnection.onicegatheringstatechange = (ev) => {
let connection = ev.target;
// Now we can activate broadcast button
if (connection.iceGatheringState === 'complete') {
let delay = 50;
let tries = 0;
let maxTries = 3;
let timerId = setTimeout(function allowStreaming() {
if (isOnline) {
setBroadcastingBtnActive(true);
return;
}
if (tries < maxTries) {
tries += 1;
delay *= 2;
timerId = setTimeout(allowStreaming, delay);
} else {
// TODO: show user notification
console.error("Can't connect to server");
alert("Can't connect to server");
}
}, delay);
}
};webrtc-signaling-server คือเซิร์ฟเวอร์ที่จำเป็นสำหรับการแลกเปลี่ยนคำอธิบายเซสชันระหว่างสองเพียร์ ซึ่งอาจเป็น websocket หรือ xhr-server ที่ง่ายที่สุดบน PL ใดก็ได้ หน้าที่ของมันง่ายมาก: ยอมรับคำอธิบายเซสชั่นจากเพียร์หนึ่งแล้วโอนไปยังอีกเพียร์หนึ่ง
หลังจากการแลกเปลี่ยนคำอธิบายเซสชัน ทั้งสองฝ่ายก็พร้อมที่จะออกอากาศและรับสตรีมวิดีโอ ที่ด้านที่ได้รับสตรีมวิดีโอ เหตุการณ์ ontrack จะถูกทริกเกอร์บนการเชื่อมต่อแบบเพียร์ ในตัวจัดการ ซึ่งแทร็กที่ได้รับสามารถกำหนดให้กับ และดูคู่สนทนาที่คุณชื่นชอบ ทฤษฎีและรายละเอียดเพิ่มเติม
ลิงค์และวรรณกรรม:
- เอกสาร
- การใช้งานโปรโตคอล WebRTC ขณะเดินทาง
- หนังสือจากผู้สร้างไพออน
- จองเครือข่ายเบราว์เซอร์ประสิทธิภาพสูง มีการกล่าวถึงประเด็นต่างๆ ของการรับรองประสิทธิภาพสูงของเว็บแอปพลิเคชันอย่างละเอียด ในตอนท้ายจะมีการอธิบาย WebRTC หนังสือเล่มนี้เก่าอย่างแน่นอน (2013) แต่ก็ไม่ได้สูญเสียความเกี่ยวข้อง
ในส่วนถัดไป ฉันต้องการให้เพิ่มอีกเล็กน้อยของทฤษฎีและในทางปฏิบัติเพื่อวิเคราะห์การรับและการประมวลผลสตรีมวิดีโอบนเซิร์ฟเวอร์โดยใช้ pion การแปลงรหัสเป็น HLS ผ่าน ffmpeg สำหรับการออกอากาศครั้งต่อไปไปยังผู้ชมในเบราว์เซอร์
สำหรับผู้ที่ใจร้อน: (นี่เป็นเพียงการทดลอง)
ที่มา: will.com
