免费建站自己的网址,美化网站公司,隆昌网站建设,建设网站的分析报告在前面介绍了ADM(Audio Device Module)#xff0c;它用于抽象音频设备管理和音频数据采集/播放接口。windows的实现是AudioDeviceWinowCode#xff0c;它封装了Core Audio APIs实现了对音频设备的操作。
Core Audio APIs
windows提供了多种音频操作API#xff0c;比如最常…在前面介绍了ADM(Audio Device Module)它用于抽象音频设备管理和音频数据采集/播放接口。windows的实现是AudioDeviceWinowCode它封装了Core Audio APIs实现了对音频设备的操作。
Core Audio APIs
windows提供了多种音频操作API比如最常用的是 waveXxx系列APIDirectSound等。而Core Audio APIs是这些API的基础这些API使用Core Audio APIs提供了更通用的功能。
如下图是Core Audio APIs的架构图 Core Audio APIs是一些高阶API例如MMEDirectSound等的基础。箭头的方向表示了音频数据的流向。它有两种工作模式共享模式和独占模式。共享模式就是大家(多个应用程序)同时播放声音(声音被混音)独占模式就是只能有一个程序播放我一播就没其他程序的声音了。共享模式下会有一个Audio Service进行协调各应用程序间的音频数据处理。这个很容易理解多路声音总该需要一个大管家来协调使用设备。独占模式下音频数据就直接到内核的驱动了。
Core Audio APIs特点是音频处理更高效延时更低。对webrtc 这种RTC系统来说正是需要其低延时的保证。
它四类子API
从上图中可以看到Core Audio APIs是一系列API的集合它包括四类子API。
MMDevice API(用于检索播放采集设备)
用于应用程序检索音频终端设备枚举出所有可使用的音频设备属性及确定其功能并为这些设备创建驱动程序实例是最基本的Core Audio API服务于其它3个APIs。 WASAPI(控制播放和采集流)
应用程序可以通过它管理程序和音频终端设备之间音频数据的流。比如采集回放音频。 DeviceTopology API(webrtc中没用到)
应用程序可以遍历音频适配器设备和音频终端设备的内部拓扑并单步执行将设备链接到另一台设备的连接。通过 DeviceTopology API 中的接口和方法客户端程序可直接沿着音频适配器 (audio adapters) 的硬件设备里的数据通道进入布局特征(例如沿着音频终端设备的数据路径上进行音量控制) 。
EndpointVolume API(控制音量)
应用程序可以控制和监视音频终端设备的音量。
它们都以COM组件的方式提供应用程序需要创建对应COM组件的实例获取接口对象再使用它们提供的方法。
AudioDeviceWindowCore
在webrtc中使用Core Audio APIs以下四个功能
检索音频回放设备。检索音频采集设备。使用指定的音频设备回放声音。使用指定的音频设备采集声音。音频回放。音频采集。
类图如下 它直接管理Core Audio APIs的COM对象
以**I**开头的都是对象接口类
IMMDevice代表一个音频设备。IMMDeviceCollection音频设备集。IMMDeviceEnumerator用于枚举音频设备。IMMEndpoint代表一个音频终端设备。
功能实现
检索音频设备
如下图系统中一般都会有扬声器和麦克风在声音设置中可以看到它们。 在AudioDeviceWindowCore::Init方法中实现检索回放和采集设备需要使用的接口对象是IMMDeviceEnumerator检索出来的结果保存在 IMMDeviceCollection对象中。
音频设备有名字音频参数(如:声道数采样率等)等属性这些都会一并获取到。
IMMDeviceCollection* pCollection NULL;
hr _ptrEnumerator-EnumAudioEndpoints(dataFlow, // data-flow direction (input parameter)DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED | DEVICE_STATE_UNPLUGGED,pCollection);
hr pCollection-GetCount(count);
for (ULONG i 0; i count; i) {//遍历每个设备获取对应的属性
}调用EnumAudioEndpoints方法检索指定状态的设备通过GetCount获取数量再遍历设备获取属性。
播放声音
指定回放设备
首先要指定要使用的回放设备通过序号指定在IMMDeviceCollection中检索通过index获取到IMMDevice对象它就代表了一个音频设备。
回放声音需要使用WASAPI模块的IAudioClient接口它通过IMMDevice获取
hr _ptrDeviceOut-Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL,(void**)_ptrClientOut);根据设备支持的音频参数确定一个输出格式。
音频有采样率声道位率这些参数不同的值决定了声音的质量及数据大小。WASAPI中用这个结构体来描述 在回放声音时要指定这些参数就是告诉WASAPI怎么去播放声音但是首先要知道的是音频设备支持怎样的播放参数。
hr _ptrClientOut-GetMixFormat(pWfxOut);获取到的信息如下 [017:755][95740] (audio_device_core_win.cc:1851): Audio Engine’s current rendering mix format: [017:755][95740] (audio_device_core_win.cc:1853): wFormatTag : 0xfffe (65534) [017:755][95740] (audio_device_core_win.cc:1857): nChannels : 2 [017:755][95740] (audio_device_core_win.cc:1859): nSamplesPerSec : 48000 [017:755][95740] (audio_device_core_win.cc:1861): nAvgBytesPerSec: 384000 [017:755][95740] (audio_device_core_win.cc:1863): nBlockAlign : 8 [017:755][95740] (audio_device_core_win.cc:1865): wBitsPerSample : 32 [017:755][95740] (audio_device_core_win.cc:1866): cbSize : 22 在webrtc中以采用率及声道数为标准现找一个与需求最贴合的参数如下信息 [017:802][95740] [017:802][95740] (audio_device_core_win.cc:1927): VoE selected this rendering format: [017:802][95740] (audio_device_core_win.cc:1928): wFormatTag : 0x1 (1) [017:802][95740] (audio_device_core_win.cc:1931): nChannels : 2 [017:802][95740] (audio_device_core_win.cc:1932): nSamplesPerSec : 48000 [017:802][95740] (audio_device_core_win.cc:1933): nAvgBytesPerSec : 192000 [017:802][95740] (audio_device_core_win.cc:1934): nBlockAlign : 4 [017:802][95740] (audio_device_core_win.cc:1935): wBitsPerSample : 16 [017:802][95740] (audio_device_core_win.cc:1936): cbSize : 0 [017:802][95740] (audio_device_core_win.cc:1937): Additional settings: [017:802][95740] (audio_device_core_win.cc:1938): _playAudioFrameSize: 4 [017:802][95740] (audio_device_core_win.cc:1939): _playBlockSize : 480 [017:802][95740] (audio_device_core_win.cc:1940): _playChannels : 2 确定了这些参数就可以确定喂入设备的音频数据量大小。
获取流输出控制接口IAudioRenderClient
通过IAudioClient获取IAudioRenderClient它就是控制音频流的接口。
hr _ptrClientOut-GetService(__uuidof(IAudioRenderClient),(void**)_ptrRenderClient);相关代码在AudioDeviceWindowsCore::InitPlayout方法中。
播放
在webrtc使用的Core Audio API的共享模式在共享模式下将会有一个Audio Service(在上面的图中可以看出来)应用程序将通过Enpoint Buffer与Service交互。
播放声音就是往这个buffer中写入音频数据应用程序写入数据Audio Service读取数据。
一端写一端读就需要判断buffer的空间所以需要程如下几步
先通过IAudioClient的 GetBufferSize接口获取buffer大小。再通过IAudioClient的 GetCurrentPadding接口获取buffer待Audio Service的处理的数据。计算可用空间buffer size - padding data size 就是buffer中可用的空间。通过IAudioRenderClient的GetBuffer接口获取buffer的地址。往buffer中写数据。
完整的流程可以看看AudioDeviceWindowsCore::DoRenderThread()方法。
需要注意一点这里的buffer size不是以字节为单位而是以audio frame为单位通过API获取的是buffer可存放的audio frame数及可用的frame空间。
audio frame的大小由采样率和采样时长决定在webrtc中以10ms作为采样时长那么48000HZ的采样率一个audio frame的大小就是480采样点(换算成字节数每个采样点2个字节10ms的数据960个字节)。
播放线程
音频数据是不停的往Audio Service的buffer中写入webrtc通过一个线程实现取应用层音频数据到写入buffer流程如下流程图: 播放线程不会停会持续不断的取数据写入Audio Service Buffer线程对应的方法为 AudioDeviceWindowsCore::DoRenderThread()。