65.9K
CodeProject 正在变化。 阅读更多。
Home

在原生 C++ 中激活 WRL 音频接口

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.71/5 (5投票s)

2014 年 1 月 21 日

CPOL

2分钟阅读

viewsIcon

16132

在原生 C++ 中激活 WRL 音频接口

引言

这是一个演示如何封装和转换 ActivateAudioInterfaceAsyncIActivateAudioInterfaceAsyncOperationIActivateAudioInterfaceCompletionHandler 编程模式为 task 对象并使用它的示例。

背景

您应该熟悉 C++、WRL、IDL 和多媒体 (MM) 设备 API。

Using the Code

代码相对较短,但必须小心保持对对象的引用,并确保初始调用以及操作完成调用都在 UI 线程中进行。使用一个 event 对象作为信号机制,就像在任务库中完成的那样。

#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>

使用代码就像调用 create_audio_task 来返回一个基于 ActivateAudioInterfaceAsync 参数的任务对象一样简单,而无需担心操作参数,该参数完全在类中处理。

关注点

这里的编程模式与 C++/CX 相同,后者在接口的库处理方面也存在缺陷。

这可以直接集成到 ppltasks.h 中,或者使用自定义原生 C++ ppltasks_winrt.h,后者可以在单独的提示中找到。但是,由于此特定接口不符合 AsyncBase 模式,因此不太有必要考虑这种更改。

与正常的 WRL 事件处理程序委托不同,在这种情况下,必须从 FtmBase 继承以引入 IAgileObject 接口,否则将返回错误 E_ILLEGAL_METHOD_CALL (0x8000000E)。

Windows Phone 8.1 还不支持更详细的音频接口,例如 IAudioSessionControlIAudioMeterInformation,但它确实支持更通用的 IAudioClient,因此在开发通用应用程序时,在使用手机上不支持的接口之前,最好考虑到这一点。

历史

  • 2014 年 1 月 21 日:初始版本
  • 2014 年 5 月 7 日:更新为 Visual Studio 2013 和 Windows 8.1
  • 已确认支持 Visual Studio 2012/2013,现在也支持 2015 以及 Windows 8/8.1/10
© . All rights reserved.