I have set:
mSeekBar.setMax(mp.getDuration()); // 8480
After completion of Audiofile, What I am getting is:
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer)
{
Log.e("onComplete>>", ""+mediaPlayer.getCurrentPosition());
// mediaPlayer.getCurrentPosition() = 8192
Log.e("getDuration", ""+mediaPlayer.getDuration());
// mediaPlayer.getDuration() = 8480
if(mediaPlayer.getCurrentPosition()>=mediaPlayer.getDuration())
{
// Why never get called???
}
}
});
So, Why is MediaPlayer's Current position never reaches the total duration of Audio file ?
Or technically we can say as:
Why Not?
mediaPlayer.getCurrentPosition()==mediaPlayer.getDuration()
Why Always
mediaPlayer.getCurrentPosition() < mediaPlayer.getDuration()
in OnCompletion listener?
For Example:
I have a Play Symbol for starting the Player. Now when I press play symbol it will convert to Pause symbol.
I have a Maxduration of audiodfile.
Now I want to convert Pause symbol to Play Symbol when Audio file is played completely.
SO what I am doing is Checking:
if(mediaPlayer.getCurrentPosition()>=mediaPlayer.getDuration())
{
// Convert Imagview from Pause to Play
// But never get called
}
If you need to do some task on completion by checking currentPoision to duration, you can do below trick:
if(mediaPlayer.getDuration()-mediaPlayer.getCurrentPosition()<1000){//milliseconds
new Handler().postDelayed(
new Runnable() {
#Override
public void run() {
// Convert Imageview from Pause to Play
}
},1000);
}
Related
I'm trying to get the duration of a .ogg audio file from the web. I always get -1 as result of getDuration(). Here's my code:
String audioUrl = "URLHERE";
mMediaPlayer.setDataSource(audioUrl);
mMediaPlayer.prepareAsync(); //Also tried with prepare(), same result
Inside OnViewCreated method of my fragment I use the setOnPreparedListener to know when MediaPlayer is prepared, and here I use the getDuration method:
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
int duration = mp.getDuration(); //ALWAYS -1
}
});
So here I always get -1. I don't think is because of the audio format, because the audio is loaded correctly, and with the .start() method I can hear it.
I'm creating a simple soundboard to play sounds when a user clicks a button. Problem is, if the button is pressed enough ( usually around 10 times ) it will eventually stop playing and show the error E/MediaPlayer: error (1, -19)
what am I doing wrong? My code that plays the sound:
private void playSound(int soundID){
final MediaPlayer mp = MediaPlayer.create(this,soundID);
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mp.start();
}
});
}
You should use Soundpool. It's created exactly for playing short sound effects. And it's much simpler to use than MediaPlayer. MediaPlayer should only be used for playing regular/large music.
See here for example:
http://www.vogella.com/tutorials/AndroidMedia/article.html#tutorial-play-sounds-via-soundpool
Note: No need to use onTouch as in the example, you can just use onClick for simplicity.
Reason: "W/Choreographer: (let say) Frame time is 0.239384 ms in the future! Check that graphics HAL is generating vsync timestamps using the correct timebase."
i.e, there is a much gap between timestamps.
This problem can be removed by using setOnCompletionListener() within your OnClick() method like: `
#Overrid
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
// Get the {#link Word} object at the given position the user clicked on
Word word = words.get(position);
Log.v("NumbersActivity","Current word: "+word);
// Create and setup the {#link MediaPlayer} for the audio resource associated with the current word
MediaPlayer mMediaPlayer = MediaPlayer.create(NumbersActivity.this, word.getAudioResourceId());
// Start the audio file
mMediaPlayer.start();
// Keep timeStamp sync
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
mMediaPlayer.release();
}
});
}
`
private void playSound(int soundID){
final MediaPlayer mp = MediaPlayer.create(this,soundID);
mp.start();
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
mp.release();
}
});
}
I am currently using the Glide library to show a gif in my android device, on specific event, but now I also want to set audio as background when the gif is playing, and when it stops the audio also stops!
Attempt:
Glide.with(this).load(R.drawable.somegifFile).into(imageView);
try {
if (mp.isPlaying()) {
mp.stop();
mp.release();
mp = MediaPlayer.create(context, R.raw.sound);
}
mp.start();
} catch(Exception e) { e.printStackTrace(); }
Ok try this
1. First check weather image view is null or it's not loaded with an image
2. If its loaded then it means gif starts working .. then start a timer and make it call after every 10 seconds
3. inside that's run() method refresh the audio like you did
private void startWaitingTimeRunner() {
waitingTimer = new Timer();
waitingTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// reset audio -> stop , release , play gain
}
}, 0, 10000);
}
this following source code snippet is given:
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END){
activity.dismissDialog(DialogID.DIALOG_LOADING);
return true;
}
return false;
}
});
}
});
I am streaming HLS streams with Android 3.x+ devices and trying to hide a loading dialog once the buffering is completed.
The video streaming works, but the info events are never fired.
Any ideas?
I know its too late, But posting it for the users still seeking for the solution (This worked for me):
progressDialog.show();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END){
progressDialog.dismiss();
return true;
} else if(what == MediaPlayer.MEDIA_INFO_BUFFERING_START){
progressDialog.show();
}
return false;
}
});
progressDialog.dismiss();
videoView.start();
}
});
You're right, the events are never fired. This is a known HLS bug that I don't think Google will fix.
This applies to the onInfo and the buffering events.
See https://code.google.com/p/android/issues/detail?id=42767 and https://code.google.com/p/googletv-issues/issues/detail?id=2
Sorry!
Not fully sure as to what the OP is asking, but here are some very untimely bits of information.
I wouldn't rely on onPrepared. I find it to be unreliable.
I have found the two most useful pieces of information for HLS streaming through the MediaPlayer are the duration of the video and the progress position of the video. You get both of these by listening to progress updates.
When the duration is greater than zero, you know the video is truly prepared and can be manipulate (scrub). When progress position changes, you know the video is done buffering and has commenced playback. This last item only works when the video is playing of course. The MediaPlayer tends to relay inaccurate information.
These pieces of information are mostly accurate and can usually be relied upon to be "fairly" timely. This timeliness varies from device to device.
onPrepared is called when the MediaPlayer is prepared to start buffering, not when the video is completely buffered. However, it is completely natural to dismiss the loading dialog from within the onPrepared method.
Also MEDIA_INFO_BUFFERING_END is used when MediaPlayer is resuming playback after filling buffers, so I do not think it should be something to use to dismiss the dialog. So this should work:
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
activity.dismissDialog(DialogID.DIALOG_LOADING);
}
});
You can able to set OnPreparedListener on videoView because its your object but if you checkout source of VideoView you will find that mMediaPlayer is its private member so any change that you do from external will not be applied to it.
As per your requirement you need buffering status so you can have thread or handler or some thing so you can update your UI to get buffer status there is one method
int percent = videoView.getBufferPercentage();
if(percent == 100){
// buffering done
}
You no need to go through setOnInfoListener
by overriding setOnPreparedListener method is enough. as in the api show
public void setOnPreparedListener (MediaPlayer.OnPreparedListener l)
Register a callback to be invoked when the media file is loaded and
ready to go.
so, you can dismiss your dialog inside setOnPreparedListener method is enough
like this
vv.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "finish11", Toast.LENGTH_LONG).show();
}
});
}
});
If you want to show loading each time it's buffering (initial time or subsequent buffer underruns) just ensure to show it again:
// at the beginning
show
boolean onInfo(int what, int extra) {
switch (what) {
case MEDIA_INFO_BUFFERING_END:
"hide";
break;
case MEDIA_INFO_BUFFERING_START
"show":
}
}
So this event sequence will do as desired:
- whenever you start (setVideoURI or start): show
- onPrepared: just plug the info listener
- onInfo BUFFERING_END hide (it's playing)
- onInfo BUFFERING_START show (it's buffering again)
- onInfo BUFFERING_END hide (it's playing)
Update:
This is assuming the info events work. Of course.
The MediaPlayer's getDuration() method is giving me an incorrect value for some audio files. I think the common trait for all these files is that they were manipulated using Audacity or some other audio editing tool. This is a problem when trying to tie MediaPlayer progress to a Progress Bar.
I went ahead and logged it:
while(mPlayer.isPlaying())
Log.i("progress/total",
mPlayer.getCurrentPosition() +
"/" + mPlayer.getDuration());
and found this:
I/progress/total(643): 14615/14620
I/progress/total(643): 14647/14620
This is only two log line of thousands, but the point is after the progress passes what getDuration() believes to be the total duration of the song, it just keeps going. Because the MediaPlayer can in fact give the correct total for duration, is there a way to use this to get a proper maximum for my ProgressBar?
I had similar problem when MediaPlayer.getDuration() returned 542434 ms for mp3 file (HTC Desire C with ICS 4.0.3).
File itself was around 89 seconds, difference is too big.
I checked mp3 file content and saw some strange xml like:
<?xpacket begin="п»ї" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.2-c063 53.351735, 2008/07/22-18:04:26 ">
After saving this file as new one that xml was dropped and getDuration() returned correct value.
I know that it will not help those who need playing files you can't modify, but for those who can - it should help.
I was trying to play demo player a few while ago ,when i tested in Android emulator ,its behavior was the same as like you mentioned in your question but when i tried in some real device it gave me accurate value of media duration.
If your intention is only play media syncing with seekbar then you can do something like below ,
if (!mediaPlayer.isPlaying())
mediaPlayer.start();
handler.post(new SeekbarRefresh(seekbar));
//Class to update progress of seekbar according to music player
private class SeekbarRefresh implements Runnable {
SeekBar seekBar;
public SeekbarRefresh(SeekBar seekBar, ImageView imageView) {
this.seekBar = seekBar;
}
#Override
public void run() {
if (mediaPlayer != null) {
if (mediaPlayer.getDuration() > 0) {
int currentDuration = mediaPlayer.getCurrentPosition();
seekBar.setProgress(currentDuration);
if (mediaPlayer.isPlaying()){
handler.post(this);
isAudioPlaying = true;
}
else {
handler.removeCallbacks(this);
isAudioPlaying = false;
}
}
}
}
}
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
mediaPlayer.seekTo(progress);
}
});
I have encountered a similar situation. In my case the time difference between mPlayer.getDuration() to mPlayer.getCurrentPosition() was around 80 seconds.
After reading few posts on the subject, I used third party software to convert the mp3's sample rate from 22,000 kHz to 44,100 kHz. Once converted, the result of getDuration() and getCurrentPosition() are the almost the same (0.0012s constant error).
Here is the test used:
dur = mp.getDuration();
Log.d("dur", dur + " <- getDuration");
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
// finish current activity
Log.d("dur", mp.getCurrentPosition() + " <- getCurrentPostion");
}
});