I have a error which is
Error showing is :
Uncaught DOMException: play() failed because the user didn't interact with the document first.
The error does not prevent function to run but it should not be shown as some of the question in SO , Chrome , Mozilla documentation states that audio or video which are muted are not blocked from playing.
So there must be something I am doing wrong . Can you tell that or any way to remove the error.
I have muted the audio at first hand then why it is still showing up . As function is running every second so error is also showing up every second .
The error stop showing up when I click the start btn which plays the audio .
Is there any way to remove this error :
var start = document.getElementById("triggerSnd")
var audioElement = document.getElementById('audiotag1')
var demo = document.getElementById('demo')
var interval, isMuted = true
clockRunner();
clock();
setInterval(() => clock(), 1000)
start.addEventListener('click', clockRunner)
function clockRunner() {
audioElement.muted = isMuted
start.innerText = isMuted ? "Start" : "Stop"
isMuted = !isMuted
}
function clock(isMuted) {
//Clock code goes here , here only used a simple timer
demo.innerText = new Date();
audioElement.play();
}
<audio id="audiotag1" src="https://soundbible.com/mp3/Tick-DeepFrozenApps-397275646.mp3" preload="metadata"></audio>
<button id="triggerSnd">Start</button>
<div id="demo"></div>
It is not showing up in above snippet but can seen in console of VS code(Using it, so can tell about it) every second
Thanks for help in advance
Related
I have function running every second (for clock) .
I wanted to add sound to every tick tick....(second) but as function is running automatic (means no triggering is taking place) and when sound added produces an error
Error showing is :
Uncaught DOMException: play() failed because the user didn't interact with the document first.
Know that it is not possible to play audio automatic .
So tried to create a start sound btn which play the audio but as second time (of clock) and don't match with audio . So there is a mismatch
I am trying to add that function(audio play) inside second(clock time) calculator .
Is this possible or not
Link to similar question but not able to find the solution
The code is as follows
setInterval(clockRunner, 1000);
function clockRunner() {
//Clock code goes here
function trigger() {
var audioElement = document.getElementById('audiotag1');
audioElement.play();
}
}
<audio id="audiotag1" src="https://soundbible.com/mp3/Tick-DeepFrozenApps-397275646.mp3" preload="metadata" controls></audio>
<button onclick="trigger()">Start</button>
Update
Added event listener inside the outer function but this way sound is playing once not every second .
One solution here can be adding another setInterval but this will again create problem of playing sound at different timing of clock's second
Also it shows the same error in the console(mentioned above) until user clicks the btn
setInterval(clockRunner, 1000);
function clockRunner() {
//Clock code goes here
document.getElementById('demo').innerHTML = new Date();
setInterval(trigger, 1000);
document.getElementById("triggerSnd").addEventListener('click', trigger)
function trigger() {
var audioElement = document.getElementById('audiotag1');
audioElement.play();
}
}
<audio id="audiotag1" src="https://soundbible.com/mp3/Tick-DeepFrozenApps-397275646.mp3" preload="metadata" controls></audio>
<button id="triggerSnd">Start</button>
<div id="demo"></div>
Thanks for help in advance
If you make use of some variables, you can control your code to perform like a clock. It's worth noting that there are two possibilities, either the clock has started or it has stopped.
The interval will run when you clicked to start and it will be cleared in stopping it. Here I can't notice any mismatch between the sound and the timer.
var start = document.getElementById("triggerSnd")
var audioElement = document.getElementById('audiotag1')
var demo = document.getElementById('demo')
var interval, isMuted = true
// The second argument of addEventListener should be a function
// that receives an argument 'event'
clockRunner();
clock(); // call firstly
setInterval(() => clock(), 1000)
start.addEventListener('click', clockRunner)
function clock(isMuted){
//Clock code goes here
demo.innerText = new Date();
audioElement.play();
}
function clockRunner() {
audioElement.muted = isMuted
start.innerText = isMuted ? "Start" : "Stop"
isMuted = !isMuted
}
<audio id="audiotag1" src="https://soundbible.com/mp3/Tick-DeepFrozenApps-397275646.mp3" preload="metadata"></audio>
<button id="triggerSnd">Start</button>
<div id="demo"></div>
I've changed my answer completely. Now I didn't need to use an event listener, just the proper API of HTMLMediaElement that audio uses. Note that I've add loop attribute to tick's audio.
var blast = document.getElementById("blast");
var tick = document.getElementById("tick");
var tickDuration, timeDiff, lastTime
tick.onloadedmetadata = () => tickDuration = tick.duration
timeDiff = 0.3 // max difference between sync, dont lower it or it will bug (can explain if u want)
lastTime = 0
blast.addEventListener("timeupdate", () => {
let bct = blast.currentTime
let tct = tick.currentTime
let syncBlastTime = tickDuration - (tickDuration - bct%tickDuration)
let diff = Math.abs(syncBlastTime - tct)
lastTime = bct
console.log(`Blast: ${bct} Tick: ${tct}\nSynced time difference (seconds): ${diff.toFixed(6)}`)
if(diff > timeDiff) { // add this or it will bug the tick audio
tick.currentTime = syncBlastTime
}
})
blast.addEventListener("pause", () => {
tick.pause()
})
blast.addEventListener("playing", () => {
tick.play()
})
<audio id="blast" src="http://stream.arrowcaz.nl/caz64kmp3" controls="loop"></audio>
<audio id="tick" src="https://soundbible.com/mp3/A-Z_Vocalized-Mike_Koenig-197996831.mp3" loop controls='loop'></audio>
<br />
I am trying to figure out how to play another track immediately after the first one has ended automatically and then the whole thing to loop again until the user presses pause.
var myAudio = document.getElementById("myAudio");
var isPlaying = false;
function togglePlay() {
isPlaying ? myAudio.pause() : myAudio.play();
};
myAudio.onplaying = function() {
isPlaying = true;
};
myAudio.onpause = function() {
isPlaying = false;
};
<audio id="myAudio" src="/sound/track.mp3" preload="auto" loop="true">
</audio>
<button id="play-pause"><a onClick="togglePlay()">PLAY/PAUSE SOUND</a></button>
Firstable don't write inline JavaScript, it has a lot of disadvantages, and since you want to change the song when the current ends, you should get rid of the loop attribute cause you don't want to keep playing just one song, and you don't need to track the playing state of the audio element, it has already a property audio.paused to tell if it's playing or not, and I see no reason to add an <a> tag inside the button element, here is an example of playing some songs from a playlist it's all dynamic, feel free to add the number of songs you desire
var myAudio = document.getElementById("myAudio"),
// a simple playing list
playingList = ["v1601656608/lambada_saxo_bxdmys", "v1601656600/coffin_dance_saxo_ze81hy", "v1601656611/mr_saxobeat_saxo_snh2di"],
currentSong = 0;
// set the initial song url to be the first song in the playlist
myAudio.src = `https://res.cloudinary.com/dzcscgx8y/video/upload/${playingList[0]}.mp3`;
document.querySelector("#play-pause").onclick = function() {
myAudio.paused ? myAudio.play() : myAudio.pause();
}
myAudio.onended = function() {
// change the src to be the url of the next song, if the song is the last one in the playlist then the next should be the first one
this.src = `https://res.cloudinary.com/dzcscgx8y/video/upload/${playingList[++currentSong === playingList.length ? 0 : currentSong]}.mp3`;
// the audio player stops after playing each song, so after changing the src just launch the player
this.play();
}
<audio id="myAudio" src="" preload="auto"></audio>
<button id="play-pause">PLAY/PAUSE SOUND</button>
I want to play a random song in a website. The tunes are short (max a few seconds, they don't need preload or buffering).
This part works, the number of songs may be unlimited, because tunes.length automatically counts all songs.
document.write displays the URL of a random song URL on the screen
tunes = new Array(
'"http://example.net/abcd.ogg"',
'"http://example.net/efgh.ogg"',
'"http://example.net/ijkl.ogg"'
)
var audiopath = (tunes[Math.floor(Math.random() * tunes.length)])
document.write (audiopath)
This part works too, when the URL is defined as a constant.
var song = new audio('http://example.net/abcd.ogg');
song.play();
When I try to replace the constant URL with the variable audiopath, it fails to play.
May it be anything wrong with the syntax?
I tried to run it with and without single quotes in the URL '"http://example.net/ijkl.ogg"' or "http://example.net/ijkl.ogg"
var song = new audio(audiopath);
song.play();
It might be better to handle starting playback once the song has fully loaded. Something like this:
let loaded = false;
const song = new Audio();
song.addEventListener('loadeddata', function()
{
loaded = true;
song.play();
}, false);
song.addEventListener('error' , function()
{
alert('error loading audio');
}, false);
song.src = tunes[Math.floor(Math.random() * tunes.length)];
I was trying to play a list of audio files on the same web page with only a text link as play button, and I found the following solution, which works really perfect for me:
(thanks #linstantnoodles for this script!)
<audio id="song1" preload='auto'>
<source src='song1.mp3' type='audio/mp3' />
</audio>
<audio id="song2" preload='auto'>
<source src='song2.mp3' type='audio/mp3' />
</audio>
Listen
Listen
<script type="text/javascript">
// List of audio/control pairs
var playlist = [{
"audio": document.getElementById('song1'),
"control": document.getElementById('song1-control')
}, {
"audio": document.getElementById('song2'),
"control": document.getElementById('song2-control')
}];
for (var i = 0; i < playlist.length; i++) {
var obj = playlist[i];
var audio = obj.audio;
var control = obj.control;
// returns a closure
var listener = function (control, audio) {
return function () {
var pause = control.innerHTML === 'Pause';
control.innerHTML = pause ? 'Listen' : 'Pause';
// Update the Audio
var method = pause ? 'pause' : 'play';
audio[method]();
// Prevent Default Action
return false;
}
};
control.addEventListener("click", listener(control, audio));
}
</script>
My only problem with this code is, that if one song is playing, and I start a second one, both are playing at the same time. I've tried many ways to get this problem fixed, but none of them did work - how do I need to adapt it, so that the first one pauses or stops when a second one starts? Thanks!
You can do something like this. When a new audio is started, loop through the playlist array to find all the audio elements that are not the one that just got started and stop them.
Here is an example:
....
var method = pause ? 'pause' : 'play';
audio[method]();
if(!pause){
playlist.forEach(function(pl){
if(pl.audio !== audio){
pl.audio.pause();
pl.audio.currentTime = 0;
pl.control.innerHTML = 'Listen';
}
});
}
....
Note: Exactly this has been asked before here, and here, without satisfactory answers.
I'll try to explain the problem better here, and you can also read TLDR below. Here's a simple fiddle I created using Soundcloud JS sdk v3. I define global variables playerGlobal and playingId. During the first play, both of them are null, and clicking one of play or playNext buttons initializes those variables. Suppose, we click play first, the related track starts playing. When we click pause button soon after, pause() fires and uses the globalPlayer to pause the currently playing track. This works as expected.
When I click playNext, both global variables are updated as they should. The problem arises when I click play again. For some strange reasons, the track associated with play button plays from time starting at when I clicked pause above. When I click pauseagain, nothing happens.
TLDR: Click play -> pause -> playNext(works fine till here) -> play(strange remembering of last position happens) -> pause(nothing happens).
I'm including the snippet here as well.
SC.initialize({
client_id: 'MmZKx4l7fDwXdlL3KJZBiJZ8fLonINga'
});
//Get player
function getPlayer(url) {
return new Promise(function(resolve, reject) {
SC.stream(url)
.then(player => {
if (player.options.protocols[0] === 'rtmp')
player.options.protocols.splice(0, 1);
resolve(player);
});
});
}
//Global players and id to track current playing track
var playerGlobal = null;
var playingId = null;
function play() {
var id = '1';
//Resume playing if the same song is hit
if (playerGlobal !== null && id === playingId) {
console.log("-- using old player");
playerGlobal.play();
return;
}
//New player on a new song
var url = '/tracks/309689093';
getPlayer(url)
.then(player => {
if (playerGlobal) playerGlobal = null;
playerGlobal = player;
console.log("-- new player created");
playerGlobal.play();
playingId = id;
});
}
function pause() {
playerGlobal.pause();
}
function playNext() {
var id = '2';
//Resume playing if the same song is hit
if (playerGlobal !== null && id === playingId) {
console.log("-- using old player");
playerGlobal.play();
return;
}
//New player on a new song
var url = "/tracks/309689082";
getPlayer(url)
.then(player => {
if (playerGlobal) playerGlobal = null;
playerGlobal = player;
console.log("-- new player created");
playerGlobal.play();
playingId = '2';
});
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<button onClick="play()">play</button>
<button onClick="pause()">pause</button>
<button onClick="playNext()">playNext</button>
<script src="https://connect.soundcloud.com/sdk/sdk-3.1.2.js"></script>
</body>
</html>
I'm not sure why this wouldn't work. One of the ways I was able to make this work was by defining separate player, pause and id variables for both tracks. And then when a track is played after another, I set seek to position 0. Here's it. The problem of course is, this is just for reference, my use case involves many more tracks, and I didn't want to define separate variables for them all, until I'm sure why above code doesn't work and that it is the only way. Any hints are appreciated.