封装了P2P连接与传输过程的DLL最新版--支持语音传输
经过了几天的努力,语音传输终于被集成到了DLL中,因为我仅在2台机器上进行了测试,效果如何,还希望大家在使用后能及时的告诉我。
声音的捕捉和回放采用了DirectSound,在捕捉和回放时都采用了DirectSound的Notify功能来读写缓冲区,使声音能够较流畅地表现出来。声音数据被捕捉后,保存在了一个指令的CStringEx对象中,然后传输到连接方,连接方接收到指令后,写入回放缓冲区中,从而完成整个声音的传送过程。
在这个版本里,我还没有作得很完善,并没有对每次传送的声音数据进行格式校验,因此连接双方必需使用相同的格式(即采样速率、8/16位、单声道或立体声)来捕捉和回放声音,否则声音可能会变调。
在你使用缺省值(即22.05KHz,8位,单声道)方式进行声音捕捉和回放时,每秒传送的数据量约为22K,这个数据量对于56K的Modem也应该可以承受。因为我用的是宽带,因此无法在低带宽的网络中进行测试,希望测试过的朋友能告诉我结果。
另外,在这个版本里,我作了一个小的偿试,并没有象传统的语音传输程序在整个的对话过程中,不断地传送声音,而不管你是否在说话。我在DLL里加了一小段滤音程序,如果声音捕捉时没有有效地声音数据,就不会再向对方传送数据,只有当出现有效数据时,才会向对方传送声音指令。我只在自己的机器上作了测试,不知道效果如何,希望大家使用后,能告诉我使用后的效果。
如何启动声音传输呢?
非常简单,只需要调用几个在PDefine类中定义的静态方法,你就可以完成整个语音的传输过程,拥有一部IP_Phone。请按照以下几个步骤来启动声音传输:
1 给PDefine::cSMsgInfo结构赋值。
2 创建PFriend对象并于对方建立聊天连接。
这两步的过程的具体作法在前面的文章中有详细地介绍,这里就不再详细介绍了,具体方法可以参看PPSer例子程序。
3 PDefine::SPlaySound(8);
//启动声音播放设备,参数为0..15之间的整数。缺省值为8。
//整数所表示的含义与捕捉设备的格式列表中的顺序是一样的。
//声音播放的格式应和录音的格式一样,否则会产生变调。
4 HWND hCombo=this->GetDlgItem(IDC_COMBO1)->m_hWnd;
PDefine::SGetSoundCaptureDeviceList(hCombo);
//创建声音捕捉设备,传递一个组合框控件的HWND,DLL会将可利用的声音捕捉设备填充在组合框内。
//如果给出的HWND为空,DLL不作填充。组合框控件不要排序。
5 PDefine::SInitSoundCaptureDevice(NULL);
//如果你在第4步的方法中给出了一个组合框控件的HWND,DLL会自动地设定初始选择为第0个条例。
//你可以在等待用户选择组合框,按确定按钮后,将组合框控件的HWND作为参数传送给
//SInitSoundCaptureDevice()方法。
//如果你在前一个方法中HWND为空,则在调用SInitSoundCaptureDevice()方法时,
//设定第一个参数为NULL,然后传递第二个参数,第二个参数表示你选择第几个设备,这个值必需
//是一个有效的选择,第二个参数缺省时为0。
6 HWND hListBox=this->GetDlgItem(IDC_LIST1)->m_hWnd;
PDefine::SGetSoundCaptureAvailableFormats(hListBox);
//得到选择的捕捉设备的可利用的格式列表,传递一个列表框控件的HWND,DLL会将可利用的捕捉
//格式填充在列表框中。如果HWND为空,DLL不作填充。列表框控件不要排序。
7 PDefine::SSetSoundCaptureAcceptdFriend(CPPSerDlg::SGetFriendFromID("PPQ123456789"));
//通过这个方法的调用,你可以选择后续的语音被传送给哪一个好友。
//这个方法可以在开始声音捕捉后多次调用,来改变接收方。
//如果你和这个好友之间没有创建连接,则语音不会被传送,程序也不会出错,我会在后续的版本中加入一些消息来通知DLL外的程序作出相应的响应。
8 PDefine::SCreateSoundCaptureBuffer(NULL);
//使用方法参考上面组合框的使用。第二个参数缺省,表示使用缺省的值为8,
//即22.05KHz,8位,单声道格式。
9 PDefine::SRecordSound();
//开始声音捕捉。
经过以上9个步骤,你已经创建了一个语音传输的通道,语音传输和文字传输采用的是同一个连接,你可以在传输声音的同时,也传输其它指令。从第4到第9的步骤中除了第7步外,都不要重复调用,除非你释放了捕捉或回放设备。
和声音捕捉与回放相关的所有方法,都是PDefine类中的静态方法,其它方法如下:
static void SStopRecordSound();
//暂时停止声音捕捉,停止后声音捕捉设备并没有被释放,你可以使用PDefine::SRecordSound()方法继续开始声音捕捉。
static void SReleaseSoundCaptureDevice();
//释放声音捕捉设备。调用该方法时,不需要预先去停止声音捕捉,方法内部会自动调用。
//如果你释放了声音捕捉设备,你不能够再通过调用PDefine::SRecordSound()方法来继续开始声音捕捉;你必需重复第3步到第9步的过程,来重新启动声音捕捉。
//注意: 在程序结束时,一定要调用该方法去释放声音捕捉设备,即使你没有启动过声音捕捉设备,调用该方法也不会产生错误。
static void SStopPlaySound();
//暂时停止声音回放。你可以通过调用PDefine::SPlaySound()方法继续开始声音回放。在你停止声音回放的期间,你所接收到的声音都会在内存中被保存下来,当你继续开始声音回放时,会自动按照原来接收的顺序将声音依次回放出来。
//在这个版本时,还不能创建多个声音回放,在后续的版本中,将会支持多个声音回放。
static void SReleaseSoundPlayDevice();
//释放声音回放设备。你可以通过调用PDefine::SPlaySound()方法继续开始声音回放。
//注意: 在程序结束时,一定要调用该方法去释放声音回放设备,即使你没有启动过声音回放设备,调用该方法也不会产生错误。
关于声音的传输方法,就暂时介绍到这里啦。在下一个版本中,我将把突破防火墙的方法集成进DLL中,使处在任何位置的双方都可以实现P2P的互连。
因受到开发条件的限制,试验突破防火墙的方法,对我来讲是一件很麻烦的事。因为我只有一台机器,所以作这件事情,要绕很多的弯,不知道哪一位朋友是否愿意共同合作来进行测试。
希望大家能继续关注DLL的后续版本。