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






4.71/5 (5投票s)
在原生 C++ 中激活 WRL 音频接口
引言
这是一个演示如何封装和转换 ActivateAudioInterfaceAsync
、IActivateAudioInterfaceAsyncOperation
、IActivateAudioInterfaceCompletionHandler
编程模式为 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 还不支持更详细的音频接口,例如 IAudioSessionControl
和 IAudioMeterInformation
,但它确实支持更通用的 IAudioClient
,因此在开发通用应用程序时,在使用手机上不支持的接口之前,最好考虑到这一点。
历史
- 2014 年 1 月 21 日:初始版本
- 2014 年 5 月 7 日:更新为 Visual Studio 2013 和 Windows 8.1
- 已确认支持 Visual Studio 2012/2013,现在也支持 2015 以及 Windows 8/8.1/10