7

I am trying to programmatically raise the volume to the STREAM_MUSIC stream's maximum value, but I am having a "Sending message to a Handler on a dead thread" issue when I do. Also, it seems like it does not raise the volume 100% of the time, although when I get this error, it will raise it MOST of the time.

The code is:

System.out.println("Maximum volume for this stream is: "+maxstreamvol+" and it used to be set to: "+currentvol);     
final AudioManager am = (AudioManager)this.getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(AudioManager.STREAM_MUSIC, maxstreamvol, AudioManager.FLAG_SHOW_UI);
am.setStreamSolo(AudioManager.STREAM_MUSIC, true);
System.out.println("Volume Raised!"); 

After googling around, it seems that this error has to do with multi-threaded situations... The code at this point should be running on the UI thread.

In fact, I even surrounded it with:

runOnUiThread(new Runnable() {

    public void run() {
        // code_goes_here
    }
});

And, that produced the same error. The error that I am seeing is this:

I/System.out(24949): Maximum volume for this stream is: 15 and it used to be set to: 0
W/MessageQueue(  490): Handler (android.media.AudioManager$FocusEventHandlerDelegate$1) {42b52f28} sending message to a Handler on a dead thread
W/MessageQueue(  490): java.lang.RuntimeException: Handler (android.media.AudioManager$FocusEventHandlerDelegate$1) {42b52f28} sending message to a Handler on a dead thread
W/MessageQueue(  490):  at android.os.MessageQueue.enqueueMessage(MessageQueue.java:294)
W/MessageQueue(  490):  at android.os.Handler.enqueueMessage(Handler.java:618)
W/MessageQueue(  490):  at android.os.Handler.sendMessageAtTime(Handler.java:587)
W/MessageQueue(  490):  at android.os.Handler.sendMessageDelayed(Handler.java:558)
W/MessageQueue(  490):  at android.os.Handler.sendMessage(Handler.java:495)
W/MessageQueue(  490):  at android.media.AudioManager$1.dispatchAudioFocusChange(AudioManager.java:1894)
W/MessageQueue(  490):  at android.media.IAudioFocusDispatcher$Stub.onTransact(IAudioFocusDispatcher.java:57)
W/MessageQueue(  490):  at android.os.Binder.execTransact(Binder.java:351)
W/MessageQueue(  490):  at dalvik.system.NativeStart.run(Native Method)
I/System.out(24949): Volume Raised!

Does anybody know what's happening here?

iTech
  • 18,192
  • 4
  • 57
  • 80
Dwebtron
  • 777
  • 13
  • 27
  • 1
    Do you request *Audio Focus* in your code? Also try to use the `applicationContext` e.g. `(AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE);` – iTech Mar 11 '13 at 22:04
  • I tried this, and tested it. It made the Handler crash disappear, but it still does not let me raise the audio reliably... – Dwebtron Mar 12 '13 at 18:15
  • Edit: Turns out the audio not raising was my own fault since I caused a race condition! Oops! (I forgot to edit this a while ago) – Dwebtron Feb 21 '14 at 21:33

2 Answers2

3

Your problem may be related to the one reported on this thread - onPostExecute not being called in AsyncTask (Handler runtime exception)

The display for the audio focus change is triggering a UI event that android is not able to complete. It is not immediately clear why this is the case. Perhaps the audio manager was obtained with one context and the toast to show the volume is executed in another context ? A quick and dirty change is to swap the flag for FLAG_VIBRATE and check if that makes a difference. That would narrow down the problem to a UI update which you can then work on.

Community
  • 1
  • 1
Deepak Bala
  • 11,095
  • 2
  • 38
  • 49
  • Actually, I had just added the AudioManager.FLAG_SHOW_UI to make sure that the audio was being properly raised. Previously, I had called setStreamVolume with a flag of '0'. Really, I'm shooting for all of this to happen behind-the-scenes, so I don't mind if I have to go back to flag '0'.... but it doesn't seem to work 100% either way, flags at 0 or AudioManager.FLAG_SHOW_UI seem to produce the same result, of course one with a UI indication and one without. – Dwebtron Mar 12 '13 at 15:46
  • 1
    Is the AudioManager requested elsewhere in your application ? I assume the code snippet you posted initially is from within an activity. I dug into the Impl code and found out that the audio manager uses an internal looper and handler to alert the framework about audio focus changes. I wonder if an internal handler that is cached with the wrong context can cause this problem. – Deepak Bala Mar 12 '13 at 16:22
  • I'm not sure... but it could be possible. How would I check, and/or fix it if it was? Whenever I call setStreamVolume, the previous line is always: final AudioManager am = (AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE); – Dwebtron Mar 12 '13 at 18:17
  • 2
    AsyncTasks had this problem when they are instantiated from background threads. If the first Async task in your program is NOT instantiated from the UI thread, you get this problem. AudioManagers *might* suffer from something similar. To verify - create an Application class for your app; register it on the android manifest; and get the audio manager system service from the onCreate() method. That might instantiate the internal looper and handler correctly. – Deepak Bala Mar 12 '13 at 18:33
  • I tried that like so: static AudioManager am; void onCreate(Bundle savedInstanceState) { final AudioManager am = (AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE); But, it's throwing up a NullPointerException whenever I try to use it... Am I doing something wrong? – Dwebtron Mar 12 '13 at 19:39
  • 1
    You don't necessarily have to use this instance. Instantiating it with the right context alone should do, since that would set the handler inside the audio manager correctly. Using the application context to get the audio service the next time should do away with the handler problem and it appears from your other comment that the error no longer occurs. Raising audio reliably is another problem on its own. It might be better if you raise another question for that and post more code on how maxstream volume is obtained etc. – Deepak Bala Mar 13 '13 at 04:47
0

AudioManager uses the thread which it was created to invoke your callback or do UI manipulating (display Volume toast etc.)
(Via Looper.myLooper or getMainLooper, see this).

So you should make sure your first call to Context.getSystemService(AUDIO_MANAGER) happens on the UI thread.
(Not sure that subsequence calls will reuse that instance, but even if I re-retrieve the AudioManager the exception still occur)

I've come across this issue today and solved it by adding that call to my Application.onCreate(). (Somewhat similar to this answer?)

KenIchi
  • 1,129
  • 10
  • 22