歌曲第一次播放但停止后不播放:Java 中的剪辑
Posted
技术标签:
【中文标题】歌曲第一次播放但停止后不播放:Java 中的剪辑【英文标题】:Song plays first time but does not play once stopped : Clip in Java 【发布时间】:2012-04-03 19:23:07 【问题描述】:我在java中使用Clip播放歌曲如下:
MR.clip= (Clip) Audiosystem.getLine(MR.info[docIdOfSelectedSong]);
MR.clip.open(MR.sounds[docIdOfSelectedSong]);
MR.clip.setMicrosecondPosition(5* 1000000);
MR.clip.start();
其中 MR.sounds 是 AudioInputStream
类型的数组,MR.info 是 DataLine.info
类型的数组。当我按下一个按钮时,上面的代码被调用来播放歌曲。此外,我还有另一个按钮来停止调用以下代码的歌曲
public static void stopSong()
MR.clip.close();
问题是当我第一次播放歌曲时,播放和停止按钮工作正常。但是,当我第二次尝试播放这首歌时,我听不到这首歌。对出了什么问题有任何建议吗?
【问题讨论】:
【参考方案1】:与所有其他 InputStream 一样,AudioInputStream 只能读取一次(除非它可以是 .reset())。在尝试再次播放声音之前,您可以尝试在 AudioInputStream 上调用 .reset(),但 AudioInputStream 可能不支持 .reset()。 InputStreams 不需要支持重置。另见markSupported()。
如果 .reset() 不起作用,请考虑在每次需要开始播放时构造一个新的 AudioInputStream。
更新:我做了一个在内存中缓存声音数据并使用 Clip 播放这些声音的示例。此示例使用 AudioInputStream.reset()。那怎么能行呢?事实上,AudioInputStream确实支持reset()当且仅当它的底层InputStream支持.reset()。因此,我的示例创建了一个由 ByteArrayInputStream 支持的 AudioInputStream。因为ByteArrayInputStream支持reset,所以这些缓存的AudioInputStreams也支持.reset(),可以重复使用。
请注意,如果您要同时播放任何一个缓存的声音,您可能不应该缓存AudioInputStream
s,而是缓存byte[]
s 并构造一个AudioInputStream
每次播放。这是因为AudioInputStream
是有状态的,因此将它的单个实例传递给两个同时运行的剪辑,或在播放一个剪辑时重置流,将导致状态冲突。
public class CachedSoundClipTest
static ArrayList<AudioInputStream> cachedSounds =
new ArrayList<AudioInputStream>();
public static void main(String[] args) throws Exception
File[] audioFiles = new File("/audio_storage_directory").listFiles();
for (File file : audioFiles)
AudioInputStream reusableAudioInputStream =
createReusableAudioInputStream(file);
cachedSounds.add(reusableAudioInputStream);
while(true)
System.out.println("Press enter to play next clip");
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
br.readLine();
playCachedSound(0);
private static void playCachedSound(int i)
throws IOException, LineUnavailableException
AudioInputStream stream = cachedSounds.get(i);
stream.reset();
Clip clip = AudioSystem.getClip();
clip.open(stream);
clip.start();
private static AudioInputStream createReusableAudioInputStream(File file)
throws IOException, UnsupportedAudioFileException
AudioInputStream ais = null;
try
ais = AudioSystem.getAudioInputStream(file);
byte[] buffer = new byte[1024 * 32];
int read = 0;
ByteArrayOutputStream baos =
new ByteArrayOutputStream(buffer.length);
while ((read = ais.read(buffer, 0, buffer.length)) != -1)
baos.write(buffer, 0, read);
AudioInputStream reusableAis =
new AudioInputStream(
new ByteArrayInputStream(baos.toByteArray()),
ais.getFormat(),
AudioSystem.NOT_SPECIFIED);
return reusableAis;
finally
if (ais != null)
ais.close();
【讨论】:
是的,不支持重置。考虑构建一个新的 AudioInputStream 是什么意思?你能给我一个使用 CLip 的例子吗 如何创建 AudioInputStreams 开始?只需再次执行初始化 AudioInputStream[] 数组的操作即可。但请在播放剪辑之前执行此操作。 哦!我以为我可以在程序开始时读取 AudioInputStream 并继续重复使用它 是的,这就是我想说的。 “AudioInputStream 只能读取一次”也表示“AudioInputStream 只能使用一次”,也表示“不能重复使用”。 @Programmer 我用可重用缓存 AudioInputStreams 的工作示例更新了我的答案【参考方案2】:诀窍是将剪辑的当前位置重置为开始。
clip.stop();
clip.setMicrosecondPosition(0);
clip.start();
使用这种方法,不需要多次加载同一个资源。剪辑应该只加载一次并存储为实例变量或其他东西。
【讨论】:
【参考方案3】:在您的代码示例中,使用 Clip,您应该使用 stop() 方法而不是 close() 方法。然后,当您重新启动时,它将从上次中断的地方继续。如果你想从头开始,那么你可以使用 setMicrosecondPosition() 或 setFramePosition() 为 0,然后使用 start()。
有关详细信息,请参阅以下教程中的“使用剪辑”!
http://docs.oracle.com/javase/tutorial/sound/playing.html
SourceDataLine 只能使用一次,不能重置。是吗?
【讨论】:
【参考方案4】:我在 OS X 上遇到过类似的问题,如果您在播放时尝试停止剪辑,然后从头开始重新启动,有时无法播放剪辑。它是通过在stop()
之后调用flush()
修复的:
if(clip.isActive() || clip.isRunning())
clip.stop();
clip.flush();
绝对不要使用close()
,如果您想再次播放您的剪辑,请使用stop()
。
【讨论】:
以上是关于歌曲第一次播放但停止后不播放:Java 中的剪辑的主要内容,如果未能解决你的问题,请参考以下文章
如何在 android 的 mediaplayer 中停止和播放新歌曲?
在播放 iOS 中的下一首歌曲之前,我是不是需要先停止 MusicPlayerController?