Skype录音答录机 编程思路阐述和源代码下载

【版   本】

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呼入时自动提机并提示主叫方留言然后开始录音,用户随时可以听取主叫方的留言原声。

   5Skype通话是可以播放音乐给对方听。

   6、通话过程中可以实时查看通话声音的波形图。

   7、录音文件可以单独保存为.mp3文件,对重要的通话录音文件进行备份。

   8、录音文件按登录用户的账号进行分开存放,同一台电脑的不同用户只能看到自己的录音文件。

   9、录音时将主叫方和被叫方的声音分别保存在左右不同声道里,听取录音时更真实,更有空间感,当然这个功能也可以通过选项配置关闭。

   10、当有新的录音留言时自动提醒用户有多少条录音留言未读。

   11、通话过程中随时可以终止录音,可以对同一个通话其中重要的部分选择性地进行录音,每次录音会产生一个新的.mp3文件。

 

你可以任意修改复制本代码,但请保留这段文字不要修改。

希望我能为中国的软件行业尽一份薄力!

【软件下载】

http://www.google.cn/search?complete=1&hl=zh-CN&newwindow=1&q=Skype%E5%BD%95%E9%9F%B3%E7%AD%94%E5%BD%95%E6%9C%BA&meta=&aq=f

 

 

Skype 是免费的语音通话软件,不但可以点对点用电脑进行免费的语音通话,而且只需花费低廉的费用就可以直接呼叫固定电话或手机, 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.

auxGetDevCaps

 

auxGetNumDevs

 

auxGetVolume

 

auxOutMessage

 

auxSetVolume

 

PlaySound

 

sndPlaySound

 

waveInAddBuffer

 

waveInClose

 

waveInGetDevCaps

 

waveInGetErrorText

 

waveInGetID

 

waveInGetNumDevs

 

waveInGetPosition

 

waveInMessage

 

waveInOpen

 

waveInPrepareHeader

 

waveInProc

 

waveInReset

 

waveInStart

 

waveInStop

 

waveInUnprepareHeader

 

waveOutBreakLoop

 

waveOutClose

 

waveOutGetDevCaps

 

waveOutGetErrorText

 

waveOutGetID

 

waveOutGetNumDevs

 

waveOutGetPitch

 

waveOutGetPlaybackRate

 

waveOutGetPosition

 

waveOutGetVolume

 

waveOutMessage

 

waveOutOpen

 

waveOutPause

 

waveOutPrepareHeader

 

waveOutProc

 

waveOutReset

 

waveOutRestart

 

waveOutSetPitch

 

waveOutSetPlaybackRate

 

waveOutSetVolume

 

waveOutUnprepareHeader

 

waveOutWrite

 

有了这些函数,我就想到了一个办法,那就是用系统钩子改变这些函数的原地址,在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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值