I am attempting to build a standard HTML5 video player that supports closed captioning through the <track> element and WebVTT. My goal for this player is to not have to build a custom control UI, but rather rely on the default controls provided by the browser/device.
In order to comply with FCC regulations regarding closed captioning, I am also building a menu with caption formatting options - color, size, opacity, etc. One of the options I would like to include is a toggle for captions off and on, which will be especially useful in a browser like Firefox where the CC button does not exist in the default controls.
I have everything working properly, except for one issue I can not seem to figure out. While using my custom toggle to turn on or off captions, the CC button on the default video controls will also toggle; however, I cannot get this to work the opposite way.
I am looking for some sort of event that gets triggered when the default CC button is pressed so that I can check the showing/hidden/disabled mode of the video textTracks and then update my custom toggle accordingly. Does such an event exist? Is there any way to remove just the CC button from the default controls while leaving the rest? I would hate to have to build a completely custom UI for the player just for this one issue.
Edit 1: Here is a jsFiddle for an example.
http://jsfiddle.net/6z5e37h6/
<div class="htmlVid">
<video width="640" height="360" controls="controls" id="vid">
<source type="video/mp4" src="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4"></source>
</video>
</div>
<label>Captions:</label>
<input onclick="capToggle('off');" type="radio" name="captions" checked="checked" />Off
<input onclick="capToggle('on');" type="radio" name="captions" />On
<script>
var vid = document.getElementById('vid');
var track = vid.addTextTrack('subtitles', 'test', 'en');
var capToggle = function (val) {
if (val == 'on') {
track.mode = 'showing';
} else {
track.mode = 'hidden';
}
}
</script>
As you can see (viewing on Chrome) if you select the captions "on" radio button, the captions will turn on and the default CC button on the default controls will activate (turn opaque). What I am looking for is some way to know that a user clicked the default CC button so that I can automatically update the radio button to reflect the current state.
I would rather not have a regular interval constantly running to check this state, especially with all the other scripts I plan to have running. I know there is an "oncuechange" event for when a new caption shows up, but I was wondering if there was a better way to check right away, rather than have to wait a few seconds potentially to update the value.
Related
I'm trying to get a small sound file to play automatically using an tag and javascript to initiate it.
<audio id="denied" preload="auto" controls="false">
<source src="sound/denied.wav" />
</audio>
And then through javascript, at the appropriate time:
$('#denied')[0].play()
Works fine on Chrome on my desktop. In Android 4.1.1, the sound will not play, unless I hit "play" on the HTML5 audio controls before javascript attempts to play it.
So basically the Android browser (stock or Dolphin) will not play the audio unless the user initiates it at some point before the javascript. Is this intended? Is there any way around this?
Well, for my purposes, here's what I did:
Luckily, before the user can trigger the behavior to start audio, they have to click a button. I set the volume of the element to 0.0, and have it "play" when they click this button.
After the sound is played silently, I simply set the volume property back to 1.0, and it plays without user intervention just fine.
In my case this was an easy solution:
https://stackoverflow.com/a/28011906/4622767
Copy & paste this in your chrome:
chrome://flags/#autoplay-policy
My web app has many page reload so I can't force the user to press a button every time; but it is for internal usage, so I can force the users to use chrome and configure that option.
I know that in mobile safari any javascript call to play() must be in the same call stack as a user initialted click event. Spoofing the the click with a javascript trigger won't work either.
On my nexus 7 I can confirm that unless the javascript was triggered by a user click, it does not play.
The main issue is that sound (on iOS and Android) must be triggered by a user click. My workaround was very simple. Tie the audio.play() to a click event listener and then immediately pause it. From that point and on the sound works perfect.
var myAudio = new Audio('assets/myAudio.mp3');
...
button.addEventListener("click", function() {
myAudio.play();
myAudio.pause();
...
});
Here is a blog-post on the reason and how to overcome it by loading all the audio files on first user interaction and play them later in programmed manner: https://blog.foolip.org/2014/02/10/media-playback-restrictions-in-blink/ Adopting this approach a small javascript module is available on GitHub https://github.com/MauriceButler/simple-audio
I tried this simple approach on my own - worked seamlessly & great!
Luckily for me the html5 app I'm working on only needs to work in Android 4.1, but if you're trying to make something cross-platform you'll need to adapt this slightly. Neither setting volume to 0.0 then back or autoplay on the control worked for me. I also tried muted and that didn't work either. Then I thought, what if I set the duration and only play a miniscule amount of the file? Here's yet another hacked-together script that actually did work:
function myAjaxFunction() {
clearTimeout(rstTimer); //timer that resets the page to defaults
var snd=document.getElementById('snd');
snd.currentTime=snd.duration-.01; //set seek position of audio near end
snd.play(); //play the last bit of the audio file
snd.load(); //reload file
document.getElementById('myDisplay').innerHTML=defaultDisplay;
var AJAX=new XMLHttpRequest(); //won't work in old versions of IE
sendValue=document.getElementById('myInput').value;
AJAX.open('GET', encodeURI('action.php?val='+sendValue+'&fn=find'), true);
AJAX.send();
AJAX.onreadystatechange=function() {
if (AJAX.readyState==4 && AJAX.status==200) {
document.getElementById('myDisplay').innerHTML=AJAX.responseText;
if (document.getElementById('err')) { //php returns <div id="err"> if fail
rstTimer = setTimeout('reset()', 5000); //due to error reset page in 5 seconds
snd.play(); //play error sound
document.getElementById('myInput').value=''; //clear the input
}
}
}
}
You don't need JavaScript for autoplay, and I see several issues in your code:
<audio id="denied" preload="auto" controls="false">
<source src="sound/denied.wav" />
</audio>
I'd change it to (in HTML5 you don't need attribute="value" syntax in some cases, that's for XHTML):
<audio id="denied" autobuffer controls autoplay>
<source src="sound/denied.wav" />
</audio>
play!
In iOS autoplay is disabled, you need to click play button or put a user click event on custom controls like this with JavaScript:
var audio = document.getElementById('denied');
var button = document.getElementById('play-button');
button.addEventListener('click',function(){
audio.play();
});
or with jQuery:
$('#play-button').click(function(){ audio.play(); });}
Edit
Keep in mind that HTML5 is pretty recent technology (at least some functionalities), so browser compatibility and functionality changes every once in a while.
I encourage everybody to keep informed about the current status, as sometimes things start to be less hack-dependant, or the other way around.
A good starting point: http://caniuse.com/#feat=audio (check the tabs at the bottom).
Also for a global audio solution I recommend using SoundManager2 JS library
I met the same problem in my app. My application usage scenario was like this:
click the button to show a table with information (user action)
show the table and refresh data in it by AJAX
play sound when data has been changed
Fortunately I had the user action (step 1) so I was able to "initiate" the sound by it and then play it by javascript without the user action needed. See the code.
HTML
<audio id="kohoutAudio">
<source src="views/images/kohout.mp3">
</audio>
<button id="btnShow">Show table</button>
Javascript
$("#btnShow").click(function () {
//some code to show the table
//initialize the sound
document.getElementById('kohoutAudio').play();
document.getElementById('kohoutAudio').pause();
});
function announceChange(){
document.getElementById('kohoutAudio').play();
};
It happened to me too. Here's how I hacked this:
I set the audio to autoplay and set the vol to 0.
When I need it to play, I use the load() method and it will autoplay.
It's a light mp3 file and it plays every one hour/two hour, so this works fine for me.
I am trying to limit subjects to play an audio file only once in my experiment. I am using the following html code:
<audio src="sound.mp3" type="audio/mp3" preload="auto" controls="controls" oncontextmenu="return false;">Audio could not be loaded.</audio>
Is there a way to do it using html? If not how can I adapt this to javascript?
Thank you!
It depends on what your rules are for "play an audio file only once": is when the user hits the play button or is it after the user listens to the entire track?
You cannot disable the native audio controls while still having them visible. If you want the ability to manipulate audio controls, you will need to use your own controls using JS, HTML, and CSS. There are libraries out there for this already.
Also, if you are kind, you should give the user the ability to stop the audio after she hits play.
Here's what I would do:
use a plugin to add your own player controls
only show the play / stop button
write javascript that marks the file as "played" when...
the player hits the stop button, or
when the end of the song is reached
Once the audio is considered "played", disable the play button
The way I would do this is put the audio in a div called audioDiv
<div id="audioDiv">
<audio onclick="playedOnce()" src="sound.mp3" type="audio/mp3" preload="auto" controls="controls" oncontextmenu="return false;">Audio could not be loaded.</audio>
</div>
and then add this javascript method somewhere
function playedOnce(){
var children = document.getElementById("audioDiv").getElementsByTagName('*');
for(var i = 0; i < children.length; i++){
children[i].disabled = true;
}
}
Now obviously this is a shell method that assumes you only have one audio, so perhaps your javascript method takes in a parameter to determine which one to disable etc.
Additionally, this is assuming the user doesn't simply refresh the page. If you want to keep it hidden despite the user refreshing the page, I would look into PHP sessions!
Hope this helps!
I'm a radio presenter and have an mp3 stream of my broadcasts set up to autoplay on my website (I know, I know, just humour me). Using the HTML5 audio tag, I want the audio to autoplay the first time someone visits my site.
However, I want them to be able to check a checkbox with the result that the audio never autoplays for them again unless they uncheck the checkbox.
This checkbox should appear just under the audio player and change the autoplay tag from "true" to "false".
I've seen plugins that will stop autoplay, but can't find any code online to offer the option myself, which just goes to show how many people use autoplay indiscriminately. I would never dream of using it without offering a disable option.
Following some quick research I have put together the following code, but as I am a n00b coder I can't make it work. Where am I going wrong and what is the most elegant solution?
function check(that){
if(that.value === "disable-autoplay"){
if((this).is(':checked')){
autoplay="no"('checked');
}
}else {
autoplay="autoplay"('unchecked');
}
}
<audio controls autoplay="true"><source src="stream.mp3" type="audio/mp3"></audio>
<input type="checkbox" name="disable-autoplay" value="disable-autoplay" onchange="check(this)" />
From the MDN
autoplay:
A Boolean attribute; if specified (even if the value is "false"!), the audio will automatically begin playback as soon as it can do so, without waiting for the entire audio file to finish downloading
First thing is don't assign any autoplay at all in your HTML
<audio id="myAudio" controls>
<source src="song.ogg" type="audio/ogg">
<source src="song.mp3" type="audio/mpeg">
</audio>
Create the checkbox with some selector like id also don't assign event handler in the attribute
<input type="checkbox" name="disableAutoplay" id="disableAutoplay" />
Now i suppose you want the preference to persist entire site so even if user refreshes /navigates around your site, his preference should stay, for that use cookies or browser storage.
I think using local storage would be better due to its simplicity
localStorage.setItem('disableAP','yes'); //saving
disableAutoplay = localStorage.getItem('disableAP');//retriing
see how simple it is.
Now whenever page loads just check user pref. from above variable in storage and accordingly enable/disable autoplay property of the audio and check/uncheck the checkbox
now comes the most important part : the load() method
The load() method is used to update the audio/video element after changing the source or other settings.
load() function is the heart of this code it refreshes your audio element with newly assigned config. but without actually refreshing the page or editing HTML physically so in essence it gives you the effect of dynamic markup.
see how load() is being used below in check() function
var chkAutoPlay = document.getElementById('disableAutoplay');
var myAudio = document.getElementById('myAudio');
function check(that){
if (that.checked) //checkbox is checked
{
myAudio.autoplay=false;
localStorage.setItem('disableAP','yes');
} else { //checkbox is not checked
myAudio.autoplay=true;
localStorage.setItem('disableAP','no');
myAudio.load();
}
}
finally assign event handler for checkbox
document.getElementById('disableAutoplay').onchange=check;
Demo: https://jsfiddle.net/sanddune/oz0nhv2k/
I need to detect only the clicks that don't fire any action. See example below.
http://jsfiddle.net/SdNL5/1/
<video id="video" width="320" height="240" src="http://vjs.zencdn.net/v/oceans.mp4" controls>
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
var video = document.getElementById("video");
video.onclick = function(){
alert("This click is useless");
};
In that case when the user clicks the video he receives an alert message. BUT, problem is, I don't want the alert message to show up when the user clicks play button, pause button or volume control. I want it to show up only when the user clicks the video but not any button. Also I need to open a popup window after that so, I can't use setTimeout or similar in order for the browsers not to block the popup.
I'm aware that I can read coordinates and calculate whether there is a button or not, but I would prefer another solution.
I asked a question which is very similar to this one.(How to prevent event bubbling when clicking on HTML5 video controls in Firefox)
The only way I know to do that consistently in different browsers is to have an overlay over the video and then custom controls over that overlay.
There are several reasons why. For example 'useless' clicks will depend on the browser:
Firefox will toggle play/pause when clicking on the video.
IE will have a 'useless' click but on double click will go into
full-screen.
Chrome & Safari will have 'useless' clicks
BUT if you don't care about Firefox then this example would work for you but only in Chrome, Safari & IE : http://jsfiddle.net/me2loveit2/cSTGM/40/
<a href="javascript: alert('Nothing');">
<video ...
</video>
</a>
in this example im using setTimeout to let .paused, .volume And .muted to Be updated before I compare them with the last status (in the Variables).
var video = document.getElementById("video");
var isPaused = video.paused;
var lastVolume = video.volume;
var isMute = video.muted;
video.onclick = function(){
setTimeout(function() {
// if the user did not change: Play/Pause && Volume && mute
if(isPaused == video.paused && lastVolume == video.volume && isMute == video.muted) {
alert("This click is useless");
} else {
// if the user did change, update to current status
isPaused = video.paused;
lastVolume = video.volume;
isMute = video.muted;
}
}, 100);
}
demo: http://jsfiddle.net/SdNL5/22/
note: if the user click on volume control and did not make change, It will be considered as 'useless' click.
i know you already checked an answer, but please consider that you can still hide the default video controls and use your custom controls to play with.
if you don't want/have time to spend on it yourself you can just use some javascript lib like videojs
this way you'll have really full control both over buttons and video separately in a cross-browser way.
http://www.w3.org/2010/05/video/mediaevents.html
http://msdn.microsoft.com/en-us/library/ie/hh924822(v=vs.85).aspx
I'm trying to get audio to work outside the app (I'm using the HTML5, Javascript approach) in Windows 8, so when you close the app the sound continues to work, from what I have researched on here and on other sites and I believe this is called in Windows 8 'background audio, I've followed all the tutorials on Microsoft Developer site, and have declared background audio in the app manifest as so:
<Extension Category="windows.backgroundTasks" StartPage="default.html">
<BackgroundTasks>
<Task Type="audio" />
<Task Type="controlChannel" />
</BackgroundTasks>
</Extension>
and where I have added the msAudioCategory="BackgroundCapableMedia" controls="controls" to my HTML5 audio tag as so:
<audio id="playback" msAudioCategory="BackgroundCapableMedia" controls="controls">
</audio>
and I've also added this to my default.js file which was apprently needed, although I'm not sure what this does
// Declare a variable that you will use as an instance of an object
var mediaControls;
// Assign the button object to mediaControls
mediaControls = Windows.Media.MediaControl;
// Add an event listener for the Play, Pause Play/Pause toggle button
mediaControls.addEventListener("playpausetogglepressed", playpausetoggle, false);
mediaControls.addEventListener("playpressed", playbutton, false);
mediaControls.addEventListener("pausepressed", pausebutton, false);
// The event handler for the play/pause button
function playpausetoggle() {
if (mediaControls.isPlaying === true) {
document.getElementById("playback").pause();
} else {
document.getElementById("playback").play();
}
}
// The event handler for the pause button
function pausebutton() {
document.getElementById("playback").pause();
}
// The event handler for the play button
function playbutton() {
document.getElementById("playback").play();
}
I have also tried changing the ID in the last part to have a hash tag as well but still when I press the start button to go back home the audio stops, am I doing something wrong?
Thanks
I believe you also need to handle the "stoppressed" event:
mediaControls.addEventListener("stoppressed", stop, false);
function stop() {
// Handle the stop event.
document.getElementById("playback").pause();
document.getElementById("playback").currentTime = 0;
}
The three steps for playing background audio in Windows 8 JavaScript apps are:
Decalare an audio background task in package.appxmanifest. Also list a StartPage. You did this correctly.
Set msAudioCategory="BackgroundCapableMedia". You did this.
Implement support for media controls. Media controls are buttons on remote controls or on certain keyboards that play, pause, or stop audio. See the Configure keys for media sample on MSDN for a working example. I was able to get the example to work when only handling "stoppressed" in addition to the 3 events you were already handling.
For more information, watch Your Metro style app, video and audio, part 2 from the 2011 Build conference. Background audio is covered beginning at around 31 minutes, 20 seconds into the video and lasts for about 10 minutes. Note that this video is from September, 2011, and covers the Developer Preview of Windows 8. The concepts still apply to the released versions of Windows 8 and Windows RT, but namespaces and attribute names are different in some places.