工作中有个需求是关于抓取扬声器的声音, 为什么会有这个需求? 
试想我们在共享远程桌面时,如果能够把本地桌面应用程序的声音也一起发给对方, 用户体验该是多么棒。

在考虑如何实现这个需求前,我们先讨论下电脑声音的三种模式:

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的声音是我们自己播放的,所以我们有该声音样本, 理论上我们可以通过噪声消除从混音里过滤掉与会者的声音,当然这块知识太高深,需要专门的人才能做了。
 一些Audio相关的例子:http://msdn.microsoft.com/zh-cn/subscriptions/downloads/dd316764.aspx

 个人写的一个小Demo: AudioRecord

posted on 2014-08-21 23:34 Richard Wei 阅读(8905) 评论(5)  编辑 收藏 引用 所属分类: windows desktop

FeedBack:
# re: 如何抓取扬声器的声音
2015-03-23 19:35 | 王小亮
恩,这里代码不错的。正在学习中。  回复  更多评论
  
# re: 如何抓取扬声器的声音[未登录]
2015-06-15 16:22 |
8错。关于声卡的LOOPBACK模式,这里也有介绍http://v.youku.com/v_show/id_XMTI2Mjc1MTg2OA==.html?from=y1.7-1.2  回复  更多评论
  
# re: 如何抓取扬声器的声音
2016-01-05 13:43 | josanna
博主,你好!
首先感谢你的代码分享,我从中受益不少。但有个问题想向你反馈,不知道你有没有解决方法。
在点击startCapture以后,程序开始采集播放声卡上的声音。但在这个过程中,我打开Audition软件,并有频繁切换桌面上文件夹。然后,点击stopCapture停止录音。并打开StartPlay以后,听录下的音源,发现声音存在数据不连续,丢失的现象。于是,也具体到代码和日志里面分析,发现在录音过程中,博主所用的定时器并非完全按照5ms去探测AudioEndpointBuffer上的数据,在桌面上操作或打开一些软件的时候,计时器会受到影响,异常时会出现几次一两百毫秒周期,出现了音频数据的丢失。针对这种情况,博主,你有相关的解决方法吗?  回复  更多评论
  
# re: 如何抓取扬声器的声音
2016-01-05 19:36 | Richard Wei
@josanna
不行就开线程吧,还不行可以尝试提高线程的优先级  回复  更多评论
  
# re: 如何抓取扬声器的声音
2016-01-06 08:45 | josanna
@Richard Wei
好的 我去试试,多谢!  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理