javascriptjqueryaudiohtml5-audio

how to get audio.duration value by a function


Im my audio player I need to get the duration of my audio track. I need a function that gets src of the audio and returns its duration. Here is what I am trying to do but does not work:

function getDuration(src){
    var audio = new Audio();
    audio.src = "./audio/2.mp3";
    var due;
    return getVal(audio);
}
function getVal(audio){
    $(audio).on("loadedmetadata", function(){
        var val = audio.duration;
        console.log(">>>" + val);
        return val;
    });
}

I tried to split into two functions but it does not work. It would be great if it was as on working function.

Any idea?


Solution

  • because you're relying on an event to fire, you can't return a value in getDuration or getVal

    instead, you want to use a callback function, like this (callbacks)

    The example assume you want to put the duration into a span written like this

    <span id="duration"></span>
    

    function getDuration(src, cb) {
        var audio = new Audio();
        $(audio).on("loadedmetadata", function(){
            cb(audio.duration);
        });
        audio.src = src;
    }
    getDuration("./audio/2.mp3", function(length) {
        console.log('I got length ' + length);
        document.getElementById("duration").textContent = length;
    });
    

    Any code that needs to "know" the length should be inside the callback function (where console.log is)


    using Promises

    function getDuration(src) {
        return new Promise(function(resolve) {
            var audio = new Audio();
            $(audio).on("loadedmetadata", function(){
                resolve(audio.duration);
            });
            audio.src = src;
        });
    }
    getDuration("./audio/2.mp3")
    .then(function(length) {
        console.log('I got length ' + length);
        document.getElementById("duration").textContent = length;
    });
    

    using Events - note 'myAudioDurationEvent' can obviously be (almost) anything you want

    function getDuration(src, obj) {
        return new Promise(function(resolve) {
            var audio = new Audio();
            $(audio).on("loadedmetadata", function(){
                var event = new CustomEvent("myAudioDurationEvent", {
                    detail: {
                        duration: audio.duration,
    
                    }
                });
                obj.dispatchEvent(event);
            });
            audio.src = src;
        });
    }
    var span = document.getElementById('xyz'); // you'll need to provide better logic here
    span.addEventListener('myAudioDurationEvent', function(e) {
        span.textContent = e.detail.duration;
    });
    getDuration("./audio/2.mp3", span);
    

    although, this can be done similarly with callback or promise by passing in a destination to a modified getDuration function in those solutions as well - my point about using event listeners was more appropriate if one span for example was updated with duration multiple times - this solution still only does each span only once, so can be achieved with the other methods just as easily


    given the new information in the comments for this answer, I believe this to be the better solution

    function getDuration(src, destination) {
        var audio = new Audio();
        $(audio).on("loadedmetadata", function(){
            destination.textContent = audio.duration;
        });
        audio.src = src;
    }
    

    and then invoke getDuration as needed like this

    var span = createOrGetSomeSpanElement();
    getDuration("./audio/2.mp3", span);
    

    createOrGetSomeSpanElement returns the destination element to use in the getDuration function - how this is done is up to you, seeing as you create a playlist in a loop, I'm guessing you have some element created to receive the audio length already created - it's hard to answer a half asked question sometimes