引 言
随着计算机网络的日益普及,人们通过网络进行交流显得越来越重要,于是出现了一系列语音通信的软件,比如NetMeeting、IPPhone、MediaRing以及VoxPhone等等,但这些软件都功能完善、相对独立,不利于集成到自己开发的软件中,有时我们也希望将这种语音通信功能集成到自己的软件中,尤其当一个单位的局域网用户分散在不同的房间时。本文给出一种灵活、简单的实现方法,采用基于对话框的方式编程,硬件上只需要一块双DMA通道的声卡(目前的声卡大多支持双DMA通道)和一支耳麦,其余全部由软件编程实现。程序在 Windows98/2000、Visual C++6.0 下编译通过,在Windows NT 100M 以太网上运行良好。

设计思路

要实现点对点语音通信,原理非常简单,只要针对一个点实现话音的实时采集、处理、播放,同时能进行可靠的传送和接收,这样两点一连便可通话。对于前者,采用Windows MDK的低层音频服务比较合适,因为低层音频服务中的回调机制为我们提供了很大的方便。当应用程序不断向设备驱动程序提供音频数据时,设备驱动程序控制音频设备在后台完成录音和放音的具体操作,通过回调机制,我们又可以检测到什么时候用完一个数据块,并及时传送下一个数据块,从而保证了声音的连续,有了这种单机上的实时采集、回放功能后,接下来的工作就是在网络上传送话音数据。在点对点网络传输方面,选择面向连接的TCP协议,TCP传输协议自动处理分组丢失和交付失序问题,这样我们不用为这些问题操心,只需很好地利用这个连接,在采集话音回放之前一方面将自己的话音传给网络,另一方面接收网络传来的话音,这样便实现了点对点语音通信。其结构框图如下:

具体实现

一、话音的实时采集、处理、回放
首先要介绍一下Windows低层波形音频数据块结构 WAVEHDR,其声明如下:
type struct{
LPSTR lpData; //指向锁定的数据缓冲区的指针
DWORD dwBufferLength; //数据缓冲区的大小
DWORD dwByteRecorded; //录音时指明缓冲区中的数据量
DWORD dwUser; //用户数据
DWORD dwFlag; //提供缓冲区信息的标志
DWORD dwLoops; //循环播放的次数
struct wavehdr_tag * lpNext; //保留
DWORD reserved; //保留
} WAVEHDR;
声音的采集和播放都是在操作这个音频数据块结构,实际上主要用到的就是第一个成员变量lpData, 所以我们只要在分配缓冲区(内存)的同时相应分配WAVEHDR数据块结构,然后将缓冲区的指针赋给对应的数据块结构的成员变量 lpData,这样当一个缓冲区填满后,也就是一个音频数据块填满了,通过消息机制就可以在消息函数中进行处理和播放,播放完后又可通过消息函数把缓冲区再送给音频设备输入驱动程序,继续进行采集并播放,当你一次性分配多个缓冲区和数据块结构并赋给音频设备输入驱动程序后,至于把哪个缓冲区填满,然后再把哪个空缓冲区赋给设备输入驱动程序,不需人为干预,完全由Windows控制,这就是一种用动态循环缓冲区实现话音的实时采集、播放的简单而巧妙的办法。实现步骤:
1.初始化操作

①用waveInGetNumDevs()和waveOutGetNumDevs()查看当前系统波形音频输入、输出设备;
②按11025Hz,16Bit,单声道,22K/S的格式设置WAVEFORMATEX结构的成员变量,也可以改为其他WAVE格式;
③用waveInOpen(...) 和waveOutOpen(...)分别调用WAVE_FORMAT_QUERY参数查看波形输入设备是否支持所设定的格式;
④再次用waveInOpen(...) 和waveOutOpen(...)分别调用CALLBACK_WINDOW参数打开波形输入设备;
⑤分别给音频数据块和音频数据缓冲区分配、锁定全局内存;
⑥初始化音频数据块结构各成员变量,主要是将每个缓冲区指针赋给对应数据块结构中的缓冲区指针变量lpData;调用waveInPrepareHeader(...)和waveInAddBuffer(...)将音频数据块赋给输入设备驱动程序;
⑦调用waveInStart(...)函数开始录音。

2.消息操作
录音开始后,每当有采样数据填满数据块后,设备驱动程序就会发消息MM_WIM_DATA给用户窗口,相应的消息回调函数OnMmWimData(...)对数据块中的采样数据进行处理,然后就可以发送给输出设备进行回放,每当一个音频数据块播放完毕,设备驱动程序又会发出消息MM_WOM_DONE,相应的消息回调函数 OnMmWomDone(...)记录音频数据并经必要准备后重新发送给输入设备,以准备接收后续的采样数据。这样,最初为输入设备准备的音频数据块就在消息的控制下,在输入、输出设备间循环使用,无需人为控制实现了实时采集、处理和播放。
当结束通话时要关闭音频输入设备,这时音频设备驱动程序会发送MM_WIM_CLOSE消息,可在相应的消息函数OnMmWimClose(..)中清除赋给输入、输出设备的音频数据块。

二、基于TCP协议的点对点话音传输

对于声音的传送和接收主要是采用面向连接的TCP协议,并用Windows Socket进行网络编程实现,但首先要将发送和接收的函数接口放在 OnMmWimData(...)函数中,这样才能做到采集数据块填满后被发送,接收的数据收到后被播放。 Windows Socket对于从事过网络编程的人来说应该不陌生,因为我们要实现点对点通信,所以得把客户和服务器模式融合为一种模式,让服务器可以做客户,客户也可以做服务器,从而使双方都有呼叫对方和接受对方呼叫的能力,这只需增加一个监听Socket就行了。一旦呼叫连接建立成功,便在两个点之间建立了一个数据流,即使双方不讲话,每个点也在不停地收、发数据,一方有话音自然就随着这个数据流传给了对方,所以关键的问题就是怎样读取话音数据流,因为TCP提供的流式服务是不保证边界的,当发送方想一次发送 4000个字节时,调用语句Send(sBuffer,4000),并不能保证一定能发送出4000个字节;同样,接收方准备一次接收发过来的数据,调用语句Receive(rBuffer,4000),也不能保证一定能接收4000个字节,因此实际一次发送和接收的字节数会是1到4000中的任何一个值,最坏的情况是只有1个字节。相反,如果用Send函数连续发送少量数据,比如一次发送400个字节,连续发送10次,接收方用Receive函数可能一次就把这4000个字节都接收下来了,而为了实现播放,我们希望调用一次发送函数就能把缓冲区大小的话音数据发送出去,调用一次接收函数就能把对方一次发送的话音数据准确接收下来,以便进行播放,所以一种比较简单实用的办法,就是利用TCP协议发送数据时为每个数据包加个标志头:


这个标志头包含长型(4字节)的话音数据量值和一个标志字符串,程序中可为这两项标志相应设置偏移量,同时也为话音数据设置偏移量,通过重载OnReceive(...)进行接收。开始接收前,偏移量都置0,接收开始后先检测是否收到了4 个字节的话音数据量大小值和字符串标志,如果没有收到,则通过偏移量来控制将它们准确收到,之后校验字符串标志的正确性,如果两项标志都正确收到了,则按收到的数据量大小值进行真正的话音数据接收,如果在OnReceive函数中一次调用Receive(...)接收没有达到这个值,则采用非阻塞模式,调用AsyncSelect(...)函数继续接收,直至全部收到,这样重载 OnReceive(...)接收函数后就可以一次接收对方发过来的数据;同理,我们重载CAsyncSocket 的OnSend函数,也可以实现一次发完一个缓冲区中的数据。这样只要将收发函数的接口放在OnMmWimData(...)函数中,使收和发都产生恒定速率的数据流,从而实现了网络话音的传输和回放。

三、界面及其他功能
界面及其他功能也要做一番设计:
1.设置“查找邻居"项,可查看谁在网上,用ListBox进行显示,在ListBox选中一位邻居,对应的邻居编辑框中就显示出该邻居,便于呼叫,“查找邻居"主要用到的函数是WnetOpenEnum(...)、WnetEnumResource(...)、 WnetCloseEnum(...)。
2.程序是基于对话框的,运行后不做任何显示,直接放入系统托盘,直至双击托盘图标或选择菜单再运行,但可随时监听是否有呼叫接入,一旦连接建立立刻开启话音处理功能。

3.每次运行都在注册表的RunServicesOnce键中写入或修改NetPhone项,使程序能保持开机就自动运行。
4.加入了调节麦克和耳机音量的功能。
5.为通话对方提供音乐播放,但只支持与采样格式相同的.wav文件,其他格式的.wav文件可用Windows的录音机转换即可。

一种基于局域网的点对点语音通信相关推荐

  1. 种基于局域网的点对点语音通信

    引 言 随着计算机网络的日益普及,人们通过网络进行交流显得越来越重要,于是出现了一系列语音通信的软件,比如NetMeeting.IPPhone.MediaRing以及VoxPhone等等,但这些软件都 ...

  2. 点对点语音通信(转)

    随着计算机网络的日益普及,人们通过网络进行交流显得越来越重要,于是出现了一系列语音通信的软件,比如NetMeeting.IPPhone.MediaRing以及VoxPhone等等,但这些软件都功能完善 ...

  3. 计算机winform参考文献写,毕业论文基于C#WinForm的语音通信系统设计.doc

    毕业论文基于C#WinForm的语音通信系统设计 毕 业 设 计 目基于C#WinForm的语音通信系统设计学生姓名学 号系 别防灾仪器系专 业测控技术与仪器班 级开题时间2013年12月25日答辩时 ...

  4. android蓝牙传输脉冲,一种基于Android操作系统的激光测距仪蓝牙通信方法与流程...

    本发明属于无线通信技术领域,涉及Android操作系统的应用,具体涉及一种基于Android操作系统的激光测距仪蓝牙通信方法. 背景技术: 目前,随着智能设备的普及,智能操作系统得到了极大的发展,An ...

  5. 基于modbus协议的工业自动化网络规范_一种基于Modbus的工业通信网关设计

    近年来,随着工业自动化领域的发展,工业现场对网络的可靠性及成本有极高的要求.传统基于串口的工业网关可以满足工业现场的应用,但却要付出高额成本.一种基于 ModBus 设计的工业通信网关就走进人们的眼中 ...

  6. 极限元语音算法专家刘斌:基于深度学习的语音生成问题

    一.深度学习在语音合成中的应用 语音合成主要采用波形拼接合成和统计参数合成两种方式.波形拼接语音合成需要有足够的高质量发音人录音才能够合成高质量的语音,它在工业界中得到了广泛使用.统计参数语音合成虽然 ...

  7. html5 视频语音对讲,一种基于WebRTC的多人语音视频通话方法及系统与流程

    本发明涉及视频通话领域,特别涉及一种基于WebRTC的多人语音视频通话方法及系统. 背景技术: 随着互联网技术和通信技术的快速发展,人们的交流方式与交流内容得到了极大的丰富和发展.在节奏越来越快的信息 ...

  8. 帕德逼近matlab算法,一种基于帕德逼近的通信误差函数逼近方法与流程

    本发明属于通信与电子信息技术领域,具体是属于计算机仿真领域,涉及一种基于帕德逼近的通信误差函数逼近方法. 背景技术: 在通信领域,通信误差高斯Q函数在数字调制方案的符号错误概率(SEP).加性高斯白噪 ...

  9. webrtc在服务器端通信协议,一种基于WebRTC通信的Web协议WebTorrent

    本文来自WebTorrent的创始人.PeerCDN联合创始人Feross Aboukhadijeh,他介绍了一种基于WebRTC通信的Web协议WebTorrent,通过WebTorrent可以节省 ...

最新文章

  1. 2019年终总结:好好爱自己
  2. postgresql 查询序列_时间序列数据库(TSDB)初识与选择
  3. 企业为什么要开通银企直联_企业为什么要把人事外包出去
  4. SSM项目整合Quartz
  5. python3.7.2教程-python 3.7极速入门教程2 Hello与变量
  6. 2021-03-01 英文写作中的“许多”
  7. JVM—方法区到底是怎么保存函数方法的?
  8. form表单图片预览 layui_layui 实现图片上传和预览
  9. 隐藏文件或文件夹属性无法修改解决方案
  10. Vue学习笔记之15-vue-router详解
  11. SQL Server 2014新特性:其他
  12. 用IO多路复用,实现每秒百万并发的原理你懂吗?
  13. pandas读取excel带汉字的列头_Pandas读取excel与中文文件名
  14. 工业智能网关BL110应用之四十三:网口采集欧姆龙PLC的配置
  15. 黑灰产攻击洪峰来袭,企业如何守住自己的钱袋子?
  16. 2018年阅读随笔记录(持续更新)
  17. ACE+TAO环境搭建 windows平台
  18. 如何将台式计算机连接到WiFi,台式机怎么连接wifi?台式电脑连接无线网络的方法(图文)...
  19. 安卓 获取屏幕坐标(点击屏幕获取坐标)
  20. DDIA读书笔记 第五章 数据同步

热门文章

  1. Mysql中,order by + limt的大坑
  2. 不限速开源的下载工具:Persepolis Download Manager
  3. 数据库 SQL Server错误18456,window身份验证登录失败解决办法
  4. 名帖234 俞和 行书《云锦帖》
  5. 深入理解Java虚拟机——Parallel Old收集器
  6. 使用R语言并行提取栅格数据
  7. Spring注解驱动
  8. 微信运营——利用python自动加微信(通往销冠之路)
  9. html 怎么获取焦点的位置,jQuery怎么获取焦点?
  10. Spoon Kettle 输入之获取文件名(Get file names)