Escritura de una aplicación remota holográfica mediante la API de OpenXR

Si no está familiarizado con la comunicación remota holográfica, puede que quiera leer nuestra información general.

Importante

En este documento se describe la creación de una aplicación remota para HoloLens 2 y cascos de Windows Mixed Reality mediante la API de OpenXR. Las aplicaciones remotas para HoloLens (1.ª generación) deben usar la versión 1.x.x del paquete NuGet. Esto implica que las aplicaciones remotas escritas para HoloLens 2 no son compatibles con HoloLens 1 y viceversa. La documentación de HoloLens 1 se puede encontrar aquí.

Las aplicaciones de comunicación remota holográfica pueden transmitir contenido representado de forma remota a HoloLens 2 y Windows Mixed Reality cascos envolventes. También puede acceder a más recursos del sistema e integrar vistas envolventes remotas en el software de pc de escritorio existente. Una aplicación remota recibe un flujo de datos de entrada de HoloLens 2, representa el contenido en una vista envolvente virtual y transmite fotogramas de contenido a HoloLens 2. La conexión se realiza mediante Wi-Fi estándar. La comunicación remota holográfica se agrega a una aplicación de escritorio o para UWP a través de un paquete NuGet. Se requiere código adicional que controla la conexión y se representa en una vista envolvente. Una conexión remota típica tendrá tan solo 50 ms de latencia. La aplicación del reproductor puede notificar la latencia en tiempo real.

Todo el código de esta página y los proyectos de trabajo se pueden encontrar en el repositorio de github de ejemplos de Holographic Remoting.

Requisitos previos

Un buen punto de partida es una aplicación de escritorio o UWP basada en OpenXR en funcionamiento. Para más información, consulte Introducción a OpenXR.

Importante

Cualquier aplicación que use Holographic Remoting debe crearse para usar un apartamento multiproceso. Se admite el uso de un apartamento de un solo subproceso , pero dará lugar a un rendimiento óptimo y posiblemente a la reproducción. Cuando se usa C++/WinRT winrt::init_apartment un apartamento multiproceso es el valor predeterminado.

Obtención del paquete NuGet de comunicación remota holográfica

Los pasos siguientes son necesarios para agregar el paquete NuGet a un proyecto en Visual Studio.

  1. Abra el proyecto en Visual Studio.
  2. Haga clic con el botón derecho en el nodo del proyecto y seleccione Administrar paquetes NuGet...
  3. En el panel que aparece, seleccione Examinar y busque "Comunicación remota holográfica".
  4. Seleccione Microsoft.Holographic.Remoting.OpenXr y asegúrese de que la versión 2.x.x más reciente esté seleccionada y, a continuación, seleccione Instalar.
  5. Si aparece el cuadro de diálogo Vista previa , seleccione Aceptar.
  6. Seleccione Acepto cuando aparezca el cuadro de diálogo del contrato de licencia.
  7. Repita los pasos 3 a 6 para los siguientes paquetes NuGet: OpenXR.Headers, OpenXR.Loader

Nota

La versión 1.x.x del paquete NuGet sigue estando disponible para los desarrolladores que quieran dirigirse a HoloLens 1. Para obtener más información, consulte Agregar comunicación remota holográfica (HoloLens (1.ª generación)).

Seleccione el entorno de ejecución de OpenXR de comunicación remota holográfica.

El primer paso que debe realizar en la aplicación remota es seleccionar el entorno de ejecución de OpenXR de comunicación remota holográfica, que forma parte del paquete NuGet Microsoft.Holographic.Remoting.OpenXr. Para ello, establezca la XR_RUNTIME_JSON variable de entorno en la ruta de acceso del archivo RemotingXR.json dentro de la aplicación. El cargador de OpenXR usa esta variable de entorno para no usar el entorno de ejecución predeterminado de OpenXR del sistema, sino que redirige al entorno de ejecución de OpenXR de comunicación remota holográfica. Cuando se usa el paquete NuGet Microsoft.Holographic.Remoting.OpenXr, el archivo RemotingXR.json se copia automáticamente durante la compilación en la carpeta de salida, la selección en tiempo de ejecución de OpenXR suele ser la siguiente.

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

Creación de XrInstance con la extensión de comunicación remota holográfica

Las primeras acciones que debe realizar una aplicación OpenXR típica son las extensiones de OpenXR y crear una XrInstance. La especificación principal de OpenXR no proporciona ninguna API específica de comunicación remota. Por ese motivo, Holographic Remoting presenta su propia extensión OpenXR denominada XR_MSFT_holographic_remoting. Asegúrese de que XR_MSFT_HOLOGRAPHIC_REMOTING_EXTENSION_NAME se incluye en XrInstanceCreateInfo de la llamada xrCreateInstance.

Sugerencia

De forma predeterminada, el contenido representado de la aplicación solo se transmite al reproductor de comunicación remota holográfica que se ejecuta en un HoloLens 2 o en un casco de Windows Mixed Reality. Para mostrar también el contenido representado en el equipo remoto, a través de una cadena de intercambio de una ventana por ejemplo, Holographic Remoting proporciona una segunda extensión openXR denominada XR_MSFT_holographic_remoting_frame_mirroring. Asegúrese de habilitar también esta extensión con XR_MSFT_HOLOGRAPHIC_REMOTING_FRAME_MIRRORING_EXTENSION_NAME en caso de que quiera usar esa funcionalidad.

Importante

Para obtener información sobre la API de extensión de OpenXR de Holographic Remoting, consulte la especificación que se puede encontrar en el repositorio de github de ejemplos de Holographic Remoting.

Conexión al dispositivo

Una vez creada la aplicación remota, XrInstance y consultado el XrSystemId a través de xrGetSystem, se puede establecer una conexión con el dispositivo del reproductor.

Advertencia

El entorno de ejecución de OpenXR de comunicación remota holográfica solo puede proporcionar datos específicos del dispositivo, como configuraciones de vista o modos de combinación de entornos después de establecer una conexión. xrEnumerateViewConfigurations, xrEnumerateViewConfigurationViews, xrGetViewConfigurationProperties, xrEnumerateEnvironmentBlendModesy xrGetSystemProperties le proporcionará valores predeterminados, lo que normalmente obtendría si se conecta a un reproductor que se ejecuta en un HoloLens 2, antes de estar completamente conectado. Se recomienda encarecidamente no llamar a estos métodos antes de establecer una conexión. La sugerencia se usa estos métodos después de que XrSession se haya creado correctamente y el estado de sesión sea al menos XR_SESSION_STATE_READY.

Las propiedades generales, como velocidad de bits máxima, habilitada para audio, códec de vídeo o resolución de secuencia de búfer de profundidad, se pueden configurar de xrRemotingSetContextPropertiesMSFT la siguiente manera.

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 conexión se puede realizar de dos maneras.

  1. La aplicación remota se conecta al reproductor que se ejecuta en el dispositivo.
  2. El reproductor que se ejecuta en el dispositivo se conecta a la aplicación remota.

Para establecer una conexión desde la aplicación remota al dispositivo del reproductor, llame xrRemotingConnectMSFT al método que especifica el nombre de host y el puerto a través de la XrRemotingConnectInfoMSFT estructura . El puerto usado por holographic Remoting Player es 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);

La escucha de las conexiones entrantes en la aplicación remota se puede realizar mediante una llamada al xrRemotingListenMSFT método . Tanto el puerto de protocolo de enlace como el puerto de transporte se pueden especificar a través de la XrRemotingListenInfoMSFT estructura . El puerto del protocolo de enlace se usa para el protocolo de enlace inicial. A continuación, los datos se envían a través del puerto de transporte. De forma predeterminada, se usan 8265 y 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);

El estado de conexión debe desconectarse cuando se llama a xrRemotingConnectMSFT o xrRemotingListenMSFT. Puede obtener el estado de conexión en cualquier momento después de haber creado una XrInstance y consultado para XrSystemId a través xrRemotingGetConnectionStateMSFTde .

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

Los estados de conexión disponibles son:

  • XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTING_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT

Importante

xrRemotingConnectMSFT o xrRemotingListenMSFT debe llamarse antes de intentar crear una XrSession a través de xrCreateSession. Si intenta crear una XrSession mientras el estado de conexión es XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT la creación de la sesión se realizará correctamente, pero el estado de sesión pasará inmediatamente a XR_SESSION_STATE_LOSS_PENDING.

La implementación de Holographic Remoting de xrCreateSession admite la espera de establecer una conexión. Puede llamar xrRemotingConnectMSFT a o xrRemotingListenMSFT inmediatamente seguido de una llamada a xrCreateSession, que bloqueará y esperará a que se establezca una conexión. El tiempo de espera con xrRemotingConnectMSFT se fija a 10 segundos y es ilimitado con xrRemotingListenMSFT. Si se puede establecer una conexión en este momento, la creación de XrSession se realizará correctamente y el estado de sesión pasará a XR_SESSION_STATE_READY. En caso de que no se pueda establecer ninguna conexión, la creación de la sesión también se realiza correctamente, pero inmediatamente pasa a XR_SESSION_STATE_LOSS_PENDING.

En general, el estado de conexión se acopla con el estado XrSession. Cualquier cambio en el estado de conexión también afecta al estado de sesión. Por ejemplo, si el estado de conexión cambia de XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT al XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT estado de sesión también pasará a XR_SESSION_STATE_LOSS_PENDING.

Control de eventos específicos de comunicación remota

El entorno de ejecución de OpenXR de holographic Remoting expone tres eventos, que son importantes para supervisar el estado de una conexión.

  1. XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: se desencadena cuando se ha establecido correctamente una conexión al dispositivo.
  2. XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: se desencadena si se cierra una conexión establecida o no se pudo establecer una conexión.
  3. XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT: cuando se inicia la escucha de las conexiones entrantes.

Estos eventos se colocan en una cola y la aplicación remota debe leer desde la cola con regularidad a través xrPollEventde .

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

Vista previa del contenido transmitido localmente

Para mostrar el mismo contenido en la aplicación remota que se envía al dispositivo, se puede usar la XR_MSFT_holographic_remoting_frame_mirroring extensión. Con esta extensión, puede enviar una textura a xrEndFrame mediante el XrRemotingFrameMirrorImageInfoMSFT que no está encadenado a XrFrameEndInfo como se indica a continuación.

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

En el ejemplo anterior se usa una textura de cadena de intercambio DX11 y se presenta la ventana inmediatamente después de la llamada a xrEndFrame. El uso no está restringido a las texturas de la cadena de intercambio. Además, no se requiere ninguna sincronización de GPU adicional. Para más información sobre el uso y las restricciones, consulte la especificación de extensión. Si la aplicación remota usa DX12, usa XrRemotingFrameMirrorImageD3D12MSFT en lugar de XrRemotingFrameMirrorImageD3D11MSFT.

Opcional: Canales de datos personalizados

A partir de la versión 2.5.0, los canales de datos personalizados se pueden usar con la API de OpenXR para enviar datos de usuario a través de la conexión remota ya establecida. Para obtener más información, consulte Canales de datos personalizados con la API de OpenXR.

Opcional: Voz

A partir de la versión 2.6.0, la extensión permite que la XR_MSFT_holographic_remoting_speech aplicación remota reaccione a los comandos de voz detectados por la aplicación del reproductor con la API de OpenXR.

[! IMPORTANTE] La especificación detallada se puede encontrar en el repositorio de github de ejemplos de comunicación remota holográfica.

Para inicializar un reconocedor de voz en la aplicación del reproductor, la aplicación remota puede llamar a xrInitializeRemotingSpeechMSFT. Esta llamada transmite parámetros de inicialización de voz, que constan de un idioma, un diccionario de frases y el contenido de un archivo de gramática, a la aplicación del reproductor.

Nota

Antes de la versión 2.6.1 , el reconocedor de voz solo se debe inicializar una vez por XrSession.

Si la creación del reconocedor de voz se realizó correctamente, como se indica en el evento, se notificará a la XR_TYPE_EVENT_DATA_REMOTING_SPEECH_RECOGNIZER_STATE_CHANGED_MSFT aplicación remota cuando se genere un resultado de reconocimiento de voz en la aplicación del reproductor. La XrEventDataRemotingSpeechRecognizerStateChangedMSFT estructura de eventos se coloca en la cola de eventos cuando cambia el estado del reconocedor de voz en el reproductor.

XrRemotingSpeechRecognizerStateMSFT define todos los estados posibles del reconocedor de voz en el lado del jugador y la XrEventDataRemotingSpeechRecognizedMSFT estructura de eventos se coloca en la cola de eventos si el reconocedor de voz del lado del jugador tiene una frase reconocida. Una vez que se notifica a la aplicación remota sobre una frase reconocida, puede recuperar la frase reconocida llamando a xrRetrieveRemotingSpeechRecognizedTextMSFT.

Nota

XrRemotingSpeechRecognitionConfidenceMSFT es una asignación directa de la enumeración SpeechRecognitionConfidence devuelta con el resultado del reconocimiento de voz por la API de reconocimiento de voz de Windows.

Opcional: Sincronización del sistema de coordenadas

A partir de la versión 2.7.0, la sincronización del sistema de coordenadas se puede usar para alinear los datos espaciales entre el reproductor y la aplicación remota. Para obtener más información, consulte Coordinate System Synchronization with Holographic Remoting Overview (Coordinar la sincronización del sistema con la comunicación remota holográfica).

Consulte también