语音聊天室( 二 )


语音聊天室

文章插图
视频语音聊天室AudioSystem 类是Java标準音频系统的入口点,在AudioSystem 类中使用他的getLine() 方法创建TargetDataLine对象 。LineListener接口用来对线路状态改变的时间进行监听,他的重要的方法是update(LineEvent event)方法 。(封装在AudioPlayStream.java档案中)AudioPlayStream类与AudioCapture类刚好相反,它封装了GSM压缩音频数据的解码和音频信号的回放过程,提供给我们一个音频信号输出流 。AudioCapture类用到的Java Sound API中的类它也基本都用到了,只是它使用了SourceDataLine接口而不是TargetDataLine接口(封装在Debug.java档案中)Debug类主要用来在调试时输出讯息,代码很少,后来我把其中输出信息的语句都禁止了,对程式运行没有影响 。为了方便使用以上的几个类,我们需要对它们进行编译和打包,编译时需要设定相关的编译环境,以下是我们需要用到的命令行说明一下,我将以上提到的Java源码档案放在了am目录下,编译之后可以得到一个8k的am.jar档案,我们下一步所需要做的就是在我们的程式中引用这个包 。实例介绍有了以上的基本的介绍,我就可以通过对我写的一个极为简单的语音对讲软体代码的解释让大家更清楚地了解一下这几个模组的具体使用方法,大家可以从中获得开发具有诸如网路电话、自动应答等功能的软体的类似方法,用于语音数据的传输 。程式的结构整个程式分三层,作用分别如下:. 顶层: 用户界面. 中间层: 控制层. 底层: 传输层程式有两个主要的类: (表)类名描述CallLink 网路传输层,用于接收或传送音频数据 。VoiceSender 作为第二个启动的执行绪提供从音频硬体捕获并编码好的数据给网路传输层 。程式的主类jphone使用了Runnable和ActionListener接口,主类除了基本的几个方法之外,还具有方法initAudioHardware()、ShowMSG、startPhone分别用于初始化AudioCapture类与AudioPlayStream类、显示程式状态和开始程式 。主类jphone具有两个子类VoiceSender和CallLink 。子类VoiceSender同样使用了Runnable接口,它在程式中作为第二个启动的执行绪负责传送捕获到的音频数据 。CallLink子类就是负责建立scoket连线,并且负责接收或传送网路数据、监听网路连线等功能的实现 。它具有主要的方法是getInputStream()、getOutputStream()、listen()、open()、close()等 。为了让大家更清楚的了解程式的结构请大家看下面的类图 。程式工作流程当程式启动时首先执行建立当前主类的实例,当按下呼叫按钮的时候执行startPhone()方法,startPhone()方法通过调用initAudioHardware()方法建立AudioCapture对象和AudioPlayStream对象的实例PhoneMIC和PhoneSPK, 紧接着在建立CallLink子类的实例curCallLink来与具有目标IP位址的计算机进行scoket连线后,startPhone()方法又将子类VoiceSender作为secondThread执行绪启动,然后又调用run()方法 。run()方法通过已经建立的CallLink子类的实例curCallLink监听网路上的数据(也就是等待别人的呼叫),一旦有音频数据到来curCallLink 实例就为AudioPlayStream 对象PhoneSPK 提供网路传来的音频数据,而PhoneSPK在一个循环中不断的将音频数据转换为音频信号,完成类似电话听筒的功能 。子类VoiceSender 就作为第二执行绪启动的时候,startPhone() 方法传递给它的参数是实例化的CallLink 子类curCallLink , 子类VoiceSender 通过实例化的AudioCapture 对象PhoneMIC 将音频信号压缩成GSM数据,并通过curCallLink 将音频数据传送到具有目标IP 地址的计算机上,完成类似电话受话器的功能 。在这里实例化的CallLink 子类curCallLink 就相当于两个电话之间的电话线,这样通过我以上的解释大家对程式的原理就有一个大概的了解了吧 。其中的音频数据传送执行绪和音频数据接收执行绪是同步的,不过考虑到网路的因素,可能在声音的传输上有一些延迟,不过由于延迟比较小对及时听到对方的话语影响不大 。编写代码摘要在使用AudioCapture 类和AudioPlayStream 类的方法之前需要知道怎样初始化这两个类 。在声明AudioCapture 对象的时候需要传递给它一个静态的整型值用于表达将音频信号压缩的方式,这个静态的整型常量可以是AMAudioFormat 类的以下四个值之一: FORMAT_CODE_CD 、FORMAT_CODE_FM 、FORMAT所以声明AudioCapture 对象就要用一下的形式:private AudioCapture PhoneMIC null;PhoneMIC new AudioCaptureFORMAT_CODE_GSM);而声明AudioPlayStream 对象则不同,我们在初始化它的时候需要传递给它一个AudioFormat 对象,用于通知它我们所要播放音频的格式,这个AudioFormat 对象可以通过AMAudioFormat 类的getLineAudioFormat(格式参数值)方法获得,其中格式参数的取值和上面提到过的AMAudioFormat 的四个值相同,所以声明AudioPlayStream 对象就要用以下的形式:private AudioPlayStream PhoneSPK null;在这之后就可以使用AudioCapture 和AudioPlayStream 对象的open() 方法打开音频捕获和音频回放通道完成它们的初始化了 。如以下的形式:PhoneMIC.open();PhoneSPK.open();初始化完成之后要使AudioPlayStream 对象播放声音还需要以下过程,首先建立一个缓冲区(位元组数组)用于存放从网路传来的音频数据流,然后执行AudioPlayStream 对象的start() 方法使AudioPlayStream对象开始声音的回放,这时执行一个while 循环,在循环中将音频流数据写入缓冲区,再使用AudioPlayStream对象的write()方法将缓冲区的数据还原成语音信号然后播放出来 。如下面的例子: