Episode ini membahas peran WebSocket dalam WebRTC: signaling untuk pertukaran SDP dan ICE candidate, alur offer dan answer, manajemen room, serta konfigurasi server STUN dan TURN.

WebRTC memungkinkan dua browser berbagi video dan audio secara langsung, tanpa server sebagai penerus data. Tapi ada satu bagian yang justru membutuhkan WebSocket: signaling. Sebelum dua peer bisa terhubung, mereka harus saling mengenal — dan pertukaran pengenalan itulah signaling.
Episode 25 membahas peran WebSocket sebagai signaling channel untuk WebRTC: pertukaran SDP offer dan answer, aliran ICE candidate, manajemen room, serta konfigurasi STUN dan TURN untuk menembus NAT.
WebRTC mengalirkan media langsung antar browser, tapi pertukaran awal tidak bisa dilakukan begitu saja — peer tidak tahu alamat satu sama lain.
peer A -> signaling (WebSocket) -> peer B
media -> langsung antara peer A dan BWebSocket hanya membawa pesan kontrol: SDP (deskripsi sesi media) dan ICE candidate (calon alamat jaringan). Begitu kedua peer sepakat, media mengalir langsung tanpa server.
WebSocket bertugas mengantar SDP dan ICE candidate bolak-balik sampai kedua sisi terhubung.
Server signaling sangat sederhana: terima pesan dari satu peer, teruskan ke peer tujuan.
const { Server } = require("socket.io");
const io = new Server(server);
io.on("connection", (socket) => {
socket.on("signal", (data) => {
io.to(data.tujuan).emit("signal", {
dari: socket.id,
tipe: data.tipe,
payload: data.payload,
});
});
});io.to(data.tujuan).emit("signal", ...) meneruskan pesan ke peer tujuan. Server signaling tidak perlu memahami isi SDP atau ICE — ia hanya kurir yang andal.
Alur lengkap pembentukan koneksi:
const pc = new RTCPeerConnection(config);
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
socket.emit("signal", {
tujuan: peerId,
tipe: "offer",
payload: offer,
});pc.createOffer() membuat SDP offer, lalu dikirim lewat WebSocket. Peer penerima menjawab dengan pc.createAnswer(), dan kedua sisi saling menerima remote description.
Selama pembuatan koneksi, kedua peer menemukan kandidat alamat secara bertahap.
pc.onicecandidate = (event) => {
if (event.candidate) {
socket.emit("signal", {
tujuan: peerId,
tipe: "candidate",
payload: event.candidate,
});
}
};
socket.on("signal", async (data) => {
if (data.tipe === "candidate") {
await pc.addIceCandidate(data.payload);
}
});pc.onicecandidate memicu pengiriman setiap kandidat baru, dan pc.addIceCandidate(data.payload) menambahkannya ke koneksi. ICE trickling membuat koneksi mulai terbentuk sebelum semua kandidat ditemukan.
Room WebSocket (episode 9) berfungsi sebagai ruang rapat: semua yang bergabung di room yang sama bisa saling signaling.
socket.on("room:join", (room) => {
socket.join(room);
const hadir = io.sockets.adapter.rooms.get(room) || new Set();
const lainnya = [...hadir].filter((id) => id !== socket.id);
socket.emit("room:peer", lainnya);
socket.to(room).emit("room:new-peer", socket.id);
});hadir memberi daftar peer yang sudah ada, dan socket.to(room).emit("room:new-peer", ...) memberi tahu yang lama ada pendatang baru. Setiap pendatang baru membuat koneksi WebRTC ke semua peer lama — pola mesh.
Dalam konferensi 3-4 orang, mesh (setiap orang terhubung ke semua orang) masih baik. Di atas itu, video dan audio berlipat membebani bandwidth — saat itulah dibutuhkan SFU (Selective Forwarding Unit) seperti MediaSoup, yang berada di luar cakupan episode ini.
Browser membutuhkan server STUN dan TURN untuk menembus NAT.
const config = {
iceServers: [
{ urls: "stun:stun.l.google.com:19302" },
{
urls: "turn:turn.example.com:3478",
username: "user",
credential: "secret",
},
],
};
const pc = new RTCPeerConnection(config);stun:stun.l.google.com:19302 adalah STUN publik gratis. turn:turn.example.com:3478 menyediakan relay untuk koneksi yang gagal langsung. TURN membutuhkan kredensial — server signaling yang membagikannya secara aman.
NAT simetris dan firewall ketat sering memblokir koneksi langsung. ICE lalu memilih rute TURN: media diteruskan melalui server, dengan harga latensi dan bandwidth ekstra. Untuk produksi, siapkan TURN sendiri karena layanan publik tidak untuk skala aplikasi.
Episode 25 menunjukkan kolaborasi WebSocket dan WebRTC: WebSocket sebagai kurir yang mengantar SDP dan ICE, WebRTC sebagai pembawa media langsung antar peer. Yang satu mengatur, yang lain mengalir.
Inti yang harus dibawa pulang:
Di episode 26 berikutnya kita membahas testing WebSocket applications: unit dan integration testing, load testing dengan Artillery dan k6, serta chaos testing untuk menyimulasikan kegagalan.