Does the "preload" attribute of <audio> affect the window.onload event time? - javascript

I have assumed (possibly incorrectly?), due to the asynchronous nature of HTML, that the timeline of page loading is as follows:
... etc loading html into DOM
encounter <audio> tag
preload is specified as "auto"; trigger buffering
continue loading html into DOM... etc
fire window.onload event callbacks
asynchronously some time later: audio resource is found, begin buffering, or server error is returned; fire readystatechange event callbacks
Whereas what I'm hoping for is that the preload attribute with a value of "auto" will delay the window.onload event from firing or delay tag-to-DOM processing until the audio resource is found and has had begun buffering, or a server error is returned and loading is canceled.
I can't imagine withholding window.onload for an audio resource, but then I have seen page processing come to a halt for flash resource loading or tracking script loading in the past.
TLDR: What is the exact timeline of window.onload with regard to resource loading--specifically the audio tag?

window.onload event appears to be called before the media src is fully loaded. Using approaches described at How do you check if a HTML5 audio element is loaded? ; and including .webkitAudioDecodedByteCount
<!DOCTYPE html>
<html>
<head>
<script>
window.addEventListener("load", function() {
var media = document.querySelector("audio");
console.log("window onload event"
, media.webkitAudioDecodedByteCount
, media.readyState)
})
function myOnCanPlayFunction() {
console.log("Can play", event.target.webkitAudioDecodedByteCount
, event.target.seekable.start(0)
, event.target.seekable.end(0));
}
function myOnCanPlayThroughFunction() {
console.log("Can play through", event.target.webkitAudioDecodedByteCount
, event.target.seekable.start(0)
, event.target.seekable.end(0));
}
function myOnLoadedData() {
console.log("Loaded data", event.target.webkitAudioDecodedByteCount
, event.target.seekable.start(0)
, event.target.seekable.end(0));
}
</script>
</head>
<body>
<audio oncanplay="myOnCanPlayFunction()"
oncanplaythrough="myOnCanPlayThroughFunction()"
onloadeddata="myOnLoadedData()"
src="/path/to/audio/file"
preload autoplay buffered controls></audio>
</body>
</html>
plnkr version 1 http://plnkr.co/edit/zIIDDLZeVU7NHdfAtFka?p=preview
An alternative approach using XMLHttpRequest , onended event of AudioContext; Promise; recursion to request, play array of files in sequence. See AudioContext.decodeAudioData()
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script>
var sources = ["/path/to/audio/src/1"
, "/path/to/audio/src/2"];
var src = sources.slice(0); // copy original array
function getAudio(url) {
return new Promise(function(resolve, reject) {
var audioCtx = new(window.AudioContext || window.webkitAudioContext)();
var source = audioCtx.createBufferSource();
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.responseType = "arraybuffer";
request.onload = function() {
var audioData = request.response;
audioCtx.decodeAudioData(audioData).then(function(decodedData) {
source.buffer = decodedData;
source.connect(audioCtx.destination);
console.log(source, decodedData);
// do stuff when current audio has ended
source.onended = function() {
console.log("onended:", url);
if (src.length)
resolve(src)
else resolve("complete")
}
source.start(0);
});
}
request.send();
})
}
var audio = (function tracks(s) {
return getAudio(s.shift())
.then(function(data) {
if (Array.isArray(data) && data.length) return tracks(data)
else return data
})
}(src));
// do stuff when all `src` have been requested, played, ended
audio.then(function(msg) {
console.log(msg)
})
</script>
</head>
<body>
</body>
</html>
plnkr version 2 http://plnkr.co/edit/zIIDDLZeVU7NHdfAtFka?p=preview

Related

How to play a video in a Seamless loop using media source extensions

I am working on media source extension to play the video in a seamless loop without any delay. I have done an extensive r&d about it and also done different things. Now i am working on this code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<video controls></video>
<script>
var video = document.querySelector('video');
var assetURL = 'test1.mp4';
// Need to be specific for Blink regarding codecs
// ./mp4info frag_bunny.mp4 | grep Codec
var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
var mediaSource = new MediaSource;
//console.log(mediaSource.readyState); // closed
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
console.error('Unsupported MIME type or codec: ', mimeCodec);
}
function sourceOpen (_) {
//console.log(this.readyState); // open
var mediaSource = this;
var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
fetchAB(assetURL, function (buf) {
sourceBuffer.addEventListener('updateend', function (_) {
mediaSource.endOfStream();
video.play();
//console.log(mediaSource.readyState); // ended
});
sourceBuffer.appendBuffer(buf);
});
};
function fetchAB (url, cb) {
console.log(url);
var xhr = new XMLHttpRequest;
xhr.open('get', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
cb(xhr.response);
};
xhr.send();
};
</script>
</body>
</html>
It is working fine but the video is playing again with a slight delay. I want to play the video without any delay and I know that it is possible with media source extensions but after spending a lot of time still didn't get any idea that how to do it. Any help would be really appreciated. Thanks
Setting the mode value to sequence worked for me, it ensures continuous media playback, no matter if the media segment timestamps were discontinuous.
sourceBuffer.mode = 'sequence';
May be this code solve Your Problem ....play the video in a seamless loop without any delay
for (let chunk of media) {
await new Promise(resolve => {
sourceBuffer.appendBuffer(chunk.mediaBuffer);
sourceBuffer.onupdateend = e => {
sourceBuffer.onupdateend = null;
sourceBuffer.timestampOffset += chunk.mediaDuration;
console.log(mediaSource.duration);
resolve()
}
})
}
if you need more information visit this link.....
http://www.esjay.org/2020/01/01/videos-play-without-buffering-in-javascript/
You can't really do that because it really depends on how fast your PC runs. Its delay should only be there if you have a slow PC but if not it shouldn't have a noticeable delay. Maybe the video that you have is big or it just delays inside the video because only thing I could tell you is autoplay loop inside the videos element as a attribute unless you find a way to replay the video before the video ends but even if it doesn't delay for you it may delay big or just play over the video for others
#CoolOppo
The simplest thing to do is to just rewind the video when it reaches it's end time (duration).
See demo here: https://vc-lut.000webhostapp.com/demos/public/mse_loop_example1.html
(to play video just click the picture part, since no controls for looping background)
The code:
<!DOCTYPE html>
<html>
<head> <meta charset="utf-8"/> </head>
<body>
<div>
<video id="video_mse" > </video>
</div>
<script>
var assetURL = "testloop.mp4";
//# use correct mime/codecs or else Error is "source not open"...
var mimeCodec = 'video/mp4; codecs="avc1.42C01E"';
var mediaSource; var sourceBuffer;
var video = document.getElementById( "video_mse" );
video.onclick = vid_togglePlay; //# for playing/pausing
video.ontimeupdate = vid_checkTime; //# for looping
//# handle play/pause (because controls are hidden)
function vid_togglePlay()
{
if( video.paused == true ) { video.play(); }
else { video.pause(); }
}
//# handle looping...
function vid_checkTime()
{
if( video.currentTime == video.duration)
{
video.currentTime = 0;
video.play();
}
}
if ( 'MediaSource' in window && MediaSource.isTypeSupported(mimeCodec) )
{
mediaSource = new MediaSource;
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
}
else
{ console.error('Unsupported MIME type or codec: ', mimeCodec); }
function sourceOpen()
{
//console.log(this.readyState); // open
var mediaSource = this;
sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
fetchAB(assetURL, function (buf) {
sourceBuffer.addEventListener('updateend', function() {
mediaSource.endOfStream();
video.play();
});
sourceBuffer.appendBuffer(buf);
});
};
function fetchAB (url, callbackfunc )
{
console.log("loading file: " + url);
var xhr = new XMLHttpRequest;
xhr.open('get', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function() { callbackfunc( xhr.response ); }
xhr.send();
}
</script>
</body>
</html>

Javascript mediaSource element

I am trying to play a video using javascript mediasource to hide video URL from the users. But I get an error as,
Uncaught InvalidStateError: Failed to execute 'endOfStream' on 'MediaSource': The MediaSource's readyState is not 'open'. And it would also be helpful if the video type and codes to be passed dynamically.
Below is my code,
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<video controls></video>
<script>
var video = document.querySelector('video');
var assetURL = 'adsss.mp4';
// Need to be specific for Blink regarding codecs
// ./mp4info frag_bunny.mp4 | grep Codec
var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
var mediaSource = new MediaSource;
//console.log(mediaSource.readyState); // closed
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
console.error('Unsupported MIME type or codec: ', mimeCodec);
}
function sourceOpen (_) {
console.log(this.readyState); // open
var mediaSource = this;
console.log(mediaSource);
var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
console.log(sourceBuffer);
fetchAB(assetURL, function (buf) {
sourceBuffer.addEventListener('updateend', function (_) {
mediaSource.endOfStream();
video.play();
console.log(mediaSource.readyState); // ended
});
sourceBuffer.appendBuffer(buf);
});
};
function fetchAB (url, cb) {
console.log(url);
var xhr = new XMLHttpRequest;
xhr.open('get', url);
console.log(xhr);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
cb(xhr.response);
console.log(xhr.response);
};
xhr.send();
};
</script>
The reason why the above code was not working is that, only fragmented mp4 videos with moov(movie header box) moved at the beginning will be played using the Media source.
Refer the below links,
1) Unable to get MediaSource working with mp4 format in chrome
2) What exactly is Fragmented mp4(fMP4)? How is it different from normal mp4?
You can fragment your videos using MP4box tool with the following command,
MP4Box -dash 1000 -rap -frag-rap test.mp4

Execute function only when images/sounds are loaded, Jquery

I dynamically set image and audio sources when window/document is already loaded, e.g. I set them after user performs some manipulations on the page:
// image and audio set
jQuery("#image").css('background-image', 'url(../content/icons/1/18.png)').css('backgroundPosition', '0 -40px');
var myAudio = new Audio('http://domain/content/audio/1/full-18.mp3');
myAudio.pause();
// i want this part of code be executed only when images and audio is fully loaded
myAudio.play();
Solution number 1, isn't working
jQuery("#page").load(function() {});
Solution number 2, isn't working
jQuery(window).load(function() {});
Any other idea how to this can be solved? Thank you in advance
You need to specifically target the image element to check if it has loaded.
$('#image').load(function () {
console.log('image loaded');
});
To check if the audio element is ready to be played you need to use onloadeddata.
var myAudio = new Audio('http://www.mfiles.co.uk/mp3-downloads/edvard-grieg-peer-gynt1-morning-mood.mp3');
myAudio.onloadeddata = audioIsLoaded();
function audioIsLoaded() {
console.log('audio is loaded');
}
Run the below code snippet to see this in action.
$('#image').load(function() {
alert('image loaded');
});
var myAudio = new Audio('http://www.mfiles.co.uk/mp3-downloads/edvard-grieg-peer-gynt1-morning-mood.mp3');
myAudio.onloadeddata = audioReady();
function audioReady() {
alert('audio ready');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id="image" src="http://armpit-wrestling.com/wp-content/uploads/2016/06/bret-hart.jpg">

Running a HTML5 Audio player in a Firefox Add-ons SDK page-worker

I am trying to repair a firefox addon that I created some time ago which has stopped functioning properly after a recent-ish Firefox update. The part which no longer functions was a mp3 player, which ran in the background.
The page-worker has a very small html page with an embedded media player and a script that controls the player. The script is passed in a filepath for an mp3 on my machine to use as the players src, and then told to start playing. This used to work, but now upon calling the embedded player's play function an error is thrown. The src is correctly set and the play event triggers, but the canplay event does not. The error code given is 4, which I believe is MEDIA_ERR_SRC_NOT_SUPPORTED.
If I open the HTML page and feed the player the filepath manually, it all works fine. What's going wrong here that wasn't before?
The HTML page is
<!DOCTYPE hmtl>
<html>
<head>
<title>Sound Stone: mp3 pageworker</title>
</head>
<body>
<video></video>
</body>
<html>
The content script is
var player = document.getElementsByTagName("video")[0];
var starttime;
var stoptime;
var checkTime;
self.port.on("start", function(url){
player.src=url;
player.pause();
stoptime = undefined;
self.port.emit("change", false);
});
self.port.on("stop", function(){
player.pause();
player.removeEventListener("canplay", goTo);
});
self.port.on("play", function(beg, end){
clearInterval(checkTime);
if(beg){
starttime = beg/1000;
}
if(end){
stoptime = end/1000;
}
player.play(); // this is where it goes wrong
if(beg){
player.addEventListener("canplay", goTo);
}
if(stoptime){
checkTime = setInterval(function (){
if(player.currentTime>=stoptime){
player.currentTime=99999;
clearInterval(checkTime);
}
}, 1000);
}
});
self.port.on("pause", function(){
player.pause();
});
player.onplay = function(){
self.port.emit("change", true);
}
player.onpause = function(){
self.port.emit("change", false);
}
player.onended = function(){
self.port.emit("done");
}
player.onerror = function(){
self.port.emit("out", player.error.code); // this outputs 4
self.port.emit("out", player.src); // this outputs as expected
}
function goTo(){
player.currentTime=starttime;
player.removeEventListener("canplay", goTo);
}
And a small excerpt of the main program is
var mp3 = worker.Page({
contentScriptFile: "./mp3.js",
contentURL: "./mp3.html",
});
mp3.port.on("out", function(msg){
console.log(msg);
});

audio.play() html tag doesn't play in chrome

I am facing an issue while playing audio in chrome when audio.src is not called preceeding to play call. However, firefox plays it alright. Can someone pls suggest? Below is the fiddle link -
http://jsfiddle.net/vn215r2d/1/
One can also find the code over here -
<html>
<head>
<script language="javascript">
var audioo = document.createElement("audio");
function newCall() {
audioo.src = "";
audioo.src = "http://xx.xx.xx.xx:8181/api/captcha/sound";
audioo.play();
}
function playAgain() {
audioo.play(); // doesn't work in chrome :(
}
</script>
</head>
<body>
<button type="button" onClick="newCall()">New Captcha Call</button>
<br>
<button type="button" onClick="playAgain()">Replay Captcha</button>
</body>
</html>
Update
Oh waw, apparently is comes down to the audio.currentTime not being writeable until you rewrite the src. Heres what you can do and it does work:
function newCall() {
audioo.src = "http://xx.xx.xx.xx:8181/api/captcha/sound";
// make all audio attributes writeable again by resetting the src
audioo.src = audio.src;
}
The answer took a bit of googling, but I got it from here: https://stackoverflow.com/a/14850353
Original
I tested on Chrome with resetting the audio position and it worked. Its safest to pause first, but it works either way.
var audioo = document.createElement("audio");
// Lets add an event listener to play when we are ready to start playing
audioo.addEventListener("canplaythrough", function(){
audioo.play();
}, false);
function newCall() {
audioo.src = "";
audioo.src = "http://xx.xx.xx.xx:8181/api/captcha/sound";
}
function playAgain() {
// Let's check if we are ready enough to play
if(audioo.readyState === 4){
audioo.pause(); // first pause
audioo.currentTime = 0; // then reset
audioo.play(); // then play
} else {
// else inform us that we are not ready to play yet.
alert("Audio not ready yet.");
}
}
Here are two fun resources that can help:
MDN:
MediaElement (usefull properties and functions)
MDN:
Media Events (for event listeners)

Categories