So implementieren Sie Videokonferenzen in Next.js

Ein Video-Meeting sieht aus wie ein einzelnes Feature, doch in einer Next.js-App sind es mehrere. Ein Team öffnet seinen Meeting-Raum, und alle sehen und hören einander, ein paar Leute oder ein paar Dutzend, mit geteilten Bildschirmen. Jemand leitet das Meeting und kann ein störendes Mikrofon stummschalten oder jemanden aus dem Meeting entfernen. Wer die Seite öffnet, während das Meeting läuft, sollte sofort drin sein, und alle anderen im Team sollten erfahren, dass es begonnen hat, auf welcher Seite sie auch gerade sind.
Dieser Beitrag geht jeden Teil durch, den eine echte App braucht, mit einem vollständigen, funktionierenden Beispiel: Team Space, das Team-Intranet aus unserer Next.js-Anleitung. Dort hat jedes Team seinen Meeting-Raum und seine Kanäle, und Kolleginnen und Kollegen sehen, wer online ist, und rufen einander an. Sie können es live ausprobieren: Seien Sie Mia, die Design leitet, und starten Sie das Meeting des Teams, dann öffnen Sie die Seite von Design in einem privaten Fenster als Ava, die ebenfalls zu Design gehört, und schon beim Öffnen der Seite ist sie im Meeting.
Was Videokonferenzen brauchen
- Viele Kameras gleichzeitig. Zwischen zwei Personen kann das Bild direkt von einem Browser zum anderen gehen. In einem Meeting schickt jeder Browser seine Kamera einmal an Medienserver, die sie an alle anderen weitergeben (wie Medienserver funktionieren). Ihre Verbindungen bleiben das ganze Meeting über offen, und die kann eine Serverless-Funktion nicht halten (warum, und was sich dagegen tun lässt).
- Wer teilnehmen darf und wer leitet. Eine Regel auf Ihrem Server, mit Ihren eigenen Daten: Die Mitglieder des Teams nehmen teil, die Teamleitung ist Host, und sonst kommt niemand hinein.
- Ein Meeting-Raum in der Seite. Die Kameras und Bildschirme aller, die Steuerung, und ein Meeting, das weiterläuft, während man zwischen den Seiten Ihrer App wechselt.
- Hineinkommen. Ein Button, um das Meeting zu starten oder ihm beizutreten, und eine Seite, die einen direkt hineinbringt, während das Meeting läuft.
- Die Steuerung des Hosts. Jemanden stummschalten oder aus dem Meeting entfernen.
- Wissen, dass es begonnen hat. Ein Hinweis an das Team, und Listen der gerade laufenden Meetings, die sich von selbst aktualisieren.
Sie können all das selbst bauen, auf WebRTC und eigenen Medienservern. Oder Sie lassen eine Echtzeit-Cloud die Medien und den Meeting-Bildschirm betreiben, während Ihr Server den einen Teil behält, der wirklich Ihrer ist: die Regel. Genau das macht Team Space, über WordPlus Cloud.
Das Beispiel: ein Team-Intranet
Die Kolleginnen und Kollegen arbeiten in Teams, und jedes Team hat eine Leitung. Ein Team hat eine eigene Seite: seinen Meeting-Raum, seine Kanäle und seine Mitglieder, angeführt von denen, die online sind. Es ist eine Next.js-App mit dem App Router, Better Auth und Postgres, und ihr Echtzeit-Teil besteht aus wenigen Dateien. Fünf Schritte machen ihre Meetings.
1. Wer teilnehmen darf und wer Host ist
Jedes Team hat einen Meeting-Raum, einen Gruppenanruf, benannt nach der Nummer des Teams: meeting:3. Die Website deklariert sie einmal, nach diesem Muster, mit der Regel:
realtime.groupCalls('meeting:{id}', async (user, { id }) => {
if (!(await isMember(id, user))) return false;
const team = await teamOf(id);
return team?.lead === String(user) ? { admin: true } : true;
});Wer zum Team gehört, kommt hinein, die Teamleitung mit admin: true, was sie zum Host macht. Alle anderen bekommen false, und die Seite des Teams fragt dasselbe isMember, also sind sich Seite und Meeting nie uneinig. Will eine Seite beitreten, fragt sie zuerst den eigenen Server der Website, unter /api/realtime/calls. Es ist derselbe Route Handler, über den auch die Anrufe der Dating-Website laufen (so implementieren Sie Videoanrufe in Next.js). Die Regel läuft mit der eigenen Sitzung der Website, und die Seite bekommt einen Pass für das Meeting, signiert mit dem Secret der App, oder den Grund, warum nicht.
2. Der Meeting-Raum in der Seite
Das Meeting erscheint direkt auf der Seite des Teams, dort, wo die Seite es platziert, mit dem Button zum Starten darin:
export function MeetingRoom({ room, team, people }: Props) {
const rt = useRealtime();
return (
<CallSpot rt={rt} call={room} className="h-[32rem] rounded-2xl">
<p>The {team} meeting room</p>
<GroupCallButton rt={rt} room={room} type="video" title={`${team} meeting`}>
{people.length > 0 ? 'Join the meeting' : 'Start the meeting'}
</GroupCallButton>
</CallSpot>
);
}Vor dem Meeting zeigt CallSpot das, was darin steht: den Namen des Raums, wer gerade im Meeting ist, und den Button. Sobald diese Person drin ist, tritt das Meeting an seine Stelle: die Kameras aller in einem Raster, ein geteilter Bildschirm groß, und die Steuerung für Mikrofon, Kamera, Bildschirm und Verlassen. Auf einer anderen Seite der App läuft das Meeting in einem Fenster in der Ecke weiter und kehrt hierher zurück, sobald die Seite des Teams wieder geöffnet wird. Wer die Website verlässt oder die Seite neu lädt, wird vorher gefragt.
3. Direkt hinein, sobald die Seite sich öffnet
Wer die Seite öffnet, während das Meeting läuft, sollte nichts drücken müssen. Die Seite weiß von ihrem Server, ob jemand im Meeting ist (Schritt 4), und gibt dem Spot nur dann join:
const [join] = useState(people.length > 0 ? ('video' as const) : undefined);
<CallSpot rt={rt} call={room} join={join} className="h-[32rem] rounded-2xl">Mit join tritt der Spot dem Meeting bei, sobald die Seite sich öffnet, wie es der Button tun würde, und die Regel entscheidet wie bei einem Klick. Das wird einmal entschieden, beim Öffnen der Seite, und im State gehalten: Wer das Meeting verlässt oder von der Teamleitung entfernt wird, bleibt draußen, solange die Seite offen ist. Ist niemand im Meeting, tritt die Seite auch nicht bei, und wer als Erstes kommt, startet es mit dem Button.
Wer so dazukommt, hat Kamera und Mikrofon aus: Das Meeting ist sofort zu sehen und zu hören, und der Browser fragt erst dann nach Kamera oder Mikrofon, wenn man eines davon in der Steuerung einschaltet. So startet das Öffnen einer Seite nie überraschend eine Kamera. Soll man gleich beim Dazukommen sprechen können, schaltet joinWith="microphone" das Mikrofon schon beim Beitreten ein, und "microphone camera" beides.
4. Wer drin ist
WordPlus Cloud weiß, wer in jedem Meeting ist, also führt die Website keine Tabelle dafür:
export async function inMeeting(team: string): Promise<string[]> {
const { list } = await realtime.call(meetingOf(team)).get();
return list.flatMap((person) => (person.user ? [String(person.user)] : []));
}Die Seite des Teams fragt das beim Rendern ab und zeigt die Gesichter derer, die im Meeting sind, mit „Mia and Omar are in the meeting“. Die Liste der Teams fragt auf dieselbe Weise realtime.listCalls() nach jedem gerade laufenden Meeting und danach, wie viele jeweils darin sind.
5. Ein Meeting beginnt, und wer davon erfährt
Wenn jemand einem Meeting beitritt, schickt WordPlus Cloud der Website einen Webhook. Die Website sagt jeder Seite, dass sich die Meetings geändert haben, und ist es die erste Person im Meeting, benachrichtigt sie den Rest des Teams:
realtime.on('group.joined', async ({ call, user }) => {
const team = teamIn(call);
if (!team) return;
await realtime.to('meetings').emit('changed');
// The first one in starts it.
const { people } = await realtime.call(call).get();
if (people > 1) return;
const others = (await peopleIn(team)).map((person) => person.id).filter((id) => id !== String(user));
await realtime.toUser(others).emit('meeting', {
team,
name: (await teamOf(team))?.name,
by: await nameOf(String(user)),
});
});toUser() erreicht jede Seite, die eine dieser Personen geöffnet hat, auf jedem Gerät. Im Layout hören die Seiten auf beides:
useUserEvent('meeting', (data: MeetingStarted) => {
if (path === `/teams/${data.team}`) return; // its page shows it already
show(`${data.by} started the ${data.name} meeting`, `/teams/${data.team}`);
});
useRoom('meetings', { changed: () => router.refresh() });Der erste Hook zeigt einen Hinweis, der die Seite des Teams öffnet: „Leo started the Engineering meeting“. Der zweite lässt jede Seite den Server erneut nach ihren Listen fragen, ohne Neuladen, sodass immer stimmt, wer in welchem Meeting ist. Der Webhook group.left schickt ebenfalls changed, wenn jemand geht.
Der Host, ohne eigenen Code
admin: true in der Regel ist alles, was den Host ausmacht. Auf dem Bildschirm der Teamleitung hat jede Kachel der anderen einen Button zum Stummschalten und einen zum Entfernen, und der Anrufbildschirm schickt die Anfrage über dieselbe Route an WordPlus Cloud, das sie nur von einem Host annimmt. Wer stummgeschaltet wurde, darf das Mikrofon wieder einschalten, und wer entfernt wird, ist sofort draußen. Damit die Person draußen bleibt, sagt die Regel Nein.
Was dazugehört
- Bildschirmfreigabe, samt Ton, direkt aus der Steuerung.
- Auch Anrufe zu zweit. In Team Space hat ein Gespräch mit einer Kollegin oder einem Kollegen einen eigenen Anruf, der neben den Nachrichten erscheint, so wie auf der Dating-Website.
- Namen und Gesichter aus Ihrer App. Jede Kachel zeigt Namen und Foto einer Person so, wie das
profileder Website sie liefert, ohne dass WordPlus Cloud eine Liste der Nutzer führt. - Zugang entziehen. Verlässt jemand ein Team, nimmt die Website die Person mit
realtime.call(name).remove(user)sofort aus dessen Meeting, und ab dann sagt die Regel Nein.
Ausprobieren, dann selbst bauen
In der Live-Demo gehören die Kolleginnen, Kollegen und Teams einen Tag lang nur Ihnen: Was Sie dort schreiben oder mit wem Sie sich treffen, sieht sonst niemand, und ein Meeting endet nach 10 Minuten von selbst. Unter jeder Seite zeigt How this page works Schritt für Schritt den Code, der sie erzeugt, mit den Werten der Seite, die Sie gerade geöffnet haben.
Die Anleitung zum Team-Intranet baut die ganze Website auf, mit jeder Datei ihres Echtzeit-Teils in voller Länge, und Anrufe in Next.js zeigt jeden Weg, einen Anruf oder ein Meeting in Ihre eigene App zu bringen.
Für WordPlus Cloud for Apps gelten Preise nach gleichzeitigen Verbindungen, ab 1.000, monatlich oder jährlich abgerechnet. Mit 1.000 Verbindungen sind Gruppenanrufe bis zu 32 Personen mit Video gleichzeitig ohne Abrechnung, wobei eine Person nur mit Audio halb zählt, und mit jeweils 1.000 weiteren Verbindungen kommen 12 hinzu. Darüber verbraucht jede weitere Person mit Video ein Credit pro Minute, und Anrufe zwischen zwei Personen verbrauchen keine. Sehen Sie sich Videoanrufe für Apps an, oder werfen Sie einen Blick auf die Preise für Apps. Fragen zu Ihrer Integration? Schreiben Sie uns.