When I play a sound in my app it comes off as clippy and distorted. Here is a recording: recording.
Here is the sound file as it was uploaded to android studio: success sound cue
Here is the function that calls the sound from the .raw
public void playCorrectAnswerSound() {
final MediaPlayer mp = MediaPlayer.create(this, R.raw.correct);
mp.start();
}
Heres how I call it:
Thread t = new Thread(){
public void run(){
playCorrectAnswerSound();
}
};
t.start()
This is my first time debugging a sound related issue. I don't know what else to include in this post, so if you need more info please say so.
EDIT: I was asked to record more of the distortion. Here it is. Also I should say that after more testing, my physical device lacks the sound distortion while the sound distortion is present on 3 different emulators.
I'm going to say this is stuttering due to underrun (starvation) of the MediaPlayer's internal playback buffer. That is, the MediaPlayer can't supply data fast enough to keep up with the sound hardware (which suggests a severe lack of processing power). If the buffer starves, it'll start to play back old data (because it's a circular buffer). This causes a sharp phase transition, which sounds like a "click". Presumably the MediaPlayer recovers quickly enough that the "correct" sound resumes playing shortly thereafter.
Here is a picture of the spectrum from Audacity. 0-4KHz. The first row is the clean .mp3; the next four rows are the distorted recordings (in no particular order). All rows have been aligned in time, and are roughly the same amplitude. The large vertical stripes in the last four rows represent the distortion/clicks that you hear.
I am using Python Kivy for an Android Game. I want to play a sound on an event
sound = SoundLoader.load("sound.wav")
def onEvent():
sound.play()
, and It works. But now the problem: Of course an event can, and in my case will happen again before the sound is done playing from the last event. And as the sounds are based on a play/pause idea I am getting a problem playing multiple sounds of the same object at once. That can be solved like this for first:
onEvent():
SoundLoader.load("sound.wav").play()
As this creates a new object all the time, and so is able to play it the same time another event plays the sound. But the problem using this method is quite obvious, because the sound must be loaded everytime the event occurs, and so causes a delay until it's played.
Is there a more useful way to do this?
{ if you don't understand what I am talking about, or just don't see the problem, feel free to ask }
You can workaround this by loading multiple instances of the sound.
For instance
sounds = [SoundLoader.load("sound.wav") for _ in range(10)]
index = 0
and then
def play():
sounds[index].play()
index = (index + 1) % len(sounds)
The more sounds you load, the more instances you can have playing at the same time (in this example 10).
hi ive been working on my app and have found a hurdle in an activity i just cant seem to overcome. the activity is essentially a large novelty piano with 8 keys that play sounds there are 6 buttons along the side that change the picture of the notes and the notes themselves, this i accomplished :-) now i would like to add a background song to each different set of notes (instruments) only when i do the app crashes i have set the mediaplayer at the top (globally?) using MediaPlayer mp; MediaPlayer mp2; etc and im using this in my code to check if any music is playing, stop it, release it, and then play the piece i want,
if(mp!=null&&mp.isPlaying()){
mp.stop();
mp.release();
}
if(mp2!=null&&mp2.isPlaying()){
mp2.stop();
mp2.release();
}
if(mp3!=null&&mp3.isPlaying()){
mp3.stop();
mp3.release();
}
mp3 = MediaPlayer.create(MusicActivity.this, R.raw.snaps);
mp3.setLooping(true);
mp3.start();
this again works but going from one to another and then back crashes the app. is there something else i should be doing? or is just an out of memory error?
EDIT--
Thanks to ranjk89 for his help
changed to soundpools but they wont stop ranjk89 suggests referring to the stream id and not the sound id looking for a little more clarification if possible i have
farmback =0;
drumback =0;
at the top then its loaded in oncreate using
drumback = sp.load(this, R.raw.snaps,1);
farmback = sp.load(this, R.raw.oldmacdonaldbeta,1);
and then way down, in the same method i change the button icons, not the same method i change all my other sounds for my notes i call
sp.stop(drumback);
sp.play(farmback, 1, 1, 0, -1, 1);
in one and
sp.stop(farmback);
sp.play(drumback, 1, 1, 0, -1, 1);
in another but there are 6 different instruments in total that all need a different backing track which should stop when the instrument is changed and play the one associated to it so something like
if (sp !=null && sp.isplaying()){
sp.stop();
sp.play(dumback);
}
but obviously this is not possible any help appreciated
My Initial reaction is, you shouldn't be using multiple MediaPlayer at all in the first place.
I would suggest you to use SoundPool as you can load all the media(audio) initially, once they are all loaded you can play them at will. Plus you won't have multiple players which would downsize the complexity of your code.
But if you do want to use Media player,
See this. But be aware that once you release you will not be able to reuse that instance of MediaPlayer. Even if you are using multiple MediaPlayers, do not call release on them unless you are sure you don't want to use them any more. Use stop()/prepare() combination.
For application doing too much work on the Main Thread,
If you either use a SoundPool or only one MediaPlayer and still bump in to the same issue, Use AsyncTask. Android dev site has a very good tutorial on this
I am using SoundPool to play sfx sounds in a game on Android. In most cases it works perfectly, except sometimes I need to stop all sounds at once not pause (doesn't matter if they are set to loop or not).
I can't figure out how to stop a sound from playing without knowing the StreamID of that sound. What I know:
soundpool.load(...some sound...) returns a soundID
soundpool.play(soundID) plays the sound and returns a streamID
soundpool.stop(streamID) stops the sound
My question is, how can I stop a sound without knowing the streamID ? I tried tracking all streamIDs in a list, but sometimes there are so many short streams playing at once, that it won't work. And I can't find any method in SoundPoolto get the active streamIDs. Does anyone know how to stop all sounds?
Any hint is appreciated! thanks
I'd recommend using autoPause() and autoResume() to pause and restart your sounds. This function is part of the soundpool:
http://developer.android.com/reference/android/media/SoundPool.html#autoPause()
What about using .release() ? Accourding to the documentation:
Release the SoundPool resources. Release all memory and native resources used by the SoundPool object. The SoundPool can no longer be used and the reference should be set to null.
I think it also stops everything. (Actually it was causing a bug at one of my apps, that's why I say it)
However, I believe that if you want to play any sounds later, you may have to load them again.
SoundPool doesn't have a method to retrieve the streamID from the index of the stream, like it should. So even when you know the maximum number of streams, you can't just iterate through like the following:
for(int index=0;index<MAXSTREAMS;index++){
int streamid = SoundPool.getStreamID(index);//getStreamID action doesn't exist :(
soundpool.stop(streamid);
}
As you mentioned, the coder has to manage this himself with a list. I implement the declaration as follows:
List<Integer> streams = new ArrayList<Integer>();
You can add and remove soundIDs to this list as you play and stop sounds as follows:
streams.add(batattack_soundID);
streams.remove(Integer.valueOf(batattack_soundID));//NOT streams.remove(batattack_soundID);
Be sure to use Integer.valueOf() or .remove() will interpret your parameter as an index position, likely giving you an IndexOutOfBoundsException.
To clean everything up you can code as follows:
for (Integer stream : streams) {
soundPool.stop(stream);
}
streams.clear();
I am programming for android 2.2 and am trying to using the
SoundPool class to play several sounds simultaneously but at what feel like random times sound will stop coming out of the speakers.
for each sound that would have been played this is printed in the logcat:
AudioFlinger could not create track. status: -12
Error creating AudioTrack
Audio track delete
No exception is thrown and the program continues to execute without any changes except for the lack of volume. I've had a really hard time tracking down what conditions cause the error or recreating it after it happens. I can't find the error in the documentation anywhere and am pretty much at a loss.
Any help would be greatly appreciated!
Edit: I forgot to mention that I am loading mp3 files, not ogg.
i had almost this exact same problem with some sounds i was attempting to load and play recently.
i even broke it down to loading a single mp3 that was causing this error.
one thing i noted: when i loaded with a loop of -1, it would fail with the "status 12" error, but when i loaded it to loop 0 times, it would succeed. even attempting to load 1 time failed.
the final solution was to open the mp3 in an audio editor and re-edit it with slightly lesser quality so that the file is now smaller, and doesn't seem to take up quite as many resources in the system.
finally, there is this discussion that encourages performing a release on the objects you are using, because there is indeed a hard limit on the resources that can be used, and it is system-wide, so if you use several of the resources, other apps will not be able to use them.
https://groups.google.com/forum/#!topic/android-platform/tyITQ09vV3s/discussion%5B1-25%5D
For audio, there's a hard limit of 32 active AudioTrack objects per
device (not per app: you need to share those 32 with rest of the system), and AudioTrack is used internally beneath SoundPool,
ToneGenerator, MediaPlayer, native audio based on OpenSL ES, etc. But
the actual AudioTrack limit is < 32; it depends more on soft factors
such as memory, CPU load, etc. Also note that the limiter in the
Android audio mixer does not currently have dynamic range compression,
so it is possible to clip if you have a large number of active sounds
and they're all loud.
For video players the limit is much much lower due to the intense load
that video puts on the device.
I'll use this as an opportunity to remind media developers: please
remember to call release() for media objects when your app is paused.
This frees up the underlying resources that other apps will need.
Don't rely on the media objects being cleaned up in finalize by the
garbage collector, as that has unpredictable timing.
I had a similar issue where the music tracker within my Android game would drop notes and I got the Audioflinger error (although my status was -22). I got it working however so this might help some people.
The problem occurred when a single sample was being output multiple times simultaneously. So in my case it was a single sample being played on two or more tracks. This seemed to occasionally deadlock or something and one of the two notes would be dropped. The solution was to have two copies of the sample (two actual ogg files - identical but both in the assets). Then on each track even although I was playing the same sample, it was coming from a different file. This totally fixed the issue for me.
Not sure why it works as I cache the samples into memory, but even loading the same file into two different sounds didn't fix it. Only when the samples came out of two different files did the errors go away.
I'm sure this won't help everyone and it's not the prettiest fix but it might help someone.
john.k.doe is right. You must reduce the size of your mp3 file. You should keep the size under 100kb per file. I had to reduce my 200kb file to 72kb using a constante bit rate(CBR) of 32kbps instead of the usual 128kbps. That worked for me!
Try
final ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 50);
tg.startTone(ToneGenerator.TONE_PROP_BEEP, 200);
tg.release();
Releasing should keep your resources.
I was with this problem. In order to solve it i run the method .release() of SoundPool object after finish playing the sound.
Here's my code:
SoundPool pool = new SoundPool(10, AudioManager.STREAM_MUSIC, 50);
final int teste = pool.load(this.ctx,this.soundS,1);
pool.setOnLoadCompleteListener(new OnLoadCompleteListener(){
#Override
public void onLoadComplete(SoundPool sound,int sampleId,int status){
pool.play(teste, 20,20, 1, 0, 1);
new Thread(new Runnable(){
#Override
public void run(){
try {
Thread.sleep(2000);
pool.release();
} catch (InterruptedException e) { e.printStackTrace(); }
}
}).start();
}
});
Note that in my case my sounds had length 1-2 seconds max, so i put the value of 2000 miliseconds in Thread.sleep(), in order to only release the resources after the player have had finished.
Like said above, there is a problem with looping: when I set repeat to -1 I get this error, but with 0 everything is working properly.
I've noticed that some sounds give this error when I'm trying to play them one by one. For example:
mSoundPool.stop(mStreamID);
mStreamID = mSoundPool.play(mRandID, mVolume, mVolume, 1, -1, 1f);
In such case, first track is played ok, but when I switch sounds, next track gives this error. It seems that using looping, a buffer is somehow overloaded, and mSoundPool.stop cannot release resources immediately.
Solution:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mStreamID = mSoundPool.play(mRandID, mVolume, mVolume, 1, -1, 1f);
}, 350);
And it's working, but delay is different for different devices.
In my case, reducing the quality and thereby the file sizes of the MP3's to under 100kb wasn't sufficient, as some 51kb files worked while some longer duration 41kb files still did not.
What helped us was reducing the sample rate from 44100 to 22050 or shortening the duration to less than 5 seconds.
I see too many overcomplicated answer. Error -12 means that you did not release the variables.
I had the same problem after I played an OGG audio file 8 times.
This worked for me:
SoundPoolPlayer onBeep; //Global variable
if(onBeep!=null){
onBeep.release();
}
onBeep = SoundPoolPlayer.create(getContext(), R.raw.micon);
onBeep.setOnCompletionListener(
new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) { //mp will be null here
loge("ON Beep! END");
startGoogleASR_API_inner();
}
}
);
onBeep.play();
Releasing the variable right after .play() would mess things up, and it is not possible to release the variable inside onCompletion, so notice how I release the variable before using it(and checking for null to avoid nullpointer exceptions).
It works like charm!
A single soundPool has an internal memory limitation of 1 (one) Mb. You might be hitting this if your sound is very high quality. If you have many sounds and are hitting this limit, just create more soundpools, and distribute your sounds across them.
You may not even be able to reach the hard track limit if you are running out of memory before you get there.
That error not only appears when the stream or track limit has been reached, but also the memory limit. Soundpool will stop playing old and/or de-prioritized sounds in order to play a new sound.