Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Audio keeps playing after force close

First of all, thank you for this great site, I have found a great deal of information by searching through the questions answered here. I have a problem, though, that I only found one mention of (with no answer).

I am writing an application that uses AudioTrack to loop a runtime-generated sinewave through the headphone jack (to control other electronics). It does this at timed intervals (using Handler.postDelayed), and it works just fine - except if you happen to force close the application. In that case, the sine wave keeps on playing even after the app itself is long gone, and literally the only thing I can do to stop it is to reboot the phone.

The sound stops like it should if the application is closed properly, and even if it crashes.

I have tried:

  • creating an onDestroy() method to stop and release the AudioTrack instance, but unfortunately, it doesn't even get called.
  • using a larger audio buffer for the sound loop (hoping that the small buffer size caused the bug); no difference.
  • starting my app again: now I have two freaking sine waves!
  • uninstalling(!) the app entirely: the sine wave is still there to haunt me from beyond its grave.
  • putting the phone into silent mode: no difference. (I don't want this to happen to my users.)
  • turning the Media Volume all the way down, and waiting 15+ minutes: no difference.
  • changing the sample rate to 11, 22, or 44.1 kHz: no difference.
  • starting and killing the app again and again: I could actually get 8 different immortal sine waves interfering with each other this way. Pretty cool actually. :P

I know it's not 'healthy' to use task killers on Android, but a lot of people still do, and I don't want my users' phones to become unstoppable noise generators in case my application happens to hang and get its arse whooped.

Here is the code that generates the sine wave:

int bufSize = (int)(11025.0 / 60.0); // the number of samples needed for a seamless loop at 60Hz
AT = new AudioTrack(AudioManager.STREAM_MUSIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO,
    AudioFormat.ENCODING_PCM_8BIT, bufSize, AudioTrack.MODE_STATIC);

byte buffer[] = new byte[bufSize];

float angle = 0.0f;
for (int i=0; i < bufSize; i++){
    buffer[i] = (byte)(Math.sin(angle) * 255);
    angle += (float)(2*Math.PI) * 60 / 11025;
}

if (AT.write(buffer, 0, bufSize) != bufSize){
    log("Error: Couldn't write audio buffer!");
} else {
    AT.setLoopPoints(0, bufSize, -1);
    AT.play();
}

Even though I'm pretty sure this bug is in Android itself, I have been desperately searching for a way to detect a force close in order to run one last line of code to stop this from happening before my app dies. I've found no solution, even though I know this is possible somehow (I have an evil alarm app that comes back to life even if you kill it with a task killer). I would be extremely grateful if anyone could enlighten me!

I've also noticed that when my app is running in the background and I return to it (from the "recent apps" menu or through any other way), it seems as if a new instance is created each time. This means you can't stop the other instance playing in the background - except if you use a task killer... I'm sure this must be some trivial beginner's mistake I've made, but I was wondering if it might be related to the Sinewave of Death.

Running Android 2.1.1 on an Xperia X10 mini pro.

like image 201
therealdm Avatar asked Jul 03 '11 13:07

therealdm


1 Answers

Even though I'm pretty sure this bug is in Android itself

It sure seems like it. Any chance I can convince you to post a complete project that demonstrates this problem? Also, what Android OS versions have you tried this on?

I have been desperately searching for a way to detect a force close in order to run one last line of code to stop this from happening before my app dies.

By definition, that's not possible.

I've found no solution, even though I know this is possible somehow

No, it isn't.

(I have an evil alarm app that comes back to life even if you kill it with a task killer).

This does not mean that the "evil alarm app" instance that was force-closed found out about the fact. This means that the "evil alarm app" is using other techniques to find out after the fact that it had died and starts a fresh copy. And, even if you were to try to do this yourself, as you noted, it would not help -- the best you'd get would be your "8 different immortal sine waves" scenario.

I've also noticed that when my app is running in the background

Why would you bother writing a Service to play a sine wave? I can see playing it while your activity is in the foreground, but you should be stopping the sine wave in onPause(), so when you're not in the foreground, the noise stops.

and I return to it (from the "recent apps" menu or through any other way), it seems as if a new instance is created each time

Depending on what "running in the background" means and how you got to the "background", this is normal. Pressing the BACK button will destroy the activity, for example; going back to it by any means will create a new activity instance.

like image 84
CommonsWare Avatar answered Sep 28 '22 06:09

CommonsWare