I am displaying a Timer on a screen.
The requirement is I need to play a sound every second when the timer duration is 5 seconds remaining & finally when it reaches 0 (end) , I need to play another sound.
I am using the following code:
public void onTick(long millisUntilFinished) {
long timeLeft = secondsRemaining // I am getting the seconds left here
if (timeLeft <= 5) {
playAlertSound(R.raw.beep);
}
else if(timeLeft == 0){
playAlertSound(R.raw.beep1);
}
public void playAlertSound(int sound) {
MediaPlayer mp = MediaPlayer.create(getBaseContext(), sound);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
The problem I am facing using the above code , though the each beep sound duration is less than 1 second , I am getting a continuation of the sound. I want to have separate beep sound for every second starting from the remaining 5 seconds till it reaches zero.
Also , the volume of the sound is too low.
Kindly provide your inputs , whether I need to follow any other logic ?
Thanks in advance.
Warm Regards,
CB
You should make sure looping is disabled using the setLooping function and for the volume issue, you can set the playback volume using: the setVolume function.
But, for your appliction you may want to look into using the SoundPool class instead of the MediaPlayer because it's more suitable for situations like yours when you want to play the same short sound more than once.
With your sample code, I would also reverse the order of the setting the onCompleteListener and starting playback, like this:
MediaPlayer mp = MediaPlayer.create(getBaseContext(), sound);
// move the mp.start() from here..
mp.setOnCompletionListener(new OnCompletionListener() {
// your handler logic here..
});
// and add the setLooping and setVolume calls here..
mp.setLooping(false);
mp.setVolume(1.0, 1.0);
mp.start(); // to here..
I tried this code without the OnCompletionListener, and it worked fine with no looping? I guess I'm not understanding your problem. Also... setVolume(1.0,1.0) isn't correct, you need (float,float) not doubles.
Related
I'm playing a sound through STREAM_ALARM:
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(context, notificationSoundUri);
mp.setAudioStreamType(AudioManager.STREAM_ALARM);
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
mp.prepare();
It worked ok until I tried on Android 6. On Android 6 sound doesn't play from beginning, so if I play short sounds, no sound is heard. I tried using seekTo(0) and initializing MediaPlayer in other ways.
It only happens in Android 6 when using STREAM_ALARM (other streams work well).
Any help?
EDIT: I realized that sound actually starts playing from start, but at very low volume, and after about 2 seconds volume increases... do you know how to deactivate this behavior?
It sounds like an equalization problem (maybe this audio stream comes with an audioSessionId which is already handled by the system equalizer?)
I will try the following trick before the MediaPlayer initialization:
1) Change the STREAM_ALARM volume
AudioManager mAudioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM);
mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, maxVolume, 0 /*flags*/);
2) Set volume after prepare()
//...
mp.prepare();
mp.setVolume(1.0f, 1.0f);
3) Change the audioSessionId
//...
mp.setAudioStreamType(AudioManager.STREAM_ALARM);
mp.setAudioSessionId(CUSTOM_ID); //manually assign an ID here
//...
UPDATE
4) Try to use the SoundPool API instead of MediaPlayer and see if the problem persists (I also suspect that this is a device-dependent issue).
5) Try to call start() ==> pause() ==> start() on MediaPlayer
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
mp.pause();
mp.start();
}
6) Try to trick the initial "low volume" period using the following logic:
before play, set volume to 0
play
after 2 seconds of playback, seek to position 0 (this may consume the silent period)
set the volume to max
play again
In this way, you may be able to do a normal playback, with an initial delay of few seconds.
Let us know your progress, I'll update this answer accordingly with more information and suggestions.
Here's my scenario:
I have a timer that counts down from 20 seconds. At 13 seconds, a sound starts playing. At 0 seconds, I stop the current sound, load up a new sound and play that new sound. Once that sounds finishes, I load up the previous sound, set it to loop, and start it.
This is the logic for hitting 0 seconds:
mp.stop();
mp = MediaPlayer.create(mActivity, R.raw.second_sound);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp = MediaPlayer.create(mActivity, R.raw.first_sound);
mp.setLooping(true);
mp.start();
}
});
Once the last sound starts playing, calling mp.release() doesn't stop the player. Any ideas as to how to stop the player?
Note: mp.release() works during the first time I start playing and during the second sound but not during the looping sound.
Solution: My global MediaPlayer is also named "mp". Oops.
You're getting the mp MediaPlayer objects mixed up a little. If mp.release() is being called outside of the onCompletion() method, it is not referring to the looping instance created there. Change the identifiers in onCompletion() to refer to the "outer" mp. For example, if your code is in MainActivity:
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
#Override
public void onCompletion(MediaPlayer mp)
{
MainActivity.this.mp = MediaPlayer.create(MainActivity.this, R.raw.chirp);
MainActivity.this.mp.setLooping(true);
MainActivity.this.mp.start();
}
}
);
Why are you creating new media player every time and not releasing old one onCompltion? did you try setDataSource?
I'm trying to write a function to play a short sound (in /res/raw) in my program, called at effectively random times throughout the program. So far I have this function:
public void playSound() {
MediaPlayer mp = new MediaPlayer();
mp = MediaPlayer.create(this, R.raw.ShortBeep);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setLooping(false);
mp.start();
}
It works fine for awhile, but after exactly 30 plays of the sound, it stops making sound.
According to the Docs
... failure to call release() may cause subsequent instances of MediaPlayer objects to fallback to software implementations or fail altogether.
When you are done with it call mp.release() so that it can release the resources. I don't know what the limit is and I'm sure it depends on many factors. Either way you should be calling this function on your MediaPlayer object, especially if it will be used more than once.
I've just solved the exact same problem, but I'm using Xamarin. I ended up changing from holding on to a MediaPlayer instance for the lifetime of the activity to creating an instance each time I want to play a sound. I also implemented the IOnPreparedListener and IOnCompletionListener.
Hopefully you can get the idea despite it being C# code
public class ScanBarcodeView :
MvxActivity,
MediaPlayer.IOnPreparedListener,
MediaPlayer.IOnCompletionListener
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.ScanBarcodeView);
((ScanBarcodeViewModel) ViewModel).BarcodeScanFailed += (sender, args) => PlaySound(Resource.Raw.fail);
((ScanBarcodeViewModel) ViewModel).DuplicateScan += (sender, args) => PlaySound(Resource.Raw.tryagain);
}
private void PlaySound(int resource)
{
var mp = new MediaPlayer();
mp.SetDataSource(ApplicationContext, Android.Net.Uri.Parse($"android.resource://com.company.appname/{resource}"));
mp.SetOnPreparedListener(this);
mp.SetOnCompletionListener(this);
mp.PrepareAsync();
}
public void OnPrepared(MediaPlayer mp)
{
mp.Start();
}
public void OnCompletion(MediaPlayer mp)
{
mp.Release();
}
}
So, each time I want a sound to be played I create a MediaPlayer instance, so the data source, tell it that my Activity is the listener to Prepared and Completion events and prepare it. Since I'm using PrepareAsync I don't block the UI thread. When the media player is prepared the Start method on the MediaPlayer is called, and when the sound has finished playing the MediaPlayer object is released.
Before I made these changes I would get to 30 sounds played and it would all stop working. Now I've gone way past 30, also multiple sounds can be played simultaneously.
Hope that helps.
I want to play two sounds. I'm using this code but there's lag between the two sounds for about 2s. I want to play the second directly when the first sound is finished. How can I do that?
MediaPlayer mp = MediaPlayer.create(getApplicationContext(),R.raw.s83);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp2){
mp2 = MediaPlayer.create(getApplicationContext(),R.raw.ss);
mp2.start();
}
});
Android 4.1 (v16) adds MediaPlayer.setNextMediaPlayer which was added to allow gapless playing as per the feature list. Prior to that, there is always a small delay between onCompletion and starting another MediaPlayer due to buffering. Creating the second MediaPlayer before onCompletion might help as well (and would be required for using setNextMediaPlayer anyways).
Try this:
Make mp2 a MediaPlayer class field and then use this code:
mp2 = MediaPlayer.create(getApplicationContext(),R.raw.ss);
MediaPlayer mp = MediaPlayer.create(getApplicationContext(),R.raw.s83);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp){
YourActivityClass.this.mp2.start();
}
});
It will at least create the second MediaPlayer object and prepare() before the first sound is played, so you gain some time there.
I am trying to play two sound items, one after the other
MediaPlayer mp = null;
protected void produceErrorSound(int index) {
if (mp != null) {
mp.reset();
mp.release();
}
mp = MediaPlayer.create(this, index);
mp.start();
}
public void correctAnswerAndNext(){
produceErrorSound(R.raw.right1) ;
produceErrorSound(R.raw.right1) ;
}
but only second sound is produced.
is there any alternative approach?
I can't see any wait mechanism in your code.
You can use an onCompletionListener to receive a callback when your first MediaPlayer has finished playback. At that point you can start the second MediaPlayer.
An alternative way in Jellybean (and later versions) is to use the audio chaining functionality (i.e. setNextMediaPlayer) to automatically start another MediaPlayer as soon as the current one has finished playing. Something like this (I've omitted the calls to setDataSource etc for brevity):
mediaPlayer1.prepare();
mediaPlayer2.prepare();
mediaPlayer1.start();
mediaPlayer1.setNextMediaPlayer(mediaPlayer2);