31 May, 2020

#36: Mình đã "tự chế" phần mềm video call như thế nào?

#36: Mình đã "tự chế" phần mềm video call như thế nào?
Available in:
 Vietnamese
Reading time: 4 min.
Table of content

    Đợt lockdown vì COVID-19 này khiến mình sống dựa vào video call. Nào là video call để phục vụ học tập, để phỏng vấn, và để nói chuyện với DT nữa. Vậy là một hôm, mình tự nhiên nảy ra ý tưởng: sao không thử build một app video call của riêng mình nhỉ?

    app rtc demo

    Sau khi tìm kiếm Google một lúc, mình tìm ra giải pháp khá phổ biến, đó là sử dụng giao thức WebRTC. Với giải pháp này, dữ liệu video sẽ truyền thẳng giữa 2 máy mà không cần qua server trung gian. Vậy thì quá tiện lợi rồi còn gì! Tuy nhiên, làm thế nào 2 máy có thể tìm thấy nhau giữa “biển” internet bao la nhỉ? Vậy hãy cùng tìm hiểu thêm về cách hoạt động của WebRTC nhé.

    webrtc

    WebRTC hoạt động như thế nào?

    WebRTC hoạt động bằng cách tạo một kết nối ngang hàng (peer-to-peer) để truyền dữ liệu (video/audio) trực tiếp giữa 2 máy, ở đây vì dụ là máy A và B.

    Để làm được việc này, A và B phải biết IP lẫn nhau. Tuy nhiên, việc biết IP thôi là chưa đủ, vì hầu hết các modem bây giờ đều dùng firewallNAT, đồng nghĩa với việc kết nối từ bên ngoài sẽ bị chặn ngay từ modem.

    firewall/NAT

    Để giải quyết vấn đề này, WebRTC sử dụng giao tức STUN để “đục” một cổng trên firewall:

    • Đầu tiên, máy của A sẽ gửi một binding request tới STUN server.
    • Do là gói tin UDP, modem sẽ mở và giữ 1 cổng để đợi câu trả lời từ phía server.
    • STUN server đó sẽ gửi lại dữ liệu rằng IP bên ngoài của bạn là bao nhiêu, và cổng nào đã được mở để giao tiếp.
    • Máy B có thể dùng IP và số cổng này để giao tiếp với máy A.

    STUN

    Do STUN hoạt động rất đơn giản, nên hầu hết các “ông lớn” (như Google, Facebook,…) đều cung cấp server STUN miễn phí để tất cả mọi người sử dụng.

    STUN sẽ hoạt động tốt trong hầu hết mọi trường hợp. Tuy nhiên, có một số trường hợp khá hiếm, modem sẽ chặn cả các gói tin UDP. Với trường hợp này, WebRTC sử dụng thêm một giao thức tên là TURN.

    TURN

    Giao thức TURN đơn giản là có một cái server đứng giữa (gọi là relay), làm nơi trung chuyển các gói tin giữa 2 máy. Và vì nó phải làm việc “nhận hàng” và “giao hàng” như thế, nên server cần băng thông khá lớn. Vì lý do đó, không có nhiều bên cung cấp TURN miễn phí. Mình chỉ tìm thấy numb.viagenie.ca là bên duy nhất miễn phí server TURN này.

    Sau khi đã thiết lập được “đường” tới máy A, máy A sẽ bằng cách nào đó gửi thông tin này cho máy B. Việc gửi này sẽ cần một server trung gian mà máy A và B đều có thể kết nối tới được. Ở phần mềm mà mình làm, mình có sử dụng firebase realtime database. Tuy nhiên, cũng có cách đơn giản hơn, đó là bạn copy – paste thông tin offer này qua facebook messenger chẳng hạn, và người kia nhập vào.

    Ý tưởng code

    Do WebRTC đã được hỗ trợ bởi tất cả các trình duyệt hiện hành, mình cũng không cần phải sử dụng thêm thư viện ngoài nào cả.

    1. Đầu tiên, bên app cần gọi hàm navigator.mediaDevices.getUserMedia để lấy quyền truy cập camera (trên iOS, bước này là bắt buộc để sử dụng WebRTC)
    2. Tạo một RTCPeerConnection mới (gọi tắt là pc)
    3. Ngay khi WebRTC tìm được một “đường” có thể dùng để kết nối từ ngoài vào (còn gọi là candidate), nó sẽ gọi pc.onicecandidate
    4. Như vậy, mình cần tạo hàm pc.onicecandidate sao cho nó nhận candidate này, và gửi cho máy còn lại
    5. Ngoài ra, do WebRTC yêu cầu phải có một máy làm “chủ”, và một (hay nhiều) máy khác kết nối tới, nên các máy kết nối tới sẽ cần tạo một offer bằng hàm pc.onnegotiationneededpc.createOffer
    6. Offer này sẽ được gửi cho máy “chủ”, có thể thông qua firebase hoặc đơn giản là copy paste offer qua.
    7. Và thế là đủ thông tin để 2 máy có thể kết nối với nhau.

    Demo

    Bản demo này mình code dựa trên bản của scaledrone. Mình có chỉnh sửa để nó sử dụng firebase realtime database, kèm theo một vài fix để nó chạy trên iOS:

    Source code + live demo: https://github.com/ngxson/hobby-rtc-demo

    Nếu bạn thấy code này hữu ích, đừng quên cho mình 1 star trên github nhé !

    Want to receive latest articles from my blog?