DOM Exception 11 when calling webkitEnterFullscreen() - javascript

What does the exception mean? How can I fix it? I am using the latest Google Chrome for Ubuntu.

INVALID_STATE_ERR: DOM Exception 11 can occur when a call to webkitEnterFullscreen is made before the video element has received its asset's metadata. The simplest solution is to defer the invocation of webkitEnterFullscreen by putting it in a callback function assigned to the video's loadedmetadata event.
In a mobile environment, you need to take things a step further by attaching that call to a touchable element so that it is user initiated since play and fullscreen actions must be driven by user interaction in mobile environments.
The code should look kind of like this:
var video, play, fullscreen;
video = document.createElement('video');
video.src = 'my_cool_video.mp4';
video.addEventListener('loadedmetadata', function () {
fullscreen.disabled = false;
}, false);
play = document.createElement('button');
play.innerHTML = 'PLAY';
play.addEventListener('click', function () {
video.play();
}, false);
fullscreen = document.createElement('button');
fullscreen.innerHTML = 'FULLSCREEN';
fullscreen.disabled = true;
fullscreen.addEventListener('click', function () {
video.webkitEnterFullscreen();
}, false);
document.body.appendChild(video);
document.body.appendChild(play);
documnet.body.appendChild(fullscreen);

Related

How can I programmatically determine when an JavaScript AudioContext AudioBufferSource is done playing?

I am playing .MP3 files with the Web Audio API, and I am having trouble programmatically determining when the song is finished playing.
This is what I have:
var request = new XMLHttpRequest();
audioContext = new AudioContext();
source = audioContext.createBufferSource();
source.connect(audioContext.destination);
request.open('GET',url,true);
request.responseType='arraybuffer';
request.onload = function() {
audioContext.decodeAudioData(request.response).then(function(buffer) {
source.buffer = buffer;
source.start(0);
});
}
request.send();
This works well; I can start, stop, pause, and unpause a song with no problems.
What I want to do, however, is when a song stops playing upon completion (i.e., I have not called audioContext.close()), I want to call another function to set a message for the user. I have looked for some sort of callback I could leverage, I have tried the finally() of the promise provided by the audioContext.decodeAudioData() provides, but I haven't been able to figure this out.
Handle the ended event of your audioContext. See AudioScheduledSourceNode: ended event for reference.
source.addEventListener('ended', () => {
// done!
});
Or use the onended property.
source.onended = () => {
// done!
}

How to autoplay audio when the countdown timer is finished?

I want to play a sound after the countdown timer is done.
Normally I will do it using this peace of code
var audio = new Audio('path to file.mp3');
audio.play();
But I get the following error Unhandled Promise Rejection: NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
The thing is ... Google it self is doing it using a HTML5 audio tag
If you type countdown timer into google search field it should show you the widget that plays a sound after the countdown timer is finished.
Here is how Googles timer look like, if you guys don't know what I'm talking about :)
By making you click this "START" button, they ask for an user gesture and thus have marked their document as approved-by-user to play audio. This means they are not subject for chrome's autoplay policies anymore.
Now, Safari by default is even stricter than Chrome here, and a simple click on the document doesn't work: in this browser you need to start the playback from the user-event itself.
So in your case, it won't work, even if you did start the countdown from a click like Google.
The solution is then to start the playback from the click event, and to pause it immediately after. Doing so, your Element will be marked as approved-by-user and you will ave full control over it.
const audio = new Audio("https://dl.dropboxusercontent.com/s/1cdwpm3gca9mlo0/kick.mp3");
let time = 5;
btn.onclick = e => {
// mark our audio element as approved by the user
audio.play().then(() => { // pause directly
audio.pause();
audio.currentTime = 0;
});
countdown();
btn.disabled = true;
};
function countdown() {
pre.textContent = --time;
if(time === 0) return onend();
setTimeout(countdown, 1000);
}
function onend() {
audio.play(); // now we're safe to play it
time = 5;
btn.disabled = false;
}
<button id="btn">start countdown</button><br>
<pre id="pre"></pre>

Vimeo Froogaloop - Not detecting pause

I am using the old Vimeo API froogaloop for a project. I realise this is now out of date but this is a legacy project and does not support the new version.
I am trying to determine if a video is paused or not by doing this..
$lg.on('onAfterSlide.lg', function(event, prevIndex, index){
iframe = $('.inner .item').eq(index).find('.vimeo').get(0);
var player = $f(iframe);
player.addEvent('ready', function() {
player.addEvent('paused', function(paused) {
if (paused) {
console.log('Video is paused');
}
else {
console.log('Video is not paused');
}
});
});
});
For some reason the paused function never runs, can anyone see any obvious mistakes I am making?
Looks like you are listening to the wrong event. Update paused to pause.
player.addEvent('pause',...
That should ensure you are listening to the correct event.
Out of curiosity, what in your out of date project blocks you from updating to the latest Video Player API from Froogaloop?

Video 'timeupdate' listener forgets values

I have a html5 video event listener that is supposed to wait until the correct time and then pause the video while the user takes part in a quiz. The first 'lesson' works fine, and the second video also appears to add the listener with the correct time to pause. But upon playing the second video it always pauses at 170 seconds, the pause time from the FIRST video.
Also, when I check Chrome's dev panel it actually shows timeCache as having immediately reverted back to the previous videos values as soon as the video is played; unless the video has passed the 170 mark, then it will use the 230 second timeCache value as it should. At first I thought it was because the old event listener was still attached, but I have eliminated that possibility and the problem still persists. Here is the link http://koreanwordgame.com/grammar/
var setPause = function (time) {
var video = $("video").get(0);
var timeCache = time;
video.removeEventListener('timeupdate', timeListener, false);
function timeListener (){
if (video.currentTime >= timeCache && video.currentTime < (timeCache + 0.3)) {
video.pause();
}}
video.addEventListener('timeupdate', timeListener);
};
the first $watch in the directive is triggered each time a new lesson is loaded, it binds the ended event as well as the timeupdate listener via setPause() and then loads and plays the video. The idea is that setPause sets the time that the video will automatically pause at when it reaches, and then the second $watch waits until all the questions have been answered before playing the remainder of the video (generally a congratulations message)
app.directive('videoWatcher', function () {
return function (scope, video, attrs) {
scope.$watch(attrs.videoLoader, function () {
$(video[0]).bind('ended', function () {
$(this).unbind('ended');
if (!this.ended) {
return;
}
scope.tutorialNumber++;
scope.$apply();
scope.loadFromMenu();
});
setPause(scope.currentTutorial.pause);
video[0].load();
video[0].play();
});
scope.$watch(attrs.congrats, function(){
var cT = scope.currentTutorial;
if (scope.questionNumber === cT.material.length){
video[0].play();
setTimeout(function () {
video[0].play();
}, 500);
}
});
};
})
Every time you call your pause function, you create a new instance of the timeListener function. Any reference to timeListener is a reference to the one you just created. So when you're removing the event listener, you're removing the new function, not the one you attached before.
In Javascript, within a given function, it doesn't matter where you declare variables and functions; they are always "hoisted" to the top. So even though you write the timeListener function after your call to removeEventListener, your code behaves as though you declared it at the top of pause. This is why it's usually a good idea to declare all your variables and functions before running any other code (and JSLint will give you a hard time if you don't). The exception is when you explicitly assign a function to a variable.
You can fix this by declaring timeListener outside of pause, so it will always be a reference to the previous instance. Like this:
var timeListener;
function pause(time) {
//timeCache is unnecessary
var video = $("video").get(0),
end = time + 0.3; //cache this so you don't have to add every time
if (timeListener) {
//remove previous timeListener function, if there is one
video.removeEventListener('timeupdate', timeListener, false);
}
//make a new function and save it for later as timeListener
timeListener = function () {
if (video.currentTime >= time && video.currentTime < end) {
video.pause();
}
};
video.addEventListener('timeupdate', timeListener);
};

Tell whether video is loaded or not in Javascript

So, I've been using a listener on
document.getElementById("video").buffered.length
to see if it's greater than 0 for when a video's loaded or not. This works for a very small video, and only in Google Chrome. It doesn't work in Firefox at all. Any ideas for how to get this to work?
I essentially want to wait till 3 seperate videos are loaded to take a specific action, how do I go about this?
Try this:
var video = document.getElementById("video-id-name");
if ( video.readyState === 4 ) {
// it's loaded
}
Read here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState
UPDATE:
As others have mentioned, my original solution below does work but it can lead to performance issues and some unpredictability in its behaviour.
Therefore I recommend listening to the loadeddata event.
Read more here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/loadeddata_event
const videoElement = document.getElementById("my_video");
videoElement.addEventListener('loadeddata', (e) => {
//Video should now be loaded but we can add a second check
if(videoElement.readyState >= 3){
//your code goes here
}
});
==================================
INFERIOR SOLUTION:
I find using setInterval works for actively listening to when the readyState of the video changes by checking every half-second until it loads in.
checkforVideo();
function checkforVideo() {
//Every 500ms, check if the video element has loaded
var b = setInterval(()=>{
if(VideoElement.readyState >= 3){
//This block of code is triggered when the video is loaded
//your code goes here
//stop checking every half second
clearInterval(b);
}
},500);
}
If you're not using ES6 just replace () => with function()
To make this into a listener, under normal circumstances, you'll want to listen to the suspend event. It's triggered when download is paused or stopped for any reason, including it's finished.
You'll also want to listen to playing for the cases when the content is already loaded (like, from cache)
video.addEventListener("playing", function() {
console.log("[Playing] loading of video");
if ( video.readyState == 4 ) {
console.log("[Finished] loading of video");
}
});
video.addEventListener("suspend", function(e) {
console.log("[Suspended] loading of video");
if ( video.readyState == 4 ) {
console.log("[Finished] loading of video");
}
});
Source: https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events
Use onloadeddata event on the video element. It checks whether the video is loaded or not. See this reference for more information.
The loadeddata event is fired when the frame at the current playback position of the media has finished loading; often the first frame.
var video = document.getElementById("video");
video.onloadeddata = function() {
// video is loaded
}
I find other way
const video = document.querySelector('video');
video.addEventListener('canplaythrough', (event) => {
console.log('I think I can play through the entire ' +
'video without ever having to stop to buffer.');
});
source - https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canplaythrough_event

Categories