Écriture d’une application distante holographique à distance à l’aide de l’API HolographicSpaceWriting a Holographic Remoting remote app using the HolographicSpace API

Important

Ce document décrit la création d’une application distante pour HoloLens 2 à l’aide de l' API HolographicSpace.This document describes the creation of a remote application for HoloLens 2 using the HolographicSpace API. Les applications distantes pour HoloLens (1re génération) doivent utiliser le package NuGet version 1. x. x.Remote applications for HoloLens (1st gen) must use NuGet package version 1.x.x. Cela implique que les applications distantes écrites pour HoloLens 2 ne sont pas compatibles avec HoloLens 1 et vice versa.This implies that remote applications written for HoloLens 2 are not compatible with HoloLens 1 and vice versa. La documentation de HoloLens 1 est disponible ici.The documentation for HoloLens 1 can be found here.

Les applications de communication à distance holographique peuvent diffuser du contenu diffusé à distance sur des casques immersifs HoloLens 2 et Windows Mixed Reality.Holographic Remoting apps can stream remotely rendered content to HoloLens 2 and Windows Mixed Reality immersive headsets. Vous pouvez également accéder à davantage de ressources système et intégrer des vues immersives distantes dans des logiciels de poste de travail existants.You can also access more system resources and integrate remote immersive views into existing desktop PC software. Une application distante reçoit un flux de données d’entrée de HoloLens 2, restitue le contenu dans une vue immersive virtuelle et diffuse en continu des frames de contenu vers 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 connexion est établie à l’aide du Wi-Fi standard.The connection is made using standard Wi-Fi. La communication à distance holographique est ajoutée à une application de bureau ou UWP via un paquet NuGet.Holographic Remoting is added to a desktop or UWP app via a NuGet packet. Du code supplémentaire est nécessaire pour gérer la connexion et le rendu dans une vue immersive.Additional code is required which handles the connection and renders in an immersive view. Une connexion à distance classique aura une latence aussi faible que 50 ms de latence.A typical remoting connection will have as low as 50 ms of latency. L’application de lecteur peut signaler la latence en temps réel.The player app can report the latency in real time.

Tout le code de cette page et des projets de travail se trouve dans le référentiel GitHub d’exemples de communication à distance holographique.All code on this page and working projects can be found in the Holographic Remoting samples github repository.

PrérequisPrerequisites

Un bon point de départ est un bureau DirectX opérationnel ou une application UWP qui cible l' API HolographicSpace.A good starting point is a working DirectX based Desktop or UWP app, which targets the HolographicSpace API. Pour plus d’informations, consultez vue d’ensemble du développement DirectX.For details see DirectX development overview. Le modèle de projet holographique C++ est un bon point de départ.The C++ holographic project template is a good starting point.

Important

Toute application utilisant la communication à distance holographique doit être créée pour utiliser un cloisonnementmultithread.Any app using Holographic Remoting should be authored to use a multi-threaded apartment. L’utilisation d’un cloisonnement à thread unique est prise en charge, mais entraîne des performances non optimales et éventuellement des interruptions pendant la lecture.The use of a single-threaded apartment is supported but will lead to sub-optimal performance and possibly stuttering during playback. Lors de l’utilisation de C++/WinRT WinRT :: init_apartment un cloisonnement multithread est la valeur par défaut.When using C++/WinRT winrt::init_apartment a multi-threaded apartment is the default.

Procurez-vous le package NuGet de communication à distance holographiqueGet the Holographic Remoting NuGet package

Les étapes suivantes sont requises pour ajouter le package NuGet à un projet dans Visual Studio.The following steps are required to add the NuGet package to a project in Visual Studio.

  1. Ouvrez le projet dans Visual Studio.Open the project in Visual Studio.
  2. Cliquez avec le bouton droit sur le nœud du projet et sélectionnez gérer les packages NuGet...Right-click the project node and select Manage NuGet Packages...
  3. Dans le volet qui s’affiche, sélectionnez Parcourir , puis recherchez « accès à distance holographique ».In the panel that appears, select Browse and then search for "Holographic Remoting".
  4. Sélectionnez Microsoft. holographique. Remoting, assurez-vous de choisir la version la plus récente de 2. x. x , puis sélectionnez installer.Select Microsoft.Holographic.Remoting, ensure to pick the latest 2.x.x version and select Install.
  5. Si la boîte de dialogue Aperçu s’affiche, sélectionnez OK.If the Preview dialog appears, select OK.
  6. Sélectionnez J’accepte quand la boîte de dialogue du contrat de licence s’affiche.Select I Accept when the license agreement dialog pops up.

Notes

La version 1. x. x du package NuGet est toujours disponible pour les développeurs qui souhaitent cibler HoloLens 1.Version 1.x.x of the NuGet package is still available for developers who want to target HoloLens 1. Pour plus d’informations , consultez Ajouter une communication à distance holographique (HoloLens (1re génération)).For details see Add Holographic Remoting (HoloLens (1st gen)).

Créer le contexte distantCreate the remote context

En guise de première étape, l’application doit créer un contexte distant.As a first step the application should create a remote context.

// class declaration
#include <winrt/Microsoft.Holographic.AppRemoting.h>

...

private:
    // RemoteContext used to connect with a Holographic Remoting player and display rendered frames
    winrt::Microsoft::Holographic::AppRemoting::RemoteContext m_remoteContext = nullptr;
// class implementation
#include <HolographicAppRemoting\Streamer.h>

...

CreateRemoteContext(m_remoteContext, 20000, false, PreferredVideoCodec::Default);

Avertissement

La communication à distance holographique fonctionne en remplaçant le runtime Windows Mixed Reality qui fait partie de Windows par un Runtime spécifique à distance.Holographic Remoting works by replacing the Windows Mixed Reality runtime which is part of Windows with a remoting specific runtime. Cette opération est effectuée lors de la création du contexte distant.This is done during the creation of the remote context. Pour cette raison, tout appel sur une API de réalité mixte Windows avant de créer le contexte distant peut entraîner un comportement inattendu.For that reason any call on any Windows Mixed Reality API before creating the remote context can result in unexpected behavior. L’approche recommandée consiste à créer le contexte distant le plus tôt possible avant d’interagir avec une API de réalité mixte.The recommended approach is to create the remote context as early as possible before interaction with any Mixed Reality API. Ne combinez jamais des objets créés ou récupérés par le biais d’une API Windows Mixed Reality avant l’appel à CreateRemoteContext avec des objets créés ou récupérés par la suite.Never mix objects created or retrieved through any Windows Mixed Reality API before the call to CreateRemoteContext with objects created or retrieved afterwards.

L’espace holographique doit ensuite être créé.Next the holographic space needs to be created. La spécification d’un CoreWindow n’est pas obligatoire.Specifying a CoreWindow isn't required. Les applications de bureau qui n’ont pas de CoreWindow peuvent simplement passer un nullptr .Desktop apps that don't have a CoreWindow can just pass a nullptr.

m_holographicSpace = winrt::Windows::Graphics::Holographic::HolographicSpace::CreateForCoreWindow(nullptr);

Se connecter à l’appareilConnect to the device

Lorsque l’application distante est prête pour le rendu du contenu, une connexion à l’appareil Player peut être établie.When the remote app is ready for rendering content a connection to the player device can be established.

La connexion peut être effectuée de deux manières.Connection can be done in one of two ways.

  1. L’application distante se connecte au lecteur qui s’exécute sur l’appareil.The remote app connects to the player running on the device.
  2. Le lecteur s’exécutant sur l’appareil se connecte à l’application distante.The player running on the device connects to the remote app.

Pour établir une connexion de l’application distante à l’appareil Player Connect , appelez la méthode sur le contexte distant en spécifiant le nom d’hôte et le port.To establish a connection from the remote app to the player device call the Connect method on the remote context specifying the hostname and port. Le port utilisé par le lecteur de communication à distance holographique est 8265.The port used by the Holographic Remoting Player is 8265.

try
{
    m_remoteContext.Connect(m_hostname, m_port);
}
catch(winrt::hresult_error& e)
{
    DebugLog(L"Connect failed with hr = 0x%08X", e.code());
}

Important

Comme pour toute API/WinRT C++ Connect peut lever une exception WinRT :: hresult_error qui doit être gérée.As with any C++/WinRT API Connect might throw an winrt::hresult_error which needs to be handled.

Conseil

Pour éviter d’utiliser la projection du langage C++/WinRT build\native\include\<windows sdk version>\abi\Microsoft.Holographic.AppRemoting.h , vous pouvez inclure le fichier situé dans le package NuGet de communication à distance holographique.To avoid using C++/WinRT language projection the file build\native\include\<windows sdk version>\abi\Microsoft.Holographic.AppRemoting.h located inside the Holographic Remoting NuGet package can be included. Il contient les déclarations des interfaces COM sous-jacentes.It contains declarations of the underlying COM interfaces. L’utilisation de C++/WinRT est toutefois recommandée.The use of C++/WinRT is recommended though.

L’écoute des connexions entrantes sur l’application distante peut être effectuée en appelant la Listen méthode.Listening for incoming connections on the remote app can be done by calling the Listen method. Le port de liaison et le port de transport peuvent être spécifiés au cours de cet appel.Both the handshake port and transport port can be specified during this call. Le port de négociation est utilisé pour le protocole de transfert initial.The handshake port is used for the initial handshake. Les données sont ensuite envoyées sur le port de transport.The data is then sent over the transport port. Par défaut, 8265 et 8266 sont utilisés.By default 8265 and 8266 are used.

try
{
    m_remoteContext.Listen(L"0.0.0.0", m_port, m_port + 1);
}
catch(winrt::hresult_error& e)
{
    DebugLog(L"Listen failed with hr = 0x%08X", e.code());
}

Important

L' build\native\include\HolographicAppRemoting\Microsoft.Holographic.AppRemoting.idl intérieur du package NuGet contient une documentation détaillée sur l’API exposée par la communication à distance holographique.The build\native\include\HolographicAppRemoting\Microsoft.Holographic.AppRemoting.idl inside the NuGet package contains detailed documentation for the API exposed by Holographic Remoting.

Gestion des événements de communication à distance spécifiquesHandling Remoting specific events

Le contexte distant expose trois événements, qui sont importants pour surveiller l’état d’une connexion.The remote context exposes three events, which are important to monitor the state of a connection.

  1. OnConnected : déclenché lorsqu’une connexion à l’appareil a été établie avec succès.OnConnected: Triggered when a connection to the device has been successfully established.
winrt::weak_ref<winrt::Microsoft::Holographic::AppRemoting::IRemoteContext> remoteContextWeakRef = m_remoteContext;

m_onConnectedEventRevoker = m_remoteContext.OnConnected(winrt::auto_revoke, [this, remoteContextWeakRef]() {
    if (auto remoteContext = remoteContextWeakRef.get())
    {
        // Update UI state
    }
});
  1. OnDisconnected : déclenché si une connexion établie est fermée ou si une connexion n’a pas pu être établie.OnDisconnected: Triggered if an established connection is closed or a connection couldn't be established.
m_onDisconnectedEventRevoker =
    m_remoteContext.OnDisconnected(winrt::auto_revoke, [this, remoteContextWeakRef](ConnectionFailureReason failureReason) {
        if (auto remoteContext = remoteContextWeakRef.get())
        {
            DebugLog(L"Disconnected with reason %d", failureReason);
            // Update UI

            // Reconnect if this is a transient failure.
            if (failureReason == ConnectionFailureReason::HandshakeUnreachable ||
                failureReason == ConnectionFailureReason::TransportUnreachable ||
                failureReason == ConnectionFailureReason::ConnectionLost)
            {
                DebugLog(L"Reconnecting...");

                ConnectOrListen();
            }
            // Failure reason None indicates a normal disconnect.
            else if (failureReason != ConnectionFailureReason::None)
            {
                DebugLog(L"Disconnected with unrecoverable error, not attempting to reconnect.");
            }
        }
    });
  1. OnListening : lors du démarrage de l’écoute des connexions entrantes.OnListening: When listening for incoming connections starts.
m_onListeningEventRevoker = m_remoteContext.OnListening(winrt::auto_revoke, [this, remoteContextWeakRef]() {
    if (auto remoteContext = remoteContextWeakRef.get())
    {
        // Update UI state
    }
});

En outre, l’état de la connexion peut être interrogé à l’aide de la ConnectionState propriété sur le contexte distant.Additionally the connection state can be queried using the ConnectionState property on the remote context.

auto connectionState = m_remoteContext.ConnectionState();

Gestion des événements vocauxHandling speech events

À l’aide de l’interface de reconnaissance vocale à distance, il est possible d’inscrire les déclencheurs vocaux avec HoloLens 2 et de les faire distants à l’application distante.Using the remote speech interface it's possible to register speech triggers with HoloLens 2 and have them remoted to the remote application.

Ce membre supplémentaire est requis pour effectuer le suivi de l’état de la voix à distance.This additional member is required to track the state of the remote speech.

winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker m_onRecognizedSpeechRevoker;

Tout d’abord, l’interface de reconnaissance vocale à distance doit être récupérée.First the remote speech interface needs to be retrieved.

if (auto remoteSpeech = m_remoteContext.GetRemoteSpeech())
{
    InitializeSpeechAsync(remoteSpeech, m_onRecognizedSpeechRevoker, weak_from_this());
}

À l’aide d’une méthode d’assistance asynchrone, vous pouvez initialiser la reconnaissance vocale à distance.Using an asynchronous helper method you can then initialize the remote speech. Cette opération doit être effectuée de façon asynchrone, car l’initialisation peut prendre beaucoup de temps.This should be done asynchronously as initializing might take a considerable amount of time. Opérations d’accès concurrentiel et asynchrones avec c++/WinRT explique comment créer des fonctions asynchrones avec c++/WinRT.Concurrency and asynchronous operations with C++/WinRT explains how to author asynchronous functions with C++/WinRT.

winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> LoadGrammarFileAsync()
{
    const wchar_t* speechGrammarFile = L"SpeechGrammar.xml";
    auto rootFolder = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation();
    return rootFolder.GetFileAsync(speechGrammarFile);
}

winrt::fire_and_forget InitializeSpeechAsync(
    winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech remoteSpeech,
    winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker& onRecognizedSpeechRevoker,
    std::weak_ptr<SampleRemoteMain> sampleRemoteMainWeak)
{
    onRecognizedSpeechRevoker = remoteSpeech.OnRecognizedSpeech(
        winrt::auto_revoke, [sampleRemoteMainWeak](const winrt::Microsoft::Holographic::AppRemoting::RecognizedSpeech& recognizedSpeech) {
            if (auto sampleRemoteMain = sampleRemoteMainWeak.lock())
            {
                sampleRemoteMain->OnRecognizedSpeech(recognizedSpeech.RecognizedText);
            }
        });

    auto grammarFile = co_await LoadGrammarFileAsync();

    std::vector<winrt::hstring> dictionary;
    dictionary.push_back(L"Red");
    dictionary.push_back(L"Blue");
    dictionary.push_back(L"Green");
    dictionary.push_back(L"Default");
    dictionary.push_back(L"Aquamarine");

    remoteSpeech.ApplyParameters(L"", grammarFile, dictionary);
}

Il existe deux façons de spécifier des expressions à reconnaître.There are two ways of specifying phrases to be recognized.

  1. Spécification à l’intérieur d’un fichier XML de grammaire vocale.Specification inside a speech grammar xml file. Pour plus d’informations, consultez comment créer une grammaire XML de base .See How to create a basic XML Grammar for details.
  2. Spécifiez en les passant dans le vecteur du dictionnaire à ApplyParameters .Specify by passing them inside the dictionary vector to ApplyParameters.

À l’intérieur du rappel OnRecognizedSpeech, les événements vocaux peuvent ensuite être traités :Inside the OnRecognizedSpeech callback, the speech events can then be processed:

void SampleRemoteMain::OnRecognizedSpeech(const winrt::hstring& recognizedText)
{
    bool changedColor = false;
    DirectX::XMFLOAT4 color = {1, 1, 1, 1};

    if (recognizedText == L"Red")
    {
        color = {1, 0, 0, 1};
        changedColor = true;
    }
    else if (recognizedText == L"Blue")
    {
        color = {0, 0, 1, 1};
        changedColor = true;
    }
    else if (recognizedText == L"Green")
    {
        ...
    }

    ...
}

Afficher un aperçu du contenu diffusé en continu localementPreview streamed content locally

Pour afficher le même contenu dans l’application distante qui est envoyé à l’appareil, l' OnSendFrame événement du contexte distant peut être utilisé.To display the same content in the remote app that is sent to the device the OnSendFrame event of the remote context can be used. L' OnSendFrame événement est déclenché chaque fois que la bibliothèque de communication à distance holographique envoie le frame actuel au périphérique distant.The OnSendFrame event is triggered every time the Holographic Remoting library sends the current frame to the remote device. C’est le moment idéal pour prendre le contenu et le configurer dans la fenêtre du bureau ou UWP.This is the ideal time to take the content and also blit it into the desktop or UWP window.

#include <windows.graphics.directx.direct3d11.interop.h>

...

m_onSendFrameEventRevoker = m_remoteContext.OnSendFrame(
    winrt::auto_revoke, [this](const winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface& texture) {
        winrt::com_ptr<ID3D11Texture2D> texturePtr;
        {
            winrt::com_ptr<ID3D11Resource> resource;
            winrt::com_ptr<::IInspectable> inspectable = texture.as<::IInspectable>();
            winrt::com_ptr<Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess> dxgiInterfaceAccess;
            winrt::check_hresult(inspectable->QueryInterface(__uuidof(dxgiInterfaceAccess), dxgiInterfaceAccess.put_void()));
            winrt::check_hresult(dxgiInterfaceAccess->GetInterface(__uuidof(resource), resource.put_void()));
            resource.as(texturePtr);
        }

        // Copy / blit texturePtr into the back buffer here.
    });

Reprojection de profondeurDepth Reprojection

À partir de la version 2.1.0, la communication à distance holographique prend en charge la reprojection de profondeur.Starting with version 2.1.0, Holographic Remoting supports Depth Reprojection. Cela requiert que la mémoire tampon de couleur et la mémoire tampon de profondeur soient diffusées de l’application distante vers HoloLens 2.This requires both the color buffer and depth buffer to be streamed from the Remote application to the HoloLens 2. Par défaut, la diffusion en continu de la mémoire tampon est activée et configurée pour utiliser la moitié de la résolution de la mémoire tampon de couleur.By default depth buffer streaming is enabled and configured to use half the resolution of the color buffer. Vous pouvez modifier cette valeur comme suit :This can be changed as follows:

// class implementation
#include <HolographicAppRemoting\Streamer.h>

...

CreateRemoteContext(m_remoteContext, 20000, false, PreferredVideoCodec::Default);

// Configure for half-resolution depth.
m_remoteContext.ConfigureDepthVideoStream(DepthBufferStreamResolution::Half_Resolution);

Notez que, si les valeurs par défaut ne doivent pas être utilisées, ConfigureDepthVideoStream doivent être appelées avant d’établir une connexion à HoloLens 2.Note, if default values should not be used ConfigureDepthVideoStream must be called before establishing a connection to the HoloLens 2. Le meilleur emplacement est juste après avoir créé le contexte distant.The best place is right after you have created the remote context. Les valeurs possibles pour DepthBufferStreamResolution sont les suivantes :Possible values for DepthBufferStreamResolution are:

  • Full_ResolutionFull_Resolution
  • Half_ResolutionHalf_Resolution
  • Quarter_ResolutionQuarter_Resolution
  • Désactivé (ajouté avec la version 2.1.3 et, s’il n’est utilisé, aucun flux vidéo de profondeur supplémentaire n’est créé)Disabled (added with version 2.1.3 and if used no additional depth video stream is created)

Gardez à l’esprit que l’utilisation d’une mémoire tampon de profondeur de résolution complète affecte également les besoins en bande passante et doit être comptabilisée dans la valeur de bande passante maximale que vous fournissez à CreateRemoteContext .Keep in mind that using a full resolution depth buffer also affects bandwidth requirements and needs to be accounted for in the maximum bandwidth value you provide to CreateRemoteContext.

À côté de la configuration de la résolution, vous devez également valider un tampon de profondeur à l’aide de HolographicCameraRenderingParameters. CommitDirect3D11DepthBuffer.Beside configuring the resolution, you also have to commit a depth buffer via HolographicCameraRenderingParameters.CommitDirect3D11DepthBuffer.


void SampleRemoteMain::Render(HolographicFrame holographicFrame)
{
    ...

    m_deviceResources->UseHolographicCameraResources([this, holographicFrame](auto& cameraResourceMap) {
        
        ...

        for (auto cameraPose : prediction.CameraPoses())
        {
            DXHelper::CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get();

            ...

            m_deviceResources->UseD3DDeviceContext([&](ID3D11DeviceContext3* context) {
                
                ...

                // Commit depth buffer if available and enabled.
                if (m_canCommitDirect3D11DepthBuffer && m_commitDirect3D11DepthBuffer)
                {
                    auto interopSurface = pCameraResources->GetDepthStencilTextureInteropObject();
                    HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose);
                    renderingParameters.CommitDirect3D11DepthBuffer(interopSurface);
                }
            });
        }
    });
}

Pour vérifier si la reprojection de profondeur fonctionne correctement sur HoloLens 2, vous pouvez activer un visualiseur de profondeur via le portail de l’appareil.To verify if depth reprojection is correctly working on HoloLens 2, you can enable a depth visualizer via the Device Portal. Pour plus d’informations, voir vérification de la profondeur définie correctement .See Verifying Depth is Set Correctly for details.

Facultatif : canaux de données personnalisésOptional: Custom data channels

Les canaux de données personnalisés peuvent être utilisés pour envoyer des données utilisateur sur la connexion de communication à distance déjà établie.Custom data channels can be used to send user data over the already established remoting connection. Pour plus d’informations, consultez canaux de données personnalisés .See custom data channels for more information.

Voir aussiSee Also