ExoPlayer getDuration
Asked Answered
G

5

17

I'm trying to play mp3 file from URL with ExoPlayer.

Everything is fine, but now I wonder when is the it is safe to call getDuration() of the audio track. I just need it once the track is loaded. I didn't find it in Google's example project.

When I try to get it immediately after exoPlayer.prepare() then I get UNKNOWN_TIME.

Gulden answered 9/2, 2016 at 17:16 Comment(0)
G
35

Ok, looks like this is the only solution here.

We add listener to our player, and get duration when state changes to STATE_READY. It will obviously called on every play/pause action so we need to wrap it with boolean durationSet flag if check to call it once on track start. Then durationSet = false somewhere near audioPlayer.prepare()

audioPlayer.addListener(new ExoPlayer.Listener() {
        @Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            if (playbackState == ExoPlayer.STATE_READY && !durationSet) {
                long realDurationMillis = audioPlayer.getDuration();
                durationSet = true;
            }

        }

        @Override
        public void onPlayWhenReadyCommitted() {
            // No op.
        }

        @Override
        public void onPlayerError(ExoPlaybackException error) {
            // No op.
        }
    });
Gulden answered 16/2, 2016 at 10:53 Comment(3)
I am trying ExoPlayer playback of .mp3 and .aac files. I get duration for mp3 but not for aac. What can I try? Where might I be wrong?Canopy
Please have a look at #39778475Canopy
Thank you! I think the new version of exoplayer users: google.github.io/ExoPlayer/doc/reference/com/google/android/… if you want to update the answer.Pernickety
D
4
private int getVideoDurationSeconds(SimpleExoPlayer player)
    {
        int timeMs=(int) player.getDuration();
        int totalSeconds = timeMs / 1000;
        return totalSeconds;
    }

just call this method with exoplayer object and you will find total seconds

complete method

private String stringForTime(int timeMs) {
    StringBuilder mFormatBuilder = new StringBuilder();
    Formatter mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
    int totalSeconds = timeMs / 1000;
  //  videoDurationInSeconds = totalSeconds % 60;
    int seconds = totalSeconds % 60;
    int minutes = (totalSeconds / 60) % 60;
    int hours = totalSeconds / 3600;

    mFormatBuilder.setLength(0);
    if (hours > 0) {
        return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
    } else {
        return mFormatter.format("%02d:%02d", minutes, seconds).toString();
    }
}
Deluna answered 9/8, 2020 at 13:52 Comment(0)
L
1

The answer of pavelkorolevxyz works well if you have a single media item in the track, but if there are multiple items/files, it would be a cumbersome to get around the if (playbackState == ExoPlayer.STATE_READY && !durationSet) condition and to reset the durationSet for the new media file.

We'd better change that by Media3 ExoPlayer API onMediaItemTransition() callback for the upcoming media files:

var mediaDuration = 0L // inital value is 0 before starting the player
val listener = object : Player.Listener {

    override fun onPlaybackStateChanged(playbackState: Int) {
        if (playbackState == ExoPlayer.STATE_READY && mediaDuration == 0) {
            // The player is just run, and this is the 1st MediaItem duration
            mediaDuration = exoPlayer.duration
        }
    }
    
    override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
        super.onMediaItemTransition(mediaItem, reason)
       
        // Media Transition, this is another mediaItem beyond the first one
        mediaDuration = exoPlayer.duration
        
    }
}

// register the listener 
exoPlayer.addListener(listener)

Then you could reset mediaDuration = 0L when releasing the player resources.

Lheureux answered 17/10, 2023 at 21:59 Comment(0)
C
0

to get the duration, after the media is prepared and loaded in exoplayer, call exoPlayer.getDuration() which returns the duration in milliseconds.

note that if the media is liveStream or duration is not available, it will return C.TIME_UNSET.

you can also customize the duration for your self if you're showing Ad. telegram android project is doing something like this:

@Override
  public long getDuration() {
    if (isPlayingAd()) {
      MediaPeriodId periodId = playbackInfo.periodId;
      playbackInfo.timeline.getPeriodByUid(periodId.periodUid, period);
      long adDurationUs = period.getAdDurationUs(periodId.adGroupIndex, periodId.adIndexInAdGroup);
      return C.usToMs(adDurationUs);
    }
    return getContentDuration();
  }

here is the source code to telegram android project.

Celery answered 26/8, 2023 at 12:15 Comment(0)
K
0

The duration is not available immediately, but as soon as its available, the timeline is updated.

From Android Docs:

When information such as the duration of a media item in the playlist becomes available, the Timeline will be updated and onTimelineChanged will be called with TIMELINE_CHANGE_REASON_SOURCE_UPDATE.

override fun onTimelineChanged(timeline: Timeline, reason: Int) {
    if (reason == Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) {
        // duration is available now:
        // player.duration
    }            
}
Kaltman answered 11/3, 2024 at 13:44 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.