2
votes

I need to dynamically vary volume of videoView outside of onPrepared method. So I have saved a reference to videoView's media player on which I am using setVolume method.

private MediaPlayer videoViewMediaPlayer;

videoView onPreparedListener:

videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        videoViewMediaPlayer = mediaPlayer;
        setVolumeForMediaPlayer(mediaPlayer);
        videoView.setBackgroundColor(Color.TRANSPARENT);
        mediaPlayer.setLooping(false);
    }
});

...
private void setVolumeForMediaPlayer(MediaPlayer mediaPlayer) {
    if (mediaPlayer != null) {
        if (muteAudio)
            mediaPlayer.setVolume(0, 0);
        else
            mediaPlayer.setVolume(1.0f, 1.0f);
    }
}

Now, whenever I need to adjust volume of mediaPlayer, I am using:

setVolumeForMediaPlayer(videoViewMediaPlayer);

But, following exception is thrown:

java.lang.IllegalStateException
    at android.media.MediaPlayer._setVolume(Native Method)
    at android.media.MediaPlayer.setVolume(MediaPlayer.java:1604)
    at com.blynq.app.fragments.PlayerPane.setVolumeForMediaPlayer(PlayerPane.java:501)
    at com.blynq.app.fragments.PlayerPane.changeActiveMedia(PlayerPane.java:408)
    at com.blynq.app.asyncs.PanePlayerAsyncTask.onProgressUpdate(PanePlayerAsyncTask.java:130)
    at com.blynq.app.asyncs.PanePlayerAsyncTask.onProgressUpdate(PanePlayerAsyncTask.java:22)
    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:656)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5343)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
  1. What is the reason for this exception ?
  2. If videoView is invisible by the time onPrepared is called, would setVolume(0, 0) set videoView to mute ?
  3. How do I set the volume outside of onPrepared(...) method ?
1

1 Answers

2
votes

It might be late to respond on your question, but answering this in case someone else stumbles on this thread in future.

I encountered a similar problem while trying to set the volume for VideoView based MediaPlayer, as I was calling the mediaPlayer.setVolume() method right after the MediaPlayer was reset. It is important to check in your code where all are you calling the setVolumeForMediaPlayer(videoViewMediaPlayer) method.

According to MediaPlayer State-Diagram docs,

There is a subtle but important difference between a newly constructed MediaPlayer object and the MediaPlayer object after reset() is called. It is a programming error to invoke methods setLooping(boolean), setVolume(float, float) in the Idle state for both the cases. If any of these methods is called right after a MediaPlayer object is constructed, the user supplied callback method OnErrorListener.onError() won't be called by the internal player engine and the object state remains unchanged; but if these methods are called right after reset(), the user supplied callback method OnErrorListener.onError() will be invoked by the internal player engine and the object will be transfered to the Error state.

Answering your questions:

  1. This exception is occurring because while setting the volume, your mediaPlayer is not yet in the PREPARED state, and calling them causes it to slide to the ERROR state. A possible solution can be setting volume only when the view is prepared or any later state.

  2. Yes. Given that the state it is not in the ERROR state as described above.

  3. I would advise you to call the method carefully after tracking the state. For instance, you can check for the isPlaying() or isPaused() state inside your setVolumeForMediaPlayer(videoViewMediaPlayer) method.

PS: On other note, I wonder why are you initializing the videoViewMediaPlayer in your onPrepared call, when you are using the mediaPlayer parameter everywhere else. That initialization seems safe, but redundant.