Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I have problem with mp 3 player. I'm using jLayer.
This is my code
private void formWindowOpened(java.awt.event.WindowEvent evt) {
new Thread (){
public void run(){
try
{
Player prehravac;
FileInputStream buff = new FileInputStream(Okno.filename);
prehravac = new Player(buff);
prehravac.play();
if (prehravac != null)
{
prehravac.play();
}
}
catch(Exception e)
{
}
}
}.start();
}
In my application I need to play song from the beginning to the end. So when song ends I need to start it again and when window closes I want to stop this song...
JLayer does not support continuous play, so you have to use a loop to repeatedly start a new player after the old one finished. For example:
try
{
do
{
FileInputStream buff = new FileInputStream(Okno.filename);
prehravac = new AdvancedPlayer(buff );
prehravac .play();
}while(loop);
}
catch(Exception ioe)
{
//TODO error handling
}
with loop being a boolean you can set true or false in a different method depending on if you want it to be played just once or repeatedly.
If you want to access the thread later you should at least declare it to a variable. Even better is writing a seperate class that extends thread. Doing so you can add method to the thread you can later call.
For your code it might look something like that:
import java.io.*;
import javazoom.jl.player.*;
public class MyAudioPlayer extends Thread {
private String fileLocation;
private boolean loop;
private Player prehravac;
public MyAudioPlayer(String fileLocation, boolean loop) {
this.fileLocation = fileLocation;
this.loop = loop;
}
public void run() {
try {
do {
FileInputStream buff = new FileInputStream(fileLocation);
prehravac = new Player(buff);
prehravac.play();
} while (loop);
} catch (Exception ioe) {
// TODO error handling
}
}
public void close(){
loop = false;
prehravac.close();
this.interrupt();
}
}
With this you can simply create the Thread when and wherever you want like this:
private MyAudioPlayer thePlayer;
[... some class code here...]
public void yourMethod(){
thePlayer = new MyAudioPlayer("path of the music file", true);
thePlayer.start();
}
and if you want to get rid of it at some point call thePlayer.close();
Note that thePlayer should be an instance variable so you can reuse it again. If you only declare it within a method it will disappear after the method is finished.
Hope this helps.
Related
I am trying to make a text to speech thread stop whenever the talk(String text, boolean voiceEnabled) method is called from an ActionEvent using buttons.
When these buttons are pressed different text Strings are passed to the method, which runs the audio on a new thread. If the current thread is still running but a new ActionEvent occurs I need the current thread to stop (i.e the text-to-speech) so that the new text-to-speech audio can be played without the current audio clip and new clip playing over the top of eachother.
This is what I currently have but the TTS audio are playing over the top of eachother. I need the current TTS to stop as soon as a new TTS is triggered. I believe my main problem is that a new Thread is being made each time the method is called.
Any help greatly appreciated. Thanks!
public void talk(String text, boolean voiceEnabled) {
System.out.println(text);
// Create a new Thread as JLayer is running on the current Thread and will
// make the application lag
Thread thread = new Thread(() -> {
try {
// Create a JLayer instance
AdvancedPlayer player = new AdvancedPlayer(synthesizer.getMP3Data(text));
if (voiceEnabled) {
player.play(); //Plays the TTS audio
System.out.println("Successfully retrieved synthesizer data");
}
else {
}
} catch (IOException | JavaLayerException e) {
e.printStackTrace();
}
});
// We don't want the application to terminate before this Thread terminates
thread.setDaemon(false);
// Start the Thread
thread.start();
}
You appear to be burying key references inside of anonymous inner classes, and I don't see how you can get to them when and if needed. Why do this? Why not create an instance of a non-anonymous class, one with an AdvancedPlayer field, one whose reference is held by some collection, perhaps a List<...> or a HashMap, or by a variable if only one to two are running, where you can extract the object, get its AdvancedPlayer field and call .stop() on it?
e.g.,
public class RunnablePlayer implements Runnable {
private AdvancedPlayer player;
private String text;
private boolean voiceEnabled;
public RunnablePlayer(String text, boolean voiceEnabled) {
this.text = text;
this.voiceEnabled = voiceEnabled;
}
#Override
public void run() {
try {
// Create a JLayer instance
player = new AdvancedPlayer(synthesizer.getMP3Data(text));
if (voiceEnabled) {
player.play(); //Plays the TTS audio
System.out.println("Successfully retrieved synthesizer data");
}
} catch (IOException | JavaLayerException e) {
e.printStackTrace();
}
}
public AdvancedPlayer getPlayer() {
return player;
}
public void stop() {
// perhaps do a null check here first?
if (player != null) {
player.stop();
}
}
}
Then you could have a field of the class, something like:
// field of the class
private RunnablePlayer runnablePlayer;
and use this in your talk method:
public void talk(String text, boolean voiceEnabled) {
if (runnablePlayer != null) {
runnablePlayer.stop(); // not calling this on a Thread
}
runnablePlayer = new RunnablePlayer(text, voiceEnabled);
Thread thread = new Thread(runnablePlayer);
//.....
thread.start();
}
Code not compiled or tested, but is presented to just give a general idea.
Due to the fact that in almost every question regarding the use of Thread.sleep it is mostly indicated to use it only in certain situations, I come to ask you if it is correct to use it in my case or if there is a better way to do it.
The operating system is Linux(Debian), in which a bash script is running that is detecting when a device (more specifically, a storage device) is inserted/removed, and then writes into a FIFO a string under the type "ADD {path-to-dev}" or "REM {path-to-dev}".
I created a small app in java which makes use of two threads. The first thread will call upon a read method that parses the String to the standard output, after which it will wait(). The second thread will check if the FIFO is empty or not and then, when it sees that a String has been inserted then it will call notify() so the other thread will print the String in there and so on. Inside the loop where it checks if the FIFO has data or not, I call Thread.sleep(1000), and I am unsure whether this is a good approach or not. I will present the code which handles all the action.
First, the class which has the methods of reading:
public class Detect {
private File file;
private BufferedReader read;
private volatile boolean readable;
private static String readFromFile;
public Detect() throws FileNotFoundException {
file = new File("/hardware_stuff/hardware_events");
read = new BufferedReader(new FileReader(file));
readable = true;
}
synchronized String readFromFifo() {
while (!readable) {
try {
wait();
} catch (InterruptedException ex) {
System.out.println("Interrupted during the wait for read.");
}
}
try {
while (read.ready()) {
readFromFile = read.readLine();
}
} catch (IOException ex) {
System.out.println("Error in reading from FIFO.");
}
readable = false;
notify();
return readFromFile;
}
synchronized void waitForFifo() {
while (readable) {
try {
wait();
} catch (InterruptedException ex) {
Logger.getLogger(Detect.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
while (!read.ready()) {
Thread.sleep(1000);
System.out.println("Sleeping due to lack of activity in FIFO in thread : " + Thread.currentThread().getName());
}
} catch (IOException | InterruptedException ex) {
Logger.getLogger(Detect.class.getName()).log(Level.SEVERE, null, ex);
}
readable = true;
notify();
}}
Next, the thread which will read from it.
public class ReadThread extends Thread {
Detect detect;
private boolean shouldBeRunning;
public ReadThread(Detect detect) {
this.detect = detect;
shouldBeRunning = true;
}
#Override
public void run() {
while (shouldBeRunning) {
String added = detect.readFromFifo();
System.out.println(added);
}
}
public void stopRunning() {
shouldBeRunning = false;
}}
Finally, the thread which will check if the FIFO is empty or not.
public class NotifyThread extends Thread {
Detect detect;
private boolean shouldBeRunning;
public NotifyThread(Detect detect) {
this.detect = detect;
shouldBeRunning = true;
}
#Override
public void run() {
while (shouldBeRunning) {
detect.waitForFifo();
}
}
public void stopRunning() {
shouldBeRunning = false;
}}
In main I just create the threads and start them.
Detect detect = new Detect();
NotifyThread nThread = new NotifyThread(detect);
ReadThread rThread = new ReadThread(detect);
nThread.start();
System.out.println("Started the notifier thread in : " + Thread.currentThread().getName());
rThread.start();
System.out.println("Started the reading thread in : " + Thread.currentThread().getName());
Is there any alternative to calling sleep or another approach I can take to replace the sleep with something else? I have already read other questions related to this topic and I am still uncertain/have not understood whether this sort of case is indicated for sleep or not.
UPDATE: As #james large said, there was no need to poll for ready. I was not aware that if there is no line, the readLine() will 'sleep' and there was no need to poll it after all. I removed the notifier thread, and I simply kept the ReadThread which will call the Detect readFromFifo() method and it all works good. #dumptruckman, thanks for the suggestion. Although it doesn't apply to my case, I didn't know of the WatchService and it was a good read, good stuff to know. #Nyamiou The Galeanthrope, the timer would have been useful, but as I already said, I only keep one thread to execute the same method and it works as intended.#Krzysztof Cichocki, thanks for pointing out there are issues. I was aware of that, otherwise I wouldn't have asked this question.
I'm new to Java so sorry if the problem is trivial. My code is probably a mess. I created a online radio player for Raspberry Pi in Java and I have to do a POST request every 10 seconds to check what is the current song playing and if the song has changed, I have to do some things (like scrobble old song, update display with new song data, store play session to my server etc.). I created a class for this:
public class Scrobbler implements Runnable, Commands, Observer {
private TimeCounter counter;
private Timer timer;
private Radio radio;
private List<Observer> observers;
private final Object MUTEX= new Object();
private int currentPlaySession;
// And all other variables which I deleted before posting
// Constructor
public Scrobbler(TimeCounter _counter, Radio _radio)
{
currentTrack = null;
counter = _counter;
radio = _radio;
timer = null;
observers = new ArrayList<>();
currentPlaySession = 0;
}
private void GetInfo()
{
// POST request to get current song playing
// If song has changed, notify observers
}
public void Scrobble()
{
// POST request - Scrobble song to my website and last.fm
}
public void StartPlaySession()
{
// Again POST request to my website
}
public void EndPlaySession()
{
// Again POST request to my website
}
#Override
public void start() {
new Thread(this).start();
}
public void stop()
{
timer.cancel();
timer.purge();
timer = null;
}
#Override
public void register(Observer obj) {
if(obj == null) throw new NullPointerException("Null Observer");
synchronized (MUTEX) {
if(!observers.contains(obj)) observers.add(obj);
}
}
#Override
public void unregister(Observer obj) {
synchronized (MUTEX) {
observers.remove(obj);
}
}
#Override
public void notifyObservers(String command) {
for (Observer obj : observers) {
obj.update(command);
}
}
#Override
public void run() {
timer = new Timer();
timer.schedule(new TimeOut(), 0, 10000);
GetInfo();
StartPlaySession();
}
public class TimeOut extends TimerTask
{
#Override
public void run() {
EndPlaySession();
GetInfo();
}
}
#Override
public void update(String command) {
if ("RADIO_STARTED".equals(command))
{
this.start();
}
if ("RADIO_STOPPED".equals(command))
{
this.stop();
if (this.currentTrack != null && this.counter.getTrackTime() >= 60)
this.Scrobble();
EndPlaySession();
}
}
private void handleException(String message)
{
try {
String timeStamp = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("/home/pi/OnlineRadio/error_log.txt", true)));
out.println("(" + timeStamp + ") [SCROBBLER] - " + message + "\n\n\r");
out.close();
} catch (IOException e) {}
this.stop();
this.start();
}
}
I create a new instance of Scrobbler in my main method and register it as an observable to player. Once I start the radio, player will notify its observers (including instance of Scrobbler class) by calling update() method and forward "RADIO_STARTED" or "RADIO_STOPPED" (after starting or stopping the radio). As you can see in code, on RADIO_STARTED, a start() method is called where new Thread is started. Starting a new thread is probably unnecessary here since it only starts the timer but it shouldn't be a problem neither. After starting the timer, every 10 seconds method run() in class TimeOut will be called which then calls necessary methods.
This code works but sometimes it just stops for no reason. All other parts of application continue to work (music is still playing, application reacts on buttons etc.), just it doesn't update the song and there's no communication with my website at all so not even one of these methods is called, just like the timer stopped. When I stop and start the radio again or change the station, it works again (as you can see in code, the timer will be stoped every time the radio stops and the timer will start everytime the radio starts), but it will break again after some time.
Since I have a lot of try-catch blocks in those methods with POST requests, at first I thought that there must be an exception occuring and killing the timer thread so I created the handleException() method which logs exception message to a file and restarts this timer (you can see in code), and then I handle exceptions like this, for example:
try {
writer.close();
} catch (IOException e) {
this.handleException(e.getMessage());
}
But when the problem occured again, log file was empty, which means that not even one exception occured. I also tried to log all the data everytime the song changes and everything is fine, it just stops after a while for no reason. And I can't find a regularity in occuring, sometimes it occurs after a few minutes and sometimes if works for hours before it breaks.
This app runs on Raspberry Pi model B, and I don't know if this means something, but it's in JAR and it starts with the Pi (via cron #reboot) since I don't have any monitor nor keyboard/mouse on this Pi, so the app must start with it and run in background all the time. And I use SSH to transfer the JAR to Pi and to read log files.
Somewhere I read that it's not uncommon for the Java timer to stop without any reason. But how to solve this?
I just started using the Jlayer library to play MP3s. It works perfectly and I can play the song. My only problem is implementing pause and resume methods. With my limited amount of knowledge about multithreading, I though that making the thread where I play the MP3 wait, the sound would stop and in order to resume the song I would just have to notify the thread. Here is what I got:
import java.util.Scanner;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import javazoom.jl.player.Player;
public class MP3 extends Thread{
private String filename;
private Player player;
private Thread t;
private volatile boolean continuePlaying = true;
// constructor that takes the name of an MP3 file
public MP3(String filename) {
this.filename = filename;
}
public void close() { if (player != null) player.close(); }
// play the MP3 file to the sound card
public void play() {
try {
FileInputStream fis = new FileInputStream(filename);
BufferedInputStream bis = new BufferedInputStream(fis);
player = new Player(bis);
}
catch (Exception e) {
System.out.println("Problem playing file " + filename);
System.out.println(e);
}
}
public void run() {
play();
try {
while (true) {
synchronized(this) {
while(!continuePlaying)
wait();
player.play();
}
}
}
catch (Exception e) {
System.out.println(e);
}
}
private void pause() throws InterruptedException{
System.out.println("Pause");
continuePlaying = false;
}
private void resumeSong() throws InterruptedException{
synchronized(this) {
System.out.println("Resume");
continuePlaying = true;
notify();
}
}
// test client
public static void main(String[] args) throws InterruptedException{
String filename = ("Fall To Pieces.mp3");
MP3 mp3 = new MP3(filename);
mp3.start();
Scanner s = new Scanner(System.in);
s.nextLine();
mp3.pause();
s.nextLine();
mp3.resumeSong();
try {
mp3.join();
} catch (Exception e){
}
}
}
For some reason, however, wait() doesn't do anything and the program doesn't even reach notify(). Why is this happening?
I've read the previous SO questions about this, but I haven't been able to make them work. I am also interested in learning why this code doesn't work so I can further understand multithreading. Thank you!
It's late here so pardon me if I read your code wrong. But as far as I see it, you start your thread with continuePlaying = true; and the run method just calls play(); no initialize the new player and then straight enters a while (true) loop wich has to exit point. continuePlaying can't be changed by that thread still stuck in it's endless loop and even if you start another MP3 thread to access the volatile variable, it will enter the same loop before being able to change anything. Therefore wait() will never be reached.
Later on you are trying to notify() your waiting thread from within itself. Which is a bit of a paradoxon because it is waiting to be notified and in that state of waiting doing nothing, let alone notifying itself. It simply can't do anything until notified, that includes notifying itself or others. What I am trying to say is, that you should handle wait() but especially notify() from outside the thread that is being adressed/waiting.
Additionally your player.play(); is in an odd position. At the moment the player should only start playing after the thread has been paused(waited) at least once because it is behind the while(!continuePlaying) condition.
So for your case i'd rater go with methods in a different thread (or even the main thread for your tests) which call a wait() and notify() on and synchronized over the thread in question.
Tons of JProgressBar questions on here I know, but through all the answers and I can't seem to diagnose my issue. I am processing a file with some address verification software. I click the Process button and I need my JProgressBar to update with each file processed.
Here is the button:
private JButton getJButton0() {
...
jButton0.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
jButton0ActionActionPerformed(event);
t.start();
}
...
Per everybody's recommendation, I used the setValue() method within a thread
Thread t = new Thread(){
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jProgressBar0.setValue(BulkProcessor.getPercentComplete());
}
});
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
...
BulkProcessor.getPercentComplete() is a method I'm calling from another class which represents the percentage complete. I have tested this method and it updates correctly. The issue is that the progress bar will not update until the files are finished processing, and then it will jump to 100%. I apologize if this is a repeat question, but I have done some serious digging on this site with no luck. Any help much appreciated.
Edit:
Per recommended duplicate, I tried this:
public void update(){
new SwingWorker<Void,Void>() {
protected Void doInBackground() throws Exception {
jProgressBar0.setValue(BulkProcessor.getPercentComplete());
return null;
};
}.execute();
}
And then tried calling this update() method under the actionPerformed() (switched t.start() with update()). I am still having the same issue.
Edit
Based on user1676075's recommendation, however same issue:
public static void update(){
new SwingWorker<Void,Integer>() {
protected Void doInBackground() throws Exception {
do
{
percentComplete = BulkProcessor.getPercentComplete();
publish(percentComplete);
Thread.sleep(100);
} while(percentComplete < 100);
return null;
}
#Override
protected
void process(List<Integer> progress)
{
jProgressBar0.setValue(progress.get(0));
}
}.execute();
}
Edit
Here is the code from my BulkProcessor class
private String getOutputLine( String searchString, String inputLine )
throws QasException
{
..(code for processing lines)..
countRecord++;
percentComplete = (int) Math.round((countRecord/totalRecord)*100);
totalRecord is updated in the main class of my BulkProcessor class
public static void main( String input, String output ){
count.clear();
try{
String inputFile = input;
String outputFile = output;
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(input)));
lnr.skip(Long.MAX_VALUE);
totalRecord = lnr.getLineNumber() + 1; //line count in file
BulkProcessor bulk = new BulkProcessor(inputFile, outputFile, ConfigManager.DFLT_NAME);
bulk.process();
}catch(Exception e ){
e.printStackTrace();
}
}
Looks like you're mixing usages. See the SwingWorker documentation, example at the top: http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html.
Ideally you'd update your BulkProcessor in the doInBackground method of the SwingWorker, and that would call setProgress, and the jProgressBar would be listening for those progress updates as in the example.
If that won't work for you, which it seems like it won't just based on the above, start a SwingWorker from the button press event. Implement the SwingWorker methods kinda like this (pseudocode):
new SwingWorker<Void,Integer>()
{
doInBackground()
{
do
{
percentComplete = BulkProcessor.getPercentComplete();
publish(percentCompete);
Thread.sleep(100);
} while (percentComplete < 100);
}
#Override
process(List<Integer> progress)
{
jProgressBar0.setValue(progress.get(0));
}
}.execute();
You'll need to add error-handling and checks for complete and failure cases, but that should get you started and to where you want to be. doInBackground runs in a background thread so won't block anything, and process() runs on the swing worker thread so will post the updates.
The mistake you probably went on is calling the t.start(); after thejButton0ActionPerformed(event); which makes that after the action is performed the thread will start. Therefore the value of the progress bar is not updated as intended.
You need to start the thread in jButton0ActionPerformed(event); and then update the value in it.
Just a hunch, but...
percentComplete = (int) Math.round((countRecord/totalRecord)*100);
Are you sure this is not integer arithmetic? I don't know the type of totalRecord, so I can't say for sure.
I'd guess everything works fine, and just the progress is 0 all the time, until complete where it magically is 100. This is because an int divided by an int will not have fraction values (ie. 99/100 == 0, 100/100 == 1). This fits perfectly with the symptoms you are experiencing.
Try replacing the line above with:
percentComplete = (int) Math.round((countRecord/(double) totalRecord)*100);
to see it I'm right. :-)
Have you tried to use the PropertyChangeListener-interface?
The calculations will be done by the Swingworker-thread and the main-gui will implement this interface. Some example-code
#Override
public void actionPerformed(ActionEvent e) {
this.myButton.setEnabled(false);
MyWorkerThread thread = new MyWorkerThread(); //Data-processing
thread.addPropertyChangeListener(this.mainguiframe); //Separation of concern
thread.execute();
}
Using the "setProgress"-method of the swing-worker-thread the main-gui-thread will be notified if something has happend.
#Override
public void propertyChange(PropertyChangeEvent property) {
Integer currentValue = new Integer(0);
currentValue = (Integer) property.getNewValue();
this.progressBar.setValue(currentValue.intValue());
}
Swing is not thread-safe. This is not the best solution but perhaps it can help you. Please comment if there is somethin horrible wrong.