Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Activating WRL Audio Interfaces in Native C++

4.71/5 (5 votes)
7 May 2014CPOL2 min read 15.8K  
Activating WRL audio interfaces in native C++

Introduction

This is a demonstration of how to wrap and convert the ActivateAudioInterfaceAsync, IActivateAudioInterfaceAsyncOperation, IActivateAudioInterfaceCompletionHandler programming patterns to a task object and use it.

Background

One should be familiar with C++, WRL, IDL and the MultiMedia (MM) device API.

Using the Code

The code is relatively short but care must be taken to keep a reference on the object and make certain the UI thread is used for the initial call as well as the operation completion call. An event object is used as a signal mechanism just as is done in the task library.

C++
#ifdef __cplusplus_winrt
namespace Concurrency
#else
namespace Concurrency_winrt
#endif
{
template<typename TCallback>
struct ActivateAudioInvokeHelper : 
    public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags
        <Microsoft::WRL::Delegate>, Microsoft::WRL::FtmBase>
{
    explicit ActivateAudioInvokeHelper(TCallback callback) throw() : callback_(callback)
    {
    }

    STDMETHOD(ActivateCompleted)(IActivateAudioInterfaceAsyncOperation *activateOperation)
    {
#if _MSC_VER >= 1800
        return Microsoft::WRL::DelegateTraits<Microsoft::WRL::DefaultDelegateCheckMode>::CheckReturn(
            callback_(activateOperation));
#else
        return callback_(activateOperation);
#endif
    }
    TCallback callback_;
};

template<typename>
Microsoft::WRL::ComPtr<IActivateAudioInterfaceCompletionHandler> ActivateAudioCallback(TCallback callback) throw()
{
    return Microsoft::WRL::Make<ActivateAudioInvokeHelper<TCallback>>(callback);
}

__declspec(noinline)
    auto create_audio_task(_In_ LPCWSTR deviceInterfacePath, _In_ REFIID riid,
    _In_opt_ PROPVARIANT *activationParams, IUnknown** activatedInterface) -> task<void>
{
        Microsoft::WRL::ComPtr<IActivateAudioInterfaceAsyncOperation> pOperation;
        std::shared_ptr<Concurrency::event> _completed = std::make_shared<Concurrency::event>();
        Microsoft::WRL::ComPtr<IActivateAudioInterfaceCompletionHandler> pHandler = ActivateAudioCallback(
            [activatedInterface, _completed](IActivateAudioInterfaceAsyncOperation *activateOperation) -> HRESULT {
            HRESULT innerhr;
            HRESULT hr = activateOperation->GetActivateResult(&innerhr, activatedInterface);
            if (FAILED(hr)) return hr;
            _completed->set();
            return innerhr;
        });
        HRESULT hr = ActivateAudioInterfaceAsync(deviceInterfacePath, riid,
            activationParams, pHandler.Get(), pOperation.GetAddressOf());
        if (FAILED(hr)) return task<void>();
        task<void> _CreatedTask = create_task DEFINE_RET_TYPE(void)(
            [_completed]()->DEFINE_RET_FORMAL(void) { _completed->wait(); RET_VAL_BASE });
        // Ideally we would like to forceinline create_task, 
        // but __forceinline does nothing on debug builds. Therefore, we ask for no inlining
        // and overwrite the creation address hint set by the task constructor. 
        // DO NOT REMOVE this next line from create_task. It is
        // essential that _ReturnAddress() evaluate to the instruction 
        // right after the call to create_task in client code.
#if _MSC_VER < 1800
        _CreatedTask._SetTaskCreationAddressHint(_ReturnAddress());
#else
        task_options _TaskOptions = task_options();
        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
#endif
        return _CreatedTask;
}
}
</void>

Using the code is as simple as calling create_audio_task to return a task object based on the arguments to ActivateAudioInterfaceAsync without the overhead of worrying about the operation parameter which is taken care of completely within the class.

Points of Interest

The programming pattern here is identical for C++/CX which also is deficient in terms of library handling for this interface.

This could be integrated directly into ppltasks.h or using custom native C++ ppltasks_winrt.h which can be found in a separate tip. However, given that this particular interface does not match the AsyncBase pattern, there is less motivation to think in terms of such a change.

Unlike with normal WRL event handler delegates, in this case FtmBase must be inherited from to bring in the IAgileObject interface, otherwise an error E_ILLEGAL_METHOD_CALL (0x8000000E) will be returned.

Windows Phone 8.1 does not support more detailed audio interfaces such as IAudioSessionControl and IAudioMeterInformation yet it does support the more generic IAudioClient so when developing universal applications, it is good to take this into account before using interfaces not supported on the phone.

History

  • 21st January, 2014: Initial version
  • 7th May, 2014: Updated for Visual Studio 2013 and Windows 8.1
  • Support confirmed for Visual Studio 2012/2013 and now 2015 as well as Windows 8/8.1/10

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)