How to initialize WinRT AudioGraphSettings using WRL ComPtr?

318 views Asked by At

With C++/WinRT the AudioGraphSettings can be easily initialized with its constructor:

AudioGraphSettings settings(AudioRenderCategory::Media);

I'm having trouble to use it inside my WRL project. Below is my implementation

ComPtr<IAudioGraphSettings> settings;
Windows::Foundation::GetActivationFactory(
    HStringReference(RuntimeClass_Windows_Media_Audio_AudioGraphSettings).Get(),
    &settings
);

The settings still null and I don't know how to initialize it with the required AudioRenderCategory constructor.

If I do it like below, I got access violation crash because it's still null.

settings->put_AudioRenderCategory(AudioRenderCategory::AudioRenderCategory_Media);
1

There are 1 answers

0
IInspectable On BEST ANSWER

Type activation at the ABI level is more involved than, for example, instantiating types in C++. The admittedly terse documentation outlines the different mechanisms:

WinRT defines three activation mechanisms: direct activation (with no constructor parameters), factory activation (with one or more constructor parameters), and composition activation.

The IAudioGraphSettings type falls into the second category: It instantiates a type based on a single argument of type AudioRenderCategory. Instantiating a type is thus a two-phase process:

  1. Retrieve an activation factory
  2. Use the activation factory to instantiate a type

The code in the question conflates both operations, and the call to GetActivationFactory returns an HRESULT value of 0x80004002, i.e. E_NOINTERFACE. It needs to request the IAudioGraphSettingsFactory interface instead, and subsequently use that factory to instantiate the IAudioGraphSettings type.

The following is a complete implementation that illustrates how to activate an IAudioGraphSettings type:

#include <wrl/wrappers/corewrappers.h>
#include <wrl/client.h>

#include <windows.foundation.h>
#include <windows.media.audio.h>
#include <windows.media.render.h>

#pragma comment(lib, "windowsapp")

using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Media::Audio;
using namespace ABI::Windows::Media::Render;

int main()
{
    RoInitializeWrapper init { RO_INIT_MULTITHREADED };
    HRESULT hr { init };
    if (FAILED(hr))
        return hr;

    // Retrieve activation factory
     ComPtr<IAudioGraphSettingsFactory> settings_factory {};
     hr = GetActivationFactory(
         HStringReference(RuntimeClass_Windows_Media_Audio_AudioGraphSettings).Get(),
         &settings_factory);
     if (FAILED(hr))
         return hr;

     // Use activation factory to instantiate type
     ComPtr<IAudioGraphSettings> settings {};
     hr = settings_factory->Create(AudioRenderCategory_Media, &settings);
     if (FAILED(hr))
         return hr;

    return hr;
}

This is how things look at the ABI level, which is ultimately where the WRL lives. C++/WinRT takes care of all the boilerplate code, and neatly maps parameterized factory activation onto C++ constructor implementations. That's why the C++/WinRT implementation is so much more compact.