HTML5 video ended event called several times - javascript

I have a problem with playing a video in HTML5 and the ended Event.
I view some HTML content and after a expired time I play a video. Is the video ended I will show the HTML content again. This should loop. Its for a presentation.
My problem is, that after the first complete run, the ended event will fired repeatedly and the HTML content will displayed false.
Here is the code part:
function playVideo() {
var video = $('video')[0];
video.addEventListener('ended', function () {
$('video').hide();
fadeShow();
}, false);
video.play();
}
function fadeHide() {
$('#content').fadeOut(1200, function () {
$('div ul[id^=item]').each(function () {
$(this).hide();
});
$('li[class^=visitor] span[id]').each(function () {
$(this).hide();
});
playVideo();
});
}
The fadeHide(); function will not called two times, just the video.addEventListener('ended', function () {}; fill called several times. `fadeshow(); will display the HTML content. Actually I use the newest version of Chrome.
Does anyone have an idea what went wrong?
Edit
HTML video code. I hide the video with css.
<video>
<source src="video/mp4/xxx.mp4" type="video/mp4" />
<source src="video/ogg/xxx.ogg" type="video/ogg" />
<source src="video/webm/xxx.webm" type="video/webm" />
Your browser does not support the video tag.
</video>
Greetz

You should assign the event listener once or when you assign it upon play everytime, you need to detach the event listener again.
function playVideo() {
var video = $('video')[0];
video.addEventListener('ended', function () {
$('video').hide();
video.removeEventListener('ended'); <<<<<<<
fadeShow();
}, false);
video.play();
}
EDIT: I tested in chrome with this fiddle and indeed even if you remove the eventlistener it starts to fire multiple times. It seems there's an issue that removing the event listener does not work correctly.
You should change the event binding / unbinding to jQuery then there is only one ended event.
function playVideo() {
var video = $('video')[0];
$('video').bind('ended', function () {
$('video').unbind('ended');
$('video').hide();
fadeShow();
});
video.play();
}
And your fiddle updated (with shorter video)

Instead of adding an event listener and then manually removing it, try simply using the built in command called "one" (https://github.com/videojs/video.js/blob/master/docs/api/vjs.Player.md#one-first-second-third-)
So your code will become somewhat like this:
function playVideo() {
var video = $('video')[0];
$('video').one('ended', function () {
$('video').hide();
fadeShow();
});
video.play();
}
Which is a little brief, and more dependent on the API itself. That I believe is generally a good practice because the functions in the API have been tested multiple times by a large number of people in the community over multiple browsers and operating systems.

Related

Error occurred after playing last video from parent div by clicking on play image (Jquery)

I have multiple videos been fetched with ajax (dynamically, load more I mean).
All videos play well when play button is clicked from parent div but when last video (or sometimes the first video) is been clicked, the other videos refuses to play when clicked and current clicked video (which is the last) refuses to stop when paused and play button only blink multiple times.
I have been trying to solve this problem but I have been facing difficulties for I have no clue. I need your help.
JQUERY
// Ajax load more script that fetches videos starts here
// success:function(data) {
// video play/pause
$('.post_video').parent().click(function() {
var currentVideo = $(this).children(".post_video").get(0);
var allVideos = $(".post_video");
allVideos.each(function(){
if (currentVideo != this)
this.pause();
});
if (currentVideo.paused){
currentVideo.play();
$(this).children(".playpause").fadeOut();
} else {
currentVideo.pause();
$(this).children(".playpause").fadeIn();
}
});
// }
// Ajax load more script that fetches videos ends here
HTML
<div class="video_wrapper">
<video class="post_video" loop>
<source src="videos/vid.mp4" type="video/mp4">
</video>
<div class="playpause"></div>
</div>
It seems like adding duplicate click handlers to your video_wrapper when you load more videos.
You should only add the handler to the newly added videos or use event delegation so you don't have to add the handler every time you load more videos.
// Use event delegation to attach click handlers outside of ajax
// any reason you select post_video then get their parents instead of just selecting video_wrapper?
$(document).on('click', '.video_wrapper', function() {
var currentVideo = $(this).children(".post_video").get(0);
var allVideos = $(".post_video");
allVideos.each(function(){
if (currentVideo != this)
this.pause();
});
if (currentVideo.paused){
currentVideo.play();
$(this).children(".playpause").fadeOut();
}
else {
currentVideo.pause();
$(this).children(".playpause").fadeIn();
}
});

Please help me to use play/stop code so my code should stop and reset not pause [duplicate]

I am playing a small audio clip on click of each link in my navigation
HTML Code:
<audio tabindex="0" id="beep-one" controls preload="auto" >
<source src="audio/Output 1-2.mp3">
<source src="audio/Output 1-2.ogg">
</audio>
JS code:
$('#links a').click(function(e) {
e.preventDefault();
var beepOne = $("#beep-one")[0];
beepOne.play();
});
It's working fine so far.
Issue is when a sound clip is already running and i click on any link nothing happens.
I tried to stop the already playing sound on click of link, but there is no direct event for that in HTML5's Audio API
I tried following code but it's not working
$.each($('audio'), function () {
$(this).stop();
});
Any suggestions please?
Instead of stop() you could try with:
sound.pause();
sound.currentTime = 0;
This should have the desired effect.
first you have to set an id for your audio element
in your js :
var ply = document.getElementById('player');
var oldSrc = ply.src;// just to remember the old source
ply.src = "";// to stop the player you have to replace the source with nothing
I was having same issue. A stop should stop the stream and onplay go to live if it is a radio. All solutions I saw had a disadvantage:
player.currentTime = 0 keeps downloading the stream.
player.src = '' raise error event
My solution:
var player = document.getElementById('radio');
player.pause();
player.src = player.src;
And the HTML
<audio src="http://radio-stream" id="radio" class="hidden" preload="none"></audio>
Here is my way of doing stop() method:
Somewhere in code:
audioCh1: document.createElement("audio");
and then in stop():
this.audioCh1.pause()
this.audioCh1.src = 'data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAVFYAAFRWAAABAAgAZGF0YQAAAAA=';
In this way we don`t produce additional request, the old one is cancelled and our audio element is in clean state (tested in Chrome and FF) :>
This method works:
audio.pause();
audio.currentTime = 0;
But if you don't want to have to write these two lines of code every time you stop an audio you could do one of two things. The second I think is the more appropriate one and I'm not sure why the "gods of javascript standards" have not made this standard.
First method: create a function and pass the audio
function stopAudio(audio) {
audio.pause();
audio.currentTime = 0;
}
//then using it:
stopAudio(audio);
Second method (favoured): extend the Audio class:
Audio.prototype.stop = function() {
this.pause();
this.currentTime = 0;
};
I have this in a javascript file I called "AudioPlus.js" which I include in my html before any script that will be dealing with audio.
Then you can call the stop function on audio objects:
audio.stop();
FINALLY CHROME ISSUE WITH "canplaythrough":
I have not tested this in all browsers but this is a problem I came across in Chrome. If you try to set currentTime on an audio that has a "canplaythrough" event listener attached to it then you will trigger that event again which can lead to undesirable results.
So the solution, similar to all cases when you have attached an event listener that you really want to make sure it is not triggered again, is to remove the event listener after the first call. Something like this:
//note using jquery to attach the event. You can use plain javascript as well of course.
$(audio).on("canplaythrough", function() {
$(this).off("canplaythrough");
// rest of the code ...
});
BONUS:
Note that you can add even more custom methods to the Audio class (or any native javascript class for that matter).
For example if you wanted a "restart" method that restarted the audio it could look something like:
Audio.prototype.restart= function() {
this.pause();
this.currentTime = 0;
this.play();
};
It doesn't work sometimes in chrome,
sound.pause();
sound.currentTime = 0;
just change like that,
sound.currentTime = 0;
sound.pause();
From my own javascript function to toggle Play/Pause - since I'm handling a radio stream, I wanted it to clear the buffer so that the listener does not end up coming out of sync with the radio station.
function playStream() {
var player = document.getElementById('player');
(player.paused == true) ? toggle(0) : toggle(1);
}
function toggle(state) {
var player = document.getElementById('player');
var link = document.getElementById('radio-link');
var src = "http://192.81.248.91:8159/;";
switch(state) {
case 0:
player.src = src;
player.load();
player.play();
link.innerHTML = 'Pause';
player_state = 1;
break;
case 1:
player.pause();
player.currentTime = 0;
player.src = '';
link.innerHTML = 'Play';
player_state = 0;
break;
}
}
Turns out, just clearing the currentTime doesn't cut it under Chrome, needed to clear the source too and load it back in. Hope this helps.
As a side note and because I was recently using the stop method provided in the accepted answer, according to this link:
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events
by setting currentTime manually one may fire the 'canplaythrough' event on the audio element. In the link it mentions Firefox, but I encountered this event firing after setting currentTime manually on Chrome. So if you have behavior attached to this event you might end up in an audio loop.
shamangeorge wrote:
by setting currentTime manually one may fire the 'canplaythrough' event on the audio element.
This is indeed what will happen, and pausing will also trigger the pause event, both of which make this technique unsuitable for use as a "stop" method. Moreover, setting the src as suggested by zaki will make the player try to load the current page's URL as a media file (and fail) if autoplay is enabled - setting src to null is not allowed; it will always be treated as a URL. Short of destroying the player object there seems to be no good way of providing a "stop" method, so I would suggest just dropping the dedicated stop button and providing pause and skip back buttons instead - a stop button wouldn't really add any functionality.
This approach is "brute force", but it works assuming using jQuery is "allowed". Surround your "player" <audio></audio> tags with a div (here with an id of "plHolder").
<div id="plHolder">
<audio controls id="player">
...
</audio>
<div>
Then this javascript should work:
function stopAudio() {
var savePlayer = $('#plHolder').html(); // Save player code
$('#player').remove(); // Remove player from DOM
$('#FlHolder').html(savePlayer); // Restore it
}
I was looking for something similar due to making an application that could be used to layer sounds with each other for focus. What I ended up doing was - when selecting a sound, create the audio element with Javascript:
const audio = document.createElement('audio') as HTMLAudioElement;
audio.src = getSoundURL(clickedTrackId);
audio.id = `${clickedTrackId}-audio`;
console.log(audio.id);
audio.volume = 20/100;
audio.load();
audio.play();
Then, append child to document to actually surface the audio element
document.body.appendChild(audio);
Finally, when unselecting audio, you can stop and remove the audio element altogether - this will also stop streaming.
const audio = document.getElementById(`${clickedTrackId}-audio`) as HTMLAudioElement;
audio.pause();
audio.remove();
If you have several audio players on your site and you like to pause all of them:
$('audio').each( function() {
$(this)[0].pause();
});
I believe it would be good to check if the audio is playing state and reset the currentTime property.
if (sound.currentTime !== 0 && (sound.currentTime > 0 && sound.currentTime < sound.duration) {
sound.currentTime = 0;
}
sound.play();
for me that code working fine. (IE10+)
var Wmp = document.getElementById("MediaPlayer");
Wmp.controls.stop();
<object classid="clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6"
standby="Loading áudio..." style="width: 100%; height: 170px" id="MediaPlayer">...
Hope this help.
What I like to do is completely remove the control using Angular2 then it's reloaded when the next song has an audio path:
<audio id="audioplayer" *ngIf="song?.audio_path">
Then when I want to unload it in code I do this:
this.song = Object.assign({},this.song,{audio_path: null});
When the next song is assigned, the control gets completely recreated from scratch:
this.song = this.songOnDeck;
The simple way to get around this error is to catch the error.
audioElement.play() returns a promise, so the following code with a .catch() should suffice manage this issue:
function playSound(sound) {
sfx.pause();
sfx.currentTime = 0;
sfx.src = sound;
sfx.play().catch(e => e);
}
Note: You may want to replace the arrow function with an anonymous function for backward compatibility.
In IE 11 I used combined variant:
player.currentTime = 0;
player.pause();
player.currentTime = 0;
Only 2 times repeat prevents IE from continuing loading media stream after pause() and flooding a disk by that.
What's wrong with simply this?
audio.load()
As stated by the spec and on MDN, respectively:
Playback of any previously playing media resource for this element stops.
Calling load() aborts all ongoing operations involving this media element

How to keep synchronized video element especially after pause/play event in (html5/javascript)

I try to have in a html5 webpage project three elements fully synchronized. To ensure no shift due to video download, I put the attribute preload="auto" to the video elements.
My script is as follows:
var run = document.getElementById("run"); //run is a button element
var vid = document.getElementById("video1"); // the first video element
function PlayVideo() {
if (vid.paused) {
vid.play();
run.textContent = "||";
} else {
vid.pause();
run.textContent = ">";
}
} // The PlayVideo() function is called onclick on the run button
$('#video1').on('play', ambiance = function(){
document.getElementById("video2").play();
document.getElementById("video3").play();
});
$('#video1').on('pause', ambiance = function(){
document.getElementById("video2").pause();
document.getElementById("video3").pause();
});
When using this piece of script after waiting few seconds to a complete load of the video files, the run button plays correctly the first video and the two others start synchronized. But when I pause the run button pushing a second time on it, only the first video stops and the two others continue to be played during 2 or 3 seconds (both of them synchronized but not with the first one).
Could you help me?
Is there an other way (more elegant) to play synchronized video?
One last element: the source of the three video is the same. (Same video played in each elements).
Thank you
Try something like this:
var videos = document.querySelectorAll('video');
function playAll() {
[].forEach.call(videos, function(video) {
video.play()
});
}
function pauseAll() {
[].forEach.call(videos, function(video) {
video.pause()
});
}
// this keeps everything synchronized
[].forEach.call(videos, function(video) {
video.addEventListener('play', playAll, false);
video.addEventListener('pause', pauseAll, false);
});
Keep in mind there will probably still be a slight offset (if you have sound it'll sound distorted)

HTML5 video - Play event not firing

I currently have an HTML5 video event issue in Safari. I am playing a single video on my page. The video loads and plays correctly. However, the play event does not always fire. If the user:
Clicks play
Watches the video to the end (ended event fires)
Clicks play again
The play event does not fire on the second click. If I pause/play the movie at that time, the correct events fire.
How can I make the video tag's play event fire if the video has completed and the user presses play again?
drawVidPlayer is called with the videos index as part of the page render
function drawVidPlayer(vindex){
var turl=vidList[vindex]['thumbUrl'];
var vurl=vidList[vindex]['url'];
var valias=vidList[vindex]['type'];
destroyVidPlayer();
$('#mediaspot').css('backgroundColor', '#000000');
$('#mediaspot').show();
$('#mediaspot').html('<video controls="controls" id="twnvideo" poster="'+turl+'" style="height:225px; width:460px;"><source src="'+vurl+'" type="video/ogg" /><source src="'+vurl+'" type="video/mp4" /><source src="'+vurl+'" type="video/webm" />Your browser does not support the video tag.</video>').appendTo('#wrap_media_vod');
var velem=document.getElementsByTagName('video')[0];
velem.addEventListener('play', initVidTimer, false);
velem.addEventListener('pause', killVidTimer, false);
velem.addEventListener('ended', killVidTimer, false);
}
function destroyVidPlayer(){
var velem=document.getElementsByTagName('video')[0];
if(velem!=undefined){
velem.removeEventListener('play', initVidTimer);
velem.removeEventListener('pause', killVidTimer);
velem.removeEventListener('ended', killVidTimer);
}
$('#mediaspot').empty();
$('#mediaspot').html('');
}
function initVidTimer(){
if(activityTimer==null){
external.OnUserActivity(19);
activityTimer=setInterval(function(){
external.WriteLog('activity timer running');
external.OnUserActivity(19);
}, 5000);
}
}
function killVidTimer(){
clearInterval(activityTimer);
activityTimer=null; // Kill keepAlive timer
var velem=document.getElementsByTagName('video')[0];
external.WriteLog(velem.ended);
}
HTML5 now specifies that the browser must throw the timeupdate, paused, and ended events when the playback position reaches the end of a media file, but the spec wasn't always that clear. As a result, this behavior is inconsistent between browsers. Some don't set paused=true or fire the paused event when the file ends.
In your Safari issue, paused is still equal to false when the video starts to play for the second time - so there is no reason for the browser to fire the play event again.
This may no longer be an issue in Safari 6, but it still breaks in IE 9. Take a look at the End Events column in this chart from longtailvideo.com - they outline the inconsistencies well.
It would easy to normalize this issue with a couple lines of code - like this:
$("video").on("ended", function () {
if (!this.paused) this.pause();
});
This puts the video in the paused state on ended, so it will throw the play event correctly on replay.
You can try this working sample in IE 9 or to see what I mean on this jsfiddle: http://jsfiddle.net/PWnUb/
I had the same issue, I solved with a bit of jquery:
function videoend(){
var duration = $("video").get(0).duration;
var current = $("video").get(0).currentTime;
if(current==duration){
//Whatever you wanna do when video ends
};
}
$(document).ready(function(){
setInterval("videoend()", 200); //or any other time you wanna use
});
Hope this helps.

Jquery return original event on video

I have multiple video plays on a single page which I need to listen for onplay and onpause triggers, and execute custom functions which take the IDs from each of the videos tags. I need to be able to get the video id that was activated. Ive tried a few different ways, with the simple vid.onplay event works well when I know what ID is being called into. I've tried the $("video").onplay but doesn't seem to be working.
jQuery( document ).ready(function($) {
$("video").onplay = function() {
alert("The video has been paused");
};
var vid = document.getElementbyid("myVideo");
vid.onplay = function() {
alert("The video has been played");
};
});
<video class="mdia_video_player" id=myVideo poster="https://tcokchallenge.com/launch2/wp-content/uploads/2020/04/Carter.jpg?336660464" id="v0" onclick="doplayvideo(" 0")"="" controls="">
<source src="https://tcokchallenge.com/launch2/wp-content/uploads/2020/04/Carter.mp4?1222152426" type="video/mp4">
</video>```
In your first demo, it should be $("#video") to call by ID. It also says .onplay and then says that is was paused so you might want to fix that.
Ended up doing a much simpler answer, videos are within a php loop. So, I placed this within the tag
onpause="dopausevideo(<?=$vid ?>)"
onplay="doplayvideo(<?=$vid ?>)"

Categories