Delen via


Een Holographic Remoting Remote-app schrijven met behulp van de HolographicSpace-API

Als u geen gebruik hebt van Holographic Remoting, kunt u ons overzicht lezen.

Belangrijk

In dit document wordt beschreven hoe u een externe toepassing maakt voor HoloLens 2 met behulp van de HolographicSpace-API. Externe toepassingen voor HoloLens (1e generatie) moeten NuGet-pakketversie 1.x.x gebruiken. Dit betekent dat externe toepassingen die zijn geschreven voor HoloLens 2 niet compatibel zijn met HoloLens 1 en vice versa. De documentatie voor HoloLens 1 vindt u hier.

Kennisgeving over afschaffing: de releaseregel 2.9.x is de laatste die Ondersteuning biedt voor Windows Holographic API's voor het ontwikkelen van toepassingen. Toekomstige versies ondersteunen alleen OpenXR voor het ontwikkelen van toepassingen. Onafhankelijk van dat raden we het gebruik van OpenXR in uw toepassing aan voor alle nieuwe toepassingsontwikkeling. Bestaande toepassingen die 2.9 of ouder gebruiken, blijven werken zonder dat dit wordt beïnvloed door toekomstige wijzigingen.

Holografische externe apps kunnen extern weergegeven inhoud streamen naar HoloLens 2 en Windows Mixed Reality immersive headsets. U kunt ook toegang krijgen tot meer systeembronnen en externe insluitende weergaven integreren in bestaande desktop-pc-software. Een externe app ontvangt een invoergegevensstroom van HoloLens 2, geeft inhoud weer in een virtuele insluitende weergave en streamt inhoudsframes terug naar HoloLens 2. De verbinding wordt gemaakt met behulp van standaard Wi-Fi. Holografische externe communicatie wordt toegevoegd aan een desktop- of UWP-app via een NuGet-pakket. Er is aanvullende code vereist waarmee de verbinding wordt verwerkt en in een insluitende weergave wordt weergegeven. Een typische externe verbinding heeft een lage latentie van wel 50 ms. De speler-app kan de latentie in realtime rapporteren.

Alle code op deze pagina en werkprojecten zijn te vinden in de GitHub-opslagplaats holographic Remoting-voorbeelden.

Vereisten

Een goed uitgangspunt is een werkende desktop- of UWP-app op basis van DirectX die is gericht op de Windows Mixed Reality API. Zie Overzicht van DirectX-ontwikkeling voor meer informatie. De holografische C++-projectsjabloon is een goed uitgangspunt.

Belangrijk

Elke app die gebruikmaakt van Holographic Remoting moet worden geschreven voor het gebruik van een appartement met meerdere threads. Het gebruik van een appartement met één schroefdraad wordt ondersteund, maar leidt tot suboptimale prestaties en mogelijk haperingen tijdens het afspelen. Wanneer u C++/WinRT winrt::init_apartment is een appartement met meerdere threads de standaardinstelling.

Download het Holographic Remoting NuGet-pakket

De volgende stappen zijn vereist om het NuGet-pakket toe te voegen aan een project in Visual Studio.

  1. Open het project in Visual Studio.
  2. Klik met de rechtermuisknop op het projectknooppunt en selecteer NuGet-pakketten beheren...
  3. Selecteer bladeren in het deelvenster dat wordt weergegeven en zoek vervolgens naar 'Holographic Remoting'.
  4. Selecteer Microsoft.Holographic.Remoting, zorg ervoor dat u de nieuwste versie 2.x.x kiest en selecteer Installeren.
  5. Als het dialoogvenster Voorbeeld wordt weergegeven, selecteert u OK.
  6. Selecteer Ik ga akkoord wanneer het dialoogvenster met de licentieovereenkomst wordt weergegeven.

Notitie

Versie 1.x.x van het NuGet-pakket is nog steeds beschikbaar voor ontwikkelaars die holoLens 1 willen targeten. Zie HoloOgraphic Remoting (HoloLens (1e generatie) toevoegen voor meer informatie.

De externe context maken

Als eerste stap moet de toepassing een externe context maken.

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

Waarschuwing

Holographic Remoting werkt door de Windows Mixed Reality runtime die deel uitmaakt van Windows te vervangen door een specifieke runtime voor externe communicatie. Dit wordt gedaan tijdens het maken van de externe context. Daarom kan elke aanroep op een Windows Mixed Reality-API voordat de externe context wordt gemaakt, leiden tot onverwacht gedrag. De aanbevolen aanpak is om de externe context zo vroeg mogelijk te maken vóór interactie met een Mixed Reality API. Meng nooit objecten die zijn gemaakt of opgehaald via een Windows Mixed Reality API vóór de aanroep van CreateRemoteContext met objecten die later zijn gemaakt of opgehaald.

Vervolgens moet de holografische ruimte worden gemaakt. Het opgeven van een CoreWindow is niet vereist. Bureaublad-apps die geen CoreWindow hebben, kunnen gewoon een nullptrdoorgeven.

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

Verbinding maken met het apparaat

Wanneer de externe app gereed is voor het weergeven van inhoud, kan er een verbinding met het spelerapparaat tot stand worden gebracht.

U kunt op twee manieren verbinding maken.

  1. De externe app maakt verbinding met de speler die op het apparaat wordt uitgevoerd.
  2. De speler die op het apparaat wordt uitgevoerd, maakt verbinding met de externe app.

Als u een verbinding tot stand wilt brengen tussen de externe app en het spelerapparaat, roept u de Connect methode aan in de externe context en geeft u de hostnaam en poort op. De poort die wordt gebruikt door de 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());
}

Belangrijk

Net als bij elke C++/WinRT-API Connect kan een winrt::hresult_error genereren die moet worden verwerkt.

Tip

Om het gebruik van C++/WinRT-taalprojectie te voorkomen, kan het bestand build\native\include\<windows sdk version>\abi\Microsoft.Holographic.AppRemoting.h in het Holographic Remoting NuGet-pakket worden opgenomen. Het bevat declaraties van de onderliggende COM-interfaces. Het gebruik van C++/WinRT wordt echter aanbevolen.

Luisteren naar binnenkomende verbindingen in de externe app kan worden uitgevoerd door de Listen methode aan te roepen. Zowel de handshakepoort als de transportpoort kunnen tijdens deze aanroep worden opgegeven. De handshakepoort wordt gebruikt voor de eerste handshake. De gegevens worden vervolgens verzonden via de transportpoort. Standaard worden 8265 en 8266 gebruikt.

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

Belangrijk

De build\native\include\HolographicAppRemoting\Microsoft.Holographic.AppRemoting.idl in het NuGet-pakket bevat gedetailleerde documentatie voor de API die wordt weergegeven door Holographic Remoting.

Afhandeling van specifieke gebeurtenissen voor externe communicatie

In de externe context worden drie gebeurtenissen weergegeven, die belangrijk zijn voor het bewaken van de status van een verbinding.

  1. OnConnected: wordt geactiveerd wanneer een verbinding met het apparaat tot stand is gebracht.
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: wordt geactiveerd als een tot stand gebrachte verbinding is gesloten of als er geen verbinding tot stand kan worden gebracht.
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: wanneer het luisteren naar binnenkomende verbindingen wordt gestart.
m_onListeningEventRevoker = m_remoteContext.OnListening(winrt::auto_revoke, [this, remoteContextWeakRef]() {
    if (auto remoteContext = remoteContextWeakRef.get())
    {
        // Update UI state
    }
});

Daarnaast kan de verbindingsstatus worden opgevraagd met behulp van de ConnectionState eigenschap in de externe context.

auto connectionState = m_remoteContext.ConnectionState();

Spraakevenementen verwerken

Met behulp van de externe spraakinterface is het mogelijk om spraaktriggers te registreren met HoloLens 2 en deze op afstand naar de externe toepassing te laten uitvoeren.

Het volgende extra lid is vereist om de status van de externe spraak bij te houden:

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

Haal eerst de externe spraakinterface op.

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

Met behulp van een asynchrone helpermethode kunt u vervolgens de externe spraak initialiseren. Dit moet asynchroon worden gedaan, omdat initialisatie veel tijd kan kosten. Gelijktijdigheid en asynchrone bewerkingen met C++/WinRT legt uit hoe u asynchrone functies kunt maken met 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);
}

Er zijn twee manieren om zinnen op te geven die moeten worden herkend.

  1. Specificatie in een XML-bestand met spraak grammatica. Zie How to create a basic XML Grammar (Een eenvoudige XML-grammatica maken) voor meer informatie.
  2. Geef op door ze in de woordenlijstvector door te geven aan ApplyParameters.

In de callback OnRecognizedSpeech kunnen de spraakgebeurtenissen vervolgens worden verwerkt:

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")
    {
        ...
    }

    ...
}

Lokaal gestreamde inhoud bekijken

Als u dezelfde inhoud wilt weergeven in de externe app die naar het apparaat wordt verzonden, kan de OnSendFrame gebeurtenis van de externe context worden gebruikt. De OnSendFrame gebeurtenis wordt geactiveerd telkens wanneer de Holographic Remoting-bibliotheek het huidige frame naar het externe apparaat verzendt. Dit is het ideale moment om de inhoud te nemen en ook in het bureaublad- of UWP-venster te snijden.

#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.
    });

Diepteherprojectie

Vanaf versie 2.1.0 ondersteunt Holographic Remoting Diepteherprojectie. Hiervoor moeten zowel de kleurbuffer als de dieptebuffer worden gestreamd van de externe toepassing naar de HoloLens 2. Dieptebufferstreaming is standaard ingeschakeld en geconfigureerd om de helft van de resolutie van de kleurbuffer te gebruiken. Dit kan als volgt worden gewijzigd:

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

...

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

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

Als standaardwaarden niet moeten worden gebruiktConfigureDepthVideoStream, moet u aangeroepen worden voordat er een verbinding met de HoloLens 2 tot stand wordt gebracht. De beste plaats is direct nadat u de externe context hebt gemaakt. Mogelijke waarden voor DepthBufferStreamResolution zijn:

  • Full_Resolution
  • Half_Resolution
  • Quarter_Resolution
  • Uitgeschakeld (toegevoegd met versie 2.1.3 en bij gebruik wordt er geen extra dieptevideostream gemaakt)

Houd er rekening mee dat het gebruik van een dieptebuffer voor volledige resolutie ook van invloed is op de bandbreedtevereisten en moet worden meegenomen in de maximale bandbreedtewaarde die u opgeeft aan CreateRemoteContext.

Naast het configureren van de resolutie moet u ook een dieptebuffer doorvoeren 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);
                }
            });
        }
    });
}

Als u wilt controleren of diepteherprojectie correct werkt op HoloLens 2, kunt u een diepte visualiseren via de apparaatportal. Zie Controleren of diepte juist is ingesteld voor meer informatie.

Optioneel: Aangepaste gegevenskanalen

Aangepaste gegevenskanalen kunnen worden gebruikt om gebruikersgegevens te verzenden via de reeds tot stand gebrachte externe verbinding. Zie Aangepaste gegevenskanalen voor meer informatie.

Optioneel: Systeemsynchronisatie coördineren

Vanaf versie 2.7.0 kan systeemsynchronisatie coördineren worden gebruikt om ruimtelijke gegevens uit te lijnen tussen de speler en de externe toepassing. Zie Systeemsynchronisatie coördineren met Holographic Remoting Overview (Overzicht van externe communicatie met Holographic) voor meer informatie.

Zie ook