Autoplay doesn't work with my music playlist [duplicate] - javascript

This question already has answers here:
How to make audio autoplay on chrome
(23 answers)
Closed 2 years ago.
I want to play a music playlist on my web-page in the background, I'm using chrome I don't want the console and I want autoplay but, though I write autoplay, the audio is starting only with the play button of the console. That's what I write in the HTML:
<div id="music_list">
<audio controls autoplay></audio>
</div>
And in the Javascript
(function () {
// Playlist array
var files = [
"ms4/14_1.30.mp3",
"ms4/20_20.mp3",
"ms4/21_34.mp3"
];
// Current index of the files array
var i = 0;
// Get the audio element
var music_player = document.querySelector("#music_list audio");
// function for moving to next audio file
function next() {
// Check for last audio file in the playlist
if (i === files.length - 1) {
i = 0;
} else {
i++;
}
// Change the audio element source
music_player.src = files[i];
}
// Check if the player is slected
if (music_player === null) {
throw "Playlist Player does not exists ...";
} else {
// Start the player
music_player.src = files[i];
// Listen for the music ended event, to play the next audio file
music_player.addEventListener('ended', next, false)
}
})();
How can I fix that? I'm really new in HTML and JS and I'm stuck in this problem.

I got this problem 1 year ago. The problem is of the Internet Browser you using at, for example, in Google Chrome controls autoplay doesn't work, the problem is about the permission, security and privacity of the users.
I think there is some way to make it work in any Internet Browser but, "controls autoplay" doesn't work, just in some Internet Explorers.

Bug players consider autoplay a bad thing because ads. At the end you will be forced to click to play. Nowadays you can try adding muted property to the audio element alongside with autoplay, and remove it after ading the first src

This depends upon your browsers
Run your code in different browsers
and also try this javascript function
var mp3 = document.getElementByTagName("audio");
mp3.autoplay = true;
mp3.load();

Related

Create Seamless Loop of Audio - Web

I want to create a seamless loop of an audio file. But in all approaches I used so far, there was a noticeable gap between end & start.
This is what I tried so far:
First approach was to use the audio in the HTML and it loops but there is still a noticeable delay when going from the end of the track to the beginning.
<audio loop autoplay>
<source src="audio.mp3" type="audio/mpeg">
<audio>
Then I tried it from JavaScript with the same result:
let myAudio = new Audio(file);
myAudio.loop = true;
myAudio.play();
After that I tried this (according to this answer)
myAudio.addEventListener(
'timeupdate',
function() {
var buffer = .44;
if (this.currentTime > this.duration - buffer) {
this.currentTime = 0;
this.play();
}
},
false
);
I played around with the buffer but I only got it to reduce the gap but not leave it out entirely.
I turned to the library SeamlessLoop (GitHub) and got it to work to loop seamlessly in Chromium browsers (but not in the latest Safari. Didn't test in other browsers). Code I used for that:
let loop = new SeamlessLoop();
// My File is 58 Seconds long. Btw there aren't any gaps in the file.
loop.addUri(file, 58000, 'sound1');
loop.callback(soundsLoaded);
function soundsLoaded() {
let n = 1;
loop.start('sound' + n);
}
EDIT: I tried another approach: Looping it trough two different audio elements:
var current_player = "a";
var player_a = document.createElement("audio");
var player_b = document.createElement("audio");
player_a.src = "sounds/back_music.ogg";
player_b.src = player_a.src;
function loopIt(){
var player = null;
if(current_player == "a"){
player = player_b;
current_player = "b";
}
else{
player = player_a;
current_player = "a";
}
player.play();
/*
3104.897 is the length of the audio clip in milliseconds.
Received from player.duration.
This is a different file than the first one
*/
setTimeout(loopIt, 3104.897);
}
loopIt();
But as milliseconds in browsers are not consistent or granular enough this doesn't work too well but it does work much better than the normal "loop" property of the audio.
Can anyone guide me into the right direction to loop the audio seamlessly?
You can use the Web Audio API instead. There are a couple of caveats with this, but it will allow you to loop accurately down to the single sample level.
The caveats are that you have to load the entire file into memory. This may not be practical with large files. If the files are only a few seconds it should however not be any problem.
The second is that you have to write control buttons manually (if needed) as the API has a low-level approach. This means play, pause/stop, mute, volume etc. Scanning and possibly pausing can be a challenge of their own.
And lastly, not all browsers support Web Audio API - in this case you will have to fallback to the regular Audio API or even Flash, but if your target is modern browsers this should not be a major problem nowadays.
Example
This will load a 4 bar drum-loop and play without any gap when looped. The main steps are:
It loads the audio from a CORS enabled source (this is important, either use the same domain as your page or set up the external server to allow for cross-origin usage as Dropbox does for us in this example).
AudioContext then decodes the loaded file
The decoded file is used for the source node
The source node is connected to an output
Looping is enabled and the buffer is played from memory.
var actx = new (AudioContext || webkitAudioContext)(),
src = "https://dl.dropboxusercontent.com/s/fdcf2lwsa748qav/drum44.wav",
audioData, srcNode; // global so we can access them from handlers
// Load some audio (CORS need to be allowed or we won't be able to decode the data)
fetch(src, {mode: "cors"}).then(function(resp) {return resp.arrayBuffer()}).then(decode);
// Decode the audio file, then start the show
function decode(buffer) {
actx.decodeAudioData(buffer, playLoop);
}
// Sets up a new source node as needed as stopping will render current invalid
function playLoop(abuffer) {
if (!audioData) audioData = abuffer; // create a reference for control buttons
srcNode = actx.createBufferSource(); // create audio source
srcNode.buffer = abuffer; // use decoded buffer
srcNode.connect(actx.destination); // create output
srcNode.loop = true; // takes care of perfect looping
srcNode.start(); // play...
}
// Simple example control
document.querySelector("button").onclick = function() {
if (srcNode) {
srcNode.stop();
srcNode = null;
this.innerText = "Play";
} else {
playLoop(audioData);
this.innerText = "Stop";
}
};
<button>Stop</button>
There is a very simple solution for that, just use loopify it makes use of the html5 web audio api and works perfectly well with many formats, not only wav as the dev says.
<script src="loopify.js" type="text/javascript"></script>
<script>
loopify("yourfile.mp3|ogg|webm|flac",ready);
function ready(err,loop){
if (err) {
console.warn(err);
}
loop.play();
}
</script>
This will automatically play the file, if you want to have start and stop buttons for example take a look at his demo

How to determine if playing HTML5 audio is actually making sound?

For the purposes of a project I am working, I want to find out via the JS console if the <audio> tag found on facebook.com is playing audio or not. (I can then move this code into a Chrome extension and also apply it against other websites such as silent HTML5 ads.)
You can find the element by typing:
$$("audio")[0]
I have used the following code (adapted from this jsfiddle which I found during a search) to show when different event listeners are called:
var audio = $$("audio")[0];
var events = 'abort,canplay,canplaythrough,durationchange,emptied,ended,error,loadeddata,loadedmetadata,loadstart,pause,play,playing,progress,ratechange,seeked,seeking,stalled,suspend,timeupdate,volumechange,waiting'.split(',');
// event handler
var onEvent = function(e) {
console.log(e.type);
};
// add event listener to audio for all events
for (var i = 0, len = events.length; i < len; i++) {
audio.addEventListener(events[i], onEvent, false);
}
I would then play the audio by typing:
$$("audio")[0].play();
If I check $$("audio")[0].paused, it will show false, but I haven't found any properties or events that would indicate whether it played sound or not. (I wouldn't expect it to here since I don't think it has audio data to play, but if there was a way to check, I could compare that with an audio element that does play sound.)
Also, I have tried sending myself a message from an incognito tab and don't see a trace of this happening. (I assume the audio element gets used for that.)
Help is appreciated.
To check if an HTMLMediaElement (either video or audio) has ever been played on the page, the best solution is to check for its played attribute.
This will return a TimeRanges object that you can as well use to get how much of the media has been played.
If it has never been played, then the length property of this TimeRanges object will be set to 0 :
if(audioElement.played.length){
// This media has already been played
}else{
// Never
}

Use javascript to detect if an MP4 video has a sound track

I am creating a custom controller for MP4 video on a web page. The controller includes a volume slider. Some of the videos that are to be played have no sound track. It would be good to disable the volume slider for these videos, so that the user is not confused when changing the position of the volume slider has no effect.
Is there a property or a trick for checking if an MP4 file has an audio track? (jQuery is an option).
Edit: using #dandavis's suggestion, I now have this solution for Chrome (and .ogg on Opera):
var video = document.getElementById("video")
var volume = document.getElementById("volume-slider")
function initializeVolume() {
var enableVolume = true
var delay = 1
if (video.webkitAudioDecodedByteCount !== undefined) {
// On Chrome, we can check if there is audio. Disable the volume
// control by default, and reenable it as soon as a non-zero value
// for webkitAudioDecodedByteCount is detected.
enableVolume = false
startTimeout()
function startTimeout () {
if (!!video.webkitAudioDecodedByteCount) {
enableVolume = true
toggleVolumeEnabled(enableVolume)
} else {
// Keep trying for 2 seconds
if (delay < 2048) {
setTimeout(startTimeout, delay)
delay = delay * 2
}
}
}
}
toggleVolumeEnabled(enableVolume)
}
function toggleVolumeEnabled(enableVolume) {
volume.disabled = !enableVolume
}
The video.webkitAudioDecodedByteCount value is initially 0. In my tests, it may take up to 256ms to get populated with a non-zero value, so I have included a timeout to keep checking (for a while).
There might be a better way of doing this, although it's fairly simple just using regular javascript for webkit or mozilla enabled browsers. webkit utilizes this.audioTracks and mozilla uses this.mozHasAudio respectively:
document.getElementById("video").addEventListener("loadeddata", function() {
if ('WebkitAppearance' in document.documentElement.style)
var hasAudioTrack = this.audioTracks.length;
else if (this.mozHasAudio)
var hasAudioTrack = 1;
if (hasAudioTrack > 0)
alert("audio track detected");
else
alert("audio track not detected");
});
<video id="video" width="320" height="240" controls>
<source src="http://media.w3.org/2010/05/video/movie_300.mp4" type="video/mp4">
</video>
There's also a function this.webkitAudioDecodedByteCount, however, I've never had any luck making it work.
There are different ways to check whether a video file has audio or not, one of which is to use mozHasAudio, video.webkitAudioDecodedByteCount and video.audioTracks?.length properties of video, clean and simple...

HTML 5 audio .play() delay on mobile

I just built a real-time app using socket.io where a "master" user can trigger sounds on receiving devices (desktop browsers, mobile browsers). That master user sees a list of sound files, and can click "Play" on a sound file.
The audio playback is instant on browsers. On mobiles however, there is a 0.5-2 seconds delay (my Nexus 4 and iPhone 5 about 1 second and iPhone 3GS 1-2 seconds).
I've tried several things to optimize the audio playback to make it faster on mobiles. Right now (at the best "phase" of its optimization I'd say), I combine all the mp3's together in one audio file (it creates .mp3, .ogg, and .mp4 files). I need ideas on how I can further fix / improve this issue. The bottleneck really seems to be in the hmtl 5 audio methods such as .play().
On the receivers I use as such:
<audio id="audioFile" preload="auto">
<source src="/output.m4a" type="audio/mp4"/>
<source src="/output.mp3" type="audio/mpeg"/>
<source src="/output.ogg" type="audio/ogg"/>
<p>Your browser does not support HTML5 audio.</p>
</audio>
In my JS:
var audioFile = document.getElementById('audioFile');
// Little hack for mobile, as only a user generated click will enable us to play the sounds
$('#prepareAudioBtn').on('click', function () {
$(this).hide();
audioFile.play();
audioFile.pause();
audioFile.currentTime = 0;
});
// Master user triggered a sound sprite to play
socket.on('playAudio', function (audioClip) {
if (audioFile.paused)
audioFile.play();
audioFile.currentTime = audioClip.startTime;
// checks every 750ms to pause the clip if the endTime has been reached.
// There is a second of "silence" between each sound sprite so the pause is sure to happen at a correct time.
timeListener(audioClip.endTime);
});
function timeListener(clipEndTime) {
this.clear = function () {
clearInterval(interval);
interval = null;
};
if (interval !== null) {
this.clear();
}
interval = setInterval(function () {
if (audioFile.currentTime >= clipEndTime) {
audioFile.pause();
this.clear();
}
}, 750);
}
Also considered blob for each sound but some sounds can go for minutes so that's why I resorted to combining all sounds together for 1 big audio file (better than several audio tags on the page for each clip)
Instead of pausing / playing, I simply set the volume to 0 when it shouldn't be playing, and back to 1 when it should be playing. The Audio methods currentTime and volume don't slow the audio playback at all even on an iPhone 3GS.
I also added the 'loop' attribute to the audio element so it never has to be .play()'ed again.
It was fruitful to combine all mp3 sounds together because this solutions can work because of that.
Edit: audioElement.muted = true or audioElement.muted = false makes more sense.
Edit2: Can't control volume on user's behalf on iOS so I must pause() and play() the audio element as opposed to just muting and unmuting it.
Your setup is working well on desktop because of the preload attribute.
Unfortunately, here's Apple on the subject of preload:
Safari on iOS never preloads.
And here's MDN:
Note: This value is often ignored on mobile platforms.
The mobile platforms are making a tradeoff to save battery and data usage to only load media when it's actually interacted with by the user or programmatically played (autoplay generally doesn't work for similar reasons).
I think the best you're going to do is combining your tracks together, as you said you've done, so you don't have to pay the initial load-up "cost" as much.
I was having the same delay issue when testing in mobile. I found out what some HTML 5 games are using for audio since games demand very low latencies. Some are using SoundJS. I recommend you try that library out.
You can find a speed comparison between using the HTML Audio tag vs using SoundJS here:
http://www.nickfrazier.com/javascript/audio/ui/2016/08/14/js-sound-libraries.html
(test in mobile to hear the difference)
From my tests SoundJS is much faster.
In fact, it's Good enough to be used in a game, or for sound feedback in a user interface.
Old question but here is my solution using one of the answer above:
const el = document.createElement("audio");
el.muted = true;
el.loop = true;
const source = document.createElement("source");
source.src = lineSe;
source.type = "audio/mpeg";
el.appendChild(source);
// need to call this function after user first interaction, or safari won't do it.
function firstPlay() {
el.play();
}
let timeout = null;
function play() {
// In case user press the button too fast, cancel last timeout
if (lineSeTimeout) {
clearTimeout(timeout);
}
// Back to beginning
el.currentTime = 0;
// unmute
el.muted = false;
// set to mute after the audio finish. In my case 500ms later
// onended event won't work because loop=tue
timeout = setTimeout(() => {
// mute audio again
el.muted = true;
}, 500);
}

JS .play() on iPad plays wrong file...suggestions?

So, I am building a web app that has a div with text that changes on various user actions (it's stepping through an array of pieces of text). I'm trying to add audio to it, so I made another array with the sound files in the appropriate positions:
var phrases=['Please hand me the awl.','etc1','etc2','etc3'];
var phrasesAudio=['awl.mp3','etc1.mp3','etc2.mp3','etc3.mp3'];
And on each action completion, a 'counter' variable in incremented, and each array looks for the object at that counter
var audio = document.createElement("audio"),
canPlayMP3 = (typeof audio.canPlayType === "function" &&
audio.canPlayType("audio/mpeg") !== "");
function onAction(){
correct++;
document.getElementById('speech').innerHTML=phrases[correct];
if(canPlayMP3){
snd = new Audio(phrasesAudio[correct]);
}
else{
snd = new Audio(phrasesAudioOgg[correct]);
}
snd.play();
}
(the text replaces a div's HTML and I use .play() for the audio object)...usually works okay (and ALWAYS does in a 'real' browser), but on the iPad (the actual target device) after a few successful iterations, the TEXT continues to progress accurately, but the AUDIO will hiccup and repeat a sound file one or more times. I added some logging and looking there it reports that it's playing screw.mp3 (just an example, no particular file is more or less error prone), but in actuality it plays screwdriver.mp3 (the prior file, if there is an error, the audio always LAGS, never LEADS)...because of this I am thinking that the problem is with my use of .play()...so I tried setting snd=null; between each sound, but nothing changed...Any suggestions for how to proceed? This is my first use of audio elements so any advice is appreciated. Thanks.
edit: I've also tried setting the files with snd.src (based on https://wiki.mozilla.org/Audio_Data_API) and this caused no audio to play
for iPad you need to call snd.load() before snd.play() - otherwise you get "odd" behaviour...
see for some insight:
http://jnjnjn.com/187/playing-audio-on-the-ipad-with-html5-and-javascript/
Autoplay audio files on an iPad with HTML5
EDIT - as per comment from the OP:
Here https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox you can find a tip on halting a currently playing piece of media with
var mediaElement = document.getElementById("myMediaElementID");
mediaElement.pause();
mediaElement.src = "";
and, following that with setting the correct src, load(), play() works great

Categories

Resources