Java – 通过Java套接字广播语音

我创建了一个从客户端接收声音的服务器应用程序,然后我广播这个存储为字节的声音并将字节发送回连接到服务器的客户端。 现在我只使用一个客户端进行测试,客户端正在接收语音,但声音一直都是口吃。 有人可以告诉我我做错了什么吗?

我想我理解为什么声音播放不顺畅但不明白如何解决问题。

代码是吼叫。

客户端:

将语音发送到服务器的部分

public void captureAudio() { Runnable runnable = new Runnable(){ public void run() { first=true; try { final AudioFileFormat.Type fileType = AudioFileFormat.Type.AU; final AudioFormat format = getFormat(); DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); line = (TargetDataLine)AudioSystem.getLine(info); line.open(format); line.start(); int bufferSize = (int) format.getSampleRate()* format.getFrameSize(); byte buffer[] = new byte[bufferSize]; out = new ByteArrayOutputStream(); objectOutputStream = new BufferedOutputStream(socket.getOutputStream()); running = true; try { while (running) { int count = line.read(buffer, 0, buffer.length); if (count > 0) { objectOutputStream.write(buffer, 0, count); out.write(buffer, 0, count); InputStream input = new ByteArrayInputStream(buffer); final AudioInputStream ais = new AudioInputStream(input, format, buffer.length /format.getFrameSize()); } } out.close(); objectOutputStream.close(); } catch (IOException e) { System.exit(-1); System.out.println("exit"); } } catch(LineUnavailableException e) { System.err.println("Line Unavailable:"+ e); e.printStackTrace(); System.exit(-2); } catch (Exception e) { System.out.println("Direct Upload Error"); e.printStackTrace(); } } }; Thread t = new Thread(runnable); t.start(); } 

从服务器接收数据字节的部分

  private void playAudio() { //try{ Runnable runner = new Runnable() { public void run() { try { InputStream in = socket.getInputStream(); Thread playTread = new Thread(); int count; byte[] buffer = new byte[100000]; while((count = in.read(buffer, 0, buffer.length)) != -1) { PlaySentSound(buffer,playTread); } } catch(IOException e) { System.err.println("I/O problems:" + e); System.exit(-3); } } }; Thread playThread = new Thread(runner); playThread.start(); //} //catch(LineUnavailableException e) { //System.exit(-4); //} }//End of PlayAudio method private void PlaySentSound(final byte buffer[], Thread playThread) { synchronized(playThread) { Runnable runnable = new Runnable(){ public void run(){ try { InputStream input = new ByteArrayInputStream(buffer); final AudioFormat format = getFormat(); final AudioInputStream ais = new AudioInputStream(input, format, buffer.length /format.getFrameSize()); DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); sline = (SourceDataLine)AudioSystem.getLine(info); sline.open(format); sline.start(); Float audioLen = (buffer.length / format.getFrameSize()) * format.getFrameRate(); int bufferSize = (int) format.getSampleRate() * format.getFrameSize(); byte buffer2[] = new byte[bufferSize]; int count2; ais.read( buffer2, 0, buffer2.length); sline.write(buffer2, 0, buffer2.length); sline.flush(); sline.drain(); sline.stop(); sline.close(); buffer2 = null; } catch(IOException e) { } catch(LineUnavailableException e) { } } }; playThread = new Thread(runnable); playThread.start(); } } 

您将声音数据包非常随机地分成1000000个字节,并在客户端播放这些数据包,而不考虑您在服务器端计算的采样率和帧大小,因此您最终会将声音的和平分成两个属于一起。

您需要在客户端发送它们时解码服务器上发送的相同块。 也许使用http multipart(更容易分割数据)发送它们更容易,然后通过套接字以基本方式进行。 最简单的方法是使用apache commons http client,看看这里: http : //hc.apache.org/httpclient-3.x/methods/multipartpost.html

除了HefferWolf的回答之外,我还要补充说,你通过发送从麦克风上读取的音频样本来浪费大量带宽。 您没有说您的应用程序是否仅限于本地网络,但如果您要通过Internet,则在发送/接收时压缩/解压缩音频是很常见的。

一个常用的压缩方案是SPEEX编解码器 ( 这里有一个Java实现),虽然如果你不熟悉音频采样/压缩文档看起来有点可怕,它相对容易使用。

在客户端,您可以使用org.xiph.speex.SpeexEncoder进行编码:

  • 使用SpeexEncoder.init()初始化编码器(这必须匹配采样率,通道数和AudioFormat字节顺序)然后
  • SpeexEncoder.processData()来编码一个帧,
  • SpeexEncoder.getProcessedDataByteSize()SpeexEncoder.getProcessedData()来获取编码数据

在客户端使用org.xiph.speex.SpeexDecoder来解码您收到的帧:

  • SpeexDecoder.init()使用与编码器相同的参数初始化解码器,
  • SpeexDecoder.processData()解码一个帧,
  • SpeexDecoder.getProcessedDataByteSize()SpeexDecoder.getProcessedData()来获取编码数据

我概述了更多涉及的内容。 例如,您必须将数据吐出到正确的编码大小,这取决于采样率,通道和每个样本的位数,但是您会看到通过该方式发送的字节数量急剧下降网络。