2015-11-16 55 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(); 
     } 
    } 

} 

有一個愉快的一天。

相關問題