What is the best way to get an audio file duration in Android?
Asked Answered
L

3

14

I'm using a SoundPool to play audio clips in my app. All is fine but I need to know when the clip playback has finished.

At the moment I track it in my app by obtaining the duration of each clip using a MediaPlayer instance. That works fine but it looks wasteful to load each file twice, just to get the duration. I could roughly calculate the duration myself knowing the length of the file (available from the AssetFileDescriptor) but I'd still need to know the sample rate and the number of channels.

I see two potential solutions to that problem:

  1. Figuring out when a clip has finished playing (doesn't seem to be possible with SoundClip).
  2. Having a class which could load just the header of an audio file and give me the sample rate/number of channels (and, ideally, the sample count to get the exact duration).

Any suggestions?

Thanks, Max

The code I'm using at the moment (works fine but is rather heavy for the purpose):

String[] fileNames = ...
MediaPlayer mp = new MediaPlayer();
for (String fileName : fileNames) {
    AssetFileDescriptor d = context.getAssets().openFd(fileName);
    mp.reset();
    mp.setDataSource(d.getFileDescriptor(), d.getStartOffset(), d.getLength());
    mp.prepare();
    int duration = mp.getDuration();
    // ...
}

On a side note, this question has already been asked but got no answers.

Lutenist answered 17/1, 2011 at 3:46 Comment(4)
have you considered an onCompletitionListener? developer.android.com/reference/android/media/…Gaby
@SatelliteSD it simply doesn't work (never get called) on any of the devices I have. Even if it does get called on some OS versions / some devices it's unreliable and therefore useless.Lutenist
you doublechecked that setOnCompletitionListner is called after .start()?Gaby
The completion listener is only used for MediaPlayer, not for SoundPool. As far as I know, the only way to have a callback on a sound finishing is with a MediaPlayer, not a SoundPool.Guenna
M
16

Did you try this:

String mediaPath = Uri.parse("android.resource://<your-package-name>/raw/filename").getPath();
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(mediaPath);
String duration = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
mmr.release();

But i am not exactly sure that this is lighter than exisiting code.

Maitland answered 16/7, 2014 at 19:4 Comment(3)
Don't forget to release the MediaMetadataRetrieverHearttoheart
I tried this, but I am always thrown an IllegalArgumentException from mmr.setDataSource() - is there some way to find out how exactly that path should look like? Because I'm suspecting that the path I use might be incorrect. I am using in-bundle .m4a and/or .wav audio files.Moribund
is there any way to check duration from URL without downloading fileMotherofpearl
K
4

Try FFmpegMediaMetadataRetriever:

String[] fileNames = ...
FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();

for (String fileName : fileNames) {
    AssetFileDescriptor d = context.getAssets().openFd(fileName);
    mmr.setDataSource(d.getFileDescriptor(), d.getStartOffset(), d.getLength());
    String duration = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION);
}

mmr.release();
Kristikristian answered 17/7, 2014 at 18:52 Comment(0)
S
3

this is work for me to get assets audio file duration in total seconds=====>

MediaMetadataRetriever mmr = new MediaMetadataRetriever();
AssetFileDescriptor d = context.getAssets().openFd(fileName);
mmr.setDataSource(d.getFileDescriptor(), d.getStartOffset(), d.getLength());
String duration = 
mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
mmr.release();

Updated

method to get assets audio file duration in seconds

  public String gettotaltimeassets() {

   MediaMetadataRetriever mmr = new MediaMetadataRetriever();
    AssetFileDescriptor d = null;
    try {
        d = getApplicationContext().getAssets().openFd("ASSETS FILE NAME");
    } catch (IOException e) {
        e.printStackTrace();
    }
    mmr.setDataSource(d.getFileDescriptor(), d.getStartOffset(), d.getLength());
    String duration = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
    long dur = Long.parseLong(duration);
    String seconds = String.valueOf((dur % 60000) / 1000);
    Log.d("seconds===========>", seconds);
    mmr.release();
    return  seconds;
}

method to get internal storage audio file duration in seconds

public String gettotaltimestorage(String filePath) {
    // load data file
    Log.d("time=================>","time=================>");
    MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
    metaRetriever.setDataSource(YourACTIVITY.this, Uri.parse(filePath));
    Log.d("time=================>","time=================>");
    String out = "";
    // get mp3 info

    // convert duration to minute:seconds
    String duration =
            metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
    Log.d("time=================>", duration);
    long dur = Long.parseLong(duration);
    String seconds = String.valueOf((dur % 60000) / 1000);
    Log.d("seconds===========>", seconds);
    // close object
    metaRetriever.release();
    return  seconds;

}
Stardom answered 17/8, 2017 at 6:20 Comment(3)
Please provide explanation to your answer. This will not only help to understand the cause of current issue but to avoid the same in future.Antiperistalsis
actually i write code to get duration of any audio file in assets as @William Seemann write but i use MediaMetadata to retrieve duration...i modify my answer so you understand better...you can call this method for multiple audio file to get duration.Stardom
I didn't write that comment because I was not able to understand your code, but it is a good practice on SO to accompany your solution with proper explanation. Code-Only answers are not highly appreciated.Antiperistalsis

© 2022 - 2024 — McMap. All rights reserved.