JavaScript APIs

Übersicht

Mit der JavaScript-API steuern Sie aus Ihrer eigenen Seite heraus einen laufenden Meetingraum. Sie muten Ihr eigenes Mikrofon, lesen die Teilnehmerliste, senden Chat-Nachrichten, wechseln Geräte und hören auf Events. Das gelingt Ihnen mit einem eingebetteten iFrame genauso wie mit den Web-Komponenten von Veeting Blocks.

Verwendung mit einem KI-Assistenten

Wenn Sie mit einem KI-Coding-Assistenten arbeiten, können Sie den folgenden Text in Ihren Assistenten kopieren und mit einem Satz ergänzen, der beschreibt, was Sie programmieren möchten.

Der Prompt verweist auf unsere Entwicklerdokumentation, die wir für Coding-Assistenten in einer separaten, token-optimierten KI-Version ausliefern.

Lies zuerst diese Seite, bevor Du Code schreibst:
https://www.veeting.com/de/developer-documentation/javascript-apis

Sie dokumentiert die JavaScript-API eines Veeting Rooms
Meetingraums. Halte Dich an diese fünf Regeln:

1. Frage mich zuerst, wo mein Code läuft: IM Raum (Veeting Blocks),
   in einem eigenen Tool (ein iFrame im Raum) oder in der Seite rund
   um einen eingebetteten iFrame. Alle drei erreichen die API
   unterschiedlich, und die Antwort ändert alles Weitere. Ein
   eigenes Tool bekommt weder den Handler noch Events und kann nur
   {action, payload} per postMessage an window.parent senden.
2. Warte auf das Event «joined», bevor Du Methoden aufrufst, die
   die Anwesenheit im Meeting voraussetzen.
3. «connected» bezieht sich nur auf den WebSocket zu unserer API,
   nicht auf WebRTC-Medien. Behandle es nicht als Medienzustand.
   «disconnected» kommt, wenn dieser WebSocket abbricht, aber auch,
   wenn die Medienverbindung abbricht.
4. Verwende nur Methoden, die auf dieser Seite stehen. Erfinde
   keine und rate keine Signatur.
5. Aus einer übergeordneten Seite sprichst Du per postMessage mit
   dem Raum: {action, payload} hinein, {event, payload} heraus. Das
   geht nur in eine Richtung, Methoden mit Rückgabewert nützen dort
   also nichts. Prüfe message.origin bei allem, was ankommt.

Was ich bauen möchte:

Wo Ihr Code läuft, entscheidet über den Zugang zur API

Diese Frage ist wichtiger als alles andere auf dieser Seite. Klären Sie sie zuerst.

Ihr Code läuftSo erreichen Sie die API
Im Meetingraum selbst, also in Veeting BlocksDirekt über den Handler. Die vollständige API, samt Rückgabewerten.
In einem eigenen Tool, also einem iFrame im RaumNur postMessage an window.parent mit { action, payload }. Ohne Events und Rückgabewerte.
In der Seite rund um einen eingebetteten iFrameÜber postMessage. Sie rufen jede Methode auf, die nichts zurückgibt, und empfangen jedes Event.

Betten Sie den Raum als iFrame ein, sind Ihre Seite und der Meetingraum zwei verschiedene Dokumente, meist auf zwei verschiedenen Origins. Ihre Seite kommt nicht an das window des Raums heran und der Raum nicht an Ihres. Alles überquert diese Grenze als Nachricht.

Unterschiedliche Origins sind vorgesehen und werden unterstützt. Der Raum läuft normalerweise unter Ihrer eigenen White-Label-Domain, zum Beispiel meeting.example.com, während Ihre Anwendung unter app.example.com oder ganz woanders liegt. Beides braucht keine Sonderbehandlung: Eine andere Subdomain und eine völlig andere Domain verhalten sich hier gleich.

Den Raum aus der umgebenden Seite steuern

Events empfangen

Der Meetingraum sendet jedes Event an sein übergeordnetes Fenster. Hören Sie auf diese Nachrichten:

window.addEventListener("message", (message) => {
  // Always check the origin. The room posts to any parent, so this check is
  // yours to make, and without it any page could forge these events.
  if (message.origin !== "https://<DOMAIN-NAME>") {
    return;
  }

  const { event, payload } = message.data;

  if (event === "joined") {
    console.log("The meeting room is ready");
  }

  if (event === "participantsUpdated") {
    console.log(`${payload.length} participants in the room`);
  }
});

event ist einer der 13 Namen weiter unten, payload genau das, was dieses Event mitführt. Sie müssen nichts abonnieren: Jedes Event geht an die übergeordnete Seite, ob Sie darauf hören oder nicht.

Methoden aufrufen

Senden Sie dem iFrame eine Nachricht mit dem Namen der Methode und ihren Argumenten:

const room = document.getElementById("meeting-frame");

room.contentWindow.postMessage({
  action: "muteAudio",
  payload: [true]
}, "https://<DOMAIN-NAME>");

action ist der Methodenname, payload sind die Argumente der Methode, in der richtigen Reihenfolge als Array. Bei einer Methode ohne Argumente übergeben Sie payload: [] oder lassen das Feld ganz weg.

Weil der Weg nur in eine Richtung führt, gelten zwei Grenzen:

  • Sie erhalten keinen Rückgabewert. Alles, was mit get beginnt, nützt über diese Grenze hinweg also nichts. Lesen Sie die Teilnehmer aus dem Event participantsUpdated statt über getParticipantsList(), und die Raumkonfiguration aus meetingRoomConfigUpdated.
  • Sie erhalten auch keinen Fehler. Vertippen Sie sich im Methodennamen, geschieht nichts, und es wird auch nichts gemeldet. Prüfen Sie den Namen gegen die Tabellen weiter unten.

Ein vollständiges Beispiel

Ein Mute-Button und ein Teilnehmerzähler in Ihrer eigenen Seite, ausserhalb des iFrames:

<button id="mute">Mute</button>
<span id="count">0</span> participants

<iframe id="meeting-frame"
  src="https://<DOMAIN-NAME>/meeting/<MEETING-ID>"
  allow="microphone;camera;encrypted-media;fullscreen;autoplay;display-capture;layout-animations;">
</iframe>

<script>
  const ROOM_ORIGIN = "https://<DOMAIN-NAME>";
  const room = document.getElementById("meeting-frame");
  let muted = false;

  window.addEventListener("message", (message) => {
    if (message.origin !== ROOM_ORIGIN) {
      return;
    }
    if (message.data.event === "participantsUpdated") {
      document.getElementById("count").textContent = message.data.payload.length;
    }
  });

  document.getElementById("mute").addEventListener("click", () => {
    muted = !muted;
    room.contentWindow.postMessage({ action: "muteAudio", payload: [muted] }, ROOM_ORIGIN);
  });
</script>

Den Handler erhalten

Der übrige Teil dieses Abschnitts gilt für Code, der im Meetingraum läuft, also für Veeting Blocks. Betten Sie einen iFrame ein, verwenden Sie stattdessen die Nachrichten oben. Ein eigenes Tool bekommt keinen Handler: Es kann nur { action, payload } an window.parent senden.

Die API existiert erst, wenn der Meetingraum vollständig geladen ist. Aus einem Skript, das beim Laden der Seite läuft, erreichen Sie die API deshalb noch nicht. Definieren Sie stattdessen auf window eine Funktion wlvmrApiReady. Sobald der Raum bereit ist, ruft er sie auf und übergibt Ihnen den Namen des Objekts, unter dem er sich registriert hat.

window["wlvmrApiReady"] = (handler) => {
  if (!window[handler]) {
    console.error(`Handler window.${handler} not found!`);
    return;
  }

  // Every API method lives on this object
  window[handler].muteAudio(true);
};

Daraus folgen zwei Regeln. Beide gehen häufig vergessen:

  1. Definieren Sie wlvmrApiReady, bevor der Meetingraum lädt. Weisen Sie die Funktion später zu, ist der Aufruf längst erfolgt und Sie erhalten den Handler nie.
  2. Schreiben Sie den Handler-Namen nicht fest in den Code. Sie bekommen ihn als Argument. Greifen Sie immer über window[handler] zu, nie über einen festen Namen.

Ein durchgängiges Beispiel

Warten Sie auf den Raum, abonnieren Sie Events und rufen Sie erst dann Methoden auf:

window["wlvmrApiReady"] = (handler) => {
  if (!window[handler]) {
    console.error(`Handler window.${handler} not found!`);
    return;
  }

  const api = window[handler];

  api.on("joined", () => {
    console.log("The meeting room is ready to use");
  });

  api.on("participantsUpdated", (participants) => {
    console.log(`${participants.length} participants in the room`);
  });

  api.on("chatMessage", (message) => {
    console.log(`${message.fromParticipantName}: ${message.message}`);
  });

  api.setAudioInputDeviceId("default", false);
  api.setVideoInputDeviceId("default", true);
};

Events

Abonnieren Sie mit on(event, callback). Es gibt 13 Events.

EventLöst aus, wennPayload
beforeConnectingDer Raum gleich seine Medien verbindetkeine
connectedDer WebSocket zur Veeting-API steht und verwendet wirdkeine
joinedDer Meetingraum einsatzbereit istkeine
disconnectedDer WebSocket oder die Medienverbindung abbrichtkeine
leaveDer lokale Teilnehmer das Meeting verlässtkeine
participantsUpdatedJemand beitritt, geht oder seinen Zustand ändertIApiParticipant[]
chatMessageEine Gruppen-Chatnachricht eintrifftIApiChatMessage
privateChatMessageEine private Chatnachricht eintrifftIApiChatMessage
chatModerationSich der Moderationsstatus einer Chatnachricht ändertIApiChatModeration
meetingDurationUpdatedSich die verbleibende Meeting-Zeit ändertIApiRemainingTimeUpdate
meetingRoomConfigUpdatedSich die Raumkonfiguration ändertIMeetingRoomConfig
customMessageEin anderer Teilnehmer eine Custom-Message sendetICustomMessage
screenshareStateChangeScreensharing startet oder endetIScreenshareState

Hinweis: connected beschreibt nur den WebSocket zu unserer API, nicht die WebRTC-Medien. disconnected kommt, wenn dieser WebSocket abbricht, und auch, wenn die Medienverbindung abbricht. Das Event allein sagt also nicht, was getrennt wurde.

Methoden

Meeting und Teilnehmer

MethodeBeschreibung
getVersion(): stringGibt den Versionsstring des laufenden Meetingraums zurück.
getParticipantsList(): IApiParticipant[]Gibt die aktuelle Teilnehmerliste zurück.
leaveMeeting(): voidTrennt die Verbindung zum Server und verlässt den Meetingraum.
enableFollowMe(enabled: boolean): voidSchaltet Follow Me ein oder aus. Sie brauchen dafür Moderationsrechte.

Audio und Video

MethodeBeschreibung
muteAudio(muted: boolean): voidSchaltet Audio stumm oder wieder ein.
toggleMuteAudio(): voidSchaltet die Audio-Stummschaltung um.
muteVideo(muted: boolean): voidSchaltet Video stumm oder wieder ein.
toggleMuteVideo(): voidSchaltet die Video-Stummschaltung um.
setVolume(volume: number, meetingParticipantId?: string): voidSetzt die Wiedergabelautstärke, entweder für einen Teilnehmer oder für alle.
connect(mediaConfig?: { audio: boolean, video: boolean }): voidVerbindet die Medien. Sind sie bereits verbunden, passiert nichts. Beim Beitritt verbindet der Raum die Medien ohnehin selbst.
disconnect(): voidTrennt die Medien. Sind sie bereits getrennt, passiert nichts.
restartMediaConnections(): voidStartet die Medienverbindungen neu. Das hilft nach einem Gerätewechsel.
enterVideoFullscreen(): voidWechselt in den Fullscreen. In den meisten Browsern ausser Chrome scheitert das, weil Fullscreen eine User-Interaktion verlangt.

Geräte

MethodeBeschreibung
getMediaDeviceSettings(): IMediaDeviceSettingsGibt die aktuell gewählten Geräte und die Auflösung zurück.
getMediaDeviceAudioInputList(audioOnly: boolean): MediaDeviceInfo[]Gibt die verfügbaren Mikrofone zurück. audioOnly beschränkt die Berechtigungsabfrage auf Audio.
getMediaDeviceAudioOutputList(audioOnly: boolean): MediaDeviceInfo[]Gibt die verfügbaren Lautsprecher zurück. audioOnly beschränkt die Berechtigungsabfrage auf Audio.
getMediaDeviceVideoInputList(): MediaDeviceInfo[]Gibt die verfügbaren Kameras zurück.
setAudioInputDeviceId(deviceId: string, reconnect: boolean): voidSetzt das Mikrofon. Die API prüft nicht, ob die Geräte-ID gültig ist.
setAudioOutputDeviceId(deviceId: string, reconnect: boolean): voidSetzt den Lautsprecher. Heute unterstützen das nur Chrome und Edge.
setVideoInputDeviceId(deviceId: string, reconnect: boolean): voidSetzt die Kamera. Die API prüft nicht, ob die Geräte-ID gültig ist.
setVideoResolution(resolution: MeetingRoomVideoResolution, reconnect: boolean): voidSetzt die Auflösung des ausgehenden Videos.
setMediaStreamConstraints(constraints: MediaStreamConstraints, merge?: boolean): voidSetzt Constraints für getUserMedia. merge steht standardmässig auf true und kombiniert Ihre Constraints mit unseren.
setDisplayMediaConstraints(constraints: MediaStreamConstraints, merge?: boolean): voidSetzt Constraints für getDisplayMedia. merge steht standardmässig auf true.

reconnect steht standardmässig auf false. Übergeben Sie true, baut der Raum die Medien neu auf und die Änderung greift sofort.

Die drei Listen-Methoden können eine Abfrage auslösen. Diese Methoden fragen den Browser nach der Medienberechtigung, um die Gerätenamen lesen zu können. Ein Aufruf kann also einen Berechtigungsdialog öffnen. Rufen Sie sie deshalb dann auf, wenn der Teilnehmer damit rechnet, und nicht beim Laden der Seite.

Screensharing und Aufzeichnung

MethodeBeschreibung
setScreensharingInterceptor(callback: () => void): voidErlaubt einer Electron-Anwendung, Screensharing-Anfragen abzufangen und eine Quelle vorzuwählen.
startScreensharing(sourceId?: string): voidStartet das Screensharing, auf Wunsch von einer bestimmten Quelle. Darf der Teilnehmer nicht teilen, geschieht nichts.
stopScreensharing(): voidBeendet das Screensharing.
forceStopScreensharing(): voidBeendet das Screensharing eines anderen Teilnehmers. Das dürfen nur Moderatoren, sonst blockiert der Server den Aufruf.
startRecording(): voidStartet die Aufzeichnung. Das gelingt nur, wenn das Meeting für teilweise Aufzeichnung konfiguriert ist.
stopRecording(): voidBeendet die Aufzeichnung. Es gilt dieselbe Bedingung.

Nachrichten

MethodeBeschreibung
sendChatMessage(message: string): voidSendet eine Gruppen-Chatnachricht.
sendPrivateChatMessage(message: string, participantId: string): voidSendet eine private Chatnachricht an einen Teilnehmer.
sendCustomMessage(message: ICustomMessage): voidSendet eine Custom-Message an alle Teilnehmer. Die Teilnehmer erhalten sie als Event customMessage.

Darstellung und Events

MethodeBeschreibung
setVideoDisplayCalculator(calculator: IVideoDisplayCalculator): voidÜberlässt Ihnen die Anordnung der Videos. Siehe Videodarstellung.
on(event: MeetingRoomApiEvent, callback: ApiEventCallback): voidAbonniert ein Event.

Zusätzliche Methoden in Veeting Blocks

Setzen Sie Veeting Blocks statt eines eingebetteten Raums ein, erhalten Sie vier zusätzliche Methoden. Mit ihnen steuern Sie den Beitritt selbst:

MethodeBeschreibung
isBrowserSupported(): booleanMeldet, ob im aktuellen Browser ein Meeting laufen kann.
loadMeeting(meetingId: string): Promise<IMeetingRoomConfig>Lädt die Konfiguration eines Meetings.
joinMeeting(config: IMeetingConnectionConfig): Promise<void>Tritt dem Meeting bei.
can(meetingPermission: string): Promise<boolean>Meldet, ob der aktuelle Teilnehmer die angegebene Berechtigung hat.

Typdefinitionen

interface IApiParticipant {
  id: string;
  name: string;
  muted?: boolean;
  handRaised?: boolean;
  fromPSTN?: boolean;
  hasVideo?: boolean;
  hadVideo?: boolean;
  joinedAt: number;
}

interface IApiChatMessage {
  fromParticipantId?: string;
  fromParticipantName: string;
  message: string;
  fromParticipantNameAnonymized?: boolean;
  messageId?: string;
  moderationState?: ChatModerationState; // "pending" | "approved" | "rejected" | "deleted"
}

interface IApiChatModeration {
  messageId: string;
  moderationState: ChatModerationState; // "pending" | "approved" | "rejected" | "deleted"
  message: string;
  fromParticipantName: string;
  fromParticipantNameAnonymized?: boolean;
}

interface IApiRemainingTimeUpdate {
  remainingSeconds: number;
}

interface IScreenshareState {
  active: boolean;
}

interface IMediaDeviceSettings {
  videoResolution: string;
  audioInputDeviceId: string;
  audioOutputDeviceId: string;
  videoInputDeviceId: string;
}

interface IMeetingConnectionConfig {
  meetingId: string;
  participantName: string;
  participantEmail?: string;
  audio: boolean;
  video: boolean;
  moderatorToken?: string;
  interpreterToken?: string;
  invisibleToken?: string;
  speakerToken?: string;
}

type MediaDirection = "receiveonly" | "sendonly" | "sendreceive";
type JoinMode = "audio-only" | "audio-video" | "video-only" | "no-media";
type ChatModerationState = "pending" | "approved" | "rejected" | "deleted";

type ApiEventCallback = (payload: void | IApiParticipant[] | IApiChatMessage
  | IApiChatModeration | IApiRemainingTimeUpdate | IMeetingRoomConfig
  | ICustomMessage | IScreenshareState) => void;

Anonymisiert der Raum die Chat-Autoren, fehlt in IApiChatMessage die fromParticipantId, fromParticipantName ist leer und fromParticipantNameAnonymized steht auf true. In einem moderierten Raum kann eine Nachricht als pending ankommen und ihren Status später ändern; jede Änderung meldet das Event chatModeration. Dort ist message leer, ausser der neue Status ist approved oder deleted. Ein approved-Event kann also das Erste sein, was Sie von einer zurückgehaltenen Nachricht sehen.

Häufige Fehler

  • wlvmrApiReady erst zuweisen, wenn der Meetingraum schon geladen ist. Die Funktion wird dann nie aufgerufen.
  • Den Handler-Namen fest in den Code schreiben, statt den übergebenen zu verwenden.
  • Eine Methode vor dem Event joined aufrufen. Der Raum ist dann zwar geladen, der Teilnehmer aber noch nicht im Meeting.
  • connected für einen Beleg halten, dass Medien fliessen. Es bezieht sich auf den WebSocket zu unserer API.
  • Von startScreensharing eine Rückmeldung erwarten. Darf der Teilnehmer nicht teilen, kehrt der Aufruf stillschweigend zurück.
  • startRecording in einem Meeting aufrufen, das nicht für teilweise Aufzeichnung konfiguriert ist.
  • forceStopScreensharing ohne Moderationsrechte aufrufen. Der Server blockiert den Aufruf.
  • Eine Geräte-ID übergeben, ohne zu prüfen, ob sie existiert. Die API validiert sie nicht.

Sind Sie nicht sicher, wie Sie Ihr Projekt am Besten umsetzen sollen?

Sprechen Sie mit unserem Team über Ihre Pläne.