JavaScript APIs

Übersicht

Mit der JavaScript-API steuern Sie aus Ihrer eigenen Seite heraus einen laufenden Meetingraum. Sie muten Teilnehmer, 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, ob mein Code IM Raum läuft (Veeting Blocks,
   ein eigenes Tool) oder in der Seite rund um einen eingebetteten
   iFrame. Beide erreichen die API völlig unterschiedlich, und die
   Antwort ändert alles Weitere.
2. Warte auf das Event «joined», bevor Du Methoden aufrufst, die
   die Anwesenheit im Meeting voraussetzen.
3. «connected» und «disconnected» beziehen sich auf den WebSocket
   zu unserer API, nicht auf WebRTC-Medien. Behandle sie nicht als
   Medienzustand.
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

Das ist wichtiger als alles andere auf dieser Seite, klären Sie es deshalb zuerst.

Ihr Code läuftSo erreichen Sie die API
Im Meetingraum selbst, also in Veeting Blocks oder in einem eigenen ToolDirekt über den Handler. Die vollständige API, samt Rückgabewerten.
In der Seite rund um einen eingebetteten iFrameÜber postMessage. Sie rufen jede Methode ohne Rückgabewert auf 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 unterstützt. Der Raum läuft normalerweise unter Ihrer eigenen White-Label-Domain, 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 darauf:

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 12 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 ihre Argumente in der richtigen Reihenfolge als Array. Eine Methode ohne Argumente braucht trotzdem payload: [] oder gar nichts.

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 niemand meldet es. Prüfen Sie den Namen gegen die Tabellen weiter unten.

Ein vollständiges Beispiel

Ihr eigener Mute-Button und Ihr eigener 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: Veeting Blocks oder ein eigenes Tool. Betten Sie einen iFrame ein, verwenden Sie stattdessen die Nachrichten oben.

Die API existiert erst, wenn der Meetingraum vollständig geladen ist. Aus einem Skript, das beim Laden der Seite läuft, erreichen Sie sie 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

Sie abonnieren mit on(event, callback). Es gibt 12 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 zur Veeting-API getrennt oder ungenutzt istkeine
leaveDer Teilnehmer das Meeting verlässtkeine
participantsUpdatedJemand beitritt, geht oder seinen Zustand ändertIApiParticipant[]
chatMessageEine Gruppen-Chatnachricht eintrifftIApiChatMessage
privateChatMessageEine private Chatnachricht eintrifftIApiChatMessage
meetingDurationUpdatedSich die verbleibende Meeting-Zeit ändertIApiRemainingTimeUpdate
meetingRoomConfigUpdatedSich die Raumkonfiguration ändertIMeetingRoomConfig
customMessageEin anderer Teilnehmer eine eigene Nachricht sendetICustomMessage
screenshareStateChangeEin Screensharing startet oder endetIScreenshareState

Hinweis: connected und disconnected beschreiben den WebSocket zu unserer API, nicht die WebRTC-Medien. Ein Teilnehmer kann von den Medien getrennt sein und trotzdem das Whiteboard nutzen.

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): voidAktiviert Follow Me. 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. Ausser in Chrome scheitert das in den meisten Browsern, denn Fullscreen verlangt eine User-Interaktion.

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. Sie 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 eigene Nachricht an alle Teilnehmer. Diese 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 der aktuelle Browser ein Meeting ausführen 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 eine 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;
}

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 ApiEventCallback = (payload: void | IApiParticipant[] | IApiChatMessage
  | IApiRemainingTimeUpdate | IMeetingRoomConfig | ICustomMessage | IScreenshareState) => void;

Häufige Fehler

  • Sie weisen wlvmrApiReady zu, nachdem der Meetingraum geladen ist. Die Funktion wird dann nie aufgerufen.
  • Sie schreiben den Handler-Namen fest in den Code, statt den übergebenen zu verwenden.
  • Sie rufen eine Methode vor dem Event joined auf. Der Raum ist dann zwar geladen, das Meeting aber noch nicht betreten.
  • Sie halten connected für einen Beleg, dass Medien fliessen. Es bezieht sich auf den WebSocket zu unserer API.
  • Sie erwarten von startScreensharing eine Rückmeldung. Darf der Teilnehmer nicht teilen, kehrt der Aufruf stillschweigend zurück.
  • Sie rufen startRecording in einem Meeting auf, das nicht für teilweise Aufzeichnung konfiguriert ist.
  • Sie rufen forceStopScreensharing ohne Moderationsrechte auf. Der Server blockiert es.
  • Sie übergeben eine Geräte-ID, 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.