Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get duration of Audio Stream and continue audio streaming from any point

Description:

I have following code for an Audio player. I can continue Audio playback from any duration by clicking on Progress Bar(between 0-to-mediaplayer.getDuration()). It is working perfectly for Audio playback.

Problem in Audio Streaming:

  • When I stream an Audio file from an internet server (say s3-bucket) it starts streaming correctly.
  • But mediaPlayer.getDuration() and mediaPlayer.getCurrentPosition() return wrong values. At the beginning of streaming mediaPlayer.getCurrentPosition() returns 5 hours.
  • Due to this I am not able to continue Audio streaming from a specified duration of Stream (0-to-Stream Duration).

Questions:

  1. How can I get the duration of an Audio stream
  2. How can I continue Audio Streaming from a specified duration. For example for a file of 10-minute duration, I want to start streaming from 6th minute.

Code:

public class MyAudioPlayer extends Activity 
implements OnClickListener{


    MediaPlayer mediaPlayer = null;
    private boolean isPaused=false;
    private boolean isStop = true;

    String filePath = null;
    String productName = null;

    ImageButton btnPlay = null;
    ImageButton btnPause = null;
    ImageButton btnReset = null;
    ImageButton btnStop = null;

    AudioManager audioManager = null;
    SeekBar volControl = null;
    SeekBar progressControl = null;
    TextView progressText = null;
    long durationInMillis = -1;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ltd_audio_player);

        volControl = (SeekBar)findViewById(R.id.player_volume);
        progressControl = (SeekBar)findViewById(R.id.player_seekbar);
        progressText = (TextView) findViewById(R.id.player_progress_text);

        btnPlay = (ImageButton) findViewById(R.id.ic_player_play); 

        btnPause = (ImageButton) findViewById(R.id.ic_player_pause);  

        btnReset = (ImageButton) findViewById(R.id.ic_player_reset); 

        btnStop = (ImageButton) findViewById(R.id.ic_player_stop);   

        btnPlay.setOnClickListener(this);
        btnPause.setOnClickListener(this);
        btnReset.setOnClickListener(this);
        btnStop.setOnClickListener(this);

        filePath = getIntent().getExtras().getString("localPath");

        this.setPlayer();
        this.resetAndStartPlayer();


    }

    @Override
    protected void onResume() {
        super.onResume();   
        isPaused=false;
        progressText.postDelayed(onEverySecond, 1000);
    }

    @Override
    protected void onPause() {
        super.onPause();

        isPaused=true;
    }
    private void setProgressControl() {
        int maxVolume = mediaPlayer.getDuration();
        int curVolume = mediaPlayer.getCurrentPosition();

        progressControl.setMax(maxVolume);
        progressControl.setProgress(curVolume);
        progressControl.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

            @Override
            public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) {
                mediaPlayer.seekTo(progress);
            }

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

            }

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

            }
        });     
    }
    @Override
    public void onClick(View v) {
        switch(v.getId()){
        case R.id.ic_player_play:
            if(isStop==true){
                try {
                    mediaPlayer.prepareAsync();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else{
                mediaPlayer.start();
                isStop = true;
            }
            break;
        case R.id.ic_player_pause:
            mediaPlayer.pause();
            break;
        case R.id.ic_player_reset:
            mediaPlayer.seekTo(0);
            break;
        case R.id.ic_player_stop:
            isStop = true;
            progressControl.setProgress(0);
            mediaPlayer.stop();
            break;
        }

    }
    private void resetAndStartPlayer(){
        try {
            if(filePath!=null){
                mediaPlayer.setDataSource(filePath);
                mediaPlayer.prepareAsync();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void setPlayer(){

        getWindow().setFormat(PixelFormat.UNKNOWN);
        mediaPlayer = new MediaPlayer();    

        mediaPlayer.setOnBufferingUpdateListener(new OnBufferingUpdateListener() {

            @Override
            public void onBufferingUpdate(MediaPlayer mp, int percent) {
                progressControl.setSecondaryProgress((progressControl.getMax()/100)*percent);

            }
        });
        mediaPlayer.setOnPreparedListener(new OnPreparedListener() {

            @Override
            public void onPrepared(MediaPlayer mp) {
                mediaPlayer.start();
                isStop=false;
                durationInMillis = mediaPlayer.getDuration();
                MyAudioPlayer.this.setProgressControl();
            }
        });
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    }
    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        mediaPlayer.release();
        super.onDestroy();
    }
    protected void setProgressText() {
        durationInMillis = mediaPlayer.getDuration();
        int curVolume = mediaPlayer.getCurrentPosition();
        long HOUR = 60*60*1000;
        if(progressText!=null){
            if(durationInMillis>HOUR){
                progressText.setText(String.format("%1$tH:%1$tM:%1$tS", new Date(curVolume))
                        +" / "+String.format("%1$tH:%1$tM:%1$tS", new Date(durationInMillis)));
            }else{
                progressText.setText(String.format("%1$tM:%1$tS", new Date(curVolume))
                        +" / "+String.format("%1$tM:%1$tS", new Date(durationInMillis)));
            }
        }       
    }
    private Runnable onEverySecond=new Runnable() {
        public void run() {

            if (mediaPlayer!=null) {
                progressControl.setProgress(mediaPlayer.getCurrentPosition());

                MyAudioPlayer.this.setProgressText();
            }

            if (!isPaused) {
                progressText.postDelayed(onEverySecond, 1000);
            }
        }
    };
}

Time is displayed above the progress bar.

Time: 'Current Duration'/'Total Duration'

enter image description here

like image 399
Muhammad Nabeel Arif Avatar asked Jan 23 '12 13:01

Muhammad Nabeel Arif


2 Answers

Hope that it might solve your problem.

1) Duration and Progress of Audio Stream

I have looked into your code, you have a major error in your code to calculate time. You create new Date(durationInMillis). Date adds your locallity i.e GMT+XX hours, that is why you are getting 5- hours in the beginnging of streaming. You should use following method to calculate currentProgress/duration.

protected void setProgressText() {

    final int HOUR = 60*60*1000;
    final int MINUTE = 60*1000;
    final int SECOND = 1000;

    int durationInMillis = mediaPlayer.getDuration();
    int curVolume = mediaPlayer.getCurrentPosition();

    int durationHour = durationInMillis/HOUR;
    int durationMint = (durationInMillis%HOUR)/MINUTE;
    int durationSec = (durationInMillis%MINUTE)/SECOND;

    int currentHour = curVolume/HOUR;
    int currentMint = (curVolume%HOUR)/MINUTE;
    int currentSec = (curVolume%MINUTE)/SECOND;

    if(durationHour>0){
        System.out.println(" 1 = "+String.format("%02d:%02d:%02d/%02d:%02d:%02d", 
                currentHour,currentMint,currentSec, durationHour,durationMint,durationSec));            
    }else{
        System.out.println(" 1 = "+String.format("%02d:%02d/%02d:%02d", 
                currentMint,currentSec, durationMint,durationSec));
    }
}

2) Scrubbing for Stream.

MediaPlayer allows scrubbing of audio stream. I have implemented it in one of my projects, but it takes some time. It takes some time to resume audio streaming from another location.

like image 151
Talha Hafeez Avatar answered Nov 15 '22 22:11

Talha Hafeez


First big problem is your order of initialization: you call getDuration before you actually call setDataSource in resetAndStartPlayer. How is MediaPlayer supposed to know duration without data source?

Here's how to do that properly:

  1. call MediaPlayer.setDataSource() in Activity.onCreate

  2. execute AsyncTask, in its doInBackground call MediaPlayer.prepare(), this will take a while if it's streaming from http, but after it finishes, player should know lenght of media

  3. in the AsyncTask.onPostExecute call MediaPlayer.getDuration(), which should succeed if stream was opened successfully; afterwards you may call MediaPlayer.start()

Important things:

  • getDuration works after prepare was called
  • prepare may take longer time, and should be called in other thread
  • you may also use prepareAsync and avoid AsyncTask, then you'd use setOnPreparedListener callback to call getDuration
like image 27
Pointer Null Avatar answered Nov 15 '22 23:11

Pointer Null