Schreiben einer Holographic Remoting-Remote-App mithilfe der OpenXR-API

Wenn Sie noch nicht mit Holographic Remoting sind, sollten Sie unsere Übersicht lesen.

Wichtig

In diesem Dokument wird die Erstellung einer Remoteanwendung für HoloLens 2- und Windows Mixed Reality-Headsets mithilfe der OpenXR-API beschrieben. Remoteanwendungen für HoloLens (1. Generation) müssen nuGet-Paketversion 1.x.x verwenden. Dies bedeutet, dass Remoteanwendungen, die für HoloLens 2 geschrieben wurden, nicht mit HoloLens 1 kompatibel sind und umgekehrt. Die Dokumentation zu HoloLens 1 finden Sie hier.

Holographic Remoting-Apps können remote gerenderte Inhalte an HoloLens 2 und Windows Mixed Reality immersive Headsets streamen. Sie können auch auf weitere Systemressourcen zugreifen und immersive Remoteansichten in vorhandene Desktop-PC-Software integrieren. Eine Remote-App empfängt einen Eingabedatenstrom von HoloLens 2, rendert Inhalte in einer virtuellen immersiven Ansicht und streamt Inhaltsframes zurück an HoloLens 2. Die Verbindung wird über standardmäßiges WLAN hergestellt. Holographic Remoting wird einer Desktop- oder UWP-App über ein NuGet-Paket hinzugefügt. Es ist zusätzlicher Code erforderlich, der die Verbindung verarbeitet und in einer immersiven Ansicht rendert. Eine typische Remotingverbindung weist eine Latenz von nur 50 ms auf. Die Player-App kann die Latenz in Echtzeit melden.

Der gesamte Code auf dieser Seite und die funktionierenden Projekte finden Sie im GitHub-Repository für Holographic Remoting-Beispiele.

Voraussetzungen

Ein guter Ausgangspunkt ist eine funktionierende OpenXR-basierte Desktop- oder UWP-App. Weitere Informationen finden Sie unter Erste Schritte mit OpenXR.

Wichtig

Jede App, die Holographic Remoting verwendet, sollte für die Verwendung eines Multithread-Apartments erstellt werden. Die Verwendung eines Singlethread-Apartments wird unterstützt, führt jedoch zu einer suboptimalen Leistung und möglicherweise zu Stottern während der Wiedergabe. Bei Verwendung von C++/WinRT winrt::init_apartment ist ein Multithread-Apartment die Standardeinstellung.

Abrufen des Holographic Remoting-NuGet-Pakets

Die folgenden Schritte sind erforderlich, um das NuGet-Paket einem Projekt in Visual Studio hinzuzufügen.

  1. Öffnen Sie das Projekt in Visual Studio.
  2. Klicken Sie mit der rechten Maustaste auf den Projektknoten, und wählen Sie NuGet-Pakete verwalten... aus.
  3. Wählen Sie im daraufhin angezeigten Bereich Durchsuchen aus, und suchen Sie dann nach "Holographic Remoting".
  4. Wählen Sie Microsoft.Holographic.Remoting.OpenXr aus, stellen Sie sicher, dass die neueste Version 2.x.x ausgewählt ist, und wählen Sie dann Installieren aus.
  5. Wenn das Dialogfeld Vorschau angezeigt wird, wählen Sie OK aus.
  6. Wählen Sie Ich stimme zu , wenn das Dialogfeld für den Lizenzvertrag angezeigt wird.
  7. Wiederholen Sie die Schritte 3 bis 6 für die folgenden NuGet-Pakete: OpenXR.Headers, OpenXR.Loader

Hinweis

Version 1.x.x des NuGet-Pakets ist weiterhin für Entwickler verfügbar, die HoloLens 1 als Ziel verwenden möchten. Weitere Informationen finden Sie unter Hinzufügen von Holographic Remoting (HoloLens (1. Generation)).

Auswählen der OpenXR-Runtime für Holographic Remoting

Der erste Schritt, den Sie in Ihrer Remote-App ausführen müssen, besteht darin, die Holographic Remoting OpenXR-Runtime auszuwählen, die Teil des Microsoft.Holographic.Remoting.OpenXr NuGet-Pakets ist. Hierzu können Sie die Umgebungsvariable XR_RUNTIME_JSON auf den Pfad der Datei RemotingXR.json in Ihrer App festlegen. Diese Umgebungsvariable wird vom OpenXR-Ladeprogramm verwendet, um nicht die OpenXR-Standardlaufzeit des Systems zu verwenden, sondern stattdessen zur Holographic Remoting OpenXR-Runtime umzuleiten. Wenn Sie das NuGet-Paket Microsoft.Holographic.Remoting.OpenXr verwenden, wird die Datei RemotingXR.json während der Kompilierung automatisch in den Ausgabeordner kopiert. Die OpenXR-Laufzeitauswahl sieht in der Regel wie folgt aus.

bool EnableRemotingXR() {
    wchar_t executablePath[MAX_PATH];
    if (GetModuleFileNameW(NULL, executablePath, ARRAYSIZE(executablePath)) == 0) {
        return false;
    }
    
    std::filesystem::path filename(executablePath);
    filename = filename.replace_filename("RemotingXR.json");

    if (std::filesystem::exists(filename)) {
        SetEnvironmentVariableW(L"XR_RUNTIME_JSON", filename.c_str());
            return true;
        }

    return false;
}

Erstellen von XrInstance mit Holographic Remoting-Erweiterung

Die ersten Aktionen, die eine typische OpenXR-App ausführen sollte, sind die Auswahl von OpenXR-Erweiterungen und das Erstellen einer XrInstance. Die OpenXR-Kernspezifikation stellt keine Remoting-spezifische API bereit. Aus diesem Grund führt Holographic Remoting eine eigene OpenXR-Erweiterung namens ein XR_MSFT_holographic_remoting. Stellen Sie sicher, dass XR_MSFT_HOLOGRAPHIC_REMOTING_EXTENSION_NAME in XrInstanceCreateInfo des xrCreateInstance-Aufrufs enthalten ist.

Tipp

Standardmäßig wird der gerenderte Inhalt Ihrer App nur an den Holographic Remoting-Player gestreamt, der entweder auf einem HoloLens 2 oder auf einem Windows Mixed Reality Headsets ausgeführt wird. Um auch den gerenderten Inhalt auf dem Remote-PC anzuzeigen, stellt Holographic Remoting über eine Swapchain eines Fensters für instance eine zweite OpenXR-Erweiterung mit dem Namen bereitXR_MSFT_holographic_remoting_frame_mirroring. Stellen Sie sicher, dass Sie diese Erweiterung auch mithilfe von XR_MSFT_HOLOGRAPHIC_REMOTING_FRAME_MIRRORING_EXTENSION_NAME aktivieren, falls Sie diese Funktionalität verwenden möchten.

Wichtig

Weitere Informationen zur OpenXR-Erweiterungs-API für Holographic Remoting finden Sie in der Spezifikation , die im GitHub-Repository holographic Remoting samples (Holographic Remoting-Beispiele) zu finden ist.

Stellen Sie eine Verbindung mit dem Gerät her.

Nachdem Ihre Remote-App die XrInstance erstellt und die XrSystemId über xrGetSystem abgefragt hat, kann eine Verbindung mit dem Playergerät hergestellt werden.

Warnung

Die Holographic Remoting OpenXR-Runtime kann nur gerätespezifische Daten wie Ansichtskonfigurationen oder Umgebungsmischungsmodi bereitstellen, nachdem eine Verbindung hergestellt wurde. xrEnumerateViewConfigurations, xrEnumerateViewConfigurationViews, xrGetViewConfigurationProperties, xrEnumerateEnvironmentBlendModesund xrGetSystemProperties erhalten Sie Standardwerte, die dem entsprechen, was Sie normalerweise erhalten würden, wenn Sie eine Verbindung mit einem Player herstellen, der auf einem HoloLens 2 ausgeführt wird, bevor sie vollständig verbunden werden. Es wird dringend empfohlen, diese Methoden nicht aufzurufen, bevor eine Verbindung hergestellt wurde. Der Vorschlag wird mit diesen Methoden verwendet, nachdem die XrSession erfolgreich erstellt wurde und der Sitzungszustand mindestens XR_SESSION_STATE_READY ist.

Allgemeine Eigenschaften wie max bitrate, audio enabled, video codec oder depth buffer stream resolution können wie xrRemotingSetContextPropertiesMSFT folgt konfiguriert werden.

XrRemotingRemoteContextPropertiesMSFT contextProperties;
contextProperties = XrRemotingRemoteContextPropertiesMSFT{static_cast<XrStructureType>(XR_TYPE_REMOTING_REMOTE_CONTEXT_PROPERTIES_MSFT)};
contextProperties.enableAudio = false;
contextProperties.maxBitrateKbps = 20000;
contextProperties.videoCodec = XR_REMOTING_VIDEO_CODEC_H265_MSFT;
contextProperties.depthBufferStreamResolution = XR_REMOTING_DEPTH_BUFFER_STREAM_RESOLUTION_HALF_MSFT;
xrRemotingSetContextPropertiesMSFT(m_instance.Get(), m_systemId, &contextProperties);

Die Verbindung kann auf zwei Arten hergestellt werden.

  1. Die Remote-App stellt eine Verbindung mit dem Player her, der auf dem Gerät ausgeführt wird.
  2. Der auf dem Gerät ausgeführte Player stellt eine Verbindung mit der Remote-App her.

Um eine Verbindung zwischen der Remote-App und dem Playergerät herzustellen, rufen Sie die xrRemotingConnectMSFT -Methode auf, um den Hostnamen und port über die XrRemotingConnectInfoMSFT -Struktur anzugeben. Der vom Holographic Remoting Player verwendete Port ist 8265.

XrRemotingConnectInfoMSFT connectInfo{static_cast<XrStructureType>(XR_TYPE_REMOTING_CONNECT_INFO_MSFT)};
connectInfo.remoteHostName = "192.168.x.x";
connectInfo.remotePort = 8265;
connectInfo.secureConnection = false;
xrRemotingConnectMSFT(m_instance.Get(), m_systemId, &connectInfo);

Das Lauschen auf eingehende Verbindungen in der Remote-App kann durch Aufrufen der xrRemotingListenMSFT -Methode erfolgen. Sowohl der Handshakeport als auch der Transportport können über die XrRemotingListenInfoMSFT -Struktur angegeben werden. Der Handshakeport wird für den ersten Handshake verwendet. Die Daten werden dann über den Transportport gesendet. Standardmäßig werden 8265 und 8266 verwendet.

XrRemotingListenInfoMSFT listenInfo{static_cast<XrStructureType>(XR_TYPE_REMOTING_LISTEN_INFO_MSFT)};
listenInfo.listenInterface = "0.0.0.0";
listenInfo.handshakeListenPort = 8265;
listenInfo.transportListenPort = 8266;
listenInfo.secureConnection = false;
xrRemotingListenMSFT(m_instance.Get(), m_systemId, &listenInfo);

Der Verbindungsstatus muss getrennt werden, wenn Sie oder xrRemotingListenMSFTaufrufenxrRemotingConnectMSFT. Sie können den Verbindungsstatus jederzeit abrufen, nachdem Sie eine XrInstance erstellt und über xrRemotingGetConnectionStateMSFTdie XrSystemId abgefragt haben.

XrRemotingConnectionStateMSFT connectionState;
xrRemotingGetConnectionStateMSFT(m_instance.Get(), m_systemId, &connectionState, nullptr);

Verfügbare Verbindungszustände sind:

  • XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTING_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT

Wichtig

xrRemotingConnectMSFT oder xrRemotingListenMSFT muss aufgerufen werden, bevor Versucht wird, eine XrSession über xrCreateSession zu erstellen. Wenn Sie versuchen, eine XrSession zu erstellen, während der Verbindungszustand ist XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT , wird die Sitzungserstellung erfolgreich ausgeführt, aber der Sitzungszustand wechselt sofort in XR_SESSION_STATE_LOSS_PENDING.

Holographic Remotings Implementierung von xrCreateSession Unterstützungen, die darauf warten, dass eine Verbindung hergestellt wird. Sie können oder xrRemotingListenMSFT unmittelbar gefolgt von einem Aufruf xrCreateSessionvon aufrufenxrRemotingConnectMSFT, der blockiert und wartet, bis eine Verbindung hergestellt wird. Das Timeout mit xrRemotingConnectMSFT ist auf 10 Sekunden und mit xrRemotingListenMSFTunbegrenzt festgelegt. Wenn innerhalb dieses Zeitraums eine Verbindung hergestellt werden kann, ist die XrSession-Erstellung erfolgreich, und der Sitzungszustand wechselt zu XR_SESSION_STATE_READY. Falls keine Verbindung hergestellt werden kann, ist die Sitzungserstellung ebenfalls erfolgreich, wechselt jedoch sofort zu XR_SESSION_STATE_LOSS_PENDING.

Im Allgemeinen ist der Verbindungszustand mit dem XrSession-Zustand gekoppelt. Jede Änderung des Verbindungszustands wirkt sich auch auf den Sitzungszustand aus. Wenn instance der Verbindungszustand von zum XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFTXR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT Sitzungszustand wechselt, wird auch in XR_SESSION_STATE_LOSS_PENDING übergehen.

Behandeln bestimmter Remotingereignisse

Die Holographic Remoting OpenXR-Runtime macht drei Ereignisse verfügbar, die wichtig sind, um den Zustand einer Verbindung zu überwachen.

  1. XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: Wird ausgelöst, wenn eine Verbindung mit dem Gerät erfolgreich hergestellt wurde.
  2. XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: Wird ausgelöst, wenn eine hergestellte Verbindung geschlossen wird oder keine Verbindung hergestellt werden konnte.
  3. XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT: Wenn die Überwachung auf eingehende Verbindungen gestartet wird.

Diese Ereignisse werden in einer Warteschlange platziert, und Ihre Remote-App muss regelmäßig über xrPollEventaus der Warteschlange lesen.

auto pollEvent = [&](XrEventDataBuffer& eventData) -> bool {
	eventData.type = XR_TYPE_EVENT_DATA_BUFFER;
	eventData.next = nullptr;
	return CHECK_XRCMD(xrPollEvent(m_instance.Get(), &eventData)) == XR_SUCCESS;
};

XrEventDataBuffer eventData{};
while (pollEvent(eventData)) {
	switch (eventData.type) {
	
	...
	
	case XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT: {
		DEBUG_PRINT("Holographic Remoting: Listening on port %d",
					reinterpret_cast<const XrRemotingEventDataListeningMSFT*>(&eventData)->listeningPort);
		break;
	}
	case XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: {
		DEBUG_PRINT("Holographic Remoting: Connected.");
		break;
	}
	case XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: {
		DEBUG_PRINT("Holographic Remoting: Disconnected - Reason: %d",
					reinterpret_cast<const XrRemotingEventDataDisconnectedMSFT*>(&eventData)->disconnectReason);
		break;
	}
}

Lokale Vorschau gestreamter Inhalte

Um den gleichen Inhalt in der Remote-App anzuzeigen, die an das Gerät gesendet wird, kann die XR_MSFT_holographic_remoting_frame_mirroring Erweiterung verwendet werden. Mit dieser Erweiterung können Sie eine Textur an xrEndFrame übermitteln, indem Sie den verwenden, der XrRemotingFrameMirrorImageInfoMSFT nicht wie folgt mit XrFrameEndInfo verkettet ist.

XrFrameEndInfo frameEndInfo{XR_TYPE_FRAME_END_INFO};
...

XrRemotingFrameMirrorImageD3D11MSFT mirrorImageD3D11{
    static_cast<XrStructureType>(XR_TYPE_REMOTING_FRAME_MIRROR_IMAGE_D3D11_MSFT)};
mirrorImageD3D11.texture = m_window->GetNextSwapchainTexture();

XrRemotingFrameMirrorImageInfoMSFT mirrorImageEndInfo{
    static_cast<XrStructureType>(XR_TYPE_REMOTING_FRAME_MIRROR_IMAGE_INFO_MSFT)};
mirrorImageEndInfo.image = reinterpret_cast<const XrRemotingFrameMirrorImageBaseHeaderMSFT*>(&mirrorImageD3D11);

frameEndInfo.next = &mirrorImageEndInfo;

xrEndFrame(m_session.Get(), &frameEndInfo);

m_window->PresentSwapchain();

Im obigen Beispiel wird eine DX11-Swapchaintextur verwendet und das Fenster unmittelbar nach dem Aufruf von xrEndFrame angezeigt. Die Verwendung ist nicht auf Swapchaintexturen beschränkt. Darüber hinaus ist keine zusätzliche GPU-Synchronisierung erforderlich. Ausführliche Informationen zu Verwendung und Einschränkungen finden Sie in der Erweiterungsspezifikation. Wenn Ihre Remote-App DX12 verwendet, verwenden Sie XrRemotingFrameMirrorImageD3D12MSFT anstelle von XrRemotingFrameMirrorImageD3D11MSFT.

Optional: Benutzerdefinierte Datenkanäle

Ab Version 2.5.0 können benutzerdefinierte Datenkanäle mit der OpenXR-API verwendet werden, um Benutzerdaten über die bereits hergestellte Remotingverbindung zu senden. Weitere Informationen finden Sie unter Benutzerdefinierte Datenkanäle mit der OpenXR-API.

Optional: Sprache

Ab Version 2.6.0 ermöglicht die Erweiterung der XR_MSFT_holographic_remoting_speech Remote-App, auf Sprachbefehle zu reagieren, die von der Player-App mit der OpenXR-API erkannt wurden.

[! WICHTIG] Die detaillierte Spezifikation finden Sie im GitHub-Repository für Holographic Remoting-Beispiele.

Um eine Spracherkennung in der Player-App zu initialisieren, kann die Remote-App aufrufen xrInitializeRemotingSpeechMSFT. Dieser Aufruf überträgt Sprachinitialisierungsparameter, die aus einer Sprache, einem Wörterbuch mit Ausdrücken und dem Inhalt einer Grammatikdatei bestehen, an die Player-App.

Hinweis

Vor Version 2.6.1 muss die Spracherkennung nur einmal pro XrSessioninitialisiert werden.

Wenn die Erstellung der Spracherkennung erfolgreich war, wie durch das XR_TYPE_EVENT_DATA_REMOTING_SPEECH_RECOGNIZER_STATE_CHANGED_MSFT Ereignis angegeben, wird die Remote-App benachrichtigt, wenn ein Spracherkennungsergebnis für die Player-App generiert wurde. Die XrEventDataRemotingSpeechRecognizerStateChangedMSFT Ereignisstruktur wird in der Ereigniswarteschlange platziert, wenn sich der Status der Spracherkennung auf der Spielerseite ändert.

XrRemotingSpeechRecognizerStateMSFT definiert alle möglichen Zustände der Spracherkennung auf der Spielerseite, und die XrEventDataRemotingSpeechRecognizedMSFT Ereignisstruktur wird in der Ereigniswarteschlange platziert, wenn die Spracherkennung auf der Spielerseite über einen erkannten Ausdruck verfügt. Nachdem die Remote-App über einen erkannten Ausdruck benachrichtigt wurde, kann sie den erkannten Ausdruck durch Aufrufen xrRetrieveRemotingSpeechRecognizedTextMSFTvon abrufen.

Hinweis

ist XrRemotingSpeechRecognitionConfidenceMSFT eine direkte Zuordnung der SpeechRecognitionConfidence-Enumeration , die mit dem Spracherkennungsergebnis der Windows-Spracherkennungs-API zurückgegeben wird.

Optional: Koordinatensystemsynchronisierung

Ab Version 2.7.0 kann die Koordinatensystemsynchronisierung verwendet werden, um räumliche Daten zwischen dem Player und der Remote-App auszurichten. Weitere Informationen finden Sie unter Koordinatensystemsynchronisierung mit Holographic Remoting – Übersicht.

Weitere Informationen