19

I am working on an app with recorder and player. I am using mediaplayer to play the recorded .wav file and meantime I want to update to a seekbar. Everything is working fine But my problem is mediaplayer progress updation to seekbar is not happening smoothly, If we are playig a small file, thumb of the seekbar jumps in seconds or between.

Can anyone help me with a workaround to make it smooth seeking of the progress in seekbar. My code is shown below.I am totlay stuck here.

    mediaPlayerIntiate();
    mediaPlayerSetSource();
    mMediaPlayer.start();
    task = new TimerTask() {
                @Override
                public void run() {
                    Graphbar.post(new Runnable() {
                        @Override
                        public void run() {

                            if (mMediaPlayer != null) {

                                if (playButtonState == MediaMode.PLAY) {
                                    if (mMediaPlayer.isPlaying()) {
                                        Graphbar.setProgress(mMediaPlayer
                                                .getCurrentPosition());
                                        mediaPlayerUpdateTimer(mMediaPlayer
                                                .getCurrentPosition());
                                        enableRewindandForward();
                                    }
                                }

                            }

                        }
                    });
                }
            };
            timer = new Timer();
            timer.schedule(task, 0, 8);
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Sreedev
  • 6,563
  • 5
  • 43
  • 66
  • Have You tried just animate (using Property Animation) seek bar instead of calling mMediaPlayer.getCurrentPosition() in case if total duration of record is less than some value? – sandrstar Jul 23 '13 at 10:04
  • 3
    Advice: don't call new Runnable() 125 times in second. You're making too much garbage. – Pointer Null Jul 25 '13 at 04:59
  • What device are you testing this on? I tried your code and the seekbar updates smoothly, even with `1` second playing time(on nexus 4). – Vikram Jul 31 '13 at 05:05
  • Am having a problem when am playing a .wav file can you please let me know how a 1 sec wav file works in ma code. – Sreedev Jul 31 '13 at 06:43

6 Answers6

21

mMediaPlayer.getCurrentPosition() Return current Time in millisecond and you are updating this to Seekbar which maximum capacity is 100. Make one formula to with length of file and 100. try this function

    MediaPlayer mMediaPlayer = new MediaPlayer();
    final SeekBar mSeelBar = new SeekBar(this);
    final int duration = mMediaPlayer.getDuration();
    final int amoungToupdate = duration / 100;
    Timer mTimer = new Timer();
    mTimer.schedule(new TimerTask() {

        @Override
        public void run() {
            runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    if (!(amoungToupdate * mSeelBar.getProgress() >= duration)) {
                        int p = mSeelBar.getProgress();
                        p += 1;
                        mSeelBar.setProgress(p);
                    }
                }
            });
        };
    }, amoungToupdate);

And this process should be called when Media player start playing. inside

    mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

        @Override
        public void onPrepared(MediaPlayer mp) {
        **// call here**
        }
    });

Update

Update 125 times in seconds is not something you should do. Please increase your interval for updating SeekBar. I adding this after reading comments of NullPointer

Mohsinali
  • 543
  • 7
  • 14
Tofeeq Ahmad
  • 11,935
  • 4
  • 61
  • 87
  • Actually am I have the totalduration of playing audiofile in milliseconds and am setting Graphbar.setMax("totalduration"); to seekbar before playing...Seekbar max in millisec and progres upadate is also in millisec so thats not the issue ...Sorry that part of the code is missing in ma question..:-) – Sreedev Jul 30 '13 at 09:46
  • 1
    Ok , then you can try Runnable to update progress, Timer is never recommend to use. Its consume memory leak – Tofeeq Ahmad Jul 30 '13 at 09:50
  • 1
    I used runnable to update the seekbar but its not at all smooth. Vigorously giggling when updating. So what am doin is i update the seekbar 125time in every second yes it helped me to make it somwot smooth but still that jiggling is there...its not happening smoothly – Sreedev Jul 30 '13 at 11:30
  • ok, once see this example http://androidtrainningcenter.blogspot.in/2012/09/media-player-example-in-android-with.html. Try to download and run, uncheck the mark on ziddu else you will not able to download it – Tofeeq Ahmad Jul 30 '13 at 11:36
  • we shud just call mediaplayer.start() in onPreparedlistner ryt?or we shud also start the timer?? – Sreedev Jul 31 '13 at 07:56
  • You should schedule your timertask in onPreparedListener. That mean start timer in onPreparedListener and start the timer too – Tofeeq Ahmad Jul 31 '13 at 08:30
  • Yes this code worked for me...yes the seeking is getting smoother but the problem is seekbar updating is not happening correctly..if we play a long file seeking will happen too fast..i think am near to it..is there somthing am missing?? – Sreedev Aug 01 '13 at 05:30
  • Yes , the only problem is you are interval of update is not correct still. Pay attention to your formula in which you are calculating seeking value – Tofeeq Ahmad Aug 01 '13 at 05:40
  • If you are near to solution using my code then you can award the bounty before it goes to waste :) – Tofeeq Ahmad Aug 01 '13 at 05:48
  • Thankss @Sameer still I need to work on calculating intervals and updating...But this answer did helped me to get somewre near to the solution so accepting this and an upvote for putting this much effort on this issue..and Bonuty off course its urs :-)....Happy coding – Sreedev Aug 01 '13 at 08:33
  • which schedule function you had used in this logic public void schedule (TimerTask task, Date when) or public void schedule (TimerTask task, long delay) – Sreedev Sep 11 '13 at 12:44
8

seekbar.setProgress() only accepts int. Hence, most of us tend to pass the elapsed percentage to this method. However, if you need much smoother progression, then you can use the duration in milliseconds as the MAX. Then we get to update the progression of the seekbar every millisecond. Below is an example and I have updated it every 15th millisecond as almost every android phone comes with a refresh rate of 60 fps (frames per second).

    try{
        mediaPlayer.start();
        seekbar.setProgress(0);
        seekbar.setMax(mediaPlayer.getDuration());

        // Updating progress bar
        seekHandler.postDelayed(updateSeekBar, 15);
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    }

/**
 * Background Runnable thread
 * */
private Runnable updateSeekBar = new Runnable() {
    public void run() {
        long totalDuration = mediaPlayer.getDuration();
        long currentDuration = mediaPlayer.getCurrentPosition();

        // Displaying Total Duration time
        remaining.setText(""+ milliSecondsToTimer(totalDuration-currentDuration));
        // Displaying time completed playing
        elapsed.setText(""+ milliSecondsToTimer(currentDuration));

        // Updating progress bar
        seekbar.setProgress((int)currentDuration);

        // Call this thread again after 15 milliseconds => ~ 1000/60fps
        seekHandler.postDelayed(this, 15);
    }
};

/**
 * Function to convert milliseconds time to
 * Timer Format
 * Hours:Minutes:Seconds
 * */
public String milliSecondsToTimer(long milliseconds){
    String finalTimerString = "";
    String secondsString = "";

    // Convert total duration into time
    int hours = (int)( milliseconds / (1000*60*60));
    int minutes = (int)(milliseconds % (1000*60*60)) / (1000*60);
    int seconds = (int) ((milliseconds % (1000*60*60)) % (1000*60) / 1000);
    // Add hours if there
    if(hours > 0){
        finalTimerString = hours + ":";
    }

    // Prepending 0 to seconds if it is one digit
    if(seconds < 10) {
        secondsString = "0" + seconds;
    }else {
        secondsString = "" + seconds;
    }

    finalTimerString = finalTimerString + minutes + ":" + secondsString;

    // return timer string
    return finalTimerString;
}
Hamzeen Hameem
  • 2,360
  • 1
  • 27
  • 28
4

Here is how i handle the seekbar;

        mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

        @Override
        public void onPrepared(MediaPlayer mp) {
            mediaPlayer.start();
            new SeekBarHandler().execute();
    });

Now i have an Async Task called SeekBarHandler that handles the seekbar like this:

    public class SeekBarHandler extends AsyncTask<Void, Void, Void> {

@Override
protected void onPostExecute(Void result) {
    Log.d("##########Seek Bar Handler ################","###################Destroyed##################");
    super.onPostExecute(result);
}

@Override
protected void onProgressUpdate(Void... values) {
    seekBar.setProgress(mediaPlayer.getCurrentPosition());
    super.onProgressUpdate(values);
}

@Override
protected Void doInBackground(Void... arg0) {
    while(mediaPlayer.isPlaying()&&isViewOn==true) {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    onProgressUpdate();
    }
    return null;
}

    }

Now in my onPause, i terminate the AsyncTask as it doesnt make sense to keep the thread going when the user is not able to see the seekbar

    protected void onPause() {
    isViewOn=false;
    super.onPause();
    }

And on onResume i start the AsyncTaskAgain like this

    protected void onResume() {
    isViewOn=true;
    new SeekBarHandler().execute();
    super.onResume();
    }

As you can see i use a boolean flag isViewOn to check whether the view is on or not to handle the seekbar.

Peshal
  • 1,508
  • 1
  • 12
  • 22
  • Thankzz yes this is working(not as i expected) its happening updating the progress bar when mediaplayer is playing ...but jiggling of the seekbar is still there :-(..I need to update it smoother as possible...UPVOTE for helping me to try one more way as you did...Thankz a lot..but sad its still not that smooth.. – Sreedev Jul 27 '13 at 06:13
  • Hi Sreedev, here is another way you can try to move the seekbar. I wrote this answer while back so i dont know if it still works, but its worth a try :http://stackoverflow.com/questions/9684302/android-mediaplayer-with-seekbar/14976350#14976350 – Peshal Jul 30 '13 at 23:13
  • `If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.` https://developer.android.com/reference/android/os/AsyncTask.html Also AsyncTask by default runs on SERIAL_EXECUTOR, you may want to execute it on THREAD_POOL_EXECUTOR to ensure other tasks are not blocked. – Madeyedexter Dec 29 '16 at 05:59
4
player.prepare(); // or start()

ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.scheduleWithFixedDelay(new Runnable()
{
  @Override
  public void run()
  {
    progressBar.setProgress(player.getCurrentPosition());
  }
}, 1, 1, TimeUnit.MICROSECONDS);
Hun
  • 3,652
  • 35
  • 72
0

The problem you're experiencing has to do with the way Android's SeekBar is designed/implemented. While it functions very well, you're limited by a combination of segments used (i.e. seekbar.setMax(int)) and the delay time of your Handler.

That being said, I subclassed SeekBar to make my own SmoothSeekBar that uses ViewPropertyAnimators instead of a Handler.

Check it out here: https://github.com/Indatus/Android-SmoothSeekBar

jonstaff
  • 2,672
  • 2
  • 19
  • 18
0
private void startPlaying() {
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.reset();
            mediaPlayer.setDataSource(audioPlayerName);
            mediaPlayer.prepare();
            mediaPlayer.start();

            setAudioProgress(); //call method

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


public void setAudioProgress() {
    total_duration = mediaPlayer.getDuration();

    binding.total.setText(timeConversion((long) total_duration));
    binding.current.setText(timeConversion((long) current_pos));
    binding.seekbar.setMax((int) total_duration);

    runnable = new Runnable() {
        @Override
        public void run() {
            try {
                current_pos = mediaPlayer.getCurrentPosition();
                binding.current.setText(timeConversion((long) current_pos));
                binding.seekbar.setProgress((int) current_pos);
                handlerProgressBar.postDelayed(this, 1000);

                Log.e(LOG_TAG, "11111");
            } catch (IllegalStateException ed) {
                ed.printStackTrace();
            }
        }
    };
    handlerProgressBar.postDelayed(runnable, 1000);
}
Mohsinali
  • 543
  • 7
  • 14