องค์ประกอบหลัก 3 ส่วน เป้าหมายเดียว
เบื้องหลัง Timmy สร้างขึ้นอย่างเรียบง่ายและใช้งานได้จริง: Flutter สำหรับแอป, WebRTC สำหรับเสียงและวิดีโอแบบเรียลไทม์ และ Firebase สำหรับการประสานงาน ผมไม่ต้องการสร้างแพลตฟอร์มขนาดใหญ่ที่ส่งทุกอย่างผ่านคลาวด์ แต่ละส่วนควรรู้ข้อมูลให้น้อยที่สุด และยังทำงานร่วมกับส่วนอื่นได้อย่างน่าเชื่อถือ
WebRTC: เชื่อมต่อตรง เข้ารหัสเป็นค่าเริ่มต้น
WebRTC (Web Real-Time Communication) ส่งเสียงและวิดีโอระหว่างอุปกรณ์ฝั่งลูกกับฝั่งผู้ปกครอง ในกรณีที่ดีที่สุด ข้อมูลจะไหล ตรงระหว่างอุปกรณ์ทั้งสอง, แบบเพียร์ทูเพียร์ โดยไม่มีเซิร์ฟเวอร์สื่อคั่นกลาง
การเชื่อมต่อ WebRTC ทุกครั้งใช้ DTLS-SRTP เป็นค่าเริ่มต้น หากมีใครดักจับแพ็กเก็ตเครือข่าย ก็จะไม่สามารถอ่านเสียงหรือวิดีโอได้ การเข้ารหัสนี้เป็นส่วนหนึ่งของโปรโตคอล และไม่สามารถปิดใน WebRTC ได้ง่าย ๆ
นี่คือจุดสำคัญสำหรับผม: ข้อมูลสื่อจากห้องของลูกไม่ควรอยู่บนเซิร์ฟเวอร์ของผม แต่ควรอยู่ระหว่างอุปกรณ์ของคุณเท่านั้น
การส่งสัญญาณผ่าน Firebase Firestore
ก่อนที่ WebRTC จะเริ่มทำงาน อุปกรณ์ต้องค้นหากันให้เจอและตกลงวิธีเชื่อมต่อกันก่อน ขั้นตอนนี้เรียกว่า การส่งสัญญาณ. Timmy ใช้ Firebase Firestore ซึ่งเป็นฐานข้อมูลบนคลาวด์ของ Google สำหรับขั้นตอนนี้
มีการแลกเปลี่ยนเฉพาะข้อมูลการเชื่อมต่อทางเทคนิค:
- ข้อเสนอและคำตอบ SDP: อธิบายความสามารถของอุปกรณ์ (โคเดกที่รองรับ ความละเอียด เป็นต้น)
- ICE candidates: เส้นทางเครือข่ายที่เป็นไปได้ ซึ่งอุปกรณ์ใช้เข้าถึงกันได้
เสียงและวิดีโอจะไม่ถูกส่งไปยัง Firebase โดย Firestore ทำหน้าที่ส่งเฉพาะข้อมูลการเชื่อมต่อทางเทคนิค Timmy ยังเข้ารหัสชั้นการส่งสัญญาณนี้ด้วย เพื่อไม่ให้ Firestore กลายเป็นจุดรวมข้อมูล SDP และ ICE แบบข้อความธรรมดา
เซิร์ฟเวอร์ TURN: เมื่อเชื่อมต่อตรงไม่ได้
บางเครือข่ายบล็อกการเชื่อมต่อตรง เช่น ไฟร์วอลล์ที่เข้มงวดหรือผู้ให้บริการมือถือบางราย ในกรณีนั้น WebRTC ต้องใช้ TURN relay (Traversal Using Relays around NAT)
Timmy จะลองใช้เซิร์ฟเวอร์ TURN ในเครื่องก่อน และใช้ Cloudflare เป็นทางเลือกสำรองเมื่อรีเลย์ในเครื่องไม่พร้อมใช้งานหรือมีภาระหนักเกินไป รีเลย์จะส่งต่อแพ็กเก็ตที่เข้ารหัส โดยไม่มีคีย์สำหรับเสียงหรือวิดีโอ การเข้ารหัสของ WebRTC ยังคงทำงานครบถ้วน
ข้อมูลรับรองสำหรับ TURN มาจาก Firebase Cloud Function และใช้ได้เพียง 24 ชั่วโมง สำหรับผม การฝังข้อมูลรับรองแบบถาวรไว้ในแอปเบบี้มอนิเตอร์มีความเสี่ยงเกินไป
Nearby Connections: ให้อุปกรณ์ค้นหากันเองโดยอัตโนมัติ
เพื่อไม่ให้การตั้งค่าระหว่างอุปกรณ์ฝั่งลูกและฝั่งผู้ปกครองยุ่งยาก Timmy ใช้ Nearby Connections. Google ให้ชั้นการค้นหานี้ผ่าน Bluetooth และ WiFi
การจับคู่อัตโนมัติใน Timmy ทำงานได้โดยไม่ต้องกรอกรหัสเอง: อุปกรณ์จะค้นหากันและหาจุดนัดพบเดียวกันสำหรับการแลกเปลี่ยนคีย์ หากไม่สำเร็จ คุณสามารถพิมพ์รหัส 4 ตัวอักษรได้ รหัสจับคู่จะไม่ออกจากอุปกรณ์; Firestore จะเห็นเพียงแฮชเชิงเข้ารหัส (SHA-256) ในฐานะตัวระบุเอกสาร
การยืนยันตัวตนแบบไม่ระบุตัวตน
Timmy ใช้ Firebase Anonymous Authentication เมื่อเปิดใช้ครั้งแรก อุปกรณ์แต่ละเครื่องจะได้รับ ID ชั่วคราวแบบไม่ระบุตัวตน ไม่มีบัญชี ไม่มีอีเมล และไม่มีรหัสผ่าน ID นี้มีไว้เพื่อบังคับใช้กฎของ Firestore เท่านั้น: เฉพาะอุปกรณ์ที่ยืนยันตัวตนแล้วจึงจะอ่านหรือเขียนข้อมูลเซสชันได้
โครงสร้างระบบ: ใครส่ง ใครรับ
Timmy มี 2 โหมด:
- โหมดลูกน้อย (ผู้ส่ง): อุปกรณ์จะรับเสียงผ่านไมโครโฟนและส่งไปยังอุปกรณ์ของผู้ปกครองผ่าน WebRTC คุณสามารถเปิดกล้องได้ตามต้องการ แล้ววิดีโอจะถูกส่งตรงเช่นกัน
- โหมดผู้ปกครอง (ผู้รับ): อุปกรณ์จะรับเสียงและวิดีโอ แสดงภาพจากกล้อง และมีฟังก์ชันกดพูดสำหรับส่งข้อความเสียงสั้น ๆ ไปยังอุปกรณ์ฝั่งลูก
การควบคุม เช่น กดพูดและเปิด/ปิดกล้อง ใช้ DataChannel, ซึ่งเป็นอีกช่องทางหนึ่งของ WebRTC สำหรับส่งข้อความขนาดเล็กที่เข้ารหัสโดยตรงระหว่างอุปกรณ์
ทำไมต้อง Flutter?
Flutter คือเฟรมเวิร์กของ Google สำหรับสร้างแอปบนหลายแพลตฟอร์ม สำหรับ Timmy นั่นหมายความว่าผมสามารถเขียนตรรกะส่วนใหญ่เพียงครั้งเดียว แล้วนำไปใช้ได้ทั้งบน Android และ iOS Timmy พร้อมใช้งานบน Android แล้ว และเวอร์ชัน iOS ใกล้จะเปิดตัว การมีโค้ดซ้ำซ้อนน้อยลงหมายถึงมีจุดที่บั๊กอาจแฝงตัวเข้ามาได้น้อยลง
สรุป
หลักการทางเทคนิคเรียบง่าย: Timmy ควรแตะต้องเฉพาะข้อมูลที่จำเป็นจริง ๆ เท่านั้น WebRTC ปกป้องข้อมูลสื่อ Firebase ประสานการตั้งค่าการเชื่อมต่อ TURN เห็นเพียงแพ็กเก็ตที่เข้ารหัส และ Nearby Connections ช่วยให้การจับคู่สะดวกขึ้น
เทคโนโลยีที่ดีควรกลมกลืนไปกับชีวิตประจำวันบ้าง ใช้งานได้โดยไม่เปลี่ยนห้องลูกให้กลายเป็นโปรเจกต์บนคลาวด์