Synchronize HTML5 audio and JavaScript - javascript

I am writing a simple game by JavaScript, in which sound should be parallel with JavaScript.
I am using setInterval and I should be sure if the sound is playing correct, without pauses and delays.
I think about it this way: user can start game, when audio is loaded.
How can I do it? Maybe you can advise me another way.

Have a look at JPlayer, you could load the audio track:
$("#jquery_jplayer_1").jPlayer({
ready: function () {
$(this).jPlayer("setMedia", {
mp3: "track.mp3"
});
}
});
And then when your game is ready to start playing call:
$("#jquery_jplayer_1").jPlayer("play", 0);
or if you want to check if the audio is playing:
if(event.jPlayer.status.currentTime > 0) {
//Game start
}

Related

jPlayer with Icecast stream: how to play stream from live position (not last position) after pause?

I have a website that plays an icecast stream with jPlayer.
I want the play button to always start the stream from the live position (like a radio) instead of picking the stream back up from the last position. Attempted behavior:
play plays the stream live > pause suspends / discards the stream / optionally stops downloading it > play plays the stream from live position / reloads the stream.
There is a way to monitor the current media position with $.jPlayer.event.timeupdate as mentioned in comment on this post, and use that to resume playing from the end of the stream.
Alternatively, there must be a way to discard the stream when pausing and then reloading it when hitting play again. I think it is what is happening on this jPlayer demo. But I don't know how to do that part:
The error event is used with a check for the URL_NOT_SET error type to jPlayer("setMedia",stream) back to the live-stream again and jPlayer("play") it.
I am new to javascript and can't make it work. I can't find another post of someone trying to do that. I tried with the "playhead" at 100 which does not start the stream at all.
Here is the code I am using:
<script type="text/javascript">
//<![CDATA[
$(document).ready(function(){
$("#jquery_jplayer_1").jPlayer({
ready: function () {
$(this).jPlayer("setMedia", {
mp3: "http://realbadradio.ddns.net:21000/mpd.mp3"
})
},
});
});
//]]>
</script>
Here the repo to my website for full code.
I finally found the solution thanks to this answer on a different question related to achieving autoplay in jPlayer.
SOLUTION
$(document).ready(function(){
const stream = {
// stream address
mp3: 'http://realbadradio.ddns.net:21000/mpd.mp3'
};
ready = false;
$("#jquery_jplayer_1").jPlayer({
ready: function () {
ready = true;
$(this).jPlayer("setMedia", stream);
},
pause: function() {
$(this).jPlayer("clearMedia");
},
error: function(event) {
if(ready && event.jPlayer.error.type === $.jPlayer.error.URL_NOT_SET) {
// Setup the media stream again and play it.
$(this).jPlayer("setMedia", stream).jPlayer("play");
}
},
keyEnabled: true,
preload: 'none',
});
});

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);
}

HTML5 audio - get time played of a sound object (howler.js)

Im playing some HTML5 audio using the Howler.js library.
Currently im able to determine the total length of the audio file with sound.duration(); however im not sure how to create a timer to show how much time that has been played.
I create a simple sound object like so:
var sound = new Howl({
src: ['sound.ogg', 'sound.mp3', 'sound.wav'],
autoplay: true,
loop: false,
volume: 1,
onload: function() {
var totalSoundDuration = sound.duration();
},
onplay: function(getSoundId) {
//sound playing
},
onend: function() {
//sound play finished
}
});
I can't seem to find any method within the library (?) to check for currentTime so I can update my timer function.
An alternative route could simply be to trigger/toggle a setInterval upon onplay: like:
var currentTimeTracker=setInterval(function () {myTimer()}, 1000);
function myTimer() {
timePlayed++;
$("#time" ).html(timePlayed);
}
Not sure if that would be a good approach? Any suggestions?
Howler.js ref:
https://github.com/goldfire/howler.js/tree/2.0#global-core-properties
According to http://goldfirestudios.com/blog/104/howler.js-Modern-Web-Audio-Javascript-Library sound.pos() should get the current position. The posmethod can get or set, depending on whether you pass through the optional position parameter.

Soundmanager2 mp3 player button preload next sound

I use Soundmanager2's mp3 player button to play mp3s links on my website. I used the following modifcation in-order to preload the next mp3 during playing the current mp3.
play: function() {
sm.load('basicMP3Sound'+(1*this._data.oLink.title)+1);
//mycode end
pl.removeClass(this._data.oLink,this._data.className);
this._data.className = pl.css.sPlaying;
pl.addClass(this._data.oLink,this._data.className);
},
In the above example you may notce that the title tag in this._data.oLink.title which I added it to the mp3 link to handle files order in simple way, for example:
/002001.mp3
However, I noticed that the next mp3 link does not preloaded during playing the current mp3. This is because the next mp3 does not being played contiousely or start played after finish playing its previous mp3. In other word, it takes some time or delay to be downloaded.
Is there something wrong in my code? or what are your suggestions?
Notice a life demo of this mp3 layer is found in this link
Edit: Approach to work with the SoundManager inline button player
In your setup params in mp3-player-button.js under config, where playNext : true|false is found (line 39), update it to look like this:
...
this.config = {
// configuration options
playNext: true, // stop after one sound, or play through list until end
autoPlay: false, // start playing the first sound right away
preloadNext : true // preload next sound when previous sound starts to play
};
...
Then, further down under the this.events object (line 96), modify the play function to preload the next sound:
...
this.events = {
// handlers for sound events as they're started/stopped/played
play: function() {
pl.removeClass(this._data.oLink,this._data.className);
this._data.className = pl.css.sPlaying;
pl.addClass(this._data.oLink,this._data.className);
if (pl.config.preloadNext) {
var nextLink = (pl.indexByURL[this._data.oLink.id]+1);
if (nextLink<pl.links.length) {
sm.load(nextLink)
}
}
},
...
In summary, when a song starts, we check to see if there's a next song; if there is, we pull its id from the array of sounds that was created when we instantiated SoundManager. In this case, SoundManager is sm, so we simply pass the id of our next song to the sm.load() function.
Here is a live demo: http://plnkr.co/edit/mpBkfDIrLNduMAWJjRfN.
Try this approach:
Using the onplay and onfinish events of the createSound method, you can chain a series files which delegate each other.
Explicitly telling firstSound: "when you start to play, preload the next sound, and when you finish playing, play that next sound"
JavaScript
var firstSound = soundManager.createSound({
id: 'firstSound',
url: 'path/to/your/firstSound.mp3'
});
var secondSound = soundManager.createSound({
id: 'secondSound',
url: 'path/to/your/secondSound.mp3'
});
// Kickoff first sound
firstSound.load();
// Define the chain of events
firstSound.play({
onplay: function () {
// When `firstSound` starts, preload `secondSound`
secondSound.load();
},
onfinish: function () {
// Repeat, with next sound
secondSound.play({...
})
}
});

Reference URL with JavaScript to play sound?

Im using soundcloud dot com to upload my sounds. i want to press a button within my mobile application and have that sound play.
So basically i want my sound to be referenced from the URL that I am given when the button is pressed by the user.
I need to do it with Javascript only. No HTML 5 please. Any help is greatly appreciated cause this is Xtremely frustrating. Any ideas? Thanks in advance.
It's pretty simple to get started really:
function playSound(url) {
var a = new Audio(url);
a.play();
}
Use that as whatever event handler you want for your application. Of course, I'd hope you'd want to do more than just play (for example, maybe pause would be good too?), but it's a start.
let sound = new Audio("http://sound.com/mySound.mp3");
//on play event:
sound.onplay = () => {
};
//on pause event:
sound.onpause = () => {
};
//on end event:
sound.onended = () => {
};
//play:
sound.play();
//pause:
sound.pause();
//stop:
sound.pause();
sound.currentTime = 0;
Use jPlayer to play sound using Javascript. This will take you a lot of time and frustration.
jplayer.org/
Here's what your code might look like with jPlayer. Note: You're not forced to use a skin with jPlayer because all it is is just an API to play audio.
Example code to play a video or audio on load.
$(function() { // executed when $(document).ready()
$("#jpId").jPlayer( {
ready: function () {
$(this).jPlayer("setMedia", {
m4v: "http://www.myDomain.com/myVideo.m4v" // Defines the m4v url
}).jPlayer("play"); // Attempts to Auto-Play the media
},
supplied: "m4v",
swfPath: "jPlayer/js"
});
});
http://jplayer.org/latest/developer-guide/

Categories

Resources