I use Clips in a game. The clips play fine, but after some "shots", the following problem occurs
Exception in thread "PulseAudio Eventloop Thread" java.lang.IllegalStateException: drain failed
at org.classpath.icedtea.pulseaudio.EventLoop.native_iterate(Native Method)
at org.classpath.icedtea.pulseaudio.EventLoop.run(EventLoop.java:133)
at java.lang.Thread.run(Thread.java:724)
My code:
public static Clip[] sounds;
...
sounds = new Clip[3];
sounds[0] = getClip("gun.wav");
sounds[1] = getClip("click.wav");
sounds[2] = getClip("over.wav");
...
private void playSound(Clip clp) {
final Clip clip = clp;
Runnable soundPlayer = new Runnable() {
#Override
public void run() {
try {
if(clip.isActive() || clip.isRunning()) clip.stop();
clip.setMicrosecondPosition(0);
clip.start();
} catch (Exception e) {
e.printStackTrace();
}
}
};
new Thread(soundPlayer).start();
}
public void shoot() { //runs when space is clicked
if(canShoot) playSound(sounds[0]);
}
So I had a similar problem on OS X, where the clip was sometimes not playing if you tried to stop it and restart it from the beginning. I fixed it by calling flush() right after stop():
if(clip.isActive() || clip.isRunning()) {
clip.stop();
clip.flush();
}
You shouldn't need to spawn a background thread to interact with the Clip. The most commonly used methods of Clip, like "start" and "stop" operate asynchronously, meaning they do not block, so it should be okay to call them from the GUI/AWT/Swing thread.
This page has some reasonable examples:
http://www3.ntu.edu.sg/home/ehchua/programming/java/J8c_PlayingSound.html
I see you are using IcedTea and PulseAudio. You may experience different behavior when using javax.sound in this JVM, as opposed to the Oracle JVM, since the implementations of javax.sound are significantly different between these two products.
Related
I don't have any code to show in particular to link because this is quite a general question...you see, I made a small game applet with 8 AudioClip variables, and these were supposed to play every time a certain action was taken by the user. Ex: Player clicks = Shooting sound plays. The thing is, the moment I added these AudioClip files my program just freezes terribly and becomes borderline unplayable if the freezing is particularly bad.
The simple way I did it is here (From the book, actually)
AudioClip playerShooting;
playerShooting=getAudioClip(getDocumentBase(),"PlayerShooting.wav");
Then I would just use the following whenever the user clicked:
playerShooting.play():
My program worked smoothly before I added these wav files. They aren't even that long. Where did I go wrong here, and, how can I remove the random freezing?
EDIT:
This is the code I am running:
public void mouseClicked(MouseEvent e)
{
if(playerAlive)
{
timeShotsAfter=System.currentTimeMillis();
if((timeShotsAfter-timeShotsBefore)>=100)
{
if(shotIndex<10)
{
playerShooting(); //Here is where I call the function
shotFiredX[shotIndex]=currentX;
shotFiredY[shotIndex]=currentY;
shotSize[shotIndex]=20;
}
if(shotIndex<10)
shotIndex++;
else
shotIndex=0;
timeShotsBefore=System.currentTimeMillis();
}
else{}
toggleShooting=false;
}
}
This is the function:
public void playerShooting()
{
new Thread(
new Runnable() {
public void run() {
try {
playerShooting.play();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
I was having the same problem a while back. What I did to solve my problem was update to JDK 8. In previous JDK versions, audio files appear to have been an afterthought and can be buggy. If you are still having problems, JDK 8 has the ability to play mp3 files which are significantly smaller than wav (you may want to try this). Make sure you use sound.stop() when your clips are done as this might free up some memory.
Play the audio clip in another thread?
EDIT:
new Thread(
new Runnable() {
public void run() {
try {
playerShooting.play():
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
Edit:
I'm not quite sure if this part is correct:
getAudioClip(getDocumentBase(),"PlayerShooting.wav");
Try adding System.out.println(getDocumentBase()); to see whether the location is correct.
Is there any way/tool to control the threads running within a process on android platform, such as let some threads delay for a random time.
Background: I am a QA engineer. I'd like to see if some threads are forced to run slowly, what will happen to the whole app? I'd like to see other kind of errors rather than ANR. For multiple threading, if programmer doesn't use or use bad strategies to sync threads, some bugs might happen. So I want to do this kind of testing.
You only have to take care of the UIThread, well actually Android will take care of it for you. Taking that into account, try to don't do any intensive operation in this thread as you won't have full control of it (see activity lifecycle)
As long as the UIthread is fine, you won't notice a slow responding app, for the rest of threads I suggest you taking a look in different classes that will ease the task of communicating back with this UIThread;
Asynctask & Handlers, there are more options, but these two are the most important (imo)
The rest of threads, you can control them as you would in Java, even sleeping them if needed.
Let's see an example:
public class MapView extends SurfaceView implements Runnable{
Thread t = null;
SurfaceHolder holder;
boolean draw = false;
#Override
public void run() {
while (draw) {
if (!holder.getSurface().isValid())
continue;
Canvas c = holder.lockCanvas();
//Draw something
holder.unlockCanvasAndPost(c);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
void pause() {
draw = false;
try {
t.join(); // this will cause the main thread to wait for this one to
//finish and then it can safely access its data.
} catch (InterruptedException e) {
e.printStackTrace();
}
t = null;
}
void resume() {
draw = true;
t = new Thread(this);
t.start(); // This will look for our run method (this)
}
}
In this example, a normal Thread is used to control how/when and with what delay we draw. The resume and pause methods let us control that thread so we can stop drawing if the activity using it is in background and restart it when it comes back (Overriding onPause and onResume)
I have this Timer that is supposed to initiate various actions at 1 second intervals. It's a pretty simple idea that simulates a 5 second countdown (literally). At the start, a JLabel is updated to set its text to "5". Simultaneously, a little mp3 sound file plays that voices the number that the user sees on the screen. Then, one second later, the text is changed to "4" and a different mp3 plays that voices the number 4. And so on until we get to zero.
This all works, but I can't get the visual updating to synchronize precisely with the audio part. The mp3 always seems to play just slightly before the screen is updated. At first, I thought that I just needed to put a little extra silence at the beginning of each mp3 on a trial and error basis until things synched up. But no matter how much silence I prepend to each mp3, I still hear the audio before the screen updates. All that changes is the lag between each "one second" update.
Anyway, here is the code that I am working with. Can anyone help me get this to synchronize? Maybe I need a second timer? I'm not sure how that would work. Thanks in advance!
class Countdown extends JFrame implements ActionListener {
private Timer countdownTimer = new Timer(1000, this);
int countdownSeconds;
MyJFrame myFrame;
public Countdown(MyJFrame thisFrame) {
int countdownSeconds = 5;
countdownTimer.start();
myFrame = thisFrame;
}
#Override
public void actionPerformed(ActionEvent e) {
if (countdownSeconds == 0) {
myFrame.updateCountdown(myFrame, "Go");
SoundEffect.play("launch.mp3");
countdownTimer.stop();
} else {
myFrame.updateCountdown(myFrame, Integer.toString(countdownSeconds));
if (countdownSeconds == 5) {SoundEffect.play("five.mp3");}
if (countdownSeconds == 4) {SoundEffect.play("four.mp3");}
if (countdownSeconds == 3) {SoundEffect.play("three.mp3");}
if (countdownSeconds == 2) {SoundEffect.play("two.mp3");}
if (countdownSeconds == 1) {SoundEffect.play("one.mp3");}
countdownSeconds--;
}
}
}
public void updateCountdown(MyJFrame thisFrame, String numSec) {
lblCountdown.setText(numSec);
}
import java.io.FileInputStream;
import javazoom.jl.player.Player;
public class SoundEffect {
public static void play(String mp3File) {
try {
FileInputStream mp3_file = new FileInputStream(mp3File);
Player mp3 = new Player(mp3_file);
mp3.play();
}
catch(Exception e) {
System.out.println(e);
}
}
}
I highly doubt you will ever be able to sync those perfectly, but I can explain why the current approach will not work.
Swing components must be updated on the Event Dispatch Thread, as you do with the Timer. When you update the text of the label, it will schedule a repaint on the Event Dispatch Thread. Note the word schedule, and not perform.
However, the Event Dispatch Thread is currently busy playing your sound, so the actual repaint operation will only occur after you called mp3.play().
Now you could (if allowed, not sure about the threading rules for playing MP3's) try to play the mp3 on a different Thread (e.g. by using a secondary non-Swing timer). But since you never have full control over when the actual repaint is going to happen and only can control when the repaint is scheduled, the visual and auditive updates can still be out-of-sync.
The major part of the problem comes down to:
if (countdownSeconds == 5) {SoundEffect.play("five.mp3");}
..leading to..
public class SoundEffect {
public static void play(String mp3File) {
try {
FileInputStream mp3_file = new FileInputStream(mp3File);
Player mp3 = new Player(mp3_file);
mp3.play();
}
catch(Exception e) {
System.out.println(e);
}
}
}
Whoa! This is not the time to be loading the clips!
Instead they should be loaded before the timer ever starts. I think the file I/O is the real cause of the (perceptible) lag or delay.
I used following logic to load the sound from a different thread to load it while my game goes on.
Though it works for very small wav files, sometimes, I have to wait till it loads.
How can I make sure that it is loaded beforehand?
public class MusicPlayer implements Runnable {
String sound;
Player p;
public MusicPlayer(String sound)
{
this.sound = sound;
InputStream is = getClass().getResourceAsStream("/"+sound);
try
{
p = Manager.createPlayer(is, "audio/X-wav");
}
catch(Exception e)
{}
}
public void start()
{
Thread t = new Thread(this);
t.start();
}
public void run()
{
try
{
p.start();
}
catch(Exception e)
{}
}
}
Most reliable solution is to create a progress bar and wait for the sounds to get loaded, so this will keep the user entertained a little as he can see something moving
Try
t.setPriority(Thread.MAX_PRIORITY);
Just in case anybody needs it, The best way I found is actually initialize the object in Main thread itself. If not the fastest, it will be the most reliable solution.
You could add a delay I.E Thread.sleep(100); this will delay the thread for 100 milliseconds
The simple piece of midlet code (class Moo) below (after the excerpts) deadlocks (At least I assume it deadlocks after reading this post on threads here).
I have reproduced the relevant excerpts from the post :
String url = ...
Connection conn = null;
try {
conn = Connector.open( url );
// do something here
}
catch( IOException e ){
// error
}
The root of the problem is the blocking nature of the open() call. On some platforms, the system does the actual connection under the covers, on the equivalent of a separate thread. The calling thread blocks until the connection thread makes the connection. At the same time, the security subsystem may require the user to confirm the connection, and the connection thread blocks until the event thread gets confirmation from the user. Deadlock occurs because the event thread is already waiting for the connection thread.
public class Moo extends MIDlet {
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
// TODO Auto-generated method stub
}
protected void pauseApp() {
}
protected void startApp() throws MIDletStateChangeException {
Display display = Display.getDisplay(this);
MyCanvas myCanvas = new MyCanvas();
display.setCurrent(myCanvas);
myCanvas.repaint();
}
class MyCanvas extends Canvas {
protected void paint(Graphics graphics) {
try {
Image bgImage = Image.createImage(getWidth(), getHeight());
HttpConnection httpConnection = (HttpConnection) Connector
.open("http://stackoverflow.com/content/img/so/logo.png");
Image image = Image.createImage(httpConnection
.openInputStream());
bgImage.getGraphics().drawImage(image, 0, 0, 0);
httpConnection.close();
graphics.drawImage(bgImage, 0, 0, 0);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Can someone please tell me how the system thread invocation is done here (event and notification threads) and the sequence of events leading to the deadlock. I am not clear as to what are the thread involved here that lead to deadlock.
Is there any documentation on j2me thread model?
Where can I get the sources for j2me system classes (I want to check out the implementation of Connection classes)?
EDIT : In the above code I get the logic. But the below code should at least work right? This one also deadlocks where I am doing the network connection in a separate thread.
public class Foo extends MIDlet {
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
// TODO Auto-generated method stub
}
protected void pauseApp() {
// TODO Auto-generated method stub
}
protected void startApp() throws MIDletStateChangeException {
Display display = Display.getDisplay(this);
MyCanvas myCanvas = new MyCanvas();
display.setCurrent(myCanvas);
myCanvas.repaint();
}
class MyCanvas extends Canvas {
protected void paint(Graphics graphics) {
try {
Image bgImage = Image.createImage(getWidth(), getHeight());
FetchImage fetchImage = new FetchImage();
Thread thread = new Thread(fetchImage);
thread.start();
thread.join();
bgImage.getGraphics().drawImage(fetchImage.image, 0, 0, 0);
graphics.drawImage(bgImage, 0, 0, 0);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class FetchImage implements Runnable {
public Image image;
public void run() {
HttpConnection httpConnection;
try {
httpConnection = (HttpConnection) Connector
.open("http://10.4.71.200/stage/images/front/car.png");
image = Image.createImage(httpConnection.openInputStream());
httpConnection.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Where can I get the sources for
j2me system classes (I want to check
out the implementation of Connection
classes)?
You cant. Its actually vendor dependent. The way in which Nokia handles this situation may be different from Motorola.
The lesson you have to learn is that don't do expensive computation in system callbacks as that might make the system unresponsive. So put the time consuming operation in a sepearate thread and always return from call backs as early as possible.
Even though you have created a separate thread in your second example, you wait for its completion in paint() and it eventually makes a result of no threading at all!
One thing you can do is
class MyCanvas extends Canvas {
Image image;
boolean imageFetchFailed;
protected void paint(Graphics g) {
if (image == null) {
fetchImage();
g.drawString("Fetching...", getWidth() >> 1, getHeight() >> 1, Graphics.HCENTER | Graphics.TOP)
} else if (imageFetchFailed) {
g.drawString("Failed to fetch image", getWidth() >> 1, getHeight() >> 1, Graphics.HCENTER | Graphics.TOP)
} else {
g.drawImage(image, 0, 0, 0);
}
}
private void fetchImage() {
new Thread(new Runnable() {
public void run() {
HttpConnection httpConnection = null;
try {
httpConnection = (HttpConnection) Connector
.open("http://10.4.71.200/stage/images/front/car.png");
image = Image.createImage(httpConnection.openInputStream());
} catch (IOException e) {
e.printStackTrace();
imageFetchFailed = true;
}
if (httpConnection != null) {
try {
httpConnection.close();
} catch (IOException ignored) {
}
}
// Following will trigger a paint call
// and this time image wont be null and will get painted on screen
repaint();
}
}).start();
}
}
Canvas.paint() is a event delivery method, which means it is called by a system event thread.
Assume on a system, both Canvas.paint() calling and user confirmation event handling are implemented to be done by a UI event thread (UT).
Now, when UT is blocked inside Canvas.paint() by Connector.open(), UT sure not able to handle the next coming event, which in this case is the user confirmation event triggered by Connector.open(). It is not possible for UT to process another event when it's blocked inside your application code.
That's why the deadlock occur here, the connection thread is waiting for something will never happen, and blocks UT forever.
In general, you should not expect how will system event thread be implemented, and try to return from event handling method as quickly as possible. Otherwise, you might receive lower performance or deadlock like this.
Well, the basic problem is that some Java VM implementations use the same Java thread to do everything.
One of the first thing you need to figure out about the threading model of your VM is who developed it.
There is a list of J2ME licensees here: http://java.sun.com/javame/licensees/index.jsp
From that information, try to figure out how many native threads your VM is using.
The 2 usual models are either run all bytecode interpretation into one native thread or run each java thread into its own native thread.
The next step is to gather information about how asynchronous the underlying operating system APIs are. When developing the VM, the licensees would have had to write native code to port the VM to the operating system. Any Inter-Process Communication or use of slow transmission medium (from flash card to GPS signal) might be implemented using a separate native thread that could allow the bytecode interpreter thread to keep running while the system waits for some data.
The next step is to realize how badly implemented the VM is. Typically, your problem happens when the VM uses only one internal java thread for all callbacks methods in the MIDP spec. So, you don't get a chance to react to keypad events until after your connection is opened if you try to open it in the wrong java thread.
Worse, you can actually prevent the screen from being refreshed because Canvas.paint() would be called in the same java thread as javax.microedition.media.PlayerListener.playerUpdate() for example.
From the VM implementation perspective, the golden rule is that any callback that you don't control (because it can end up in "user" code, like a listener) cannot be called from the same java thread you use unblock standard API calls. A lot of VM out there simply break that rule, hence the Sun recommendation that JavaME developers work around it.
Some good ideas, but it seems that there is a race condition in Manoj's example.
Multiple paint calls is possible while an image is downloading, causing multiple threads to be created all downloading the same image (One example of extra paint calls is when the HTTP connection prompt pops up).
Since all paint calls are made on the same thread, we can avoid synchronization by testing and setting a flag inside the paint call. Below is an attempt at an improved version:
class MyCanvas extends Canvas {
Image image;
boolean imageDownloadStarted;
boolean imageFetchFailed;
protected void paint(Graphics g) {
g.fillRect(0, 0, g.getClipWidth(), g.getClipHeight());
if (image == null) {
if (imageDownloadStarted)
return;
imageDownloadStarted = true;
fetchImage();
g.drawString("Fetching...", getWidth() >> 1, getHeight() >> 1, Graphics.HCENTER | Graphics.TOP);
} else if (imageFetchFailed) {
g.drawString("Failed to fetch image", getWidth() >> 1, getHeight() >> 1, Graphics.HCENTER | Graphics.TOP);
} else {
g.drawImage(image, 0, 0, 0);
}
}
private void fetchImage() {
new Thread(new Runnable() {
public void run() {
try {
final HttpConnection httpConnection = (HttpConnection) Connector.open("http://stackoverflow.com/content/img/so/logo.png");
try {
final InputStream stream = httpConnection.openInputStream();
try {
image = Image.createImage(stream);
} finally {
stream.close();
}
} finally {
httpConnection.close();
}
} catch (IOException e) {
e.printStackTrace();
imageFetchFailed = true;
}
repaint();
}
}).start();
}
}
Note the use of the final key word to avoid a null test and the explicit closing of the stream returned by openInputStream.