#java #audio #javasound
#java #Аудио #javasound
Вопрос:
Мое воспроизведение звука Java запускается с ошибкой, но звук не воспроизводится.
Я искал в Интернете, но он по-прежнему не работает D:
можете ли вы, пожалуйста, помочь мне понять мою проблему исправить?
если вам нужны какие-либо дополнительные детали, код, дампы, выходные данные, просто дайте мне знать.
Sound.java:
package com.itaysharon.questematic;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import com.itaysharon.questematic.enums.SoundOptions;
public class Sound {
public static Thread dj;
public static synchronized void playSound(final String url, SoundOptions mode) {
dj = new Thread(new Runnable() {
@Override
public void run() {
try {
AudioInputStream inputStream = AudioSystem.getAudioInputStream(new File("assets" File.separator url));
AudioSystem.getClip().open(inputStream);
AudioSystem.getClip().setFramePosition(0);
switch(mode) {
case Stop:
AudioSystem.getClip().stop();
break;
case Play:
AudioSystem.getClip().start();
break;
case Loop:
AudioSystem.getClip().loop(Clip.LOOP_CONTINUOUSLY);
break;
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
});
if (mode != SoundOptions.Stop) {
dj.start();
} else {
try {
AudioSystem.getClip().stop();
AudioSystem.getClip().close();
dj.interrupt();
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
SoundOptions.java:
package com.itaysharon.questematic.enums;
public enum SoundOptions {
Play, Loop, Stop;
}
Комментарии:
1. пожалуйста, поделитесь сообщением об ошибке
2. сообщения об ошибке нет, он просто не воспроизводит файл wav
3. чистая java и никаких специальных библиотек
4. самое смешное, что раньше это работало с тем же файлом wav…
5. Я исправил это для вас
Ответ №1:
Хорошо, после проверки вашего кода здесь и там были довольно мелкие вещи.
Прежде чем я начну, возможно, ваш код работал случайно один раз ранее и перестал работать впоследствии, обычно это происходит, когда поток плохо запрограммирован.
Проблема в том, что поток запускается и заканчивается до того, как аудиофайл получит возможность воспроизведения, потому что поток не знает, какой длины файл в этом случае.
И поскольку у меня нет полной логики поведения вашей программы, я сохраню вашу логику кода и добавлю несколько вещей, которые решают проблему как отдельный экземпляр. Кстати, я протестировал исправленный код, и он отлично работает как изолированный класс на моей машине.
Я бы упомянул ключевые моменты для решения. Речь идет о том, чтобы позволить потоку продолжаться во время воспроизведения звука, пока он не будет завершен слушателем.
audioLineClip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
... listen when audio is ended and close the line. to end the program.
}
});
и мы продолжаем наш поток в ожидании завершения звука
synchronized (dj) {
while (true) {
try {
dj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Теоретически вы могли бы использовать Thread.sleep(sometime)
alone без synchronized, но поскольку вы не знаете, как долго спать, поскольку вы не знаете, какой длины аудиофайл!
Итак, ваш окончательный код будет выглядеть так, я поместил решение в код с объяснением, включая дополнительные незначительные изменения с примечаниями:
import javax.sound.sampled.*;
import java.io.File;
/**
* By Maytham on 07-10-2016.
*/
public class Sound {
public static void main(String[] args) {
playSound("8k16bitpcm.wav", SoundOptions.Play);
}
// 1) make it private
private static Thread dj;
// 2) make it private and 3) SoundOptions should be final
private static synchronized void playSound(final String url, final SoundOptions mode) {
dj = new Thread(new Runnable() {
@Override
public void run() {
try {
AudioInputStream inputStream = AudioSystem.getAudioInputStream(
new File("assets" File.separator url));
// 4) declare AudioSystem in stead of using AudioSystem repeatedly
final Clip audioLineClip = (Clip) AudioSystem.getLine(
new Line.Info(Clip.class));
audioLineClip.open(inputStream);
audioLineClip.setFramePosition(0);
// 5) our line listener checks when audio is ended and stops the line
//this is full example, but you manipulated your way
audioLineClip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
LineEvent.Type type = event.getType();
if (type == LineEvent.Type.OPEN) {
} else if (type == LineEvent.Type.CLOSE) {
System.exit(0);
} else if (type == LineEvent.Type.START) {
} else if (type == LineEvent.Type.STOP) {
audioLineClip.close();
}
}
});
switch (mode) {
case Stop:
audioLineClip.stop();
break;
case Play:
audioLineClip.start();
break;
case Loop:
audioLineClip.loop(Clip.LOOP_CONTINUOUSLY);
break;
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
});
if (mode != SoundOptions.Stop) {
dj.start();
// 6) this keep the thread until some line listener change status
synchronized (dj) {
while (true) {
try {
dj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} else {
dj.interrupt();
// 7) you do not need this it is done by line listener
/*try {
AudioSystem.getClip().stop();
AudioSystem.getClip().close();
dj.interrupt();
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
}
}
}
Комментарии:
1. должен ли метод воспроизведения звука быть закрытым? Я вызываю его из другого класса
2. хорошо, тогда вы можете сделать его защищенным или общедоступным в зависимости от вашей структуры
3. поток — отличная вещь, но если мы не используем их правильно, мы можем сойти с ума, и это мир и искусство сами по себе
4. исправленный код работает с моим изолированным классом отладки, но не с «генератором»… Я должен реорганизовать свой код: (
5. 🙂 это жизнь программистов