嘿那里堆栈溢出。
我正在用Java创建一个播放列表播放器,到目前为止,一切顺利,我已经掌握了所有逻辑,并且该项目即将完成。我们一直在通过创建一些较大的播放列表来测试回放,只是让事情从头到尾进行下去。播放听起来不错,但有时音频会在最后被切断。这种情况很少发生。最后x秒(时间会有所不同)不会播放。
我正在测试的文件都是16或24位采样大小的PCM波形文件。我将Java声音引擎与Java zoom 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();
}
}
}
如您所见,我之后排空了线路,所以我不认为问题在于在播放流中的所有内容之前关闭了线路。
谁能看到此代码有什么问题吗?
最佳答案
我没有看到明显的答案,但是有几件事为我升起了黄旗。通常的做法是将line.write()方法放入while循环中,而不是反复调用它。通常不需要测试line.available()或处理锁定行。如果行上没有可用空间,则方法line.write()将处理必要的阻塞。我一直被警告不要不必要地锁定或阻塞音频线。
锁定逻辑是否是队列顺序处理中不可或缺的一部分?您正在描述的错误可能在该处理中。 (与缓冲区大小相比,也许与available()的测试存在交互作用?截止量是否大致等于缓冲区大小?)
我会考虑实现LineListener来宣布某个提示何时结束,并使该事件触发下一个提示的回放。给定文件完成后,可以发出STOP类型的LineEvent,通知处理队列的任何人继续进行下一个文件。
关于java - Java音频播放器最后剪切音频,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22986101/