1
votes

I want to play a single audio file (mp3) and my only problem is media length.

It works just fine on Android 5.0.1, but on 4.4.2/4.4.4 it doesn't work!

With native implementation I get a value but it's incorrect and if I use the Media plugin API (from Phonegap) the media.duration is undefined and media.getDuration() returns -1.

I'm trying to get duration only after loadedmetadata event is fired, so this could not be the problem. The native implementation is done through js with new Audio(), no DOM element involved. The file is stored on sdcard, and src looks like file:///storage/sdcard/audio.mp3. Everything else regarding html5 audio api works, but duration.

Are there any solutions to fix this?

4

4 Answers

2
votes

Thanks to @tawpie's answer I figured out a workaround for this issue I'm having. That setInterval made me thing about my custom seekbar been updated (correctly) while the audio is playing and in calculating the width of it I was using audio duration value and from that results that the duration is working after media file play method is fired.

The problem is that loadedmetadata event doesn't return the correct duration value (in some browsers like android webView), but after audio played for at least 1s the duration is updated and you can use it.

So you can forget about loadedmetadata event and jump straight to canplay event and from there you can make something like this:

var myAudio = new Audio();
myAudio.src = 'file://mnt/sdcard/audio.mp3';
myAudio.load();
myAudio.correctDuration = null;

myAudio.addEventListener('canplay', function(){

   myAudio.play();
   myAudio.muted = true;
   setTimeout(function(){
      myAudio.pause();
      myAudio.currentTime = 0;
      myAudio.muted = false;

      myAudio.correctDuration = myAudio.duration;

   },1000);

});

...of course, you can use volume = 0.0/1.0 instead of mute.
Another method would be to create a helper function (in my case - a AngularJS service) which takes your src value and uses the code above and returns the correctDuration. This one is preferred if you have listeners to audio timeUpdate which changes the DOM.

The Media plugin works exactly the same way - if the audio haven't played for at least 1s you cannot use getDuration() method or duration property inside a interval/timeout wrapper to get the correct duration.

I think the video element behaves similarly. I'll test it these days.
Hope this workaround helps!

1
votes

Try Media.node.duration. That works on windows... For what it's worth, as long as getDuration is called in an interval, I don't have any problems on Android 4.4. But I'm using just the media plugin new Media(src, onSuccess, onError, playbackStatus) and not the HTML5 player.

0
votes

Hardcoded values. It's a pain, but you can do this if the files are local.

I ran into an issue where chrome was reporting different duration values than other browsers, and this is where we landed. I know it's not really a solution, but it works.

OR... you can use some external process to generate a json of duration times, and reference those values at runtime.

0
votes

For the sake of reference:

audio.addEventListener('durationchange', function(e) {
    console.log(e.target.duration); //FIRST 0, THEN REAL DURATION
});

worked for me.

Credit: this stackowerflow question