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

13,725

Solution 1

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.

Solution 2

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
Share:
13,725
Muhammad Nabeel Arif
Author by

Muhammad Nabeel Arif

I am a passionate mobile developer with 10+ years of experience in iOS and android development. I am currently working with Objective C and Swift programming languages in XCode 7 and 8 under iOS Development. I am adept at using several software design patterns and have extensive knowledge of creating applications for mobile platforms I have managed all aspects of application development, from requirement gathering to publishing the product to the app stores. I have good understanding of web technologies and their integration with mobile clients. Apart from development a major portion of my role remained as a team lead. I have spent time being a team lead for mobile platform as well as technical lead for iOS team in my recent projects. To keep up with the latest trends in respective development and share my knowledge I spend my time on Stackoverflow and write my own blog. As a student I have a good record I completed my education with distinction, securing first position amongst my batch and received gold medal from prime minister of Pakistan. I would like to proceed working with Objective C / Swift on challenging iOS projects. So a position of Sr. iOS Developer, iOS Developer and technical lead will suit me. As I have experience in Android and Java also, I would also accept a challenge of becoming an Android Developer.  Having worked on different roles in my professional career, I am totally able to work well with different teams.

Updated on July 18, 2022

Comments

  • Muhammad Nabeel Arif
    Muhammad Nabeel Arif almost 2 years

    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

  • Muhammad Nabeel Arif
    Muhammad Nabeel Arif over 12 years
    I appreciate your interest in solving the problem. I have modified the code to getDuration after mediaPlayer is prepared in mediaPlayer.onPrepared()... As I mentioned that the problem was in audio streaming, it is still there. When I stream the audio even smaller one. GetDuration returns me 6-hours and something. But when I play audio from sdcard the same code returns correct duration.
  • Pointer Null
    Pointer Null over 12 years
    Post example url of your remote stream.