Android: why MediaPlayer plays the same sound louder than SoundPool? - android

You can play a sound with MediaPlayer or SoundPool on Android.
Two of our Android devices play the same sound much louder when MediaPlayer is used.
On the third device, the volume sounds the same.
Do you know why?
Can I make SoundPool to play sounds as loud as MediaPlayer?
Devices in question:
Tablet LG-V400 (Android 4.4 Kit Kat)
Phone Sony Xperia L (Android 4.2.2)
Code: play mp3 sound with SoundPool
private void playSoundPool() {
int MAX_STREAMS = 2;
SoundPool soundPool = new SoundPool(MAX_STREAMS, AudioManager.STREAM_MUSIC, 0);
soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int soundId, int status) {
int loop = 0;
int priority = 0;
float rate = 1.f;
soundPool.play(soundId, 1, 1, priority, loop, rate);
}
});
soundPool.load(this, R.raw.test, 1);
}
Code: play mp3 sound with MediaPlayer
private void playMediaPlayer() {
MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.test);
mediaPlayer.setVolume(1, 1);
mediaPlayer.start();
}
You are welcome to download test project.

Possible Solution:
You need to create AudioManager for getting, changing the global media volume set by user in phone and changing the volume for our own app independently by changing stream volume in soundPool.
AudioManager mgr = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
int streamVolume = mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
streamVolume = streamVolume / AudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, 0, 1f);
Note:
if I set 0.5 for volume in soundpool, the actual volume will be always half of the global one. Very easy to reproduce:
set global media volume in phone settings to max
set volume in activity using soundpool.play to 0.5 - play sound
set volume in soundpool.play to 1 - play sound, it will be two times
louder
So volume passed to SoundPool.play method really a multiplier to the global volume!
**So If you want to play a sound at the current volume setting just pass "1" as the volume or change it as per the requirement **
may be media player class using global media volume for playing the audio file. you are using hard-coded soundPool.play(soundId, 1, 1, priority, loop, rate); values !
we need try with
MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.test);
mediaPlayer.setVolume(streamVolume,streamVolume);
mediaPlayer.start();
Some more Texts :
SoundPool:
SoundPool is designed for short clips which can be kept in memory
decompressed for quick access, this is best suited for sound effects in apps or games. Using this method with soundboards is a bad
idea as you will be loading lots of “medium” sized sounds into the
memory and you may exceed your limit (16Mb) and get an
OutOfMemoryException. SoundPool load music files using a separate
thread, the operation of the main thread does not block the UI.
it can be used to play short sound clips say like gun shots during
a game (something like less than 3 seconds long). A nice feature that
sound pool comes with is that you can play many sounds simultaneously
which happens a lot when you think of a game. So you first build a
Sound Pool object to load all media files.
MediaPlayer:"
MediaPlayer is designed for longer sound files or streams, this is
best suited for music files or larger files. The files will be loaded
from disk each time create is called, this will save on memory space
but introduce a small delay (not really noticeable).
Ref: SO

Mechanism difference is there, as you can say that due to compression and decompression the sound quality and volume could go below the actual one, and when you compare it with MediaPlayer. So it is better to use MediaPlayer for better sound quality and volume in your case.
SoundPool
SoundPool is designed for short clips which can be kept in memory decompressed for quick access, this is best suited for sound effects in apps or games. Using this method with soundboards is a bad idea as you will be loading lots of “medium” sized sounds into the memory and you may exceed your limit (16Mb) and get an OutOfMemoryException.
MediaPlayer
MediaPlayer is designed for longer sound files or streams, this is best suited for music files or larger files. The files will be loaded from disk each time create is called, this will save on memory space but introduce a small delay (not really noticeable).

Related

precision of Android MediaPlayer seekTo

I have a number of mp3 files that I use with Android MediaPlayer to play from certain offsets.
Using seekTo() seems to stop at correct location. player.getCurrrentPosition() returns the correct offset, but in some cases the real position is off for as much as 200 ms. The files are about 3 minutes worth of recording and the incorrect offsets seem to appear at the end. Of some of the files.
I have the same effect either trying with Android 4.0.3 device or 4.3 emulator.
Anybody has experience with "finetuning" MediaPlayer offsets? Any experience why MediaPlayer might not be working correctly with some files? They are all CBR, stereo, some have sampling frequency 22050, some 44100, different bitrates.
I'm setting the offsets from another program and saving to mp3 tags, then in case of doubt verifying manually using Audacity. Audacity agrees with my estimate of what the correct offset is, MediaPlayer seems to disagree.
I'm aware that I could use AudioTrack with raw sound files and have a better control, however it might be impractical as there are many mp3 files, so using raw sound data will make pretty large application or many large data files.
The code is nothing fancy:
player.seekTo(start);
player.start();
CountDownTimer timer = new CountDownTimer(length, 100) {
#Override
public void onTick(long millisUntilFinished) {
if (player!=null) setInt(R.id.nLocation, player.getCurrentPosition());
}
#Override
public void onFinish() {
if (player!=null) {
if (player.isPlaying()) {
player.pause();
}
setInt(R.id.nLocation, player.getCurrentPosition());
player.stop();
player.release();
player = null;
}
}
};
timer.start();
I did not manage to find the rule why the MediaPlayer interprets offset (seekTo) differently for a group of MP3 files. For example when creating a new MP3 file with the same parameters from Audacity+Lame (MPEG1, Layer III, 44100 Hz, 192 Kb/s) it worked perfectly.
However:
this can be reproduced - rip MP3 file using Windows Media Player, settings: MP3, 192 kb/s [added when edited]
I found the workaround that seems to work for any recording.
The background - in order to tell MediaPlayer to play from certain offset, I store certain data in MP3 tags. I use a separate program to set up the playback (in frames): Label A, start frame=1000, length=100 frames, Label B, start #1500 etc. Now when I need to play it back, I read the MP3 headers, determine the frame length, for example 26.12245 ms/frame and calculate the offset (1000 frames will be 26122 ms).
The workaround is to store in MP3 tag also the frame count and length in ms (or pass through again and count the frames). Then when start MediaPlayer, compare MediaPlayer.getDuration() (MediaPlayer estimate) with the duration stored in MP3 tag. Then adjust the frame size:
adjustedFrameSizeMs = realFrameSizeMs + (player.getDuration()-storedDurationMs)/storedframeCount;
In my case (for the files with incorrect offset) the adjusted frame length always was between 26.08 and 26.09 ms (instead of 26.12245).
I attempted to try see if this is because Android plays the recording quicker (so it estimates the "real time", not the time according to frame size and frame count). It seems that it really does plays quicker. But even quicker than its own estimate. For example a recording of about 1 hour:
my estimate: 2448 s
MediaPlayer: 2444 s (4 sec difference)
Audacity: 2442 s (here we are in disagreement)
Foobar: 2448 s (another witness that agrees with my estimate :-)
MediaPlayer, real play time: 2438 s
The real playtime was 6 s (0.25%) less than MediaPlayer own estimate. Another attempt on a different sample gave the same percentage difference. However the fact that Audacity and Foobar did not always agree with my estimates, does not let me put all the blame on MediaPlayer.

Increase MediaPlayer volume beyond 100%

Below code is working but not increasing the media player volume higher than the default max volume.Please help
AudioManager am =
(AudioManager) getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(
AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
0);
The MediaPlayer class's setVolume() method only accepts scalars in the range [0.0, 1.0], but the classes deriving from AudioEffect can be used to amplify the MediaPlayer's audio session.
For example, LoudnessEnhancer amplifies samples by a gain specified in millibels (i.e. hundredths of decibels):
MediaPlayer player = new MediaPlayer();
player.setDataSource("https://www.example.org/song.mp3");
player.prepare();
// Increase amplitude by 20%.
double audioPct = 1.2;
int gainmB = (int) Math.round(Math.log10(audioPct) * 2000);
LoudnessEnhancer enhancer = new LoudnessEnhancer(player.getAudioSessionId());
enhancer.setTargetGain(gainmB);
It's unclear from the documentation, but it appeared to me that LoudnessEnhancer doesn't work properly with negative gains, so you may still need to use MediaPlayer's setVolume() method if you want to decrease the volume.
DynamicsProcessing provides multiple stages across multiple channels, including an input gain stage.
For increasing the volume of the device beyond the system volume u have to go in engineers mode.for that save below code.and paste it in number entering box In calling option it will directly redirect you to the engineers mode
*#*#3646633#*#*
By this you can access the system settings one thing make sure that don't use this without care it may affect your system performance.

Android Media Player setVolume Issues

Until now, I was setting my MediaPlayer volume by setting the stream volume. I don't want to do that anymore because it messes with user settings. I now take the value from a SeekBar (0 to 100) and do valueFromSeekBar / 100 to get a float between 0 and 1 to use in MediaPlayer.setVolume(float, float).
The problem is that the volume level doesn't seem to change. Here is how I set up the MediaPlayer:
player.setAudioStreamType(AudioManager.STREAM_ALARM);
player.setLooping(true);
player.prepare();
float alarmVolume = AudioUtils.getMediaPlayerScaledVolume(100, alarm.volume);
if(NetworkUtils.isInCall(context)) {
alarmVolume = IN_CALL_VOLUME;
}
mediaPlayer.setVolume(alarmVolume, alarmVolume); //I've even tried hardcoding 0.1f
No matter what I do, it seems like the value I put in MediaPlayer.setVolume gets ignored, and the volume of the stream (in this case the alarm stream) gets used instead. It's most noticeable when the stream volume is set to max, and I play two audio files, one with MediaPlayer.setVolume(1f, 1f) and the other with MediaPlayer.setVolume(0.01f, 0.01f). They are almost indistinguishable from one another. I need a way for my users to be able to position the SeekBar at 1 and get a barely audible sound, or at 100 and have the max sound. Is this possible or am I gonna have to go back to messing with streams?
Set volume:
it will set maximum value(100) to Alarm Stream.
amanager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
amanager.setStreamVolume(AudioManager.STREAM_ALARM, amanager.getStreamMaxVolume(AudioManager.STREAM_ALARM), AudioManager.FLAG_PLAY_SOUND);
Can it be you have two objects "player" and "mediaPlayer"? Here I just used that API, and it works as was to be expected.

Android File Specific Volume

I've got an application where I will be playing 2 audio files simultaneously and the user will be attempting to hear the one (spoken words) over the other (background noise). With successful feedback input that they heard the file correctly, I want to decrease the volume of 1 (words) of the 2 files and play it again and they will attempt to hear it over the noise. I only want to decrease the volume of one file... the other one needs to remain constant (otherwise it defeats the purpose of trying to hear the one over the other). All I've found so far with the MediaManager is the ability to change the global volume of the application and not the specific audio clips within the application.
Any help is greatly appreciated.
My impression that the media player was global was incorrect. You can set the volume for this file and it will keep that volume even when you play a louder or quieter file (even when using the same mp). The oncompletion listener is important to releasing the file when over other wise you'll get exceptions and lose all sound. The logarithmic math function is important to getting the volume to scale appropriately between 0 & 100.
Assuming MAX_VOLUME is 100:
mp = MediaPlayer.create(getApplicationContext(), R.raw.noise);
final float noisevolume = (float) (1 - (Math.log(MAX_VOLUME - 50) / Math.log(MAX_VOLUME)));
mp.setVolume(noisevolume, noisevolume);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});

Background music length and speed

For my Android app I would like background music. It doesn't have to go across activities so services do not matter.
Soundpool seems to stop playing the .ogg or .mp3 after about 6 seconds
MediaPlayer doesn't have the ability to change the speed (rate) of the music
What I would like to do is to allow the user to change the speed of the background music as it is playing. It would seem like SoundPool can do this but its hard to tell since it only plays for a few seconds.
Any suggestions for how to do this?
SoundPool is bad with wav files, with mp3 I didn't have problems...
public final int play (int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
float rate - value of 0.5 means playback at half speed, can be 0.5-2.... I think you ought to use SoundPool... As for me, I appreciate Mediaplayer...

Categories

Resources