2

I am playing audio file of different sizes in my application and while audio is playing the progress bar should progress smoothly but progress bar is taking random size steps.

I am using following code :

 mp = new MediaPlayer(); 
 mp.setDataSource("audio file path");
 mp.prepare();
 mp.start();
 pb.setMax(mp.getDuration());
            new AsyncTask<Void, Integer, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    while(mp.isPlaying())
                    {
                     publishProgress(mp.getCurrentPosition);
                    }
                    return null;
                }
                 protected void onProgressUpdate(Integer... progress) {
                     pb.setProgress(progress[0]);
                 }
                @Override
                protected void onPostExecute(Void result) {
                    super.onPostExecute(result);
                    mp.stop();
                    mp.release();
                }
            }.execute();

Is there any way to smoothly increase progressbar?

cordeiro
  • 121
  • 1
  • 12
DCoder
  • 3,486
  • 7
  • 36
  • 68
  • Key to smoothly increase progress bar is to increase its value by 1 till audio is playing and do not depend on MediaPlayer.getCurrentPosition() method. – DCoder Mar 18 '14 at 12:30

5 Answers5

4

Please check this steps

Step 1: Get audio duration with MediaPlayer.getDuration()

Step 2: Set ProgressBar progress max. value to value from step 1

Step 3:

Update progress bar periodically from MediaPlayer.getCurrentPosition(), while media playing using Handler.

So the code will be like this

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

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

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

I followed this link for the code

Community
  • 1
  • 1
NullPointerException
  • 3,978
  • 4
  • 34
  • 52
  • yeah... thats what I am doing now.. but Progress bar is increasing in steps not smoothly.. – DCoder Mar 18 '14 at 10:39
  • check edited answer that 1 helped me during my implementation – NullPointerException Mar 18 '14 at 10:46
  • A better implementation: ScheduledExecutorService service = Executors.newScheduledThreadPool(1); service.scheduleWithFixedDelay(new Runnable() { @Override public void run() { progressBar.setProgress(player.getCurrentPosition()); } }, 1, 1, TimeUnit.MICROSECONDS); – Shubham Oct 19 '15 at 10:50
2

Set the Max size of progress bar to a high range... If u set the progress bar to increment between 1 to maximum 100, then rather than using 100 as max use 1000 in place..This is a suggestion from me. Coz i found your code working ok.

Nithin Michael
  • 2,166
  • 11
  • 32
  • 56
2

This is my mediaplayer creation , just check it out .

  public TextView songName,startTimeField,endTimeField;
   private MediaPlayer mediaPlayer;
   private double startTime = 0;
   private double finalTime = 0;
   private Handler myHandler = new Handler();;
   private int forwardTime = 5000; 
   private int backwardTime = 5000;
   private SeekBar seekbar;
   private ImageButton playButton,pauseButton;
   public static int oneTimeOnly = 0;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      songName = (TextView)findViewById(R.id.textView4);
      startTimeField =(TextView)findViewById(R.id.textView1);
      endTimeField =(TextView)findViewById(R.id.textView2);
      seekbar = (SeekBar)findViewById(R.id.seekBar1);
      playButton = (ImageButton)findViewById(R.id.imageButton1);
      pauseButton = (ImageButton)findViewById(R.id.imageButton2);
      songName.setText("song.mp3");
      mediaPlayer = MediaPlayer.create(this, R.raw.song);
      seekbar.setClickable(false);
      pauseButton.setEnabled(false);

   }

   @TargetApi(Build.VERSION_CODES.GINGERBREAD) public void play(View view){
   Toast.makeText(getApplicationContext(), "Playing sound", 
   Toast.LENGTH_SHORT).show();
      mediaPlayer.start();
      finalTime = mediaPlayer.getDuration();
      startTime = mediaPlayer.getCurrentPosition();
      if(oneTimeOnly == 0){
         seekbar.setMax((int) finalTime);
         oneTimeOnly = 1;
      } 

      endTimeField.setText(String.format("%d min, %d sec", 
         TimeUnit.MILLISECONDS.toMinutes((long) finalTime),
         TimeUnit.MILLISECONDS.toSeconds((long) finalTime) - 
         TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.
         toMinutes((long) finalTime)))
      );
      startTimeField.setText(String.format("%d min, %d sec", 
         TimeUnit.MILLISECONDS.toMinutes((long) startTime),
         TimeUnit.MILLISECONDS.toSeconds((long) startTime) - 
         TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.
         toMinutes((long) startTime)))
      );
      seekbar.setProgress((int)startTime);
      myHandler.postDelayed(UpdateSongTime,100);
      pauseButton.setEnabled(true);
      playButton.setEnabled(false);
   }

   private Runnable UpdateSongTime = new Runnable() {
      @TargetApi(Build.VERSION_CODES.GINGERBREAD) public void run() {
         startTime = mediaPlayer.getCurrentPosition();
         startTimeField.setText(String.format("%d min, %d sec", 
            TimeUnit.MILLISECONDS.toMinutes((long) startTime),
            TimeUnit.MILLISECONDS.toSeconds((long) startTime) - 
            TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.
            toMinutes((long) startTime)))
         );
         seekbar.setProgress((int)startTime);
         myHandler.postDelayed(this, 100);
      }
   };
   public void pause(View view){
      Toast.makeText(getApplicationContext(), "Pausing sound", 
      Toast.LENGTH_SHORT).show();

      mediaPlayer.pause();
      pauseButton.setEnabled(false);
      playButton.setEnabled(true);
   }    
   public void forward(View view){
      int temp = (int)startTime;
      if((temp+forwardTime)<=finalTime){
         startTime = startTime + forwardTime;
         mediaPlayer.seekTo((int) startTime);
      }
      else{
         Toast.makeText(getApplicationContext(), 
         "Cannot jump forward 5 seconds", 
         Toast.LENGTH_SHORT).show();
      }

   }
   public void rewind(View view){
      int temp = (int)startTime;
      if((temp-backwardTime)>0){
         startTime = startTime - backwardTime;
         mediaPlayer.seekTo((int) startTime);
      }
      else{
         Toast.makeText(getApplicationContext(), 
         "Cannot jump backward 5 seconds",
         Toast.LENGTH_SHORT).show();
      }

   }
kathir
  • 489
  • 2
  • 11
0

You can make it smoother by using following logic.

  1. Store current value of progress bar and latest progress value as members.

  2. Update latter when onProgressUpdate method is called.

  3. In a timer, put this logic to be executed periodically.

    if (currentValue < latestProgress) {
        currentValue++;
        pb.setProgress(currentValue);
    }
    

    Note that it will slowly march towards it's target value.

Hope this helps.

Tanmay Patil
  • 6,882
  • 2
  • 25
  • 45
  • By printing value of mp.getCurrentPosition in LogCat I found out that the values are not linear.. at some point it stays constant for a while and then jumps randomly.. I have already tried to smooth progress by adding to current progress bar value till getCurrentPosition() returns different value.. but its not working as expected.. – DCoder Mar 18 '14 at 10:52
  • Did you use timer to put time gap in successive addition in current value? – Tanmay Patil Mar 18 '14 at 10:55
  • Separating each update with small time gaps like 50 ms or 200 ms would give you the smoothing effect. Timers are easy to implement, you can have a look at an example here. http://stackoverflow.com/questions/4597690/android-timer-how – Tanmay Patil Mar 18 '14 at 11:25
0

Although the suggestion of using Handler to track the current position of Audio while playing is the only correct way. However, MediaPlayer.getCurrentPosition() not super precise for short audio (saying, about 1 second); and to make life easier I wrote a Utils class to support this purpose by using CountDownTimer

Link demo: https://github.com/mttdat/utils

Nguyen Tan Dat
  • 3,780
  • 1
  • 23
  • 24