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

标签 java sockets tcp audio-streaming audio-recording

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

我想我理解了声音播放不流畅的部分原因,但不明白如何解决这个问题。

代码如下。

客户:

向服务器发送语音的部分

     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();
   }


   }

最佳答案

除了 HefferWolf 的回答之外,我还要补充一点,您发送从麦克风读取的音频样本会浪费大量带宽。您不会说您的应用是否仅限于本地网络,但如果您通过互联网访问,则在发送/接收时压缩/解压缩音频是很常见的。

常用的压缩方案是 SPEEX codec (Java 实现可用 here ),尽管如果您不熟悉音频采样/压缩,文档看起来有点吓人,但它相对容易使用。

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

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

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

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

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

关于Java - 通过 Java 套接字广播语音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7728850/

相关文章:

c# - Socket.Connect 抛出和我无法捕获的错误

java - Android 分发包含后台服务的 SDK。

c - 如何初始化缓冲区

sockets - Coffeescript 等待回调设置标志,然后继续执行代码的下一部分

c - 套接字编程中struct addrinfo {}中链接列表的用途

java - setout 文件不会根据日期每天生成

java - 使用空格对 JAVA_OPTIONS 进行 JVM 调优?

java - WildFly 10.0.0 Final正在接受请求,但将其放入队列中而不进行处理

java - 在 ubuntu 上使用安装 JavaCV 和 OpenCV(对于 eclipse)

java - ObjectInputStream.readObject() 断开连接时不抛出异常