SeekBar and media player in android

AndroidAndroid MediaplayerAndroid Seekbar

Android Problem Overview


I have a simple player and recorder. Everything works great but have a one problem. I want to add seek bar to see progress in playing record and use this seek bar to set place from player should play. I have onProgress but with no effect. This is code:

package com.example.recorder;

import java.io.IOException;

import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class MainActivity extends Activity implements OnSeekBarChangeListener
{
    private static final String LOG_TAG = "AudioRecordTest";
    private static String mFileName = null;
    private SeekBar seekBar;
    private MediaRecorder mRecorder = null;
    private Button startRecord, startPlaying, stopPlaying;
    private MediaPlayer   mPlayer = null;

    private void onRecord(boolean start) {
        if (start) {
            startRecording();
        } else {
            stopRecording();
        }
    }


    
    private void startPlaying() {
    	if(mPlayer != null && mPlayer.isPlaying()){
            mPlayer.pause();
        } else if(mPlayer != null){
        	mPlayer.start();
        }else{
        mPlayer = new MediaPlayer();
        try {
        	
            mPlayer.setDataSource(mFileName);
            mPlayer.prepare();
            mPlayer.start();
            
        } catch (IOException e) {
            Log.e(LOG_TAG, "prepare() failed");
        }
        }
    
    }

    private void stopPlaying() {
        mPlayer.release();
        mPlayer = null;
        startPlaying.setText("Start playing");
    }

    private void pausePlaying(){
        if(mPlayer.isPlaying()){
            mPlayer.pause();
        } else {
          mPlayer.start();
        }
    }
    
    private void startRecording() {
        mRecorder = new MediaRecorder();
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mRecorder.setOutputFile(mFileName);
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

        try {
            mRecorder.prepare();
        } catch (IOException e) {
            Log.e(LOG_TAG, "prepare() failed");
        }

        mRecorder.start();
    }

    private void stopRecording() {
        mRecorder.stop();
        mRecorder.release();
        mRecorder = null;
    }



    public MainActivity() {
        mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
        mFileName += "/audiorecordtest.3gp";
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        setContentView(R.layout.activity_main);
        
        startPlaying = (Button) findViewById(R.id.buttonStartPlay);
        stopPlaying = (Button) findViewById(R.id.buttonStopPlaying);
        startRecord = (Button) findViewById(R.id.buttonStartRecord);
        seekBar = (SeekBar) findViewById(R.id.seekBar);
        
        startRecord.setOnClickListener(new OnClickListener() {
        	boolean mStartRecording = true;
			@Override
			public void onClick(View v) {
				onRecord(mStartRecording);
                if (mStartRecording) {
                    startRecord.setText("Stop recording");
                } else {
                    startRecord.setText("Start recording");
                }
                mStartRecording = !mStartRecording;
				
			}
		});  
        
        
        startPlaying.setOnClickListener(new OnClickListener() {
        	boolean mStartPlaying = true;
			@Override
			public void onClick(View v) {
				//onPlay(mStartPlaying);
				startPlaying();
                if (mStartPlaying) {
                    startPlaying.setText("Stop playing");
                } else {
                    startPlaying.setText("Start playing");
                }
                mStartPlaying = !mStartPlaying;
			}
		});
        
        stopPlaying.setOnClickListener(new OnClickListener() {
        	boolean mStartPlaying = true;
			@Override
			public void onClick(View v) {
			     stopPlaying();
				
			}
		});
        
        
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mRecorder != null) {
            mRecorder.release();
            mRecorder = null;
        }

        if (mPlayer != null) {
            mPlayer.release();
            mPlayer = null;
        }
    }



	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
		if(fromUser){
		    mPlayer.seekTo(progress); 
		    seekBar.setProgress(progress);
	        }
	        else{
	         // the event was fired from code and you shouldn't call player.seekTo()
	        }
		
	}



	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {
		// TODO Auto-generated method stub
		
	}



	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {
		// TODO Auto-generated method stub
		
	}
}

Any ideas how use seek bar to see progress and set place from record should play?

Android Solutions


Solution 1 - Android

To create a 'connection' between SeekBar and MediaPlayer you need first to get your current recording max duration and set it to your seek bar.

mSeekBar.setMax(mFileDuration/1000); // where mFileDuration is mMediaPlayer.getDuration();

After you initialise your MediaPlayer and for example press play button, you should create handler and post runnable so you can update your SeekBar (in the UI thread itself) with the current position of your MediaPlayer like this :

private Handler mHandler = new Handler();
//Make sure you update Seekbar on UI thread
MainActivity.this.runOnUiThread(new Runnable() {
	
	@Override
	public void run() {
		if(mMediaPlayer != null){
			int mCurrentPosition = mMediaPlayer.getCurrentPosition() / 1000;
			mSeekBar.setProgress(mCurrentPosition);
		}
		mHandler.postDelayed(this, 1000);
	}
});

and update that value every second.

If you need to update the MediaPlayer's position while user drag your SeekBar you should add OnSeekBarChangeListener to your SeekBar and do it there :

		mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
		
		@Override
		public void onStopTrackingTouch(SeekBar seekBar) {
			
		}
		
		@Override
		public void onStartTrackingTouch(SeekBar seekBar) {
			
		}
		
			@Override
			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {				
				if(mMediaPlayer != null && fromUser){
					mMediaPlayer.seekTo(progress * 1000);
				}
			}
	});

And that should do the trick! : )

EDIT: One thing which I've noticed in your code, don't do :

public MainActivity() {
    mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
    mFileName += "/audiorecordtest.3gp";
}

make all initialisations in your onCreate(); , do not create constructors of your Activity.

Solution 2 - Android

I've used this tutorial with success, it's really simple to understand: www.androidhive.info/2012/03/android-building-audio-player-tutorial/

This is the interesting part:

/**
 * Update timer on seekbar
 * */
public void updateProgressBar() {
    mHandler.postDelayed(mUpdateTimeTask, 100);
}  

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

           // Displaying Total Duration time
           songTotalDurationLabel.setText(""+utils.milliSecondsToTimer(totalDuration));
           // Displaying time completed playing
           songCurrentDurationLabel.setText(""+utils.milliSecondsToTimer(currentDuration));

           // Updating progress bar
           int progress = (int)(utils.getProgressPercentage(currentDuration, totalDuration));
           //Log.d("Progress", ""+progress);
           songProgressBar.setProgress(progress);

           // Running this thread after 100 milliseconds
           mHandler.postDelayed(this, 100);
       }
    };

/**
 *
 * */
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {

}

/**
 * When user starts moving the progress handler
 * */
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
    // remove message Handler from updating progress bar
    mHandler.removeCallbacks(mUpdateTimeTask);
}

/**
 * When user stops moving the progress hanlder
 * */
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
    mHandler.removeCallbacks(mUpdateTimeTask);
    int totalDuration = mp.getDuration();
    int currentPosition = utils.progressToTimer(seekBar.getProgress(), totalDuration);

    // forward or backward to certain seconds
    mp.seekTo(currentPosition);

    // update timer progress again
    updateProgressBar();
}

Solution 3 - Android

After you initialize your MediaPlayer and SeekBar, you can do this :

 Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            mSeekBar.setProgress(mMediaPlayer.getCurrentPosition());
        }
    },0,1000);

This updates SeekBar every second(1000ms)

And for updating MediaPlayer, if user drag SeekBar, you must add OnSeekBarChangeListener to your SeekBar :

mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
            mMediaPlayer.seekTo(i);
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });

HAPPY CODING!!!

Solution 4 - Android

Code in Kotlin:

var updateSongTime = object : Runnable {
            override fun run() {
                val getCurrent = mediaPlayer?.currentPosition
                startTimeText?.setText(String.format("%d:%d",
                        TimeUnit.MILLISECONDS.toMinutes(getCurrent?.toLong() as Long),
                        TimeUnit.MILLISECONDS.toSeconds(getCurrent?.toLong()) -
                                TimeUnit.MINUTES.toSeconds(
                                        TimeUnit.MILLISECONDS.toMinutes(getCurrent?.toLong()))))
                seekBar?.setProgress(getCurrent?.toInt() as Int)
                Handler().postDelayed(this, 1000)
            }
        }

For changing media player audio file every second

If user drags the seek bar then following code snippet can be use

Statified.seekBar?.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
                if(b && Statified.mediaPlayer != null){
                    Statified.mediaPlayer?.seekTo(i)
                }

            }
            override fun onStartTrackingTouch(seekBar: SeekBar) {}
            override fun onStopTrackingTouch(seekBar: SeekBar) {}
        })

Solution 5 - Android

check this, you should give arguments in msecs, Dont just send progress to seekTo(int)

and also check this getCurrentPostion() and getDuration().

You can do some calcuations, ie., convert progress in msec like msce = (progress/100)*getDuration() then do seekTo(msec)

Or else i have an easy idea, you don't need to change any code anywer else just add seekBar.setMax(mPlayer.getDuration()) once your media player is prepared.

and here is link exactly what you want seek bar update

Solution 6 - Android

The below code worked for me.

I've created a method for seekbar

@Override
public void onPrepared(MediaPlayer mediaPlayer) {
    mp.start();
     getDurationTimer();
    getSeekBarStatus();


}
//Creating duration time method
public void getDurationTimer(){
    final long minutes=(mSongDuration/1000)/60;
    final int seconds= (int) ((mSongDuration/1000)%60);
    SongMaxLength.setText(minutes+ ":"+seconds);


}



 //creating a method for seekBar progress
public void getSeekBarStatus(){

    new Thread(new Runnable() {

        @Override
        public void run() {
            // mp is your MediaPlayer
            // progress is your ProgressBar

            int currentPosition = 0;
            int total = mp.getDuration();
            seekBar.setMax(total);
            while (mp != null && currentPosition < total) {
                try {
                    Thread.sleep(1000);
                    currentPosition = mp.getCurrentPosition();
                } catch (InterruptedException e) {
                    return;
                }
                seekBar.setProgress(currentPosition);

            }
        }
    }).start();





    seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        int progress=0;

        @Override
        public void onProgressChanged(final SeekBar seekBar, int ProgressValue, boolean fromUser) {
            if (fromUser) {
                mp.seekTo(ProgressValue);//if user drags the seekbar, it gets the position and updates in textView.
            }
            final long mMinutes=(ProgressValue/1000)/60;//converting into minutes
            final int mSeconds=((ProgressValue/1000)%60);//converting into seconds
            SongProgress.setText(mMinutes+":"+mSeconds);
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });
}

SongProgress and SongMaxLength are the TextView to show song duration and song length.

Solution 7 - Android

    int  pos  = 0;
    yourSeekBar.setMax(mPlayer.getDuration());

After You start Your MediaPlayer i.e mplayer.start()

Try this code

while(mPlayer!=null){
    	 try {
                Thread.sleep(1000);
                pos  = mPlayer.getCurrentPosition();
            }  catch (Exception e) {
                //show exception in LogCat
            }
            yourSeekBar.setProgress(pos);

   }

Before you added this code you have to create xml resource for SeekBar and use it in Your Activity class of ur onCreate() method.

Solution 8 - Android

This works for me:

seekbarPlayer.setMax(mp.getDuration());
getActivity().runOnUiThread(new Runnable() {

	@Override
	public void run() {
		if(mp != null){
			seekbarPlayer.setProgress(mp.getCurrentPosition());
		}
		mHandler.postDelayed(this, 1000);
	}
});

Solution 9 - Android

Given the answer hardartcore that worked for me with a small change and did not work before the change:

private Handler mHandler = new Handler();
MusicPlayer.this.runOnUiThread(new Runnable() {
     @Override
     public void run() {
          if(player != null){
               int mCurrentPosition = player.getCurrentPosition();//clear ' /1000 '
               seekBar.setProgress(mCurrentPosition);
          }
          mHandler.postDelayed(this, 1000);
      }
});



seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
          if(player != null && fromUser){
              player.seekTo(progress); // clear ' * 1000  '
          }
     }
});

Solution 10 - Android

My code snippet:

public class PlayerActivity extends AppCompatActivity {

private static final String TAG = "PlayerActivity";
private ActivityPlayerBinding binding;
private MediaPlayer mediaPlayer;
private boolean playingAudio = false;
Runnable runnable;
Handler handler;


 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ActivityPlayerBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());

        mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioAttributes(
            new AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                    .setUsage(AudioAttributes.USAGE_MEDIA)
                    .build()
    );

    try {
        mediaPlayer.setDataSource(songUrl);
        mediaPlayer.prepareAsync();
    } catch (IOException e) {
        e.printStackTrace();
    }

    mediaPlayer.setOnPreparedListener(mp -> {
        binding.playBtn.setBackground(getDrawable(R.drawable.ic_pause));
        binding.seekbarPlayer.setMax(mp.getDuration());
        mediaPlayer.start();
        playingAudio = true;
        updateSeekbar();
    });

    mediaPlayer.setOnBufferingUpdateListener((mp, percent) -> {
        double ratio = percent / 100.0;
        int bufferingLevel = (int) (mp.getDuration() * ratio);
        binding.seekbarPlayer.setSecondaryProgress(bufferingLevel);
    });

    binding.seekbarPlayer.setOnSeekBarChangeListener(seekBarChangeListener);

}

    private SeekBar.OnSeekBarChangeListener seekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (fromUser) {
            mediaPlayer.seekTo(progress);
            seekBar.setProgress(progress);
        }
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }
};
    private void updateSeekbar() {
    try {
        if (mediaPlayer != null) {
            int currentPos = mediaPlayer.getCurrentPosition();
            binding.seekbarPlayer.setProgress(currentPos);
            runnable = this::updateSeekbar;
            handler.postDelayed(runnable, 1000);
        }
    } catch (Exception e) {
        e.printStackTrace();
        Log.d(TAG, "updateSeekbar: " + e.getMessage());
    }  
  }
}

Solution 11 - Android

To add on to @hardartcore's answer.

  1. Instead of calling postDelayed on a Handler, the best approach would be to get callbacks from the MediaPlayer during play-back and then accordingly update the seekBar with the progress.

  2. Also, pause your MediaPlayer at onStartTrackingTouch(SeekBar seekBar) of the OnSeekBarChangeListener and then re-start it on onStopTrackingTouch(SeekBar seekBar).

Solution 12 - Android

Based on previous statements, for better performance, you can also add an if condition

if (player.isPlaying() {
    handler.postDelayed(..., 1000);
}

Solution 13 - Android

Try this Code:

public class MainActivity extends AppCompatActivity {

MediaPlayer mplayer;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
            //You create MediaPlayer variable ==> set the path and start the audio.

    mplayer = MediaPlayer.create(this, R.raw.example);
    mplayer.start();

            //Find the seek bar by Id (which you have to create in layout)
            // Set seekBar max with length of audio
           // You need a Timer variable to set progress with position of audio

    final SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar);
    seekBar.setMax(mplayer.getDuration());

    new Timer().scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    seekBar.setProgress(mplayer.getCurrentPosition());
                }
            }, 0, 1000);


            seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

            // Update the progress depending on seek bar
                    mplayer.seekTo(progress);

                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {

                }

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {

                }
            });
        }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionedi233View Question on Stackoverflow
Solution 1 - AndroidhardartcoreView Answer on Stackoverflow
Solution 2 - AndroidEnrichmanView Answer on Stackoverflow
Solution 3 - AndroidM. Doosti LakhaniView Answer on Stackoverflow
Solution 4 - AndroidBilal H. HungundView Answer on Stackoverflow
Solution 5 - AndroidCharan PaiView Answer on Stackoverflow
Solution 6 - AndroidGopalakrishna UmapathiView Answer on Stackoverflow
Solution 7 - AndroidSamView Answer on Stackoverflow
Solution 8 - AndroidRajesh GauswamiView Answer on Stackoverflow
Solution 9 - AndroidclasherView Answer on Stackoverflow
Solution 10 - AndroidManish kumarView Answer on Stackoverflow
Solution 11 - AndroidAnkit AggarwalView Answer on Stackoverflow
Solution 12 - AndroidAdrian GrygutisView Answer on Stackoverflow
Solution 13 - AndroidNechView Answer on Stackoverflow