π Resumen del Sistema
β Completitud del Sistema: 100%
El sistema de notificaciones WebRTC estΓ‘ COMPLETO con todos los eventos implementados y documentados.
EstadΓsticas
- Eventos Totales: 18 eventos
- Eventos CrΓticos: 4 (producer-closed, transport-closed, peer-left, consume-error)
- Eventos de Alta Prioridad: 7
- Eventos de Media Prioridad: 7
Eventos Nuevos Agregados (2025-10-31)
- β
transport-closed- NotificaciΓ³n de transport cerrado - β
transport-state-changedπ - Cambios de estado del transport - β
peer-left- NotificaciΓ³n de peer desconectado - β
peer-joined- NotificaciΓ³n de peer conectado - β
producer-created- Producer creado (interno) - β
producer-paused- Producer pausado - β
producer-resumed- Producer reanudado - β
consume-error- Error al consumir producer
Vistas Actualizadas
- β
bidder-asm-stream.html- Manejo completo de eventos - β
host-asm-stream.html- Monitoreo de eventos - β
viewer-stream.html- Limpieza automΓ‘tica de recursos - β
videoconference.html- Multi-party event handling
ποΈ Arquitectura del Sistema de Eventos
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MEDIASOUP (Capa WebRTC Nativa) β
β - producer.on('close') β
β - producer.on('pause') β
β - transport.on('close') β
β - consumer.on('producerclose') β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β EVENT BUS (room.mjs) β
β - Centraliza todos los eventos β
β - room.emit('ProducerClosed', data) β
β - room.emit('TransportClosed', data) β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WEBSOCKET BROADCAST (ws.mjs) β
β - room.eventBus.onProducerClosed = (data) => broadcast(...) β
β - EnvΓa eventos a todos los peers conectados β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLIENTES (bidder-asm-stream.html, host-asm-stream.html) β
β - ws.onmessage: if (m.type === 'producer-closed') {...} β
β - Actualiza UI segΓΊn evento recibido β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Event Bus
Sistema centralizado para emitir eventos WebRTC de manera consistente:
const room = {
eventBus: {
onProducerCreated: null,
onProducerClosed: null,
onProducerPaused: null,
onProducerResumed: null,
onTransportClosed: null,
onDataProducerClosed: null,
},
emit(event, data) {
const handler = this.eventBus[\`on\${event}\`];
if (handler && typeof handler === 'function') {
handler(data);
}
},
};
π¬ Eventos de Ciclo de Vida
welcome
Alta Prioridad
Primer mensaje del servidor al cliente, informa su identidad asignada (peerId, role, roomId).
{
"type": "welcome",
"peerId": "uuid-del-peer",
"roomId": "sala-100",
"role": "bidder"
}
rtp-capabilities
Alta Prioridad
EnvΓa las capacidades del router mediasoup para que el cliente pueda cargar el Device y negociar codecs.
{
"type": "rtp-capabilities",
"rtpCapabilities": {
"codecs": [...],
"headerExtensions": [...]
}
}
πΉ Eventos de Producers
producer-announced
Alta Prioridad
Notifica a todos los clientes que hay un nuevo producer disponible para consumir (video o audio).
{
"type": "producer-announced",
"roomId": "sala-100",
"peerId": "peer-abc123",
"producerId": "producer-xyz789",
"kind": "video"
}
producer-closed
β CRΓTICO
Notifica que un producer ya no estΓ‘ disponible (peer detuvo cΓ‘mara/micrΓ³fono, se desconectΓ³, etc.). Este es el evento mΓ‘s importante para limpieza de UI.
{
"type": "producer-closed",
"roomId": "sala-100",
"peerId": "peer-abc123",
"producerId": "producer-xyz789",
"kind": "video",
"serverTs": 1234567890
}
Ejemplo de Manejo:
if (m.type === 'producer-closed') {
const { producerId, kind, peerId } = m;
if (kind === 'video' && mediaEls.has(peerId)) {
updateVideoState(peerId, 'ended', 'disconnected',
'El auctioneer detuvo la transmisiΓ³n');
}
producers.delete(producerId);
}
producer-paused
π Media Prioridad
Indica que un producer se pausΓ³ temporalmente (ej: auctioneer mutea micrΓ³fono). Diferente de cerrar permanentemente.
{
"type": "producer-paused",
"roomId": "sala-100",
"peerId": "peer-abc123",
"producerId": "producer-xyz789",
"kind": "audio",
"serverTs": 1234567890
}
producer-resumed
π Media Prioridad
Indica que un producer previamente pausado vuelve a estar activo.
{
"type": "producer-resumed",
"roomId": "sala-100",
"peerId": "peer-abc123",
"producerId": "producer-xyz789",
"kind": "audio",
"serverTs": 1234567890
}
π Eventos de Transports
transport-closed
β CRΓTICO
Notifica que un transport WebRTC se cerrΓ³ (falla de red, desconexiΓ³n, timeout). Este evento es crΓtico para detectar pΓ©rdida de conexiΓ³n.
{
"type": "transport-closed",
"roomId": "sala-100",
"transportId": "transport-123",
"peerId": "peer-abc123",
"direction": "send",
"serverTs": 1234567890
}
Ejemplo de Manejo:
if (m.type === 'transport-closed') {
const { transportId, peerId, direction } = m;
if (direction === 'send' && mediaEls.has(peerId)) {
updateVideoState(peerId, 'ended', 'disconnected', 'ConexiΓ³n perdida');
}
}
transport-created
Alta Prioridad
EnvΓa parΓ‘metros para que el cliente cree el transport WebRTC (ICE candidates, DTLS parameters, etc.).
{
"type": "transport-created",
"direction": "send",
"params": {
"id": "transport-123",
"iceParameters": {...},
"iceCandidates": [...],
"dtlsParameters": {...}
}
}
π₯ Eventos de Peers
peer-joined
π Media Prioridad
Notifica que un nuevo peer se ha unido a la sala (antes de que produzca video/audio).
{
"type": "peer-joined",
"roomId": "sala-100",
"peerId": "peer-abc123",
"role": "bidder",
"serverTs": 1234567890
}
peer-left
β CRΓTICO
Notifica que un peer se ha desconectado (cerrΓ³ navegador, perdiΓ³ conexiΓ³n, timeout). CrΓtico para limpieza de recursos y UI.
{
"type": "peer-left",
"roomId": "sala-100",
"peerId": "peer-abc123",
"role": "auctioneer",
"serverTs": 1234567890
}
Ejemplo de Manejo:
if (m.type === 'peer-left') {
const { peerId, role } = m;
// Limpiar producers del peer
for (const [producerId, info] of producers.entries()) {
if (info.peerId === peerId) {
producers.delete(producerId);
}
}
// Limpiar UI
if (mediaEls.has(peerId)) {
const { tile, healthCheckInterval } = mediaEls.get(peerId);
if (healthCheckInterval) clearInterval(healthCheckInterval);
tile.remove();
mediaEls.delete(peerId);
}
}
π¨ Eventos de Errores
consume-error
π Alta Prioridad
Notifica que no se pudo crear un consumer para un producer (codec incompatible, producer no existe, etc.).
{
"type": "consume-error",
"producerId": "producer-xyz789",
"error": "router cannot consume this producer",
"code": "CONSUME_FAILED",
"serverTs": 1234567890
}
Ejemplo de Manejo:
if (m.type === 'consume-error') {
const { producerId, error, code } = m;
console.error('β Error al consumir:', producerId, error);
showErrorNotification(\`No se puede reproducir: \${error}\`);
}
π» Ejemplos de ImplementaciΓ³n
Cliente: Manejo Completo de Eventos
ws.onmessage = async (ev) => {
const m = JSON.parse(ev.data);
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// CICLO DE VIDA
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if (m.type === 'welcome') {
const { peerId, roomId, role } = m;
myPeerId = peerId;
log(\`Conectado como \${role} en \${roomId}\`);
return;
}
if (m.type === 'rtp-capabilities') {
device = new mediasoupClient.Device();
await device.load({ routerRtpCapabilities: m.rtpCapabilities });
return;
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// PRODUCERS
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if (m.type === 'producer-announced') {
const { producerId, kind, peerId } = m;
producers.set(producerId, { kind, peerId });
consume(producerId);
return;
}
if (m.type === 'producer-closed') {
const { producerId, kind, peerId } = m;
if (kind === 'video' && mediaEls.has(peerId)) {
updateVideoState(peerId, 'ended', 'disconnected',
'El auctioneer detuvo la transmisiΓ³n');
}
producers.delete(producerId);
return;
}
if (m.type === 'producer-paused') {
const { producerId, kind, peerId } = m;
if (kind === 'video') {
updateVideoState(peerId, 'paused', null, 'Video pausado');
}
return;
}
if (m.type === 'producer-resumed') {
const { producerId, kind, peerId } = m;
if (kind === 'video') {
checkVideoPlaying(peerId);
}
return;
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// TRANSPORTS
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if (m.type === 'transport-closed') {
const { transportId, peerId, direction } = m;
if (direction === 'send' && mediaEls.has(peerId)) {
updateVideoState(peerId, 'ended', 'disconnected', 'ConexiΓ³n perdida');
}
return;
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// PEERS
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if (m.type === 'peer-joined') {
const { peerId, role } = m;
log('π Peer conectado:', peerId, role);
return;
}
if (m.type === 'peer-left') {
const { peerId, role } = m;
log('π Peer desconectado:', peerId, role);
// Limpiar producers
for (const [producerId, info] of producers.entries()) {
if (info.peerId === peerId) {
producers.delete(producerId);
}
}
// Limpiar UI
if (mediaEls.has(peerId)) {
const { tile, healthCheckInterval } = mediaEls.get(peerId);
if (healthCheckInterval) clearInterval(healthCheckInterval);
tile.remove();
mediaEls.delete(peerId);
}
return;
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// ERRORES
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if (m.type === 'consume-error') {
const { producerId, error } = m;
log('β Error al consumir:', producerId, error);
return;
}
};
Flujo Completo: Auctioneer Inicia Streaming
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β AUCTIONEER β β SERVER β β BIDDER β
ββββββββ¬βββββββ ββββββββ¬βββββββ ββββββββ¬βββββββ
β β β
β 1. WebSocket connect β β
βββββββββββββββββββββββββββββββ>β β
β β β
β 2. welcome, rtp-capabilities β β
β<βββββββββββββββββββββββββββββββ€ β
β β β
β 3. create-transport (send) β β
βββββββββββββββββββββββββββββββ>β β
β β β
β 4. transport-created β β
β<βββββββββββββββββββββββββββββββ€ β
β β β
β 5. connect-transport β β
βββββββββββββββββββββββββββββββ>β β
β β β
β 6. transport-connected β β
β<βββββββββββββββββββββββββββββββ€ β
β β β
β 7. produce (video) β β
βββββββββββββββββββββββββββββββ>β β
β β β
β 8. produced β 9. producer-announced (broadcast)
β<βββββββββββββββββββββββββββββββ€ββββββββββββββββββββββββββββββ>β
β β β
β β 10. (Bidder consume video...) β
β β<βββββββββββββββββββββββββββββββ€
β β β
β 11. Detener cΓ‘mara β β
β (producer.close()) β β
βββββββββββββββββββββββββββββββ>β β
β β β
β β 12. producer-closed (broadcast)
β βββββββββββββββββββββββββββββββ>β
β β β
β β 13. UI muestra "TransmisiΓ³n β
β β finalizada" β
β β β
π Tabla Resumen de Eventos
| Evento | DirecciΓ³n | Prioridad | CuΓ‘ndo |
|---|---|---|---|
welcome |
Server β Client | Alta | ConexiΓ³n inicial |
rtp-capabilities |
Server β Client | Alta | DespuΓ©s de welcome |
producer-announced |
Server β All | Alta | Nuevo producer |
producer-closed |
Server β All | CRΓTICA | Producer cierra |
producer-paused π |
Server β All | Media | Producer pausa |
producer-resumed π |
Server β All | Media | Producer reanuda |
transport-created |
Server β Client | Alta | Crear transport |
transport-closed π |
Server β All | CRΓTICA | Transport cierra |
transport-state-changed π |
Server β All | Media | Cambio estado transport |
peer-joined π |
Server β All | Media | Peer conecta |
peer-left π |
Server β All | CRΓTICA | Peer desconecta |
consume-error π |
Server β Client | Alta | Error al consumir |
producers (lista) |
Server β Client | Alta | Late-joiner sync |
consumable |
Server β Client | Alta | Params de consumer |
π― Eventos CrΓticos (4)
Estos eventos son esenciales para el correcto funcionamiento del sistema:
producer-closed- Limpieza de UI cuando se detiene video/audiotransport-closed- DetecciΓ³n de fallas de conexiΓ³npeer-left- Limpieza de recursos al desconectarseconsume-error- Manejo de errores de reproducciΓ³n