Blog

Zo implementeer je livestreaming in Next.js

· Andrij Tkachenko · 7 min leestijd

Een browservenster met iemand in beeld en een gast ernaast, dat uitzendt naar vier kleinere vensters, in één steekt iemand een hand op, in een ander schrijft iemand

Een livestream lijkt één functie, maar in een Next.js-app zijn het er meerdere. Iemand gaat live vanuit de browser, of vanuit een encoder zoals OBS. Iedereen die mag kijken, ziet en hoort het op hetzelfde moment, dichtbij genoeg om een vraag te stellen en antwoord te krijgen. Kijkers schrijven in een chat, reageren, en sommigen komen met hun eigen camera op het podium. En voor dat alles moet je app beslissen wie uitzendt, wie kijkt en wie hoort dat een stream begonnen is.

Dit artikel loopt elk onderdeel langs dat een echte app nodig heeft, met een volledig werkend voorbeeld: Live Lessons, de site voor livelessen uit onze Next.js-handleiding, waar docenten koken, muziek en fitness live gaan in hun lessen, en leerlingen kijken, vragen stellen en op het podium komen. Je kunt het live uitproberen: wees Mia en ga live vanuit haar studio, open daarna haar les in een privévenster als Ava, een van haar leerlingen, om te kijken en je hand op te steken.

Wat livestreaming nodig heeft

  • Het beeld erin. De camera en microfoon vanuit de browser, een gedeeld scherm met geluid, of een encoder via WHIP voor scènes en meerdere camera’s.
  • Het beeld eruit, naar velen, op hetzelfde moment. Een stream waarvan het publiek terugpraat, gaat over WebRTC, zoals gesprekken, via mediaservers die hem aan elke kijker doorgeven (hoe mediaservers werken). De verbindingen blijven de hele stream open, en dat kan een serverless functie niet volhouden (waarom, en wat je eraan doet).
  • Wie uitzendt en wie kijkt. Een regel op je server, met je eigen gegevens: de docent zendt uit, de leerlingen van de cursus kijken, en een open les mag iedereen zien.
  • Een studio en een speler. Live gaan en stoppen, de camera en het scherm, de chat, reacties en hoeveel mensen kijken.
  • Het podium. Een kijker steekt een hand op, de docent nodigt hem uit, en iedereen ziet hem naast de docent.
  • Weten wat er live is. Lijsten van de streams die nu live zijn en zichzelf bijwerken, en een melding voor wie het wil weten.

Je kunt elk onderdeel zelf bouwen, op WebRTC en eigen mediaservers. Of je laat een realtime cloud de media, de studio en de speler draaien, terwijl je server het ene deel houdt dat echt van jou is: de regel. Dat doet Live Lessons, met WordPlus Cloud.

Het voorbeeld: livelessen

Docenten hebben cursussen, elk met hun lessen. Een les staat open voor iedereen, of alleen voor de leerlingen van de cursus. Een docent gaat live in een les vanuit de eigen studio, en leerlingen kijken op de pagina van de les. Het is een Next.js-app met de App Router, Better Auth en Postgres, en het realtime deel is een paar bestanden. Vijf stappen maken de streams.

1. Wie mag kijken

Elke les heeft een stream, genoemd naar haar nummer: lesson:7. De site declareert ze één keer, met dat patroon, samen met de regel:

lib/realtime.ts
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 },
);

De docent is de host, met beeld tot 1080p. Wie mayWatch binnenlaat, kijkt mee, en user is null voor een bezoeker die niet is ingelogd, dus een open les heeft geen account nodig. Iedereen anders krijgt false. De instellingen laten gasten op het podium toe, en reacties. De pagina van de les vraagt dezelfde mayWatch, dus de pagina en de stream zijn het altijd eens.

2. Waar de regel draait

Als een pagina live wil gaan, of wil kijken, vraagt ze het eerst aan de eigen server van de site, in een route handler:

app/api/realtime/calls/route.ts
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);
}

Het is dezelfde route waar de videogesprekken van de datingsite doorheen gaan (zo implementeer je videogesprekken in Next.js). De regel draait met de eigen sessie van de site, en de pagina krijgt een pas voor de stream, ondertekend met het geheim van de app, of de reden waarom niet. De route antwoordt in één kort verzoek, precies waar serverless hosting goed in is.

3. De studio van de docent

Een docent gaat live vanaf een eigen pagina, met de studio van WordPlus Cloud erin:

app/(site)/studio/[id]/page.tsx
<LiveStream
    name={roomOf(lesson.id)}
    view="studio-page"
    title={`${lesson.position}. ${lesson.title}`}
    url={`/lessons/${lesson.id}`}
    backUrl="/studio"
/>

De studio vult de hoogte die de pagina haar geeft: het beeld zo groot als past, met de camera, het scherm, OBS en Go live eronder, en ernaast, in tabbladen, de chat, de gasten met de opgestoken handen, en de stream met de link van de les om te delen. Vooraf controleert de pagina of degene die vraagt de les geeft, en stuurt ieder ander naar de les. Na het inloggen komt een docent bij een lijst van de eigen lessen, elk één klik van live gaan.

4. De pagina van de les

Leerlingen kijken waar de les is:

app/(site)/lessons/[id]/page.tsx
<LiveStream
    name={roomOf(lesson.id)}
    title={lesson.title}
    loginUrl="/signin"
    studioUrl={teaches ? `/studio/${lesson.id}` : undefined}
/>

Eén element tekent de speler en de chat. Voordat de les begint, zegt het dat, en het speelt zodra de docent live gaat, zonder herladen. Een ingelogde leerling kan schrijven, reageren en op Ask to join on stage drukken. Een bezoeker kijkt en leest mee, met de weg om in te loggen. De docent ziet de weg naar de studio boven de speler.

5. Wat er live is, altijd actueel

WordPlus Cloud weet welke streams live zijn en hoeveel mensen elk ervan kijken, dus de site houdt er geen tabel voor bij:

lib/realtime.ts
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;
}

De startpagina toont daarmee de lessen die nu live zijn. Om die lijst actueel te houden op pagina’s die al open staan, stuurt WordPlus Cloud de site een webhook als een stream live gaat en als hij eindigt, en de site geeft die door aan een ruimte waar elke pagina aan meedoet, ook die van een bezoeker:

lib/realtime.ts
realtime.room('live', { public: true });

realtime.on('stream.ended', async ({ stream }) => {
    if (lessonIn(stream)) await realtime.to('live').emit('changed');
});
app/(site)/live.tsx
export function LiveNow() {
    const router = useRouter();
    useRoom('live', { changed: () => router.refresh() });
    return null;
}

LiveNow staat in de layout, dus elke pagina vraagt de server opnieuw om haar lijsten, zonder herladen. De webhook stream.live doet hetzelfde, en meldt het bovendien aan de leerlingen van de cursus, en bij een open les aan de volgers van de docent, op welke pagina ze ook zijn: „Mia is live: Your first tune”.

Het podium, zonder eigen code

stage: true in de regel is alles wat het podium nodig heeft. Terwijl een les live is, steekt een leerling vanuit de speler een hand op, de docent ziet dat onder Guests en drukt op Invite, en zodra de leerling accepteert, ziet iedereen hem naast de docent, met camera en microfoon. De docent kan hem dempen of van het podium halen, en de leerling kan het zelf verlaten en weer gewoon kijken, zonder herladen.

Wat erbij zit

  • Vanuit de browser of met OBS. De studio gaat live met de camera, met een scherm en het geluid, of met allebei, of neemt OBS of een andere encoder via WHIP aan.
  • Op hetzelfde moment. De stream gaat over WebRTC, dus een vraag in de chat bereikt de docent terwijl die nog bij het onderwerp is.
  • Een chat die je bijhoudt. Moderators zetten berichten vast, verwijderen, dempen een tijdje, verwijderen mensen en verbannen ze, en de regel kan een assistent van de docent moderator maken: { role: 'viewer', mod: true }.
  • Toegang intrekken. Als een leerling een cursus verlaat, haalt de site hem met realtime.stream(name).kick() uit de lessen die nu live zijn, en vanaf dan zegt de regel nee.

Probeer het, en bouw dan je eigen

In de live demo zijn de docenten en leerlingen een dag lang alleen van jou, dus wat je er ook uitzendt of schrijft, niemand anders ziet het. Onder elke pagina toont How this page works stap voor stap de code die de pagina maakt, met de waarden van de pagina die je open hebt.

De handleiding voor Live Lessons bouwt de hele site, met elk bestand van de realtime kant volledig uitgeschreven, en livestreams in Next.js laat elke manier zien om een stream in je eigen app te zetten, met een eigen weergave erbij.

WordPlus Cloud for Apps is geprijsd op gelijktijdige verbindingen, vanaf 1.000, maandelijks of jaarlijks gefactureerd. Met 1.000 verbindingen worden livestreams niet gemeten tot 50 kijkers tegelijk, en elke 1.000 verbindingen extra voegen er 20 toe. Daarboven kost elke extra kijker een credit per minuut, alleen geteld terwijl de stream live is. Bekijk livestreaming voor apps, of de prijzen voor apps. Vragen over je integratie? Schrijf ons.