我的 Java 應用程式需要一些幫助。它的目的是閱讀某個網站,所以我需要連續播放很多音頻檔案。JAR 是使用 Java 8 編譯的。我使用 Windows 11 和 Java 16.0.1 測驗了我的應用程式,一切正常。然后我使用了最新的 Ubuntu Linux 和 Java 11.0.13 以及 Java 8:它播放一些音頻,但不是每個檔案。
我寫了一個測驗類,結果是——無論我以什么順序播放音頻——只播放第一個(完全正確!)62個檔案。每個下一個檔案(即使是最初成功播放的檔案)都會產生我的代碼在此位置拋出的例外:
if (mixerSelected != null) {
audioClip0 = AudioSystem.getClip(mixerSelected);
} else {
throw new IllegalArgumentException("File is not compatible: '" audioFilePath "'.");
}
我確保每個音頻檔案都.WAV帶有
- 8k 采樣率,
- 平均每秒 16k 位元組,
- 16 位,和
- pcm_s16le 編解碼器。
我的應用程式構建為 JAR 檔案,包括資源目錄中的音頻檔案。
這是我的代碼:
public class PlayAudio {
/**
* plays an audio file
*
* @param audioFilePath String: path to the audio file
* @param speed double: speed applied to the audios
*/
public boolean singleFile(String audioFilePath, double speed) {
//audioFilePath = "audio" File.separator audioFilePath;
audioFilePath = "audio" "/" audioFilePath;
AudioInputStream audioStream0;
//create new file using path to the audio
try {
//load files from resources folder as stream
ClassLoader classLoader = getClass().getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(audioFilePath);
InputStream bufferedInputStream = new BufferedInputStream(inputStream);
if (bufferedInputStream == null) {
throw new IllegalArgumentException("File not found: '" audioFilePath "'.");
} else {
//create new AudioStream
audioStream0 = AudioSystem.getAudioInputStream(bufferedInputStream);
}
} catch (IllegalArgumentException e) {
//handle
return false;
} catch (IOException e) {
//handle
return false;
} catch (UnsupportedAudioFileException e) {
//handle
return false;
}
try {
//create new AudioFormat
AudioFormat audioFormat0 = audioStream0.getFormat();
//create new Info
DataLine.Info info0 = new DataLine.Info(Clip.class, audioFormat0);
//initialize new Mixer
Mixer.Info mixerSelected = null;
for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) {
Mixer mixer = AudioSystem.getMixer(mixerInfo);
if (mixer.isLineSupported(info0)) {
mixerSelected = mixerInfo;
break;
}
}
//create new Clip
Clip audioClip0;
if (mixerSelected != null) {
audioClip0 = AudioSystem.getClip(mixerSelected);
} else {
//THIS EXCEPTION GETS THROWN!!!
throw new IllegalArgumentException("File is not compatible: '" audioFilePath "'.");
}
//open created Clips via created AudioStream
audioClip0.open(audioStream0);
//start the play of audio file
audioClip0.start();
//wait until play completed
double waitTime = (double)((((double)audioClip0.getMicrosecondLength()/1000.0)/speed 50.0) * 0.8);
Thread.sleep((long)waitTime);
return true;
//handle exceptions
} catch (LineUnavailableException e) {
//handle
return false;
} catch (IOException e) {
//handle
return false;
} catch (InterruptedException e) {
//handle
return false;
} catch (IllegalArgumentException e) {
//THIS EXCEPTION GETS THROWN!!!
//handle invalid audio clips
System.out.println(e);
e.printStackTrace();
return false;
}
}
/**
* plays multiple audio files in the order they are stored in an ArrayList
*
* @param fileNames ArrayList<String>: list with filenames of audio files to play
* @param speaker String: speaker to use for playing the audios (can be 'm' or 'w')
* @param speed double: speed applied to the audios
* @return boolean: true if playing audios completed successfully, otherwise false
*/
public static boolean multiFiles(ArrayList<String> fileNames, String speaker, double speed) {
PlayAudio player = new PlayAudio();
//play every audio file in the array of file names
for (int i = 0; (i < fileNames.toArray().length); i ) {
//generate file names
String fullFileName = speaker "_" fileNames.toArray()[i];
//play audio
player.singleFile(fullFileName, speed);
}
return true;
}
}
我已經嘗試了什么?
- 我也在另一臺運行 Ubuntu Linux 的計算機上進行了嘗試。
PlayAudio()每次播放新音頻時,我都會創建一個新實體。- 我
audioClip0.stop();在每個音頻后使用。 - 我將每個音頻后的睡眠毫秒數增加到音頻長度加 1 秒。
- 我重建了專案......近 1k 次。
如何重現錯誤?
我只需要在 Linux Ubuntu 下播放超過 62 個運行我的 JAR 檔案的音頻檔案。
你怎么能幫助我?
我不知道如何處理這個問題。.WAV用 Linux播放檔案有什么問題?有沒有一種通用的方法來解決這個問題?(我不允許使用除 OracleJDK 和 OpenJDK 之外的任何庫。)
uj5u.com熱心網友回復:
#1 的建議是由 Mark Rotteveel 提出的。AudioInputStream課程需要關閉。這通常會讓人們感到驚訝,因為 Java 以管理垃圾收集而聞名。但是因為AudioInputStream有些資源需要釋放。恕我直言,API 沒有充分指出這一點,但可以從AudioInputStream.close()方法的描述中推斷出需要處理:
關閉此音頻輸入流并釋放與該流關聯的所有系統資源。
來自 Andrew Thompson 和 Hendrik 的第 2 條建議可能比直接解決方案更有幫助,但這仍然是一個非常好的主意,而且在我看來,所有額外的、不需要的基礎設施的低效率 ( ClassLoader, InputStream, BufferedInputStream) 可能會導致該問題。但我對底層代碼的理解真的不夠好,無法知道它的相關性。
但是,我認為你可以做得更好。不要使用Clip. 你目前的使用Clip違背了它的設計理念。Clips適用于要保存在記憶體中并多次播放的短時間聲音,而不是在每次播放之前重復重新加載的檔案。這種使用(加載和播放)的正確類是SourceDataLine.
SourceDataLine可以在javasound wiki中找到使用 a 播放的示例。這個例子還說明了使用URLfor 獲得必要的AudioInputStream. 我將在這里逐字參考。
public class ExampleSourceDataLine {
public static void main(String[] args) throws Exception {
// Name string uses relative addressing, assumes the resource is
// located in "audio" child folder of folder holding this class.
URL url = ExampleSourceDataLine.class.getResource("audio/371535__robinhood76__06934-distant-ship-horn.wav");
// The wav file named above was obtained from https://freesound.org/people/Robinhood76/sounds/371535/
// and matches the audioFormat.
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
AudioFormat audioFormat = new AudioFormat(
Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
SourceDataLine sourceDataLine = (SourceDataLine)AudioSystem.getLine(info);
sourceDataLine.open(audioFormat);
int bytesRead = 0;
byte[] buffer = new byte[1024];
sourceDataLine.start();
while((bytesRead = audioInputStream.read(buffer)) != -1)
{
// It is possible at this point manipulate the data in buffer[].
// The write operation blocks while the system plays the sound.
sourceDataLine.write(buffer, 0, bytesRead);
}
sourceDataLine.drain();
// release resources
sourceDataLine.close();
audioInputStream.close();
}
}
您將不得不進行一些編輯,因為該示例被設定為通過main方法運行。此外,您將使用您的音頻格式,并且音頻檔案的名稱及其檔案夾位置必須與您在getResource()方法中使用的引數中指定的相對或絕對位置相匹配。buffer此外,可能首選更大尺寸的陣列。(我經常用8192)。
但最重要的是,請注意,在此示例中,我們關閉了SourceDataLine和AudioInputStream。使用 try-with-resources 的替代建議是一個很好的建議,并且也會釋放資源。
如果在更改上述內容以適應您的程式時遇到困難,我相信如果您向我們展示您的嘗試,我們可以幫助使其作業。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/413125.html
標籤:
