How to manage MediaPlayer.setVolume() + SeekBar to set it + device volume control
android, android-mediaplayer, seekbar
Solution
`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.
Problem
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) { } }; ```