androidandroid-mediaplayerandroid-seekbar

SeekBar and media player in android


I have a simple player and recorder. Everything works great but have one problem. I want to add seek bar to see progress in playing record and use this seek bar to set the place from the player should play. I have onProgress but with no effect. This is the 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 on how to use seek bar to see progress and set place from the record should play?


Solution

  • 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.