[{"data":1,"prerenderedAt":941},["ShallowReactive",2],{"courses-list":3,"course-rust-webrtc-p2p":604},[4,23,35,277,289,593],{"slug":5,"title":6,"shortDescription":7,"description":8,"category":9,"level":10,"totalDuration":11,"totalLessons":12,"tags":13,"createdAt":14,"updatedAt":14,"rating":15,"reviewCount":16,"thumbnail":17,"instructor":18,"lessons":22},"rust-voip-kurento-media-server","Rust VoIP: Kurento Media Server","Khóa học này hướng dẫn bạn xây dựng hệ thống WebRTC Media Server chuyên sâu với Kurento Media Server\n và Rust Programming Language để tạo các ứng dụng realtime communication, SIP gateway và media processing ở mức low-level. Kurento là một media server mạnh mẽ hỗ trợ WebRTC, RTP, recording, transcoding, media routing và tích hợp OpenCV cho xử lý video realtime.","Khóa học này giúp bạn hiểu sâu cách hoạt động của một WebRTC Media Server thực thụ bằng cách sử dụng Kurento Media Server\n kết hợp với Rust Programming Language để xây dựng các hệ thống realtime communication, SIP gateway và media processing chuyên nghiệp.\n\nKhác với các nền tảng abstraction cao như LiveKit hay Twilio, Kurento cho phép bạn kiểm soát media flow ở mức rất sâu:\n\nRTP packet\nSDP negotiation\nMedia pipeline\nTranscoding\nRecording\nMedia filtering\nRouting\nMixing\nComputer Vision processing\n\nKurento là một Open Source WebRTC media server được xây dựng trên GStreamer, hỗ trợ:\n\nWebRTC\nRTP\nRTSP\nHTTP streaming\nRecording\nMixing\nTranscoding\nMCU\u002FSFU functionality\nOpenCV integration\n\nTrong khóa học này, bạn sẽ không chỉ “dùng API”, mà sẽ hiểu cách media server hoạt động thực sự phía bên dưới.\n\nBạn sẽ hiểu:\n\nVì sao cần media server\nPeer-to-peer limitations\nSFU vs MCU\nRTP routing\nCodec adaptation\nICE negotiation\nNAT traversal\nTURN\u002FSTUN\nSIP interoperability\nWebRTC media flow\n\nKhóa học bắt đầu bằng việc giải thích nền tảng WebRTC:\n\nOffer\u002FAnswer\nSDP\nICE Candidate\nRTP\nSRTP\nDTLS\nNAT traversal\nMedia transport\n\nSau đó bạn sẽ học kiến trúc của Kurento:\n\nMedia Pipeline\nMedia Element\nWebRtcEndpoint\nRtpEndpoint\nPlayerEndpoint\nRecorderEndpoint\nComposite\nHub\nDispatcher\n\nKurento được thiết kế theo mô hình modular pipeline, nơi media được xử lý bằng cách kết nối các component với nhau giống Lego blocks.\n\nBạn sẽ học cách:\n\nTạo media pipeline\nKết nối media element\nPublish\u002Fsubscribe media\nRoute media stream\nRecord media\nMix audio\u002Fvideo\nBroadcast stream\nHandle multiple participants\n1. Call App ↔ App\n\nBạn sẽ xây dựng hệ thống gọi điện realtime giữa:\n\nBrowser ↔ Browser\nMobile ↔ Browser\nDesktop ↔ Browser\n\nBao gồm:\n\nAudio Call\nVideo Call\nScreen Sharing\nRecording\nMulti-user room\nGroup call\nBroadcasting\n\nQuan trọng hơn, bạn sẽ hiểu:\n\nMedia flow bên trong media server\nRTP packet routing\nWebRTC endpoint hoạt động thế nào\nSFU forwarding\nMedia synchronization\nCodec transcoding\n\nBạn cũng sẽ tự xây signaling server bằng Rust:\n\nWebSocket signaling\nSDP exchange\nICE candidate exchange\nRoom management\nParticipant state\nSession lifecycle\n\nRust sẽ được sử dụng để xây:\n\nHigh-performance signaling server\nRealtime event handling\nAsync networking với Tokio\nSIP bridge service\nGateway service\n2. Call SIP → App\n\nĐây là phần cực kỳ quan trọng nếu bạn muốn làm VoIP hoặc AI Telephony.\n\nBạn sẽ học cách:\n\nNhận SIP INVITE\nParse SDP\nBridge SIP RTP vào WebRTC\nKết nối SIP phone với browser\nRoute media từ PSTN vào app\n\nFlow thực tế:\n\nSIP Phone gọi vào server\nSIP server gửi RTP\nKurento tạo RtpEndpoint\nBridge sang WebRtcEndpoint\nBrowser nhận audio\u002Fvideo realtime\n\nBạn sẽ hiểu sâu:\n\nSIP signaling\nINVITE\u002FACK\u002FBYE\nRTP media transport\nCodec negotiation\nG711\nOPUS\nH264\nDTMF\nSIP trunk\n\nKhóa học sẽ hướng dẫn cách kết nối:\n\nFreeSWITCH\nKamailio\nAsterisk\nSIP provider\nPSTN gateway\n\nSau phần này, bạn có thể tự xây:\n\nSIP Gateway\nAI Phone Bot\nAI Call Center\nPBX integration\nTelecom platform\n3. Call App → SIP\n\nChiều ngược lại cũng rất quan trọng:\n\nTừ browser gọi ra số điện thoại SIP\u002FPSTN.\n\nBạn sẽ học:\n\nRTP generation\nSIP dialing\nSIP registration\nOutbound calling\nSIP authentication\nRTP bridging\n\nFlow:\n\nUser click Call trên Web App\nRust backend gửi signaling\nKurento tạo media pipeline\nSIP gateway gửi INVITE\nRTP bridge WebRTC ↔ SIP\nĐiện thoại nhận cuộc gọi\n\nĐây là nền tảng để xây:\n\nSoftphone\nBrowser Phone\nCRM Calling\nAI Outbound Calling\nClick-to-call system\n4. Advanced Media Processing\n\nĐiểm mạnh lớn nhất của Kurento là media processing.\n\nBạn sẽ học:\n\nRecording stream\nMedia transcoding\nMedia mixing\nBroadcasting\nRTP forwarding\nRTSP integration\nIP Camera integration\n\nKurento hỗ trợ:\n\nRTSP camera\nRTP stream\nHTTP stream\nRecording MP4\u002FWebM\nTranscoding codec realtime\n\nNgoài ra:\n\nOpenCV integration\nFace recognition\nObject tracking\nAugmented reality\nVideo filtering\n\nĐây là phần cực kỳ hữu ích cho:\n\nAI Vision\nSmart Camera\nSurveillance system\nVideo analytics\nAI streaming platform\n5. Production Architecture\n\nKhóa học cũng đi sâu vào production deployment.\n\nBạn sẽ học:\n\nDocker deployment\nTURN\u002FSTUN setup\nNAT traversal\nTLS\u002FHTTPS\nScaling signaling server\nMonitoring\nRTP debugging\nWebRTC internals\nPerformance tuning\n\nBạn cũng sẽ hiểu:\n\nVì sao media server tốn CPU\nBottleneck của transcoding\nScaling challenge của MCU\u002FSFU\nRTP optimization\nMulti-node architecture\n\nKurento mạnh về khả năng media processing nhưng cần kiến trúc tốt để scale production lớn.","Backend","Advanced","5",0,"[\"kurento\",\"bytebuffer\",\"RTP\"]","2026-05-13 03:01:26",4,150,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778641249115-63e9889f-c5f1-4ffe-9ec7-c9ff5ef677f7.png",{"name":19,"title":20,"bio":21},"ByteBuffer","Coder cỏ tại DTS Group và IPAS","Chuyên gia về Rust và hệ thống VoIP\u002FWebRTC. Nhiều năm kinh nghiệm xây dựng các hệ thống real-time communication với hiệu năng cao và độ trễ thấp.",[],{"slug":24,"title":25,"shortDescription":26,"description":27,"category":9,"level":28,"totalDuration":11,"totalLessons":12,"tags":29,"createdAt":30,"updatedAt":30,"rating":15,"reviewCount":31,"thumbnail":32,"instructor":33,"lessons":34},"rust-voip-livekit-media-server","Rust VoIP: LiveKit Media Server","Khóa học này giúp bạn xây dựng hệ thống Voice\u002FVideo Call hoàn chỉnh với LiveKit\n và ngôn ngữ Rust Programming Language, tập trung vào kiến trúc realtime hiện đại dành cho VoIP, AI Voice Agent và ứng dụng WebRTC quy mô lớn.\n\nBạn sẽ học cách xây dựng từ đầu một nền tảng gọi điện realtime sử dụng LiveKit làm media server và Rust làm backend xử lý signaling, SIP routing, authentication, room management và business logic. Khóa học không chỉ dừng ở video call cơ bản mà còn đi sâu vào tích hợp SIP Telephony để kết nối giữa WebRTC và hệ thống điện thoại truyền thống.","Khóa học này hướng dẫn bạn xây dựng một hệ thống realtime communication hoàn chỉnh bằng LiveKit\n kết hợp với Rust Programming Language — một trong những stack hiện đại và mạnh mẽ nhất hiện nay dành cho Voice AI, WebRTC và SIP Telephony.\n\nTrong nhiều năm, việc xây dựng hệ thống gọi điện realtime thường phụ thuộc vào các nền tảng phức tạp như Asterisk, FreeSWITCH hoặc các giải pháp C\u002FC++ khó mở rộng và khó maintain. Với sự phát triển của WebRTC và LiveKit, việc xây dựng hệ thống voice\u002Fvideo realtime đã trở nên linh hoạt hơn rất nhiều. LiveKit cung cấp SFU media server hiện đại cùng hệ sinh thái SDK mạnh mẽ, hỗ trợ voice, video, screen sharing, AI Agents và SIP Telephony.\n\nTrong khóa học này, bạn sẽ không chỉ học cách “gọi video” đơn giản, mà sẽ hiểu cách xây dựng toàn bộ kiến trúc realtime communication thực tế để deploy production.\n\nBạn sẽ bắt đầu bằng việc tìm hiểu:\n\nWebRTC hoạt động như thế nào\nSFU là gì\nMedia flow giữa browser và server\nRTP\u002FSRTP\nICE, STUN, TURN\nSignaling architecture\nSIP và PSTN hoạt động ra sao\nLiveKit bridge SIP ↔ WebRTC như thế nào\n\nSau phần nền tảng, khóa học sẽ đi vào xây dựng backend bằng Rust với kiến trúc async hiệu năng cao sử dụng Tokio. Bạn sẽ học cách:\n\nTạo API backend cho LiveKit\nGenerate JWT token\nQuản lý room\nQuản lý participant\nDispatch user vào room\nXây signaling service riêng\nTheo dõi trạng thái cuộc gọi realtime\nScale realtime system\n\nRust được lựa chọn vì khả năng:\n\nHiệu năng cao\nMemory-safe\nAsync concurrency mạnh\nPhù hợp cho realtime networking\nTriển khai production ổn định\n\nĐây là stack rất phù hợp để xây:\n\nVoice AI\nCall Center\nCustomer Support Platform\nTelephony Gateway\nOmnichannel Communication\nSIP\u002FWebRTC Gateway\nAI Calling Platform\n\nMột phần quan trọng của khóa học là xây dựng các flow gọi điện thực tế.\n\n1. Call App ↔ App\n\nBạn sẽ học cách xây dựng hệ thống gọi giữa:\n\nBrowser ↔ Browser\nMobile ↔ Browser\nDesktop ↔ Mobile\n\nBao gồm:\n\nAudio Call\nVideo Call\nScreen Share\nRealtime Events\nParticipant Management\nRoom State\nMute\u002FUnmute\nRecording\n\nBạn cũng sẽ hiểu:\n\nMedia publish\u002Fsubscribe\nTrack management\nSFU forwarding\nLow latency optimization\n2. Call SIP → App\n\nĐây là phần rất quan trọng dành cho VoIP và Telephony.\n\nBạn sẽ học cách:\n\nNhận cuộc gọi từ SIP trunk\nKết nối từ PSTN\u002FSIP vào LiveKit room\nDispatch SIP participant vào ứng dụng\nBridge audio từ điện thoại vào WebRTC app\n\nFlow thực tế:\n\nNgười dùng gọi số điện thoại\nSIP provider gửi INVITE vào LiveKit\nLiveKit tạo SIP participant\nRust backend xử lý routing\nAgent\u002FWeb App tham gia room\nAudio được bridge RTP ↔ WebRTC\n\nBạn sẽ học:\n\nSIP INVITE\nSDP negotiation\nCodec negotiation\nRTP flow\nSIP trunk configuration\nDispatch rule\nDTMF handling\n\nSau phần này, bạn có thể xây:\n\nTổng đài AI\nHotline support\nSIP gateway\nAI receptionist\nVirtual call center\n3. Call App → SIP\n\nKhóa học cũng hướng dẫn chiều ngược lại:\n\nTừ WebRTC App gọi ra số điện thoại SIP\u002FPSTN\n\nBạn sẽ học:\n\nOutbound SIP trunk\nDialing flow\nSIP authentication\nCaller ID\nOutbound routing\nSIP participant creation\n\nFlow:\n\nUser click Call trong app\nRust backend tạo SIP participant\nLiveKit gửi SIP INVITE tới provider\nProvider route tới PSTN\nĐiện thoại nhận cuộc gọi\n\nĐây là nền tảng để xây:\n\nSoftphone\nAI outbound calling\nAuto-call system\nTelemarketing platform\nCRM Calling System\n4. Production Architecture\n\nKhóa học không chỉ demo local mà còn tập trung vào kiến trúc production thực tế.\n\nBạn sẽ học:\n\nSelf-host LiveKit\nRedis integration\nHorizontal scaling\nMonitoring\nLogging\nSIP gateway deployment\nTURN server setup\nTLS\u002FHTTPS\nDocker deployment\nReverse proxy\nLoad balancing","Intermediate","[\"livekit\",\"bytebuffer\"]","2026-05-13 02:50:39",130,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778640418253-386ef4a2-6cbc-42ad-80ed-3301d8d1e613.png",{"name":19,"title":20,"bio":21},[],{"slug":36,"title":37,"shortDescription":38,"description":39,"category":9,"level":28,"totalDuration":40,"totalLessons":41,"tags":42,"createdAt":43,"updatedAt":44,"rating":15,"reviewCount":45,"thumbnail":46,"instructor":47,"lessons":48},"rust-voip-janus-media-server","Rust VoIP: Janus Media Server","Chinh phục VoIP với khóa học \"Lập trình VoIP với Rust: Janus Media Server\". Bước tiếp từ nền tảng WebRTC P2P để xây dựng các hệ thống Media Server quy mô lớn, có khả năng scale thực tế và dùng trong production. Bạn sẽ làm chủ Janus Audiobridge để giải quyết triệt để các bài toán về băng thông, ghi âm tập trung và kết nối đa phương thức từ App-to-App đến SIP","Nâng tầm ứng dụng WebRTC của bạn lên quy mô Production\nNếu bạn đã hiểu cách các trình duyệt kết nối trực tiếp qua WebRTC P2P, thì đây chính là bước đi tiếp theo để đưa ứng dụng của bạn vào thực tế\n\nMô hình P2P rất tuyệt vời cho các kết nối đơn giản, nhưng khi đối mặt với các bài toán lớn hơn, nó bộc lộ 4 hạn chế nghiêm trọng:\n1. Khả năng mở rộng: Với 10 người dùng, hệ thống P2P cần tới 90 kết nối trực tiếp, khiến việc mở rộng là gần như không thể\n2. Tốn tài nguyên: Client phải upload đồng thời nhiều luồng media, gây ngốn CPU và nhanh hết pin, đặc biệt là trên thiết bị di động\n3. Không thể ghi âm tập trung: Media truyền trực tiếp giữa các peer nên không có cách nào ghi lại cuộc gọi một cách tập trung tại server\n4. Vấn đề NAT: Khoảng 15% người dùng gặp lỗi kết nối do NAT nghiêm ngặt\n\nGiải pháp đột phá với Janus Media Server\nKhóa học này sẽ hướng dẫn bạn sử dụng Janus Media Server – một thành phần trung gian mạnh mẽ để thay thế mô hình kết nối trực tiếp\n. Thay vì gửi dữ liệu cho nhau, tất cả client sẽ gửi media lên server để server xử lý và phân phối lại\nChúng ta sẽ tập trung sâu vào kiến trúc Modular của Janus, đặc biệt là Audiobridge plugin\nCơ chế Mixing: Server sẽ trộn (mix) các luồng audio lại thành một luồng duy nhất, giúp giảm đáng kể băng thông và tải cho phía người dùng\n\nKhả năng Scale: Hệ thống có thể đáp ứng hàng trăm, thậm chí hàng nghìn người dùng cùng lúc\n\nBạn sẽ học được gì?\nXuyên suốt khóa học, chúng ta sẽ cùng nhau lập trình bằng ngôn ngữ Rust để xây dựng một hệ thống hoàn chỉnh với các tính năng thực tế nhất:\n\nCall App to App: Kết nối giọng nói giữa hai ứng dụng WebRTC.\nCall App to SIP: Tích hợp gọi từ Web\u002FApp sang hệ thống tổng đài SIP truyền thống.\nCall SIP to App: Nhận cuộc gọi ngược lại từ hệ thống SIP về Web\u002FApp.\nAuto Callout: Phát triển hệ thống tự động gọi ra chuyên nghiệp.\n\nMục tiêu khóa học\nToàn bộ nội dung được thiết kế theo lộ trình từ cơ bản đến nâng cao, giúp bạn không chỉ hiểu về mặt lý thuyết mà còn có đủ kỹ năng để tự tay xây dựng một hệ thống Voice IP thực tế.","3",23,"[\"janus\",\"kamailio\",\"rtpengine\",\"b2bua\",\"rust\",\"bytebuffer\"]","2026-04-09 09:50:16","2026-05-06 15:07:02",190,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775728211540-3d1f7ec5-ba21-4176-9aa3-ca9775e232ba.png",{"name":19,"title":20,"bio":21},[49,59,69,79,88,98,108,118,128,138,148,158,168,178,188,198,208,218,228,238,248,258,268],{"slug":50,"title":51,"description":52,"duration":53,"youtubeId":54,"order":55,"thumbnail":56,"createdAt":57,"updatedAt":58},"rust-voip-janus-media-server-1-gioi-thieu-khoa-hoc","Rust VoIP - Janus Media Server #1: Giới thiệu khóa học","Chào mừng các bạn đến với khóa học: Lập trình VoIP với Rust: Janus Media Server.\nSau khi đã hoàn thành series WebRTC Peer-to-Peer (P2P), chúng ta sẽ bước sang một cấp độ mới: xây dựng hệ thống VoIP thực tế có khả năng scale và chạy production bằng Media Server.\n\nTrong video mở đầu này, chúng ta sẽ cùng phân tích những hạn chế của mô hình P2P và tìm hiểu cách Janus Media Server trở thành giải pháp tối ưu cho các hệ thống Voice IP hiện đại.","3:46","Yn69fThI0Hg",1,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777516323031-5d7bee10-a3a5-4286-bb2a-8d4d830e62f5.webp","2026-04-30 02:33:10","2026-04-30 02:33:20",{"slug":60,"title":61,"description":62,"duration":63,"youtubeId":64,"order":65,"thumbnail":66,"createdAt":67,"updatedAt":68},"rust-voip-janus-media-server-2-setup-janus-media-server","Rust VoIP - Janus Media Server #2: Setup Janus Media Server","Sau khi đã nắm vững lý thuyết về Media Server ở bài 1, trong video này chúng ta sẽ bắt đầu thực hành bằng cách cài đặt và triển khai Janus Media Server phiên bản 1.4.0 theo cách hiện đại, tối ưu và sẵn sàng cho production.","8:38","-OPBJaOqjRY",2,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777605821094-4f4f68f8-e270-4320-ae4d-7c47dfcb49a9.jpg","2026-05-01 03:29:04","2026-05-01 03:29:33",{"slug":70,"title":71,"description":72,"duration":73,"youtubeId":74,"order":75,"thumbnail":76,"createdAt":77,"updatedAt":78},"rust-voip-janus-media-server-3-setup-codebase-config-janus","Rust VoIP - Janus Media Server #3: Setup Codebase + Config Janus","Trong video này, chúng ta sẽ bắt đầu xây dựng nền tảng codebase cho toàn bộ hệ thống VoIP. Thay vì viết lại từ đầu, chúng ta sẽ tận dụng và tối ưu lại codebase từ series WebRTC P2P trước đó, đồng thời refactor để phù hợp với mô hình Media Server sử dụng Janus.","16:14","JpzsRi8woaE",3,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777734586801-ca933f87-d03b-438a-afd3-afccd8930252.png","2026-05-02 15:12:00","2026-05-02 15:34:42",{"slug":80,"title":81,"description":82,"duration":83,"youtubeId":84,"order":15,"thumbnail":85,"createdAt":86,"updatedAt":87},"rust-voip-janus-media-server-4-code-test-janus-api","Rust VoIP - Janus Media Server #4: Code + Test Janus API","Trong video này, chúng ta sẽ bắt đầu hiện thực hóa toàn bộ lý thuyết bằng code thực tế: từ deploy ứng dụng Rust lên server, cấu hình môi trường cho đến việc viết các service quan trọng để điều khiển Janus Media Server thông qua HTTP API và WebSocket.\n\nĐây là bước then chốt giúp bạn hiểu rõ cách Janus quản lý session, plugin và cách Rust Server có thể làm chủ hệ thống Audio Room trong thực tế.\n","29:18","LAiLHcPJuaE","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777821272050-d30cd83d-92f2-443b-ab15-940825aa45f9.png","2026-05-03 15:16:54","2026-05-03 15:17:04",{"slug":89,"title":90,"description":91,"duration":92,"youtubeId":93,"order":94,"thumbnail":95,"createdAt":96,"updatedAt":97},"rust-voip-janus-media-server-5-call-app-to-app-setup-call","Rust VoIP - Janus Media Server #5: Call App to App - Setup Call","Trong bài học này, chúng ta sẽ bắt đầu hiện thực hóa tính năng quan trọng nhất: Cuộc gọi App-to-App (ứng dụng gọi ứng dụng). Thay vì kết nối trực tiếp P2P như trước, chúng ta sẽ để Rust Server điều phối toàn bộ quá trình thiết lập cuộc gọi thông qua Janus Media Server.\n\nVideo sẽ hướng dẫn bạn cách thiết kế cấu trúc cuộc gọi, làm việc với Janus API và xây dựng State Machine để quản lý toàn bộ lifecycle của call.","42:50","LQv_TsMxffE",5,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777913016312-9f137fde-6b89-4edb-a8c6-624d82051c3b.png","2026-05-04 16:45:20","2026-05-04 16:45:30",{"slug":99,"title":100,"description":101,"duration":102,"youtubeId":103,"order":104,"thumbnail":105,"createdAt":106,"updatedAt":107},"rust-voip-janus-media-server-6-call-app-to-app-waiting-caller-sdp","Rust VoIP - Janus Media Server #6: Call App to App - Waiting Caller SDP","Trong bài học này, chúng ta sẽ đi sâu vào việc hiện thực hóa State Machine cho cuộc gọi App-to-App, với trọng tâm là trạng thái Waiting Caller SDP – bước quan trọng để thiết lập kết nối Media giữa Client và Janus Media Server.\n\nBạn sẽ học cách quản lý session, xử lý SDP Offer\u002FAnswer và hoàn tất quá trình handshake WebRTC giữa trình duyệt và Media Server.","45:37","x0I2XvmY3s4",6,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777996201433-4d12daf8-15ca-4037-954a-bcf1b8909e02.png","2026-05-05 15:51:42","2026-05-05 15:51:52",{"slug":109,"title":110,"description":111,"duration":112,"youtubeId":113,"order":114,"thumbnail":115,"createdAt":116,"updatedAt":117},"rust-voip-janus-media-server-7-call-app-to-app-connect-to-callee","Rust VoIP - Janus Media Server #7: Call App to App - Connect to Callee","Trong bài học trước, chúng ta đã hoàn tất việc trao đổi SDP giữa Caller và Janus. Trong phần này, chúng ta sẽ bước sang một giai đoạn quan trọng tiếp theo: kết nối tới người nhận (Callee).\n\nĐây là bước xử lý signaling giữa Server và nhiều client, bao gồm việc gửi thông báo incoming call, nhận phản hồi từ callee và điều phối state machine tương ứng.","24:20","Njas98M9haM",7,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778079658942-fbcfb353-2a9d-4500-bfdc-c8b39683fe74.png","2026-05-06 15:02:33","2026-05-06 15:02:44",{"slug":119,"title":120,"description":121,"duration":122,"youtubeId":123,"order":124,"thumbnail":125,"createdAt":126,"updatedAt":127},"rust-voip-janus-media-server-8-call-app-to-app-talking-state","Rust VoIP - Janus Media Server #8: Call App to App - Talking State","Hôm nay, chúng ta sẽ hoàn thiện bước cuối cùng để thiết lập một cuộc gọi App-to-App hoàn chỉnh: xử lý trạng thái Waiting Callee SDP và chuyển chính thức sang Talking State – trạng thái hai người dùng bắt đầu đàm thoại thực tế.\nVideo này sẽ giúp bạn hiểu sâu cách Rust Server phối hợp với Janus Media Server để quản lý Handle, xử lý SDP Answer và điều phối State Machine trong hệ thống VoIP production-ready.","27:43","3BQKNHshNss",8,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778113800978-2b2a5344-e1e2-4b57-97fb-52437cad8b6d.png","2026-05-07 00:32:38","2026-05-07 00:32:45",{"slug":129,"title":130,"description":131,"duration":132,"youtubeId":133,"order":134,"thumbnail":135,"createdAt":136,"updatedAt":137},"rust-voip-janus-media-server-9-call-app-to-app-end-state-keep-alive","Rust VoIP - Janus Media Server #9: Call App to App - End State + Keep Alive","Trong bài học này, chúng ta sẽ hoàn thiện những mảnh ghép cuối cùng của luồng gọi App-to-App. Trọng tâm của video là xử lý Talking State, End State và thiết lập cơ chế Keep Alive để duy trì kết nối ổn định giữa Rust Server và Janus Media Server.\n\nViệc quản lý tài nguyên (Resource Management) là cực kỳ quan trọng trong các hệ thống Media Server. Bạn sẽ học cách giải phóng sạch sẽ Session, Handle và Room sau khi cuộc gọi kết thúc để đảm bảo hệ thống luôn hoạt động ổn định và không bị memory leak.","19:16","ZmpNseImpVo",9,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778248694955-4d5b1236-dfcb-4266-9892-a5f1677a0ebf.png","2026-05-08 14:01:38","2026-05-08 14:01:50",{"slug":139,"title":140,"description":141,"duration":142,"youtubeId":143,"order":144,"thumbnail":145,"createdAt":146,"updatedAt":147},"rust-voip-janus-media-server-10-call-app-to-app-tong-ket","Rust VoIP - Janus Media Server #10: Call App to App - Tổng kết","Đây là bài học khép lại chương về luồng gọi App-to-App. Sau khi đã hiện thực hóa thành công toàn bộ hệ thống, hôm nay chúng ta sẽ cùng nhìn lại bức tranh tổng quan để hiểu rõ bản chất của việc kết nối qua Media Server khác biệt như thế nào so với mô hình WebRTC P2P truyền thống.\n\nVideo này sẽ giúp bạn hệ thống hóa lại toàn bộ quy trình signaling, phân tích luồng media thực tế thông qua Sequence Diagram và chuẩn bị nền tảng cho các chương nâng cao như SIP Integration.","10:29","zhnMLQ1GnW4",10,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778301141606-20df2c2b-0ab4-4666-aad2-1fc46a814096.png","2026-05-09 04:35:32","2026-05-09 04:50:11",{"slug":149,"title":150,"description":151,"duration":152,"youtubeId":153,"order":154,"thumbnail":155,"createdAt":156,"updatedAt":157},"rust-voip-janus-media-server-11-setup-telco-simulator","Rust VoIP - Janus Media Server #11: Setup Telco Simulator","Sau khi đã hoàn thành luồng gọi App-to-App (Web ↔ Web) ở các bài trước, hôm nay chúng ta sẽ bước sang một chương hoàn toàn mới và cực kỳ quan trọng trong hệ thống VoIP thực tế: kết nối giữa Web\u002FApp (WebRTC) và Phone\u002FSIP.\n\nTrong môi trường production, việc kết nối trực tiếp tới các nhà mạng (Telco) như Viettel, Vinaphone hoặc Mobifone thường rất phức tạp, tốn kém và khó test. Vì vậy, trong video này chúng ta sẽ cùng xây dựng một hệ thống Telco Simulator bằng Kamailio + Docker để giả lập hạ tầng viễn thông thực tế.","25:09","zJHrJyoujgA",11,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778349798865-8f7a4b58-5074-4a97-ab15-6f71fe10060e.png","2026-05-09 18:05:59","2026-05-09 18:06:07",{"slug":159,"title":160,"description":161,"duration":162,"youtubeId":163,"order":164,"thumbnail":165,"createdAt":166,"updatedAt":167},"rust-voip-janus-media-server-12-setup-sip-server-rtp-engine","Rust VoIP - Janus Media Server #12: Setup SIP server & RTP-engine","Nếu như ở bài trước chúng ta đã thiết lập Telco Simulator để phục vụ việc test, thì từ bài học này chúng ta sẽ bắt đầu xây dựng những thành phần cốt lõi của một hệ thống VoIP Production thực tế.","26:08","3ay4s5xqPuk",12,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778506468290-f62a272b-e9c1-48b0-8ff9-8f5787f1e70b.png","2026-05-11 13:36:44","2026-05-11 13:36:52",{"slug":169,"title":170,"description":171,"duration":172,"youtubeId":173,"order":174,"thumbnail":175,"createdAt":176,"updatedAt":177},"rust-voip-janus-media-server-13-route-from-phone-to-rust-server","Rust VoIP - Janus Media Server #13: Route from Phone to Rust Server","Trong bài học này, chúng ta sẽ bắt đầu hiện thực hóa luồng kết nối từ \"thế giới bên ngoài\" vào hệ thống nội bộ.\n\nCụ thể, chúng ta sẽ cấu hình để một cuộc gọi từ điện thoại (thông qua Softphone Zoiper) có thể đi xuyên qua nhiều lớp trung gian và đi đến Rust Server của chúng ta.\n\nĐây là bước cực kỳ quan trọng để backend Rust có thể nhận diện được cuộc gọi đến và chuẩn bị tài nguyên trên Janus Media Server cho luồng SIP-to-App.","33:00","PzBPUkLoPDY",13,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778594064646-5aeda5fd-1629-4744-8691-015e2e3991f9.png","2026-05-12 13:56:11","2026-05-12 13:56:20",{"slug":179,"title":180,"description":181,"duration":182,"youtubeId":183,"order":184,"thumbnail":185,"createdAt":186,"updatedAt":187},"rust-voip-janus-media-server-14-sip-to-app-create-call-and-define-call-state","Rust VoIP - Janus Media Server #14: Sip To App - Create Call and Define Call State","Trong bài học này, chúng ta sẽ bắt đầu hiện thực hóa luồng SIP-to-App, kết nối thế giới điện thoại truyền thống với ứng dụng WebRTC.\nTrọng tâm của video là cách xử lý bản tin SIP INVITE từ nhà mạng, khởi tạo tài nguyên trên Janus Media Server và xây dựng State Machine chuyên biệt cho luồng gọi SIP-to-App.\nBạn sẽ học cách lập trình Rust để \"hiểu\" các gói tin SIP\u002FUDP từ Kamailio và cách quản lý lifecycle của cuộc gọi.","33:30","AymBcvdDs0I",14,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778681710629-c7ed353a-5cc1-491f-8999-5fddf03c7f38.png","2026-05-13 14:17:02","2026-05-13 14:17:12",{"slug":189,"title":190,"description":191,"duration":192,"youtubeId":193,"order":194,"thumbnail":195,"createdAt":196,"updatedAt":197},"rust-voip-janus-media-server-15-sip-to-app-join-sip-member-state","Rust VoIP - Janus Media Server #15: Sip To App - Join SIP Member State","Tiếp tục hành trình xây dựng tính năng SIP-to-App, video hôm nay sẽ dẫn dắt bạn đi sâu vào việc lập trình trạng thái đầu tiên sau khi nhận cuộc gọi: Join SIP Member To Room.\nĐây là giai đoạn cực kỳ quan trọng để \"bắt tay\" giữa giao thức SIP truyền thống và Media Server hiện đại.\nBạn sẽ học cách quản lý các bản tin SIP đang chờ xử lý (Pending Transactions), kỹ thuật bóc tách dữ liệu SDP để lấy thông tin media và cách đưa một luồng RTP trực tiếp vào phòng họp của Janus.","32:15","hTZ5PF6lskU",15,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778811938620-8463785f-e4b5-4de5-b279-628414b63145.jpg","2026-05-15 02:27:58","2026-05-16 17:24:32",{"slug":199,"title":200,"description":201,"duration":202,"youtubeId":203,"order":204,"thumbnail":205,"createdAt":206,"updatedAt":207},"rust-voip-janus-media-server-16-sip-to-app-join-sip-member-state-sip-sdp-processing","Rust VoIP - Janus Media Server #16: Sip To App - Join SIP Member State: SIP SDP Processing","Trong bài học này, chúng ta sẽ đi sâu vào một trong những phần khó và quan trọng nhất của hệ thống VoIP thực tế:\n→ Điều phối luồng Media giữa:\n• SIP Phone\n• RTPEngine\n• Janus Media Server\nVideo tập trung vào cách tích hợp RTPEngine với Kamailio, xử lý các vấn đề NAT\u002FLocal IP và sử dụng Janus Admin API để lấy thông tin RTP thực tế phục vụ cho SIP-to-App flow.\nĐây là bước cực kỳ quan trọng trước khi chúng ta xây dựng SDP Answer hoàn chỉnh để kết nối media giữa Phone và WebRTC Client.","45:32","mjjyMDtdDCo",16,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778850470687-823a7c4f-46f3-4ea9-a506-f16be9c36f20.jpg","2026-05-15 13:11:02","2026-05-16 17:24:57",{"slug":209,"title":210,"description":211,"duration":212,"youtubeId":213,"order":214,"thumbnail":215,"createdAt":216,"updatedAt":217},"rust-voip-janus-media-server-17-sip-to-app-join-sip-member-state-finish","Rust VoIP - Janus Media Server #17: Sip To App - Join SIP Member State: Finish","Trong bài học này, chúng ta sẽ đi đến những bước cuối cùng để hoàn thiện trạng thái:\n\n→ Join SIP Member To Room\n\nĐây là giai đoạn cực kỳ quan trọng, nơi chúng ta thực hiện việc \"đấu nối\" thực tế luồng Media giữa:\n\n📞 SIP Phone\n↔ RTPEngine\n↔ Janus Media Server\n\nVideo tập trung vào cách sử dụng Janus Admin API để lấy RTP information thực tế, xây dựng SDP Answer chuẩn SIP và thiết lập Early Media trước khi kết nối tới WebRTC Client.","30:37","gHeivJ6qqwA",17,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1778952995672-add35f45-001b-4f51-b49d-eb15e221cf10.png","2026-05-16 17:39:24","2026-05-16 17:39:34",{"slug":219,"title":220,"description":221,"duration":222,"youtubeId":223,"order":224,"thumbnail":225,"createdAt":226,"updatedAt":227},"rust-voip-janus-media-server-18-sip-to-app-connect-to-agent","Rust VoIP - Janus Media Server #18: Sip To App - Connect to Agent","Sau khi đã hoàn thành việc đưa SIP Member vào phòng họp ở bài trước, hôm nay chúng ta sẽ thực hiện bước tiếp theo trong luồng SIP-to-App:\n\n→ Kết nối với WebRTC Client (Agent)\n\nMặc dù logic này có nhiều điểm tương đồng với cuộc gọi App-to-App, nhưng việc tích hợp vào luồng SIP đòi hỏi sự quản lý chặt chẽ hơn về:\n\n• WebSocket Events\n• Janus Events\n• State Machine\n• SDP Signaling\n\nVideo này sẽ hướng dẫn cách gửi thông báo cuộc gọi, xử lý phản hồi từ trình duyệt và hoàn tất quá trình bắt tay WebRTC để chuẩn bị bước sang Talking State.","24:49","49TTx-lZ5rw",18,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1779030645122-3b6972ed-0a86-49f3-8049-070f5276413b.png","2026-05-17 15:12:29","2026-05-17 15:12:41",{"slug":229,"title":230,"description":231,"duration":232,"youtubeId":233,"order":234,"thumbnail":235,"createdAt":236,"updatedAt":237},"rust-voip-janus-media-server-19-sip-to-app-end-state-and-edge-case","Rust VoIP - Janus Media Server #19: Sip To App - End state and EDGE case","Trong bài học này, chúng ta sẽ chưa đi ngay vào trạng thái Talking mà tập trung xử lý một phần cực kỳ quan trọng trong hệ thống VoIP Production:\n→ End State\n→ SIP Edge Cases\n→ Resource Cleanup\n→ SIP Dialog Management\n\nVideo sẽ hướng dẫn cách xử lý các SIP message như:\n• CANCEL\n• BYE\n• ACK\n• PRACK\nđồng thời đảm bảo mọi tài nguyên trên Janus Media Server được giải phóng chính xác khi cuộc gọi kết thúc.\n\nĐây là bước cực kỳ quan trọng để tránh:\n• Memory leak\n• SIP retransmission loop\n• Zombie session\n• Treo signaling\n• Room\u002FHandle không được cleanup","27:42","U6w6css4QXM",19,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1779108882667-ac46f71e-10e9-4c2f-9178-915f30b222e3.png","2026-05-18 12:56:43","2026-05-18 12:56:55",{"slug":239,"title":240,"description":241,"duration":242,"youtubeId":243,"order":244,"thumbnail":245,"createdAt":246,"updatedAt":247},"rust-voip-janus-media-server-20-sip-to-app-talking-state","Rust VoIP - Janus Media Server #20: Sip To App - Talking State","Chào mừng bạn đến với Bài 20 của khóa học: \"Lập trình VoIP với Rust: Janus Media Server\".\n\nSau khi đã xử lý xong các trạng thái chờ và các tình huống ngoại lệ (Edge Cases) ở bài trước, hôm nay chúng ta sẽ đi vào giai đoạn cuối cùng của luồng gọi SIP-to-App:\n\n→ Talking State\n\nĐây là trạng thái đàm thoại chính thức, nơi các bản tin signaling cuối cùng được trao đổi để thiết lập luồng media hoàn chỉnh giữa:\n\n📞 SIP Phone\n↔ RTP\n↔ Janus Media Server\n↔ WebRTC Browser\n\nTrong video này, bạn sẽ học cách định nghĩa Talking State, build SIP 200 OK chuẩn RFC và quản lý toàn bộ signaling trong suốt thời gian cuộc gọi diễn ra.","19:07","_lodSSKa7-c",20,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1779202016573-aef84b9b-e887-4063-bdc8-26f2404e6a61.png","2026-05-19 14:48:54","2026-05-19 14:49:08",{"slug":249,"title":250,"description":251,"duration":252,"youtubeId":253,"order":254,"thumbnail":255,"createdAt":256,"updatedAt":257},"rust-voip-janus-media-server-21-sip-to-app-debug-rtp-media","Rust VoIP - Janus Media Server #21: Sip To App - Debug RTP Media","Chào mừng bạn đến với Bài 21 của khóa học: \"Lập trình VoIP với Rust: Janus Media Server\".","13:39","QZra2Xi8-EE",21,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1779300155714-89fafa47-3a66-488f-830d-cb62d5ec7838.png","2026-05-20 18:05:57","2026-05-20 18:06:07",{"slug":259,"title":260,"description":261,"duration":262,"youtubeId":263,"order":264,"thumbnail":265,"createdAt":266,"updatedAt":267},"rust-voip-janus-media-server-22-app-to-sip-setup-call","Rust VoIP - Janus Media Server #22: App To Sip: Setup Call","Sau khi đã triển khai thành công các luồng gọi: App-to-App, SIP-to-App, trong bài học này, chúng ta sẽ bắt đầu xây dựng luồng ngược lại: 📞 App-to-SIP. Đây là tính năng cho phép WebRTC Browser thực hiện cuộc gọi trực tiếp tới số điện thoại SIP thông qua hệ thống Telco Simulator.\n\n","24:42","eGdvnoDsC98",22,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1779374627371-6af0878c-d12d-48f4-b06c-e36bc6722549.png","2026-05-21 14:46:13","2026-05-21 14:46:38",{"slug":269,"title":270,"description":271,"duration":272,"youtubeId":273,"order":41,"thumbnail":274,"createdAt":275,"updatedAt":276},"rust-voip-janus-media-server-23-app-to-sip-waiting-caller-sdp-state","Rust VoIP - Janus Media Server #23: App To Sip: Waiting Caller SDP State","Sau khi đã xây dựng xong bộ khung cho luồng:📞 App-to-SIP, ở bài trước, hôm nay chúng ta sẽ bắt đầu hiện thực hóa state đầu tiên của outbound calling flow: → Waiting Caller SDP State. Đây là giai đoạn quan trọng để thiết lập media path từ WebRTC Browser trước khi hệ thống thực hiện cuộc gọi ra phía SIP\u002FTelco.","30:51","xl8G5x-fKuk","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1779410950781-23b55e4e-1f61-46f3-91d0-d7614510bc18.png","2026-05-22 00:52:02","2026-05-22 00:52:18",{"slug":278,"title":279,"shortDescription":280,"description":281,"category":9,"level":10,"totalDuration":282,"totalLessons":12,"tags":283,"createdAt":284,"updatedAt":285,"rating":12,"reviewCount":12,"thumbnail":286,"instructor":287,"lessons":288},"rust-voip-freeswitch-media-server","Rust VoIP: Freeswitch Media Server","Khám phá sức mạnh của FreeSWITCH trong việc xây dựng hệ thống VoIP production-ready. Từ nền tảng WebRTC P2P, bạn sẽ tiến tới kiến trúc Media Server có khả năng scale lớn, xử lý hàng nghìn cuộc gọi đồng thời.","FreeSWITCH mang lại những tính năng mạnh mẽ:\n\n1. Xử lý SIP call linh hoạt (inbound\u002Foutbound, gateway, trunking)\n2. Hỗ trợ codec đa dạng (Opus, G.711, G.729…)\n3. Conference (multi-party call) với khả năng scale cao\n4. IVR (Interactive Voice Response) tùy biến bằng XML\u002FLua\n5. Ghi âm cuộc gọi (call recording) và media processing\n6. Event Socket (ESL) cho phép control realtime từ backend (Rust, Java…)\n7. Tích hợp WebRTC ↔ SIP bridge\n8. Load balancing & clustering cho hệ thống lớn\n\nPhù hợp để xây dựng các hệ thống như call center, voice app, hoặc bridge giữa WebRTC và hạ tầng viễn thông truyền thống.","4","[\"freeswitch\",\"rust\",\"bytebuffer\"]","2026-04-11 13:07:47","2026-04-11 13:07:57","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775912828865-ef7f2462-4ba9-4256-b115-8ee175030134.png",{"name":19,"title":20,"bio":21},[],{"slug":290,"title":291,"shortDescription":292,"description":293,"category":9,"level":28,"totalDuration":294,"totalLessons":295,"tags":296,"createdAt":297,"updatedAt":298,"rating":299,"reviewCount":300,"thumbnail":301,"instructor":302,"lessons":303},"rust-webrtc-p2p","WebRTC Peer to Peer với Rust","Xây dựng Signaling Server bằng Rust để thiết lập cuộc gọi audio\u002Fvideo P2P giữa hai trình duyệt với WebRTC.","Khóa học thực chiến giúp bạn xây dựng từ đầu một Signaling Server bằng Rust, xử lý các cuộc gọi audio\u002Fvideo trực tiếp giữa hai trình duyệt thông qua WebRTC Peer-to-Peer mà không cần Media Server.\n\nBạn sẽ nắm vững kiến trúc WebRTC signaling, cách trao đổi SDP Offer\u002FAnswer và ICE Candidates giữa các peer thông qua WebSocket. Khóa học sử dụng Axum + Tokio cho backend, MongoDB để lưu trữ dữ liệu, và JWT để xác thực người dùng.\n\nĐây là Phần 1 trong series 7 phần về Lập trình Rust với VoIP, bao gồm: WebRTC P2P, Media Server (Janus, LiveKit, Kurento, Asterisk, FreePBX), và hệ thống CRM\u002FQueue\u002Fnhạc chờ\u002Fchuyển tiếp cuộc gọi.\n\nYêu cầu tiên quyết: Kiến thức cơ bản về Rust (Ownership, Lifetimes, Traits, Async\u002FAwait).","5 giờ",32,"[\"Rust\",\"WebRTC\",\"VoIP\",\"P2P\",\"Axum\",\"Tokio\",\"WebSocket\",\"MongoDB\",\"JWT\"]","2026-04-06 16:39:52","2026-04-10 00:15:52",4.8,320,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775495865592-4cdf9be1-d9ed-459c-b59b-178041ba66b5.png",{"name":19,"title":20,"bio":21},[304,312,320,328,336,344,352,361,370,378,387,396,405,414,423,432,441,450,459,468,477,486,495,504,514,524,534,544,554,564,574,584],{"slug":305,"title":306,"description":307,"duration":308,"youtubeId":309,"order":55,"thumbnail":310,"createdAt":297,"updatedAt":311},"gioi-thieu-khoa-hoc","Rust WebRTC P2P #1 - Giới thiệu khóa học","Chào mừng bạn đến với series Rust VoIP! Trong bài mở đầu, bạn sẽ nắm được bức tranh toàn cảnh: mục tiêu xây dựng Signaling Server bằng Rust, kiến trúc P2P (Browser ↔ Rust Server ↔ Browser), tech stack sử dụng (Axum, Tokio, WebSocket, MongoDB, JWT), và lộ trình 7 phần của toàn bộ series từ WebRTC đến CRM\u002FQueue.","5:29","Gj9wYJ57qfA","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775495174815-9cda6d98-4692-4476-815d-0437bad01c59.webp","2026-04-11 05:30:00",{"slug":313,"title":314,"description":315,"duration":316,"youtubeId":317,"order":65,"thumbnail":318,"createdAt":297,"updatedAt":319},"voip-la-gi-webrtc-la-gi","Rust WebRTC P2P #2 - VoIP là gì? WebRTC là gì?","Hiểu bản chất VoIP — công nghệ truyền thoại\u002Fvideo qua mạng IP đứng sau Skype, Zoom, Google Meet. Sau đó khám phá WebRTC — bộ tiêu chuẩn cho phép trình duyệt giao tiếp trực tiếp peer-to-peer: media đi thẳng giữa hai browser, server chỉ làm nhiệm vụ signaling duy nhất.","7:13","Ih1lcfZwzeE","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775495227568-62ba7951-3528-4c10-973d-13f726732f56.webp","2026-04-06 17:07:52",{"slug":321,"title":322,"description":323,"duration":324,"youtubeId":325,"order":75,"thumbnail":326,"createdAt":297,"updatedAt":327},"sip-overview-why-rust","Rust WebRTC P2P #3 - SIP overview + Why choose Rust","So sánh SIP (giao thức signaling truyền thống trong telephony) với WebRTC signaling nhẹ hơn, phù hợp browser. Đi sâu vào 4 lý do chọn Rust: hiệu năng không GC pause, safety ngăn data race từ compile time (Arc, DashMap, mpsc), async mạnh mẽ với Tokio, và cơ chế bắt buộc xử lý lỗi — yếu tố sống còn khi server chịu hơn 100K cuộc gọi\u002Fngày.","3:23","SVOsqmEs2SQ","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775495301130-3cedf79b-354f-4035-bad9-1d2166099956.webp","2026-04-06 17:08:23",{"slug":329,"title":330,"description":331,"duration":332,"youtubeId":333,"order":15,"thumbnail":334,"createdAt":297,"updatedAt":335},"install-rust-rustrover-cargo","Rust WebRTC P2P #4 - Install Rust + RustRover + Cargo Commands","Thực hành cài đặt Rust Toolchain qua rustup.rs trên Windows\u002FLinux\u002FmacOS và xác thực bằng rustc, cargo, rustup. Khám phá RustRover — IDE chuyên biệt giúp code Rust nhanh hơn VS Code. Làm quen 4 lệnh Cargo thiết yếu: cargo new, cargo build, cargo build --release và cargo run.","7:36","Pzj8FiXvmwo","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775495334946-b2e8a644-6797-4a0a-8aa8-bc9f6926fb1b.webp","2026-04-06 17:08:56",{"slug":337,"title":338,"description":339,"duration":340,"youtubeId":341,"order":94,"thumbnail":342,"createdAt":297,"updatedAt":343},"hello-world-tokio-runtime-cargo-toml","Rust WebRTC P2P #5 - Hello World + Tokio Runtime + Cargo.toml","Khám phá Cargo.toml — trái tim quản lý dependencies của mọi dự án Rust. Khai báo các thư viện sẽ dùng xuyên suốt khóa học: Axum, Tokio, Serde, DashMap, UUID, Log4rs, Anyhow. Cấu hình Tokio Runtime biến hàm main thành async, tận dụng thread pool xử lý hàng nghìn kết nối đồng thời. Kết thúc bằng việc chạy thành công project Hello World đầu tiên.","5:13","HIcUJYrI_7U","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775495371395-6e99fb8b-7734-479f-9386-6a4bc75d6cff.webp","2026-04-06 17:09:32",{"slug":345,"title":346,"description":347,"duration":348,"youtubeId":349,"order":104,"thumbnail":350,"createdAt":351,"updatedAt":351},"axum-server-config-loading","Rust WebRTC P2P #6 - Axum Server + Config Loading","Chào mừng bạn quay trở lại với series WebRTC Peer-to-Peer (P2P) với Rust\n\nTrong phần 6 này:\nChúng ta bắt đầu xây dựng backend\n→ Thiết lập hệ thống cấu hình (Config)\n→ Khởi tạo Axum HTTP Server","42:44","DmHrozL4its","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775495482671-3d9accc9-dbe7-45e4-bdaa-2b4361dc3b34.webp","2026-04-06 17:12:39",{"slug":353,"title":354,"description":355,"duration":356,"youtubeId":357,"order":114,"thumbnail":358,"createdAt":359,"updatedAt":360},"mongodb-logging-with-log4rs","Rust WebRTC P2P #7 - MongoDB + Logging with log4rs","Chào mừng bạn quay trở lại với series WebRTC Peer-to-Peer (P2P) bằng Rust\n\nTrong video 7 này:\nChúng ta hoàn thiện nền tảng Signaling Server với 2 phần quan trọng:\n- Cấu hình MongoDB\n- Thiết lập hệ thống Logging với log4rs","15:44","K9D_tT1iJQ8","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775495650431-ec57a6c7-3937-48b5-ac5d-7c2b105d32b4.webp","2026-04-06 17:14:11","2026-04-06 17:15:17",{"slug":362,"title":363,"description":364,"duration":365,"youtubeId":366,"order":124,"thumbnail":367,"createdAt":368,"updatedAt":369},"create-websocket-endpoint-with-axum","Rust WebRTC P2P #8 - Create WebSocket Endpoint with Axum","WebSocket là giao thức giữ kết nối hai chiều liên tục — khác HTTP request\u002Fresponse. Trong signaling server, mỗi user kết nối WebSocket và giữ kết nối suốt session\n","15:45","dX4phlMs4b4","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775574741518-39f6b0a5-0899-4775-bae8-2c07da84f8ee.webp","2026-04-07 15:20:06","2026-04-07 15:29:25",{"slug":371,"title":372,"description":373,"duration":374,"youtubeId":375,"order":134,"thumbnail":376,"createdAt":377,"updatedAt":377},"connectionstate-client-online-management","Rust WebRTC P2P #9 - ConnectionState — Client Online management","Chào mừng bạn quay trở lại với series WebRTC Peer-to-Peer (P2P) bằng Rust\n\nTrong phần 9 này:\nChúng ta xây dựng một thành phần cốt lõi của Signaling Server\n→ Quản lý trạng thái kết nối (Connection State)\n→ Quản lý danh sách user đang online","8:46","DSWewq_Ft48","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775657276388-20da4fcb-6126-4224-b333-16adac68afe2.webp","2026-04-08 14:14:48",{"slug":379,"title":380,"description":381,"duration":382,"youtubeId":383,"order":144,"thumbnail":384,"createdAt":385,"updatedAt":386},"message-routing-dispatcher-pattern","Rust WebRTC P2P #10 - Message Routing — Dispatcher Pattern","Trong phần 10 này, chúng ta sẽ tiến hành chuẩn hóa cách thức trao đổi dữ liệu giữa Client và Server thông qua WebSocket bằng cách xây dựng hệ thống Message Routing và áp dụng Dispatcher Pattern.","9:37","w1o6z46nbgs","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775726962635-205922a3-435d-455d-bf21-f41c57ca7436.webp","2026-04-09 09:33:02","2026-04-10 00:14:36",{"slug":388,"title":389,"description":390,"duration":391,"youtubeId":392,"order":154,"thumbnail":393,"createdAt":394,"updatedAt":395},"nginx-config-deploy-live-on-vps","Rust WebRTC P2P #11 - Nginx Config + Deploy Live on VPS","Chúng ta đưa Signaling Server từ local lên VPS thực tế\n→ Cấu hình domain\n→ Setup Nginx\n→ Thiết lập HTTPS (SSL)","16:28","CQKW3uUgm_Y","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775831831726-148865ca-dcbf-4682-9e0b-41435a17be0d.jpg","2026-04-10 14:40:09","2026-04-11 02:04:35",{"slug":397,"title":398,"description":399,"duration":400,"youtubeId":401,"order":164,"thumbnail":402,"createdAt":403,"updatedAt":404},"user-model-mongodb-queries","Rust WebRTC P2P #12 - User Model + MongoDB Queries","Trong phần này, mình bắt đầu xây dựng Data Layer cho hệ thống, bao gồm User Model và các truy vấn MongoDB. Đây là nền tảng quan trọng để triển khai Login và Authentication cho cả REST API và WebSocket server.","4:34","Ov54lD682Kw","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775911639340-b03d16cc-a0a8-4233-a5e1-50a94743f954.png","2026-04-11 12:51:02","2026-04-11 12:51:13",{"slug":406,"title":407,"description":408,"duration":409,"youtubeId":410,"order":174,"thumbnail":411,"createdAt":412,"updatedAt":413},"login-service-jwt-argon2","Rust WebRTC P2P #13 - Login Service + JWT + Argon2","Trong phần 13 này, chúng ta triển khai một trong những tính năng quan trọng nhất của backend: Login Service. Mục tiêu là xây dựng cơ chế xác thực an toàn, sử dụng JWT và các tiêu chuẩn bảo mật hiện đại để bảo vệ thông tin người dùng.","22:03","sICzdbRpwnw","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775983603748-ad6186f1-5c2f-4cf2-8e07-29b6880a9c55.png","2026-04-12 08:47:56","2026-04-12 08:48:12",{"slug":415,"title":416,"description":417,"duration":418,"youtubeId":419,"order":184,"thumbnail":420,"createdAt":421,"updatedAt":422},"auth-middleware-http-websocket-auth-flow","Rust WebRTC P2P #14 - Auth Middleware HTTP + WebSocket Auth Flow","Trong phần 14 này, chúng ta thực hiện một bước rất quan trọng để bảo vệ hệ thống: xây dựng Middleware cho HTTP Server và thiết lập luồng xác thực cho WebSocket. Đây là lớp bảo vệ giúp đảm bảo chỉ những người dùng hợp lệ mới có thể truy cập API và thiết lập kết nối signaling.","50:35","Maz-uKSzoto","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776072985484-4936c485-dfcb-4919-8b83-6e364e6a1255.webp","2026-04-13 09:37:58","2026-04-13 09:38:16",{"slug":424,"title":425,"description":426,"duration":427,"youtubeId":428,"order":194,"thumbnail":429,"createdAt":430,"updatedAt":431},"demo-login-websocket-auth-tu-postman","Rust WebRTC P2P #15 - Demo Login + WebSocket Auth từ Postman","Trong phần 15 này, chúng ta thực hiện demo toàn bộ quy trình xác thực đã xây dựng ở các phần trước. Sử dụng Postman để mô phỏng client, chúng ta sẽ kiểm tra cách server xử lý token thông qua cả HTTP và WebSocket.","5:12","8GmuMOpl_JQ","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776176649415-701f3222-2da2-43a7-b9ad-7f52a41386b4.webp","2026-04-14 14:25:25","2026-04-14 14:25:35",{"slug":433,"title":434,"description":435,"duration":436,"youtubeId":437,"order":204,"thumbnail":438,"createdAt":439,"updatedAt":440},"state-pattern-p2pcallstatehandler-trait","Rust WebRTC P2P #16 - State Pattern — P2PCallStateHandler Trait","Trong phần 16 này, chúng ta đi vào một thành phần rất quan trọng trong kiến trúc của signaling server: State Pattern. Đây là phần “trái tim” giúp điều khiển toàn bộ luồng xử lý của một cuộc gọi, từ lúc bắt đầu cho đến khi kết thúc.","12:04","6BrjxQmROU0","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776240875283-0880cb67-c8fd-4f77-975f-0d05d3fa6394.png","2026-04-15 08:17:01","2026-04-15 08:17:23",{"slug":442,"title":443,"description":444,"duration":445,"youtubeId":446,"order":214,"thumbnail":447,"createdAt":448,"updatedAt":449},"callactor-event-loop-timer-management","Rust WebRTC P2P #17 - CallActor - Event Loop + Timer Management","Trong phần 17 này, chúng ta thiết kế một thành phần rất quan trọng trong hệ thống: CallActor (Connector). Đây là nơi tiếp nhận toàn bộ sự kiện của cuộc gọi, quản lý timer và điều phối logic xử lý, đóng vai trò như “bộ não” của signaling server.","4:25","YELAgVosv2A","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776335165827-54c2c9e3-c018-4405-8095-c7880397b5f4.webp","2026-04-16 10:28:43","2026-04-16 10:29:10",{"slug":451,"title":452,"description":453,"duration":454,"youtubeId":455,"order":224,"thumbnail":456,"createdAt":457,"updatedAt":458},"callsupervisor-call-lifetime-management","Rust WebRTC P2P #18 - CallSupervisor - Call lifetime management","Trong phần này, chúng ta xây dựng CallSupervisor – thành phần quản lý trung tâm chịu trách nhiệm điều phối và quản lý vòng đời của các cuộc gọi trong hệ thống signaling server. Đây là lớp giúp hệ thống kiểm soát tài nguyên, điều phối message và đảm bảo hoạt động ổn định khi có nhiều cuộc gọi đồng thời.","23:08","rf2PzQm4DMA","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776415950702-29af7f20-e004-4d40-86e3-3c3c7fc7a10b.webp","2026-04-17 08:53:46","2026-04-17 08:53:57",{"slug":460,"title":461,"description":462,"duration":463,"youtubeId":464,"order":234,"thumbnail":465,"createdAt":466,"updatedAt":467},"architecture-offeranswerice-overview","Rust WebRTC P2P #19 - P2P Architecture + Offer\u002FAnswer\u002FICE Overview","Trong phần 19 này, chúng ta sẽ tạm dừng việc viết code để cùng nhìn lại một cách chi tiết và hệ thống nhất về kiến trúc P2P thực tế mà chúng ta đang xây dựng. Video này sẽ giúp bạn hình dung rõ nét cách các bản tin Offer, Answer và ICE Candidate di chuyển qua lại giữa Caller, Callee và Rust Signaling Server","2:31","DcRrOSEZKaI","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776525459714-02251de5-48df-49ed-8cfb-2b82559c440a.png","2026-04-18 15:21:03","2026-04-18 15:21:30",{"slug":469,"title":470,"description":471,"duration":472,"youtubeId":473,"order":244,"thumbnail":474,"createdAt":475,"updatedAt":476},"sdp-chi-tiet-ipv4-port-codec","Rust WebRTC P2P #20 - SDP Detail — ipv4, Port, Codec","Trong phần 20 này, chúng ta sẽ đi sâu vào \"trái tim\" của quá trình Signaling: SDP (Session Description Protocol). Đây là bản tin mô tả phiên làm việc giúp hai trình duyệt hiểu được nhau về mặt kỹ thuật, từ loại dữ liệu truyền tải cho đến các chuẩn nén âm thanh","4:10","AYIV_g8vdE4","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776615165942-3c7804c1-9896-4663-b407-37bee19ffc8b.png","2026-04-19 16:13:45","2026-04-19 16:14:03",{"slug":478,"title":479,"description":480,"duration":481,"youtubeId":482,"order":254,"thumbnail":483,"createdAt":484,"updatedAt":485},"ice-candidate-stunturncoturn","Rust WebRTC P2P #21 - ICE Candidate — STUN\u002FTURN\u002FcoTURN","Trong phần 21 này, chúng ta tìm hiểu về ICE Candidate – thành phần giúp hai trình duyệt thực sự kết nối được với nhau trong môi trường thực tế. Nếu SDP là bản thỏa thuận, thì ICE Candidate chính là “tọa độ mạng” giúp các peer vượt qua NAT và firewall.","5:04","ZOPr-Lgx4b8","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776615904522-a5950a49-c4b8-4c63-bb87-aae1640829c2.png","2026-04-19 16:25:28","2026-04-20 17:54:08",{"slug":487,"title":488,"description":489,"duration":490,"youtubeId":491,"order":264,"thumbnail":492,"createdAt":493,"updatedAt":494},"chrome-webrtc-internals-firefox-aboutwebrtc","Rust WebRTC P2P #22 - Chrome webrtc-internals + Firefox about:webrtc","Trong phần 22 này, chúng ta sẽ tạm rời xa code để làm quen với những công cụ debug cực kỳ quan trọng giúp bạn kiểm tra và giám sát kết nối WebRTC trực tiếp trên trình duyệt. Đây là bước không thể thiếu để xác định Signaling Server hoạt động đúng hay chưa và liệu luồng media đã được thiết lập thành công hay chưa.","3:00","zbA6onXn-pg","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776708888639-1fe16a59-b013-4fa3-b4c4-178ca019a8d3.png","2026-04-20 18:16:15","2026-04-20 18:16:43",{"slug":496,"title":497,"description":498,"duration":499,"youtubeId":500,"order":41,"thumbnail":501,"createdAt":502,"updatedAt":503},"state-machine-co-che-transition","Rust WebRTC P2P #23 - State Machine + Cơ chế Transition","Trong phần 23 này, chúng ta bắt đầu hiện thực hóa kiến trúc đã thiết kế bằng cách xây dựng State Machine và cơ chế transition cho hệ thống signaling. Đây là một bước rất quan trọng để quản lý logic cuộc gọi một cách rõ ràng, chặt chẽ và an toàn.","6:50","RpXhBqmNk7c","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776783343994-ba548841-5db5-412a-bcda-203cd2b95f33.png","2026-04-21 14:56:29","2026-04-21 14:56:48",{"slug":505,"title":506,"description":507,"duration":508,"youtubeId":509,"order":510,"thumbnail":511,"createdAt":512,"updatedAt":513},"rust-webrtc-p2p-24-call-start-state","Rust WebRTC P2P #24 - Call Start State","Trong phần 24 này, chúng ta bắt đầu viết những dòng code đầu tiên cho nghiệp vụ cuộc gọi bằng cách xây dựng handler xử lý lệnh call_start_request. Đây là bước khởi đầu quan trọng để server xác thực yêu cầu và chuẩn bị tài nguyên trước khi hai bên bắt đầu trao đổi SDP.","15:53","KnKWZ4hFVxw",24,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776873563139-292333ff-26c2-465b-b01c-30ad11723f2f.png","2026-04-22 16:00:49","2026-04-22 16:00:58",{"slug":515,"title":516,"description":517,"duration":518,"youtubeId":519,"order":520,"thumbnail":521,"createdAt":522,"updatedAt":523},"p2pwaitingcallersdpstate-caller-sdp-waiting","Rust WebRTC P2P #25 - P2PWaitingCallerSdpState — Caller SDP Waiting","Trong phần 25 này, chúng ta bắt đầu implement trạng thái đầu tiên trong bộ máy điều khiển cuộc gọi: **P2PWaitingCallerSdpState**. Đây là trạng thái có nhiệm vụ chờ đợi bản tin SDP Offer từ phía Caller sau khi quá trình khởi tạo cuộc gọi đã hoàn tất.","17:23","JHxGt3pEvKI",25,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1776942152770-4e5939ef-fa3e-4ad0-8848-d954a77e0b9c.png","2026-04-23 11:03:26","2026-04-23 11:03:36",{"slug":525,"title":526,"description":527,"duration":528,"youtubeId":529,"order":530,"thumbnail":531,"createdAt":532,"updatedAt":533},"p2pconnecttocalleestate-incoming-call","Rust WebRTC P2P #26 - P2PConnectToCalleeState - Incoming Call","Trong phần 26 này, chúng ta sẽ xây dựng một trong những state phức tạp và thú vị nhất của Signaling Server: P2PConnectToCalleeState. Đây là giai đoạn server thực hiện kết nối tới người bị gọi, điều phối bản tin giữa các thiết bị và xử lý các phản hồi chấp nhận hoặc từ chối cuộc gọi.","16:33","4eFYIC6v9Co",26,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777051005241-955db861-41bf-40aa-a24c-f077fd7e486f.png","2026-04-24 17:17:58","2026-04-24 17:18:08",{"slug":535,"title":536,"description":537,"duration":538,"youtubeId":539,"order":540,"thumbnail":541,"createdAt":542,"updatedAt":543},"callanswerreq-codes-100180486","Rust WebRTC P2P #27 - call_answer_req — Codes 100\u002F180\u002F486","Trong phần 27 này, chúng ta tiếp tục hoàn thiện logic phía Server bằng cách xây dựng lệnh call_answer_req. Đây là bước quan trọng giúp người bị gọi (Callee) phản hồi lại yêu cầu từ người gọi, thông báo trạng thái đổ chuông, từ chối hoặc chấp nhận cuộc gọi theo các mã chuẩn trong signaling.","11:05","omS550Fc-OU",27,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777116711181-52bb555b-9093-4761-bd65-7f861a52368c.png","2026-04-25 11:32:50","2026-04-25 11:33:03",{"slug":545,"title":546,"description":547,"duration":548,"youtubeId":549,"order":550,"thumbnail":551,"createdAt":552,"updatedAt":553},"p2pwaitingcalleesdpstate-p2ptalkingstate","Rust WebRTC P2P #28 - P2PWaitingCalleeSDPState → P2PTalkingState","Trong phần 28 này, chúng ta sẽ thực hiện bước cuối cùng trong quy trình Signaling: Triển khai trạng thái P2PWaitingCalleeSDPState. Đây là giai đoạn quan trọng để Server điều phối bản tin SDP Answer từ người bị gọi (Callee) quay trở lại cho người gọi (Caller), đồng thời hoàn tất việc trao đổi các ICE Candidates để hai bên có thể thiết lập kết nối Media.","12:34","RwSCW7omH-c",28,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777204197874-fc3d7d15-eccf-4d21-857f-1c8f59c1f4cf.png","2026-04-26 11:51:11","2026-04-26 11:51:21",{"slug":555,"title":556,"description":557,"duration":558,"youtubeId":559,"order":560,"thumbnail":561,"createdAt":562,"updatedAt":563},"p2ptalkingstate-heartbeat-timeout","Rust WebRTC P2P #29 - P2PTalkingState — Heartbeat + Timeout","Trong phần 29 này, chúng ta sẽ tiến tới trạng thái quan trọng nhất trong vòng đời cuộc gọi: P2PTalkingState. Đây là giai đoạn hai người dùng đang đàm thoại trực tiếp với nhau. Tuy nhiên, vì đây là kết nối P2P (media không đi qua server), chúng ta cần một cơ chế để server biết cuộc gọi còn đang diễn ra hay đã bị ngắt kết nối một cách “im lặng”.","18:26","YXEw4XYJoXY",29,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777299316144-7266ad71-4734-48ff-80a9-3087540e7032.png","2026-04-27 14:15:53","2026-04-27 14:16:04",{"slug":565,"title":566,"description":567,"duration":568,"youtubeId":569,"order":570,"thumbnail":571,"createdAt":572,"updatedAt":573},"ice-candidate-forwarding-trong-talking-state-end-state","Rust WebRTC P2P #30 - ICE Candidate Forwarding trong Talking State - End State","Trong phần 30 này, chúng ta sẽ hoàn thiện mảnh ghép cuối cùng trong vòng đời cuộc gọi: EndState. Đây là trạng thái đảm nhiệm việc kết thúc cuộc gọi một cách an toàn, đảm bảo hệ thống không bị rò rỉ tài nguyên và tất cả các bên đều được thông báo chính xác khi cuộc gọi dừng lại.","17:20","CTJSx4ngEzA",30,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777373551460-992e255c-f65c-49e7-bf0b-3b822b79d2de.webp","2026-04-28 10:53:19","2026-04-28 10:53:29",{"slug":575,"title":576,"description":577,"duration":578,"youtubeId":579,"order":580,"thumbnail":581,"createdAt":582,"updatedAt":583},"test-end-to-end-2-real-browser","Rust WebRTC P2P #31 - Test End-to-End: 2 real browser","Trong phần 31 này, chúng ta sẽ thực hiện bước quan trọng nhất sau toàn bộ quá trình xây dựng hệ thống: Test End-to-End (E2E) với hai trình duyệt thật. Đây là bước kiểm chứng toàn bộ pipeline từ build, deploy cho đến thực hiện cuộc gọi P2P thực tế giữa hai user.","15:21","g2VUgdszcjo",31,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777428562735-ff26061b-ed2f-4a71-bc78-41b73584768d.jpg","2026-04-29 02:10:11","2026-04-29 02:27:06",{"slug":585,"title":586,"description":587,"duration":588,"youtubeId":589,"order":295,"thumbnail":590,"createdAt":591,"updatedAt":592},"tong-ket-va-ke-hoach-tiep-theo","Rust WebRTC P2P #32 - Tổng kết và kế hoạch tiếp theo","Sau một hành trình dài từ những dòng code đầu tiên, trong video này chúng ta sẽ cùng nhìn lại toàn bộ hệ thống đã xây dựng, tổng kết những gì đã đạt được, đồng thời phân tích các hạn chế của mô hình P2P và định hướng lộ trình học tập tiếp theo với các hệ thống Media Server chuyên nghiệp.","3:44","ilktCRe9p_c","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1777434502681-16641947-5848-496e-a05a-f4569f9bc595.jpg","2026-04-29 03:51:03","2026-04-30 02:06:10",{"slug":594,"title":595,"shortDescription":596,"description":597,"category":9,"level":10,"totalDuration":282,"totalLessons":12,"tags":598,"createdAt":599,"updatedAt":600,"rating":12,"reviewCount":12,"thumbnail":601,"instructor":602,"lessons":603},"rust-voip-asterisk-media-server","Rust VoIP: Asterisk Media Server","Làm chủ công nghệ VoIP với khóa học \"Lập trình VoIP với Rust: Asterisk Media Server\". Vượt qua những giới hạn của WebRTC P2P để xây dựng hệ thống tổng đài và media server chuyên nghiệp. Khám phá sức mạnh của Asterisk kết hợp cùng Rust để xử lý các bài toán quy mô lớn, từ gọi App-to-App đến tích hợp hệ thống SIP và Auto Callout mạnh mẽ.","Từ WebRTC P2P đến Hệ thống Media Server thực thụ\nNếu bạn đã hiểu cách kết nối trực tiếp giữa các trình duyệt qua WebRTC P2P, bạn sẽ nhận ra rằng mô hình đó chỉ là bước khởi đầu\n. Để xây dựng những ứng dụng Voice IP có thể scale lớn và dùng trong sản xuất (production), chúng ta cần một giải pháp mạnh mẽ hơn để giải quyết 4 vấn đề cốt lõi của P2P:\n\n- Khả năng mở rộng không giới hạn: Thay vì để 10 người tạo ra 90 kết nối chéo gây nghẽn mạng\n, chúng ta sẽ tập trung mọi luồng media về một điểm duy nhất.\n- Tối ưu tài nguyên thiết bị: Giảm tải tối đa CPU và pin cho người dùng mobile bằng cách không bắt thiết bị phải upload nhiều luồng media cùng lúc\n- Ghi âm tập trung (Centralized Recording): Dễ dàng lưu trữ và quản lý mọi cuộc gọi ngay tại server, điều mà mô hình P2P gần như không thể thực hiện\n- Vượt qua rào cản NAT: Xử lý triệt để vấn đề NAT nghiêm ngặt (NAT strict) vốn chiếm tới 15% người dùng, giúp kết nối luôn thông suốt mà không làm tăng chi phí relay phức tạp.\n\nTại sao lại là Asterisk và Rust?\nTrong khóa học này, chúng ta sẽ sử dụng Asterisk — một tượng đài trong thế giới VoIP — làm Media Server trung gian. Thay vì để các peer kết nối trực tiếp, tất cả client sẽ gửi dữ liệu lên Asterisk để server xử lý và phân phối lại.\n\nViệc kết hợp với ngôn ngữ Rust mang lại hiệu suất tối ưu và tính an toàn cao khi xây dựng các logic điều khiển cuộc gọi. Asterisk đóng vai trò là \"trái tim\" xử lý WebRTC, signaling và networking, giúp hệ thống dễ dàng scale lên hàng trăm, thậm chí hàng nghìn người dùng\n\nNội dung thực hành trọng tâm\nKhóa học sẽ dẫn dắt bạn đi từ những bước cơ bản nhất đến khi hoàn thiện một hệ thống Voice IP thực tế với đầy đủ các tính năng\n\n1. Call App to App: Lập trình cuộc gọi giữa hai ứng dụng WebRTC thông qua Asterisk.\n2. Call App to SIP: Kết nối thế giới Web\u002FApp với hệ thống tổng đài SIP truyền thống.\n3. Call SIP to App: Nhận cuộc gọi ngược lại từ các đầu số SIP về trình duyệt hoặc ứng dụng di động.\n4. Auto Callout: Xây dựng hệ thống tự động gọi ra chuyên nghiệp phục vụ cho thông báo hoặc CSKH.\n\nKết quả đạt được\nToàn bộ khóa học được thiết kế để bạn có thể tự mình xây dựng, vận hành và triển khai một hệ thống VoIP thực tế\n. Đây không chỉ là lý thuyết, mà là những kỹ năng thực chiến để bạn làm chủ công nghệ truyền thông thời gian thực.","[\"asterisk\",\"rust\",\"b2bua\",\"kamailio\"]","2026-04-09 10:01:22","2026-04-09 14:19:52","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775728872332-8cae7a0a-719d-4c6f-bf67-8829e2a9cf42.png",{"name":19,"title":20,"bio":21},[],{"slug":290,"title":291,"shortDescription":292,"description":293,"category":9,"level":28,"totalDuration":294,"totalLessons":295,"tags":296,"createdAt":297,"updatedAt":298,"rating":299,"reviewCount":300,"thumbnail":301,"instructor":605,"lessons":606},{"name":19,"title":20,"bio":21},[607,630,647,664,681,698,705,710,727,743,762,780,794,804,821,828,837,843,849,855,861,867,873,879,887,893,901,907,913,919,925,931],{"slug":305,"title":306,"description":307,"duration":308,"youtubeId":309,"order":55,"thumbnail":310,"createdAt":297,"updatedAt":311,"sections":608},[609,612,615,618,621,624,627],{"title":610,"content":611},"Giới thiệu khóa học","Chào mừng bạn đến với khóa học Lập trình Rust với VoIP - Phần 1: WebRTC Peer-to-Peer.\n\nĐây là series thực chiến giúp bạn xây dựng từ đầu một Signaling Server → Xử lý các cuộc gọi audio\u002Fvideo trực tiếp giữa hai trình duyệt → Không cần thông qua Media Server.",{"title":613,"content":614},"Nội dung chính trong video","• Mục tiêu khóa học: Xây dựng hoàn chỉnh một Signaling Server bằng Rust → Thiết lập kết nối P2P giữa hai trình duyệt.\n\n• Kiến trúc hệ thống: Browser A gửi SDP Offer qua Rust Server → chuyển tiếp đến Browser B. Trao đổi ICE Candidates để tìm đường kết nối tối ưu.\n\n• Media Exchange (RTP): Dữ liệu audio\u002Fvideo truyền trực tiếp giữa 2 browser. Rust Server không can thiệp vào luồng media.",{"title":616,"content":617},"Kiến trúc tổng thể","\u003Cp>Browser A ↔ Rust Server (WebSocket) ↔ Browser B Browser A ⇄ P2P Media ⇄ Browser B Lưu ý: Media không đi qua server → Chỉ signaling đi qua Rust backend.\u003C\u002Fp>\u003Cfigure class=\"image-figure\" style=\"margin: 32px 0px; text-align: center; display: flex; flex-direction: column; align-items: center;\">\u003Cimg src=\"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1775885347095-841c25ac-be6b-43bc-8995-61a6a9ea4b65.png\" alt=\"\" style=\"max-width: 100%; height: auto; border-radius: 6px;\">\u003Cfigcaption style=\"margin-top: 12px; font-size: 14px; color: rgb(96, 98, 102); font-style: italic; text-align: center; max-width: 80%;\">Mô hình Peer to Peer\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cp>\u003C\u002Fp>",{"title":619,"content":620},"Tech stack sử dụng","• Rust\n• Axum + Tokio (backend)\n• WebSocket\n• MongoDB\n• JWT Authentication",{"title":622,"content":623},"Lộ trình series (7 phần)","• Phần 1 (hiện tại): WebRTC Peer-to-Peer\n• Phần 2 - 6: Làm việc với Media Server — Janus, LiveKit, Kurento, Asterisk, FreePBX\n• Phần 7: CRM, Queue, nhạc chờ, chuyển tiếp cuộc gọi",{"title":625,"content":626},"Kết quả sau khóa học","Bạn sẽ có một signaling server hoàn chỉnh, cho phép 2 browser thực hiện audio\u002Fvideo call P2P thực tế.",{"title":628,"content":629},"Yêu cầu tiên quyết","Bạn nên có kiến thức cơ bản về Rust:\n• Ownership\n• Lifetimes\n• Traits\n• Async\u002FAwait",{"slug":313,"title":314,"description":315,"duration":316,"youtubeId":317,"order":65,"thumbnail":318,"createdAt":297,"updatedAt":319,"sections":631},[632,635,638,641,644],{"title":633,"content":634},"VoIP là gì?","VoIP (Voice over Internet Protocol) là công nghệ truyền thoại và video qua mạng IP thay vì mạng điện thoại truyền thống (PSTN).\n\n• Ứng dụng phổ biến: Skype, Zoom, Google Meet, Discord, WhatsApp Call\n• Ưu điểm: Chi phí thấp, tích hợp dễ dàng vào ứng dụng web\u002Fmobile, hỗ trợ cả audio và video\n• Giao thức nền tảng: RTP (Real-time Transport Protocol) để truyền media, SIP hoặc WebRTC để signaling",{"title":636,"content":637},"WebRTC là gì?","WebRTC (Web Real-Time Communication) là bộ tiêu chuẩn mở cho phép trình duyệt giao tiếp trực tiếp peer-to-peer mà không cần plugin.\n\n• Được hỗ trợ native trên Chrome, Firefox, Safari, Edge\n• Ba thành phần chính: MediaStream (truy cập camera\u002Fmic), RTCPeerConnection (kết nối P2P), RTCDataChannel (truyền dữ liệu)\n• Media đi thẳng giữa hai browser — server chỉ làm nhiệm vụ signaling duy nhất",{"title":639,"content":640},"So sánh VoIP truyền thống vs WebRTC","• VoIP truyền thống: Cần cài phần mềm client, sử dụng SIP để signaling, thường cần Media Server trung gian\n• WebRTC: Chạy trực tiếp trên trình duyệt, signaling linh hoạt (WebSocket, HTTP), P2P trực tiếp giữa các peer\n\n→ WebRTC phù hợp hơn cho ứng dụng web hiện đại vì không yêu cầu cài đặt thêm và tận dụng được hạ tầng trình duyệt.",{"title":642,"content":643},"Luồng hoạt động của WebRTC","1. Browser A tạo SDP Offer (mô tả khả năng media: codec, resolution...)\n2. Gửi Offer qua Signaling Server đến Browser B\n3. Browser B tạo SDP Answer và gửi ngược lại\n4. Cả hai trao đổi ICE Candidates để tìm đường kết nối tối ưu (STUN\u002FTURN)\n5. Kết nối P2P được thiết lập → Media truyền trực tiếp",{"title":645,"content":646},"Vai trò của Signaling Server","Signaling Server là \"người mai mối\" — giúp hai browser tìm thấy nhau và thỏa thuận kết nối.\n\n• Chuyển tiếp SDP Offer\u002FAnswer giữa các peer\n• Chuyển tiếp ICE Candidates\n• Quản lý trạng thái phòng\u002Fcuộc gọi\n• Không xử lý media — chỉ xử lý metadata\n\n→ Đây chính là thứ chúng ta sẽ xây dựng bằng Rust trong khóa học này.",{"slug":321,"title":322,"description":323,"duration":324,"youtubeId":325,"order":75,"thumbnail":326,"createdAt":297,"updatedAt":327,"sections":648},[649,652,655,658,661],{"title":650,"content":651},"SIP Overview","SIP (Session Initiation Protocol) là giao thức signaling truyền thống trong hệ thống telephony.\n\n• Được dùng rộng rãi trong VoIP enterprise: tổng đài, call center, IP PBX\n• Hoạt động theo mô hình request\u002Fresponse tương tự HTTP\n• Các method chính: INVITE (mời gọi), ACK (xác nhận), BYE (kết thúc), REGISTER (đăng ký)\n• Nhược điểm: Phức tạp, nhiều header, khó triển khai trên web browser",{"title":653,"content":654},"SIP vs WebRTC Signaling","• SIP: Giao thức chuẩn hóa, cứng nhắc, phù hợp hệ thống telephony truyền thống\n• WebRTC Signaling: Không quy định giao thức cụ thể — bạn tự chọn (WebSocket, HTTP, MQTT...)\n\n→ WebRTC linh hoạt hơn, nhẹ hơn, và phù hợp với ứng dụng web hiện đại. SIP vẫn quan trọng khi cần tích hợp với hạ tầng telephony có sẵn.",{"title":656,"content":657},"Tại sao chọn Rust?","4 lý do chọn Rust để xây dựng Signaling Server:\n\n1. Hiệu năng cao: Không có Garbage Collector → Không bị GC pause, latency ổn định — yếu tố sống còn cho real-time communication.\n\n2. Memory Safety: Ownership system ngăn data race từ compile time. Sử dụng Arc, DashMap, mpsc channel an toàn khi xử lý hàng nghìn kết nối đồng thời.\n\n3. Async mạnh mẽ: Tokio runtime với thread pool xử lý hàng nghìn WebSocket connection hiệu quả mà không cần tạo thread cho mỗi connection.\n\n4. Error Handling bắt buộc: Result\u003CT, E> buộc dev phải xử lý mọi trường hợp lỗi — giảm thiểu crash trong production khi server chịu hơn 100K cuộc gọi\u002Fngày.",{"title":659,"content":660},"So sánh Rust với các ngôn ngữ khác","• Node.js: Dễ viết, ecosystem lớn, nhưng single-threaded và GC pause có thể gây jitter trong audio\n• Go: Concurrency tốt với goroutine, nhưng GC vẫn là vấn đề với latency nhạy cảm\n• C\u002FC++: Hiệu năng cao nhưng dễ gặp memory leak, buffer overflow, data race\n• Rust: Kết hợp hiệu năng của C\u002FC++ với safety của ngôn ngữ bậc cao → Lựa chọn tối ưu cho VoIP server",{"title":662,"content":663},"Khi nào nên dùng Rust cho VoIP?","• Hệ thống yêu cầu latency thấp và ổn định (\u003C 150ms cho audio call)\n• Server cần xử lý lượng lớn concurrent connections (10K+ WebSocket)\n• Môi trường production cần độ tin cậy cao, ít crash\n• Team sẵn sàng đầu tư learning curve để đổi lấy hiệu năng và safety dài hạn",{"slug":329,"title":330,"description":331,"duration":332,"youtubeId":333,"order":15,"thumbnail":334,"createdAt":297,"updatedAt":335,"sections":665},[666,669,672,675,678],{"title":667,"content":668},"Cài đặt Rust Toolchain","Cài đặt Rust thông qua rustup — công cụ quản lý phiên bản chính thức:\n\n• Truy cập rustup.rs và chạy lệnh cài đặt cho hệ điều hành của bạn\n• Windows: Tải rustup-init.exe, cần cài Visual Studio Build Tools trước\n• macOS\u002FLinux: curl --proto '=https' --tlsv1.2 -sSf https:\u002F\u002Fsh.rustup.rs | sh\n\nXác thực cài đặt thành công:\n• rustc --version → Kiểm tra compiler\n• cargo --version → Kiểm tra package manager\n• rustup --version → Kiểm tra toolchain manager",{"title":670,"content":671},"RustRover — IDE chuyên biệt cho Rust","RustRover là IDE của JetBrains được thiết kế riêng cho Rust:\n\n• Code completion thông minh, hiểu sâu type system của Rust\n• Inline error highlighting — phát hiện lỗi trước khi compile\n• Debugger tích hợp với breakpoint, watch variables\n• Refactoring tools: rename, extract function, inline variable\n• Tích hợp Cargo commands trực tiếp từ IDE\n\nSo với VS Code + rust-analyzer: RustRover mượt hơn với project lớn, ít cần cấu hình thủ công.",{"title":673,"content":674},"4 lệnh Cargo thiết yếu","Cargo là build system và package manager của Rust:\n\n1. cargo new project_name → Tạo project Rust mới với cấu trúc chuẩn (src\u002Fmain.rs, Cargo.toml)\n2. cargo build → Compile project ở chế độ debug (nhanh compile, chậm runtime)\n3. cargo build --release → Compile với tối ưu hóa cho production (chậm compile, nhanh runtime)\n4. cargo run → Build và chạy project trong một lệnh duy nhất",{"title":676,"content":677},"Cấu trúc project Rust","Sau khi chạy cargo new, bạn sẽ có:\n\nproject_name\u002F\n├── Cargo.toml    → File cấu hình project (tên, version, dependencies)\n├── Cargo.lock    → Lock file cho dependencies (tự sinh)\n└── src\u002F\n    └── main.rs   → Entry point của ứng dụng\n\n• Cargo.toml tương tự package.json (Node.js) hoặc go.mod (Go)\n• src\u002F chứa toàn bộ source code\n• target\u002F (tự sinh sau build) chứa compiled output",{"title":679,"content":680},"Các lệnh Cargo bổ sung","• cargo check → Kiểm tra lỗi compile mà không tạo binary (nhanh hơn cargo build)\n• cargo test → Chạy unit test và integration test\n• cargo doc --open → Sinh documentation và mở trên browser\n• cargo add \u003Ccrate_name> → Thêm dependency vào Cargo.toml\n• cargo update → Cập nhật dependencies lên phiên bản mới nhất",{"slug":337,"title":338,"description":339,"duration":340,"youtubeId":341,"order":94,"thumbnail":342,"createdAt":297,"updatedAt":343,"sections":682},[683,686,689,692,695],{"title":684,"content":685},"Cargo.toml — Trái tim quản lý dependencies","Cargo.toml là file cấu hình trung tâm của mọi dự án Rust:\n\n• [package]: Tên project, version, edition (2021)\n• [dependencies]: Danh sách thư viện bên ngoài (crates)\n• Mỗi dependency có thể chỉ định version, features cụ thể\n\nVí dụ: tokio = { version = \"1\", features = [\"full\"] } → Sử dụng Tokio với tất cả features bao gồm runtime, io, net, sync, time.",{"title":687,"content":688},"Dependencies sử dụng trong khóa học","Các thư viện sẽ dùng xuyên suốt khóa học:\n\n• Axum — Web framework nhẹ, hiệu năng cao, built on top of Tokio\n• Tokio — Async runtime cho Rust, hỗ trợ multi-threaded task scheduling\n• Serde + serde_json — Serialization\u002FDeserialization (JSON ↔ Rust struct)\n• DashMap — Concurrent HashMap, thread-safe mà không cần Mutex\n• UUID — Sinh unique identifier cho mỗi user\u002Fsession\n• Log4rs — Logging framework linh hoạt với multiple appenders\n• Anyhow — Simplified error handling cho application code",{"title":690,"content":691},"Tokio Runtime là gì?","Tokio là async runtime phổ biến nhất của Rust:\n\n• Biến hàm main thành async với macro #[tokio::main]\n• Multi-threaded runtime: Tận dụng tất cả CPU cores\n• Task scheduling: Hàng nghìn async task chạy đồng thời trên thread pool nhỏ\n• Không tạo OS thread cho mỗi connection → Tiết kiệm memory, xử lý 10K+ connections dễ dàng\n\nSo sánh: Node.js chạy single-threaded event loop, Tokio chạy multi-threaded event loop.",{"title":693,"content":694},"Hello World với Tokio","Chuyển từ synchronous main sang async main:\n\n• Thêm #[tokio::main] macro trước fn main()\n• Hàm main trở thành async fn main() → Có thể dùng .await\n• Tokio tự động tạo thread pool và scheduler\n• Mọi I\u002FO operation (network, file) đều non-blocking\n\nKết quả: Chạy thành công project Hello World đầu tiên với Tokio runtime — nền tảng cho toàn bộ signaling server.",{"title":696,"content":697},"Bước tiếp theo","Sau bài này, bạn đã có:\n• Project Rust với đầy đủ dependencies\n• Tokio runtime sẵn sàng xử lý async operations\n• Hiểu vai trò của từng thư viện trong hệ thống\n\n→ Bài tiếp theo sẽ bắt đầu xây dựng HTTP server với Axum và thiết lập WebSocket endpoint cho signaling.",{"slug":345,"title":346,"description":347,"duration":348,"youtubeId":349,"order":104,"thumbnail":350,"createdAt":351,"updatedAt":351,"sections":699},[700,702],{"title":701,"content":347},"1. Giới thiệu",{"title":703,"content":704},"2. Nội dung trọng tâm","(1) Thiết lập hệ thống cấu hình (Config Loading)\n\n- Tạo thư mục config và file config.yaml\n- Quản lý các thông số:\n  + host_name\n  + port (4004)\n  + jwt_key\n  + thời gian hết hạn token\n\n- Sử dụng Serde YAML:\n  → Chuyển dữ liệu từ file YAML sang Struct Rust\n\n- Sử dụng once_cell:\n  → Khởi tạo Global Config an toàn\n  → Truy cập config từ mọi nơi trong ứng dụng\n\n--------------------------------------------------\n\n(2) Quản lý AppState\n\n- Định nghĩa AppState:\n  → Lưu trữ và chia sẻ cấu hình toàn hệ thống\n\n- Sử dụng Arc (Atomically Reference Counted):\n  → Clone và truyền AppState vào các routes\n  → Đảm bảo hiệu năng và an toàn\n\n--------------------------------------------------\n\n(3) Khởi tạo Axum HTTP Server\n\n- Sử dụng Tokio TcpListener:\n  → Lắng nghe kết nối tại port đã cấu hình\n\n- Thiết lập router cơ bản\n- Chạy thử HTTP server đầu tiên với Axum\n\n--------------------------------------------------\n\n(4) Tổ chức mã nguồn (Refactoring)\n\n- Tách router ra file riêng: router.rs\n- Tạo thư mục controller:\n  + Ví dụ: auth_controller.rs\n\n→ Chuẩn bị cho các tính năng:\n- Login\n- Authentication",{"slug":353,"title":354,"description":355,"duration":356,"youtubeId":357,"order":114,"thumbnail":358,"createdAt":359,"updatedAt":360,"sections":706},[707,708],{"title":701,"content":355},{"title":703,"content":709},"(1) Cấu hình MongoDB\n\n- Bổ sung thông tin vào config.yaml:\n  + host\n  + username\n  + password\n  + database name\n\n- Định nghĩa Struct trong Rust:\n  → Ánh xạ chính xác với cấu hình YAML\n\n- Khởi tạo Global MongoDB Client:\n  → Sử dụng tokio::sync::OnceCell\n  → Client tồn tại xuyên suốt vòng đời ứng dụng\n  → Có thể truy cập từ mọi nơi\n\n- Kiểm tra kết nối:\n  → Gửi lệnh ping đến database\n  → Xác nhận kết nối thành công\n\n--------------------------------------------------\n\n(2) Thiết lập Logging với log4rs\n\n- Thay thế println! bằng hệ thống log chuyên nghiệp\n→ Giúp debug và theo dõi hệ thống hiệu quả hơn\n\n- Cấu hình 2 đầu ra chính:\n\nConsole:\n- Hiển thị log trên terminal\n- Format chi tiết:\n  + thời gian\n  + thread\n  + level\n  + file\u002Fline\n\nFile:\n- Ghi log vào file\n- Quan trọng trong môi trường production\n→ Khi không có console để theo dõi\n\n- Xử lý lỗi thiếu thư viện nén log (gzip)\n→ Đảm bảo hệ thống hoạt động ổn định\n\n--------------------------------------------------\n\n3. Kết quả đạt được\n\nSau bài học này, bạn sẽ có:\n\n- Kết nối MongoDB hoàn chỉnh\n- Hệ thống logging chuyên nghiệp\n- Nền tảng backend sẵn sàng cho production\n- Sẵn sàng xử lý logic phức tạp ở các phần tiếp theo",{"slug":362,"title":363,"description":364,"duration":365,"youtubeId":366,"order":124,"thumbnail":367,"createdAt":368,"updatedAt":369,"sections":711},[712,715,718,721,724],{"title":713,"content":714},"Cơ chế WebSocket","\u003Cp>- Quy trình handshake:\u003Cbr> Client gửi HTTP request\u003Cbr> Server trả về 101 Switching Protocols\u003Cbr> → Nâng cấp lên WebSocket connection\u003Cbr>\u003Cbr>- Dọn dẹp warning trong project\u003Cbr>→ Giữ code sạch trước khi triển khai\u003C\u002Fp>",{"title":716,"content":717},"Triển khai WebSocket với Axum","\u003Cp>- Tạo module websocket và \u003Ca target=\"_blank\" href=\"http:\u002F\u002Fhandler.rs\">handler.rs\u003C\u002Fa>\u003Cbr>- Sử dụng:\u003Cbr> + WebSocketUpgrade\u003Cbr> + Headers\u003Cbr>\u003Cbr>- Truyền AppState và ConnectInfo:\u003Cbr> → Quản lý state chung\u003Cbr> → Lấy IP user (remote address)\u003C\u002Fp>",{"title":719,"content":720},"Xử lý Socket","\u003Cp>- Tách socket thành:\u003Cbr> + Read\u003Cbr> + Write\u003Cbr>\u003Cbr>- Sử dụng async loop:\u003Cbr> → Lắng nghe message liên tục\u003Cbr> → Không ngắt kết nối\u003C\u002Fp>",{"title":722,"content":723},"Test thực tế","\u003Cp>- Dùng Postman test WebSocket\u003Cbr>- Gửi message:\u003Cbr> + \"ABC\"\u003Cbr> + \"Hello\"\u003Cbr>\u003Cbr>→ Kiểm tra log server nhận dữ liệu\u003C\u002Fp>",{"title":725,"content":726},"Kết quả đạt được:","\u003Cp>- Xây dựng thành công WebSocket Server\u003Cbr>- Duy trì kết nối realtime ổn định\u003Cbr>- Nền tảng cho:\u003Cbr> + SDP Exchange\u003Cbr> + ICE Candidates\u003C\u002Fp>",{"slug":371,"title":372,"description":373,"duration":374,"youtubeId":375,"order":134,"thumbnail":376,"createdAt":377,"updatedAt":377,"sections":728},[729,732,735,738,741],{"title":730,"content":731},"Cấu trúc dữ liệu cho Client","\u003Cp>- Định nghĩa struct ClientInfo:\u003C\u002Fp>\u003Cp>  + user_id\u003C\u002Fp>\u003Cp>  + client_id (duy nhất cho mỗi kết nối)\u003C\u002Fp>\u003Cp>  + device_id\u003C\u002Fp>\u003Cp>- Sử dụng Unbounded Sender:\u003C\u002Fp>\u003Cp>  → Gửi message xuống client theo kiểu async\u003C\u002Fp>",{"title":733,"content":734},"Quản lý kết nối với ConnectionState","\u003Cp>- Client Map:\u003C\u002Fp>\u003Cp>  → Mapping client_id → ClientInfo\u003C\u002Fp>\u003Cp>- User Map:\u003C\u002Fp>\u003Cp>  → Mapping user_id → danh sách client_id\u003C\u002Fp>\u003Cp>→ Cho phép:\u003C\u002Fp>\u003Cp>- Một user đăng nhập nhiều thiết bị\u003C\u002Fp>\u003Cp>- Quản lý nhiều kết nối song song\u003C\u002Fp>",{"title":736,"content":737},"Các logic xử lý chính","\u003Cp>- add_client:\u003C\u002Fp>\u003Cp>  → Thêm client khi có kết nối mới\u003C\u002Fp>\u003Cp>- remove_client:\u003C\u002Fp>\u003Cp>  → Xóa client khi disconnect\u003C\u002Fp>\u003Cp>  → Tự động cleanup nếu user không còn connection\u003C\u002Fp>\u003Cp>- send_to_user:\u003C\u002Fp>\u003Cp>  → Gửi message đến tất cả connection của user\u003C\u002Fp>",{"title":739,"content":740},"Tối ưu hiệu năng","\u003Cp>- Sử dụng Arc&lt;String&gt; thay vì clone String\u003C\u002Fp>\u003Cp>→ Giảm chi phí bộ nhớ khi broadcast message\u003C\u002Fp>\u003Cp>→ Tối ưu khi một user có nhiều connection\u003C\u002Fp>",{"title":725,"content":742},"\u003Cp>- Server có khả năng quản lý danh sách user online\u003C\u002Fp>\u003Cp>- Mapping chính xác giữa user và connection\u003C\u002Fp>\u003Cp>- Nền tảng cho:\u003C\u002Fp>\u003Cp>  + Gọi P2P đúng người\u003C\u002Fp>\u003Cp>  + Routing signaling message\u003C\u002Fp>",{"slug":379,"title":380,"description":381,"duration":382,"youtubeId":383,"order":144,"thumbnail":384,"createdAt":385,"updatedAt":386,"sections":744},[745,748,751,754,757,760],{"title":746,"content":747},"Trong phần 10 này:","\u003Cp>Chúng ta chuẩn hóa cách trao đổi dữ liệu giữa Client và Server\u003C\u002Fp>\u003Cp>→ Xây dựng Message Routing\u003C\u002Fp>\u003Cp>→ Áp dụng Dispatcher Pattern\u003C\u002Fp>",{"title":749,"content":750},"Định nghĩa giao thức bản tin","\u003Cp>- Sử dụng JSON thay cho text tự do\u003C\u002Fp>\u003Cp>→ Dễ mở rộng và chuẩn hóa\u003C\u002Fp>\u003Cp>- Cấu trúc message:\u003C\u002Fp>\u003Cp>  + cmd: mã lệnh (auth, send_sdp_request...)\u003C\u002Fp>\u003Cp>  + param: dữ liệu đi kèm (username, SDP...)\u003C\u002Fp>",{"title":752,"content":753},"Xử lý JSON với Serde","\u003Cp>- Sử dụng serde_json để parse dữ liệu từ WebSocket\u003C\u002Fp>\u003Cp>- Trích xuất cmd và param an toàn\u003C\u002Fp>\u003Cp>→ Tránh crash khi dữ liệu không hợp lệ\u003C\u002Fp>",{"title":755,"content":756},"Dispatcher Pattern","\u003Cp>- Mapping cmd → handler function\u003C\u002Fp>\u003Cp>→ Mỗi lệnh có 1 hàm xử lý riêng\u003C\u002Fp>\u003Cp>- Tổ chức code:\u003C\u002Fp>\u003Cp>  + Dễ mở rộng\u003C\u002Fp>\u003Cp>  + Dễ maintain\u003C\u002Fp>",{"title":758,"content":759},"Xử lý lỗi & bảo mật","\u003Cp>- Tránh panic khi nhận dữ liệu sai format\u003C\u002Fp>\u003Cp>- Loại bỏ unwrap() trong production\u003C\u002Fp>\u003Cp>→ Đảm bảo hệ thống ổn định\u003C\u002Fp>",{"title":725,"content":761},"\u003Cp>- Xây dựng \"ngôn ngữ chung\" giữa client và server\u003C\u002Fp>\u003Cp>- Chuẩn hóa message protocol\u003C\u002Fp>\u003Cp>- Sẵn sàng mở rộng:\u003C\u002Fp>\u003Cp>  + Gọi WebRTC\u003C\u002Fp>\u003Cp>  + Nhắn tin realtime\u003C\u002Fp>\u003Cp>  + Trao đổi dữ liệu\u003C\u002Fp>",{"slug":388,"title":389,"description":390,"duration":391,"youtubeId":392,"order":154,"thumbnail":393,"createdAt":394,"updatedAt":395,"sections":763},[764,767,770,773,776,778],{"title":765,"content":766},"Cấu hình Domain","\u003Cp>- Trỏ subdomain về IP VPS\u003C\u002Fp>\u003Cp>→ Sử dụng DNS A record\u003C\u002Fp>\u003Cp>- Ví dụ:\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"http:\u002F\u002Ftest.bytebuffer.com\">test.bytebuffer.com\u003C\u002Fa> → IP server\u003C\u002Fp>",{"title":768,"content":769},"Cài đặt Nginx","\u003Cp>- Cài đặt trên Linux (Debian \u002F CentOS)\u003C\u002Fp>\u003Cp>- Kiểm tra hoạt động:\u003C\u002Fp>\u003Cp>  + Port 80 (HTTP)\u003C\u002Fp>\u003Cp>  + Port 443 (HTTPS)\u003C\u002Fp>",{"title":771,"content":772},"Deploy ứng dụng Rust","\u003Cp>- Cài đặt Rust trên VPS\u003C\u002Fp>\u003Cp>- Build ứng dụng\u003C\u002Fp>\u003Cp>- Upload:\u003C\u002Fp>\u003Cp>  + File executable\u003C\u002Fp>\u003Cp>  + Thư mục config\u003C\u002Fp>\u003Cp>→ Sử dụng SFTP\u003C\u002Fp>\u003Cp>- Chạy server:\u003C\u002Fp>\u003Cp>  + Ví dụ port 1006\u003C\u002Fp>\u003Cp>  + Thiết lập biến môi trường\u003C\u002Fp>",{"title":774,"content":775},"Nginx Reverse Proxy & SSL","\u003Cp>- Tạo SSL với Cloudflare Origin Server\u003C\u002Fp>\u003Cp>- Cấu hình Nginx:\u003C\u002Fp>\u003Cp>  + Redirect HTTP → HTTPS\u003C\u002Fp>\u003Cp>  + Reverse proxy về port 1006\u003C\u002Fp>\u003Cp>- Quan trọng:\u003C\u002Fp>\u003Cp>  + Cấu hình header để hỗ trợ WebSocket\u003C\u002Fp>\u003Cp>  → Upgrade connection\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cpre>\u003Ccode>server\n{\n        listen 80;\n        server_name test-p2p.bytebuffer.co;\n        return 301 https:\u002F\u002F$host$request_uri;\n}\n\nserver\n{\n\n        client_max_body_size 20M;\n        listen 443 ssl;\n        ssl_certificate \u002Froot\u002Fssl\u002Fbytebuffer.co\u002Fcertificate.pem;\n        ssl_certificate_key \u002Froot\u002Fssl\u002Fbytebuffer.co\u002Fprivate-key.pem;\n        server_name test-p2p.bytebuffer.co;\n\n        root \u002Fusr\u002Fshare\u002Fnginx\u002Fbytebuffer-p2p;\n        index index.php index.html index.htm;\n\n        location = \u002Fcall\n        {\n                proxy_pass http:\u002F\u002F127.0.0.1:10006\u002Fcall;\n                proxy_http_version 1.1;\n                proxy_set_header Upgrade $http_upgrade;\n                proxy_set_header Connection \"upgrade\";\n                proxy_set_header Host $host;\n                proxy_read_timeout 300s;\n        }\n\n        location \u002F\n        {\n                proxy_pass http:\u002F\u002F127.0.0.1:10006\u002F;\n                proxy_http_version 1.1;\n                proxy_set_header Upgrade $http_upgrade;\n                proxy_set_header Connection 'upgrade';\n                proxy_set_header Host $host;\n                proxy_cache_bypass $http_upgrade;\n\n                proxy_request_buffering off;\n                proxy_read_timeout 300s;\n                proxy_connect_timeout 300s;\n                proxy_send_timeout 300s;\n\n                proxy_set_header X-Real-IP $remote_addr;\n                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n                proxy_set_header X-Forwarded-Proto $scheme;\n        }\n\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003C\u002Fp>",{"title":722,"content":777},"\u003Cp>- Test login qua domain thật\u003C\u002Fp>\u003Cp>→ Kiểm tra response và log\u003C\u002Fp>\u003Cp>- Test WebSocket:\u003C\u002Fp>\u003Cp>  → Kết nối qua domain\u003C\u002Fp>\u003Cp>  → Kiểm tra cookie authentication\u003C\u002Fp>",{"title":725,"content":779},"\u003Cp>- Deploy thành công ứng dụng Rust lên VPS\u003C\u002Fp>\u003Cp>- Cấu hình domain + HTTPS hoàn chỉnh\u003C\u002Fp>\u003Cp>- Thiết lập reverse proxy cho WebSocket\u003C\u002Fp>\u003Cp>- Sẵn sàng chạy production cho WebRTC\u003C\u002Fp>",{"slug":397,"title":398,"description":399,"duration":400,"youtubeId":401,"order":164,"thumbnail":402,"createdAt":403,"updatedAt":404,"sections":781},[782,785,788,791],{"title":783,"content":784},"Nội dung chính:","\u003Cp>Định nghĩa User Model: Xây dựng struct User và UserStatus trong Rust, mapping trực tiếp với document trong MongoDB.\u003Cbr>Thiết kế dữ liệu: Bao gồm các field như ID, Username, Email, Password, Phone number... để quản lý user một cách rõ ràng.\u003Cbr>Xây dựng User Repository: Triển khai các hàm truy vấn dữ liệu như get_user_by_id, get_all_users và search_user_by_keyword.\u003C\u002Fp>",{"title":786,"content":787},"Cấu trúc dữ liệu","\u003Cpre>\u003Ccode>#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]\npub enum UserStatus {\n    Pending,\n    Active,\n    Inactive,\n    Locked,\n    Suspended,\n    Deleted,\n}\n\n#[derive(Serialize, Deserialize, Clone, Debug)]\npub struct User {\n    pub id: String,\n    pub network: String,\n    pub username: String,\n    pub email: String,\n    pub password: String,\n    pub first_name: String,\n    pub last_name: String,\n    pub phone_number: Option&lt;String&gt;,\n    pub language_code: Option&lt;String&gt;,\n    pub time_zone: Option&lt;String&gt;,\n    pub date_format: Option&lt;u8&gt;,\n    pub time_format: Option&lt;u8&gt;,\n    pub number_format: Option&lt;u8&gt;,\n    pub photo_url: Option&lt;String&gt;,\n    pub created_at: Option&lt;i64&gt;,\n    pub updated_at: Option&lt;i64&gt;,\n    pub current_balance: f64,\n    pub status: Option&lt;UserStatus&gt;,\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003C\u002Fp>",{"title":789,"content":790},"Bản ghi database","\u003Cpre>\u003Ccode>{ \n    \"_id\" : ObjectId(\"68792e60c9ea0a3b0b56f141\"), \n    \"id\" : \"7dZdmdweeEQpnRCfmo0Q\", \n    \"network\" : \"web\", \n    \"username\" : \"heoluoibieng@bytebuffer.co\", \n    \"email\" : \"heoluoibieng@bytebuffer.co\", \n    \"password\" : \"$argon2id$v=19$m=19456,t=2,p=1$aWmfMcPDyuxzbKt0bnXcQg$wMeYKsojeyCZJgr9ADXH\u002FMz0Rjs36RLDWly1wQX+hLE\", \n    \"first_name\" : \"Heo\", \n    \"last_name\" : \"Lười Biếng\", \n    \"language_code\" : \"en\", \n    \"photo_url\" : \"https:\u002F\u002Favatar.bytebuffer.co\u002Fheo-luoi-bieng.jpg\", \n    \"created_at\" : NumberLong(1752772192881), \n    \"updated_at\" : NumberLong(1752772192881), \n    \"current_balance\" : 0.0\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003C\u002Fp>",{"title":792,"content":793},"Kết quả","\u003Cp>Sau phần này, bạn sẽ có một Data Layer hoàn chỉnh, code rõ ràng, dễ maintain và sẵn sàng tích hợp JWT Authentication ở bước tiếp theo.\u003C\u002Fp>",{"slug":406,"title":407,"description":408,"duration":409,"youtubeId":410,"order":174,"thumbnail":411,"createdAt":412,"updatedAt":413,"sections":795},[796,799,802],{"title":797,"content":798},"Nội dung chính","\u003Cp>Triển khai JSON Web Token (JWT): Thiết kế TokenClaim để lưu trữ các thông tin cần thiết như User ID, Display Name, Avatar và Title. Xây dựng helper để tạo token dựa trên secret key từ file cấu hình.\u003C\u002Fp>\u003Cp>Bảo mật với Argon2: Mã hóa mật khẩu trước khi lưu trữ và khi so sánh trong database, giúp đảm bảo an toàn cho dữ liệu người dùng.\u003C\u002Fp>\u003Cp>Xây dựng Login Service: Định nghĩa LoginRequest, validate dữ liệu đầu vào (định dạng email, mật khẩu tối thiểu 6 ký tự) và xử lý logic trả về AuthResponse bao gồm result code, message và token.\u003C\u002Fp>\u003Cp>Quản lý Cookie: Tạo và trả về header Set-Cookie cho trình duyệt. Cấu hình cookie với thời hạn dài, HttpOnly, SameSite và Secure để giảm thiểu rủi ro XSS và CSRF.\u003C\u002Fp>\u003Cp>Demo thực tế: Test login qua API, quan sát cách server trả về token và tự động set cookie trên trình duyệt.\u003C\u002Fp>",{"title":800,"content":801},"Công nghệ sử dụng","\u003Cp>Rust với các thư viện jsonwebtoken, argon2, axum, serde_json, cookie. Database sử dụng MongoDB.\u003C\u002Fp>\u003Cp>Trong phần này, dữ liệu người dùng đã được insert sẵn để tập trung hoàn toàn vào logic xác thực.\u003C\u002Fp>",{"title":725,"content":803},"\u003Cp>Sau bài học này, bạn sẽ có một Login Service hoàn chỉnh, áp dụng các chuẩn bảo mật phổ biến, sẵn sàng tích hợp vào hệ thống WebRTC signaling.\u003C\u002Fp>",{"slug":415,"title":416,"description":417,"duration":418,"youtubeId":419,"order":184,"thumbnail":420,"createdAt":421,"updatedAt":422,"sections":805},[806,809,812,815,818],{"title":807,"content":808},"Xây dựng HTTP Middleware","\u003Cp>Tìm hiểu cách Middleware hoạt động như một lớp gatekeeper cho các route cần xác thực. Triển khai việc đọc JWT từ cookie header, verify thông tin người dùng và inject dữ liệu user vào controller thông qua Extension của Axum. Đồng thời xử lý các trường hợp lỗi với mã 401 Unauthorized một cách rõ ràng.\u003C\u002Fp>",{"title":810,"content":811},"Xác thực WebSocket","\u003Cp>Thực hiện auth ngay từ bước handshake bằng cách lấy token từ header. Thiết lập cơ chế timeout bằng tokio::spawn, nếu client không xác thực trong vòng 30 giây thì tự động đóng kết nối để tránh lãng phí tài nguyên. Duy trì kết nối bằng cách gửi ping định kỳ mỗi 10 giây.\u003C\u002Fp>",{"title":813,"content":814},"Xử lý bất đồng bộ","\u003Cp>Sử dụng MPSC Channel và One-shot Channel để truyền dữ liệu xác thực giữa các task khác nhau, đảm bảo luồng xử lý rõ ràng và không block.\u003C\u002Fp>",{"title":816,"content":817},"Testing thực tế","\u003Cp>Sử dụng Postman để test API get_me, kiểm tra luồng xác thực HTTP. Demo quá trình kết nối WebSocket từ trạng thái bị từ chối khi thiếu token đến khi xác thực thành công và có thể trao đổi dữ liệu WebRTC.\u003C\u002Fp>",{"title":819,"content":820},"Kết quả đạt được","\u003Cp>Sau bài học này, bạn sẽ nắm được cách xây dựng Middleware trong Axum, hiểu cách tổ chức luồng xác thực cho cả HTTP và WebSocket, cũng như cách quản lý kết nối trong hệ thống realtime.\u003C\u002Fp>",{"slug":424,"title":425,"description":426,"duration":427,"youtubeId":428,"order":194,"thumbnail":429,"createdAt":430,"updatedAt":431,"sections":822},[823,826],{"title":824,"content":825},"Nội dung chính trong video:","\u003Cul>\u003Cli>\u003Cp>Demo HTTP Login: Kiểm tra flow đăng nhập, từ việc gọi LoginService để xác thực user trong database đến việc kiểm tra mật khẩu. Quan sát cách server trả về JWT token thông qua response body và header Set-Cookie.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>Kiểm tra Auth Middleware: Sử dụng cookie nhận được từ bước login để gọi API get_me. Xác nhận middleware có thể bóc tách thông tin user từ request và xử lý chính xác.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>Xác thực WebSocket: Thử nghiệm kết nối WebSocket và quan sát cơ chế tự động ngắt kết nối nếu không xác thực trong thời gian quy định. Thực hiện xác thực bằng cách gửi cookie trực tiếp trong header ngay từ bước handshake, giúp server nhận diện user mà không cần gửi message auth riêng.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>Theo dõi Server Logs: Kiểm tra log để xác nhận trạng thái authenticate thành công và cách server xử lý các message dựa trên cmd.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":725,"content":827},"\u003Cp>Sau phần này, bạn đã hoàn thiện toàn bộ hệ thống xác thực cho cả HTTP và WebSocket. Đây là nền tảng quan trọng để bước sang giai đoạn tiếp theo: xây dựng signaling giữa hai browser trong WebRTC.\u003C\u002Fp>",{"slug":433,"title":434,"description":435,"duration":436,"youtubeId":437,"order":204,"thumbnail":438,"createdAt":439,"updatedAt":440,"sections":829},[830,833,835],{"title":831,"content":832},"Tại sao cần State Pattern","\u003Cp>Một cuộc gọi P2P sẽ đi qua nhiều trạng thái như ringing, connecting, talking hoặc ended. Nếu xử lý bằng if-else, code sẽ nhanh chóng trở nên phức tạp và khó bảo trì. State Pattern giúp tách từng trạng thái thành các struct riêng, nhưng vẫn tuân theo một chuẩn chung thông qua trait, giúp hệ thống rõ ràng và dễ mở rộng.\u003C\u002Fp>",{"title":613,"content":834},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Thiết kế State Machine: Tổ chức cấu trúc thư mục theo hướng mở rộng như call, call_flow, call_types, giúp dễ dàng phát triển thêm các loại cuộc gọi trong tương lai.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Xây dựng P2PCallStateHandler Trait: Định nghĩa các hành vi chung cho mọi trạng thái, bao gồm name để định danh, on_enter và on_exit để xử lý khi chuyển trạng thái, on_event để xử lý các sự kiện và on_timer cho các logic liên quan đến thời gian.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Quản lý Action và Event: Xây dựng các enum cho state transition và hangup, giúp điều phối luồng xử lý một cách rõ ràng và nhất quán.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Tối ưu về concurrency: Sử dụng các đặc tính Send và Sync trong Rust để đảm bảo thread-safety khi xử lý các tác vụ bất đồng bộ liên quan đến cuộc gọi.\u003C\u002Fp>",{"title":819,"content":836},"\u003Cp>Sau phần này, bạn sẽ hiểu cách thiết kế State Machine trong Rust, cách sử dụng trait để quản lý logic phức tạp và xây dựng một kiến trúc rõ ràng, dễ maintain cho hệ thống realtime.\u003C\u002Fp>",{"slug":442,"title":443,"description":444,"duration":445,"youtubeId":446,"order":214,"thumbnail":447,"createdAt":448,"updatedAt":449,"sections":838},[839,841],{"title":824,"content":840},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→  \u003C\u002Fspan>Thiết kế CallActor: Xây dựng một actor chạy trên một luồng riêng, liên tục lắng nghe và xử lý các message thông qua MPSC receiver. Đây là nền tảng để triển khai kiến trúc hướng sự kiện trong hệ thống.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→  \u003C\u002Fspan>Tận dụng Tokio Runtime: Actor chỉ hoạt động khi có sự kiện và “ngủ” khi không có dữ liệu, giúp tối ưu tài nguyên và tăng hiệu năng cho server.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→  \u003C\u002Fspan>Quản lý Call Events: Phân loại các sự kiện như start, websocket, timer và stop. Thiết lập cơ chế dispatch để điều hướng sự kiện đến đúng loại call (ví dụ P2P) và xử lý logic tương ứng.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→  \u003C\u002Fspan>Quản lý Timer: Xây dựng cơ chế start_timer và stop_timer để kiểm soát các trạng thái chờ. Khi cuộc gọi kết thúc, toàn bộ timer sẽ được hủy để tránh rò rỉ tài nguyên.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→  \u003C\u002Fspan>Tư duy kiến trúc: Sử dụng enum để quản lý nhiều loại call khác nhau, giúp hệ thống dễ mở rộng và giữ được hiệu năng cao của Rust.\u003C\u002Fp>",{"title":725,"content":842},"\u003Cp>Sau phần này, bạn sẽ hiểu cách xây dựng một hệ thống event-driven với Rust, cách sử dụng MPSC để giao tiếp giữa các task và cách quản lý vòng đời cuộc gọi một cách rõ ràng, hiệu quả.\u003C\u002Fp>",{"slug":451,"title":452,"description":453,"duration":454,"youtubeId":455,"order":224,"thumbnail":456,"createdAt":457,"updatedAt":458,"sections":844},[845,847],{"title":824,"content":846},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Tổng quan kiến trúc: CallSupervisor quản lý danh sách các cuộc gọi đang hoạt động bằng DashMap, với key là CallID và value là CallHandler, chứa thông tin để điều khiển và giám sát từng cuộc gọi.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Cơ chế truyền tin: Sử dụng MPSC channel để đảm bảo các message gửi vào một cuộc gọi được xử lý tuần tự, tránh xung đột dữ liệu trong môi trường bất đồng bộ.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Tích hợp hệ thống: Supervisor được đặt trong AppState thông qua Arc, cho phép chia sẻ trạng thái giữa các thành phần khác nhau trong ứng dụng.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Quản lý vòng đời cuộc gọi: Triển khai start_call để khởi tạo CallActor và stop_call để kết thúc cuộc gọi. Mỗi cuộc gọi được chạy trên một task riêng biệt thông qua tokio::spawn.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Cơ chế timeout: Thiết lập thời gian chờ để đảm bảo task được dừng đúng cách, đồng thời xử lý cleanup nếu actor không tự đóng sau khoảng thời gian quy định.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Điều phối message: Nhận CallID từ các bản tin WebSocket như SDP Offer\u002FAnswer, tìm đúng call tương ứng và dispatch message vào actor xử lý.\u003C\u002Fp>",{"title":725,"content":848},"\u003Cp>Sau phần này, bạn sẽ hiểu cách xây dựng một hệ thống supervisor để quản lý hàng loạt actor, kiểm soát tài nguyên hiệu quả và điều phối message trong hệ thống realtime.\u003C\u002Fp>",{"slug":460,"title":461,"description":462,"duration":463,"youtubeId":464,"order":234,"thumbnail":465,"createdAt":466,"updatedAt":467,"sections":850},[851,853],{"title":824,"content":852},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Quy trình thiết lập cuộc gọi: Caller bắt đầu bằng việc gửi call_start_request lên server. Sau đó gửi SDP Offer, server chuyển tiếp đến Callee dưới dạng incoming_call. Callee phản hồi trạng thái ringing và cuối cùng gửi SDP Answer để chấp nhận cuộc gọi.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Trao đổi ICE Candidate: Cả hai phía liên tục gửi candidate lên server, server đóng vai trò forward để hai peer tìm ra đường kết nối mạng tối ưu nhất.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Truyền media và kết thúc cuộc gọi: Sau khi hoàn tất signaling, media sẽ truyền trực tiếp giữa hai browser theo mô hình P2P, không đi qua server. Khi một bên gửi call_end, cuộc gọi sẽ được kết thúc.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Liên hệ với code: Toàn bộ flow này sẽ được ánh xạ vào các state mà chúng ta đã thiết kế ở các phần trước, giúp việc triển khai logic trở nên rõ ràng và dễ kiểm soát.\u003C\u002Fp>",{"title":725,"content":854},"\u003Cp>Sau phần này, bạn sẽ hiểu rõ toàn bộ sequence của một cuộc gọi WebRTC, nắm được vai trò của signaling server và sẵn sàng bước vào phần triển khai logic chi tiết.\u003C\u002Fp>",{"slug":469,"title":470,"description":471,"duration":472,"youtubeId":473,"order":244,"thumbnail":474,"createdAt":475,"updatedAt":476,"sections":856},[857,859],{"title":824,"content":858},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>SDP là gì: Tìm hiểu vai trò của Session Description Protocol và cấu trúc cơ bản của một bản tin SDP trong WebRTC.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Phân tích thông số kỹ thuật: Giải thích các thành phần quan trọng như media (audio\u002Fvideo), port, protocol và thứ tự ưu tiên codec. Làm rõ ý nghĩa của các giá trị như 111 (Opus) hay 0, 8 trong các hệ thống VoIP truyền thống.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Vấn đề địa chỉ IP: Tại sao trong SDP thường xuất hiện c=IN IP4 0.0.0.0 và vì sao thông tin này không đủ để hai peer kết nối trực tiếp.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Trickle ICE: Hiểu ý nghĩa của a=ice-options:trickle và tại sao cần tiếp tục trao đổi ICE Candidate sau khi gửi SDP để xác định đường kết nối thực tế.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Mối liên hệ SDP và ICE: Làm rõ cách SDP và ICE kết hợp với nhau để thiết lập kết nối WebRTC hoàn chỉnh.\u003C\u002Fp>",{"title":725,"content":860},"\u003Cp>Sau phần này, bạn sẽ hiểu rõ cấu trúc và ý nghĩa của SDP, cách WebRTC thỏa thuận codec và lý do vì sao ICE Candidate là bước bắt buộc để thiết lập kết nối thành công.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>",{"slug":478,"title":479,"description":480,"duration":481,"youtubeId":482,"order":254,"thumbnail":483,"createdAt":484,"updatedAt":485,"sections":862},[863,865],{"title":824,"content":864},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Tại sao cần ICE Candidate: Làm rõ lý do vì sao SDP thường chưa đủ thông tin (ví dụ IP 0.0.0.0) và cần thêm candidate để thiết lập kết nối.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Các loại Candidate: Phân tích 3 loại phổ biến gồm Host (IP nội bộ hoặc public trực tiếp), Srflx (IP public thông qua STUN) và Relay (qua TURN server khi không thể kết nối trực tiếp).\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Hạ tầng STUN và TURN: Giới thiệu cách hoạt động của STUN server, vai trò của TURN server và phần mềm coTURN để triển khai thực tế. Đồng thời hướng dẫn sử dụng STUN miễn phí như stun.l.google.com:19302.\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Demo thực tế: Phân tích cấu trúc của các candidate (UDP, Host, Srflx, Relay) từ một ứng dụng thực tế để hiểu rõ cách WebRTC hoạt động.\u003C\u002Fp>",{"title":725,"content":866},"\u003Cp>Sau phần này, bạn sẽ hiểu cách WebRTC vượt NAT, phân biệt được các loại candidate và biết khi nào cần dùng TURN server. Đồng thời nắm được cách cấu hình STUN\u002FTURN cho ứng dụng của mình.\u003C\u002Fp>",{"slug":487,"title":488,"description":489,"duration":490,"youtubeId":491,"order":264,"thumbnail":492,"createdAt":493,"updatedAt":494,"sections":868},[869,871],{"title":797,"content":870},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Chúng ta sẽ thực hiện một cuộc gọi thực tế từ softphone và quan sát các thay đổi trực tiếp trên giao diện debug. Bạn sẽ học cách phân tích candidate pair để xác định chính xác địa chỉ local và remote nào đã được sử dụng để kết nối.\u003Cbr>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Ngoài ra, video cũng hướng dẫn cách kiểm tra luồng media thông qua các thông số RTP như packets sent và packets received để đảm bảo audio hoặc video thực sự đang được truyền.\u003Cbr>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ \u003C\u002Fspan>Bạn cũng sẽ thấy sự khác biệt giữa Chrome và Firefox trong cách hiển thị dữ liệu. Chrome cung cấp nhiều biểu đồ thống kê chi tiết, trong khi Firefox hiển thị rõ ràng các candidate đã match với nhau.\u003C\u002Fp>",{"title":819,"content":872},"\u003Cp>Sau bài học này, bạn sẽ biết cách sử dụng các công cụ debug của trình duyệt để phân tích sâu kết nối WebRTC, xác định nguyên nhân khi cuộc gọi không hoạt động và nâng cao kỹ năng debug cho các hệ thống VoIP thực tế.\u003Cbr>\u003C\u002Fp>",{"slug":496,"title":497,"description":498,"duration":499,"youtubeId":500,"order":41,"thumbnail":501,"createdAt":502,"updatedAt":503,"sections":874},[875,877],{"title":797,"content":876},"\u003Cp>Trong video, bạn sẽ được hướng dẫn cách triển khai hàm transition để điều khiển việc chuyển đổi giữa các trạng thái của một cuộc gọi. Đồng thời, chúng ta sẽ xử lý một vấn đề đặc trưng của Rust là ownership, cụ thể là lý do cần sử dụng phương thức take() để đưa state ra khỏi bộ nhớ trước khi gọi hàm, nhằm đảm bảo tuân thủ borrow checker.\u003Cbr>\u003Cbr>Bạn cũng sẽ thấy sự khác biệt trong cách triển khai State Pattern giữa Rust và các ngôn ngữ hướng đối tượng như Java, từ đó hiểu rõ hơn cách Rust xử lý logic phức tạp mà vẫn đảm bảo an toàn bộ nhớ.\u003Cbr>\u003Cbr>Phần tiếp theo, chúng ta đi vào vòng đời của state. Trạng thái cũ sẽ gọi on_exit trước khi chuyển sang trạng thái mới, sau đó trạng thái mới sẽ xử lý on_enter. Hệ thống cũng quản lý các action trả về như Stay để giữ nguyên trạng thái, Transition để chuyển tiếp, hoặc Hangup để kết thúc cuộc gọi.\u003Cbr>\u003Cbr>Cuối cùng, video mô tả luồng xử lý thực tế của một cuộc gọi. Bắt đầu từ Idle state, hệ thống chuyển sang trạng thái chờ SDP từ caller. Sau đó là giai đoạn kết nối với callee, nơi server định kỳ gửi thông báo incoming_call. Khi cuộc gọi được thiết lập, hệ thống chuyển sang trạng thái talking và có thể kết thúc ở bất kỳ thời điểm nào nếu xảy ra lỗi hoặc người dùng ngắt cuộc gọi.\u003Cbr>\u003C\u002Fp>",{"title":792,"content":878},"\u003Cp>Sau bài học này, bạn sẽ nắm được cách xây dựng một State Machine bền vững trong Rust, hiểu rõ cách quản lý vòng đời state và có cái nhìn đầy đủ về flow của một cuộc gọi WebRTC từ lúc bắt đầu đến khi kết thúc.\u003C\u002Fp>",{"slug":505,"title":506,"description":507,"duration":508,"youtubeId":509,"order":510,"thumbnail":511,"createdAt":512,"updatedAt":513,"sections":880},[881,884],{"title":882,"content":883},"Nôi dung chính:","\u003Cp>Trong video, bạn sẽ được hướng dẫn cách xây dựng handler để bóc tách dữ liệu từ JSON gửi lên từ client. Đồng thời, chúng ta sẽ quản lý req_id để đảm bảo client có thể mapping chính xác giữa request và response.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Phần tiếp theo tập trung vào validation. Chúng ta sẽ kiểm tra các điều kiện cần thiết như người bị gọi không được để trống, không được phép gọi chính mình và xác minh sự tồn tại của cả caller và callee trong MongoDB trước khi tiếp tục xử lý.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Sau khi hợp lệ, hệ thống sẽ khởi tạo cuộc gọi thông qua CallSupervisor. Mỗi cuộc gọi sẽ có một call_id duy nhất, được dùng để quản lý toàn bộ vòng đời của phiên làm việc. Server sẽ gọi hàm start_call để tạo task cho CallActor và đưa cuộc gọi vào trạng thái ban đầu là Idle.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Video cũng bao gồm phần demo thực tế với Postman, trong đó bạn sẽ thấy các trường hợp lỗi như sai user hoặc tự gọi chính mình, cũng như trường hợp thành công khi server trả về call_id cùng thông báo xác nhận.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>",{"title":885,"content":886},"Kết quả thu được","\u003Cp>Sau bài học này, bạn sẽ biết cách xây dựng một handler hoàn chỉnh cho WebSocket, kết hợp giữa validation, database và actor model để quản lý cuộc gọi. Đây là nền tảng để chúng ta tiếp tục sang bước gửi SDP Offer trong các phần tiếp theo.\u003C\u002Fp>",{"slug":515,"title":516,"description":517,"duration":518,"youtubeId":519,"order":520,"thumbnail":521,"createdAt":522,"updatedAt":523,"sections":888},[889,891],{"title":783,"content":890},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">Sau khi lệnh start_call thành công, hệ thống sẽ phát sinh sự kiện CallStart và sử dụng hàm transition để chuyển từ Idle sang trạng thái chờ SDP. Đây là bước chuyển trạng thái đầu tiên trong toàn bộ call flow.\u003Cbr>\u003Cbr>Một phần quan trọng trong state này là quản lý timeout. Ngay khi on_enter được gọi, hệ thống sẽ kích hoạt một timer 45 giây. Nếu hết thời gian mà chưa nhận được SDP, cuộc gọi sẽ tự động kết thúc để tránh giữ tài nguyên không cần thiết. Khi rời khỏi state, timer cũng được dừng lại để đảm bảo không bị leak.\u003Cbr>\u003Cbr>Ở phía WebSocket, chúng ta xây dựng SDPHandler để nhận và parse bản tin SDP từ client. Server sẽ sử dụng CallSupervisor để tìm đúng cuộc gọi theo call_id và đẩy sự kiện vào CallActor tương ứng. Ngoài ra, hệ thống cũng chuẩn bị cơ chế lưu trữ tạm thời ICE Candidate trong trường hợp client gửi lên song song với SDP.\u003Cbr>\u003Cbr>Khi SDP được xử lý thành công, state này sẽ kết thúc và hệ thống sẵn sàng chuyển sang bước tiếp theo: kết nối với callee.\u003C\u002Fspan>\u003C\u002Fp>",{"title":819,"content":892},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">Sau phần này, bạn sẽ hiểu rõ cách một state thực tế hoạt động trong hệ thống, cách xử lý timeout, cũng như cách điều phối message WebSocket vào đúng actor theo call_id.\u003C\u002Fspan>\u003C\u002Fp>",{"slug":525,"title":526,"description":527,"duration":528,"youtubeId":529,"order":530,"thumbnail":531,"createdAt":532,"updatedAt":533,"sections":894},[895,898],{"title":896,"content":897},"Nội dung trọng tâm trong video:","\u003Cp>Quản lý đa thiết bị (Multi-device):\u003C\u002Fp>\u003Cp>Giải quyết bài toán một user có thể đăng nhập trên nhiều thiết bị (web, mobile, desktop) cùng lúc.\u003C\u002Fp>\u003Cp>Xây dựng WebRTCState để lưu trữ ICE Candidate riêng biệt cho từng client_id của callee.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Logic on_enter và on_timer:\u003C\u002Fp>\u003Cp>Ngay khi vào state, server forward SDP Offer từ caller xuống toàn bộ thiết bị của callee.\u003C\u002Fp>\u003Cp>Triển khai cơ chế resend: gửi lại incoming_call mỗi 5 giây để đảm bảo không bỏ lỡ cuộc gọi.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Xử lý ICE Candidate:\u003C\u002Fp>\u003Cp>Thu thập và phân loại candidate từ cả caller và callee trong quá trình chờ kết nối.\u003C\u002Fp>\u003Cp>Xử lý phản hồi theo chuẩn SIP:\u003C\u002Fp>\u003Cp>- 180 Ringing: Thông báo đang đổ chuông\u003C\u002Fp>\u003Cp>- 486 Busy\u002FReject: Kết thúc cuộc gọi ngay\u003C\u002Fp>\u003Cp>- 200 OK: Người dùng accept → dừng resend và gửi lệnh ngắt chuông tới các device khác\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Chuyển đổi trạng thái:\u003C\u002Fp>\u003Cp>Sau khi nhận 200 OK, hệ thống chuẩn bị chuyển sang state chờ SDP Answer từ callee.\u003C\u002Fp>",{"title":899,"content":900},"Kiến thức đạt được:","\u003Cul>\u003Cli>\u003Cp>Hiểu cách xử lý multi-device trong hệ thống realtime.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>Nắm được cách forward SDP và ICE Candidate giữa các peer thông qua server.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>Làm chủ quy trình xử lý trạng thái cuộc gọi như ringing, busy và accept.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"slug":535,"title":536,"description":537,"duration":538,"youtubeId":539,"order":540,"thumbnail":541,"createdAt":542,"updatedAt":543,"sections":902},[903,905],{"title":896,"content":904},"\u003Cp>Xây dựng Answer Handler:\u003C\u002Fp>\u003Cp>Thiết kế hàm answer_handler để tiếp nhận và bóc tách dữ liệu từ bản tin answer_request gửi lên từ client.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Xử lý các mã trạng thái:\u003C\u002Fp>\u003Cp>Triển khai logic cho các mã phổ biến như:\u003C\u002Fp>\u003Cp>180 (Ringing): Thông báo đang đổ chuông\u003C\u002Fp>\u003Cp>486 (Busy\u002FReject): Từ chối hoặc bận\u003C\u002Fp>\u003Cp>200 (OK): Chấp nhận cuộc gọi và bắt đầu xử lý SDP\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Lưu ý kỹ thuật:\u003C\u002Fp>\u003Cp>Chỉ khi nhận mã 200 thì bản tin SDP mới thực sự cần thiết và được xử lý trong hệ thống.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Triển khai Candidate Handler:\u003C\u002Fp>\u003Cp>Xây dựng module riêng để xử lý ICE Candidate từ client.\u003C\u002Fp>\u003Cp>Áp dụng kỹ thuật lọc và ưu tiên log các candidate quan trọng như Srflx và Relay để phục vụ debug.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Điều phối sự kiện (Event Dispatching):\u003C\u002Fp>\u003Cp>Sử dụng call_id để xác định đúng cuộc gọi trong hệ thống.\u003C\u002Fp>\u003Cp>Dispatch các sự kiện on_answer và ICE Candidate vào đúng CallActor thông qua State Machine.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Luồng chuyển đổi trạng thái:\u003C\u002Fp>\u003Cp>Kết nối logic với state ConnectToCallee đã xây dựng ở bài trước.\u003C\u002Fp>\u003Cp>Chuẩn bị chuyển sang trạng thái chờ SDP Answer từ callee và tiến tới trạng thái Talking.\u003C\u002Fp>",{"title":899,"content":906},"\u003Cp>Hiểu cách xử lý các mã signaling chuẩn tương tự SIP trong WebRTC\u003C\u002Fp>\u003Cp>Nắm được cách thu thập và điều phối ICE Candidate giữa các peer\u003C\u002Fp>\u003Cp>Làm chủ mô hình event-driven và quản lý state trong hệ thống realtime\u003C\u002Fp>",{"slug":545,"title":546,"description":547,"duration":548,"youtubeId":549,"order":550,"thumbnail":551,"createdAt":552,"updatedAt":553,"sections":908},[909,911],{"title":896,"content":910},"\u003Cp>Chuyển đổi trạng thái (State Transition):\u003C\u002Fp>\u003Cp>Hướng dẫn cách chuyển từ trạng thái kết nối sang P2PWaitingCalleeSDPState sau khi đã notify thành công tới Callee.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Xử lý trong hàm on_enter:\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Gửi SDP Answer từ Callee về cho Caller để hoàn tất quá trình handshake\u003C\u002Fp>\u003Cp>Trao đổi ICE Candidate hai chiều giữa Caller và Callee\u003C\u002Fp>\u003Cp>Sử dụng loop để push toàn bộ candidate đã thu thập trước đó\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Xây dựng Helper Functions:\u003C\u002Fp>\u003Cp>Viết các hàm như send_notify_sdp và notify_candidate để tối ưu code, giúp việc gửi message qua WebSocket rõ ràng và dễ maintain hơn\u003Cbr>\u003C\u002Fp>\u003Cp>Xử lý sự kiện on_event:\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Tiếp tục nhận candidate trong quá trình chờ\u003C\u002Fp>\u003Cp>Điều hướng candidate đúng hướng dựa vào user_id (caller ↔ callee)\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Chuyển sang trạng thái Talking:\u003C\u002Fp>\u003Cp>Sau khi hoàn tất signaling, hệ thống sẽ chuyển sang P2PTalkingState để bắt đầu giai đoạn media streaming\u003C\u002Fp>",{"title":899,"content":912},"\u003Cp>Hiểu cách forward SDP Answer và ICE Candidate giữa hai peer\u003C\u002Fp>\u003Cp>Nắm được cơ chế matching candidate để thiết lập kết nối\u003C\u002Fp>\u003Cp>Làm chủ bước cuối của signaling trước khi media chạy P2P\u003C\u002Fp>",{"slug":555,"title":556,"description":557,"duration":558,"youtubeId":559,"order":560,"thumbnail":561,"createdAt":562,"updatedAt":563,"sections":914},[915,917],{"title":896,"content":916},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">Thiết kế TalkingState:\u003Cbr>Xây dựng cấu trúc dữ liệu để theo dõi trạng thái cuộc gọi, bao gồm last_active_caller và last_active_callee sử dụng kiểu Instant để lưu lại thời điểm tương tác gần nhất của mỗi bên. Đồng thời lưu trữ thông tin client để điều phối message chính xác.\u003Cbr>\u003Cbr>Cơ chế Heartbeat (nhịp đập hệ thống):\u003Cbr>Server định kỳ gửi bản tin in_call_request mỗi 5 giây tới cả caller và callee để kiểm tra trạng thái kết nối. Đây là giải pháp cần thiết vì server không tham gia vào luồng media.\u003Cbr>\u003Cbr>Xử lý Timeout &amp; tự động kết thúc:\u003Cbr>Nếu sau 30 giây một trong hai bên không phản hồi, server sẽ coi như kết nối đã mất và tự động chuyển sang EndState để giải phóng tài nguyên.\u003Cbr>\u003Cbr>Xử lý in_call_notify:\u003Cbr>Xây dựng handler để nhận phản hồi từ client. Khi nhận được tín hiệu “vẫn đang trong cuộc gọi”, server sẽ cập nhật lại mốc thời gian hoạt động bằng Instant::now().\u003Cbr>\u003Cbr>Hoàn thiện State Machine:\u003Cbr>\u003Cbr>On Enter: Thông báo bắt đầu đàm thoại\u003Cbr>On Event: Vẫn tiếp nhận ICE Candidate gửi muộn\u003Cbr>On Timer: Kiểm tra heartbeat định kỳ và reset timer\u003C\u002Fspan>\u003C\u002Fp>",{"title":899,"content":918},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">Hiểu vai trò của signaling server trong giai đoạn Talking của WebRTC\u003Cbr>Nắm được cách quản lý thời gian thực với Instant và Duration trong Rust\u003Cbr>Biết cách thiết kế cơ chế heartbeat\u002Ftimeout để hệ thống tự phục hồi và tránh leak tài nguyên\u003C\u002Fspan>\u003C\u002Fp>",{"slug":565,"title":566,"description":567,"duration":568,"youtubeId":569,"order":570,"thumbnail":571,"createdAt":572,"updatedAt":573,"sections":920},[921,923],{"title":896,"content":922},"\u003Cp>Vai trò của EndState:\u003C\u002Fp>\u003Cp>Tổng hợp các lý do dẫn đến kết thúc cuộc gọi như timeout (không phản hồi), người dùng chủ động hangup hoặc lỗi trong quá trình signaling. Đây là điểm cuối của toàn bộ call flow.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Cơ chế giải phóng tài nguyên:\u003C\u002Fp>\u003Cp>Sử dụng channel (TX) để gửi lệnh Stop từ CallActor về CallSupervisor.\u003C\u002Fp>\u003Cp>Tại Supervisor, hệ thống sẽ xóa cuộc gọi khỏi DashMap và dừng task tương ứng để giải phóng tài nguyên Tokio.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Thông báo tới client:\u003C\u002Fp>\u003Cp>Xây dựng helper notify_call_end để gửi bản tin kết thúc cuộc gọi tới cả caller và callee, đảm bảo UI được cập nhật đúng trạng thái.\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Triển khai trong State Machine:\u003C\u002Fp>\u003Cp>On Enter: Ghi log lý do kết thúc và thực hiện notify + cleanup.\u003C\u002Fp>\u003Cp>Xử lý sự kiện end_call: Cho phép chuyển sang EndState từ bất kỳ trạng thái nào khi người dùng yêu cầu kết thúc.\u003C\u002Fp>\u003Cp>Hàm transition: Áp dụng kỹ thuật xử lý ownership an toàn trong Rust khi chuyển state.\u003C\u002Fp>",{"title":899,"content":924},"\u003Cp>Hiểu cách thiết kế cơ chế cleanup cho hệ thống realtime\u003C\u002Fp>\u003Cp>Nắm được cách Actor giao tiếp ngược về Supervisor qua channel\u003C\u002Fp>\u003Cp>Hoàn thiện toàn bộ vòng đời cuộc gọi từ start → talking → end\u003C\u002Fp>",{"slug":575,"title":576,"description":577,"duration":578,"youtubeId":579,"order":580,"thumbnail":581,"createdAt":582,"updatedAt":583,"sections":926},[927,929],{"title":896,"content":928},"\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Build &amp; đóng gói ứng dụng:\u003Cbr>Hướng dẫn build ứng dụng Rust để chạy ngoài môi trường IDE.\u003Cbr>Thiết lập config YAML và export environment variables để chạy production.\u003Cbr>\u003Cbr>Cross-compile &amp; deploy:\u003Cbr>Sử dụng WSL (Debian) để build binary Linux từ Windows.\u003Cbr>Chuẩn bị sẵn sàng để deploy lên VPS.\u003Cbr>\u003Cbr>Kiểm tra authentication:\u003Cbr>Demo login bằng Web Client với dữ liệu trong database.\u003Cbr>Kiểm tra JWT cookie được set trên trình duyệt thông qua Network tab.\u003Cbr>\u003Cbr>Demo cuộc gọi P2P thực tế:\u003Cbr>Thực hiện cuộc gọi giữa hai user trên hai trình duyệt khác nhau (Chrome &amp; Firefox).\u003Cbr>Quan sát flow WebSocket như start_call và cách server điều phối cuộc gọi.\u003Cbr>\u003Cbr>Debug WebRTC chuyên sâu:\u003Cbr>Sử dụng chrome:\u002F\u002Fwebrtc-internals và about:webrtc để phân tích kết nối.\u003Cbr>Kiểm tra ICE Candidate pair (local\u002Fremote) đã match.\u003Cbr>Giám sát luồng RTP, codec sử dụng (PCMU\u002FPCMA) và lượng data truyền.\u003C\u002Fspan>\u003C\u002Fp>",{"title":725,"content":930},"\u003Cp>Xác nhận toàn bộ hệ thống WebRTC hoạt động end-to-end\u003C\u002Fp>\u003Cp>Biết cách build và deploy ứng dụng Rust thực tế\u003C\u002Fp>\u003Cp>Làm chủ công cụ debug WebRTC trên trình duyệt\u003C\u002Fp>",{"slug":585,"title":586,"description":587,"duration":588,"youtubeId":589,"order":295,"thumbnail":590,"createdAt":591,"updatedAt":592,"sections":932},[933,935,938],{"title":896,"content":934},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">Tổng kết hệ thống đã xây dựng:\u003Cbr>Hoàn thiện WebSocket Server để xử lý các bản tin thời gian thực.\u003Cbr>Triển khai Actor Pattern kết hợp State Machine với 6 trạng thái từ Idle đến EndState.\u003Cbr>Xây dựng hoàn chỉnh Signaling Server cho phép trao đổi SDP và ICE Candidate giữa hai trình duyệt.\u003Cbr>Triển khai thành công hệ thống lên VPS và test thực tế với môi trường internet.\u003Cbr>\u003Cbr>Những hạn chế của mô hình P2P:\u003Cbr>Khó scale với mô hình N-way mesh do giới hạn băng thông.\u003Cbr>Không thể ghi âm\u002Fghi hình vì media không đi qua server.\u003Cbr>Tốn băng thông khi có nhiều peer kết nối.\u003Cbr>Vấn đề NAT khiến một số trường hợp bắt buộc phải dùng TURN server.\u003Cbr>\u003Cbr>Lộ trình tiếp theo (Media Server):\u003Cbr>Giới thiệu hướng phát triển nâng cao với các hệ thống Media Server:\u003Cbr>\u003Cbr>Janus &amp; LiveKit: Các giải pháp WebRTC hiện đại.\u003Cbr>Kurento Media Server: Xử lý media phía server.\u003Cbr>Asterisk: Hệ thống VoIP phổ biến trong doanh nghiệp.\u003Cbr>FreeSWITCH: Nền tảng viễn thông mạnh mẽ cho hệ thống lớn.\u003C\u002Fspan>\u003C\u002Fp>",{"title":936,"content":937},"Sau toàn bộ series, bạn đã:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">Hiểu và xây dựng được một hệ thống WebRTC P2P hoàn chỉnh\u003Cbr>Nắm được kiến trúc Signaling Server với Actor + State Machine\u003Cbr>Có nền tảng vững chắc để bước sang các hệ thống Media Server chuyên sâu\u003C\u002Fspan>\u003C\u002Fp>",{"title":939,"content":940},"Source code:","\u003Cp>Backend: \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fcall-p2p-backend\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fcall-p2p-backend\u003C\u002Fa>\u003C\u002Fp>\u003Cp>Frontend: \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fcall-p2p-web\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fcall-p2p-web\u003C\u002Fa>\u003C\u002Fp>",1779462614404]