[{"data":1,"prerenderedAt":1144},["ShallowReactive",2],{"courses-list":3,"course-rust-voip-janus-media-server":631},[4,23,35,307,319,620],{"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",26,"[\"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,278,288,298],{"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":274,"thumbnail":275,"createdAt":276,"updatedAt":277},"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",23,"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":279,"title":280,"description":281,"duration":282,"youtubeId":283,"order":284,"thumbnail":285,"createdAt":286,"updatedAt":287},"rust-voip-janus-media-server-24-app-to-sip-build-deploy-debug-app-to-sip","Rust VoIP - Janus Media Server #24: App To Sip: Build + Deploy + Debug App to SIP.","Trong bài học này, chúng ta sẽ tiếp tục hoàn thiện luồng App-to-SIP. Sau khi đã xử lý xong trạng thái chờ SDP từ người gọi, video hôm nay sẽ tập trung vào việc Build, Deploy và Debug thực tế để chuyển dịch sang trạng thái tiếp theo: Connect to SIP State.\nBạn sẽ học cách định nghĩa cấu trúc trạng thái mới, xử lý các sự kiện bất đồng bộ từ WebSocket và Janus để đảm bảo điều kiện \"webrtcup\" được thỏa mãn trước khi thực hiện kết nối ra phía nhà mạng.","16:01","N0gBEN7EFBk",24,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1779553941282-ec512ecb-df02-4966-8f03-a8f296bc2924.jpg","2026-05-23 16:34:15","2026-05-23 16:34:26",{"slug":289,"title":290,"description":291,"duration":292,"youtubeId":293,"order":294,"thumbnail":295,"createdAt":296,"updatedAt":297},"rust-voip-janus-media-server-25-app-to-sip-connect-to-sip-state","Rust VoIP - Janus Media Server #25: App To Sip: Connect To SIP State","Trong bài học này, chúng ta sẽ thực hiện một trong những bước quan trọng nhất của luồng App-to-SIP: Trạng thái Connect to SIP. Đây là giai đoạn hệ thống Rust Server của chúng ta đóng vai trò là một SIP Client (UAC) để khởi tạo cuộc gọi đến SIP Server (Kamailio) và chuyển tiếp yêu cầu từ người dùng WebRTC ra thế giới điện thoại.\nBạn sẽ học cách build một bản tin SIP INVITE hoàn chỉnh, cách khai thác Janus Admin API để lấy thông tin media và cách cấu hình Kamailio để điều phối cuộc gọi đi (Outbound Call).","1:09:22","LKVQf2YkFu8",25,"https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1779585256004-d60691a7-84c4-4526-80dd-7624ac8ab253.png","2026-05-24 01:15:58","2026-05-24 01:16:11",{"slug":299,"title":300,"description":301,"duration":302,"youtubeId":303,"order":41,"thumbnail":304,"createdAt":305,"updatedAt":306},"rust-voip-janus-media-server-26-app-to-sip-talking-state-end-state","Rust VoIP - Janus Media Server #26: App To Sip: Talking State & End State","Trong bài học này, chúng ta sẽ hoàn thiện những bước cuối cùng của luồng gọi App-to-SIP với Rust và Janus Media Server. Sau khi đã kết nối thành công từ WebRTC Browser đến SIP Phone ở bài trước, video hôm nay sẽ tập trung vào việc triển khai Talking State và End State để quản lý toàn bộ vòng đời cuộc gọi VoIP từ khi bắt đầu đàm thoại đến lúc giải phóng tài nguyên hoàn toàn.\n\nBạn sẽ học cách xử lý SIP 200 OK, quản lý SIP Dialog, xử lý sự kiện kết thúc cuộc gọi từ nhiều nguồn khác nhau và cleanup tài nguyên trên Janus Media Server một cách chính xác trong hệ thống SIP ↔ WebRTC production.","24:51","UCAX2geC8dU","https:\u002F\u002Fpub-cd0f133a6f7640ca947255f10fb6c328.r2.dev\u002Fthumbnails\u002F1779754548269-71f33830-4a77-4580-9fe2-27cb449c315c.png","2026-05-26 00:17:12","2026-05-26 00:17:21",{"slug":308,"title":309,"shortDescription":310,"description":311,"category":9,"level":10,"totalDuration":312,"totalLessons":12,"tags":313,"createdAt":314,"updatedAt":315,"rating":12,"reviewCount":12,"thumbnail":316,"instructor":317,"lessons":318},"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":320,"title":321,"shortDescription":322,"description":323,"category":9,"level":28,"totalDuration":324,"totalLessons":325,"tags":326,"createdAt":327,"updatedAt":328,"rating":329,"reviewCount":330,"thumbnail":331,"instructor":332,"lessons":333},"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},[334,342,350,358,366,374,382,391,400,408,417,426,435,444,453,462,471,480,489,498,507,516,525,534,543,552,561,571,581,591,601,611],{"slug":335,"title":336,"description":337,"duration":338,"youtubeId":339,"order":55,"thumbnail":340,"createdAt":327,"updatedAt":341},"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":343,"title":344,"description":345,"duration":346,"youtubeId":347,"order":65,"thumbnail":348,"createdAt":327,"updatedAt":349},"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":351,"title":352,"description":353,"duration":354,"youtubeId":355,"order":75,"thumbnail":356,"createdAt":327,"updatedAt":357},"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":359,"title":360,"description":361,"duration":362,"youtubeId":363,"order":15,"thumbnail":364,"createdAt":327,"updatedAt":365},"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":367,"title":368,"description":369,"duration":370,"youtubeId":371,"order":94,"thumbnail":372,"createdAt":327,"updatedAt":373},"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":375,"title":376,"description":377,"duration":378,"youtubeId":379,"order":104,"thumbnail":380,"createdAt":381,"updatedAt":381},"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":383,"title":384,"description":385,"duration":386,"youtubeId":387,"order":114,"thumbnail":388,"createdAt":389,"updatedAt":390},"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":392,"title":393,"description":394,"duration":395,"youtubeId":396,"order":124,"thumbnail":397,"createdAt":398,"updatedAt":399},"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":401,"title":402,"description":403,"duration":404,"youtubeId":405,"order":134,"thumbnail":406,"createdAt":407,"updatedAt":407},"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":409,"title":410,"description":411,"duration":412,"youtubeId":413,"order":144,"thumbnail":414,"createdAt":415,"updatedAt":416},"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":418,"title":419,"description":420,"duration":421,"youtubeId":422,"order":154,"thumbnail":423,"createdAt":424,"updatedAt":425},"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":427,"title":428,"description":429,"duration":430,"youtubeId":431,"order":164,"thumbnail":432,"createdAt":433,"updatedAt":434},"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":436,"title":437,"description":438,"duration":439,"youtubeId":440,"order":174,"thumbnail":441,"createdAt":442,"updatedAt":443},"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":445,"title":446,"description":447,"duration":448,"youtubeId":449,"order":184,"thumbnail":450,"createdAt":451,"updatedAt":452},"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":454,"title":455,"description":456,"duration":457,"youtubeId":458,"order":194,"thumbnail":459,"createdAt":460,"updatedAt":461},"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":463,"title":464,"description":465,"duration":466,"youtubeId":467,"order":204,"thumbnail":468,"createdAt":469,"updatedAt":470},"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":472,"title":473,"description":474,"duration":475,"youtubeId":476,"order":214,"thumbnail":477,"createdAt":478,"updatedAt":479},"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":481,"title":482,"description":483,"duration":484,"youtubeId":485,"order":224,"thumbnail":486,"createdAt":487,"updatedAt":488},"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":490,"title":491,"description":492,"duration":493,"youtubeId":494,"order":234,"thumbnail":495,"createdAt":496,"updatedAt":497},"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":499,"title":500,"description":501,"duration":502,"youtubeId":503,"order":244,"thumbnail":504,"createdAt":505,"updatedAt":506},"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":508,"title":509,"description":510,"duration":511,"youtubeId":512,"order":254,"thumbnail":513,"createdAt":514,"updatedAt":515},"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":517,"title":518,"description":519,"duration":520,"youtubeId":521,"order":264,"thumbnail":522,"createdAt":523,"updatedAt":524},"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":526,"title":527,"description":528,"duration":529,"youtubeId":530,"order":274,"thumbnail":531,"createdAt":532,"updatedAt":533},"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":535,"title":536,"description":537,"duration":538,"youtubeId":539,"order":284,"thumbnail":540,"createdAt":541,"updatedAt":542},"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","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":544,"title":545,"description":546,"duration":547,"youtubeId":548,"order":294,"thumbnail":549,"createdAt":550,"updatedAt":551},"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","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":553,"title":554,"description":555,"duration":556,"youtubeId":557,"order":41,"thumbnail":558,"createdAt":559,"updatedAt":560},"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","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":562,"title":563,"description":564,"duration":565,"youtubeId":566,"order":567,"thumbnail":568,"createdAt":569,"updatedAt":570},"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":572,"title":573,"description":574,"duration":575,"youtubeId":576,"order":577,"thumbnail":578,"createdAt":579,"updatedAt":580},"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":582,"title":583,"description":584,"duration":585,"youtubeId":586,"order":587,"thumbnail":588,"createdAt":589,"updatedAt":590},"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":592,"title":593,"description":594,"duration":595,"youtubeId":596,"order":597,"thumbnail":598,"createdAt":599,"updatedAt":600},"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":602,"title":603,"description":604,"duration":605,"youtubeId":606,"order":607,"thumbnail":608,"createdAt":609,"updatedAt":610},"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":612,"title":613,"description":614,"duration":615,"youtubeId":616,"order":325,"thumbnail":617,"createdAt":618,"updatedAt":619},"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":621,"title":622,"shortDescription":623,"description":624,"category":9,"level":10,"totalDuration":312,"totalLessons":12,"tags":625,"createdAt":626,"updatedAt":627,"rating":12,"reviewCount":12,"thumbnail":628,"instructor":629,"lessons":630},"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":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":632,"lessons":633},{"name":19,"title":20,"bio":21},[634,648,671,690,709,731,752,776,799,820,841,860,876,894,915,933,950,968,987,1006,1027,1048,1069,1093,1103,1126],{"slug":50,"title":51,"description":52,"duration":53,"youtubeId":54,"order":55,"thumbnail":56,"createdAt":57,"updatedAt":58,"sections":635},[636,639,642,645],{"title":637,"content":638},"Những vấn đề của mô hình WebRTC P2P:","\u003Cp>Scalability: Số lượng kết nối tăng theo cấp số nhân (N²), không thể scale với nhiều người dùng\u003C\u002Fp>\u003Cp>Băng thông &amp; tài nguyên: Mỗi client phải gửi nhiều luồng media → tốn CPU, pin (đặc biệt mobile)\u003C\u002Fp>\u003Cp>Recording: Không thể ghi âm tập trung vì media không đi qua server\u003C\u002Fp>\u003Cp>NAT Strict: Một số user không thể kết nối nếu không có TURN server\u003C\u002Fp>",{"title":640,"content":641},"Giải pháp với Janus Media Server:","\u003Cp>Server trung gian giúp nhận và phân phối media → giảm tải cho client\u003C\u002Fp>\u003Cp>Kiến trúc modular:\u003C\u002Fp>\u003Cp>Janus Core (networking + signaling)\u003C\u002Fp>\u003Cp>Plugins (mở rộng chức năng linh hoạt)\u003C\u002Fp>\u003Cp>AudioBridge Plugin:\u003C\u002Fp>\u003Cp>Trộn audio tại server\u003C\u002Fp>\u003Cp>Tối ưu băng thông\u003C\u002Fp>\u003Cp>Hỗ trợ conference với số lượng lớn user\u003C\u002Fp>",{"title":643,"content":644},"Lộ trình thực hành với Rust:","\u003Cp>Call App-to-App (WebRTC ↔ WebRTC)\u003C\u002Fp>\u003Cp>Call App-to-SIP (Web ↔ SIP)\u003C\u002Fp>\u003Cp>Call SIP-to-App\u003C\u002Fp>\u003Cp>Auto Callout (hệ thống gọi tự động)\u003C\u002Fp>\u003Cp>\u003C\u002Fp>",{"title":646,"content":647},"Kiến thức đạt được:","\u003Cp>Hiểu rõ giới hạn của mô hình P2P trong thực tế\u003C\u002Fp>\u003Cp>Nắm được kiến trúc Media Server hiện đại\u003C\u002Fp>\u003Cp>Làm quen với Janus Media Server\u003C\u002Fp>\u003Cp>Sẵn sàng bắt đầu lập trình VoIP chuyên sâu với Rust\u003C\u002Fp>",{"slug":60,"title":61,"description":62,"duration":63,"youtubeId":64,"order":65,"thumbnail":66,"createdAt":67,"updatedAt":68,"sections":649},[650,653,656,659,662,665,668],{"title":651,"content":652},"Xây dựng Docker Image (Build Stage):","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Sử dụng base image debian:bookworm\u003Cbr>- Cài đặt các package cần thiết để build Janus\u003Cbr>- Clone source từ Janus Gateway v1.4.0 trên GitHub\u003Cbr>- Build và đưa output vào thư mục \u002Fopt\u002Fjanus\u003C\u002Fspan>\u003C\u002Fp>",{"title":654,"content":655},"Tối ưu Runtime Stage:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Copy artifact từ build stage sang runtime\u003Cbr>- Giảm dung lượng image (~800MB)\u003Cbr>- Mở các port quan trọng:\u003Cbr>  + 8088 (REST API)\u003Cbr>  + 8188 (WebSocket)\u003Cbr>  + 9898 (Admin API)\u003C\u002Fspan>\u003C\u002Fp>",{"title":657,"content":658},"Dockerfile","\u003Cpre>\u003Ccode># =========================================================\n# BUILD STAGE\n# =========================================================\nFROM debian:bookworm AS builder\nENV DEBIAN_FRONTEND=noninteractive\n\nRUN apt-get update &amp;&amp; apt-get install -y \\\n    build-essential \\\n    git \\\n    pkg-config \\\n    libtool \\\n    automake \\\n    autoconf \\\n    cmake \\\n    wget \\\n    curl \\\n    gengetopt \\\n    libmicrohttpd-dev \\\n    libjansson-dev \\\n    libssl-dev \\\n    libsrtp2-dev \\\n    libsofia-sip-ua-dev \\\n    libglib2.0-dev \\\n    libopus-dev \\\n    libogg-dev \\\n    libcurl4-openssl-dev \\\n    liblua5.3-dev \\\n    libconfig-dev \\\n    libnice-dev \\\n    libwebsockets-dev \\\n    libavcodec-dev \\\n    libavformat-dev \\\n    libavutil-dev \\\n    libavfilter-dev \\\n    &amp;&amp; rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n\nWORKDIR \u002Fusr\u002Fsrc\n\n# Clone Janus v1.4.0\nRUN git clone --branch v1.4.0 --depth 1 https:\u002F\u002Fgithub.com\u002Fmeetecho\u002Fjanus-gateway.git janus\n\nWORKDIR \u002Fusr\u002Fsrc\u002Fjanus\n\n# Build Janus\nRUN sh autogen.sh &amp;&amp; \\\n    .\u002Fconfigure \\\n      --prefix=\u002Fopt\u002Fjanus \\\n      --enable-websockets \\\n     # --enable-data-channels \\\n      --enable-rest \\\n      --enable-post-processing &amp;&amp; \\\n    make -j$(nproc) &amp;&amp; \\\n    make install &amp;&amp; \\\n    make configs\n\n# Debug: check binary deps\nRUN echo \"===== LDD CHECK FOR JANUS =====\" &amp;&amp; ldd \u002Fopt\u002Fjanus\u002Fbin\u002Fjanus\n\n\n# =========================================================\n# RUNTIME STAGE\n# =========================================================\nFROM debian:bookworm\nENV DEBIAN_FRONTEND=noninteractive\n\nRUN apt-get update &amp;&amp; apt-get install -y \\\n    libmicrohttpd12 \\\n    libjansson4 \\\n    libssl3 \\\n    libsrtp2-1 \\\n    libsofia-sip-ua0 \\\n    libglib2.0-0 \\\n    libopus0 \\\n    libogg0 \\\n    libcurl4 \\\n    liblua5.3-0 \\\n    libconfig9 \\\n    libnice10 \\\n    libwebsockets17 \\\n    libavcodec59 \\\n    libavformat59 \\\n    libavutil57 \\\n    libavfilter8 \\\n    ca-certificates \\\n    &amp;&amp; rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n\n# Copy Janus runtime\nCOPY --from=builder \u002Fopt\u002Fjanus \u002Fopt\u002Fjanus\n\n# Runtime dirs\nRUN mkdir -p \u002Fvar\u002Flog\u002Fjanus \u002Fvar\u002Frun\u002Fjanus\n\nEXPOSE 8088 8188 8989\nEXPOSE 50000-60000\u002Fudp\n\nWORKDIR \u002Fopt\u002Fjanus\n\nENTRYPOINT [\"\u002Fopt\u002Fjanus\u002Fbin\u002Fjanus\"]\nCMD [\"-F\", \"\u002Fopt\u002Fjanus\u002Fetc\u002Fjanus\"]\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003C\u002Fp>\u003Cp>Build:\u003C\u002Fp>\u003Cpre>\u003Ccode>docker build -t janus:1.1 .\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003C\u002Fp>",{"title":660,"content":661},"docker-compose.yaml","\u003Cpre>\u003Ccode>services:\n  janus:\n    image: janus:1.1\n    container_name: janus\n    network_mode: host\n    restart: unless-stopped\n\n    entrypoint: [\"\u002Fopt\u002Fjanus\u002Fbin\u002Fjanus\"]\n    command:\n      - \"janus\"\n      - \"--config=\u002Fopt\u002Fjanus\u002Fetc\u002Fjanus\u002Fjanus.jcfg\"\n      - \"--debug-level=4\"\n\n    environment:\n      - TZ=Asia\u002FSaigon\n      - JANUS_LOG_LEVEL=4\n\n    volumes:\n      - .\u002Fconfig:\u002Fopt\u002Fjanus\u002Fetc\u002Fjanus:ro\n      - .\u002Flog:\u002Fopt\u002Fjanus\u002Flog:rw\n      - .\u002Frecordings:\u002Fopt\u002Fjanus\u002Frecordings:rw\n      - .\u002Fsouds:\u002Fopt\u002Fjanus\u002Fsouds:rw\n\n    cap_add:\n      - SYS_NICE\n      - SYS_RESOURCE\n      - NET_ADMIN\n\n    expose:\n      - \"8088\u002Ftcp\"   # Janus HTTP API\n      - \"8188\u002Ftcp\"   # Janus WebSocket\n      - \"8989\u002Ftcp\"   # Janus Admin API\n      # RTP\u002FRTCP UDP ports fpr WebRTC media\n      - \"50000-60000\u002Fudp\"\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003C\u002Fp>\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Sử dụng network_mode: host để tối ưu media\u003Cbr>- Quản lý dải port UDP lớn (50000–60000)\u003Cbr>- Mount volumes:\u003Cbr>  + Config\u003Cbr>  + Recordings\u003Cbr>  + Sounds\u003C\u002Fspan>\u003C\u002Fp>",{"title":663,"content":664},"Cấu hình Janus (janus.jcfg):","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Thiết lập API Secret &amp; Admin Secret\u003Cbr>- Enable WebSocket transport\u003Cbr>- Cấu hình NAT &amp; ICE Candidate\u003Cbr>- Giới thiệu AudioBridge plugin cho conference\u003C\u002Fspan>\u003C\u002Fp>",{"title":666,"content":667},"Kết quả sau bài học:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Cài đặt thành công Janus Media Server bằng Docker\u003Cbr>- Có hệ thống Media Server chạy ổn định trên VPS\u003Cbr>- Sẵn sàng tích hợp với Rust backend trong các bài tiếp theo\u003C\u002Fspan>\u003C\u002Fp>",{"title":669,"content":670},"Source code:","\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-setup\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-setup\u003C\u002Fa>\u003C\u002Fp>",{"slug":70,"title":71,"description":72,"duration":73,"youtubeId":74,"order":75,"thumbnail":76,"createdAt":77,"updatedAt":78,"sections":672},[673,676,679,682,685,688],{"title":674,"content":675},"Tái cấu trúc & tối ưu Codebase:","\u003Cp>- Tận dụng lại các module cốt lõi:\u003Cbr> + WebSocket\u003Cbr> + Auth Controller\u003Cbr> + User Controller\u003Cbr> + Database access\u003Cbr>- Giữ lại Supervisor và Client Actor cho logic xử lý realtime\u003Cbr>- Loại bỏ luồng P2P Routing cũ\u003Cbr>- Refactor State Handler để phù hợp với Media Server architecture\u003C\u002Fp>",{"title":677,"content":678},"Thiết lập giao tiếp Rust ↔ Janus:","\u003Cp>Chiều đi (Rust → Janus):\u003Cbr>- Sử dụng HTTP API (port 8088)\u003Cbr>- Gửi các lệnh điều khiển từ Rust Server đến Janus\u003Cbr>\u003Cbr>Chiều về (Janus → Rust):\u003Cbr>- Cấu hình Janus Event Handler\u003Cbr>- Đẩy event về Rust thông qua WebSocket\u003C\u002Fp>",{"title":680,"content":681},"Xây dựng Event Handler trong Rust:","\u003Cp>- Tạo WebSocket Server riêng (port 10004) để nhận event từ Janus\u003Cbr>- Implement web_socket_handler:\u003Cbr> + Tách sender \u002F receiver\u003Cbr> + Loop nhận message từ Janus\u003Cbr>- Đăng ký route để hệ thống sẵn sàng nhận callback từ Media Server\u003C\u002Fp>",{"title":683,"content":684},"Kết quả đạt được:","\u003Cp>- Có codebase Rust được tổ chức lại rõ ràng, sẵn sàng mở rộng\u003Cbr>- Gửi được request từ Rust → Janus qua HTTP API\u003Cbr>- Nhận được event từ Janus → Rust qua WebSocket\u003Cbr>- Hoàn thiện nền tảng để triển khai Call App-to-App &amp; SIP Integration\u003C\u002Fp>",{"title":686,"content":687},"Janus Docs:","\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Feventhandlers.html\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Feventhandlers.html\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Frest.html\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Frest.html\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge.html\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge.html\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fp>",{"title":669,"content":689},"\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fp>",{"slug":80,"title":81,"description":82,"duration":83,"youtubeId":84,"order":15,"thumbnail":85,"createdAt":86,"updatedAt":87,"sections":691},[692,695,698,701,704,706],{"title":693,"content":694},"Deploy & kiểm tra kết nối:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Build ứng dụng Rust chạy trên Linux\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Deploy lên server\u002FVPS\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Cấu hình biến môi trường\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Chạy Janus bằng Docker Compose\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Kiểm tra cơ chế Janus gửi Event về Rust qua WebSocket\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":696,"content":697},"Làm chủ Janus API với Postman:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Gọi các API cơ bản:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Get Info\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Create Session\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hiểu Transaction ID &amp; API Secret\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Attach AudioBridge plugin → lấy Handle ID\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Lưu ý:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Session chỉ sống 60 giây\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Cần cơ chế keep-alive\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":699,"content":700},"Xây dựng Janus Service trong Rust:","\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Session Service:\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Create session\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Destroy session\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Keep-alive session\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">\u003Cbr>AudioBridge Service:\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Attach \u002F Detach plugin\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Create \u002F Delete room (có Pin, Secret)\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Join room:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">WebRTC client\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">RTP endpoint (phục vụ SIP\u002FVoIP)\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":702,"content":703},"Vì sao chọn AudioBridge thay vì SIP Plugin:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Linh hoạt hơn cho:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Invite user\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Transfer call\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Phù hợp kiến trúc VoIP hiện đại\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":683,"content":705},"\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Deploy thành công Rust + Janus trên server\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hiểu rõ cách hoạt động của Janus Session &amp; Plugin\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Viết được service quản lý Audio Room trong Rust\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Sẵn sàng build App-to-App Call ở các bài tiếp theo\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":707,"content":708},"Tài nguyên tham khảo:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">Mã nguồn (GitHub): \u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fconnect-to-janus-api\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fconnect-to-janus-api\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>Tài liệu Janus REST API:\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge.html\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge.html\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fp>",{"slug":89,"title":90,"description":91,"duration":92,"youtubeId":93,"order":94,"thumbnail":95,"createdAt":96,"updatedAt":97,"sections":710},[711,714,717,720,723,726,729],{"title":712,"content":713},"Định nghĩa cấu trúc App-to-App Call:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Tạo module app_to_app_routing\u003Cbr>- Xây dựng struct AppToAppCall\u003Cbr>- Khởi tạo AppToAppCallInitParam (Caller + Callee)\u003Cbr>- Tích hợp CallSupervisor để quản lý call theo call_id\u003C\u002Fspan>\u003C\u002Fp>",{"title":715,"content":716},"Thiết lập với Janus Media Server:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Create Session thông qua session_service\u003Cbr>- Attach AudioBridge plugin → lấy HandleID\u003Cbr>- Create Room với các tham số:\u003Cbr>  + RoomID\u003Cbr>  + Pin\u003Cbr>  + Secret\u003C\u002Fspan>\u003C\u002Fp>",{"title":718,"content":719},"Mapping & Routing Event:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Tạo JanusKey từ SessionID + HandleID\u003Cbr>- Mapping event từ Janus → đúng CallHandler\u003Cbr>- Xây dựng add_janus_handler trong CallSupervisor\u003C\u002Fspan>\u003C\u002Fp>",{"title":721,"content":722},"Xây dựng Call State Machine:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Các state chính:\u003Cbr>  + IdleState\u003Cbr>  + WaitingCallerSdpState\u003Cbr>  + ConnectToCallee\u003Cbr>  + WaitingCalleeSdpState\u003Cbr>  + TalkingState\u003Cbr>  + EndState\u003Cbr>- Cơ chế:\u003Cbr>  + Transition giữa các state\u003Cbr>  + Xử lý OnEvent \u002F OnTimer\u003Cbr>  + Cleanup tài nguyên\u003C\u002Fspan>\u003C\u002Fp>",{"title":724,"content":725},"Demo & Testing:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Gọi start_call bằng WebSocket (Postman)\u003Cbr>- Kiểm tra log từ Janus:\u003Cbr>  + Create Session\u003Cbr>  + Attach Plugin\u003Cbr>  + Create Room\u003C\u002Fspan>\u003C\u002Fp>",{"title":727,"content":728},"🚀 Kết quả đạt được:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">- Thiết kế hoàn chỉnh flow App-to-App Call phía Server\u003Cbr>- Làm chủ cách tương tác với Janus API\u003Cbr>- Xây dựng State Machine cho hệ thống VoIP\u003Cbr>- Sẵn sàng xử lý SDP &amp; Media ở các bài tiếp theo\u003C\u002Fspan>\u003C\u002Fp>",{"title":707,"content":730},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">Mã nguồn bài học:\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-1-setup\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-1-setup\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003Cbr>Tài liệu Janus AudioBridge:\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fp>",{"slug":99,"title":100,"description":101,"duration":102,"youtubeId":103,"order":104,"thumbnail":105,"createdAt":106,"updatedAt":107,"sections":732},[733,736,739,742,745,747,749],{"title":734,"content":735},"Quản lý Session & Timeout:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Thiết lập cơ chế keep-alive cho Janus Session (~30s)\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Tránh session bị expire do không hoạt động\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Cấu hình SDP timeout (45s):\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Nếu không nhận SDP từ caller → kết thúc cuộc gọi\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":737,"content":738},"Đẩy SDP lên Janus:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Join Room:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Đưa caller vào AudioBridge room\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Configure:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Gửi SDP Offer từ client lên Janus\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Thiết lập media để Janus nhận audio\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":740,"content":741}," Xử lý SDP Answer:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Lắng nghe event từ Janus\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Extract SDP Answer\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Gửi ngược về client qua WebRTC Manager\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":743,"content":744},"State Transition:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Khi xử lý SDP thành công:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">  → Chuyển sang state ConnectToCallee\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Xử lý lỗi:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">  → Transition về EndState khi cần\u003C\u002Fspan>\u003C\u002Fp>",{"title":724,"content":746},"\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Deploy lên server Linux\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Theo dõi log:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">SDP Offer → Janus\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">SDP Answer → Client\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Test thực tế bằng softphone \u002F browser\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":683,"content":748},"\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Thiết lập thành công media giữa Caller và Janus\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hiểu rõ flow SDP Offer \u002F Answer với Media Server\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Làm chủ state Waiting Caller SDP\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hoàn thành 50% flow cuộc gọi App-to-App\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":750,"content":751},"Mã nguồn:","\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-2-impl\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-2-impl\u003C\u002Fa>\u003C\u002Fp>",{"slug":109,"title":110,"description":111,"duration":112,"youtubeId":113,"order":114,"thumbnail":115,"createdAt":116,"updatedAt":117,"sections":753},[754,757,760,763,766,769,772,774],{"title":755,"content":756},"Routing Janus Events:","\u003Cp>- Sử dụng SessionID + HandleID để mapping event\u003C\u002Fp>\u003Cp>- Định tuyến event về đúng Call thông qua CallSupervisor\u003C\u002Fp>\u003Cp>- Dispatch event vào State Machine\u003C\u002Fp>",{"title":758,"content":759},"Triển khai ConnectToCalleeState:","\u003Cp>- on_enter:\u003C\u002Fp>\u003Cp>  + Gửi incoming_call tới callee\u003C\u002Fp>\u003Cp>- Quản lý thông tin:\u003C\u002Fp>\u003Cp>  + Caller \u002F Callee\u003C\u002Fp>\u003Cp>  + CallID\u003C\u002Fp>",{"title":761,"content":762},"Timer & cơ chế resend:","\u003Cp>- Resend incoming_call mỗi 5 giây\u003C\u002Fp>\u003Cp>- Timeout:\u003C\u002Fp>\u003Cp>  + Nếu callee không phản hồi → EndState\u003C\u002Fp>",{"title":764,"content":765},"Xử lý phản hồi từ callee:","\u003Cp>- 180 Ringing:\u003C\u002Fp>\u003Cp>  + Notify lại cho caller\u003C\u002Fp>\u003Cp>- 486 Busy:\u003C\u002Fp>\u003Cp>  + Kết thúc cuộc gọi\u003C\u002Fp>\u003Cp>- 200 OK:\u003C\u002Fp>\u003Cp>  + Dừng timer\u003C\u002Fp>\u003Cp>  + Chuẩn bị chuyển state\u003C\u002Fp>",{"title":767,"content":768},"State transition:","\u003Cp>- Sau khi callee accept:\u003C\u002Fp>\u003Cp>  → Chuyển sang WaitingCalleeSdpState\u003C\u002Fp>",{"title":770,"content":771},"Demo thực tế:","\u003Cp>- Test với 2 browser (caller &amp; callee)\u003C\u002Fp>\u003Cp>- Theo dõi message:\u003C\u002Fp>\u003Cp>  + incoming_call\u003C\u002Fp>\u003Cp>  + ringing\u003C\u002Fp>\u003Cp>  + answer\u003C\u002Fp>",{"title":727,"content":773},"\u003Cp>- Làm chủ signaling giữa nhiều client\u003C\u002Fp>\u003Cp>- Hiểu rõ flow incoming call trong VoIP system\u003C\u002Fp>\u003Cp>- Xử lý đầy đủ các trạng thái:\u003C\u002Fp>\u003Cp>  ringing \u002F reject \u002F accept\u003C\u002Fp>\u003Cp>- Sẵn sàng bước sang xử lý SDP từ callee\u003C\u002Fp>",{"title":750,"content":775},"\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-3-connect-to-callee\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-3-connect-to-callee\u003C\u002Fa>\u003C\u002Fp>",{"slug":119,"title":120,"description":121,"duration":122,"youtubeId":123,"order":124,"thumbnail":125,"createdAt":126,"updatedAt":127,"sections":777},[778,781,784,787,790,793,795,797],{"title":779,"content":780},"Quản lý Mapping Handle & Client ID:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Xây dựng handler_client_map:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Mapping Janus Handle ID ↔ Client ID\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Implement get_or_create_handler:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Reuse handle cũ\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Auto attach plugin nếu chưa tồn tại\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":782,"content":783},"Hiện thực hóa WaitingCalleeSdpState:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">on_enter:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Attach AudioBridge plugin cho callee\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Tạo JanusKey:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">SessionID + HandleID\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Đăng ký với CallSupervisor\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Thực hiện join_and_config:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Join room\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Configure SDP cho callee\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":785,"content":786},"Xử lý SDP Answer:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Parse Janus Event từ AudioBridge\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Extract SDP Answer\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Gửi sdp_notify về Web Client\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Thiết lập remote_description để hoàn tất WebRTC handshake\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":788,"content":789},"Cleanup & Device Management:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Auto detach các thiết bị khác của callee\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Đảm bảo chỉ còn thiết bị đang tham gia cuộc gọi hoạt động\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":791,"content":792},"Chuyển sang Talking State:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Sau khi SDP hoàn tất:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">  → Transition sang TalkingState\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Bắt đầu truyền tải media\u002Faudio thực tế\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":724,"content":794},"\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Build &amp; deploy lên Linux server\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Theo dõi log:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Ringing\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Waiting SDP\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Talking State\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Kiểm tra flow signaling &amp; media thực tế\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":727,"content":796},"\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hoàn thiện full flow App-to-App Call\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hiểu rõ cơ chế xử lý SDP với Janus\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Làm chủ State Machine trong VoIP system\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Thiết lập thành công Talking State cho cuộc gọi thực tế\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":669,"content":798},"\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-4-connect-to-callee-and-taking-state\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-4-connect-to-callee-and-taking-state\u003C\u002Fa>\u003C\u002Fp>",{"slug":129,"title":130,"description":131,"duration":132,"youtubeId":133,"order":134,"thumbnail":135,"createdAt":136,"updatedAt":137,"sections":800},[801,804,807,810,813,815,817],{"title":802,"content":803},"Xử lý Talking State:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Gửi Answer Notify cho caller và callee\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Cập nhật UI:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Bắt đầu đếm thời gian đàm thoại\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Lắng nghe sự kiện hangup từ client\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Kích hoạt quy trình kết thúc cuộc gọi\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":805,"content":806},"End State & Resource Cleanup:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Stop KeepAlive timer\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Notify call_end tới cả hai phía\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Gửi reason kết thúc cuộc gọi\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Cleanup tài nguyên Janus:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Delete Room\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Detach Handles\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Destroy Session\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":808,"content":809},"Keep Alive cho Janus Session:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Theo tài liệu Janus:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Session sẽ expire sau 60–120 giây\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Implement keep_alive định kỳ mỗi 30 giây\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Giữ session hoạt động ổn định trong suốt cuộc gọi\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":811,"content":812},"Xử lý WebSocket & ICE Candidate:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Xử lý:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">on_candidate\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">on_candidate_complete\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Tối ưu hiệu năng:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Ignore transport\u002Fcore events\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Bỏ qua event type 128 \u002F 256 không cần thiết\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":724,"content":814},"\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Test full call flow:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Start Call\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Talking\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hangup\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Destroy Session\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Theo dõi log:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Resource cleanup\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Session destroy\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Room cleanup\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":727,"content":816},"\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hoàn thiện full App-to-App VoIP system\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Làm chủ Talking State &amp; End State\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hiểu sâu về Resource Management với Janus\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Xây dựng cơ chế Keep Alive production-ready\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Tránh memory leak trong hệ thống realtime\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Đây sẽ là nền tảng cực kỳ quan trọng trước khi bước sang các tính năng nâng cao như SIP Integration hoặc Auto Callout.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp>\u003C\u002Fp>",{"title":818,"content":819},"Tài liệu tham khảo:","\u003Cp>Source code:\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-5-talking-and-end-state\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-5-talking-and-end-state\u003C\u002Fa>\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003Cp>Tài liệu:\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Frest.html\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Frest.html\u003C\u002Fa>\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Feventhandlers.html\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Feventhandlers.html\u003C\u002Fa>\u003C\u002Fp>",{"slug":139,"title":140,"description":141,"duration":142,"youtubeId":143,"order":144,"thumbnail":145,"createdAt":146,"updatedAt":147,"sections":821},[822,825,828,831,834,837,839],{"title":823,"content":824},"Demo thực tế & Phân tích ICE Candidate:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Thực hiện cuộc gọi thực tế giữa Chrome và Firefox\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Kiểm tra chất lượng media\u002Faudio\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Phân tích ICE Candidate:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Trong P2P:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">    Browser ↔ Browser\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Trong Media Server:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">    Browser ↔ Janus Server\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Tìm hiểu vì sao ICE Candidate giờ đây trỏ tới Public IP của Janus VPS thay vì IP của trình duyệt\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":826,"content":827},"Giải mã Sequence Diagram App-to-App:","\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Luồng Signaling:\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Web Client gửi request tới Rust Server\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Rust điều khiển Janus:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Create Session\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Attach Handle\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Create Room\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Trao đổi SDP Offer \u002F Answer thông qua Rust Server\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Luồng RTP \u002F Media:\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Media không còn đi trực tiếp giữa 2 browser\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Browser sẽ gửi SRTP tới Janus AudioBridge\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Janus thực hiện vai trò:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Media relay\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Audio mixer\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":829,"content":830},"Ưu thế của mô hình Media Server:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Media đi qua server giúp:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Recording cuộc gọi\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Invite thêm participant\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Transfer cuộc gọi\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Chủ động disconnect user\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hỗ trợ:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Conference\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Scalability\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Production-ready architecture\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":832,"content":833},"So sánh P2P vs Media Server:","\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">WebRTC P2P:\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Rust Server chỉ signaling\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Media đi trực tiếp giữa các browser\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">\u003Cbr>Janus Media Server:\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Signaling phức tạp hơn\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Nhưng:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Quản lý cuộc gọi tốt hơn\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Dễ scale\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hỗ trợ nhiều tính năng VoIP nâng cao\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":835,"content":836},"Lộ trình tiếp theo – SIP Integration:","\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Chuẩn bị bước sang chương:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">SIP to App\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">App to SIP\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">RTP endpoint\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Softphone integration\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Kết nối:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Browser\u002FWebRTC\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">SIP Phone\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Tổng đài VoIP thực tế\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":727,"content":838},"\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Sau bài học này, bạn sẽ:\u003C\u002Fspan>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hiểu rõ kiến trúc VoIP sử dụng Media Server\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Phân biệt bản chất giữa:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">WebRTC P2P\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Media Server Architecture\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Hiểu flow:\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cul>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">SDP\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">RTP\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">ICE Candidate\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Signaling\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Nắm được cách Janus xử lý media\u002Faudio trong production\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Sẵn sàng bước sang các bài học SIP Integration nâng cao\u003Cbr>Đây là cột mốc cực kỳ quan trọng trước khi tiến vào thế giới VoIP thực tế với SIP, RTP và hệ thống viễn thông chuyên nghiệp.\u003C\u002Fspan>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",{"title":669,"content":840},"\u003Cp>Web: \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fb2bua-web\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fb2bua-web\u003C\u002Fa>\u003C\u002Fp>",{"slug":149,"title":150,"description":151,"duration":152,"youtubeId":153,"order":154,"thumbnail":155,"createdAt":156,"updatedAt":157,"sections":842},[843,846,849,852,855,857],{"title":844,"content":845},"Phân tích Signaling & Media Flow","\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">→ Sự khác biệt giữa:\u003Cbr>\u003Cbr>• SIP (Phone)\u003Cbr>• WebRTC (Browser\u002FApp)\u003Cbr>\u003Cbr>→ Phân tích SDP &amp; ICE Candidate\u003Cbr>→ Tìm hiểu luồng RTP trong hệ thống VoIP\u003Cbr>\u003Cbr>→ Vai trò của:\u003Cbr>\u003Cbr>• Kamailio\u003Cbr>• RTPEngine\u003Cbr>• Janus AudioBridge\u003Cbr>\u003Cbr>→ Cách media được relay giữa:\u003Cbr>\u003Cbr>• SIP Phone\u003Cbr>• WebRTC Client\u003Cbr>• Media Server\u003C\u002Fspan>\u003C\u002Fp>",{"title":847,"content":848},"Setup Telco Simulator bằng Docker","\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">→ Cấu hình subdomain trên Cloudflare\u003Cbr>\u003Cbr>⚠️ Lưu ý:\u003Cbr>• Disable Proxy\u003Cbr>• SIP UDP phải đi trực tiếp tới VPS\u003Cbr>\u003Cbr>→ Setup MySQL trên Docker:\u003Cbr>\u003Cbr>• Port 3399\u003Cbr>• Lưu trữ user\u002Fconfig cho Kamailio\u003Cbr>\u003Cbr>→ Cấu hình Kamailio v5.6:\u003Cbr>\u003Cbr>• Port SIP 50600\u003Cbr>• Kết nối Database\u003Cbr>• Load module cần thiết\u003C\u002Fspan>\u003C\u002Fp>",{"title":850,"content":851},"Làm chủ Dispatcher Module","\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">→ Tìm hiểu module Dispatcher của Kamailio\u003Cbr>\u003Cbr>→ Dispatcher giúp:\u003Cbr>\u003Cbr>• Quản lý SIP Gateway\u003Cbr>• Load balancing\u003Cbr>• Routing cuộc gọi\u003Cbr>\u003Cbr>→ Cấu hình:\u003Cbr>\u003Cbr>• dispatcher.list\u003Cbr>• destination routing\u003C\u002Fspan>\u003C\u002Fp>",{"title":853,"content":854},"Testing thực tế với Zoiper","\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">→ Khởi tạo Database Schema cho Kamailio\u003Cbr>→ Tạo SIP Account giả lập\u003Cbr>→ Đăng ký tài khoản trên Zoiper\u003Cbr>\u003Cbr>📞 Demo thực tế:\u003Cbr>\u003Cbr>• Zoiper gọi vào hệ thống\u003Cbr>• Kiểm tra trạng thái Ringing\u003Cbr>• Theo dõi signaling &amp; media flow\u003C\u002Fspan>\u003C\u002Fp>",{"title":727,"content":856},"\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">→ Setup thành công Telco Simulator bằng Docker\u003Cbr>→ Hiểu rõ signaling giữa SIP ↔ WebRTC\u003Cbr>→ Làm chủ Kamailio Dispatcher\u003Cbr>→ Tạo được SIP account để test thực tế\u003Cbr>→ Sẵn sàng triển khai SIP-to-App &amp; App-to-SIP\u003C\u002Fspan>\u003C\u002Fp>",{"title":858,"content":859},"📦 Tài nguyên bài học:","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">Config mẫu:\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fkamailio\u002Fkamailio\u002Fblob\u002F5.6\u002Fetc\u002Fkamailio.cfg\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fgithub.com\u002Fkamailio\u002Fkamailio\u002Fblob\u002F5.6\u002Fetc\u002Fkamailio.cfg\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003Cbr>Tài liệu Kamailio Dispatcher:\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fwww.kamailio.org\u002Fdocs\u002Fmodules\u002F5.6.x\u002Fmodules\u002Fdispatcher.html\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fwww.kamailio.org\u002Fdocs\u002Fmodules\u002F5.6.x\u002Fmodules\u002Fdispatcher.html\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003Cbr>Zoiper:\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fwww.zoiper.com\u002Fen\u002Fvoip-softphone\u002Fdownload\u002Fcurrent\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fwww.zoiper.com\u002Fen\u002Fvoip-softphone\u002Fdownload\u002Fcurrent\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003Cbr>Source code: \u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fsimulator-telco\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fsimulator-telco\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fp>",{"slug":159,"title":160,"description":161,"duration":162,"youtubeId":163,"order":164,"thumbnail":165,"createdAt":166,"updatedAt":167,"sections":861},[862,865,868,871,873],{"title":863,"content":864},"Setup Kamailio SIP Server (v5.8.7)","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Build Kamailio trực tiếp từ Source Code:\u003Cbr>\u003Cbr>• Sử dụng Dockerfile\u003Cbr>• Clone source từ GitHub\u003Cbr>• Build Kamailio v5.8.7\u003Cbr>\u003Cbr>→ Vì sao build từ source?\u003Cbr>\u003Cbr>• Tăng khả năng tùy biến\u003Cbr>• Dễ tối ưu module\u003Cbr>• Phù hợp production system\u003Cbr>\u003Cbr>→ Setup Docker Environment:\u003Cbr>\u003Cbr>• Base image Debian\u003Cbr>• Cài dependency:\u003Cbr>  - liblua\u003Cbr>  - SSL\u003Cbr>  - build tools\u003Cbr>\u003Cbr>→ Cấu hình kamailio.cfg:\u003Cbr>\u003Cbr>• Listen Public IP\u003Cbr>• SIP Port 5061\u003Cbr>• Load module rtpengine\u003Cbr>• Chuẩn bị routing logic cho SIP-to-App\u003C\u002Fspan>\u003C\u002Fp>",{"title":866,"content":867},"Setup RTPEngine (Media Proxy)","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ RTPEngine là gì?\u003Cbr>\u003Cbr>• RTP \u002F Media Proxy\u003Cbr>• Xử lý luồng RTP\u002FUDP\u003Cbr>• Bridge media giữa:\u003Cbr>  - SIP\u003Cbr>  - WebRTC\u003Cbr>\u003Cbr>→ Build RTPEngine bằng Docker:\u003Cbr>\u003Cbr>• Multi-stage build\u003Cbr>• Builder + Runtime stage\u003Cbr>• Tối ưu image production\u003Cbr>\u003Cbr>→ Cấu hình quan trọng:\u003Cbr>\u003Cbr>• Control Port:\u003Cbr>  - 22223\u003Cbr>\u003Cbr>• RTP Port Range:\u003Cbr>  - 10000 → 20000\u003Cbr>  - Có thể mở rộng tới 60000\u003Cbr>\u003Cbr>→ Hỗ trợ:\u003Cbr>\u003Cbr>• RTP relay\u003Cbr>• ICE handling\u003Cbr>• DTMF processing\u003Cbr>• IVR interaction\u003C\u002Fspan>\u003C\u002Fp>",{"title":869,"content":870},"Tích hợp Kamailio ↔ RTPEngine","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Kết nối Kamailio với RTPEngine thông qua socket\u003Cbr>\u003Cbr>→ Kiểm tra:\u003Cbr>\u003Cbr>• RTP relay hoạt động\u003Cbr>• Module load thành công\u003Cbr>• Media proxy kết nối ổn định\u003C\u002Fspan>\u003C\u002Fp>",{"title":727,"content":872},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Setup thành công cụm SIP Server + Media Proxy\u003Cbr>→ Hiểu rõ vai trò của Kamailio và RTPEngine\u003Cbr>→ Làm chủ RTP relay trong hệ thống VoIP\u003Cbr>→ Chuẩn bị hạ tầng production-ready cho SIP Integration\u003Cbr>→ Sẵn sàng triển khai SIP-to-App và App-to-SIP\u003Cbr>\u003Cbr>Đây là bước chuẩn bị cực kỳ quan trọng trước khi chúng ta thực hiện các cuộc gọi thực tế từ Softphone xuyên qua Telco Simulator vào Rust Server.\u003C\u002Fspan>\u003C\u002Fp>",{"title":874,"content":875},"Tài nguyên bài học:","\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fwww.kamailio.org\u002Fw\u002F2026\u002F01\u002Fkamailio-v5-8-7-released\u002F\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fwww.kamailio.org\u002Fw\u002F2026\u002F01\u002Fkamailio-v5-8-7-released\u002F\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fwww.kamailio.org\u002Fdocs\u002Fmodules\u002F5.8.x\u002F\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fwww.kamailio.org\u002Fdocs\u002Fmodules\u002F5.8.x\u002F\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fwww.kamailio.org\u002Fdocs\u002Fmodules\u002F5.8.x\u002Fmodules\u002Frtpengine.html#id1355\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fwww.kamailio.org\u002Fdocs\u002Fmodules\u002F5.8.x\u002Fmodules\u002Frtpengine.html#id1355\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fkamailio\u002Fkamailio\u002Ftree\u002F5.8.7\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fgithub.com\u002Fkamailio\u002Fkamailio\u002Ftree\u002F5.8.7\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fsipwise\u002Frtpengine\u002Ftree\u002Fmr13.3.1.4\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fgithub.com\u002Fsipwise\u002Frtpengine\u002Ftree\u002Fmr13.3.1.4\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003Cbr>Source code: \u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsetup-kamailio-rtp-engine\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsetup-kamailio-rtp-engine\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fp>",{"slug":169,"title":170,"description":171,"duration":172,"youtubeId":173,"order":174,"thumbnail":175,"createdAt":176,"updatedAt":177,"sections":877},[878,881,884,887,890,892],{"title":879,"content":880},"Cấu hình Dispatcher tại Telco Simulator","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Update dispatcher.list:\u003Cbr>\u003Cbr>• Trỏ về Kamailio Server\u003Cbr>• SIP Port 5061\u003Cbr>\u003Cbr>→ Setup routing logic:\u003Cbr>\u003Cbr>• Khi gọi tới đầu số giả lập:\u003Cbr>  - 1900 1098\u003Cbr>• Telco Simulator sẽ tự động:\u003Cbr>  - Forward SIP INVITE\u003Cbr>  - Route sang Kamailio\u003C\u002Fspan>\u003C\u002Fp>",{"title":882,"content":883},"Xử lý SIP Message tại Kamailio","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Sử dụng Kamailio Cookbook để:\u003Cbr>\u003Cbr>• Setup global variable\u003Cbr>• Kiểm tra SIP request\u003Cbr>• Xử lý routing logic\u003Cbr>\u003Cbr>→ Nhận SIP INVITE\u003Cbr>\u003Cbr>→ Extract SDP từ body request\u003Cbr>\u003Cbr>→ Forward SIP message bằng:\u003Cbr>\u003Cbr>• t_relay()\u003Cbr>\u003Cbr>→ Relay sang Rust Server:\u003Cbr>\u003Cbr>• UDP protocol\u003Cbr>• Port 9982\u003C\u002Fspan>\u003C\u002Fp>",{"title":885,"content":886},"Xây dựng UDP Server trong Rust","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Tạo module shift_transport\u003Cbr>\u003Cbr>→ Bind UDP socket:\u003Cbr>\u003Cbr>• Public IP\u003Cbr>• UDP Port\u003Cbr>\u003Cbr>→ Implement receive_loop:\u003Cbr>\u003Cbr>• Chạy trên thread riêng\u003Cbr>• Listen liên tục từ socket\u003Cbr>• Parse SIP message\u003Cbr>\u003Cbr>→ Sử dụng:\u003Cbr>\u003Cbr>• Arc\u003Cbr>• Shared State\u003Cbr>\u003Cbr>để quản lý kết nối trong toàn hệ thống.\u003C\u002Fspan>\u003C\u002Fp>",{"title":888,"content":889},"Testing Signaling Flow","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">📞 Luồng cuộc gọi thực tế:\u003Cbr>\u003Cbr>Zoiper\u003Cbr>→ Telco Simulator\u003Cbr>→ Kamailio\u003Cbr>→ Rust Server\u003Cbr>\u003Cbr>→ Theo dõi log thực tế:\u003Cbr>\u003Cbr>• SIP INVITE\u003Cbr>• SDP\u003Cbr>• Record-Route\u003Cbr>• Via Header\u003Cbr>\u003Cbr>→ Kiểm tra Rust Server nhận SIP message thành công\u003C\u002Fspan>\u003C\u002Fp>",{"title":727,"content":891},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Route thành công SIP signaling từ Phone → Rust\u003Cbr>→ Hiểu cách hoạt động của SIP Proxy chain\u003Cbr>→ Làm chủ UDP socket trong Rust\u003Cbr>→ Parse và xử lý SIP message cơ bản\u003Cbr>→ Chuẩn bị nền tảng cho SIP-to-App flow\u003Cbr>\u003Cbr>Đây là bước cực kỳ quan trọng trước khi xử lý SIP INVITE, SDP negotiation và media bridging với Janus Media Server.\u003C\u002Fspan>\u003C\u002Fp>",{"title":874,"content":893},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">Kamailio Cookbook:\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fwww.kamailio.org\u002Fdocs\u002Fmodules\u002F5.8.x\u002F\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fwww.kamailio.org\u002Fdocs\u002Fmodules\u002F5.8.x\u002F\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fwww.kamailio.org\u002Fwikidocs\u002F#cookbooks\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fwww.kamailio.org\u002Fwikidocs\u002F#cookbooks\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fwww.kamailio.org\u002Fwikidocs\u002Fcookbooks\u002F5.8.x\u002Fpseudovariables\u002F\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fwww.kamailio.org\u002Fwikidocs\u002Fcookbooks\u002F5.8.x\u002Fpseudovariables\u002F\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003Cbr>Source code:\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-1-config-connect-sip-to-rust-server\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-1-config-connect-sip-to-rust-server\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"color: rgb(13, 13, 13);\">\u003Cbr>\u003Cbr>SIP document:\u003Cbr>\u003C\u002Fspan>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc3261\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc3261\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fp>",{"slug":179,"title":180,"description":181,"duration":182,"youtubeId":183,"order":184,"thumbnail":185,"createdAt":186,"updatedAt":187,"sections":895},[896,899,902,905,908,911,913],{"title":897,"content":898},"Parsing SIP Message & Ringing Response","\u003Cp>→ Parse dữ liệu UDP thành SIP Request\u003C\u002Fp>\u003Cp>→ Nhận diện SIP INVITE\u003C\u002Fp>\u003Cp>→ Extract SDP từ SIP Body\u003C\u002Fp>\u003Cp>→ Implement phản hồi:\u003C\u002Fp>\u003Cp>• 180 Ringing\u003C\u002Fp>\u003Cp>→ Gửi signaling ngược về:\u003C\u002Fp>\u003Cp>Phone\u003C\u002Fp>\u003Cp>← Kamailio\u003C\u002Fp>\u003Cp>← Telco Simulator\u003C\u002Fp>",{"title":900,"content":901},"Khởi tạo tài nguyên trên Janus","\u003Cp>→ Create Session\u003C\u002Fp>\u003Cp>→ Attach AudioBridge Plugin\u003C\u002Fp>\u003Cp>→ Create Room\u003C\u002Fp>\u003Cp>→ Xử lý lỗi và duy trì receive loop để server luôn sẵn sàng nhận signaling mới\u003C\u002Fp>",{"title":903,"content":904},"Xây dựng cấu trúc SipToAppCall","\u003Cp>→ Thiết kế SipToAppParam:\u003C\u002Fp>\u003Cp>• SIP INVITE Request\u003C\u002Fp>\u003Cp>• SessionID\u003C\u002Fp>\u003Cp>• HandleID\u003C\u002Fp>\u003Cp>• RoomID\u003C\u002Fp>\u003Cp>• Pin \u002F Secret\u003C\u002Fp>\u003Cp>→ Xây dựng SipToAppCall\u003C\u002Fp>\u003Cp>→ Tích hợp với:\u003C\u002Fp>\u003Cp>• CallSupervisor\u003C\u002Fp>\u003Cp>• Routing System\u003C\u002Fp>\u003Cp>• Janus Event Handling\u003C\u002Fp>",{"title":906,"content":907},"Thiết kế State Machine cho SIP-to-App","\u003Cp>📌 Các state chính:\u003C\u002Fp>\u003Cp>• IdleState\u003C\u002Fp>\u003Cp>• JoinSipMemberToRoomState\u003C\u002Fp>\u003Cp>• ConnectToClientState\u003C\u002Fp>\u003Cp>• TalkingState\u003C\u002Fp>\u003Cp>• EndState\u003C\u002Fp>\u003Cp>→ Xử lý:\u003C\u002Fp>\u003Cp>• State transition\u003C\u002Fp>\u003Cp>• Signaling flow\u003C\u002Fp>\u003Cp>• Cleanup logic\u003C\u002Fp>\u003Cp>• BYE \u002F Busy handling\u003C\u002Fp>\u003Cp>📌 EndState hỗ trợ:\u003C\u002Fp>\u003Cp>• Gửi SIP BYE nếu call đã connect\u003C\u002Fp>\u003Cp>• Trả về 486 Busy nếu reject\u003C\u002Fp>",{"title":909,"content":910},"Build & Testing","\u003Cp>→ Compile &amp; chạy thực tế\u003C\u002Fp>\u003Cp>→ Kiểm tra flow signaling:\u003C\u002Fp>\u003Cp>Phone\u003C\u002Fp>\u003Cp>→ Kamailio\u003C\u002Fp>\u003Cp>→ Rust\u003C\u002Fp>\u003Cp>→ Janus\u003C\u002Fp>",{"title":727,"content":912},"\u003Cp>→ Xây dựng thành công bộ khung SIP-to-App\u003C\u002Fp>\u003Cp>→ Hiểu cách xử lý SIP INVITE trong Rust\u003C\u002Fp>\u003Cp>→ Parse SIP signaling từ UDP socket\u003C\u002Fp>\u003Cp>→ Làm chủ State Machine cho SIP call\u003C\u002Fp>\u003Cp>→ Chuẩn bị môi trường media trên Janus\u003C\u002Fp>\u003Cp>Đây là nền tảng cực kỳ quan trọng trước khi triển khai:\u003C\u002Fp>\u003Cp>• SDP negotiation\u003C\u002Fp>\u003Cp>• RTP bridging\u003C\u002Fp>\u003Cp>• SIP ↔ WebRTC media flow\u003C\u002Fp>\u003Cp>• Phone ↔ Browser calling\u003C\u002Fp>",{"title":858,"content":914},"\u003Cp>Mã nguồn (GitHub):\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-2-init-sip-to-app-call-and-define-state\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-2-init-sip-to-app-call-and-define-state\u003C\u002Fa>\u003C\u002Fp>",{"slug":189,"title":190,"description":191,"duration":192,"youtubeId":193,"order":194,"thumbnail":195,"createdAt":196,"updatedAt":197,"sections":916},[917,920,923,926,929,931],{"title":918,"content":919},"Quản lý SIP Transaction ID trong Rust","\u003Cp>→ Lấy Transaction ID từ SIP INVITE\u003C\u002Fp>\u003Cp>→ Theo dõi trạng thái cuộc gọi\u003C\u002Fp>\u003Cp>→ Thiết lập cơ chế mapping trong CallSupervisor:\u003C\u002Fp>\u003Cp>• pending_transaction\u003C\u002Fp>\u003Cp>• TransactionID ↔ CallID\u003C\u002Fp>\u003Cp>→ Đảm bảo các SIP message tiếp theo được route chính xác tới đúng Call State\u003C\u002Fp>",{"title":921,"content":922},"Kỹ thuật bóc tách SDP (SDP Parsing)","\u003Cp>→ Parse SDP từ Phone\u002FKamailio\u003C\u002Fp>\u003Cp>→ Extract:\u003C\u002Fp>\u003Cp>• Public IP\u003C\u002Fp>\u003Cp>• RTP Port\u003C\u002Fp>\u003Cp>• Codec Information\u003C\u002Fp>\u003Cp>→ Lựa chọn codec phù hợp:\u003C\u002Fp>\u003Cp>• PCMU\u003C\u002Fp>\u003Cp>• PCMA\u003C\u002Fp>\u003Cp>→ Đảm bảo tương thích giữa:\u003C\u002Fp>\u003Cp>• SIP Endpoint\u003C\u002Fp>\u003Cp>• Janus AudioBridge\u003C\u002Fp>",{"title":924,"content":925},"Join RTP Member vào Janus AudioBridge","\u003Cp>📌 Điểm khác biệt quan trọng:\u003C\u002Fp>\u003Cp>→ SIP sử dụng RTP Plane\u003C\u002Fp>\u003Cp>→ WebRTC sử dụng SRTP\u003C\u002Fp>\u003Cp>→ Sử dụng API join với tham số:\u003C\u002Fp>\u003Cp>• rtp\u003C\u002Fp>\u003Cp>→ Đưa SIP Member trực tiếp vào AudioBridge Room\u003C\u002Fp>\u003Cp>→ Thiết lập media flow giữa:\u003C\u002Fp>\u003Cp>Phone\u003C\u002Fp>\u003Cp>↔ RTP\u003C\u002Fp>\u003Cp>↔ Janus Media Server\u003C\u002Fp>",{"title":927,"content":928},"Hiện thực hóa State Machine","\u003Cp>→ Implement:\u003C\u002Fp>\u003Cp>• JoinSipMemberToRoomState\u003C\u002Fp>\u003Cp>→ Xử lý on_enter()\u003C\u002Fp>\u003Cp>→ Logic chuyển state:\u003C\u002Fp>\u003Cp>• Success:\u003C\u002Fp>\u003Cp>  → ConnectToClientState\u003C\u002Fp>\u003Cp>• Failure:\u003C\u002Fp>\u003Cp>  → 486 Busy\u003C\u002Fp>\u003Cp>  → EndState\u003C\u002Fp>\u003Cp>→ Thiết lập timeout\u002Ftimer để xử lý các trường hợp join room thất bại hoặc quá thời gian\u003C\u002Fp>",{"title":683,"content":930},"\u003Cp>Sau bài học này, bạn sẽ:\u003C\u002Fp>\u003Cp>→ Làm chủ SIP Transaction Mapping\u003C\u002Fp>\u003Cp>→ Parse SDP trong Rust\u003C\u002Fp>\u003Cp>→ Hiểu rõ RTP flow của SIP\u003C\u002Fp>\u003Cp>→ Đưa SIP Member vào Janus AudioBridge\u003C\u002Fp>\u003Cp>→ Xây dựng State Machine cho SIP-to-App\u003C\u002Fp>\u003Cp>Đây là bước cực kỳ quan trọng trước khi triển khai:\u003C\u002Fp>\u003Cp>• RTP bridging\u003C\u002Fp>\u003Cp>• SIP ↔ WebRTC media flow\u003C\u002Fp>\u003Cp>• Browser ↔ Phone calling\u003C\u002Fp>\u003Cp>• Production VoIP system\u003C\u002Fp>",{"title":858,"content":932},"\u003Cp>Mã nguồn tham khảo:\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-3-connect-to-callee\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-3-connect-to-callee\u003C\u002Fa>\u003C\u002Fp>\u003Cp>Tài liệu Janus AudioBridge (RTP Join):\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge.html\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge.html\u003C\u002Fa>\u003C\u002Fp>",{"slug":199,"title":200,"description":201,"duration":202,"youtubeId":203,"order":204,"thumbnail":205,"createdAt":206,"updatedAt":207,"sections":934},[935,938,940,943,946,948],{"title":936,"content":937},"Tích hợp RTPEngine và cấu hình Kamailio","\u003Cp>→ Lọc HTTP Method:\u003C\u002Fp>\u003Cp>• Reject:\u003C\u002Fp>\u003Cp>  - GET\u003C\u002Fp>\u003Cp>  - POST\u003C\u002Fp>\u003Cp>  - Non-SIP request\u003C\u002Fp>\u003Cp>→ Tăng tính bảo mật cho SIP Server\u003C\u002Fp>\u003Cp>→ Quản lý Max-Forwards:\u003C\u002Fp>\u003Cp>• Tránh SIP Loop\u003C\u002Fp>\u003Cp>• Ngăn signaling chạy vòng vô hạn\u003C\u002Fp>\u003Cp>→ Tích hợp RTPEngine:\u003C\u002Fp>\u003Cp>• Sử dụng:\u003C\u002Fp>\u003Cp>  - rtpengine_offer()\u003C\u002Fp>\u003Cp>→ Rewrite SDP:\u003C\u002Fp>\u003Cp>• Origin\u003C\u002Fp>\u003Cp>• Connection\u003C\u002Fp>\u003Cp>• RTP Port\u003C\u002Fp>\u003Cp>→ Ép media flow đi qua RTPEngine Proxy\u003C\u002Fp>\u003Cp>→ Record-Route:\u003C\u002Fp>\u003Cp>• Đánh dấu routing path\u003C\u002Fp>\u003Cp>• Đảm bảo SIP response quay về đúng proxy chain\u003C\u002Fp>",{"title":844,"content":939},"\u003Cp>📌 Signaling Path:\u003C\u002Fp>\u003Cp>Phone\u003C\u002Fp>\u003Cp>→ Kamailio\u003C\u002Fp>\u003Cp>→ Rust\u003C\u002Fp>\u003Cp>→ Janus\u003C\u002Fp>\u003Cp>📌 Media Path:\u003C\u002Fp>\u003Cp>Phone\u003C\u002Fp>\u003Cp>→ RTPEngine\u003C\u002Fp>\u003Cp>→ Janus AudioBridge\u003C\u002Fp>\u003Cp>→ Signaling và Media hoàn toàn tách biệt\u003C\u002Fp>\u003Cp>→ Kamailio điều khiển RTPEngine bằng:\u003C\u002Fp>\u003Cp>• offer\u003C\u002Fp>\u003Cp>• answer\u003C\u002Fp>\u003Cp>→ RTPEngine quản lý:\u003C\u002Fp>\u003Cp>• RTP relay\u003C\u002Fp>\u003Cp>• NAT traversal\u003C\u002Fp>\u003Cp>• Media forwarding\u003C\u002Fp>",{"title":941,"content":942},"Giải quyết vấn đề Janus không trả về RTP Object","\u003Cp>📌 Vấn đề thực tế:\u003C\u002Fp>\u003Cp>→ Khi join RTP member vào AudioBridge\u003C\u002Fp>\u003Cp>→ Janus đôi khi không trả về:\u003C\u002Fp>\u003Cp>• RTP IP\u003C\u002Fp>\u003Cp>• RTP Port\u003C\u002Fp>\u003Cp>trong event mặc định.\u003C\u002Fp>\u003Cp>📌 Giải pháp:\u003C\u002Fp>\u003Cp>→ Sử dụng Janus Admin API\u003C\u002Fp>\u003Cp>→ get_handler_info()\u003C\u002Fp>\u003Cp>→ Query trực tiếp thông tin Handle\u003C\u002Fp>\u003Cp>→ Lấy Plane RTP Info:\u003C\u002Fp>\u003Cp>• Public IP\u003C\u002Fp>\u003Cp>• RTP Port\u003C\u002Fp>\u003Cp>• RTP Session Information\u003C\u002Fp>\u003Cp>📌 Đây là một kỹ thuật cực kỳ quan trọng trong production VoIP system.\u003C\u002Fp>",{"title":944,"content":945},"Chuẩn bị SDP Answer","\u003Cp>→ Sau khi lấy được RTP info từ Janus:\u003C\u002Fp>\u003Cp>• IP Address\u003C\u002Fp>\u003Cp>• RTP Port\u003C\u002Fp>\u003Cp>→ Chuẩn bị generate:\u003C\u002Fp>\u003Cp>• SDP Answer\u003C\u002Fp>\u003Cp>→ Trả SDP ngược về:\u003C\u002Fp>\u003Cp>Kamailio\u003C\u002Fp>\u003Cp>→ RTPEngine\u003C\u002Fp>\u003Cp>→ SIP Phone\u003C\u002Fp>\u003Cp>→ Hoàn tất bước chuẩn bị media negotiation cho SIP-to-App flow.\u003C\u002Fp>",{"title":727,"content":947},"\u003Cp>Sau bài học này, bạn sẽ:\u003C\u002Fp>\u003Cp>→ Làm chủ RTPEngine integration với Kamailio\u003C\u002Fp>\u003Cp>→ Hiểu sâu về SIP signaling vs RTP media flow\u003C\u002Fp>\u003Cp>→ Xử lý NAT và Local IP trong VoIP\u003C\u002Fp>\u003Cp>→ Sử dụng Janus Admin API trong production\u003C\u002Fp>\u003Cp>→ Lấy RTP endpoint thực tế từ Janus\u003C\u002Fp>\u003Cp>→ Chuẩn bị SDP Answer cho SIP-to-App\u003C\u002Fp>\u003Cp>Đây là bước cực kỳ quan trọng trước khi hoàn thiện media negotiation giữa:\u003C\u002Fp>\u003Cp>📞 SIP Phone\u003C\u002Fp>\u003Cp>↔ RTP\u003C\u002Fp>\u003Cp>↔ Janus\u003C\u002Fp>\u003Cp>↔ WebRTC Browser\u003C\u002Fp>",{"title":858,"content":949},"\u003Cp>Source code:\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-4-connect-to-callee-and-taking-state\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fcall-app-to-app-part-4-connect-to-callee-and-taking-state\u003C\u002Fa>\u003C\u002Fp>\u003Cp>Janus AudioBridge:\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge.html\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge.html\u003C\u002Fa>\u003C\u002Fp>\u003Cp>Janus Admin API:\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Fadmin.html\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Fadmin.html\u003C\u002Fa>\u003C\u002Fp>\u003Cp>Kamailio RTPEngine Module:\u003C\u002Fp>\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fwww.kamailio.org\u002Fdocs\u002Fmodules\u002F5.8.x\u002Fmodules\u002Frtpengine.html#rtpengine.f.rtpengine_offer\">https:\u002F\u002Fwww.kamailio.org\u002Fdocs\u002Fmodules\u002F5.8.x\u002Fmodules\u002Frtpengine.html#rtpengine.f.rtpengine_offer\u003C\u002Fa>\u003C\u002Fp>",{"slug":209,"title":210,"description":211,"duration":212,"youtubeId":213,"order":214,"thumbnail":215,"createdAt":216,"updatedAt":217,"sections":951},[952,955,958,961,964,966],{"title":953,"content":954},"Khai thác Janus Admin API","\u003Cp>📌 Vấn đề thực tế:\u003C\u002Fp>\u003Cp>→ Janus Event mặc định đôi khi không trả về:\u003C\u002Fp>\u003Cp>• RTP IP\u003C\u002Fp>\u003Cp>• RTP Port\u003C\u002Fp>\u003Cp>→ Điều này khiến hệ thống không thể build SDP Answer chính xác.\u003C\u002Fp>\u003Cp>📌 Giải pháp:\u003C\u002Fp>\u003Cp>→ Sử dụng:\u003C\u002Fp>\u003Cp>• Janus Admin API\u003C\u002Fp>\u003Cp>• get_handler_info()\u003C\u002Fp>\u003Cp>→ Truy cập sâu vào:\u003C\u002Fp>\u003Cp>• plane-rtp object\u003C\u002Fp>\u003Cp>→ Extract:\u003C\u002Fp>\u003Cp>• Local IP\u003C\u002Fp>\u003Cp>• Local RTP Port\u003C\u002Fp>\u003Cp>→ Lấy thông tin RTP thực tế từ AudioBridge plugin.\u003C\u002Fp>",{"title":956,"content":957},"Xây dựng SDP Answer","\u003Cp>→ Kết hợp:\u003C\u002Fp>\u003Cp>• RTP IP\u003C\u002Fp>\u003Cp>• RTP Port\u003C\u002Fp>\u003Cp>• Codec Information\u003C\u002Fp>\u003Cp>→ Build SDP Answer hoàn chỉnh để trả về phía SIP Proxy.\u003C\u002Fp>\u003Cp>📌 Hỗ trợ codec:\u003C\u002Fp>\u003Cp>• PCMU\u003C\u002Fp>\u003Cp>• PCMA\u003C\u002Fp>\u003Cp>→ Xử lý SDP Direction:\u003C\u002Fp>\u003Cp>• sendrecv\u003C\u002Fp>\u003Cp>• sendonly\u003C\u002Fp>\u003Cp>• recvonly\u003C\u002Fp>\u003Cp>→ Điều khiển luồng media\u002Faudio giữa:\u003C\u002Fp>\u003Cp>📞 SIP Phone\u003C\u002Fp>\u003Cp>↔ RTP\u003C\u002Fp>\u003Cp>↔ Janus\u003C\u002Fp>",{"title":959,"content":960},"Giao tiếp SIP & Quản lý Dialog","\u003Cp>📌 Sử dụng:\u003C\u002Fp>\u003Cp>• 183 Session Progress\u003C\u002Fp>\u003Cp>thay vì:\u003C\u002Fp>\u003Cp>• 200 OK\u003C\u002Fp>\u003Cp>→ Thiết lập Early Media.\u003C\u002Fp>\u003Cp>📌 Early Media cho phép:\u003C\u002Fp>\u003Cp>• Nhạc chờ\u003C\u002Fp>\u003Cp>• Ringback tone\u003C\u002Fp>\u003Cp>• Announcement\u003C\u002Fp>\u003Cp>trước khi cuộc gọi được accept hoàn toàn.\u003C\u002Fp>\u003Cp>→ Khởi tạo:\u003C\u002Fp>\u003Cp>• To-Tag\u003C\u002Fp>\u003Cp>• Dialog ID\u003C\u002Fp>\u003Cp>→ Cập nhật CallSupervisor để:\u003C\u002Fp>\u003Cp>• Mapping SIP Dialog\u003C\u002Fp>\u003Cp>• Route ACK\u002FBYE đúng Call State\u003C\u002Fp>",{"title":962,"content":963},"Transition sang ConnectToAgentState","\u003Cp>→ Sau khi SIP Member join thành công vào Janus:\u003C\u002Fp>\u003Cp>• Transition:\u003C\u002Fp>\u003Cp>→ ConnectToAgentState\u003C\u002Fp>\u003Cp>→ Chuẩn bị kết nối:\u003C\u002Fp>\u003Cp>📞 SIP Phone\u003C\u002Fp>\u003Cp>↔ Janus\u003C\u002Fp>\u003Cp>↔ WebRTC Client\u003C\u002Fp>\u003Cp>📌 Demo thực tế:\u003C\u002Fp>\u003Cp>• Zoiper chuyển từ:\u003C\u002Fp>\u003Cp>* Ringing\u003C\u002Fp>\u003Cp>* Early Media\u003C\u002Fp>\u003Cp>→ Theo dõi log signaling trên Rust Server.\u003C\u002Fp>",{"title":727,"content":965},"\u003Cp>→ Làm chủ Janus Admin API\u003C\u002Fp>\u003Cp>→ Build SDP Answer trong Rust\u003C\u002Fp>\u003Cp>→ Hiểu sâu về Early Media trong SIP\u003C\u002Fp>\u003Cp>→ Quản lý SIP Dialog &amp; To-Tag\u003C\u002Fp>\u003Cp>→ Điều phối RTP flow với Janus\u003C\u002Fp>\u003Cp>→ Hoàn thiện Join SIP Member State\u003C\u002Fp>\u003Cp>Đây là bước cực kỳ quan trọng trước khi triển khai:\u003C\u002Fp>\u003Cp>• SIP ↔ WebRTC media bridge\u003C\u002Fp>\u003Cp>• Browser ↔ Phone calling\u003C\u002Fp>\u003Cp>• Production VoIP system\u003C\u002Fp>\u003Cp>• Full SIP-to-App flow\u003C\u002Fp>",{"title":669,"content":967},"\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-5-join-sip-member-to-room-build-leg\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-5-join-sip-member-to-room-build-leg\u003C\u002Fa>\u003C\u002Fp>",{"slug":219,"title":220,"description":221,"duration":222,"youtubeId":223,"order":224,"thumbnail":225,"createdAt":226,"updatedAt":227,"sections":969},[970,973,976,979,982,984],{"title":971,"content":972},"Khởi tạo trạng thái ConnectToAgentState","\u003Cp>→ Implement:\u003C\u002Fp>\u003Cp>• send_incoming_call()\u003C\u002Fp>\u003Cp>→ Gửi incoming call notification tới Agent\u003C\u002Fp>\u003Cp>📌 Demo hiện tại:\u003C\u002Fp>\u003Cp>• Sử dụng Agent ID cố định\u003C\u002Fp>\u003Cp>→ Thiết lập Timer:\u003C\u002Fp>\u003Cp>• Resend Timer:\u003C\u002Fp>\u003Cp>* 5 giây gửi lại incoming call\u003C\u002Fp>\u003Cp>• Timeout Timer:\u003C\u002Fp>\u003Cp>* Auto reject nếu Agent không bắt máy\u003C\u002Fp>\u003Cp>→ Đảm bảo cuộc gọi không bị treo vô hạn.\u003C\u002Fp>",{"title":974,"content":975},"Xử lý WebSocket Event từ Client","\u003Cp>→ Lắng nghe signaling từ Browser qua WebSocket\u003C\u002Fp>\u003Cp>📌 Xử lý response code:\u003C\u002Fp>\u003Cp>• 486 Busy\u003C\u002Fp>\u003Cp>• 200 OK\u003C\u002Fp>\u003Cp>→ Nếu Agent accept:\u003C\u002Fp>\u003Cp>• Create\u002FGet Janus Handle\u003C\u002Fp>\u003Cp>• Join AudioBridge Room\u003C\u002Fp>\u003Cp>• Configure SDP cho WebRTC Client\u003C\u002Fp>\u003Cp>→ Chuẩn bị media flow giữa:\u003C\u002Fp>\u003Cp>📞 SIP Phone\u003C\u002Fp>\u003Cp>↔ Janus\u003C\u002Fp>\u003Cp>↔ WebRTC Browser\u003C\u002Fp>",{"title":977,"content":978},"Xử lý Janus Event từ Media Server","\u003Cp>→ Parse Janus Event\u003C\u002Fp>\u003Cp>→ Extract:\u003C\u002Fp>\u003Cp>• SDP Answer\u003C\u002Fp>\u003Cp>• Local SDP\u003C\u002Fp>\u003Cp>→ SDP Notify:\u003C\u002Fp>\u003Cp>• Gửi SDP về Browser\u003C\u002Fp>\u003Cp>→ Browser thực hiện:\u003C\u002Fp>\u003Cp>• setRemoteDescription()\u003C\u002Fp>\u003Cp>→ Hoàn tất quá trình WebRTC handshake.\u003C\u002Fp>",{"title":980,"content":981},"Transition sang TalkingState","\u003Cp>📌 Theo dõi event:\u003C\u002Fp>\u003Cp>• webrtc_up\u003C\u002Fp>\u003Cp>→ Đây là tín hiệu cho thấy:\u003C\u002Fp>\u003Cp>• WebRTC connection established thành công\u003C\u002Fp>\u003Cp>→ State transition:\u003C\u002Fp>\u003Cp>• ConnectToAgentState\u003C\u002Fp>\u003Cp>→ TalkingState\u003C\u002Fp>\u003Cp>📌 Sau bước này:\u003C\u002Fp>\u003Cp>📞 SIP Phone\u003C\u002Fp>\u003Cp>↔ RTP\u003C\u002Fp>\u003Cp>↔ Janus\u003C\u002Fp>\u003Cp>↔ WebRTC Browser\u003C\u002Fp>\u003Cp>đã có thể đàm thoại thực tế.\u003C\u002Fp>",{"title":683,"content":983},"\u003Cp>→ Hoàn thiện ConnectToAgentState\u003C\u002Fp>\u003Cp>→ Gửi incoming call tới WebRTC Client\u003C\u002Fp>\u003Cp>→ Xử lý signaling qua WebSocket\u003C\u002Fp>\u003Cp>→ Thực hiện SDP negotiation với Janus\u003C\u002Fp>\u003Cp>→ Điều phối Janus Event &amp; WebSocket Event\u003C\u002Fp>\u003Cp>→ Hoàn thiện kết nối SIP ↔ WebRTC\u003C\u002Fp>\u003Cp>Đây là bước cực kỳ quan trọng trước khi triển khai:\u003C\u002Fp>\u003Cp>• Talking State\u003C\u002Fp>\u003Cp>• Media streaming\u003C\u002Fp>\u003Cp>• Production SIP-to-App flow\u003C\u002Fp>\u003Cp>• Browser ↔ Phone calling system\u003C\u002Fp>",{"title":985,"content":986},"📦 Source code:","\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-6-connect-to-agent\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-6-connect-to-agent\u003C\u002Fa>\u003C\u002Fp>",{"slug":229,"title":230,"description":231,"duration":232,"youtubeId":233,"order":234,"thumbnail":235,"createdAt":236,"updatedAt":237,"sections":988},[989,992,995,998,1001,1003],{"title":990,"content":991},"Xử lý SIP CANCEL & Pending Transaction","\u003Cp>→ Detect SIP CANCEL tại SipTransport\u003C\u002Fp>\u003Cp>→ Implement:\u003C\u002Fp>\u003Cp>• get_pending_transition()\u003C\u002Fp>\u003Cp>→ Lấy SIP INVITE đang pending\u003C\u002Fp>\u003Cp>→ Trả về:\u003C\u002Fp>\u003Cp>• 200 OK cho CANCEL\u003C\u002Fp>\u003Cp>📌 Mục tiêu:\u003C\u002Fp>\u003Cp>→ Ngăn SIP Server gửi retransmission liên tục.\u003C\u002Fp>\u003Cp>→ Route sự kiện CANCEL vào đúng Call State thông qua:\u003C\u002Fp>\u003Cp>• CallSupervisor\u003C\u002Fp>",{"title":993,"content":994},"Hiện thực hóa EndState","\u003Cp>📌 Cleanup toàn bộ resource:\u003C\u002Fp>\u003Cp>→ Stop:\u003C\u002Fp>\u003Cp>• KeepAlive Timer\u003C\u002Fp>\u003Cp>• Call Supervisor\u003C\u002Fp>\u003Cp>→ Notify WebRTC Client qua WebSocket:\u003C\u002Fp>\u003Cp>• Call Ended\u003C\u002Fp>\u003Cp>→ Cleanup Janus Resource:\u003C\u002Fp>\u003Cp>• Delete Room\u003C\u002Fp>\u003Cp>• Detach Handle\u003C\u002Fp>\u003Cp>• Destroy Session\u003C\u002Fp>\u003Cp>📌 SIP Response Handling:\u003C\u002Fp>\u003Cp>→ try_send_bye()\u003C\u002Fp>\u003Cp>→ Hoặc gửi:\u003C\u002Fp>\u003Cp>• 486 Busy\u003C\u002Fp>\u003Cp>• Error Response\u003C\u002Fp>\u003Cp>tùy theo trạng thái cuộc gọi.\u003C\u002Fp>",{"title":996,"content":997},"Quản lý SIP Dialog & Advanced SIP Method","\u003Cp>→ Tìm Call bằng:\u003C\u002Fp>\u003Cp>• Dialog ID\u003C\u002Fp>\u003Cp>→ Xử lý các SIP method:\u003C\u002Fp>\u003Cp>• BYE\u003C\u002Fp>\u003Cp>• ACK\u003C\u002Fp>\u003Cp>• PRACK\u003C\u002Fp>\u003Cp>📌 Hỗ trợ Early Media flow:\u003C\u002Fp>\u003Cp>• 183 Session Progress\u003C\u002Fp>\u003Cp>→ Auto reply:\u003C\u002Fp>\u003Cp>• 200 OK cho BYE\u003C\u002Fp>\u003Cp>→ Đóng SIP Dialog chính xác.\u003C\u002Fp>",{"title":999,"content":1000},"Đồng bộ WebSocket & ICE Candidate","\u003Cp>→ Tích hợp xử lý:\u003C\u002Fp>\u003Cp>• ICE Candidate\u003C\u002Fp>\u003Cp>• ICE Candidate Complete\u003C\u002Fp>\u003Cp>cho SIP-to-App flow.\u003C\u002Fp>\u003Cp>→ Đồng bộ signaling giữa:\u003C\u002Fp>\u003Cp>📞 SIP Phone\u003C\u002Fp>\u003Cp>↔ Kamailio\u003C\u002Fp>\u003Cp>↔ Rust\u003C\u002Fp>\u003Cp>↔ Janus\u003C\u002Fp>\u003Cp>↔ WebRTC Browser\u003C\u002Fp>\u003Cp>→ Đảm bảo media negotiation hoạt động ổn định.\u003C\u002Fp>",{"title":727,"content":1002},"\u003Cp>Sau bài học này, bạn sẽ:\u003C\u002Fp>\u003Cp>→ Làm chủ EndState trong SIP-to-App\u003C\u002Fp>\u003Cp>→ Xử lý SIP CANCEL\u002FBYE\u002FACK\u002FPRACK\u003C\u002Fp>\u003Cp>→ Cleanup tài nguyên Janus đúng cách\u003C\u002Fp>\u003Cp>→ Quản lý SIP Dialog chuyên nghiệp\u003C\u002Fp>\u003Cp>→ Tránh SIP retransmission loop\u003C\u002Fp>\u003Cp>→ Đồng bộ ICE Candidate với WebRTC\u003C\u002Fp>\u003Cp>Đây là bước cực kỳ quan trọng trước khi triển khai:\u003C\u002Fp>\u003Cp>• Talking State\u003C\u002Fp>\u003Cp>• Media streaming\u003C\u002Fp>\u003Cp>• RTP bridging\u003C\u002Fp>\u003Cp>• Full SIP ↔ WebRTC production flow\u003C\u002Fp>",{"title":1004,"content":1005},"📦 Source code","\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-7-process-end-state\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-7-process-end-state\u003C\u002Fa>\u003C\u002Fp>",{"slug":239,"title":240,"description":241,"duration":242,"youtubeId":243,"order":244,"thumbnail":245,"createdAt":246,"updatedAt":247,"sections":1007},[1008,1011,1014,1017,1020,1023,1025],{"title":1009,"content":1010},"Định nghĩa TalkingState trong Rust","\u003Cp>→ Implement:\u003C\u002Fp>\u003Cp>• TalkingState\u003C\u002Fp>\u003Cp>• on_enter()\u003C\u002Fp>\u003Cp>• on_exit()\u003C\u002Fp>\u003Cp>📌 TalkingState được kích hoạt khi:\u003C\u002Fp>\u003Cp>• webrtc_up event\u003C\u002Fp>\u003Cp>được gửi từ Janus Media Server.\u003C\u002Fp>\u003Cp>→ Đây là tín hiệu xác nhận:\u003C\u002Fp>\u003Cp>• WebRTC connection established\u003C\u002Fp>\u003Cp>• Media path đã sẵn sàng\u003C\u002Fp>",{"title":1012,"content":1013},"Build SIP 200 OK & SDP Answer","\u003Cp>→ Sử dụng SipUtil để build:\u003C\u002Fp>\u003Cp>• SIP 200 OK\u003C\u002Fp>\u003Cp>→ Đính kèm:\u003C\u002Fp>\u003Cp>• SDP Answer hoàn chỉnh\u003C\u002Fp>\u003Cp>📌 Xử lý các SIP Header quan trọng:\u003C\u002Fp>\u003Cp>• To-Tag\u003C\u002Fp>\u003Cp>• Contact\u003C\u002Fp>\u003Cp>• Via\u003C\u002Fp>\u003Cp>• Record-Route\u003C\u002Fp>\u003Cp>→ Đảm bảo SIP Dialog hoạt động chính xác.\u003C\u002Fp>\u003Cp>📌 Đồng bộ trạng thái với WebRTC Client:\u003C\u002Fp>\u003Cp>→ Notify Browser:\u003C\u002Fp>\u003Cp>• Call Connected\u003C\u002Fp>",{"title":1015,"content":1016},"Quản lý Event trong TalkingState","\u003Cp>📌 Theo dõi Janus Event:\u003C\u002Fp>\u003Cp>• left_room\u003C\u002Fp>\u003Cp>• destroyed\u003C\u002Fp>\u003Cp>→ Nếu Room bị đóng:\u003C\u002Fp>\u003Cp>• Auto hangup cuộc gọi\u003C\u002Fp>\u003Cp>📌 Xử lý tín hiệu kết thúc cuộc gọi:\u003C\u002Fp>\u003Cp>• SIP BYE từ Phone\u003C\u002Fp>\u003Cp>• Hangup từ Browser\u003C\u002Fp>\u003Cp>→ Cleanup signaling &amp; state transition chính xác.\u003C\u002Fp>",{"title":1018,"content":1019},"Xử lý ACK & Hoàn thiện SIP Signaling","\u003Cp>→ Detect SIP ACK\u003C\u002Fp>\u003Cp>→ Xác nhận:\u003C\u002Fp>\u003Cp>• Call Established thành công\u003C\u002Fp>\u003Cp>📌 Fix các vấn đề routing:\u003C\u002Fp>\u003Cp>• BYE routing\u003C\u002Fp>\u003Cp>• Dialog mapping\u003C\u002Fp>\u003Cp>• State transition\u003C\u002Fp>\u003Cp>→ Đảm bảo SIP signaling flow hoàn chỉnh theo chuẩn viễn thông.\u003C\u002Fp>",{"title":1021,"content":1022},"Demo & Testing thực tế","\u003Cp>Zoiper\u003C\u002Fp>\u003Cp>→ Kamailio\u003C\u002Fp>\u003Cp>→ Rust\u003C\u002Fp>\u003Cp>→ Janus\u003C\u002Fp>\u003Cp>→ WebRTC Browser\u003C\u002Fp>\u003Cp>📌 Kiểm tra trạng thái trên Zoiper:\u003C\u002Fp>\u003Cp>• Ringing\u003C\u002Fp>\u003Cp>• Early Media\u003C\u002Fp>\u003Cp>• Talking Timer\u003C\u002Fp>\u003Cp>→ Xác nhận:\u003C\u002Fp>\u003Cp>• 200 OK thành công\u003C\u002Fp>\u003Cp>• ACK received\u003C\u002Fp>\u003Cp>• SIP Dialog established\u003C\u002Fp>\u003Cp>📌 Phân tích signaling log trên Rust Server.\u003C\u002Fp>",{"title":727,"content":1024},"\u003Cp>→ Hoàn thiện TalkingState cho SIP-to-App\u003C\u002Fp>\u003Cp>→ Build SIP 200 OK trong Rust\u003C\u002Fp>\u003Cp>→ Xử lý ACK &amp; SIP Dialog\u003C\u002Fp>\u003Cp>→ Điều phối signaling giữa SIP ↔ WebRTC\u003C\u002Fp>\u003Cp>→ Quản lý lifecycle trong TalkingState\u003C\u002Fp>\u003Cp>→ Hoàn thiện toàn bộ SIP-to-App signaling flow\u003C\u002Fp>\u003Cp>Đây là bước cực kỳ quan trọng trước khi triển khai:\u003C\u002Fp>\u003Cp>• RTP audio processing\u003C\u002Fp>\u003Cp>• Media streaming optimization\u003C\u002Fp>\u003Cp>• Production VoIP system\u003C\u002Fp>\u003Cp>• Full SIP ↔ WebRTC communication\u003C\u002Fp>",{"title":985,"content":1026},"\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-8-talking-state\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-8-talking-state\u003C\u002Fa>\u003C\u002Fp>",{"slug":249,"title":250,"description":251,"duration":252,"youtubeId":253,"order":254,"thumbnail":255,"createdAt":256,"updatedAt":257,"sections":1028},[1029,1032,1035,1038,1041,1044,1046],{"title":1030,"content":1031},"Ở bài trước, chúng ta đã hoàn thành toàn bộ signaling flow cho cuộc gọi SIP-to-App. Tuy nhiên, thực tế hệ thống vẫn chưa có âm thanh hai chiều giữa:","\u003Cp>📞 SIP Phone\u003C\u002Fp>\u003Cp>↔ Janus Media Server\u003C\u002Fp>\u003Cp>↔ WebRTC Browser\u003C\u002Fp>\u003Cp>Đây là một vấn đề cực kỳ phổ biến trong VoIP:\u003C\u002Fp>\u003Cp>→ Signaling hoạt động\u003C\u002Fp>\u003Cp>→ SIP call connect thành công\u003C\u002Fp>\u003Cp>→ Nhưng media (RTP) lại không truyền được.\u003C\u002Fp>\u003Cp>Trong video này, chúng ta sẽ đi sâu vào kỹ thuật debug RTP\u002Fmedia chuyên nghiệp để tìm ra nguyên nhân gốc rễ của lỗi mất tiếng và xử lý triệt để bằng:\u003C\u002Fp>\u003Cp>• TCPDump\u003C\u002Fp>\u003Cp>• Wireshark\u003C\u002Fp>\u003Cp>• RTPEngine\u003C\u002Fp>\u003Cp>• SDP Rewrite\u003C\u002Fp>",{"title":1033,"content":1034},"Debug RTP với TCPDump & Wireshark","\u003Cp>→ Capture packet trực tiếp trên server bằng:\u003C\u002Fp>\u003Cp>• TCPDump\u003C\u002Fp>\u003Cp>→ Phân tích SIP\u002FSDP bằng:\u003C\u002Fp>\u003Cp>• Wireshark\u003C\u002Fp>\u003Cp>📌 Kiểm tra:\u003C\u002Fp>\u003Cp>• INVITE SDP\u003C\u002Fp>\u003Cp>• 200 OK SDP\u003C\u002Fp>\u003Cp>• RTP IP\u003C\u002Fp>\u003Cp>• RTP Port\u003C\u002Fp>\u003Cp>→ So sánh media flow giữa:\u003C\u002Fp>\u003Cp>• SIP Phone\u003C\u002Fp>\u003Cp>• RTPEngine\u003C\u002Fp>\u003Cp>• Janus\u003C\u002Fp>\u003Cp>📌 Xác định media path thực tế.\u003C\u002Fp>",{"title":1036,"content":1037},"Phát hiện Root Cause của lỗi mất tiếng","\u003Cp>📌 Phân tích vấn đề:\u003C\u002Fp>\u003Cp>→ SDP Offer:\u003C\u002Fp>\u003Cp>• Đi qua RTPEngine\u003C\u002Fp>\u003Cp>→ SDP Answer:\u003C\u002Fp>\u003Cp>• Trả trực tiếp về Janus RTP Port\u003C\u002Fp>\u003Cp>📌 Hậu quả:\u003C\u002Fp>\u003Cp>• Media flow không đối xứng\u003C\u002Fp>\u003Cp>• RTP không đi qua Media Proxy\u003C\u002Fp>\u003Cp>• NAT traversal thất bại\u003C\u002Fp>\u003Cp>• Không có âm thanh hai chiều\u003C\u002Fp>\u003Cp>📌 Đây là lỗi cực kỳ phổ biến trong production VoIP system.\u003C\u002Fp>",{"title":1039,"content":1040},"Cấu hình Kamailio xử lý SDP Answer","\u003Cp>→ Update:\u003C\u002Fp>\u003Cp>• kamailio.cfg\u003C\u002Fp>\u003Cp>→ Xử lý SIP response có SDP bằng:\u003C\u002Fp>\u003Cp>• rtpengine_manage()\u003C\u002Fp>\u003Cp>📌 Rewrite lại:\u003C\u002Fp>\u003Cp>• Origin\u003C\u002Fp>\u003Cp>• Connection\u003C\u002Fp>\u003Cp>• RTP Port\u003C\u002Fp>\u003Cp>→ Ép toàn bộ media flow đi qua:\u003C\u002Fp>\u003Cp>📌 RTPEngine Proxy\u003C\u002Fp>\u003Cp>thay vì đi trực tiếp tới Janus.\u003C\u002Fp>\u003Cp>📌 Mô hình media chuẩn:\u003C\u002Fp>\u003Cp>📞 SIP Phone\u003C\u002Fp>\u003Cp>↔ RTPEngine\u003C\u002Fp>\u003Cp>↔ Janus AudioBridge\u003C\u002Fp>",{"title":1042,"content":1043},"Verification & Testing thực tế","\u003Cp>📞 Test cuộc gọi hai chiều:\u003C\u002Fp>\u003Cp>• SIP → Browser\u003C\u002Fp>\u003Cp>• Browser → SIP\u003C\u002Fp>\u003Cp>📌 Kiểm tra:\u003C\u002Fp>\u003Cp>• RTP packet flow\u003C\u002Fp>\u003Cp>• Audio 2 chiều\u003C\u002Fp>\u003Cp>• RTP port range\u003C\u002Fp>\u003Cp>→ Media port sau khi rewrite nằm trong vùng:\u003C\u002Fp>\u003Cp>• 30000 → 40000\u003C\u002Fp>\u003Cp>📌 Xác nhận:\u003C\u002Fp>\u003Cp>• RTP relay hoạt động chính xác\u003C\u002Fp>\u003Cp>• NAT traversal thành công\u003C\u002Fp>\u003Cp>• Audio truyền ổn định\u003C\u002Fp>",{"title":727,"content":1045},"\u003Cp>→ Làm chủ kỹ thuật debug RTP\u002Fmedia\u003C\u002Fp>\u003Cp>→ Sử dụng TCPDump &amp; Wireshark cho VoIP\u003C\u002Fp>\u003Cp>→ Hiểu sâu về SDP &amp; RTP flow\u003C\u002Fp>\u003Cp>→ Fix lỗi mất tiếng trong SIP ↔ WebRTC\u003C\u002Fp>\u003Cp>→ Làm chủ RTPEngine media proxy\u003C\u002Fp>\u003Cp>→ Xử lý NAT traversal trong production VoIP system\u003C\u002Fp>\u003Cp>Đây là bước cực kỳ quan trọng trước khi triển khai:\u003C\u002Fp>\u003Cp>• Production SIP ↔ WebRTC system\u003C\u002Fp>\u003Cp>• App-to-SIP flow\u003C\u002Fp>\u003Cp>• RTP optimization\u003C\u002Fp>\u003Cp>• Large-scale VoIP architecture\u003C\u002Fp>",{"title":985,"content":1047},"\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-9-debug-rtp-media\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fsip-to-app-part-9-debug-rtp-media\u003C\u002Fa>\u003C\u002Fp>",{"slug":259,"title":260,"description":261,"duration":262,"youtubeId":263,"order":264,"thumbnail":265,"createdAt":266,"updatedAt":267,"sections":1049},[1050,1053,1056,1059,1062,1065,1067],{"title":1051,"content":1052},"Định nghĩa cấu trúc AppToSipCall","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Tạo module:\u003Cbr>• app_to_sip_rooting\u003Cbr>→ Định nghĩa:\u003Cbr>• AppToSipCall\u003Cbr>• AppToSipCallState\u003Cbr>📌 Thiết kế các state chuyên biệt cho SIP:\u003Cbr>• ConnectUACState\u003Cbr>• TalkingState\u003Cbr>• EndState\u003Cbr>→ Hỗ trợ xử lý lifecycle cho cuộc gọi từ Browser → SIP Phone.\u003C\u002Fspan>\u003C\u002Fp>",{"title":1054,"content":1055},"Thiết lập Init Params cho App-to-SIP","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Xây dựng:\u003Cbr>• AppToSipCallInitParam\u003Cbr>📌 Bao gồm:\u003Cbr>• Caller\u003Cbr>• Callee\u003Cbr>• SessionID\u003Cbr>• HandleID\u003Cbr>• RoomID\u003Cbr>• Pin \u002F Secret\u003Cbr>📌 Bổ sung:\u003Cbr>• sip_destination\u003Cbr>→ Xác định địa chỉ SIP\u002FTelco Simulator mà cuộc gọi sẽ được route tới.\u003C\u002Fspan>\u003C\u002Fp>",{"title":1057,"content":1058},"Routing Logic: Nhận diện số điện thoại","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Implement:\u003Cbr>• valid_phone_number()\u003Cbr>📌 Quy tắc nhận diện:\u003Cbr>→ Nếu Callee:\u003Cbr>• Có đúng 10 ký tự\u003Cbr>• Toàn bộ là số\u003Cbr>→ Hệ thống sẽ route theo:\u003Cbr>📞 App-to-SIP flow\u003Cbr>📌 Nếu không phải số điện thoại:\u003Cbr>→ Fallback về:\u003Cbr>• App-to-App flow\u003Cbr>→ Cho phép hệ thống hỗ trợ đồng thời nhiều loại cuộc gọi.\u003C\u002Fspan>\u003C\u002Fp>",{"title":1060,"content":1061},"Khởi tạo Call & Tích hợp CallSupervisor","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Sử dụng:\u003Cbr>• new()\u003Cbr>để tạo:\u003Cbr>• AppToSipCall\u003Cbr>📌 Bao gồm:\u003Cbr>• app_state\u003Cbr>• connection_state\u003Cbr>• CallID\u003Cbr>• Init Params\u003Cbr>→ Tích hợp với:\u003Cbr>• CallSupervisor\u003Cbr>→ Điều phối signaling &amp; state transition trong toàn hệ thống.\u003C\u002Fspan>\u003C\u002Fp>",{"title":1063,"content":1064},"Hoàn thiện bộ khung Codebase","\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Implement các hàm cốt lõi:\u003Cbr>• on_event()\u003Cbr>• on_timer()\u003Cbr>• cleanup()\u003Cbr>📌 Kiểm tra:\u003Cbr>• Build\u003Cbr>• Compile\u003Cbr>• Routing flow\u003Cbr>→ Đảm bảo bộ khung App-to-SIP đã sẵn sàng cho các bài học tiếp theo.\u003C\u002Fspan>\u003C\u002Fp>",{"title":683,"content":1066},"\u003Cp>\u003Cspan style=\"color: rgb(13, 13, 13);\">→ Xây dựng thành công bộ khung App-to-SIP\u003Cbr>→ Thiết kế State Machine cho SIP outbound call\u003Cbr>→ Tự động route App-to-App vs App-to-SIP\u003Cbr>→ Tổ chức code VoIP theo kiến trúc mở rộng\u003Cbr>→ Làm chủ signaling routing trong Rust\u003Cbr>Đây là bước đầu trước khi triển khai:\u003Cbr>• SIP INVITE outbound\u003Cbr>• UAC handling\u003Cbr>• RTP media flow\u003Cbr>• Browser ↔ Phone calling\u003Cbr>• Production outbound VoIP system\u003C\u002Fspan>\u003C\u002Fp>",{"title":985,"content":1068},"\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fapp-to-sip-part-1-setup-call\">\u003Cspan style=\"color: rgb(13, 13, 13);\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fapp-to-sip-part-1-setup-call\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fp>",{"slug":269,"title":270,"description":271,"duration":272,"youtubeId":273,"order":274,"thumbnail":275,"createdAt":276,"updatedAt":277,"sections":1070},[1071,1074,1077,1080,1083,1086,1089,1091],{"title":1072,"content":1073},"Video sẽ tập trung vào:","\u003Cp>• State Machine\u003C\u002Fp>\u003Cp>• SDP Handshake\u003C\u002Fp>\u003Cp>• WebSocket Event\u003C\u002Fp>\u003Cp>• Janus Event\u003C\u002Fp>\u003Cp>• WebRTC signaling\u003C\u002Fp>\u003Cp>• Timeout handling\u003C\u002Fp>\u003Cp>giúp hoàn thiện bước “bắt tay media” đầu tiên giữa:\u003C\u002Fp>\u003Cp>🌐 Browser\u003C\u002Fp>\u003Cp>↔ Rust Server\u003C\u002Fp>\u003Cp>↔ Janus Media Server\u003C\u002Fp>",{"title":1075,"content":1076},"Tái cấu trúc & Chuẩn hóa Codebase","\u003Cp>→ Reuse các logic cốt lõi từ:\u003C\u002Fp>\u003Cp>• App-to-App\u003C\u002Fp>\u003Cp>• SIP-to-App\u003C\u002Fp>\u003Cp>📌 Refactor các hàm:\u003C\u002Fp>\u003Cp>• apply_action()\u003C\u002Fp>\u003Cp>• transition_to()\u003C\u002Fp>\u003Cp>• start_timer()\u003C\u002Fp>\u003Cp>• stop_timer()\u003C\u002Fp>\u003Cp>→ Đảm bảo State Machine hoạt động đồng nhất trong toàn bộ hệ thống.\u003C\u002Fp>\u003Cp>📌 Implement:\u003C\u002Fp>\u003Cp>• on_event()\u003C\u002Fp>\u003Cp>→ Dispatch chính xác event tới current state.\u003C\u002Fp>",{"title":1078,"content":1079},"Thiết kế State Machine cho App-to-SIP","\u003Cp>📌 Xây dựng flow gồm 4 state chính:\u003C\u002Fp>\u003Cp>• WaitingCallerSdpState\u003C\u002Fp>\u003Cp>• ConnectToSipState\u003C\u002Fp>\u003Cp>• TalkingState\u003C\u002Fp>\u003Cp>• EndState\u003C\u002Fp>\u003Cp>→ Điều phối lifecycle cho outbound SIP call từ Browser.\u003C\u002Fp>",{"title":1081,"content":1082},"Hiện thực hóa WaitingCallerSdpState","\u003Cp>📌 Timeout Handling:\u003C\u002Fp>\u003Cp>→ Thiết lập timeout:\u003C\u002Fp>\u003Cp>• 45 giây\u003C\u002Fp>\u003Cp>→ Nếu không nhận được SDP Offer:\u003C\u002Fp>\u003Cp>• Auto transition → EndState\u003C\u002Fp>\u003Cp>→ Tránh leak resource và zombie session.\u003C\u002Fp>\u003Cp>📌 Xử lý WebSocket signaling:\u003C\u002Fp>\u003Cp>→ Nhận:\u003C\u002Fp>\u003Cp>• SDP Offer\u003C\u002Fp>\u003Cp>từ Browser\u002FWebRTC Client.\u003C\u002Fp>\u003Cp>📌 Join AudioBridge Room:\u003C\u002Fp>\u003Cp>→ Sau khi có SDP:\u003C\u002Fp>\u003Cp>• Join Janus Room\u003C\u002Fp>\u003Cp>• Configure SDP lên Janus\u003C\u002Fp>\u003Cp>→ Chuẩn bị media path cho WebRTC.\u003C\u002Fp>",{"title":1084,"content":1085},"Xử lý Janus Event & SDP Answer","\u003Cp>→ Parse Janus Event\u003C\u002Fp>\u003Cp>→ Extract:\u003C\u002Fp>\u003Cp>• SDP Answer\u003C\u002Fp>\u003Cp>📌 Notify Browser:\u003C\u002Fp>\u003Cp>→ Gửi SDP Answer về Client bằng:\u003C\u002Fp>\u003Cp>• WebRTC Manager\u003C\u002Fp>\u003Cp>→ Browser thực hiện:\u003C\u002Fp>\u003Cp>• setRemoteDescription()\u003C\u002Fp>\u003Cp>📌 Điều kiện transition state:\u003C\u002Fp>\u003Cp>→ Chỉ chuyển sang:\u003C\u002Fp>\u003Cp>• ConnectToSipState\u003C\u002Fp>\u003Cp>khi:\u003C\u002Fp>\u003Cp>• SDP Answer received\u003C\u002Fp>\u003Cp>• webrtc_up event received\u003C\u002Fp>\u003Cp>→ Đảm bảo media path hoạt động chính xác trước khi gọi SIP.\u003C\u002Fp>",{"title":1087,"content":1088},"Error Handling & EndReason","\u003Cp>📌 Định nghĩa:\u003C\u002Fp>\u003Cp>• EndReason::Timeout\u003C\u002Fp>\u003Cp>• EndReason::Error\u003C\u002Fp>\u003Cp>→ Hỗ trợ cleanup &amp; SIP hangup chính xác trong các bước tiếp theo.\u003C\u002Fp>\u003Cp>📌 Chuẩn bị cho:\u003C\u002Fp>\u003Cp>• SIP BYE\u003C\u002Fp>\u003Cp>• Cancel flow\u003C\u002Fp>\u003Cp>• Error response handling\u003C\u002Fp>",{"title":727,"content":1090},"\u003Cp>Sau bài học này, bạn sẽ:\u003C\u002Fp>\u003Cp>→ Hoàn thiện WaitingCallerSdpState\u003C\u002Fp>\u003Cp>→ Xử lý SDP Offer\u002FAnswer trong Rust\u003C\u002Fp>\u003Cp>→ Điều phối WebSocket &amp; Janus Event\u003C\u002Fp>\u003Cp>→ Thiết kế App-to-SIP State Machine chuyên nghiệp\u003C\u002Fp>\u003Cp>→ Quản lý timeout &amp; signaling lifecycle\u003C\u002Fp>\u003Cp>→ Chuẩn bị media path cho outbound SIP call\u003C\u002Fp>",{"title":985,"content":1092},"\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fapp-to-sip-part-2-build-call\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fapp-to-sip-part-2-build-call\u003C\u002Fa>\u003C\u002Fp>",{"slug":279,"title":280,"description":281,"duration":282,"youtubeId":283,"order":284,"thumbnail":285,"createdAt":286,"updatedAt":287,"sections":1094},[1095,1098,1100],{"title":1096,"content":1097},"📌 Nội dung trọng tâm trong video:","\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">1. Định nghĩa ConnectToSipState:\u003Cbr>Khởi tạo cấu trúc trạng thái mới để lưu trữ các thông tin quan trọng: caller_handler, bản tin SDP Offer dành cho phía SIP, và cấu trúc Invite Request .\u003Cbr>Thiết lập hàm new và thực hiện chuyển dịch từ WaitingCallerSdpState sang ConnectToSipState .\u003Cbr>\u003Cbr>2. Xử lý sự kiện WebSocket &amp; Janus Events:\u003Cbr>WebSocket Candidates: Lập trình để nhận các ICE Candidate từ phía Client và forward trực tiếp vào Janus Media Server .\u003Cbr>Janus Candidate Notify: Lắng nghe các ứng viên (candidates) từ Janus và gửi ngược lại cho phía người gọi (Caller) thông qua WebSocket để hoàn tất quá trình bắt tay ICE .\u003Cbr>\u003Cbr>3. Điều kiện chuyển trạng thái (State Transition):\u003Cbr>Phân tích sự kiện webrtc_up: Đây là tín hiệu quan trọng xác nhận kết nối giữa trình duyệt và Janus đã sẵn sàng .\u003Cbr>Hệ thống chỉ chuyển sang trạng thái kết nối SIP khi đáp ứng đủ hai điều kiện: Đã nhận được SDP Answer từ Janus và nhận được sự kiện webrtc_up .\u003Cbr>\u003Cbr>4. Deploy và Debug thực tế:\u003Cbr>Thực hiện triển khai mã nguồn lên server và sử dụng Softphone (Zoiper) để kiểm tra luồng gọi .\u003Cbr>Kiểm tra log hệ thống để xác nhận việc nhận diện số điện thoại (ví dụ: 0949567890) và quá trình nhảy state trong máy trạng thái (State Machine) .\u003Cbr>\u003C\u002Fspan>\u003C\u002Fp>",{"title":727,"content":1099},"\u003Cp>\u003Cspan style=\"color: rgb(19, 19, 19);\">Sau video này, bạn đã thông suốt luồng xử lý từ lúc người dùng nhấn gọi trên trình duyệt cho đến khi hệ thống sẵn sàng kết nối với phía SIP. Việc hiểu rõ cách phối hợp giữa các sự kiện ICE và trạng thái WebRTC sẽ giúp bạn xây dựng hệ thống VoIP.\u003C\u002Fspan>\u003C\u002Fp>",{"title":1101,"content":1102},"Source code ","\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fapp-to-sip-part-3-build-and-debug-before-connect-to-sip\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fapp-to-sip-part-3-build-and-debug-before-connect-to-sip\u003C\u002Fa>\u003C\u002Fp>",{"slug":289,"title":290,"description":291,"duration":292,"youtubeId":293,"order":294,"thumbnail":295,"createdAt":296,"updatedAt":297,"sections":1104},[1105,1108,1111,1114,1117,1120,1122,1124],{"title":1106,"content":1107},"Khởi tạo và Join Room cho Callee:","\u003Cp>Thực hiện attach handle mới vào Janus Session và đưa (join) đối tượng này vào AudioBridge Room\u003C\u002Fp>\u003Cp>Sử dụng Janus Admin API (get_handler_info) để lấy chính xác thông tin IP và Port RTP của Janus, do API thông thường đôi khi không trả về dữ liệu này trong sự kiện join\u003C\u002Fp>",{"title":1109,"content":1110},"Xây dựng bản tin SIP INVITE trong Rust:","\u003Cp>Sử dụng thư viện SIP để build cấu trúc bản tin: Request URI, Header và Body (SDP Offer)\u003C\u002Fp>\u003Cp>Tạo định danh giao dịch (Transaction ID) và đăng ký với CallSupervisor để quản lý phản hồi từ phía SIP\u003C\u002Fp>\u003Cp>Gửi bản tin INVITE qua cổng UDP đến Kamailio (Port 5061)\u003C\u002Fp>",{"title":1112,"content":1113},"Xử lý phản hồi từ SIP Server (SIP Responses):","\u003Cp>Lắng nghe và phân tích các mã trạng thái: 100 Trying, 180 Ringing, 183 Session Progress và đặc biệt là 200 OK\u003C\u002Fp>\u003Cp>Bóc tách bản tin SDP Answer từ body của SIP 200 OK để lấy thông tin IP\u002FPort của phía người nhận (Phone)\u003C\u002Fp>",{"title":1115,"content":1116},"Hoàn thiện bắt tay SIP (ACK) và Cấu hình Media:","\u003Cp>Sử dụng thông tin RTP từ SIP Phone để cấu hình ngược lại cho Janus AudioBridge handle thông qua hàm config_with_rtp\u003C\u002Fp>\u003Cp>Xây dựng và gửi bản tin ACK để chính thức xác nhận thiết lập cuộc gọi thành công và chuyển sang Talking State\u003C\u002Fp>",{"title":1118,"content":1119},"Cấu hình Kamailio cho luồng Outbound:","\u003Cp>Kỹ thuật phân biệt cuộc gọi từ Rust Server bằng header tùy chỉnh x-source: rust\u003C\u002Fp>\u003Cp>Sử dụng RTPEngine để thực hiện replace-origin và replace-session-connection, giúp chuyển đổi SDP giữa mô hình Janus AudioBridge và SIP truyền thống\u003C\u002Fp>",{"title":770,"content":1121},"\u003Cp>Thực hiện cuộc gọi từ trình duyệt web đến số điện thoại thật trên Softphone (Zoiper)\u003C\u002Fp>\u003Cp>Theo dõi luồng signaling và xác nhận kết nối thành công giữa hai môi trường\u003C\u002Fp>",{"title":683,"content":1123},"\u003Cp>Sau bài học này, bạn đã thông suốt luồng kết nối từ WebRTC đến SIP. Bạn hiểu rõ cách thức đóng gói bản tin SIP ở mức thấp, cách điều phối media qua các Proxy trung gian và cách hoàn thiện một quy trình bắt tay (handshake) VoIP bằng Rust\u003C\u002Fp>",{"title":874,"content":1125},"\u003Cp>Mã nguồn tham khảo: \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fapp-to-sip-part-4-connect-to-sip-state\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fapp-to-sip-part-4-connect-to-sip-state\u003C\u002Fa>\u003C\u002Fp>\u003Cp>Tài liệu audiobridge: \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Faudiobridge\u003C\u002Fa>\u003C\u002Fp>\u003Cp>Janus Admin API: \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Fadmin.html\">https:\u002F\u002Fjanus.conf.meetecho.com\u002Fdocs\u002Fadmin.html\u003C\u002Fa>\u003C\u002Fp>",{"slug":299,"title":300,"description":301,"duration":302,"youtubeId":303,"order":41,"thumbnail":304,"createdAt":305,"updatedAt":306,"sections":1127},[1128,1131,1134,1137,1140,1142],{"title":1129,"content":1130},"Xử lý SIP Response & Transition sang TalkingState","\u003Cp>→ Parse và xử lý:\u003C\u002Fp>\u003Cp>• SIP 200 OK\u003C\u002Fp>\u003Cp>từ SIP Phone để xác nhận cuộc gọi đã được answer.\u003C\u002Fp>\u003Cp>📌 State transition:\u003C\u002Fp>\u003Cp>• ConnectToSipState\u003Cbr>→ TalkingState\u003C\u002Fp>\u003Cp>→ Hoàn tất SIP signaling flow cho outbound App-to-SIP call.\u003C\u002Fp>",{"title":1132,"content":1133},"Hiện thực hóa TalkingState trong Rust","\u003Cp>📌 on_enter():\u003C\u002Fp>\u003Cp>→ Gửi notification answer cho:\u003C\u002Fp>\u003Cp>• WebRTC Browser Client\u003C\u002Fp>\u003Cp>→ Đồng bộ trạng thái UI khi cuộc gọi được kết nối thành công.\u003C\u002Fp>\u003Cp>📌 Quản lý đa nguồn sự kiện trong on_event():\u003C\u002Fp>\u003Cp>• WebSocket Event\u003Cbr>→ Browser hangup\u003C\u002Fp>\u003Cp>• Janus Event\u003Cbr>→ Room destroyed\u003Cbr>→ Participant left\u003C\u002Fp>\u003Cp>• SIP Event\u003Cbr>→ SIP BYE từ Phone\u003C\u002Fp>\u003Cp>→ Điều phối signaling và lifecycle trong suốt thời gian đàm thoại.\u003C\u002Fp>",{"title":1135,"content":1136},"EndState & Cleanup Resource","\u003Cp>📌 Notify &amp; Stop Timer:\u003C\u002Fp>\u003Cp>→ Gửi:\u003C\u002Fp>\u003Cp>• call_end\u003C\u002Fp>\u003Cp>cho WebRTC Client.\u003C\u002Fp>\u003Cp>→ Stop toàn bộ timer liên quan đến cuộc gọi.\u003C\u002Fp>\u003Cp>📌 Cleanup Janus Resource:\u003C\u002Fp>\u003Cp>→ Delete Room\u003Cbr>→ Detach Handle\u003Cbr>→ Destroy Session\u003C\u002Fp>\u003Cp>→ Giải phóng tài nguyên trên Janus Media Server theo đúng quy trình.\u003C\u002Fp>\u003Cp>📌 SIP Dialog Termination:\u003C\u002Fp>\u003Cp>→ Gửi:\u003C\u002Fp>\u003Cp>• SIP BYE\u003Cbr>hoặc\u003Cbr>• SIP CANCEL\u003C\u002Fp>\u003Cp>tùy theo trạng thái hiện tại của cuộc gọi.\u003C\u002Fp>\u003Cp>→ Đảm bảo SIP Dialog được đóng hoàn toàn từ phía SIP Server\u002FPhone.\u003C\u002Fp>",{"title":1138,"content":1139},"Demo thực tế & Test Audio hai chiều","\u003Cp>📞 Demo flow hoàn chỉnh:\u003C\u002Fp>\u003Cp>WebRTC Browser\u003Cbr>↔ Rust Server\u003Cbr>↔ Janus Media Server\u003Cbr>↔ Kamailio\u003Cbr>↔ SIP Phone (Zoiper)\u003C\u002Fp>\u003Cp>📌 Kiểm tra:\u003C\u002Fp>\u003Cp>• Two-way audio\u003Cbr>• SIP signaling\u003Cbr>• Hangup từ Browser\u003Cbr>• Hangup từ SIP Phone\u003Cbr>• Resource cleanup\u003C\u002Fp>\u003Cp>→ Xác nhận media flow và signaling hoạt động ổn định.\u003C\u002Fp>",{"title":727,"content":1141},"\u003Cp>→ Hoàn thiện TalkingState cho App-to-SIP\u003Cbr>→ Xử lý SIP 200 OK &amp; SIP BYE\u003Cbr>→ Quản lý lifecycle cuộc gọi VoIP\u003Cbr>→ Cleanup tài nguyên Janus đúng cách\u003Cbr>→ Điều phối signaling SIP ↔ WebRTC\u003Cbr>→ Hoàn thiện outbound calling flow bằng Rust\u003C\u002Fp>\u003Cp>Đây là nền tảng quan trọng trước khi triển khai các tính năng nâng cao như:\u003C\u002Fp>\u003Cp>• Call Recording\u003Cbr>• Audio Injection\u003Cbr>• Voice Bot\u003Cbr>• SIP Automation\u003Cbr>• Production VoIP Platform\u003C\u002Fp>",{"title":669,"content":1143},"\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fapp-to-app-part-5-talking-state-and-end-state\">https:\u002F\u002Fgithub.com\u002Fbytebuffer-voip\u002Fjanus-call-service\u002Ftree\u002Ffeat\u002Fapp-to-app-part-5-talking-state-and-end-state\u003C\u002Fa>\u003C\u002Fp>",1779754819817]