Jun 7, 2007

基于socket的简单语音聊天软件

基于socket的简单语音聊天软件是分布式的作业之一。下文摘抄了概要设计和详细设计的开头部分。

背景
软件名称:Xchat
开发者:04 双语 许一尊 200433099266
开发平台:JDK 1.5 + Eclipse3.3M6
本软件只采用了基本的Java sound API,即javax.sound中的内容,没有使用JMF和开源代码。

参考资料
《分布式计算原理与应用》
Java API
Java Sound Resources http://www.jsresources.org/apps/am.html

需求
1. 基于基本的Client/Server模式,实现一个text画板,提供一个多人的chat空间。在此模式下,每个人发出的message都通过server的中心控制,由server组播(multicast)给一个chat组的其他会话人。
2. 语音的录取、打包、传输、播放,从而将text chat空间变成了voice chat空间。
3. 通过server的中心控制实现会话的记录和交互式回放。

设计思路
客户端设计参考MVC模式,由一个核心控制模块处理语音发送接收、聊天信息和控制信号的发送接收、音频点播及界面的显示更新。
文本消息和控制信息合二为一,格式为:用户名>>>命令>>>参数
语聊信号通过建立音频管线截取语音包,直接广播到所以客户端,由客户端各自播放。客户端接收到控制信息时,提取出其中的用户名、命令和参数,如果该命令针对所有客户端,则执行该命令;如该命令针对特定用户,只有当用户检测到控制信息中的用户名项为其自身时才发生相应。
音频点播实现是由客户端通过有连接socket发送请求,服务器受到后发送确认信号,将文件以流的方式发送至客户端播放。

特殊性说明
由于只使用基本Java sound API,Java音频的一下局限性觉得了本系统一些特殊的设计:
首先,java平台的音频播放性能有限,当一次写入的数据过小是,声音容易出现断续的现象,而一次截取的包过大时,又会导致较大的延时。所以,必须在音频质量和声音延时上做出选择。最终的权衡结果是以1/4秒为单位截取声音,总的延时为0.5秒+网络延时,在局域网中,网络延时可以忽略不计,所以总的延时在0.5秒左右,可以接受。
其次,Java音频由于其性能问题,不能提供良好的混音效果,所以如两人同时发言,接收到声音的断续现象较为严重,如果多人同时发言,网络条件下4个音源的混音效果根本不能接受,所以本软件设定同一时间只能由一人发言,由一系列控制信号来达到所以客户端的同步。
其三,java保存音频文件方法较为单一,虽然可以通过InputStream保存成音频文件,但要预先制定音频文件的大小,这显然是不可实现的;所以唯一的办法就是在音频采集是直接保存成音频文件,在一次发言结束后上传到服务器,由于java本身没有音频合并的方法,所以音频文件的保存是以发言为单位的,点播时自然也只能以发言为单位。

系统结构
客户端


客户端设计参考MVC模式,由一个核心控制模块处理语音发送接收、聊天信息和控制信号的发送接收、音频点播及界面的显示更新。

服务器端

服务器端以一个控制中心为核心,处理客户端传来的消息和控制信号,执行相应操作并返回控制信号。

类图
客户端

a. 客户端以ClientAction为中心,该类处理界面相应并调用相应模块。由于ClientFram(界面类)的类中元素过于繁杂,在此图中已删除此类。
b. SocketMessageManager是文本消息处理的中心,建立messageSendThread和PacketReceivingThread处理消息包的发送和接收,受到消息包并提取其中信息后,将其交与ClientAction处理。
c. SoundCapture处理音频的截取和广播;SoundPlayer负责接收音频包并播放。
d. SoundRecoder负责讲语音保存在临时文件中,SoundSendThread负责发送该音频文件。
e. SoundRequestHelper与SoundRequest负责音频点播。

服务器端

a.服务器端以ChatServer为中心,处理客户端传来的消息和控制信号,并执行相应操作。
b.MessageServerThread负责调用RecervingThread,RecervingThread接收文本消息包并分离出其中的控制信号,交由ChatServer处理。
c.MulticastSendingThread负责相客户端广播聊天消息和控制信号。
d.SoundSaveServerThread负责处理客户端的保存聊天音频文件的请求,建立AudioSaveThread保存文件。
e.SoundRequestServerThread负责监听客户端的聊天记录点播请求,受到请求后,新建AudioPlayThread处理相应请求。