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.
Related
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
My app currently uses a SoundPool to manage all the different sounds. When the user taps the button, a sound should play. Since he might push that button quite quickly, the sounds should be able to play on top of each other.
The SoundPool is not able to listen for a sound finishing nor can it get the length of a sound file. Therefore I am thinking about using the MediaPlayer.
I have no experience with the MediaPlayer, but it seems that it is not as straight forward to set up that ability to quickly play a sound. Unfortunately I have to check when a sound finished playing, so I will have to rewrite using the MediaPlayer.
How would you make the MediaPlayer able to play many short sounds?
an instance of a media player plays one sound at a time. it's better to use soundpool..
try this with soundpool...
1) create an int, don't leave it null. somewhere before the onCreate method.
2) in the onCreate method attach a resource to it
3) lastly, apply logic to a button..
int db1, db2, db3, db4, db5 = 0;
db1 = sp.load(this, R.raw.snd1, 1);
db2 = sp.load(this, R.raw.snd2, 1);
db3 = sp.load(this, R.raw.snd3, 1);
db4 = sp.load(this, R.raw.snd4, 1);
db5 = sp.load(this, R.raw.snd5, 1);
samplebutton5.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (db5 != 0)
sp.play(db5, 1, 1, 1, 0, 1);
}
});
To use soundpool if you like you can first get the sound length by using MediaPlayer by using the following method:
private long getSoundDuration(int rawId)
{
MediaPlayer player = MediaPlayer.create(activity, rawId);
int duration = player.getDuration();
player.release();
return duration;
}
And afterwards use an handler and write something like:
handler.postAtTime(this, SystemClock.uptimeMillis() + duration);
The handler will wait until sound is finished to do the next task whatever that may be.
I have a list of songs which may be stored locally in the SD card or may be streamed from the network.Tapping on a song starts playing the song.
When the list contains have all songs to be streamed from the network everything is working fine.
But When I have songs which are stored in the sd card then While a song is playing and I tap on another one the _mediaPlayer.reset() throws an error (-38,0)and code enters the onError function where what=-38 extra=0.
However the really confusing part is that when the player has all the locally stored song and the player is paused then tapping on another song works perfectly fine. It only throws the error when a song was being played. So I tried pausing a song if it is playing but it did not help.
PS: I am encrypting the local files and decrypting the file just before playing and storing the unencrypted file with a fixed name(Ex: current.mp3). I also delete the current.mp3 before deencrypting the ile.
I am using a service to play the songs.Below is the code relevant to my problem.
private static class OnPreparedListener_r implements MediaPlayer.OnPreparedListener
{
Context ctx;
public OnPreparedListener_r(Context c) {
ctx = c;
}
public void onPrepared(MediaPlayer mp) {
Utils.acquireWakeLock();
Utils.requestAudioFocus(ctx);
mp.start();
}
//rest of the code
}
//code to play the song when the user taps on it
/*
if(_mediaPlayer.isPlaying()) { //this I tried adding to solve the issue
pause();
}
*/
_mediaPlayer.reset();
if(currentSong.isLocallyStored()){
DeleteCurrFile();
Decrypt(current_song);
_ mediaPlayer.setDataSource("path to the local file ");
}else{
_mediaPlayer.setDataSource("streaming path ");
}
_mediaPlayer.prepareAsync();
//handling the error
private static class OnErrorListener_r implements MediaPlayer.OnErrorListener
{
Context ctx;
public OnErrorListener_r(Context c) {
ctx = c;
}
public boolean onError(MediaPlayer mp, int what, int extra) {
handleMediaError(ctx);
return true;
}
}
I have been trying to figure out the problem for the last 3-4 days and went through all the links but could not find a good explanation of the error which could explain my situation. Any help would be appreciated
Thanks
I get the same error. I found the root reason:
After MediaPlayer.reset,use getDuration and getCurrentPosition methods.
Please refer to:
http://developer.android.com/reference/android/media/MediaPlayer.html
where you can find:
There is a subtle but important difference between a newly constructed MediaPlayer object and the MediaPlayer object after reset() is called.
It is a programming error to invoke methods such as getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioStreamType(int), setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(int), prepare() or prepareAsync() in the Idle state for both cases.
If any of these methods is called right after a MediaPlayer object is constructed, the user supplied callback method OnErrorListener.onError() won't be called by the internal player engine and the object state remains unchanged; but if these methods are called right after reset(), the user supplied callback method OnErrorListener.onError() will be invoked by the internal player engine and the object will be transfered to the Error state.
In my code, I use TimerTask to get getCurrentPosition and getDuration.
I want to play video in arbitrary time for videoview in Android
_player.setVideoURI(Uri.parse(uri));
MediaController mc = new MediaController(this);
_player.setMediaController(mc);
_player.start();
Now I want set time: 10:20 to seek file and play it (10 min and 20 sec)
see VideoView.seekTo(int msec) method
Also note one thing from the doc
The playback position can be adjusted with a call to seekTo(int).
Although the asynchronuous seekTo(int) call returns right way, the
actual seek operation may take a while to finish, especially for
audio/video being streamed. When the actual seek operation completes,
the internal player engine calls a user supplied
OnSeekComplete.onSeekComplete() if an OnSeekCompleteListener has been
registered beforehand via
setOnSeekCompleteListener(OnSeekCompleteListener).
You have to wait until the video is prepared to seek.
int seekTimeMs = (10 * 60 + 20) * 1000; // 10:20
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.seekTo(seekTimeMs);
}
});
Ok well I have been fighting with this for a while now and have soundboard apps that I havn't ran into this problem in. I am developing a widget that allows for a sound to be played when a button is pressed on the widget.
I am assuming I am just not using the setOnPreparedListener properly but basically what is happening is that some of my sounds play correctly and more likely than not the sounds will cut off the last part noticeable by word or sound effect missing. Below is my code please let me know if you have any idea what's wrong with the code or post a working revision.
Thanx in advance.
public int onStartCommand(Intent intent, int flags, int startId) {
/** Get our place holder for quotes & sounds. */
int s = UpdateService.getQuoteNumber();
/** Check if a sound is playing if so... stop and reset it. */
if (mp != null && mp.isPlaying()){mp.stop();mp.reset();}
/** Create a new mediaplayer and set looping. */
mp = MediaPlayer.create(this, SoundsClicked.randomSound[s]);
mp.setLooping(false);
/** Try to prepare the sound/mediaplayer, if not report error & type. */
try {mp.prepare();}
catch (IllegalStateException e) {e.printStackTrace();Log.e(Integer.toString(s), "IllegalStateException");}
catch (IOException e) {e.printStackTrace();Log.e(Integer.toString(s), "IOException");}
/** Check if the sound is prepared, if so play it. */
mp.setOnPreparedListener(new OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mp.start();
while (mp.isPlaying()) {};
}
});
return flags;}
This is called from a service (obviously from the onStartCommand) but figured I would throw that out there for those not familiar with some of the methods.
If you're using Android 2.2, there are apparently some problems with the MediaPlayer cutting off the last X% of at least some audio files. I'm running in to that problem with the app I'm currently working on. I haven't found if there is a solution or not.