// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkOpenXRManagerRemoteConnection.h" #include "vtkObjectFactory.h" #include "vtkOpenXRManager.h" #include "vtkResourceFileLocator.h" #include "vtksys/SystemTools.hxx" // Starting with Microsoft.Holographic.Remoting.OpenXr 2.9.3, the struct // `XrRemotingPreferredGraphicsAdapterMSFT` is defined in `openxr_msft_holographic_remoting.h` // and it requires the type LUID to be defined. // Since LUID is defined in `windows.h` (see `OpenXR-SDK-Source/specification/registry/xr.xml`), // we include the corresponding VTK header. #include // Defines LUID used in XrRemotingPreferredGraphicsAdapterMSFT #include // Defines XR_MSFT_holographic_remoting #include "XrConnectionExtensions.h" // Provides holographic remoting extensions #include #include // used to sleep after connection VTK_ABI_NAMESPACE_BEGIN vtkStandardNewMacro(vtkOpenXRManagerRemoteConnection); static bool vtkOpenXRManagerRemoteConnectionInitializeSymbol() { return true; } //------------------------------------------------------------------------------ bool vtkOpenXRManagerRemoteConnection::Initialize() { // Get the path for the library std::string libPath = vtkGetLibraryPathForSymbol(vtkOpenXRManagerRemoteConnectionInitializeSymbol); std::string libDir = vtksys::SystemTools::GetFilenamePath(libPath); // Get the path for the current executable std::string exePath = vtkResourceFileLocator::GetCurrentExecutablePath(); std::string exeDir = vtksys::SystemTools::GetFilenamePath(exePath); // Look for the RemotingXR.json file provided by the microsoft.holographic.remoting.openxr // package, in the system PATH, next to the vtkRenderingOpenXR library and also next to the // executable. // If found, set the XR_RUNTIME_JSON environment variable. It will be used by the OpenXR loader // to not use the system default OpenXR runtime but instead redirect to the Holographic Remoting // OpenXR runtime. std::string remotingXRPath = vtksys::SystemTools::FindFile("RemotingXR.json", { libDir, exeDir, this->RemotingXRDirectory }); if (remotingXRPath.empty()) { return false; } std::string oldValue; if (vtksys::SystemTools::GetEnv("XR_RUNTIME_JSON", oldValue)) { this->OldXrRuntimeEnvValue = std::move(oldValue); } if (!vtksys::SystemTools::PutEnv("XR_RUNTIME_JSON=" + remotingXRPath)) { return false; } return true; } //------------------------------------------------------------------------------ bool vtkOpenXRManagerRemoteConnection::EndInitialize() { if (!this->OldXrRuntimeEnvValue.empty()) { if (!vtksys::SystemTools::PutEnv("XR_RUNTIME_JSON=" + this->OldXrRuntimeEnvValue)) { return false; } } else if (!vtksys::SystemTools::UnPutEnv("XR_RUNTIME_JSON")) { return false; } return true; } //------------------------------------------------------------------------------ bool vtkOpenXRManagerRemoteConnection::ConnectToRemote(XrInstance instance, XrSystemId id) { if (this->IPAddress.empty()) { vtkErrorMacro("Remoting IP address unspecified."); return false; } XrRemotingConnectionStateMSFT connectionState; xr::ConnectionExtensionDispatchTable extensions; extensions.PopulateDispatchTable(instance); extensions.xrRemotingGetConnectionStateMSFT(instance, id, &connectionState, nullptr); if (connectionState != XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT) { vtkErrorMacro("Error connecting to " << this->IPAddress << ": " << connectionState); return false; } // Apply remote context properties while disconnected. { XrRemotingRemoteContextPropertiesMSFT contextProperties; contextProperties = XrRemotingRemoteContextPropertiesMSFT{ static_cast( XR_TYPE_REMOTING_REMOTE_CONTEXT_PROPERTIES_MSFT) }; contextProperties.enableAudio = false; contextProperties.maxBitrateKbps = 20000; contextProperties.videoCodec = XR_REMOTING_VIDEO_CODEC_ANY_MSFT; contextProperties.depthBufferStreamResolution = XR_REMOTING_DEPTH_BUFFER_STREAM_RESOLUTION_HALF_MSFT; extensions.xrRemotingSetContextPropertiesMSFT(instance, id, &contextProperties); } XrRemotingConnectInfoMSFT connectInfo{ static_cast( XR_TYPE_REMOTING_CONNECT_INFO_MSFT) }; connectInfo.remoteHostName = this->IPAddress.c_str(); connectInfo.remotePort = 8265; connectInfo.secureConnection = false; if (!vtkOpenXRManager::GetInstance().XrCheckOutput(vtkOpenXRManager::ErrorOutput, extensions.xrRemotingConnectMSFT(instance, id, &connectInfo), "Failed to connect")) { return false; } // Make sure the connection is established before the event loop gets started std::this_thread::sleep_for(std::chrono::milliseconds(2500)); return true; } //------------------------------------------------------------------------------ const char* vtkOpenXRManagerRemoteConnection::GetExtensionName() { return XR_MSFT_HOLOGRAPHIC_REMOTING_EXTENSION_NAME; } //------------------------------------------------------------------------------ bool vtkOpenXRManagerRemoteConnection::HandleXrEvent(const XrEventDataBuffer& eventData) { switch ((XrRemotingStructureType)eventData.type) { case XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: { vtkDebugMacro("Holographic Remoting: Connected."); return true; } case XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: { vtkDebugMacro("Holographic Remoting: Disconnected."); return true; } default: { break; } } return false; } VTK_ABI_NAMESPACE_END