【版 本】
1.0.3
【操作系统】
Windows 桌面操作系统
【作 者】
谢红伟·chrys ·chrys@163.com ·http://www.viction.net/
【开发日期】
2006-11-20 03:05
【文档日期】
2008-06-24 18:33
【软件说明】
1、对skype拨入拨出的通话自动录音,并自动保存为mp3文件,录音模式分三种:自动录音、录音前询问用户、禁止录音,录音不限时。
2、配合无线skype话机,脱离电脑可以像拨打普通电话一样实现skype通话,该话机可以向深圳市伟信科技开发有限公司([http://www.viction.net] [chrys@163.com] [+86-755-88840880])购买,可以邮购或者电话订购。
3、自动应答,当有skype呼入时,在规定时间内用户未接通,本软件自动提机播放用户录制的语音,实现电话自动应答的功能。
4、自动留言,在用户离开电脑以后,本软件在skype呼入时自动提机并提示主叫方留言然后开始录音,用户随时可以听取主叫方的留言原声。
5、Skype通话是可以播放音乐给对方听。
6、通话过程中可以实时查看通话声音的波形图。
7、录音文件可以单独保存为.mp3文件,对重要的通话录音文件进行备份。
8、录音文件按登录用户的账号进行分开存放,同一台电脑的不同用户只能看到自己的录音文件。
9、录音时将主叫方和被叫方的声音分别保存在左右不同声道里,听取录音时更真实,更有空间感,当然这个功能也可以通过选项配置关闭。
10、当有新的录音留言时自动提醒用户有多少条录音留言未读。
11、通话过程中随时可以终止录音,可以对同一个通话其中重要的部分选择性地进行录音,每次录音会产生一个新的.mp3文件。
你可以任意修改复制本代码,但请保留这段文字不要修改。
希望我能为中国的软件行业尽一份薄力!
【软件下载】
Skype 是免费的语音通话软件,不但可以点对点用电脑进行免费的语音通话,而且只需花费低廉的费用就可以直接呼叫固定电话或手机, Skype 以优秀的通话质量而赢得了全世界不少用户的亲睐,我就是 Skype 的忠实用户,下图就是我的 Skype 截图:
我常常使用Skype和台湾同胞还有国外的朋友进行联系,有时因为业务需要需要将语音通话录音并保留下来,在我有这个想法的那个时候(2006年)Skype官方并没有提供录音功能,咱们是做程序的嘛,没有的功能可以自己来添加啊,这也是为什么我酷爱编程的原因。
应广大网友的要求,现将该程序的编程思路和源代码贡献出来与大家共勉,希望能给对音频编程有兴趣的朋友提供一点点帮助,那我就心满意足了。
刚开始编写这个程序的时候,我试着用常规的录音方式对声卡进行录音,既然是通话录音,我们希望能将自己的声音和对方的声音同时纪录下来。首先,我们要将对方的声音录下来,那就只能选取“立体声混音”通道进行录音,但此时“麦克风”通道的声音将被丢弃,也就是说在Skype里对方将听不到我说话了;其次,如果我们还要将我自己的声音录下来,就得开启“麦克风”通道录音,但是在Skype通话过程中,“麦克风”通道已经被Skype占用了,我们的程序无法再次进行录音,看来常规的录音方式行不通。
于是,我想到了Windows音频的底层处理机制,任何语音软件的音频数据处理到最后都离不开Windows的底层音频Win32 API函数,查一下MSDN就能得知:
Waveform Functions
The following functions are used with waveform audio.
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
有了这些函数,我就想到了一个办法,那就是用系统钩子改变这些函数的原地址,在Skype调用这些Win32 API函数之前先进入我的程序,我将Skype的音频数据“偷偷地”拷贝一份传递给我自己的应用程序,再还给Skype,这样就可以神不知鬼不觉地将通话中的语音数据取出来,再加上自己的mp3压缩保存到硬盘文件即可。
以上便是整个Skype录音的全部思路,现在开始介绍代码。
在本程序中需要监视的Win32 API函数有:
waveInOpen – 打开一个音频输入设备(录音)
waveInClose – 关闭一个音频输入设备(录音)
waveOutOpen – 打开一个音频输出设备(回放)
waveOutClose – 关闭一个音频输出设备(回放)
waveInPrepareHeader – 为音频输入设备准备一个内存数据缓冲(录音)
waveOutWrite – 将语音数据块发送至音频输出设备进行播放(回放)
由于我们的程序需要嵌入到Skype程序中,所以我们只能使用dll的形式来编写这个程序,我现在需要写一个修改Win32 API函数地址的类,在这里我直接引用了《Windows 核心编程》随书代码中的 CAPIHook 类,我提供的源代码里就有这个类,这个类可以修改Win32 API函数的地址,当我们修改好API函数地址以后,Skype调用前面所说的6个函数时系统会自动调用我们的函数,请看代码:
//
// 定义函数变量
//
typedef MMRESULT (WINAPI *PFN_waveInOpen) ( LPHWAVEIN phwi, UINT uDeviceID, LPWAVEFORMATEX pwfx, DWORD dwCallback, DWORD dwCallbackInstance, DWORD fdwOpen );
typedef MMRESULT (WINAPI *PFN_waveInClose) ( HWAVEIN hwi );
typedef MMRESULT (WINAPI *PFN_waveOutOpen) ( LPHWAVEOUT phwo, UINT uDeviceID, LPWAVEFORMATEX pwfx, DWORD dwCallback, DWORD dwCallbackInstance, DWORD fdwOpen );
typedef MMRESULT (WINAPI *PFN_waveOutClose) ( HWAVEOUT hwo );
typedef MMRESULT (WINAPI *PFN_waveInPrepareHeader) ( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh );
typedef MMRESULT (WINAPI *PFN_waveOutWrite) ( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh );
//
// 修改Win32 API函数地址
//
CAPIHook g_waveInOpen("winmm.dll", "waveInOpen", (PROC) Hook_waveInOpen, TRUE);
CAPIHook g_waveInClose("winmm.dll", "waveInClose", (PROC) Hook_waveInClose, TRUE);
CAPIHook g_waveOutOpen("winmm.dll", "waveOutOpen", (PROC) Hook_waveOutOpen, TRUE);
CAPIHook g_waveOutClose("winmm.dll", "waveOutClose", (PROC) Hook_waveOutClose, TRUE);
CAPIHook g_waveInPrepareHeader("winmm.dll", "waveInPrepareHeader", (PROC) Hook_waveInPrepareHeader, TRUE);
CAPIHook g_waveOutWrite("winmm.dll", "waveOutWrite", (PROC) Hook_waveOutWrite, TRUE);
说明:
CAPIHook g_waveInOpen("winmm.dll", "waveInOpen", (PROC) Hook_waveInOpen, TRUE);
这段代码实现了 "winmm.dll" 库中 "waveInOpen"函数地址的修改,修改后的地址为“Hook_waveInOpen”,也就是说,以后Skype调用函数“waveInOpen”系统会自动先调用我们的函数“Hook_waveInOpen”。其他几个函数修改原理相同。
至此我们已经成功地修改了Win32 API函数,由于Skype在调用这些API函数时会将音频数据传递给系统,刚好系统又先调用我们的函数,那我们就可以得到Skype的音频数据,看下面代码:
//
// 修改 waveOutWrite 函数地址
//
CAPIHook g_waveOutWrite("winmm.dll", "waveOutWrite", (PROC) Hook_waveOutWrite, TRUE);
//
// This is the waveOutWrite replacement function
//
MMRESULT WINAPI Hook_waveOutWrite ( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh )
{
//
// Skype 在调用 waveOutWrite 函数进行音频回放(播放对方的声音)时我们将得
// 到这些音频数据,这些数据就存放在 pwh->lpData 缓冲中,我们调用
// SendDataToMainWnd 函数将数据发送至主窗口进行压缩和保存处理
//
SendDataToMainWnd ( pwh->lpData,
pwh->dwBytesRecorded > 0 ? pwh->dwBytesRecorded : pwh->dwBufferLength,
ENUM_CATCHSOUNDTYPE_waveOutWrite );
// Call the original waveOutWrite function
MMRESULT nResult = ((PFN_waveOutWrite)(PROC) g_waveOutWrite )
(hwo, pwh, cbwh);
// Return the result back to the caller
return(nResult);
}
以上代码中将“偷取”到的音频数据通过 SendDataToMainWnd 函数发送给主窗口,至此,回放音频数据偷取成功了。
接下来我们在“偷取”录音数据(即通话中我说话的音频数据),看代码:
//
// 修改 waveInPrepareHeader 函数地址
//
CAPIHook g_waveInPrepareHeader("winmm.dll", "waveInPrepareHeader", (PROC) Hook_waveInPrepareHeader, TRUE);
//
// This is the waveInPrepareHeader replacement function
//
MMRESULT WINAPI Hook_waveInPrepareHeader ( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh )
{
// 我们都知道,常规录音是用多个录音缓冲轮流交替使用的方式来得到来自
// 硬件设备的语音数据的,当任何一个录音缓冲数据满的时候,录音程序将
// 调用 Win32 API waveInPrepareHeader 函数来准备下一个录音缓冲,调用这
// 个函数时传递的 LPWAVEHDR 指针中刚好有已经录好的音频数据,我们
// 用同样的方式将数据取走。
SendDataToMainWnd ( pwh->lpData,
pwh->dwBytesRecorded > 0 ? pwh->dwBytesRecorded : pwh->dwBufferLength,
ENUM_CATCHSOUNDTYPE_waveInPrepareHeader );
// Call the original waveInPrepareHeader function
MMRESULT nResult = ((PFN_waveInPrepareHeader)(PROC) g_waveInPrepareHeader )
(hwi, pwh, cbwh);
// Return the result back to the caller
return(nResult);
}
至此,Skype通话过程中音频输入和输出的数据(即对方讲话和我自己讲话的声音)已经全部“偷取”到了,接下来只要压缩成mp3格式即可,mp3压缩代码网上很多,随便下载一个来用就可以了,我用的是“hw_mp3_enc.dll library”,效果一般,但用做电话录音足亦。
一个有趣的功能:我们录音后的mp3文件播放时,我可以让对方的声音在左声道,我自己的声音在右声道,好像两个人面对面在对话一样。其实做起来并不难,从上面的代码我们知道,其实输入和输出的音频数据是独立获取的,我们在合并到mp3文件时,将输入的数据存为左声道,输出的数据存为右声道即可。
既然叫“Skype答录机”,除了有录音功能外,还应该有自动应答功能,要实现这个功能有两个办法:
a) 当来电震铃超过规定的次数时自动提机,将录音通道切换到“立体声混音”,然后播放之前准备好的一个语音文件(如:您好,我现在不在电脑旁,有事请留言),本软件使用的就是这种方式;
b) 当来电震铃超过规定的次数时自动提机,然后播放之前准备好的一个语音文件(如:您好,我现在不在电脑旁,有事请留言)数据直接传递至上面的.dll文件相关函数中,然后 waveInPrepareHeader 函数中将系统从麦克风中录制的声音替换掉,这种方式比较难控制,但可以实现很多奇怪的效果,比如通话变声等。
需要注意的地方:该程序是通过钩子方式截取Skype的音频数据,所以程序的执行效率要求很高,对于慢速处理的操作(如:压缩mp3数据、数据存盘等)最好是放到其他线程中处理,否则会影响Skype通话质量,造成通话断断续续的感觉,录音数据也可能会丢失。
软件执行界面
☆ 主界面:
☆ 配置界面:
说明:由于该软件为“深圳市伟信科技开发有限公司”的商业软件,这个软件是为了“无线Skype话机”而开发的,使用该话机可以离开电脑像操作普通手机一样进行免费的Skype通话了,详情请见:http://www.viction.net。出于商业道德的考虑,我不能将整个工程源代码全部公开,但有关Skype录音和应答方面的关键性代码已经全部包含在文件包里了,只要稍加修改就可以添加到自己的工程项目中了。
以上程序在Windows XP/ Skype2.5 上测试通过,但Skype3.0 以后的版本录音好像有点问题,因为时间的关系,我尚未查找其中的原因,我初步猜测 Skype 在调用 waveInPrepareHeader 函数前将数据清除掉了,可以试着捕捉 MM_WIM_DATA 消息来获取录音数据,因为工作比较忙,所以没时间来做尝试,有兴趣的朋友可以来完成它,如果有朋友完成了请将你的方法email给我,多谢。
谢谢曹昌利、陈容清、周伟波等几位同志对本软件的严格测试。
源代码下载地址:http://download.csdn.net/source/511999