Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage MediaPlayer.setVolume() + SeekBar to set it + device volume control

As recommended by the doc, I'd like to use the setvolume() method to control the volume of my MediaPlayer, but I'm a bit confused about how to manage it.

I'm setting the volume using a SeekBar, initialized to the current volume in the AudioManager.STREAM_MUSIC stream.

This makes sense when the user does not modify the device volume control, but when he does, I'm not sure what I should do, and I have several doubts:

  • how is the MediaPlayer volume related to the device volume? Does the max value (1) set in setVolume() correspond to mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)

  • if it's the case, the progress value of the SeekBar should be reset every time the device volume control is set, but then, what's the point of using MediaPlayer.setVolume() instead of AudioManager.setStreamVolume()?

  • what's the standard way of using MediaPlayer.setVolume() with a SeekBar?

private final static int MAX_VOLUME = 100;
private AudioManager mAudioManager; 
private SeekBar mVolumeControl;

mVolumeControl = (SeekBar) getActivity().findViewById(R.id.volume_control);
mAudioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
mVolumeControl.setMax(MAX_VOLUME);
mVolumeControl.setProgress(MAX_VOLUME*mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)/mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)); 
mVolumeControl.setOnSeekBarChangeListener(mVolumeControlChangeListener);

private SeekBar.OnSeekBarChangeListener mVolumeControlChangeListener = new SeekBar.OnSeekBarChangeListener() {

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

        float volume = (float) (1 - (Math.log(MAX_VOLUME - progress) / Math.log(MAX_VOLUME)));
        mediaPlayer.setVolume(volume, volume);
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {}

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    }
};
like image 472
jul Avatar asked Aug 08 '13 15:08

jul


People also ask

What is SeekBar in player?

Well according to android.developers.com, A SeekBar is an extension of ProgressBar that adds a draggable thumb. The user can touch the thumb and drag left or right to set the current progress level or use the arrow keys. Placing focusable widgets to the left or right of a SeekBar is discouraged.

What is SeekBar?

Android SeekBar is a type of ProgressBar. On touching the thumb on seekbar and dragging it to the right or left, the current value of the progress changes. SeekBar is used for forwarding or backwarding the songs, Video etc. In the setOnSeekBarChangeListener interface is used which provides three methods.

Which method of the mediaplayer class allows you to read a music file from a given point in time rather than from the beginning of the song )?

pause(); On call to start() method, the music will start playing from the beginning. If this method is called again after the pause() method, the music would start playing from where it is left and not from the beginning. In order to start music from the beginning, you have to call reset() method.


2 Answers

MediaPlayer.setVolume sets the volume of that player as a percentage of the overall volume for that stream. It does not affect the stream volume. So if you want to set just that player's volume, set it to something between 0 and 1 (a fractional value representing the percentage) and let the user control the system volume separately by using the hardware volume controls. To hook up a SeekBar, you can scale it by a factor of 100 like you've done in your sample code, since SeekBar doesn't support fractional values. Oh, and one more thing for others' benefit (since you've already figured it out): the docs say "UI controls should be scaled logarithmically", which means that if you just set the volume without any scaling, the volume control will feel unnatural. Basically, halving the amplitude of the wave is NOT perceived by the human ear as "half the volume", so you need to scale logarithmically to make it feel more natural to the human ear, like you've done in your sample code.

If you do want to set the system volume for the given stream (and not just for the given player), you can use AudioManager.setStreamVolume with a value between 0 and the value returned by AudioManager.getStreamMaxVolume. But keep in mind that that one is generally a low-resolution volume control - getMaxStreamVolume usually returns a relatively low value - like 10 or 15, so you only have a few possible positions for the volume. This means that controlling the volume will not be as smooth as if you control the MediaPlayer's volume directly. Also, obviously, setting the volume this way sets it for the entire system and affects all applications, which may not be what the user wants.

like image 76
Todor K. Avatar answered Oct 05 '22 23:10

Todor K.


Adding to TodorK's answer.

What I did is I initially set the StreamVolume to Max, and let user control the SeekBar. Once they finished , I set the StreamVolume back to its original state. This allows the user to control the MediaPlayer volume, and does not effect other applicaitons.

First set the Stream to your desired one & Initialize AudioManager

setVolumeControlStream(AudioManager.STREAM_MUSIC);
audioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);

Get the InitialVolume (so that you set it back to this once you're done) and set it to MaxVolume

final int initVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
final int maxVolume  = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,maxVolume, 0);

Do the AudioStuff in the onProgress part of the SeekBarChangedListener

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) 
        {
            float volume = (float) (1 - (Math.log(100 - progress) / Math.log(100)));
            mp.setVolume(volume, volume);
            mp.start();
        }

Once you're done, set it back to the initialVolume, so that the User doesnt get pissed off (in my case,im using an AlertDialog, so its in the onDismiss thing

        @Override
        public void onDismiss(DialogInterface dialog) 
        {
            audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,initVolume, 0);

            //Stop Playing the Song
            stopSong();             
        }

Also notice, I did the log stuff in the onProgress part

like image 39
Zen Avatar answered Oct 05 '22 23:10

Zen