I'm using MediaPlayer to play some recorded audio and SeekBar to show the progress of the play. My problem is: when I click on the SeekBar to jump to a time position the following example happens and i see on the Log when i want to see the progess:
getprogress(ms): 10000
getprogress(ms): 9956
getprogress(ms): 10000
So I jump to the recorded audio's 10th second. The MediaPlayer jumps to the 10th second but after It jumps back a bit as you can see.
I tried everything i could. I tried playing other recorder's audio files but happened the same. Tried playing with the bit rate and sampling rate but happened the same.
I hope someone knows the solution to this. Thank You.
Edit:
Code:
SeekBar:
progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver);
// handler2.removeCallbacks(updateTimeTask);
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (PlayerForegroundService.player != null) {
// handler2.removeCallbacks(updateTimeTask);
PlayerForegroundService.player.seekTo(seekBar.getProgress());
// handler2.post(updateTimeTask);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter(Constants.ACTION.PLAYER_UPDATE_UI));
}
}
});
}
getProgess():
public int getProgress(){
if ( player != null) {
Log.i(Constants.DEFAULTS.LOG_TAG, ""+player.getCurrentPosition());
return player.getCurrentPosition();
}
else
return 0;
}
The code when getProgress gets called:
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, final Intent intent) {
actPosition.setText(intent.getStringExtra("formattedtimeplay"));
progressBar.setProgress(PlayerForegroundService.player.getProgress());
if (intent.getBooleanExtra("pausedplay", false))
playButton.setImageResource(R.drawable.playfilled);
}
};
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter(Constants.ACTION.PLAYER_UPDATE_UI));
super.onCreate(savedInstanceState);
}
It seems i solved the problem. Before, I used to set the maximum value of the SeekBar in seconds. But after I set the max in milliseconds and the values of the seekTo in milliseconds it works fine.
Related
I have looked everywhere to fix my problem but i just cant seem to get it going.
How do i make seekbar automatically with voice recorder ?
I have checked these links but did not find any solution
Move Seekbar not smooth
how to get seekbar to automatically move on song play?
lstfile.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
player = new MediaPlayer();
try {
player.setDataSource(listFiles[i].toString());
player.prepare();
player.start();
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
int videoduration=player.getDuration();
float progress=i/100.0f;
float time=videoduration*progress;
player.seekTo((int) time);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
});
You can use Handler with delay of 500ms or whatever you wish and update the seekbar inside the runnable method.
Refer below code,
Handler seekBarHandler = new Handler();
private final Runnable updateSeekBarPosRunnable = new Runnable() {
#Override
public void run() {
updateSeekPosition();
}
};
//UPDATE_FREQUENCY = 500ms or reduce/increase it as per your requirement
private void updateSeekPosition() {
seekBarHandler.removeCallbacks(updateSeekBarPosRunnable);
seekBarMusic.setProgress(mediaPlayer.getCurrentPosition());
seekBarHandler.postDelayed(updateSeekBarPosRunnable, UPDATE_FREQUENCY);
}
Now when you start recording start handler,
seekBarHandler.postDelayed(updateSeekBarPosRunnable, UPDATE_FREQUENCY);
when you stop the recorder remove the callback,
seekBarHandler.removeCallbacks(updateSeekBarPosRunnable);
I hope this may help you.
I am actually creating an app with a button, a seekbar and an an image. The button is used to Play/Pause the music. the music played smooth before adding the seekbar. But, after writing the code for seekbar to progress with the position of music, the music seems to be a bit choppy.
Also, i want to reset the position of seekbar to start and change the text on button to "Play" after the music is finished playing.
Can any one tell me why the music is choppy after implementing seekbar?
Also, suggest me how to deal after the music is finished playing.
The coded i used is below:
public class MainActivity extends ActionBarActivity {
private MediaPlayer song;
private SeekBar seekbar;
private final Handler handler = new Handler();
private final Runnable updatePositionRunnable = new Runnable() {
public void run() {
updatePosition();
}
};
//private boolean isPlaying = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
seekbar = (SeekBar)findViewById(R.id.musicSeekBar);
song = MediaPlayer.create( MainActivity.this, R.raw.xyz);
seekbar.setMax(song.getDuration());
final Button playButton = (Button)findViewById(R.id.playButton);
playButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(song.isPlaying()){
playButton.setText("Play");
song.pause();
//isPlaying = false;
handler.removeCallbacks(updatePositionRunnable);
}
else{
playButton.setText("Pause");
song.start();
//isPlaying = true;
updatePosition();
}
}
});
song.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
playButton.setText("Play");
//seekbar.setProgress(0);
//mp.stop();
}
});
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) {
song.seekTo(progress);
}
});
private void updatePosition(){
handler.removeCallbacks(updatePositionRunnable);
seekbar.setProgress(song.getCurrentPosition());
handler.postDelayed(updatePositionRunnable, 2000);
}
#Override
public void onBackPressed() {
super.onBackPressed();
song.stop();
song.release();
}
When you update the progress on the seekbar from your updatePosition method every 2 seconds, the onProgressChanged method in your listener will be called, which will set the position of the playback and cause a slight blip. You might expect onProgressChanged to be called only when the user interacts with the SeekBar but unfortunately that isn't the case.
I'm not aware of a clean solution to this. What you can do is set a boolean flag in your code immediately before calling seekbar.setProgress that indicates the next onProgressChanged callback was not caused by the user, so you can ignore it. You should use an AtomicBoolean for this purpose because the events may come from different threads.
this worked for me:
sBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
boolean userTouch;
#Override
public void onStopTrackingTouch(SeekBar arg0) {
userTouch = false;
}
#Override
public void onStartTrackingTouch(SeekBar arg0) {
userTouch = true;
}
#Override
public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
if(mPlayer.isPlaying() && arg2)
mPlayer.seekTo(arg1);
}
});
After searching for many hours , i am asking this, any related answers are welcomed . .
I'm having a video in my R.raw folder and i am playing it in two videoview of same duration simultaneously , here is my code ,
sb = (SeekBar)findViewById(R.id.control_seekbar);
mVideoView1 = (VideoView) findViewById(R.id.surface_view1);
mVideoView1.setVideoPath("android.resource://" + getPackageName() +"/"+R.raw.play1);
mVideoView1.start();
mVideoView2 = (VideoView) findViewById(R.id.surface_view2);
mVideoView2.setVideoPath("android.resource://" + getPackageName() +"/"+R.raw.play2);
mVideoView2.start();
v1 = mVideoView1.getDuration();
v2 = mVideoView2.getDuration();
mVideoView1.setOnPreparedListener(new OnPreparedListener()
{
#Override
public void onPrepared(MediaPlayer arg0)
{
sb.setMax(mVideoView1.getDuration()+3);
sb.postDelayed(onEverySecond, 60);
}
});
sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
{
#Override
public void onStopTrackingTouch(SeekBar seekBar)
{
mVideoView1.seekTo(sb.getProgress());
mVideoView2.seekTo(sb.getProgress());
}
#Override
public void onStartTrackingTouch(SeekBar seekBar)
{
mVideoView1.seekTo(sb.getProgress());
mVideoView2.seekTo(sb.getProgress());
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser)
{
mVideoView1.seekTo(progress);
mVideoView2.seekTo(progress);
}
});
}
private Runnable onEverySecond=new Runnable()
{
#Override
public void run()
{
if(sb != null)
{
sb.setProgress(mVideoView1.getCurrentPosition());
}
if(mVideoView1.isPlaying())
{
sb.postDelayed(onEverySecond, 1000);
if(mVideoView1.getDuration() <= sb.getProgress())
{
mVideoView1.seekTo(0);
mVideoView2.seekTo(0);
}
}
}
};
and i could drag the seekbar to the new position and it is playing from the new position correctly .
But i dont want to play the video initially . It should be in pause() and as i drag the seekbar, the videoview should update to the respective position .
When i change the mVideoView.start() to pause() , i could see only a blank black screen and no update for the seekbar position change in the videoview .
in what way i could achieve it .
You have to put a media controller in your videoview.
MediaController mediaController = new MediaController(context);
myVideoView.setMediaController(mediaController).
Now when you click on your video the play, pause buttons will show.
If you dont want to play the video initially then you need not call start in onCreate()
Call it when play button is clicked.
Hope this helps you.
In my Android application I am facing issue with seekbar of MediaController that I am using for Videoview.
I would like to know if the user seeks to a position greater than the buffered position,I need to show a dialog and then dismiss the dialogue on seek completed.
Please let me know if I can have this solved.
mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar arg0) {
// you can check for the current buffer state and where the use seek using mSeekBar.getProgress() and then open up a dialog.
if(condition to match buffering and seek position)
openDialog();
}
#Override
public void onStartTrackingTouch(SeekBar arg0) {
}
#Override
public void onProgressChanged(SeekBar arg0, int progress, boolean arg2) {
}
});
...
public void openDialog()
{
...
// check for buffer level to match your seek position
// when it meets the codition,cancel the dialog.
...
}
Couple ways of doing this.
Option 1: Just use the OnInfoListener from the media player.
This will send you info when the buffering has started and stopped.
mPlayer.setOnInfoListener(OnInfo);
Then create your listener code.
// info from player sent.
OnInfoListener OnInfo =
new OnInfoListener() {
public boolean onInfo(MediaPlayer mp, int what, int extra) {
Log.d(TAG,"media info what:"+what+" extra:"+extra);
// check about buffering status.
if(what==MediaPlayer.MEDIA_INFO_BUFFERING_START) {
// note: we are assuming _progressDialog was created already
_progressDialog.setMessage("Buffering...");
_progressDialog.show();
} else if(what==MediaPlayer.MEDIA_INFO_BUFFERING_END) {
if(_progressDialog.isShowing())
_progressDialog.dismiss();
}
return false;
}
};
Option 2: use the OnBufferingUpdateListener to keep track of how much has been buffered.
mPlayer.setOnBufferingListener(OnBufferingUpdate);
Then create the actual listen code.
// buffering update
OnBufferingUpdateListener OnBufferingUpdate =
new OnBufferingUpdateListener() {
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
Log.d(TAG,"BUFFERING: "+ String.valueOf(percent));
// store the percent value and check it in onStopTrackingTouch()
// which is in your setOnSeekBarChangeListener
}
};
I intend to write a custom media controller for my app. I was planning to use seekbar to do both seeking and showing progress. Trying to implement this.
Does anyone have such implementation or am I on the wrong path ?
Finally I figured it out!!
The solution that I came up with was something like this :
First of all set the max progress for seekbar as the duration of the video
videoView.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
seekBar.setMax(videoView.getDuration());
seekBar.postDelayed(onEverySecond, 1000);
}
});
This runnable will keep on updating the progressbar :
private Runnable onEverySecond=new Runnable() {
#Override
public void run() {
if(seekBar != null) {
seekBar.setProgress(videoView.getCurrentPosition());
}
if(videoView.isPlaying()) {
seekBar.postDelayed(onEverySecond, 1000);
}
}
};
And then the setOnSeekBarChangeListener for the seekbar can be used to take the user seeks on the media. By using the fromUser boolean we can make out whether it was a call back due to user's interaction or the
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) {
if(fromUser) {
// this is when actually seekbar has been seeked to a new position
videoView.seekTo(progress);
}
}
});
You set the seconday progress.
No, you're on the right track. It is very good for displaying stuff like download progress and current location for streams (media).