强制关闭后音频继续播放

发布于 2024-11-18 15:21:52 字数 1813 浏览 4 评论 0原文

首先,感谢您提供这个很棒的网站,通过搜索这里回答的问题,我找到了大量信息。不过,我有一个问题,我只发现了一个提及(没有答案)。

我正在编写一个应用程序,它使用 AudioTrack 通过耳机插孔循环运行时生成的正弦波(以控制其他电子设备)。它按时间间隔执行此操作(使用 Handler.postDelayed),并且工作得很好 - 除非您碰巧强制关闭应用程序。在这种情况下,即使应用程序本身早已消失,正弦波也会继续播放,而实际上我唯一能做的就是重新启动手机来阻止它。

如果应用程序正确关闭,即使应用程序崩溃,声音也会停止。

我尝试过:

  • 创建一个 onDestroy() 方法来停止并释放 AudioTrack 实例,但不幸的是,它甚至没有被调用。
  • 对声音循环使用更大的音频缓冲区(希望小缓冲区大小会导致错误);没有区别。
  • 再次启动我的应用程序:现在我有两个可怕的正弦波!
  • 完全卸载(!)该应用程序:正弦波仍然存在,在它的坟墓之外困扰着我。
  • 将手机设置为静音模式:没有区别。 (我不希望这种情况发生在我的用户身上。)
  • 将媒体音量一直调低,然后等待 15 分钟以上:没有区别。
  • 将采样率更改为 11、22 或 44.1 kHz:没有区别。
  • 一次又一次地启动和终止应用程序:实际上,我可以通过这种方式得到 8 个不同的不朽正弦波,它们相互干扰。实际上很酷。 :P

我知道在 Android 上使用任务杀手并不“健康”,但很多人仍然这样做,而且我不希望我的用户的手机成为不可阻挡的噪音发生器,以防我的应用程序碰巧挂起并得到它的屁股呼喊道。

这是生成正弦波的代码:

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();
}

尽管我很确定这个错误存在于 Android 本身中,但我一直在拼命寻找一种方法来检测强制关闭,以便运行最后一行代码来阻止此错误发生在我的应用程序死亡之前。我没有找到解决方案,尽管我知道这在某种程度上是可能的(我有一个邪恶警报应用程序,即使你用任务杀手杀死它,它也会复活)。如果有人能启发我,我将非常感激!

我还注意到,当我的应用程序在后台运行并且我返回到它(从“最近的应用程序”菜单或通过任何其他方式)时,似乎每次都会创建一个新实例。这意味着你无法阻止另一个实例在后台播放 - 除非你使用任务杀手......我确信这一定是我犯的一些微不足道的初学者错误,但我想知道它是否可能相关到死亡的正弦波。

在 Xperia X10 mini pro 上运行 Android 2.1.1。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我很OK 2024-11-25 15:21:52

尽管我很确定这个错误存在于 Android 本身

但看起来确实如此。我有机会说服您发布一个完整的项目来演示这个问题吗?另外,您在哪些 Android 操作系统版本上尝试过此操作?

我一直在拼命寻找一种方法来检测强制关闭,以便在我的应用程序崩溃之前运行最后一行代码来阻止这种情况发生。

根据定义,这是不可能的。

我没有找到解决方案,尽管我知道这在某种程度上是可能的

不,事实并非如此。

(我有一个邪恶的警报应用程序,即使你用任务杀手杀死它,它也会复活)。

这并不意味着被强制关闭的“邪恶警报应用程序”实例发现了这一事实。这意味着“邪恶警报应用程序”正在使用其他技术来查明它已经死亡的事实,并开始一个新的副本。而且,即使你自己尝试这样做,正如你所指出的,这也无济于事——你得到的最好的结果就是你的“8 个不同的不朽正弦波”场景。

我还注意到,当我的应用程序在后台运行时

为什么要编写一个 Service 来播放正弦波?我可以看到当您的 Activity 位于前台时正在播放它,但您应该在 onPause() 中停止正弦波,因此当您不在前台时,噪音就会停止。

然后我返回到它(从“最近的应用程序”菜单或通过任何其他方式),似乎每次都会创建一个新实例

具体取决于“在后台运行”的含义以及如何进入“后台” ,这是正常的。例如,按“BACK”按钮将破坏该 Activity;以任何方式返回它都会创建一个新的活动实例。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文