I have to play sounds on GUI events, like clicking buttons etc. For this purpose, I call the following native code from WebView:
MediaPlayer _SoundPlayer = new MediaPlayer();
private void playSound(String sound)
{
_SoundPlayer.reset();
try
{
AssetFileDescriptor afd = getAssets().openFd("sound/" + sound + ".mp3");
_SoundPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
_SoundPlayer.prepare();
_SoundPlayer.start();
}
catch (Exception e) { }
}
The problem is there is a delay ~500ms between an event and its sound. Can I optimize playing sound somehow, maybe, creating a dedicated MediaPlayer instances for every kind of sound?
Regards,
Use SoundPool for low-latency media playback, instead of MediaPlayer.
I see that this already has an accepted answer, but I would add that there is no complete solution at this time: Android currently has very large audio latency. Devs are still waiting for a good solution.
This issue refers to the NDK, but the issue is general:
http://code.google.com/p/android/issues/detail?id=3434
Related
I have a manager class with an array of MediaPlayer instances which is the manager for playing audio on my app. Until now, it worked perfectly in background and keep playing the audio when the device is blocked.
Now, starting with Oreo devices, the audio playing stops. Is there an easy way of forcing the device to keep alive the MediaPlayer instance which is playing the audio? I mean a simple way without using services or without creating custom bars on the notification bar of the device, which are the options I found for now here in Stack Overflow. Probably must be a simpler way.
This is the code I used to play an audio until now:
MediaPlayer mPlayer = new MediaPlayer();
AssetFileDescriptor fileDescriptor = ApplicationContextProvider.getContext().getAssets().openFd(res.getUrl());
long start = fileDescriptor.getStartOffset();
long end = fileDescriptor.getLength();
mPlayer.setDataSource(fileDescriptor.getFileDescriptor(), start, end);
mPlayer.prepareAsync();
mPlayer.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
mPlayer.setLooping(loop);
fileDescriptor.close();
Use foreground Serive. For details on why the service will no longer work watch
https://www.youtube.com/watch?v=Pumf_4yjTMc
It clearly says that background services will be stopped. For tutorial on Foreground Services watch:
https://www.youtube.com/watch?v=FbpD5RZtbCc
Remember you would also need to learn the notification channels starting Oreo. This guy has introduced that too.
I was using SoundPoolto play sound effects but now I need to switch to MediaPlayer as I need to listen to the onCompletion event to trigger a GUI change.
My questions are:
The sound files are very small, less than 30kB, Can I use
MediaPlayer in the main thread?
Can I just call mediaPlayer.stop() after the play is done like so,
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer) {
//Do some GUI changes
mediaPlayer.stop();
mediaPlayer.release();
}
});
Then to play another effect will do this:
mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start();
So, is it ok to create and release every time I play an effect?
Initialize your MediaPlayer
MediaPlayer mediaPlayer = new MediaPlayer();
AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
Look at the MediaPlayer lifecycle:
When the track is complete the MediaPlayer is in Stopped state and you wan't to change the track, so:
call reset()' to get toIdlethensetDataSourcethenprepareand finallystart()`.
The sound files are very small, less than 30kB, Can I use MediaPlayer in the main thread?
Irrespective of the size of your audio file, you should run MediaPlayer on its own thread, especially if you are playing a file from network. Not doing so may cause ANR (In your case I don't think much to worry about)
Can I just call mediaPlayer.stop() after the play is done
There is no need to release the MediaPlayer after every audio file. Release it once you are no longer going to use it.
how can I load a new sound
AssetFileDescriptor audio = context.getResources().openRawResourceFd(R.raw.next_audio);
mediaPlayer.setDataSource(audio);
My app is a music pad, which allows the user to create their own music by pressing buttons that will play a specific sound, and if the users presses more than one button there will be more sounds being played at the same time.
I want to stop all sounds when the onPause() gets called. But I realized that if I have more than one sound being played by the same Media player Object it only stops the last sound that was attributed to it, and the others stay on playing.
It would be very unpleasant for the user to receive a call and having my app sounds still on playing :p
Any help would be appreciated.
#Override
protected void onPause() {
super.onPause();
try {
while (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}catch (IllegalStateException e){
//Do nothing
}
}
EDIT
I tried to implement SoundPool API but since my app is very dynamic (users can upload their samples and also record using mic). And I have everything already implemented and working well, it would be a mess to change it now to another API rather than MediaPlayer. Is there any way to stop all sounds that were attributed to the MediaPlayer object and that are currently being played? maybe accessing to some other classes and using other methods to stop all the sounds?
I would suggest you look into the SoundPool API. It looks like that would be well suited for your task. It allows you to preload sound files and play them independently.
The SoundPool class manages and plays audio resources for applications.
A SoundPool is a collection of samples that can be loaded into memory from a resource inside the APK or from a file in the file system. The SoundPool library uses the MediaPlayer service to decode the audio into a raw 16-bit PCM mono or stereo stream. This allows applications to ship with compressed streams without having to suffer the CPU load and latency of decompressing during playback.
After a few research and trial and error there is no way that I discovered to stop all sounds being played by the same MediaPlayer Object, you can only control the last sound being attributed to it, all the other will continue until they end or the app gets destroyed.
Ok so what I did was:
I created an object for each key sound of my music pad, and Override the onPause() with the following code:
#Override
protected void onPause() {
super.onPause();
if (mAudioManager.isMusicActive()){
for (MediaPlayer aMMediaPlayer : mMediaPlayer) {
if (aMMediaPlayer != null) {
try {
if (aMMediaPlayer.isPlaying()) {
aMMediaPlayer.stop();
aMMediaPlayer.release();
}
} catch (IllegalStateException e) {
//Do nothing
}
}
}
}
}
I have an array of audio files and I want to play 3 audio files one after the other, so as the gap in between them is not noticeable.
I am trying it using onCompletion listener but unable to do.
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
// TODO Auto-generated method stub
if ((image100==1)&&(image10==0)&&(image1==1))
{
mediaplayer = MediaPlayer.create(getApplicationContext(), sounds[0]);
mediaplayer.start();
mediaplayer = MediaPlayer.create(getApplicationContext(), sounds[12]);
mediaplayer.start();
mediaplayer = MediaPlayer.create(getApplicationContext(), sounds[3]);
mediaplayer.start();
}
}
You may want to try using the AudioTrack class to play your sounds. With it, you can get very close and even overlapping sounds. To use it, you create separate threads for each sound.
Here's the AudioTrack reference page and here's an easy to follow blog entry where the author implements a piano with arbitrary length and simultaneous sounds. In it, he loops very short duration sounds, but you could easily adapt that to longer, single-play sounds.
If these 3 audio files are short sounds, like game sound effects or piano tones, you can use SoundPool for playing them.
Here is a link to the sample code:
Game Sound effects in Android
I am attempting to play a sound using a MediaPlayer object, but I cannot seem to get it to work despite my best efforts. The sound simply refuses to play.
It's a short sound, that is supposed to be played when the screen is touched, meaning it will have to be repeated many times without too much delay. Knowing this I followed the state diagram, http://developer.android.com/reference/android/media/MediaPlayer.html. I can't seem to see what exactly is wrong with my sequencing of method calls.
MediaPlayer mp = MediaPlayer.create(this.getContext(), R.raw.select2);
try {
mp.prepare();
mp.start();
Log.e("debug","sound played");
}
catch(Exception e) {}
mp.stop();
You call prepare() on the mediaplayer, but the create() call you use prepares the player automatically, this causes an IllegalStateException when you try to call prepare() again, and you are sent to your catch() (you would have noticed this if you handled the exception in some way, i.e. printing the stack trace).
MediaPlayer player = MediaPlayer.create(this.getContext(), R.raw.select2);
we configure the music player by setting some of its properties as shown below
player.setWakeMode(getApplicationContext()PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
try {
player.prepare();
player.start();
Log.e("debug","sound played");
} catch(Exception e) {}
player.stop();