Scrittura di un'app remota di comunicazione remota olografica tramite l'API OpenXRWriting a Holographic Remoting remote app using the OpenXR API

Importante

Questo documento descrive la creazione di un'applicazione remota per gli auricolari HoloLens 2 e Windows Mixed Reality usando l' API OpenXR.This document describes the creation of a remote application for HoloLens 2 and Windows Mixed Reality headsets using the OpenXR API. Le applicazioni remote per HoloLens (1a Gen) devono usare il pacchetto NuGet versione 1. x. x.Remote applications for HoloLens (1st gen) must use NuGet package version 1.x.x. Ciò implica che le applicazioni remote scritte per HoloLens 2 non sono compatibili con HoloLens 1 e viceversa.This implies that remote applications written for HoloLens 2 are not compatible with HoloLens 1 and vice versa. La documentazione per HoloLens 1 è disponibile qui.The documentation for HoloLens 1 can be found here.

Le app di comunicazione remota olografica possono trasmettere contenuti con rendering remoto a HoloLens 2 e agli auricolari immersivi con la realtà mista di Windows.Holographic Remoting apps can stream remotely rendered content to HoloLens 2 and Windows Mixed Reality immersive headsets. È inoltre possibile accedere a più risorse di sistema e integrare visualizzazioni immersive remote in software per PC desktop esistenti.You can also access more system resources and integrate remote immersive views into existing desktop PC software. Un'app remota riceve un flusso di dati di input da HoloLens 2, esegue il rendering del contenuto in una visualizzazione immersiva virtuale e trasmette nuovamente i frame di contenuto a HoloLens 2.A remote app receives an input data stream from HoloLens 2, renders content in a virtual immersive view, and streams content frames back to HoloLens 2. La connessione viene eseguita usando il Wi-Fi standard.The connection is made using standard Wi-Fi. La comunicazione remota olografica viene aggiunta a un'app desktop o UWP tramite un pacchetto NuGet.Holographic Remoting is added to a desktop or UWP app via a NuGet packet. È necessario codice aggiuntivo che gestisce la connessione e ne esegue il rendering in una visualizzazione immersiva.Additional code is required which handles the connection and renders in an immersive view. Una tipica connessione remota avrà una bassa di 50 ms di latenza.A typical remoting connection will have as low as 50 ms of latency. L'App Player può segnalare la latenza in tempo reale.The player app can report the latency in real time.

Tutto il codice in questa pagina e i progetti di lavoro sono disponibili nel repository GitHub degli esempi di comunicazione remota olografica.All code on this page and working projects can be found in the Holographic Remoting samples github repository.

PrerequisitiPrerequisites

Un punto di partenza valido è un'app desktop o UWP funzionante basata su OpenXR.A good starting point is a working OpenXR based Desktop or UWP app. Per informazioni dettagliate, vedere la pagina relativa all'introduzione a OpenXR.For details see Getting started with OpenXR.

Importante

Qualsiasi app che usa la comunicazione remota olografica deve essere creata per usare un Apartmentmultithread.Any app using Holographic Remoting should be authored to use a multi-threaded apartment. L'uso di un Apartment a thread singolo è supportato, ma comporta prestazioni ottimali e possibilmente balbettanti durante la riproduzione.The use of a single-threaded apartment is supported but will lead to sub-optimal performance and possibly stuttering during playback. Quando si usa C++/WinRT WinRT:: init_apartment un apartment multithread è il valore predefinito.When using C++/WinRT winrt::init_apartment a multi-threaded apartment is the default.

Ottenere il pacchetto NuGet per la comunicazione remota olograficaGet the Holographic Remoting NuGet package

I passaggi seguenti sono necessari per aggiungere il pacchetto NuGet a un progetto in Visual Studio.The following steps are required to add the NuGet package to a project in Visual Studio.

  1. Aprire il progetto in Visual Studio.Open the project in Visual Studio.
  2. Fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Gestisci pacchetti NuGet...Right-click the project node and select Manage NuGet Packages...
  3. Nel pannello visualizzato selezionare Sfoglia e quindi cercare "comunicazione remota olografica".In the panel that appears, select Browse and then search for "Holographic Remoting".
  4. Selezionare Microsoft. olografic. Remoting. OpenXr, assicurarsi di selezionare la versione 2. x. x più recente e selezionare Installa.Select Microsoft.Holographic.Remoting.OpenXr, ensure to pick the latest 2.x.x version and select Install.
  5. Se viene visualizzata la finestra di dialogo Anteprima , fare clic su OK.If the Preview dialog appears, select OK.
  6. Selezionare Accetto quando viene visualizzata la finestra di dialogo contratto di licenza.Select I Accept when the license agreement dialog pops up.
  7. Ripetere i passaggi da 3 a 6 per i pacchetti NuGet seguenti: OpenXR. Headers, OpenXR. loaderRepeat the steps 3 to 6 for the following NuGet Packages: OpenXR.Headers, OpenXR.Loader

Nota

La versione 1. x. x del pacchetto NuGet è ancora disponibile per gli sviluppatori che desiderano utilizzare HoloLens 1.Version 1.x.x of the NuGet package is still available for developers who want to target HoloLens 1. Per informazioni dettagliate, vedere aggiungere la comunicazione remota olografica (HoloLens (1st Gen)).For details see Add Holographic Remoting (HoloLens (1st gen)).

Selezionare il runtime OpenXR di comunicazione remota olograficaSelect the Holographic Remoting OpenXR runtime

Il primo passaggio da eseguire nell'app remota consiste nel selezionare il runtime OpenXR di comunicazione remota olografica, che fa parte del pacchetto NuGet Microsoft. Olografic. Remoting. OpenXr.The first step you need to do in your remote app is to select the Holographic Remoting OpenXR runtime, which is part of the Microsoft.Holographic.Remoting.OpenXr NuGet package. Questa operazione può essere eseguita impostando la XR_RUNTIME_JSON variabile di ambiente sul percorso del RemotingXR.jsnel file all'interno dell'app.You can do this by setting the XR_RUNTIME_JSON environment variable to the path of the RemotingXR.json file within your app. Questa variabile di ambiente viene usata dal caricatore OpenXR per non usare il runtime OpenXR predefinito del sistema, ma viene invece reindirizzato al runtime OpenXR della comunicazione remota olografica.This environment variable is used by the OpenXR loader to not use the system default OpenXR runtime but instead redirect to the Holographic Remoting OpenXR runtime. Quando si usa il pacchetto NuGet Microsoft. Olografic. Remoting. OpenXr, il RemotingXR.jsnel file viene copiato automaticamente durante la compilazione nella cartella di output, la selezione del runtime di OpenXR è in genere simile alla seguente.When using the Microsoft.Holographic.Remoting.OpenXr NuGet package the RemotingXR.json file is automatically copied during compilation to the output folder, the OpenXR runtime selection typically looks as follows.

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;
}

Creare XrInstance con estensione per la comunicazione remota olograficaCreate XrInstance with Holographic Remoting Extension

Il primo passaggio di un'app OpenXR tipica consiste nel selezionare le estensioni OpenXR e creare un XrInstance.The first step a typical OpenXR app is supposed to do is to select OpenXR extensions and create an XrInstance. La specifica OpenXR Core non fornisce alcuna API per servizi remoti specifici.The OpenXR core specification doesn't provide any remoting specific API. Per questo motivo, la comunicazione remota olografica introduce una propria estensione OpenXR denominata XR_MSFT_holographic_remoting .For that reason Holographic Remoting introduces its own OpenXR extension named XR_MSFT_holographic_remoting. Assicurarsi che quando si chiama xrCreateInstance XR_MSFT_HOLOGRAPHIC_REMOTING_EXTENSION_NAME sia incluso in XrInstanceCreateInfo.Ensure that when you call xrCreateInstance the XR_MSFT_HOLOGRAPHIC_REMOTING_EXTENSION_NAME is included in the XrInstanceCreateInfo.

Suggerimento

Per impostazione predefinita, il contenuto di cui è stato eseguito il rendering dell'app viene trasmesso solo al lettore di comunicazione remota olografico in esecuzione su un HoloLens 2 o su un headset di realtà mista di Windows.By default the rendered content of your app is only streamed to the Holographic Remoting player either running on a HoloLens 2 or on a Windows Mixed Reality headsets. Per visualizzare anche il contenuto sottoposto a rendering nel computer remoto, tramite una catena di scambio di una finestra, ad esempio, la comunicazione remota olografica fornisce una seconda estensione OpenXR denominata XR_MSFT_holographic_remoting_frame_mirroring .To also display the rendered content on the remote PC, via a swap-chain of a window for instance, Holographic Remoting provides a second OpenXR extension named XR_MSFT_holographic_remoting_frame_mirroring. Assicurarsi di abilitare anche questa estensione usando XR_MSFT_HOLOGRAPHIC_REMOTING_FRAME_MIRRORING_EXTENSION_NAME nel caso in cui si desideri usare tale funzionalità.Ensure to also enable this extension using XR_MSFT_HOLOGRAPHIC_REMOTING_FRAME_MIRRORING_EXTENSION_NAME in case you want to use that functionality.

Importante

Per informazioni sull'API dell'estensione OpenXR per la comunicazione remota olografica, vedere la specifica che si trova nel repository GitHub degli esempi di comunicazione remota olografica.To learn about the Holographic Remoting OpenXR extension API, check out the specification which can be found in the Holographic Remoting samples github repository.

Connetti al dispositivoConnect to the device

Dopo che l'app remota ha creato il XrInstance ed eseguito una query su XrSystemId tramite xrGetSystem, è possibile stabilire una connessione al dispositivo Player.After your remote app has created the XrInstance and queried the XrSystemId via xrGetSystem a connection to the player device can be established.

Avviso

Il runtime OpenXR di comunicazione remota olografica è in grado di fornire solo i dati specifici del dispositivo, ad esempio le configurazioni della vista o le modalità di combinazione dell'ambiente dopo aver stabilito una connessione.The Holographic Remoting OpenXR runtime is only able to provide device specific data such as view configurations or environment blend modes after a connection has been established. xrEnumerateViewConfigurations, xrEnumerateViewConfigurationViews , xrGetViewConfigurationProperties , xrEnumerateEnvironmentBlendModes e xrGetSystemProperties forniranno i valori predefiniti, corrispondenti a quello che in genere si ottiene se ci si connette a un lettore che esegue in un HoloLens 2, prima di essere completamente connessi.xrEnumerateViewConfigurations, xrEnumerateViewConfigurationViews, xrGetViewConfigurationProperties, xrEnumerateEnvironmentBlendModes, and xrGetSystemProperties will give you default values, matching what you would typically get if you connect to a player running on a HoloLens 2, before being fully connected. Si consiglia vivamente di non chiamare questi metodi prima che sia stata stabilita una connessione.It is strongly recommended to not call these methods before a connection has been established. Il suggerimento viene usato questi metodi dopo che il XrSession è stato creato correttamente e lo stato della sessione è almeno XR_SESSION_STATE_READY.The suggestion is used these methods after the XrSession has been successfully created and the session state is at least XR_SESSION_STATE_READY.

È possibile configurare le proprietà generali come la velocità in bit massima, l'audio abilitato, il codec video o la risoluzione del flusso del buffer di profondità tramite xrRemotingSetContextPropertiesMSFT come indicato di seguito.General properties such as max bitrate, audio enabled, video codec, or depth buffer stream resolution can be configured via xrRemotingSetContextPropertiesMSFT as follows.

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);

La connessione può essere eseguita in uno dei due modi seguenti.The connection can be done in one of two ways.

  1. L'app remota si connette al lettore in esecuzione sul dispositivo.The remote app connects to the player running on the device.
  2. Il lettore in esecuzione sul dispositivo si connette all'app remota.The player running on the device connects to the remote app.

Per stabilire una connessione dall'app remota al dispositivo Player, chiamare il xrRemotingConnectMSFT metodo specificando il nome host e la porta tramite la XrRemotingConnectInfoMSFT struttura.To establish a connection from the remote app to the player device call the xrRemotingConnectMSFT method specifying the hostname and port via the XrRemotingConnectInfoMSFT structure. La porta usata dal lettore di comunicazione remota olografica è 8265.The port used by the Holographic Remoting Player is 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);

L'ascolto delle connessioni in ingresso nell'app remota può essere eseguito chiamando il xrRemotingListenMSFT metodo.Listening for incoming connections on the remote app can be done by calling the xrRemotingListenMSFT method. È possibile specificare sia la porta di handshake che la porta di trasporto tramite la XrRemotingListenInfoMSFT struttura.Both the handshake port and transport port can be specified via the XrRemotingListenInfoMSFT structure. La porta di handshake viene utilizzata per l'handshake iniziale.The handshake port is used for the initial handshake. I dati vengono quindi inviati tramite la porta di trasporto.The data is then sent over the transport port. Per impostazione predefinita vengono usati 8265 e 8266 .By default 8265 and 8266 are used.

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);

Lo stato della connessione deve essere disconnesso quando si chiama xrRemotingConnectMSFT o xrRemotingListenMSFT .The connection state must be disconnected when you call xrRemotingConnectMSFT or xrRemotingListenMSFT. È possibile ottenere lo stato di connessione in qualsiasi momento dopo aver creato un XrInstance ed eseguito una query per XrSystemId tramite xrRemotingGetConnectionStateMSFT .You can get the connection state at any point after you have created an XrInstance and queried for the XrSystemId via xrRemotingGetConnectionStateMSFT.

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

Gli Stati di connessione disponibili sono:Available connection states are:

  • XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFTXR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTING_MSFTXR_REMOTING_CONNECTION_STATE_CONNECTING_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFTXR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT

Importante

xrRemotingConnectMSFT oppure xrRemotingListenMSFT deve essere chiamato prima di provare a creare un XrSession tramite xrCreateSession.xrRemotingConnectMSFT or xrRemotingListenMSFT must be called before trying to create a XrSession via xrCreateSession. Se si tenta di creare un XrSession mentre lo stato della connessione è XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT la creazione della sessione avrà esito positivo, ma lo stato della sessione passerà immediatamente a XR_SESSION_STATE_LOSS_PENDING.If you try to create a XrSession while the connection state is XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT the session creation will succeed but the session state will immediately transition to XR_SESSION_STATE_LOSS_PENDING.

L'implementazione di comunicazione remota olografica xrCreateSession supporta l'attesa della creazione di una connessione.Holographic Remoting's implementation of xrCreateSession supports waiting for a connection to be established. È possibile chiamare xrRemotingConnectMSFT o xrRemotingListenMSFT immediatamente seguito da una chiamata a, che blocca e attende che venga stabilita una connessione.You can call xrRemotingConnectMSFT or xrRemotingListenMSFT immediately followed by a call to, which will block and wait for a connection to be established. Il timeout è fisso a 10 secondi.The timeout is fixed to 10 seconds. Se è possibile stabilire una connessione entro questo periodo di tempo, la creazione del XrSession avrà esito positivo e lo stato della sessione passerà a XR_SESSION_STATE_READY.If a connection can be established within this time the XrSession creation will succeed and the session state will transition to XR_SESSION_STATE_READY. Se non è possibile stabilire alcuna connessione, la creazione della sessione riesce anche ma passa immediatamente a XR_SESSION_STATE_LOSS_PENDING.In case no connection can be established the session creation also succeeds but immediately transitions to XR_SESSION_STATE_LOSS_PENDING.

In generale, lo stato di connessione è coppia con lo stato XrSession.In general, the connection state is couple with the XrSession state. Qualsiasi modifica allo stato della connessione influisca anche sullo stato della sessione.Any change to the connection state also affects the session state. Ad esempio, se lo stato della connessione passa da XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT a XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT stato sessione, passerà anche a XR_SESSION_STATE_LOSS_PENDING.For instance, if the connection state switches from XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT to XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT the session state will transition to XR_SESSION_STATE_LOSS_PENDING as well.

Gestione di eventi specifici della comunicazione remotaHandling Remoting specific events

Il runtime OpenXR di comunicazione remota olografica espone tre eventi, che sono importanti per monitorare lo stato di una connessione.The Holographic Remoting OpenXR runtime exposes three events, which are important to monitor the state of a connection.

  1. XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: Attivato quando una connessione al dispositivo è stata stabilita correttamente.XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: Triggered when a connection to the device has been successfully established.
  2. XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: Attivato se una connessione stabilita è chiusa o non è stato possibile stabilire una connessione.XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: Triggered if an established connection is closed or a connection couldn't be established.
  3. XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT: Quando viene avviata l'attesa delle connessioni in ingresso.XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT: When listening for incoming connections starts.

Questi eventi vengono inseriti in una coda e l'app remota deve leggere dalla coda con regolarità tramite xrPollEvent .These events are placed in a queue and your remote app must read from the queue with regularity via xrPollEvent.

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;
    }
}

Anteprima del contenuto trasmesso localmentePreview streamed content locally

Per visualizzare lo stesso contenuto nell'app remota inviata al dispositivo XR_MSFT_holographic_remoting_frame_mirroring , è possibile usare l'estensione.To display the same content in the remote app that is sent to the device the XR_MSFT_holographic_remoting_frame_mirroring extension can be used. Con questa estensione, è possibile inviare una trama a xrEndFrame usando l'oggetto XrRemotingFrameMirrorImageInfoMSFT che non è concatenato a XrFrameEndInfo come indicato di seguito.With this extension, you can submit a texture to xrEndFrame by using the XrRemotingFrameMirrorImageInfoMSFT that isn't chained to the XrFrameEndInfo as follows.

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();

L'esempio precedente usa una trama a catena di scambio DX11 e visualizza la finestra immediatamente dopo la chiamata a xrEndFrame.The example above uses a DX11 swap-chain texture and presents the window immediately after the call to xrEndFrame. L'utilizzo non è limitato alle trame a catena di scambio e non è necessaria alcuna sincronizzazione aggiuntiva della GPU.The usage isn't restricted to swap-chain textures and no additional GPU synchronization is required. Per informazioni dettagliate sull'utilizzo e sui vincoli, vedere la specifica dell'estensione.For details on usage and constraints check out the extension specification. Se l'app remota USA DX12, usare XrRemotingFrameMirrorImageD3D12MSFT anziché XrRemotingFrameMirrorImageD3D11MSFT.If your remote app is using DX12 use XrRemotingFrameMirrorImageD3D12MSFT instead of XrRemotingFrameMirrorImageD3D11MSFT.

Vedere ancheSee Also