2014-04-10 76 views
0

嘿,有堆棧溢出。Java音頻播放器最後削減音頻

我在Java中創建了一個播放列表播放器,到目前爲止這麼好,我得到了所有邏輯,項目即將完成。我們一直在通過創建一些大型播放列表來測試播放,並讓它從開始到結束。播放聽起來不錯,但有時音頻在最後切斷。這很少發生。最後x秒(時間變化)不播放。

im測試的文件都是16位或24位採樣大小的PCM波形文件。 Im將Java聲音引擎與Java結合使用可以縮放mp3和ogg spi以支持其他類型的音頻文件。

到目前爲止,我已經記錄了幾次,我的第一個想法是該文件可能已損壞,情況並非如此。我嘗試過自己播放這個文件,並且它完全播放了!

我試圖找到問題,但我只是無法找到它。我不認爲我的音頻播放器存在任何問題,即將失去想法。

這裏是我創造我的音頻輸入流:

public static AudioInputStream getUnmarkableAudioInputStream(Mixer mixer, File file) 
     throws UnsupportedAudioFileException 
{ 
    if (!file.exists() || !file.canRead()) { 
     return null; 
    } 

    AudioInputStream stream; 
    try { 
     stream = getAudioInputStream(file); 
    } catch (IOException e) { 
     logger.error("failed to retrieve stream from file", e); 
     return null; 

    } 

    AudioFormat baseFormat = stream.getFormat(); 

    DataLine.Info info = new DataLine.Info(SourceDataLine.class, baseFormat); 
    boolean supportedDirectly = false; 
    if (mixer == null) { 
     supportedDirectly = AudioSystem.isLineSupported(info); 
    } else { 
     supportedDirectly = mixer.isLineSupported(info); 
    } 

    // compare the AudioFormat with the desired one 
    if (baseFormat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED || !supportedDirectly) { 
     AudioFormat decodedFormat = new AudioFormat(
       AudioFormat.Encoding.PCM_SIGNED, 
       baseFormat.getSampleRate(), 16, baseFormat.getChannels(), 
       baseFormat.getChannels() * 2, baseFormat.getSampleRate(), 
       false); 

     // convert the audio format to the supported one 
     if (AudioSystem.isConversionSupported(decodedFormat, baseFormat)) { 
      stream = AudioSystem.getAudioInputStream(decodedFormat, stream); 
     } else { 
      logger.debug(
        "Audio format {} is not supported " 
          + "and can not be converted to default format", 
        baseFormat.toString()); 
      return null; 
     } 
    } 
    return stream; 
} 

這是我的音頻播放器螺紋:

final class PlayerThread extends Thread 
{ 

    private byte[] buffer; 

    /** 
    * Initialize the buffer 
    */ 
    public void initBuffer() 
    { 
     linelock.lock(); 
     try { 
      buffer = new byte[line.getBufferSize()/5]; 
     } finally { 
      linelock.unlock(); 
     } 
    } 

    public void run() 
    { 
     initBuffer(); 
     while (!isInterrupted()) { 
      checkState(); 

      // if the line is just cleared go to the start of the loop 
      if (line == null || isInterrupted()) { 
       continue; 
      } 

      write(); 
     } 

     // clean up all resources 
     close(); 

     // change the state 
     state = Player.State.STOPPED; 
    } 

    private void checkState() 
    { 
     if (state != Player.State.PLAYING) { 
      if (line != null) { 
       line.flush(); 
      } 

      try { 
       synchronized (this) { 
        this.wait(); 
       } 
      } catch (InterruptedException e) { 
       // reset the interupt status 
       interrupt(); 
      } 
     } 
    } 

    private void write() 
    { 
     // how much bytes could be written on the line 
     int available = line.available(); 

     // is the space on the line big enough to write the buffer to 
     if (available >= buffer.length) { 
      // fill the buffer array 
      int read = 0; 
      try { 
       read = audioStream.read(buffer, 0, buffer.length); 
      } catch (Throwable ball) { 
       logger.error("Error in audio engine (read)", ball); 
      } 

      // if there was something to read, write it to the line 
      // otherwise stop the player 
      if (read >= 0) { 
       try { 
        linelock.lock(); 
        line.write(buffer, 0, read); 
       } catch (Throwable ball) { 
        logger.error("Error in audio engine (write)", ball); 
       } finally { 
        linelock.unlock(); 
       } 
       bytesRead += read; 
      } else { 
       line.drain(); 
       MoreDefaultPlayer.this.stop(); 
      } 
     } 
    } 

    private void close() 
    { 
     // invoke close on listeners 
     invokePlayerClosedOnListeners(); 

     // destroy the volume chain 
     vc.removeVolumeListener(MoreDefaultPlayer.this); 

     // close the stream 
     try { 
      audioStream.close(); 
     } catch (IOException e) { 
      logger.error("failed to close audio stream"); 
     } 

     clearAllListeners(); 

     linelock.lock(); 
     try { 
      // quit the line 
      line.stop(); 
      line.close(); 
      line = null; 
     } finally { 
      linelock.unlock(); 
     } 
    } 
} 

正如你可以看到我後瀝乾行了,所以我不認爲問題是線路在播放流的所有內容之前關閉。
任何人都可以看到什麼可能是錯誤的這段代碼?

+0

您可以在'drain'之後檢查'line.isActive()'以查看是否所有輸出都已完成 –

+1

1)爲了更好地幫助您,請發佈[MCVE] mcve)(最小完整和可驗證示例)。 2)你可以嘗試使用更簡單的'剪輯'這個任務。 –

+0

嘿安德魯,我會盡我所能,但我似乎無法查明實際的錯誤。重現它的唯一方法是讓玩家實際跑完整整一天。 – Terraego

回答

0

我沒有看到明顯的答案,但有幾件事情會爲我提升黃旗。通常的做法是將line.write()方法放在while循環中,而不是重複調用它。通常不需要測試line.available()或處理鎖定行。如果行中沒有可用空間,則line.write()方法將處理必要的阻塞。我一直警告不要不必要地鎖定或阻止音頻線路。

鎖定邏輯是處理隊列序列的組成部分嗎?您正在描述的錯誤可能在該處理中。 (也許有一個與可用()相比的緩衝區大小的測試交互?是否大致等於緩衝區大小的截止量?)

我會考慮實現一個LineListener來宣告提示完成時,並使該事件成爲下一個提示的回放的觸發器。當給定文件完成時,可以發出STOP類型的LineEvent,通知處理隊列的任何句柄以繼續到下一個文件。

+0

感謝您關注此事,我以爲我錯過了一些顯而易見的事情。我刪除line.available()和il有些重構循環,我看看它是怎麼回事! – Terraego