Kontroller über die Videodarstellung

Einführung

Die Video Display Calculater API ist Teil der Javascript APIs. Front-End-Javascript-Entwickler können die standardmässige Videopositionierung ausser Kraft setzen, indem sie ihr eigenes Layout implementieren und die Teilnehmervideos frei im Videocontainer positionieren.

Die Videos werden abhängig von der Containergrösse des Bereichs angezeigt, in dem der Besprechungsraum die Videos platziert. Die Position jedes Teilnehmervideos wird in absoluten Werten (x, y, Breite und Höhe) relativ zum Hauptcontainer definiert.

Auf den Dokumentationsseiten Javascript APIs und iFrame einbetten finden Sie weitere Informationen zu diesen Themen.

Glossar

BegriffDefinition
Video, Participant VideoDer Videostream eines Teilnehmers.
Container, Video ContainerDer Bereich des Sitzungsraumes, in dem alle Videos angezeigt werden

Primärer und sekundärer Bereich

Das Präsentationsraum-Layout hat zwei unterschiedliche Bereiche innerhalb des Videocontainers: den primären und den sekundären Bereich.

Hinweis: Im klassischen Besprechungsraum-Layout gibt es keinen sekundären Bereich, der primäre Bereich umfasst immer den gesamten Container.

Standardmässig werden alle Videos im primären Bereich angezeigt. In diesem Fall deckt der primäre Bereich 100% des Videocontainers ab. Der Moderator kann Videos zwischen dem primären und dem sekundären Bereich verschieben. Sobald mindestens ein Video im Sekundärbereich angezeigt wird, wird der Container in zwei Teile geteilt: den Primärbereich, der 85% des Containers ausmacht, und den Sekundärbereich, der die restlichen 15% des Containers nutzt.

Primärer und sekundärer Bereich

Der sekundäre Bereich kann um alle Ecken (oben, rechts, unten, links) verschoben werden.

Berechnung der Videopositionen

Der Video Display Calculater wird immer dann ausgelöst, wenn die Videopositionen aktualisiert werden sollen. Sie müssen die absolute Position und Grösse jedes Videos innerhalb des Containers berechnen und ein Array von Video-Positions-Objekten zurückgeben.

Das System kann bis zu 12 Videocontainer anzeigen. Basierend auf Ihren eigenen Regeln und der Anzahl der Teilnehmer, können Sie entscheiden, ob Sie diese ein- oder ausblenden möchten.

Eingabeparameter

Der Video Display Calculater empfängt die folgenden Parameter:

ParameternameDatentypErläuterung
containerWidthZahlDie Breite des Video-Containers, in Pixel
containerHeightZahlDie Höhe des Videocontainers, in Pixel
hasSecondaryAreabooleantrue, wenn die sekundäre Anzeige sichtbar ist, sonst false.
secondaryPositionSecondaryVideoPositionDer Bereich, in dem der sekundäre Videoanzeigebereich positioniert ist
secondarySizeSecondaryVideoSizeDie Grösse des Videocontainers, in Prozent der Breite oder Höhe des gesamten Containers
primaryParticipantsstring[]Die Liste der Teilnehmer-IDs, die dem primären Bereich zugeordnet sind
secondaryParticipantsstring[]Die Liste der Teilnehmer-IDs, die dem sekundären Bereich zugeordnet sind
participantsOrderstring[]Die sortierte Liste der Teilnehmer-IDs
particpantsMediaInformationIParticipantsMediaInformationEin Objekt, das IMediaInformation für jeden der Teilnehmer in participantsOrder enthält. IMediaInformation enthält Informationen über die Grösse und den Zustand des Videos der Teilnehmer.
hasSelfViewbooleantrue, wenn es eine Selbstansicht gibt, sonst falsch
isSelfviewInSecondarybooleantrue, wenn die Selbstansicht im sekundären Container angezeigt wird, andernfalls false
isTVModebooleantrue, wenn der Besprechungsraum im TV-Modus angezeigt wird, false andernfalls

Wichtiger Hinweis: Die Teilnehmer-ID der eigenen Ansicht ist NICHT Teil des Teilnehmer-ID-Arrays (participantsOrder). Wenn es eine Selbstansicht gibt (hasSelfView === true), können Sie sich entscheiden, die Selbstansicht hinzuzufügen. Verwenden Sie die Teilnehmer-ID myself, um die Selbstansicht zur Ausgabedatenstruktur hinzuzufügen.

Ausgabe-Datenstruktur

Die Ausgabestruktur enthält ein Array von Videopositionen, wobei die Positionselemente in dieser Reihenfolge auf die verfügbaren Videocontainer angewendet werden. Die Ausgabestruktur besteht auch aus einem Array von Booleschen Werten, die angeben, ob ein Element ausgeblendet werden soll oder nicht.

ParameternameDatentypErläuterung
videoPositionsIVideoPosition[]Ein Array von IVideoPosition-Objekten für alle sichtbaren Videocontainer
hiddenContainersboolean[]Ein Array der Grösse 12 mit false, wenn das Video angezeigt werden soll und true, wenn das Video nicht angezeigt werden soll

Die Schnittstelle für die Videoposition ist wie folgt definiert:

ParameternameDatentypErläuterung
participantIdstringDie Teilnehmer-ID des Videos, welches in diesem Container angezeigt werden soll
widthnumberDie Breite des Videocontainers in Pixeln
heightnumberDie Höhe des Video-Containers in Pixeln
topnumberDie Anzahl der Pixel vom oberen Rand des Containers
leftnumberDie Anzahl der Pixel vom linken Rand des Containers
zIndexZahlDer z-Index des Elements, wenn Sie die Videoanzeigen übereinander positionieren möchten
cssClassesstring[]CSS-Klassen, die auf den Videocontainer angewendet werden sollen. Wichtig: Die CSS-Klassen MÜSSEN mit dem Präfix 'video-container-' versehen werden

Fehlerbehandlung

Wenn der Video Display Calculator einen Fehler auslöst oder ein leeres Objekt zurückgibt, greift das System stattdessen auf den internen Positionsrechner zurück.

Beispiel

Der folgende Beispielcode platziert den ersten Teilnehmer in der Mitte des Bildschirms, alle anderen Teilnehmer in einer Reihe über dem ersten Teilnehmer und die Selbstansicht unter dem Teilnehmer:

Beispiel Videoanzeige

In diesem Beispiel wird der sekundäre Bereich nicht verwendet, alle Videos werden im primären Bereich angezeigt.

const videoDisplayCalculator = {
  calculatePositions: (containerWidth,
    containerHeight,
    hasSecondaryArea,
    secondaryPosition,
    secondarySize,
    primaryParticipants,
    secondaryParticipants,
    participantsOrder,
    particpantsMediaInformation,
    hasSelfView,
    isSelfviewInSecondary,
    isTVMode) => {

    const result = {
      videoPositions: [],
      hiddenContainers: Array(12).fill(true)
    }

    // Wir möchten die Videos in eine 4:3 Format anzeigen
    const threeToFour = 3 / 4;
    // Das Hauptvideo wird im Zentrum positioniert, 65% der gesamten Containergrösse
    const mainContainerSizePercentage = 0.65

    let mainContainerWidth = 0;
    let mainContainerHeight = 0;
    let mainContainerTop = 0;
    let mainContainerLeft = 0;

    if (Array.isArray(participantsOrder) && participantsOrder.length > 0) {
      mainContainerWidth = containerWidth * mainContainerSizePercentage;
      mainContainerHeight = mainContainerWidth * threeToFour;
      if (mainContainerHeight > containerHeight * mainContainerSizePercentage) {
        mainContainerHeight = containerHeight * mainContainerSizePercentage;
        mainContainerWidth = mainContainerHeight / threeToFour;
      }

      mainContainerTop = (containerHeight - mainContainerHeight) / 2;
      mainContainerLeft = (containerWidth - mainContainerWidth) / 2;

      // Das Hauptvideo hinzufügen
      result.videoPositions.push({
        participantId: participantsOrder[0],
        width: mainContainerWidth,
        height: mainContainerHeight,
        top: mainContainerTop,
        left: mainContainerLeft,
        zIndex: 1
      });
      result.hiddenContainers[0] = false;

      const numberOfOtherVideos = participantsOrder.length - 1;

      if (numberOfOtherVideos > 0) {
        // Wir haben andere Videos
        // Wir fügen alle anderen Videos in die obere Zeile
        let otherContainersWidth = containerWidth / numberOfOtherVideos;
        let otherContainersHeight = otherContainersWidth * threeToFour;
        if (otherContainersHeight > mainContainerTop) {
          otherContainersHeight = mainContainerTop;
          otherContainersWidth = otherContainersHeight / threeToFour;
        }

        const otherContainersTop = (mainContainerTop - otherContainersHeight) / 2;
        let otherContainersLeft = (containerWidth / 2) - ((otherContainersWidth * numberOfOtherVideos) / 2);

        for (let i = 1; i < participantsOrder.length; i++) {
          result.videoPositions.push({
            participantId: participantsOrder[i],
            width: otherContainersWidth,
            height: otherContainersHeight,
            top: otherContainersTop,
            left: otherContainersLeft,
            zIndex: 1
          });
          result.hiddenContainers[i] = false;

          otherContainersLeft += otherContainersWidth;
        }
      }
    }

    if (hasSecondaryArea) {
      // Zu implementieren
    }

    if (hasSelfView) {
      // Wir haben eine Selbstansicht, wir fügen diese unter dem Hauptvideo hinzu
      const selfViewHeight = containerHeight - mainContainerTop - mainContainerHeight;
      const selfViewWidth = selfViewHeight / threeToFour;

      result.videoPositions.push({
        // Nota bene: Die Sebstansicht hat immer die participantId 'myself'
        participantId: "myself", 
        width: selfViewWidth,
        height: selfViewHeight,
        top: containerHeight - selfViewHeight,
        left: (containerWidth / 2) - (selfViewWidth / 2),
        zIndex: 1
      });
    }

    return result;
  }
}

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

Typendefinitionen

Die folgenden Ein- und Ausgabetypen werden benutzt, um mit diesem Javascript API zu interagieren.

Interfaces


interface IVideoPosition {
  participantId: string;
  width: number;
  height: number;
  top: number;
  left: number;
  zIndex: number;
  /// Wichtig: CSS Klasse MÜSSEN mit dem Prefix 'video-container-' versehen sein
  cssClasses?: string[]
}

interface IVideoDisplayConfig {
  videoPositions: IVideoPosition[],
  hiddenContainers: boolean[]
}


export interface IMediaInformation {
    audioMuted?: boolean;
    videoMuted?: boolean;
    hasAudio?: boolean;
    hadAudio?: boolean;
    offersVideo?: boolean;
    hasVideo?: boolean;
    hadVideo?: boolean;
    videoWidth?: number;
    videoHeight?: number;
}

export interface IParticipantsMediaInformation {
    [participantId: string]: IMediaInformation
}

interface IVideoDisplayCalculator {
  calculatePositions(
    containerWidth: number,
    containerHeight: number,
    hasSecondaryArea: boolean,
    secondaryPosition: SecondaryVideoPosition,
    secondarySize: SecondaryVideoSize,
    primaryParticipants: string[],
    secondaryParticipants: string[],
    participantsOrder: string[],
    particpantsMediaInformation: IParticipantsMediaInformation,
    hasSelfView: boolean,
    isSelfviewInSecondary: boolean,
    isTVMode: boolean
  ): IVideoDisplayConfig;
}

Enums

enum SecondaryVideoSize {
  small = 0.15,
  large = 0.5
}

Types

type SecondaryVideoPosition = "none" | "left" | "top" | "right" | "bottom";

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

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