Escrever uma aplicação remota holográfica de remoting utilizando a API OpenXR

Se é novo no Remoting Holográfico, pode querer ler a nossa visão geral.

Importante

Este documento descreve a criação de uma aplicação remota para auscultadores HoloLens 2 e Windows Mixed Reality utilizando a API OpenXR. As aplicações remotas para HoloLens (1ª gen) devem utilizar a versão 1.x.x . Isto implica que as aplicações remotas escritas para HoloLens 2 não são compatíveis com HoloLens 1 e vice-versa. A documentação para HoloLens 1 pode ser consultada aqui.

As aplicações holográficas de remoting podem transmitir conteúdo remotamente renderizado para HoloLens 2 e Windows Mixed Reality auscultadores imersivos. Também pode aceder a mais recursos do sistema e integrar visões imersivas remotas no software pc de desktop existente. Uma aplicação remota recebe um fluxo de dados de entrada de HoloLens 2, torna o conteúdo numa visão imersiva virtual e transmite quadros de conteúdo de volta a HoloLens 2. A ligação é feita com Wi-Fi padrão. O Remoting Holográfico é adicionado a um desktop ou app UWP através de um pacote NuGet. É necessário um código adicional que manuseie a ligação e torna-se numa visão imersiva. Uma ligação típica de remoing terá até 50 ms de latência. A aplicação do jogador pode reportar a latência em tempo real.

Todos os códigos desta página e projetos de trabalho podem ser encontrados no repositório de amostras holográficas de github.

Pré-requisitos

Um bom ponto de partida é um desktop baseado em OpenXR ou uma aplicação UWP baseada em openXR. Para mais detalhes, consulte Começar com o OpenXR.

Importante

Qualquer aplicação que utilize o Remoting Holográfico deve ser da autoria de utilizar um apartamento com vários fios. O uso de um apartamento com fio único é suportado, mas levará a um desempenho sub-ideal e possivelmente gagueja durante a reprodução. Ao utilizar o winrt C++/WinRT::init_apartment um apartamento com vários fios é o padrão.

Obtenha o pacote Holographic Remoting NuGet

São necessários os seguintes passos para adicionar o pacote NuGet a um projeto em Visual Studio.

  1. Abra o projeto no Visual Studio.
  2. Clique com o botão direito no nó do projeto e selecione Gerir pacotes NuGet...
  3. No painel que aparece, selecione Procurar por "Remoing Holográfico".
  4. Selecione Microsoft.Holographic.Remoting.OpenXr,em seguida, certifique-se de que a versão mais recente de 2.x.x está selecionada e, em seguida, selecione Instalar.
  5. Se aparecer o diálogo de pré-visualização, selecione OK.
  6. Selecione Eu Aceito quando o diálogo do contrato de licença aparece.
  7. Repita os passos 3 a 6 para os seguintes Pacotes NuGet: OpenXR.Headers, OpenXR.Loader

Nota

A versão 1.x.x do pacote NuGet ainda está disponível para os desenvolvedores que pretendam HoloLens 1. Para mais detalhes, consulte o Add Holographic Remoting (HoloLens (1ª geração)).

Selecione o tempo de execução Holographic Remoting OpenXR

O primeiro passo que precisa de fazer na sua aplicação remota é selecionar o tempo de execução Holographic Remoting OpenXR, que faz parte do pacote Microsoft.Holographic.Remoting.OpenXr NuGet. Pode fazê-lo definindo a XR_RUNTIME_JSON variável ambiente para o caminho do ficheiro RemotingXR.json dentro da sua aplicação. Esta variável de ambiente é utilizada pelo carregador OpenXR para não utilizar o tempo de funcionaamento do OpenXR padrão do sistema, mas sim redirecionar para o tempo de funcionaamento holográfico do RemoIng OpenXR. Ao utilizar o pacote Microsoft.Holographic.Remoting.OpenXr NuGet, o ficheiro RemotingXR.json é automaticamente copiado durante a compilação para a pasta de saída, a seleção de tempo de execução OpenXR normalmente parece a seguinte.

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

Criar XrInstance com extensão holográfica de remoting

As primeiras ações que uma aplicação típica do OpenXR deve tomar são selecionar extensões OpenXR e criar um XrInstance. A especificação do núcleo OpenXR não fornece nenhuma API específica de remoagem. Por essa razão, o Remoting Holográfico introduz a sua própria extensão OpenXR chamada XR_MSFT_holographic_remoting . Certifique-se de que XR_MSFT_HOLOGRAPHIC_REMOTING_EXTENSION_NAME está incluído na XrInstanceCreateInfo da chamada xrCreateInstance.

Dica

Por predefinição, o conteúdo renderizado da sua aplicação só é transmitido para o leitor holográfico de remoing, seja em execução num HoloLens 2 ou num Windows Mixed Reality auriculares. Para também exibir o conteúdo renderizado no PC remoto, através de uma cadeia de troca de uma janela, por exemplo, o Remoting Holográfico fornece uma segunda extensão OpenXR chamada XR_MSFT_holographic_remoting_frame_mirroring . Certifique-se de que também ativa esta XR_MSFT_HOLOGRAPHIC_REMOTING_FRAME_MIRRORING_EXTENSION_NAME extensão, no caso de pretender utilizar essa funcionalidade.

Importante

Para saber mais sobre a extensão Holográfica de Remoting OpenXR API, consulte a especificação que pode ser encontrada no repositório de remoagem holográfico github.

Ligação ao dispositivo

Depois de a sua aplicação remota ter criado o XrInstance e consultado o XrSystemId via xrGetSystem, pode ser estabelecida uma ligação ao dispositivo do jogador.

Aviso

O tempo de funcionamento holográfico do Remoting OpenXR só é capaz de fornecer dados específicos do dispositivo, tais como configurações de visualização ou modos de mistura de ambiente após a criação de uma ligação. xrEnumerateViewConfigurations, xrEnumerateViewConfigurationViews , e lhe dará xrGetViewConfigurationPropertiesxrEnumerateEnvironmentBlendModesxrGetSystemProperties valores predefinidos, correspondendo ao que normalmente obtém se ligar a um jogador que corre num HoloLens 2, antes de estar totalmente ligado. Recomenda-se vivamente que não se chamem estes métodos antes de se estabelecer uma ligação. A sugestão é usada estes métodos após a criação do XrSession com sucesso e o estado da sessão é pelo menos XR_SESSION_STATE_READY.

Propriedades gerais como bitrate máximo, áudio ativado, código de vídeo ou resolução de fluxo de tampão de profundidade podem ser configuradas através da xrRemotingSetContextPropertiesMSFT seguinte forma.

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

A ligação pode ser feita de duas maneiras.

  1. A aplicação remota liga-se ao jogador que está a executar no dispositivo.
  2. O leitor em execução no dispositivo liga-se à aplicação remota.

Para estabelecer uma ligação da aplicação remota ao dispositivo do jogador, ligue para o xrRemotingConnectMSFT método que especifica o nome de anfitrião e a porta através da XrRemotingConnectInfoMSFT estrutura. A porta utilizada pelo Jogador Holográfico de Remoting é 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);

A escuta de ligações recebidas na aplicação remota pode ser feita ligando para o xrRemotingListenMSFT método. Tanto o porto de aperto de mão como o porto de transporte podem ser especificados através da XrRemotingListenInfoMSFT estrutura. A porta de aperto de mão é utilizada para o aperto de mão inicial. Os dados são então enviados para o porto de transporte. Por defeito, são utilizados 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);

O estado de ligação deve ser desligado quando xrRemotingConnectMSFT telefonar ou xrRemotingListenMSFT . . Pode obter o estado de ligação em qualquer ponto depois de ter criado um XrInstance e consultado para o XrSystemId via xrRemotingGetConnectionStateMSFT .

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

Os estados de ligação disponíveis são:

  • XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTING_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT

Importante

xrRemotingConnectMSFT ou xrRemotingListenMSFT deve ser chamado antes de tentar criar uma XrSession via xrCreateSssion. Se tentar criar uma XrSession enquanto o estado de ligação é XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT a criação da sessão será bem sucedida, mas o estado da sessão passará imediatamente para XR_SESSION_STATE_LOSS_PENDING.

A implementação de suportes holográficos à espera de xrCreateSession uma ligação a ser estabelecida. Pode ligar xrRemotingConnectMSFT ou imediatamente ser seguido por uma xrRemotingListenMSFT chamada, que bloqueará e aguardará a criação de uma ligação. O tempo limite é fixado a 10 segundos. Se uma ligação puder ser estabelecida dentro deste tempo, a criação de XrSession terá sucesso e o estado da sessão transitará para XR_SESSION_STATE_READY. Caso não seja possível estabelecer qualquer ligação, a criação da sessão também tem sucesso, mas transita imediatamente para XR_SESSION_STATE_LOSS_PENDING.

Em geral, o estado de ligação é acoplador ao estado XrSession. Qualquer alteração ao estado de ligação também afeta o estado da sessão. Por exemplo, se o estado de ligação mudar de para o estado da XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFTXR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT sessão também passará para XR_SESSION_STATE_LOSS_PENDING.

Manipulação de eventos específicos de Remoting

O tempo de funcionação holográfico do Remoting OpenXR expõe três eventos, que são importantes para monitorizar o estado de uma ligação.

  1. XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: Acionado quando uma ligação ao dispositivo foi estabelecida com sucesso.
  2. XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: Acionado se uma ligação estabelecida estiver fechada ou se não for estabelecida uma ligação.
  3. XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT: Quando se ouve as ligações recebidas, começa a ouvir as ligações recebidas.

Estes eventos são colocados numa fila e a sua aplicação remota deve ler a partir da fila com regularidade 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;
	}
}

Pré-visualização de conteúdo transmitido localmente

Para exibir o mesmo conteúdo na aplicação remota que é enviada para o XR_MSFT_holographic_remoting_frame_mirroring dispositivo, a extensão pode ser utilizada. Com esta extensão, pode submeter uma textura ao XrEndFrame utilizando o XrRemotingFrameMirrorImageInfoMSFT que não está acorrentado ao XrFrameEndInfo da seguinte forma.

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

O exemplo acima utiliza uma textura de cadeia de troca DX11 e apresenta a janela imediatamente após a chamada para xrEndFrame. O uso não se restringe à troca de texturas em cadeia. Além disso, não é necessária uma sincronização adicional da GPU. Para obter informações sobre a utilização e as restrições, consulte a especificação de extensão. Se a sua aplicação remota estiver a utilizar o DX12, utilize o XrRemotingFrameMirrorImageD3D12MSFT em vez de XrRemotingFrameMirrorImageD3D11MSFT.

Opcional: Canais de dados personalizados

A partir da versão 2.5.0,os canais de dados personalizados podem ser utilizados com a API OpenXR para enviar dados do utilizador sobre a ligação de remoagem já estabelecida. Para obter mais informações, consulte os Canais de Dados Personalizados com a API OpenXR.

Opcional: Discurso

A partir da versão 2.6.0, a extensão permite que a aplicação remota reaja aos comandos de fala detetados pela aplicação do jogador com a API OpenXR.

[! IMPORTANTE] A especificação detalhada pode ser encontrada no repositório de remoing holográfico github.

Para inicializar um reconhecimento de discurso na aplicação do jogador, a aplicação remota pode ligar xrInitializeRemotingSpeechMSFT . Esta chamada transmite parâmetros de inicialização da fala, que consistem numa linguagem, num dicionário de frases, e no conteúdo de um ficheiro gramatical, para a aplicação do jogador.

Nota

Antes da versão 2.6.1, o reconhecimento de discursos só deve ser inicializado uma vez por .

Se a criação do reconhecimento de discursos tiver sido bem sucedida, como indicado pelo XR_TYPE_EVENT_DATA_REMOTING_SPEECH_RECOGNIZER_STATE_CHANGED_MSFT evento, a aplicação remota será notificada quando um resultado de reconhecimento de voz foi gerado na aplicação do jogador. A XrEventDataRemotingSpeechRecognizerStateChangedMSFT estrutura do evento é colocada na fila do evento quando o estado do reconhecimento do discurso no lado do jogador muda.

XrRemotingSpeechRecognizerStateMSFT define todos os estados possíveis do reconhecimento do discurso no lado do jogador e a estrutura do XrEventDataRemotingSpeechRecognizedMSFT evento é colocada na fila do evento se o reconhecimento de discurso no lado do jogador tiver uma frase reconhecida. Depois de a aplicação remota ser notificada sobre uma frase reconhecida, pode recuperar a frase reconhecida xrRetrieveRemotingSpeechRecognizedTextMSFT chamando.

Nota

É XrRemotingSpeechRecognitionConfidenceMSFT um mapeamento direto do XrRemotingSpeechRecognitionConfidenceMSFT enum devolvido com o resultado do reconhecimento da fala pela API de Reconhecimento de Voz Windows.

Opcional: Coordenar a Sincronização do Sistema

A partir da versão 2.7.0,a sincronização do sistema de coordenadas pode ser utilizada para alinhar dados espaciais entre o jogador e a aplicação remota. Para obter mais informações, consulte a Sincronização do Sistema de Coordenadas com a Visão Geral de Remoting Holográfica.

Consulte também