Получение ошибки при остановке аудиоплеера в JMF

Недавно я задал вопрос об управлении громкостью аудиоклипа Java, и мне предложили попробовать JMF. Поскольку я использую старую JVM (1.4) и заинтересован только в воспроизведении файлов WAV, JMF был идеальным решением и значительно упростил код для загрузки, воспроизведения и управления громкостью аудиоклипов в моем приложении.

Но у меня возникли проблемы с остановкой клипов по запросу. Казалось бы, просто вызвать player.stop(), но stop() блокируется до тех пор, пока игрок не закончит играть. Вот простой пример кода:

Player p = Manager.createRealizedPlayer( f.toURI().toURL() );

p.start();
System.out.println( "Player playing" );

Thread.sleep( 1000 );
System.out.println( " Clip is at time: " + p.getMediaTime().getSeconds() );

p.stop();
System.out.println( " Clip is at time: " + p.getMediaTime().getSeconds() );

Это производит вывод как:

Player playing
 Clip is at time: 0.8591836730000001
 Clip is at time: 3.227619047

Где я ожидал, что второй раз будет читаться так же или ненадолго позже, чем первый. (Или, возможно, был сброшен на 0 или что-то в этом роде.) Я также пробовал p.setStopTime( p.getMediaTime() ). Это останавливает клип вовремя, но воспроизводит доли секунды искажения перед остановкой, что нежелательно.

Поиск в Google заставляет меня думать, что у других нет этой проблемы, и было довольно сложно найти варианты. Может ли это быть проблема с буферизацией или я что-то упустил? Любое понимание, которое вы можете предоставить, очень ценится.


Подробности: я использую (и не могу изменить) JVM 1.4.2 с JMF 2.1.1. Все мои файлы WAV имеют длину всего 1-10 секунд.


person Clayton    schedule 09.11.2009    source источник
comment
На самом деле это похоже на буферизацию. Любой WAV длиннее 4 с будет немедленно остановлен, в то время как воспроизводится все, что меньше 4 с. Все еще расследуют...   -  person Clayton    schedule 11.11.2009


Ответы (2)


И действительно, это была проблема с буферизацией. Мне потребовалось некоторое время, чтобы найти это, потому что, когда я пытался отобразить доступные элементы управления с помощью следующего фрагмента кода, в списке не было элементов BufferControls:

Player p = ...
Control cs[] = p.getControls();
for ( int j = 0; j < cs.length; j++ )
  System.out.println( "  Found control: " + cs[j].getClass().getCanonicalName() );

В конце концов я только что сделал слепую попытку получить BufferControl с помощью этого фрагмента, и это сработало:

BufferControl bc = (BufferControl) p.getControl( "javax.media.control.BufferControl" );

После изучения и возни еще немного выяснилось, что длина буфера по умолчанию составляет 2 секунды. Уменьшение длины буфера до 1 секунды позволило мне корректно останавливать WAV-файлы длительностью 2,5 секунды и более. Дальнейшее уменьшение его до 0,5 секунды в конечном итоге дало мне поведение, которое я изначально искал во всех моих входных файлах.

Не глядя на источник JMF, я предполагаю, что я просто столкнулся с проблемой, когда звук считывался и воспроизводился 2-секундными фрагментами (2 секунды - это длина буфера). и что эти фрагменты должны были закончить воспроизведение -- по какой-то причине -- до того, как их удалось остановить. Уменьшение его до 0,5 секунды может на самом деле не решить проблему (если звуки продолжают воспроизводиться после того, как им приказано остановиться), но это, по крайней мере, уменьшит проблему до такой степени, что она будет незаметной. Кроме того, все мои WAV-файлы небольшие и локальные, поэтому задержка или пропуски при воспроизведении не должны быть проблемой.

В конце концов, вот пересмотр фрагмента кода из исходного вопроса, который приводит к желаемому поведению:

Player p = Manager.createRealizedPlayer( f.toURI().toURL() );

BufferControl bc = (BufferControl) p.getControl( "javax.media.control.BufferControl" );
if ( bc != null )
  bc.setBufferLength( 500 ); // buffer length specified in milliseconds

p.start();
System.out.println( "Player playing" );

Thread.sleep( 1000 );
System.out.println( " Clip is at time: " + p.getMediaTime().getSeconds() );

p.stop();
System.out.println( " Clip is at time: " + p.getMediaTime().getSeconds() );
person Clayton    schedule 11.11.2009

У меня тоже была эта проблема только с короткими аудиофайлами. Установка буфера не помогла. Я закончил тем, что добавил тишину к звуку в дерзости.

Я ненавижу ЖМФ :)

Редактировать: Ну, JMF также блокирует вызовы GainControl.setLevel(), когда у вас есть короткий аудиофайл. Я предполагаю, что корень проблемы тот же, JMF просто блокирует ваш запрос (установить громкость, остановить) до тех пор, пока короткий файл не будет завершен.

person Gazihan Alankus    schedule 27.04.2011
comment
То же самое происходит, когда у вас есть длинный файл, но вы ограничиваете его продолжительность с помощью Player.setStopTime(). Когда он приближается к концу воспроизведения примерно на одну секунду, он начинает блокировать звонки. Изменение размера буфера мне не помогло. Будет продолжать публиковать. - person Gazihan Alankus; 03.05.2011