工作中有个需求是关于抓取扬声器的声音, 为什么会有这个需求?
试想我们在共享远程桌面时,如果能够把本地桌面应用程序的声音也一起发给对方,然后播放出来, 用户体验该是多么棒。
在考虑如何实现这个需求前,我们先讨论下电脑声音的三种模式:
1) render模式
该方式实际上就是播放(output)声音,常见的API如PlaySound, WaveOutXXX, DirectSound等
2) capture模式
该方式实际上就是录入(input)声音, 也就是我们通过麦克风输入声音,常见API如WaveInXXX
3)loopback模式
该方式就是我们需要实现的方式,即把扬声器里播放的声音抓取下来。
对于上面3种方式,render和capture方式应该比较好理解, 也都是系统有API直接支持的方式, loopback方式就比较奇怪了,在XP上该方式系统实际都没有正式支持, loopback的录制方式实际上也涉及到CD的版权问题。
下面是XP时代的Audio架构图, 该架构下audio的合成和压缩都是在系统内核里进行的:
在XP这种方式下,我们要抓去声卡播放的声音没有正规的方式, 一般来说只有2中:
一种是虚拟声卡,还有一种就是Hook audio 播放相关的API (很多时候我们会发现API hook是没有办法时的全能办法 ^_^)
但是在Vista之后,微软修改了原来的媒体架构, 以COM的方式重新封装了core audio API:
可以看到原来Auido的API (waveXXX, mixerXXX和DirectSound)都依赖下层的新封装的Core Audio APIs,而且这些APi都工作在用户模式, 也就是说声音的合成是在用户模式下通过软件实现的。在Vista之后, 可以看到我们可以单独控制每个应用程序的声音了, 因为每路Audio都可以工作在不同的Audio session了。通过新的Core Audio API, 我们可以很容易的实现声卡声音的抓取, 具体可参考这里:http://msdn.microsoft.com/en-us/library/ms679146.aspx
但是很快我们又发现了另外一个问题, 在一个网络会议里面, 如果共享自己桌面的人加入了VOIP, 另外也有其他与会者也加入了VOIP, 与会者说话的声音会在共享桌面端播放出来,但是该声音和共享的应用程序的声音又被一起被抓下来后发给了原来的与会者, 这样就有回声了。
这里就涉及到抓取声卡声音时能否排除掉某个声音,可惜答案是系统WASAPI不支持这种方式。但是因为与会者VOIP的声音是我们自己播放的,所以我们有该声音样本, 理论上我们可以通过噪声消除从混音里过滤掉与会者的声音,当然这块知识太高深,需要专门的人才能做了。