I have a webpage which has a continuous(ish) livestream playing on it, but I want users only to be able to see and hear it at specific, exact times. I don't want them to have to keep disconnecting and reconnecting as this takes an unpredictable amount of time.
When the user loads the page, the livestream will autostart (muted and hidden - see below) and the user will have to unmute the video (even though they can't see it yet), but I don't want them to actually hear the livestream until the allocated time. I don't want them to have to manually unmute the video at the allocated times - My goal is to have everyone connected and stable so that (for example) at 10:04:30 precisely everyone can see and hear the livestream for 30 seconds, then it disappears (and mutes) until the next time at (say) 10:07:15 and so on. The process should happen in a way that allows the user to sit back in their armchair and not have to use their mouse or keyboard after the inital page load and unmuting of the livestream.
Dealing with the video side is easy - I can just show/hide a div with a black background that covers the video, but I'm not sure how to deal with the audio side of things. Is it possible to mute/unmute the webpage as a whole? Are there other ways to achieve this goal?
Another possible perspective is to have this done at the source somehow, by having the publisher connect and start publishing, but send blank video/audio until the right time, then switch over what is being sent. Again this needs to be done without the publisher having to keep reconnecting or do anything manually.
The publisher and viewers are all connecting using WebRTC.
Assuming something like the following:
<video id="vid" ...></video>
<div id="controls" ...>
<button id="mute-btn">Mute</button>
</div>
Then you need something like this:
const vid = document.querySelector('#vid')
const muteBtn = document.querySelector('#mute-btn')
vid.muted = true
window.userHasUnmuted = false
window.liveStreamStarted = false
muteBtn.addEventListener('click', () => {
window.userHasUnmuted = true
if (window.liveStreamStarted) {
vid.muted = false
}
}
// then, in callback for whenever live-stream starts...
if (window.userHasUnmuted) {
vid.muted = false
}
Original answer below
To mute a single audio or video element:
audioOrVideoElement.muted = true
To mute all audio or video elements on a page:
document.querySelectorAll('audio, video').forEach(el => el.muted = true)
Conversely, setting muted to false re-enables sound from that element.
For finer-tuned audio controls, you can also set the element's volume (in the range 0..1), for example:
document.querySelectorAll('audio, video').forEach(el => el.volume = 0.3)
Related
I have a javascript code that checks whether there are some people connected to a room in Twilio Programmable Video. If there are any participants, the javascript adds their remote video to the webpage.
// A function that adds a remote participant audio & video to the current web page.
function AddParticipantAudioAndVideo(participant) {
participant.tracks.forEach(publication => {
if (publication.track) {
document.getElementById("some html item").appendChild(track.attach());
console.log("track subscribed");
}
});
participant.on('trackSubscribed', track => {
document.getElementById("some html item").appendChild(track.attach());
console.log('track subscribed');
});
}
function InitializeRoom() {
// room is defined somewhere else
room.on('participantConnected', participant => {
console.log('A remote Participant connected : ' + participant.identity);
AddParticipantAudioAndVideo(participant);
});
// Loop over all the participants already connected to the room
room.participants.forEach(participant => {AddParticipantAudioAndVideo(participant)});
}
If I call this code from a button click for example, it works and live video plays properly :
<div onclick="InitializeRoom()">My Button</div>
However if I call the exact same code from the page load event handler (before any manual interaction with the page), it doesn't work and the video tag is not added to the html document.
window.addEventListener("load",function(event){
InitializeRoom();
});
I know that Chrome doesn't like videos with audio and autoplay = true. So I was wondering if this problem is due to the same reason and if there is any solution to that.
Thanks
Cheers,
I know that Chrome doesn't like videos with audio and autoplay = true. So I was wondering if this problem is due to the same reason and if there is any solution to that.
Yes, exactly.
Based on your other questions, I assume you're wanting to do this in some automated context where you have control over the browser. If so, you can add a flag to the Chrome/Chromium command line:
chrome.exe --autoplay-policy=no-user-gesture-required
See also: https://developer.chrome.com/blog/autoplay/#developer-switches
I am trying to detect when a user mutes/unmutes or changes the volume of a html video so the next time a page with a video is loaded the previous audio settings can be applied. I have been able to set the video's mute state using $('video').prop('muted', sessionStorage.getItem('is-muted')); but I am unsure how to detect when the user changes the mute state so I can store it for the next time a page is loaded. For example:
// This never fires
$('video').on('change', function () {
sessionStorage.setItem('is-muted', $(this).prop('muted'));
});
How can I detect when the video mute/volume level is changed so I can persist it in storage?
You can use volumechange event and check prop.
const video = $('video');
video.on('volumechange', (e) => {
// check video.prop('muted');
});
There is a W3Schools.com page which gives an example of getting and setting audio and video volume with the DOM volume property.
in traditional JavaScript:
var vid = document.getElementById("myVideo");
vid.volume = 0.2;
To convert that to jQuery parlance in your case:
$('video').volume = 0.2;
If you have a look at the HTML 5.2 specification from W3C, specifically at the part about Effective Media Volume, it appears that a user can override media volume with their user-agent:
If the user has indicated that the user agent is to override the volume of the element, then the element’s effective media volume is the volume desired by the user. Abort these steps.
As well as many other possibly helpful HTML5 media properties.
Right now I have a very basic HTML5 Audio player that play from webradio.
I use a old iPad to play the music but also to show some information from a webpage. The problem is that is happen sometime the wifi and the old iPad does not like to stay connect so it disconnect and reconnect and then the player stop play the webradio. I need somehow a script that notice in real time or every 1 min if the radio is not running and restart the player for me. I guess I can use Javascript but have search a Little and not find any good idea and it also have to work in Chrome. It looks that some javaScript does not work in specific webbrowser
Basically, your <audio> element will dispatch an error event. Just listen for that and then retry. You could also listen to the progress event to see when it starts receiving again and then call play from there. It'd be something roughly like this:
const audio = getAudioElement();
audio.addEventListener('error', () => { playing = false; /* handle error */ });
audio.addEventListener('progress', () => {
if (!playing) {
audio.play();
playing = true;
}
});
I'm currently using VideoJS in a Rails application (where there is a video player on every page) to display videos and I'm encountering a very strange problem:
The player works perfectly fine on the first page I visit but if I play the video and visit another page, the video from the first page keeps playing in the background even though the page isn't open anymore (you can hear the audio) and the video on the page you visited doesn't initialize properly (options aren't applied which means the video can't be played because controls are an option) and the console reads VIDEOJS: WARN: Player "player" is already initialised. Options will not be applied.
How to I get VideoJS to unload itself when the user leaves the page and why does it keep playing in the first place, the HTML5 video player didn't do that before.
Is the best way around this to get VideoJS to reload itself manually on page load? If so, how can that be done?
Note: If I navigate to any other page within the website the videos continue to not initialize, but if I reload the page, any page, the video on said page works again.
Note 2: Turns out that the onbeforeunload javascript event doesn't even fire if I click a link to another page, it only fires if you're going to a whole different website, so I can't even use that to .dispose() VideoJS on page unload.
Note 3: .reset() doesn't seem to be working either.
You can check to see if the player already exists and unload it, then reload it.
I was actually able to figure out a fairly simple and elegant solution:
if (player) {player.dispose()} else {var player}
player = videojs('player', {
//options
});
First it checks to see if the player exists. If it does, it destroys the VideoJS instance. If it doesn't, it creates the variable. Then it initializes the player.
By Referring this issue : https://github.com/videojs/video.js/issues/2904
We can re-write the above solution to something like this:
const playerId = 'video-player';
const videoOptions = {
controls: true,
sources: [{
src: 'test-file.mp4',
type: 'video/mp4',
}]
};
let player;
let players = videojs.players;
const imaOptions = { adTagUrl };
if (players && Object.keys(players).length) {
player = players[playerId];
player.dispose();
}
player = videojs(playerId,videoOptions);
player.ima(imaOptions);
I found this one to be the solution:
var oldPlayer = document.getElementById('my-player');
videojs(oldPlayer).dispose();
it's in the docs actually
I'm having a problem preloading HTML5 audio content and then using what I have in cache rather than attempting to redownload the audio every time I try to replay it.
http://cs.sandbox.millennialmedia.com/~tkirchner/rich/K/kungFuPanda2_tj/
The experience is suppose to be that when someone clicks on the banner, it pops up an ad with a loading bar. THe loading bar is loading all the images necessary for the animation. In the meantime, the audio is also getting loaded via audio tags already on in the DOM (which is fine). After all the images are loaded, the loading bar disappears and the user can continue on. There are 4 buttons on the bottom of the screen that they can click. Clicking one of them plays the audio file and images do a flipbook-style animation thats synced to the audio.
Audio Tags:
<audio id="mmviperTrack" src='tigress.mp3'></audio>
<audio id="mmmantisTrack" src='viper.mp3'></audio>
<audio id="mmtigressTrack" src='kungfu3.mp3'></audio>
<audio id="mmcraneTrack" src='crane.wav'></audio>
Play Button Event Listeners:
button.addEventListener('click',function(){
if ( f.playing ) return false;
f.playing = true;
button.audio.play();
},false);
button.audio.addEventListener('playing', function(){
animate();
}, false);
The problem is, in javascript, everytime I click play(), it reloads the audio file and then plays it. I can't seem to get it to load the audio once in the beginning and go off of whats stored in memory rather than try to reload the audio every single time I click the button.
I've tried experimenting with the preload and autobuffer properties, but it seems that mobile safari ignores those properties, because no matter what I set them too, the behavior is always the same. I've tried experimenting with source tags and different file formats... nothing.
Any ideas?
Alright, so the solution was a bit of a hack, cheat, workaround, whatever you want to call it.
What I noticed is that if I hit the play button on an audio file that I just played, it doesn't reload itself. It could be because I paused the audio after it finished playing through, but I'm not 100% sure on that. In any case, what I did is I combined all 4 audio files into one large audio file (yay Audacity~!). Then, every time I hit one of the play buttons I would set the currentTime property of the audio object to whatever the starting point of that track and then play the track until it hit its ending point, and then pause it again. Mission accomplished! Loaded once in the beginning and never again for each play.
Not crazy about the idea that I had to combine all the different audio tracks, but hey it works.
Oh, also. To get the audio track to load and fire a "canplaythrough" event, I attached this function to a user click event:
var track;
function addHTMLAudio() {
track = document.createElement('audio');
track.id = 'mm_audio'
track.autoplay = false;
track.preload = false;
track.addEventListener('canplaythrough',function(){
track.removeEventListener('canplaythrough');
audioLoaded = true;
},false);
document.getElementById('body').appendChild(track);
track.src = f.trackURL;
track.play();
setTimeout(function(){ track.pause(); },1);
}
playButton.addEventListener('click',function(e){
if ( playStatus > 0 ) return;
playStatus = 1;
var myId = e.target.parentNode.id;
var myClip = findClip( myId );
myClip.state = 'active';
track.currentTime = myClip.tIndex.start;
track.play();
runAnimation(myClip);
},false);