Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

play audio range in html5

I would like to be able to have buttons that can play certain audio ranges from a larger file. Something like:

<button onclick="playClip('http://blah/source1.mp3', 2.5, 3.0, 1.0)">Play clip 1</button>
<button onclick="playClip('http://blah/source2.mp3', 10.0, 2.0, 0.5)">Play clip 2 slow</button>

where playClip has a pattern like this:

function playClip(src, startOffset, length, rate) {
  // What to put here?
}

Or instead of a length, an ending offset.

Can some one point me to code that can do that, or help me write it? The closest I could find is https://gist.github.com/remy/753003/download# but I need different sized clips, from possibly different files, and with a playback rate specified. I'm afraid I've limited experience with Javascript.

I'm trying to replace a Silverlight app that does this.

Thanks.

-John

like image 563
jtsoftware Avatar asked Jul 03 '14 18:07

jtsoftware


People also ask

Can I play audio in HTML5?

HTML5 features include native audio and video support without the need for Flash. The HTML5 <audio> and <video> tags make it simple to add media to a website. You need to set src attribute to identify the media source and include a controls attribute so the user can play and pause the media.

What is the correct HTML5 element for playing audio files?

The HTML <audio> element is used to play an audio file on a web page.

Can multiple audio sources can be played in HTML?

By adding more "<audio>" tags you can add more audio players in the browser using HTML5...

How do I embed audio in HTML5?

How to embed audio in HTML? To embed audio in HTML, we use the <audio> tag. Before HTML5, audio cannot be added to web pages in the Internet Explorer era. To play audio, we used web plugins like Flash.


2 Answers

Either use Media Fragments URI syntax:

var src,
    startOffset,
    endOffset,
    playbackRate,
    audio = new Audio(src + '#t=' + startOffset + ',' + endOffset);

audio.onloadedmetadata = function() {
  audio.playbackRate = playbackRate;
  audio.play();
};

or timeupdate event:

var audio = new Audio( ... ),
    startOffset,
    endOffset,
    playbackRate;

audio.onloadedmetadata = function() {
  audio.playbackRate = playbackRate;
  audio.currentTime = startOffset;
  audio.play();
};

audio.ontimeupdate = function() {
  if (audio.currentTime >= endOffset) {
    audio.pause();
  }
};

References:

  • Specifying playback range
  • Jumping to time offsets in HTML5 video
like image 182
Igor Gilyazov Avatar answered Nov 15 '22 13:11

Igor Gilyazov


Here's an extract of my current code, which uses both the audio control's events and timeout to make sure the audio stops. There's a reference to a volume slider you might need to trim.

var jt_audioControl;
var jt_audioSource;
var jt_audioFiles;
var jt_audioFileIndex;
var jt_audioFile;
var jt_audioStartTime;
var jt_audioEndTime;
var jt_audioPlaybackRate;
var jt_audioTimeoutHandle;
var jt_audioLink;
var jt_audioMimeType;
var jt_audioMediaType;
var jt_volumeSlider;

function jt_onAudioTimeUpdate() {
    if (jt_audioEndTime > 0.0) {
        if (jt_audioControl.currentTime >= jt_audioEndTime) {
            //alert('stopped: jt_audioControl.currentTime = ' + jt_audioControl.currentTime + ' jt_audioEndTime = ' + jt_audioEndTime);
            jt_audioControl.pause();
            //jt_audioStartTime = jt_audioEndTime = 0.0;
        }
    }
}

function jt_onAudioCanPlay() {
    jt_audioControl.pause();
    jt_audioControl.currentTime = jt_audioStartTime;
    jt_audioControl.defaultPlaybackRate = jt_audioPlaybackRate;
    jt_audioControl.playbackRate = jt_audioPlaybackRate;
    jt_audioControl.play();
    jt_audioControl.currentTime = jt_audioStartTime;
    jt_volumeSliderChanged();   // Set initial value to slider.
    var timeout = (((jt_audioEndTime - jt_audioStartTime)) / jt_audioPlaybackRate) * 1000;
    //alert('jt_audioEndTime = ' + jt_audioEndTime + ', timeout = ' + timeout);
    if (jt_audioEndTime > 0.0) {
        jt_audioTimeoutHandle = setTimeout(jt_onAudioEnded, timeout);
        //alert('jt_audioTimeoutHandle = ' + jt_audioTimeoutHandle);
    }
    else if (jt_audioTimeoutHandle != null) {
        clearTimeout(jt_audioTimeoutHandle);
        jt_audioTimeoutHandle = null;
    }
}

function jt_onAudioEnded() {
    //alert('ended called');
    if (jt_audioFiles == null)
        return;
    while (jt_audioControl.position < jt_audioControl.duration)
        ;
    jt_audioFileIndex = jt_audioFileIndex + 1;
    if (jt_audioFileIndex < jt_audioFiles.length) {
        jt_createAudio(jt_audioFiles[jt_audioFileIndex]);
    }
    else {
        jt_audioControl.pause();
        jt_audioFiles = null;
        jt_audioFileIndex = 0;
    }
}

function jt_onAudioError(e) {
    var msg;
    switch (e.target.error.code) {
        case e.target.error.MEDIA_ERR_ABORTED:
            msg = 'You aborted the video playback.';
            break;
        case e.target.error.MEDIA_ERR_NETWORK:
            msg = 'A network error caused the video download to fail part-way.';
            break;
        case e.target.error.MEDIA_ERR_DECODE:
            msg = 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support.';
            break;
        case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
            msg = 'The video could not be loaded, either because the server or network failed or because the format is not supported.';
            break;
        default:
            msg = 'An unknown error occurred.';
            break;
    }
    alert('Error loading media: ' + msg + ' Media file: ' + jt_audioFile + ' MIME type: ' + jt_audioMimeType);
}

function jt_addSource(url) {
    var srcUrl;
    var doConvertCheck = false;
    var offset = url.lastIndexOf(".");
    if (offset == -1) {
        if (jt_audioSource == null) {
            jt_audioSource = document.createElement('source');
            jt_audioControl.appendChild(jt_audioSource);
        }
        jt_audioMimeType = 'audio/mpeg3';
        jt_audioMediaType = 'audio/mpeg3';
        jt_audioSource.type = jt_audioMediaType;
        jt_audioSource.src = url;
        jt_audioControl.load();
        return;
    }
    var base = url.substr(0, offset);
    var ext = url.substr(offset).toLowerCase();
    var newExt = ext;
    if (jt_audioControl.canPlayType('audio/mpeg3')) {
        jt_audioMimeType = 'audio/mpeg3';
        jt_audioMediaType = 'audio/mpeg3';
        if (ext != '.mp3')
            newExt = '-aa.mp3';
    }
    else if (jt_audioControl.canPlayType('audio/mpeg')) {
        jt_audioMimeType = 'audio/mpeg3';
        jt_audioMediaType = 'audio/mpeg';
        if (ext != '.mp3')
            newExt = '-aa.mp3';
    }
    else if (jt_audioControl.canPlayType('audio/mp3')) {
        jt_audioMimeType = 'audio/mpeg3';
        jt_audioMediaType = 'audio/mp3';
        if (ext != '.mp3')
            newExt = '-aa.mp3';
    }
    else if (jt_audioControl.canPlayType('audio/ogg')) {
        jt_audioMimeType = 'audio/ogg';
        jt_audioMediaType = 'audio/ogg';
        if (ext != '.ogg')
            newExt = '-aa.ogg';
    }
    else {
        alert('Sorry, can not play file: ' + url);
    }
    srcUrl = base + newExt;
    if (srcUrl.lastIndexOf('~', 0) === 0) {
        if (window.location.hostname == '') {
            srcUrl = srcUrl.substr(2);
        }
        else {
            var url = 'http://' + window.location.hostname;
            if (window.location.port.toString() != '')
                url = usrl + ':' + window.location.port.toString()
            srcUrl = url + srcUrl.substr(1);
        }
    }
    //alert('srcUrl = ' + srcUrl);
    if (jt_audioSource == null) {
        jt_audioSource = document.createElement('source');
        jt_audioControl.appendChild(jt_audioSource);
    }
    jt_audioSource.type = jt_audioMediaType;
    if (doConvertCheck) {
        jt_audioLink = "/ConvertCheck?path=" + srcUrl + "&" + "mimeType=" + jt_audioMimeType
        jt_audioSource.src = jt_audioLink;
    }
    else {
        jt_audioSource.src = srcUrl;
    }
    jt_audioControl.load();
}

function jt_extractTimeRange(url) {
    var rangeFieldIndex = url.lastIndexOf("#t");
    if (rangeFieldIndex >= 0) {
        var rangeString = url.substr(rangeFieldIndex + 2);
        var range = rangeString.split(',');
        jt_audioStartTime = parseFloat(range[0]);
        jt_audioEndTime = parseFloat(range[1]);
    }
    else {
        jt_audioStartTime = 0.0;
        jt_audioEndTime = 0.0;
        return url;
    }
    return url.substr(0, rangeFieldIndex);
}

function jt_createAudio(url) {
    url = jt_extractTimeRange(url);
    if (jt_audioControl == null) {
        jt_audioFile = url;
        jt_audioControl = new Audio();
        // The ontimeupdate handler seems to be called unreliably, so we'll use
        // setTimeout as well in the oncanplay handler.
        jt_audioControl.ontimeupdate = jt_onAudioTimeUpdate;
        jt_audioControl.onloadedmetadata = jt_onAudioCanPlay;
        jt_audioControl.onended = jt_onAudioEnded;
        jt_audioControl.onerror = jt_onAudioError;
        jt_addSource(url);
        // We'll let the oncanplay call play once loaded.
    }
    else if (jt_audioFile != url) {
        jt_audioFile = url;
        jt_addSource(url);
    }
    else {
        //jt_onAudioLoaded();
        jt_audioControl.load();
    }
}

function jt_playAudioFile(url) {
    jt_audioFiles = null;
    jt_audioFileIndex = 0;
    jt_audioStartTime = 0.0;
    jt_audioEndTime = 0.0;
    jt_audioPlaybackRate = 1.0;
    jt_createAudio(url);
}

function jt_playSlowAudioFile(url) {
    jt_audioFiles = null;
    jt_audioFileIndex = 0;
    jt_audioStartTime = 0.0;
    jt_audioEndTime = 0.0;
    jt_audioPlaybackRate = 0.5;
    jt_createAudio(url);
}

function jt_playAudioFileList(urls) {
    jt_audioFiles = urls;
    jt_audioFileIndex = 0;
    jt_audioStartTime = 0.0;
    jt_audioEndTime = 0.0;
    jt_audioPlaybackRate = 1.0;
    if ((urls != null) && (urls.length > 0)) {
        jt_createAudio(urls[0]);
    }
}

function jt_playSlowAudioFileList(urls) {
    jt_audioFiles = urls;
    jt_audioFileIndex = 0;
    jt_audioStartTime = 0.0;
    jt_audioEndTime = 0.0;
    jt_audioPlaybackRate = 0.5;
    if ((urls != null) && (urls.length > 0)) {
        jt_createAudio(urls[0]);
    }
}

function jt_playAudioFileSegment(url, startTime, endTime) {
    jt_audioFiles = null;
    jt_audioFileIndex = 0;
    url = url + '#t' + startTime.toString() + ',' + endTime.toString();
    jt_audioPlaybackRate = 1.0;
    jt_createAudio(url);
}

function jt_playSlowAudioFileSegment(url, startTime, endTime) {
    jt_audioFiles = null;
    jt_audioFileIndex = 0;
    url = url + '#t' + startTime.toString() + ',' + endTime.toString();
    jt_audioPlaybackRate = 0.5;
    jt_createAudio(url);
}

function jt_stopAudio() {
    if (jt_audioControl != null)
        jt_audioControl.pause();
}

function jt_volumeSliderChanged() {
    if (jt_volumeSlider == null) {
        jt_volumeSlider = document.getElementById('volumeSlider');
        if (jt_volumeSlider == null)
            return;
    }
    var value = jt_volumeSlider.value;
    if (jt_audioControl != null)
        jt_audioControl.volume = value / 10;
    $.ajax({
        url: "/Common/SetUserOptionAjax?key=AudioVolume&value=" + value.toString(),
        type: "POST"
    });
}
like image 25
jtsoftware Avatar answered Nov 15 '22 12:11

jtsoftware