While I am scanning racks using barcode, I implemented a singleton class of soundpool, while continue scans, automatically app closed. The error is "Could not read input channel file descriptors from parcel".
public void successfulAlert() {
Logger.d("", "SuccessAlert Start" + Calendar.getInstance().getTimeInMillis());
final int audioID = mSPool.load(Application.getInstance(), R.raw.scan, 1);
mSPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
Logger.d("", "SuccessAlert Completed " + Calendar.getInstance().getTimeInMillis());
float volume = (float) mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
mSPool.play(audioID, volume, volume, 1, 0, 1f);
/// cleanupSound();
}
});
Logger.d(TAG, "Possitive Scan Beep ");
}
This code for success alert, I try to cleanup the soundpool release, sound not heared. Can anyone suggest me, how to release soundpool after playing a sound.
public void cleanupSound() {
if (mSPool != null) {
mSPool.release();
// mSPool=null;
// mAudioManager.unloadSoundEffects();
// mInstance=null;
}
}
The Question is two fold:
1) Why is my sound not playing?
2) How do I correctly release a SoundPool?
For 1 - SoundPool play is asynchronous. You are doing: "play then release" but you need to do "play then wait-until-play-has-completed then release".
For 2 - Due to 1, you ought not to release a SoundPool until play has completed. Unfortunately, there is no way to ask the SoundPool to callback when it has finished playing. I've seen two solutions to this:
If you know how long it will take to play the sample (X ms), schedule your release, for X ms in the future, perhaps using postDelayed from Handler.
Decide that the truly important concern is that the SoundPool is released when your application is finished. So, monitor all exit points from your application, and ensure that, at each, the SoundPool is released. If someone closes the application while you are playing sound, you might abruptly cut that effect, but this is probably the correct behaviour as your application is exiting!
Note: To be a truly well behaved Android citizen, your application should only play sound if it has first acquired, and continues to hold, the Audio Focus. More info on that here: https://developer.android.com/guide/topics/media-apps/volume-and-earphones.html
Related
I am having a bit of difficulty with my SoundPool. I have an ArrayList<Integer> of my soundIDs located in my res/raw folder. I'm creating the SoundPool like so in my ViewHolder class for my RecyclerView:
//create the SoundPool
sp = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);
//create the AudioManager for managing volume
audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
//store the streamVolume in an int
streamVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
//set the load listener for my soundfiles
sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
loaded = true;
}
});
I am playing the sound on the click of an ImageView like so:
#Override
public void onClick(View v) {
if (v.equals(cardImg)) {
sp.load(context, cardData.getSoundId(), 1);
if (loaded) {
sp.play(cardData.getSoundId(), streamVolume, streamVolume, 1, 0, 1f);
}
}
}
And every time I click on the cardImg it gives me this error:
W/SoundPool﹕ sample 2130968609 not READY
Where the sample int changes depending on which card I click, like it should.
So I know that it's GETTING the proper soundID from my ArrayList (stored in CardData class), and it definitely sees that it's loaded, because it wouldn't try to play otherwise because loaded would never be true. My question is: Why are my sounds never ready?
My sounds are .m4a format which Android says is supported in the documentation. I've tried on an Android 5.0 device and an Android 4.4 device but nothing changes.
I have tried using a MediaPlayer but I am running into memory errors as I have many short clips that need to be able to be spammed and I read that a SoundPool was a much better way to manage this (?).
Any help would be appreciated! I am super vexxed here.
You're using the wrong id. SoundPool.load returns an id that is suppose to be passed in to SoundPool.play.
I have a class that extends Service, where i have a MediaPlayer that manages the background music of my app.
MediaPlayer player = MediaPlayer.create(this, R.raw.background_music);
player.setLooping(true);
The problem is that it doens't "loop" well: I mean, when the mp3 file ends, there's a second of silence before it starts again.
But, in the mp3 file, actually, there's not any second of silence.
How can i solve this problem?
You can't. This bug has been there for ages now, but they still didn't fix it and it does not look like they are going to do it in the close future!
http://code.google.com/p/android/issues/detail?id=18756
You can try to use SoundPool to play your audio file (it loops very well and without delay, however might be inappropriate for some audio resources).
Here is some kind of implementation (deprecation removal and appropriate closing of resource is left as a homework :))
SoundPool pool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
afd = getResources().openRawResourceFd(audioResource);
pool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
if (0 == status) {
soundPool.play(sampleId, 1f, 1f, 10, -1 /* looping parameter */, 1f);
}
}
});
pool.load(afd, 10);
afd.close();
From other side if MediaPlayer is a must have you might look into method setNextMediaPlayer. So the idea is to initialize several MediaPlayers for the same file (what a mess) and set them in a smart way.
I'm currently working on an app that has to play audio. I have a method that plays a series of .mp3's in order. Here is the method:
/**
* Plays a series of sounds in order without delay.
*
* #param audioResourceIds
* An in-order array of the audio asset resources to play.
* */
public void playQueuedPlaylist(int[] audioResourceIds)
{
float lastPlayedSoundDuration;
for(int i = 0; i<audioResourceIds.length; i++)
{
lastPlayedSoundDuration = playMedia(audioResourceIds[i], null);
try
{
Thread.sleep((long)lastPlayedSoundDuration);
}
catch(Exception eh)
{
Log.v("BulacsAlmighty","Exception caught at playQueuedPlaylist()");
}
}
}
/**
* Used to play voice overs
*
* #param index
* id of the sound
* #param listener
* on completion listener
*/
public int playMedia(int index, OnCompletionListener listener)
{
MediaPlayer mp = MediaPlayer.create(context, index);
mp.setVolume(streamVolume, streamVolume);
stopMedia(index); // Stops the sound if it still is playing.
mp.start();
return mp.getDuration();
}
The problem is that the sounds sometimes do not play. And when they play, the timing is correct, the order is correct, but the last audio resource played is played at a significantly lower volume than the other sounds played before it.
Tell me, where did I go wrong!?
How are you stopping the previous tracks if you are not storing and releasing the associated MediaPlayer for that track? How does stopMedia work?
setVolume will fail if the MediaPlayer is on the Error state. Please set On<Event>Listeners so that you can really find out what is happening with the previously played MediaPlayers. Particularly, you might be interested in implementing OnInfoListener and OnPreparedListener.
Also, how is streamVolume modified? You might have a race condition somewhere and that code might be setting streamVolume preemptively. Please check all code that are modifying streamVolume.
Just curious why do you call
mp.setVolume(streamVolume, streamVolume);
at all? Is it really necessary? You don't mention why the volume needs to be adjusted from code.
I have a small app that basically sets up a timer and plays sets of 2 sounds one after another.
I've tried 2 timers, because I wanted both sounds to start exactly at the same time each time. I gave the app 500ms for setting both timers before they start
Calendar cal = Calendar.getInstance();
Date start = new Date(cal.getTime().getTime() + 500);
timerTask1 = new TimerTask() { //1st timer
#Override
public void run() {
soundManager.playSound(1);
}
};
timer1 = new Timer();
timer1.schedule(timerTask1, start, 550);
timerTask2 = new TimerTask() { //2nd timer
#Override
public void run() {
soundManager.playSound(2);
}
};
timer2 = new Timer();
timer2.schedule(timerTask2, start, 550);
}
soundManager is a SoundManager object which is based on this tutorial. Thew only change I've made was decreasing number of avalible streams from 20 to 2 since I play only 2 sounds at the same time.
Now the problem. It's not playing at the equal rate neither on my Motorola RAZR or the emulator. The app slows sometimes, making a longer brake than desired. I can't let that happen. What could be wrong here?
I'm using very short sounds in OGG format
EDIT:
I've made some research. Used 2 aproaches. I was measuring milisecond distances between sound was fired. Refresh rate was 500 ms.
1st aproach was TimerTask - it is a big fail. It started at 300ms, then was constantly growing, and after some time (2 mins) stabilized at 497ms which would be just fine if it started as that.
2nd aproach was while loop on AsyncTask - it was giving me outputs from 475 to 500ms which is better than TimerTask but still inaccurate
At the end none of aproach was playing smoothly. There were always lags
I know it may be a little too much, but you could try a different implementation of SoundPool:
public class Sound {
SoundPool soundPool;
int soundID;
public Sound(SoundPool soundPool, int soundID) {
this.soundPool = soundPool;
this.soundID = soundID;
}
public void play(float volume) {
soundPool.play(soundID, volume, volume, 0, 0, 1);
}
public void dispose() {
soundPool.unload(soundID);
}
}
To use it you can do something like this:
SoundPool soundPool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);
AssetFileDescriptor assetFileDescriptor = activity.getAssets().openFd(fileName);
int soundID = soundPool.load(assetFileDescriptor, 0);
Sound sound = new Sound(soundPool, soundID);
And then play:
sound.play(volume);
P.S. If the problem persists even with this code, post a comment and I'll get back to you.
Are you using SoundPool? It is quicker than MediaPlayer. The best chance of getting the two sounds together is when playing them on the same thread.
I have a class called Sound.java that consists of 3 functions (initSound, addSound, and playSound).
public static void initSound(Context con) {
mContext = con;
soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
soundPoolMap = new HashMap<Integer, Integer>();
audioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
streamVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
streamVolume = streamVolume / audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
}
public static void addSound(int index, int SoundID) {
soundPoolMap.put(index, soundPool.load(mContext, SoundID, 1));
}
public static void playSound(int index) {
soundPool.play(soundPoolMap.get(index), streamVolume, streamVolume, 1, 0, 1f);
}
I called the initSound and addSound in the MainGame.java constructor.
Sound.initSound(getContext());
Sound.addSound(1, R.raw.machine_gun);
and called playSound inside a Thread (looping) in MainGame.java. PlaySound called every second when an event is triggered (for example, when an enemy is in sight, troops (more than one) will shoot (play the sound) continuously until the enemy is dead).
Sound.playSound(1);
The problem is when the sound plays, the app is slowing down.
I'm using soundpool because as far as I know for sound effects, soundpool is better than mediaplayer. (I've tried mediaplayer and the lag is even more.)
The sound file that I use is .wav (unsigned 8bit PCM, 1 Channel, 8000hz) with size 5.44KB.
Is there a better way to play effect sounds without slowing the game performance, or is mine wrong? I really appreciate any ideas and responses.
According to the SoundPool docs, it decodes to 16-bit PCM, so you could change to that and see if you get some performance out of that. Other than that, your code seems pretty similar (at least as far as I can remember) to stuff I've done before and I didn't see any significant perf problems (I believe I wasn't even using WAV, I was just using OGGs, but I don't remember for sure). Are you trying this on an actual device, or just the emulator?
I had the same problem. Then I've created a new thread for the soundpool and added 20ms sleep into the while loop. The problem is gone.