Cómo implementar transmisiones en directo en Next.js

Una transmisión en directo parece una sola función, y en una app de Next.js son varias. Alguien sale en directo desde el navegador, o desde un codificador como OBS. Todos los que pueden verla la ven y la oyen al mismo tiempo, lo bastante cerca como para hacer una pregunta y recibir la respuesta. Los espectadores escriben en un chat, reaccionan, y algunos suben al escenario con su propia cámara. Y antes de todo eso, tu app tiene que decidir quién transmite, quién mira y quién se entera de que una transmisión ha empezado.
Este artículo recorre cada parte que necesita una app real, con un ejemplo completo que funciona: Live Lessons, el sitio de clases en directo de nuestra guía de Next.js, donde profesores de cocina, música y fitness salen en directo en sus lecciones, y los alumnos miran, preguntan y suben al escenario. Puedes probarlo en vivo: sé Mia y sal en directo desde su estudio, luego abre su lección en una ventana privada como Ava, una de sus alumnas, para mirar y levantar la mano.
Lo que necesita una transmisión en directo
- La imagen hacia dentro. La cámara y el micrófono desde el navegador, una pantalla compartida con su sonido, o un codificador por WHIP para escenas y varias cámaras.
- La imagen hacia fuera, a muchos y al mismo tiempo. Una transmisión cuyo público responde va por WebRTC, como las llamadas, a través de servidores de medios que la reenvían a cada espectador (cómo funcionan los servidores de medios). Sus conexiones siguen abiertas durante toda la transmisión, algo que una función serverless no puede mantener (por qué, y qué hacer).
- Quién transmite y quién mira. Una regla en tu servidor, con tus propios datos: el profesor transmite, los alumnos del curso miran, y una lección abierta la puede ver cualquiera.
- Un estudio y un reproductor. Salir en directo y terminar, la cámara y la pantalla, el chat, las reacciones y cuántos miran.
- El escenario. Un espectador levanta la mano, el profesor lo invita, y todos lo ven a su lado.
- Saber qué está en directo. Listas de las transmisiones en directo que se actualizan solas, y un aviso a quien quiera saberlo.
Puedes construir cada parte tú mismo, sobre WebRTC y servidores de medios propios. O dejas que una nube en tiempo real se encargue de los medios, el estudio y el reproductor, mientras tu servidor conserva la única parte que es realmente tuya: la regla. Eso es lo que hace Live Lessons, con WordPlus Cloud.
El ejemplo: clases en directo
Los profesores tienen cursos, cada uno con sus lecciones. Una lección está abierta a cualquiera, o solo a los alumnos de su curso. Un profesor sale en directo en una lección desde su estudio, y los alumnos miran en la página de la lección. Es una app de Next.js con App Router, Better Auth y Postgres, y su parte en tiempo real son unos pocos archivos. Cinco pasos hacen sus transmisiones.
1. Quién puede mirar
Cada lección tiene una transmisión, con el nombre de su número: lesson:7. El sitio las declara una sola vez, con ese patrón, junto con la regla:
realtime.streams(
'lesson:{id}',
async (user, { id }) => {
const lesson = await lessonOf(id);
if (!lesson) return false;
const me = user === null ? null : String(user);
if (me === lesson.teacher) return { role: 'host', quality: '1080p' };
return (await mayWatch(me, lesson)) ? 'viewer' : false;
},
{ stage: true, reactions: true },
);El profesor es el anfitrión, con la imagen hasta 1080p. A quien mayWatch deja entrar es espectador, y user es null para un visitante sin sesión iniciada, así que una lección abierta no necesita cuenta. Cualquier otro recibe false. La configuración permite invitados en el escenario y reacciones. La página de la lección pregunta al mismo mayWatch, así que la página y la transmisión nunca discrepan.
2. Dónde se ejecuta la regla
Cuando una página pide salir en directo, o mirar, pregunta primero al servidor del propio sitio, en un route handler:
import { currentUserId } from '@/lib/auth';
import { realtime } from '@/lib/realtime';
export async function POST(request: Request) {
// JSON only, which a page of another site can't send here.
if (!request.headers.get('content-type')?.includes('application/json')) {
return new Response(null, { status: 415 });
}
const ask = await request.json();
const user = await currentUserId();
const pass = await realtime.authorizeCall(ask, user);
return Response.json(pass);
}Es la misma ruta por la que pasan las videollamadas del sitio de citas (cómo implementar videollamadas en Next.js). La regla se ejecuta con la sesión del propio sitio, y la página recibe un pase para la transmisión, firmado con el secreto de la app, o el motivo por el que no. La ruta responde en una petición corta, que es justo en lo que destaca el hosting serverless.
3. El estudio del profesor
Un profesor sale en directo desde una página propia, con el estudio de WordPlus Cloud dentro:
<LiveStream
name={roomOf(lesson.id)}
view="studio-page"
title={`${lesson.position}. ${lesson.title}`}
url={`/lessons/${lesson.id}`}
backUrl="/studio"
/>El estudio ocupa la altura que le da la página: la imagen tan grande como cabe, con la cámara, la pantalla, OBS y Go live debajo, y al lado, en pestañas, el chat, los invitados con las manos levantadas, y la transmisión con el enlace de la lección para compartir. Antes, la página comprueba que quien pregunta imparte la lección, y envía a cualquier otro a la lección. Al iniciar sesión, un profesor llega a una lista de sus lecciones, cada una a un clic de salir en directo.
4. La página de la lección
Los alumnos miran donde está la lección:
<LiveStream
name={roomOf(lesson.id)}
title={lesson.title}
loginUrl="/signin"
studioUrl={teaches ? `/studio/${lesson.id}` : undefined}
/>Un solo elemento dibuja el reproductor y su chat. Antes de que empiece la lección lo indica, y se reproduce en cuanto el profesor sale en directo, sin recargar. Un alumno con sesión iniciada puede escribir, reaccionar y pulsar Ask to join on stage. Un visitante mira y lee, con el camino para iniciar sesión. El profesor ve el camino a su estudio encima del reproductor.
5. Qué está en directo, siempre al día
WordPlus Cloud sabe qué transmisiones están en directo y cuántos miran cada una, así que el sitio no guarda ninguna tabla para ello:
export async function liveNow(): Promise<Map<string, number>> {
const live = new Map<string, number>();
for (const stream of await realtime.listStreams()) {
const lesson = lessonIn(stream.name);
if (lesson) live.set(lesson, stream.viewers);
}
return live;
}La página de inicio lista con ello las lecciones en directo. Para que esa lista siga al día en las páginas ya abiertas, WordPlus Cloud envía al sitio un webhook cuando una transmisión empieza y cuando termina, y el sitio lo pasa a una sala a la que se une cada página, también la de un visitante:
realtime.room('live', { public: true });
realtime.on('stream.ended', async ({ stream }) => {
if (lessonIn(stream)) await realtime.to('live').emit('changed');
});export function LiveNow() {
const router = useRouter();
useRoom('live', { changed: () => router.refresh() });
return null;
}LiveNow está en el layout, así que cada página vuelve a pedir sus listas al servidor, sin recargar. El webhook stream.live hace lo mismo y además avisa a los alumnos del curso, y en una lección abierta a los seguidores de su profesor, con un aviso en la página en la que estén: «Mia is live: Your first tune».
El escenario, sin código tuyo
stage: true en la regla es todo lo que necesita el escenario. Mientras una lección está en directo, un alumno levanta la mano desde el reproductor, el profesor la ve en Guests y pulsa Invite, y en cuanto el alumno acepta, todos lo ven junto al profesor, con cámara y micrófono. El profesor puede silenciarlo o bajarlo del escenario, y el alumno puede dejarlo y volver a mirar sin recargar.
Lo que viene incluido
- Desde el navegador o con OBS. El estudio sale en directo con la cámara, con una pantalla y su sonido, o con ambas, o recibe OBS o cualquier codificador por WHIP.
- Al mismo tiempo. La transmisión va por WebRTC, así que una pregunta en el chat llega al profesor mientras sigue con el tema.
- Un chat que se cuida. Los moderadores fijan, borran, silencian un rato, expulsan y bloquean, y la regla puede nombrar moderador a un ayudante del profesor:
{ role: 'viewer', mod: true }. - Retirar el acceso. Cuando un alumno deja un curso, el sitio lo saca de sus lecciones en directo con
realtime.stream(name).kick(), y desde entonces la regla dice que no.
Pruébalo y luego construye el tuyo
En la demo en vivo, los profesores y alumnos son solo tuyos durante un día, así que nadie más ve lo que transmitas o escribas. Debajo de cada página, How this page works muestra el código que la hace funcionar, paso a paso, con los valores de la página que tienes abierta.
La guía de Live Lessons construye el sitio entero, con cada archivo de su parte en tiempo real completo, y las transmisiones en directo en Next.js reúne todas las formas de poner una transmisión en tu propia app, con una interfaz propia incluida.
WordPlus Cloud for Apps tiene un precio según las conexiones simultáneas, a partir de 1.000, con facturación mensual o anual. Con 1.000 conexiones, las transmisiones en directo no se miden hasta 50 espectadores a la vez, y cada 1.000 conexiones más añaden 20. Por encima, cada espectador adicional gasta un crédito por minuto, contado solo mientras la transmisión está en directo. Descubre las transmisiones en directo para apps, o consulta los precios para apps. ¿Preguntas sobre tu integración? Escríbenos.