Key Concept: DataChannels ≠ Media
En Arq. 6, node-datachannel no transporta audio ni vídeo. El audio va por Mumble y el vídeo por µStreamer MJPEG. node-datachannel se usa solo para datos: mensajes de texto (chat P2P), transferencia de archivos, y señalización entre peers SSB.
| Tipo de datos | Transporte | Componente |
| Vídeo | HTTP MJPEG (µStreamer) | µStreamer → Oasis proxy |
| Audio | Mumble protocol + HTTP OGG bridge | murmurd → bridge |
| Texto/chat | WebRTC DataChannel (P2P) | node-datachannel |
| Archivos | WebRTC DataChannel (P2P) | node-datachannel |
| Señalización | WebRTC DataChannel o SSB feed | node-datachannel / SSB |
Identidad del Componente
| Campo | Valor |
| npm | node-datachannel |
| Repo | murat-dogan/node-datachannel |
| Binding de | libdatachannel (C/C++) |
| Autor libdatachannel | Paul-Louis Ageneau |
| Licencia | MPL-2.0 (libdatachannel) + MIT (bindings) |
| Incluye media | ✘ No — solo DataChannels + signaling |
| RAM típica | ~5–10 MB (integrado en proceso Node.js de Oasis) |
| Install | npm install node-datachannel |
Flujo de Señalización (SDP via SSB)
PEER A (SNH) PEER B (remote)
│ │
│ 1. createPeerConnection() │
│ 2. createDataChannel('chat') │
│ 3. createOffer() → SDP offer │
│ │
│ ──── SDP offer via SSB msg ──────────────────▷│
│ │
│ 4. setRemoteDescription() │
│ 5. createAnswer() → SDP │
│ │
│◁──── SDP answer via SSB msg ──────────────────│
│ │
│ 6. setRemoteDescription() │
│ │
│ ◀═══ ICE candidates (trickle via SSB) ═══════▷│
│ │
│ ◀══════ DataChannel OPEN ═══════════════════▷ │
│ texto · archivos · señalización │
La señalización (SDP offer/answer + ICE candidates) viaja por SSB feed messages: cada peer publica su SDP como un mensaje SSB privado. No hace falta un signaling server WebSocket.
API Patterns — node-datachannel
Crear peer connection + datachannel
const nodeDataChannel = require('node-datachannel');
const peer = new nodeDataChannel.PeerConnection(
'PeerA', { iceServers: [] } // sin STUN: solo LAN
);
const dc = peer.createDataChannel('chat');
dc.onOpen(() => {
dc.sendMessage('hello from SNH');
});
dc.onMessage((msg) => {
console.log('received:', msg);
});
Generar SDP y publicar en SSB
peer.onLocalDescription((sdp, type) => {
// Publicar en SSB como mensaje privado al peer
ssbClient.publish({
type: 'webrtc-sdp',
sdpType: type, // 'offer' | 'answer'
sdp: sdp,
recps: [peerBId] // privado
});
});
peer.onLocalCandidate((candidate, mid) => {
ssbClient.publish({
type: 'webrtc-ice',
candidate, mid,
recps: [peerBId]
});
});
Recibir SDP del otro peer (listener SSB)
ssbClient.on('webrtc-sdp', (msg) => {
if (msg.value.content.sdpType === 'offer') {
peer.setRemoteDescription(
msg.value.content.sdp, 'offer'
);
} else {
peer.setRemoteDescription(
msg.value.content.sdp, 'answer'
);
}
});
ssbClient.on('webrtc-ice', (msg) => {
peer.addRemoteCandidate(
msg.value.content.candidate,
msg.value.content.mid
);
});
File Transfer via DataChannel
DataChannels soportan datos binarios. Para archivos grandes: chunk en bloques de ~16 KB (límite SCTP), enviar secuencialmente, reassemblar en destino.
const CHUNK = 16384; // 16 KB
const buf = fs.readFileSync(filePath);
dc.sendMessage(JSON.stringify({
type: 'file-meta',
name: path.basename(filePath),
size: buf.length
}));
for (let i = 0; i < buf.length; i += CHUNK) {
dc.sendMessageBinary(buf.slice(i, i + CHUNK));
}
dc.sendMessage(JSON.stringify({ type: 'file-end' }));
Alternativa: Los archivos pueden viajar como SSB blobs (inmutables, content-addressed). DataChannel para archivos pequeños/urgentes; SSB blobs para archivos que deben persistir en el log.
LAN vs Remoto — ICE Config
| Escenario | iceServers | Funciona | Nota |
| LAN directa | [] (vacío) | ✔ | mDNS / IP local directa |
| LAN con NAT simple | [STUN público] | ✔ | Reflexive candidates |
| Internet (simétric NAT) | [STUN + TURN] | ⚠️ | Necesita TURN relay |
| Tor | — | ✘ | ICE no funciona sobre Tor (UDP bloqueado) |
DataChannels P2P no funcionan sobre Tor. Para datos entre peers en Tor: usar SSB replication (TCP, compatible Tor). DataChannels solo para LAN o con STUN/TURN en clearnet.
En Arq. 6 (solo LAN), iceServers: [] es suficiente. Los peers están en la misma red, se ven directamente por IP.
Formato de Mensajes — Convención
{ "type": "chat", "text": "hola", "ts": 1711612800 }
{ "type": "file-meta", "name": "foto.jpg", "size": 48230 }
{ "type": "file-end" }
{ "type": "ping" }
{ "type": "pong", "rtt": 12 }
{ "type": "status", "video": true, "audio": true }
DRY rule: siempre JSON con campo type. Permite extensibilidad futura sin romper parsers existentes. Los chunks binarios de file-transfer son la única excepción (raw ArrayBuffer).
Keywords
DataChannel
SCTP
SDP
ICE
libdatachannel
SSB feed
recps
offer/answer
trickle ICE
16 KB chunk
P2P
mDNS