2015-11-16 19 views
15

我从Socket创建AudioInputStream时遇到问题。 这里是重要的部分:“无尽的”来自套接字的AudioInputStream

public class SoundStream extends Thread { 
    private int port; 
    private String IP; 
    private Socket socket; 

    private SoundObject soundObject; 

    private OpenAL openAL; 
    private Source source; 

    private boolean run = true; 

    public SoundStream(int port, String IP, SoundObject soundObject) { 
     this.soundObject = soundObject; 
     this.port = port; 
     this.IP = IP; 
    } 

    public void run() { 
     try { 
      this.socket = new Socket(this.IP, this.port); 
      this.openAL = new OpenAL(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     this.mainCycleMethod(); 
    } 

    private void mainCycleMethod() { 
     while (run) { 
      this.soundObject.blockAndWait(); 
      switch (this.soundObject.getAndResetEvent()) { 
       case 0: 
        this.run = false; 
        this.close(); 
        break; 
       case 1: 
        this.setPitch(); 
        break; 
       case 2: 
        this.closeSource(); 
        this.play(); 
        break; 
       case 3: 
        this.pause(true); 
        break; 
       case 4: 
        this.pause(false); 
        break; 
      } 
     } 
    } 

    private BufferedInputStream getInputStream() throws Exception { 
     return new BufferedInputStream(socket.getInputStream()); 
    } 

    private void setPitch() { 
     if(this.source != null) { 
      try { 
       this.source.setPitch(this.soundObject.getPitch()); 
      } catch (ALException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    private void play() { 
     try { 
      AudioInputStream audioInputStream = new AudioInputStream(this.getInputStream(), this.soundObject.getAudioFormat(), AudioSystem.NOT_SPECIFIED); 
//   AudioInputStream audioInputStream_tmp = AudioSystem.getAudioInputStream(this.getInputStream()); 
//   AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(this.soundObject.getAudioFormat(), audioInputStream_tmp); 
      this.source = openAL.createSource(audioInputStream); 
      this.source.setGain(1f); 
      this.source.play(); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 

    private void close() { 
     this.closeSource(); 
     this.openAL.close(); 
     try { 
      this.socket.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void closeSource() { 
     if(this.source!=null) { 
      this.source.close(); 
     } 
    } 

    private void pause(boolean pause) { 
     if(this.source != null) { 
      try { 
       if (pause) { 
        this.source.pause(); 
       } else { 
        this.source.play(); 
       } 
      } catch (ALException ex) { 
       ex.printStackTrace(); 
      } 
     } 
    } 
} 


public class SoundObject extends AbstractEventObject { 
    public AudioFormat getAudioFormat() { 
     boolean signed = false; 
     //true,false 
     boolean bigEndian = false; 
     //true,false 
     return new AudioFormat(this.frequency, this.bits, this.channels, signed, bigEndian); 
    } 
. 
. 
. 
. 
} 

这个代码在这行抛出UnsupportedAudioFileException:

AudioInputStream audioInputStream_tmp = AudioSystem.getAudioInputStream(this.getInputStream()); 

然而,当我使用此代码:

AudioInputStream audioInputStream = new AudioInputStream(this.getInputStream(), this.soundObject.getAudioFormat(), 100000); 

它播放声音,但只有后它会将这100000个样本帧加载到音频输入流中。它播放完所有100000帧后。

我想我会解决这个问题,如果我可以在第一个AudioInputStream官方化过程中直接将AudioFormat作为参数传递,但似乎不可能。 我收到来自服务器的音频格式规格。

我认为一种可能的解决方案是创建一个数据库,我可以将其作为参数传递给AudioInputStream构造函数。但是我不确定如何从套接字直接获取数据到数据库。我知道一个使用无限循环的解决方案,它在其中读取数据并将它们写入数据库。但它似乎是浪费。有更直接的方法吗?

我希望可以使用java-openAL库来解决问题,因为我需要改变速度,我希望我不必自己做。

谢谢

+1

作为第一步,您可以尝试使用'AudioInputStream audioInputStream = new AudioInputStream(this.getInputStream(),this.soundObject.getAudioFormat(),AudioSystem.NOT_SPECIFIED);'看看会发生什么。 – Roman

+0

它不能解决我的问题,因为它被openAL.createSource(audioInputStream)方法阻塞。它可能等待整个InputStream完成。谢谢 –

+0

什么是'openAL'?你可以显示完整的源代码(可能是[mcve])吗? – Roman

回答

2

我终于解决了这个问题。事实证明,java-openAL内置了流式支持,但它不在GitHub的文档中,因此我一开始并没有注意到。 Source类中有一个createOutputStream方法,它返回OutputStream。您可以将字节直接写入OutputStream。

这里是我的代码:

在这个片段中我初始化的OpenAL:

public void run() { 
    try { 
     this.socket = new Socket(this.IP, this.port); 
     this.openAL = new OpenAL(); 
    } catch (Exception ex) { 
     Log.severe(ex.toString()); 
    } 
    this.mainCycleMethod(); 
} 

这里是我的戏方法,该方法被调用时InputStream的可用:

private void play() { 
    try { 
     this.source = openAL.createSource(); 
     this.outputWriter = new OutputWriter(this.socket.getInputStream(), this.source, this.soundObject.getAudioFormat()); 
     this.source.setGain(1f); 
     this.outputWriter.start(); 
    } catch (Exception ex) { 
     Log.severe(ex.toString()); 
    } 
} 

你有要使用不带参数的createSource方法,它会返回Source的新实例。不要在源代码上调用play方法,它由SourceOutputStream类处理,该实例由createOutputStream方法返回。手动调用播放方法没有任何问题,但当缓冲区为空时,我的经历很糟糕。基本上,当您开始将数据流式传输到OpenAL时,它不会在稍后开始播放。

这里是我的OutputWriter代码这需要从InputStream中传递字节OutputStream的护理:

package cz.speechtech.sound; 

import org.urish.openal.ALException; 
import org.urish.openal.Source; 

import javax.sound.sampled.AudioFormat; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 

/** 
* Created by honza on 16.12.15. 
*/ 
public class OutputWriter extends Thread { 
    private InputStream inputStream; 
    private OutputStream outputStream; 

    private int STREAMING_BUFFER_SIZE = 24000; 
    private int NUMBER_OF_BUFFERS = 4; 

    private boolean run = true; 

    public OutputWriter(InputStream inputStream, Source source, AudioFormat audioFormat) { 
     this.inputStream = inputStream; 
     try { 
      this.outputStream = source.createOutputStream(audioFormat, this.NUMBER_OF_BUFFERS, 1024); 
     } catch (ALException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void run() { 
     byte[] buffer = new byte[this.STREAMING_BUFFER_SIZE]; 
     int i; 
     try { 
      Thread.sleep(1000); // Might cause problems 
      while (this.run) { 
       i = this.inputStream.read(buffer); 
       if (i == -1) break; 
       outputStream.write(buffer, 0, i); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 

    public synchronized void stopRunning() { 
     this.run = false; 
     try { 
      this.outputStream.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

} 

有一个愉快的一天。

相关问题