封装了P2P连接与传输过程的DLL--最新改进版
在DLL的前一版本中,采用的是CString来保存数据,但CString在频繁进行删除和添加操作时,效率太低啦,在新发布的DLL中,去掉了所有的CString,在原来使用CString的地方,使用了一个新的类CStringEx来代替,并且改进了接收与传送的过程,使原来的接收、复制、再复制过程,直接由一个接收过程来完成,使效率提高了60%,并节省了资源。
对数据的发送过程,也进行了大的改动,明显提高了效率,尤其是对大数据流的传送和接收作了特别的优化。
改进以后的最大差别是消除了原先数据流大小不能超过18000字节的限制,数据流的大小可以无限大,并且支持二进制流的传送,比如直接传送音频和视频缓冲区,将二进制流的缓冲区直接赋给CStringEx,或直接使用CStringEx来代替原先的缓冲区,你就可以直接传送缓冲区中的数据。
在新的DLL中,为了适应将来实现IP多播,取消了原先在PBaseAct基类中定义的m_sReceiver字段(即接收者ID),在对象的序列化方法进行了一些改动,具体改动可以参考在例程中的PChatAct类的定义。
CStringEx将作为DLL提供的第5个类出现。CStringEx可以实现CString的大多数功能,为了方便,仅重载了+=、=操作符,可以直接赋值或加上一个int、LPCTSTR类型的值。另外它对Delete(0,nCount)方法作了特别优化,使效率提高了100%,使进行该操作的时间为常数n,而原先CString的Delete(0,nCount)操作的时间为n*len,len为CString的长度。另外CStringEx还支持二进制流缓冲的增加。
通过对新版DLL的发布,应该可以看出,对传输与接收过程的改动,对数据流本身的改动,仅是针对于DLL内部,而对于使用DLL的开发者来讲,完全不用改动自己的程序,就可以直接享受到DLL改动所带来的传输与接收效率的提高。
在下一版的DLL中,我将加入音频的传送与回放,实现语音聊天。在下下一个版本中,我将加入对防火墙的突破(目前仅限于支持Socket5协议的防火墙)。
希望大家在使用后能将自己的使用心得写出来,让更多的人了解和使用DLL来开发,更希望大家能提出你对DLL的发展的看法和意见。
封装了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例子程序。
3PDefine::SPlaySound(8);
//启动声音播放设备,参数为0..15之间的整数。缺省值为8。
//整数所表示的含义与捕捉设备的格式列表中的顺序是一样的。
//声音播放的格式应和录音的格式一样,否则会产生变调。
4HWND hCombo=this->GetDlgItem(IDC_COMBO1)->m_hWnd;
PDefine::SGetSoundCaptureDeviceList(hCombo);
//创建声音捕捉设备,传递一个组合框控件的HWND,DLL会将可利用的声音捕捉设备填充在组合框内。
//如果给出的HWND为空,DLL不作填充。组合框控件不要排序。
5PDefine::SInitSoundCaptureDevice(NULL);
//如果你在第4步的方法中给出了一个组合框控件的HWND,DLL会自动地设定初始选择为第0个条例。
//你可以在等待用户选择组合框,按确定按钮后,将组合框控件的HWND作为参数传送给
//SInitSoundCaptureDevice()方法。
//如果你在前一个方法中HWND为空,则在调用SInitSoundCaptureDevice()方法时,
//设定第一个参数为NULL,然后传递第二个参数,第二个参数表示你选择第几个设备,这个值必需
//是一个有效的选择,第二个参数缺省时为0。
6HWND hListBox=this->GetDlgItem(IDC_LIST1)->m_hWnd;
PDefine::SGetSoundCaptureAvailableFormats(hListBox);
//得到选择的捕捉设备的可利用的格式列表,传递一个列表框控件的HWND,DLL会将可利用的捕捉
//格式填充在列表框中。如果HWND为空,DLL不作填充。列表框控件不要排序。
7PDefine::SSetSoundCaptureAcceptdFriend(CPPSerDlg::SGetFriendFromID("PPQ123456789"));
//通过这个方法的调用,你可以选择后续的语音被传送给哪一个好友。
//这个方法可以在开始声音捕捉后多次调用,来改变接收方。
//如果你和这个好友之间没有创建连接,则语音不会被传送,程序也不会出错,我会在后续的版本中加入一些消息来通知DLL外的程序作出相应的响应。
8PDefine::SCreateSoundCaptureBuffer(NULL);
//使用方法参考上面组合框的使用。第二个参数缺省,表示使用缺省的值为8,
//即22.05KHz,8位,单声道格式。
9PDefine::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的后续版本。