Scrittura di un'app Remota Holographic Remoting con l'API OpenXR

Se non si ha familiarità con Holographic Remoting, è possibile leggere la panoramica.

Importante

Questo documento descrive la creazione di un'applicazione remota per HoloLens 2 e Windows Mixed Reality visori VR usando l'API OpenXR. Le applicazioni remote per HoloLens (prima generazione) devono usare il pacchetto NuGet versione 1.x.x. Ciò implica che le applicazioni remote scritte per HoloLens 2 non sono compatibili con HoloLens 1 e viceversa. La documentazione per HoloLens 1 è disponibile qui.

Le app Holographic Remoting possono trasmettere contenuti sottoposti a rendering remoto a HoloLens 2 e Windows Mixed Reality visori VR immersive. È anche possibile accedere a più risorse di sistema e integrare visualizzazioni immersive remote nel software pc desktop esistente. 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 i frame di contenuto a HoloLens 2. La connessione viene effettuata tramite Wi-Fi standard. Holographic Remoting viene aggiunto a un'app desktop o UWP tramite un pacchetto NuGet. È necessario codice aggiuntivo che gestisce la connessione ed esegue il rendering in una visualizzazione immersiva. Una connessione remota tipica avrà un minimo di 50 ms di latenza. L'app lettore può segnalare la latenza in tempo reale.

Tutto il codice in questa pagina e i progetti funzionanti sono disponibili nel repository GitHub degli esempi di Holographic Remoting.

Prerequisiti

Un buon punto di partenza è un'app Desktop o UWP basata su OpenXR funzionante. Per informazioni dettagliate, vedere Introduzione a OpenXR.

Importante

Qualsiasi app che usa Holographic Remoting deve essere creata per usare un apartment multithread. L'uso di un apartment a thread singolo è supportato , ma comporterà prestazioni non ottimali e possibilmente stuttering durante la riproduzione. Quando si usa C++/ WinRT winrt::init_apartment un apartment multithread è l'impostazione predefinita.

Ottenere il pacchetto NuGet Holographic Remoting

Per aggiungere il pacchetto NuGet a un progetto in Visual Studio, sono necessari i passaggi seguenti.

  1. Aprire il progetto in Visual Studio.
  2. Fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Gestisci pacchetti NuGet...
  3. Nel pannello visualizzato selezionare Sfoglia e quindi cercare "Holographic Remoting".
  4. Selezionare Microsoft.Holographic.Remoting.OpenXr, quindi assicurarsi che sia selezionata la versione 2.x.x più recente e quindi selezionare Installa.
  5. Se viene visualizzata la finestra di dialogo Anteprima , selezionare OK.
  6. Selezionare Accetto quando viene visualizzata la finestra di dialogo del contratto di licenza.
  7. Ripetere i passaggi da 3 a 6 per i pacchetti NuGet seguenti: OpenXR.Headers, OpenXR.Loader

Nota

La versione 1.x.x del pacchetto NuGet è ancora disponibile per gli sviluppatori che vogliono usare HoloLens 1. Per informazioni dettagliate, vedere Aggiungere Holographic Remoting (HoloLens (prima generazione)).

Selezionare il runtime OpenXR di Holographic Remoting

Il primo passaggio da eseguire nell'app remota consiste nel selezionare il runtime OpenXR holographic Remoting, che fa parte del pacchetto NuGet Microsoft.Holographic.Remoting.OpenXr. A tale scopo, impostare la XR_RUNTIME_JSON variabile di ambiente sul percorso del file RemotingXR.json all'interno dell'app. Questa variabile di ambiente viene usata dal caricatore OpenXR per non usare il runtime OpenXR predefinito del sistema, ma reindirizza invece al runtime OpenXR holographic Remoting. Quando si usa il pacchetto NuGet Microsoft.Holographic.Remoting.OpenXr, il file RemotingXR.json viene copiato automaticamente durante la compilazione nella cartella di output, la selezione del runtime OpenXR è in genere simile alla seguente.

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 l'estensione Holographic Remoting

Le prime azioni che un'app OpenXR tipica deve eseguire sono selezionare Estensioni OpenXR e creare una XrInstance. La specifica di base OpenXR non fornisce alcuna API specifica per la comunicazione remota. Per questo motivo, Holographic Remoting introduce la propria estensione OpenXR denominata XR_MSFT_holographic_remoting. Assicurarsi che XR_MSFT_HOLOGRAPHIC_REMOTING_EXTENSION_NAME sia incluso in XrInstanceCreateInfo della chiamata xrCreateInstance.

Suggerimento

Per impostazione predefinita, il contenuto sottoposto a rendering dell'app viene trasmesso solo al lettore Holographic Remoting in esecuzione su un HoloLens 2 o su un visore VR Windows Mixed Reality. Per visualizzare anche il contenuto sottoposto a rendering nel PC remoto, tramite una catena di scambio di una finestra, ad esempio, Holographic Remoting fornisce una seconda estensione OpenXR denominata XR_MSFT_holographic_remoting_frame_mirroring. Assicurarsi anche di abilitare questa estensione usando XR_MSFT_HOLOGRAPHIC_REMOTING_FRAME_MIRRORING_EXTENSION_NAME nel caso in cui si voglia usare tale funzionalità.

Importante

Per informazioni sull'API di estensione OpenXR holographic Remoting, vedere la specifica disponibile nel repository GitHub degli esempi di Holographic Remoting.

Connettersi al dispositivo

Dopo che l'app remota ha creato la XrInstance ed eseguito una query su XrSystemId tramite xrGetSystem, è possibile stabilire una connessione al dispositivo lettore.

Avviso

Il runtime OpenXR di Holographic Remoting è in grado di fornire dati specifici del dispositivo, ad esempio configurazioni di visualizzazione o modalità di fusione dell'ambiente dopo che è stata stabilita una connessione. xrEnumerateViewConfigurations, xrEnumerateViewConfigurationViews, xrGetViewConfigurationProperties, xrEnumerateEnvironmentBlendModese xrGetSystemProperties forniscono valori predefiniti, corrispondenti a ciò che in genere si otterrebbe se ci si connette a un giocatore in esecuzione in un HoloLens 2, prima di essere completamente connesso. È consigliabile non chiamare questi metodi prima di stabilire una connessione. Il suggerimento viene usato questi metodi dopo la creazione di XrSession e lo stato della sessione è almeno XR_SESSION_STATE_READY.

Le proprietà generali, ad esempio velocità in bit massima, audio abilitato, codec video o risoluzione del flusso del buffer di profondità, possono essere configurate tramite xrRemotingSetContextPropertiesMSFT come indicato di seguito.

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.

  1. L'app remota si connette al lettore in esecuzione nel dispositivo.
  2. Il lettore in esecuzione nel dispositivo si connette all'app remota.

Per stabilire una connessione dall'app remota al dispositivo lettore, chiamare il metodo specificando il xrRemotingConnectMSFT nome host e la porta tramite la XrRemotingConnectInfoMSFT struttura. La porta usata da Holographic Remoting Player è 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 eseguita chiamando il xrRemotingListenMSFT metodo . Sia la porta di handshake che la porta di trasporto possono essere specificate tramite la XrRemotingListenInfoMSFT struttura . La porta handshake viene usata per l'handshake iniziale. I dati vengono quindi inviati sulla porta di trasporto. Per impostazione predefinita vengono usati 8265 e 8266 .

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. È possibile ottenere lo stato di connessione in qualsiasi momento dopo aver creato una XrInstance ed è stata eseguita una query per XrSystemId tramite xrRemotingGetConnectionStateMSFT.

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

Gli stati di connessione disponibili sono:

  • XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTING_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT

Importante

xrRemotingConnectMSFT o xrRemotingListenMSFT deve essere chiamato prima di provare a creare una XrSession tramite xrCreateSession. Se si tenta di creare una sessione 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.

L'implementazione di Holographic Remoting di xrCreateSession supporta l'attesa di stabilire una connessione. È possibile chiamare xrRemotingConnectMSFT o xrRemotingListenMSFT immediatamente seguito da una chiamata a xrCreateSession, che blocca e attende che venga stabilita una connessione. Il timeout con xrRemotingConnectMSFT è fisso a 10 secondi e illimitato con xrRemotingListenMSFT. Se è possibile stabilire una connessione entro questo periodo, la creazione di XrSession avrà esito positivo e lo stato della sessione passerà a XR_SESSION_STATE_READY. Se non è possibile stabilire alcuna connessione, la creazione della sessione ha esito positivo, ma passa immediatamente a XR_SESSION_STATE_LOSS_PENDING.

In generale, lo stato della connessione è associato allo stato XrSession. Qualsiasi modifica allo stato della connessione influisce anche sullo stato della sessione. Ad esempio, se lo stato della connessione passa dallo XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT stato alla XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT sessione passerà anche a XR_SESSION_STATE_LOSS_PENDING.

Gestione di eventi specifici della comunicazione remota

Il runtime OpenXR di Holographic Remoting espone tre eventi, che sono importanti per monitorare lo stato di una connessione.

  1. XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: attivato quando è stata stabilita correttamente una connessione al dispositivo.
  2. XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: attivato se una connessione stabilita è chiusa o non è stato possibile stabilire una connessione.
  3. XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT: quando si avvia l'ascolto delle connessioni in ingresso.

Questi eventi vengono inseriti in una coda e l'app remota deve leggere dalla coda con regolarità tramite 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;
	}
}

Visualizzare in anteprima il contenuto trasmesso in locale

Per visualizzare lo stesso contenuto nell'app remota inviata al dispositivo, è possibile usare l'estensione XR_MSFT_holographic_remoting_frame_mirroring . Con questa estensione, è possibile inviare una trama a xrEndFrame usando che XrRemotingFrameMirrorImageInfoMSFT non è concatenato a XrFrameEndInfo come indicato di seguito.

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 della catena di scambio DX11 e presenta la finestra immediatamente dopo la chiamata a xrEndFrame. L'utilizzo non è limitato alle trame della catena di scambio. Inoltre, non è necessaria alcuna sincronizzazione GPU aggiuntiva. Per informazioni dettagliate sull'utilizzo e sui vincoli, vedere la specifica dell'estensione. Se l'app remota usa DX12, usa XrRemotingFrameMirrorImageD3D12MSFT anziché XrRemotingFrameMirrorImageD3D11MSFT.

Facoltativo: canali dati personalizzati

A partire dalla versione 2.5.0, i canali dati personalizzati possono essere usati con l'API OpenXR per inviare dati utente tramite la connessione remota già stabilita. Per altre informazioni, vedere Canali dati personalizzati con l'API OpenXR.

Facoltativo: Riconoscimento vocale

A partire dalla versione 2.6.0, l'estensione XR_MSFT_holographic_remoting_speech consente all'app remota di reagire ai comandi vocali rilevati dall'app lettore con l'API OpenXR.

[! IMPORTANTE] La specifica dettagliata è disponibile nel repository GitHub degli esempi di Holographic Remoting.

Per inizializzare un riconoscimento vocale nell'app lettore, l'app remota può chiamare xrInitializeRemotingSpeechMSFT. Questa chiamata trasmette i parametri di inizializzazione vocale, costituiti da una lingua, da un dizionario di frasi e dal contenuto di un file grammaticale, all'app lettore.

Nota

Prima della versione 2.6.1 il riconoscimento vocale deve essere inizializzato una sola volta per XrSession.

Se la creazione del riconoscimento vocale ha avuto esito positivo, come indicato dall'evento XR_TYPE_EVENT_DATA_REMOTING_SPEECH_RECOGNIZER_STATE_CHANGED_MSFT , l'app remota riceverà una notifica quando viene generato un risultato del riconoscimento vocale nell'app lettore. La XrEventDataRemotingSpeechRecognizerStateChangedMSFT struttura di eventi viene inserita nella coda degli eventi quando lo stato del riconoscimento vocale sul lato lettore cambia.

XrRemotingSpeechRecognizerStateMSFT definisce tutti gli stati possibili del riconoscimento vocale sul lato lettore e la XrEventDataRemotingSpeechRecognizedMSFT struttura dell'evento viene inserita nella coda degli eventi se il riconoscimento vocale sul lato giocatore ha una frase riconosciuta. Dopo che l'app remota riceve una notifica su una frase riconosciuta, può recuperare la frase riconosciuta chiamando xrRetrieveRemotingSpeechRecognizedTextMSFT.

Nota

XrRemotingSpeechRecognitionConfidenceMSFT è un mapping diretto dell'enumerazione SpeechRecognitionConfidence restituita con il risultato del riconoscimento vocale dall'API Riconoscimento vocale di Windows.

Facoltativo: sincronizzazione del sistema di coordinate

A partire dalla versione 2.7.0, è possibile usare la sincronizzazione del sistema di coordinate per allineare i dati spaziali tra il lettore e l'app remota. Per altre informazioni, vedere Coordinate System Synchronization with Holographic Remoting Overview .For more information, see Coordinate System Synchronization with Holographic Remoting Overview.

Vedere anche