RTS Game HTML5 Audio in Chrome MP3 and OGG Stutters and Stops - javascript

We're writting a Canvas demonstration Real Time Strategy (RTS) game in HTML5/JavaScript and have everything pretty much working. However, in Chrome (very latest version) the sound keeps stuttering and eventually just gives up. The code runs just fine in the latest Firefox, IE9 and Safari (though no sound at all on iOS4 iPhone/iPad but apparently that's a commercial decision by Apple). You can see for yourself on the link below just get more than a few sounds at once to cause the issue.
http://www.enterprisewarfare.com/Play.aspx
The simplified sound play code is below, note each sound exists 4 times (AUDIO_CHANELS_PER_FILE) to simulate more than one channel. Adjusting this number does not cause the sound loss any earlier or later so it is not to do with reaching the end of the array or playing the same audio object again. We've tried both OGG and MP3 file formats and everything works in IE9 (MP3) and Firefox (OGG) without issue. We've also tried seeking the file back to the begining to no avail.
this.PlaySound = function(sId)
{
var iSoundMapIndex;
var asoundChannels;
if(sId == null || sId.length == 0) return;
// Grab sound channels array
iSoundMapIndex = this.SoundMap[sId];
asoundChannels = this.Sounds[iSoundMapIndex];
if(asoundChannels == null)
{
this.World.AddMessage("Unable to find sound \"" + sId + "\".");
return;
}
// play the next in sequence
asoundChannels[this.SoundChannel[iSoundMapIndex]].volume = 1;
asoundChannels[this.SoundChannel[iSoundMapIndex]].play();
this.SoundChannel[iSoundMapIndex]++;
if(this.SoundChannel[iSoundMapIndex] == this.AUDIO_CHANNELS_PER_FILE) this.SoundChannel[iSoundMapIndex] = 0;
}

It seems like this is an issue with chrome and chromium. I'd suggest looking trough the bug reports and dev answers on them or just wait for it to be resolved and ignore the problem meanwhile.
It's a shame that no-one with more experience than me in javascript made any suggestions concerning a workaround. I've upvoted the question in the hope you'll find some help.

It turns out this was a bug in Chrome and It appears this has now been fixed. Still some issues with sound loading and more than one channel but the complete breakdown of sound seems to have been resolved.

Related

VideoJS - Safari 7.1, loading spinner does not go away on initial page load

I'm implementing a video player using VideoJS. Two key functions of this video player are:
a) If the user leaves the page, resume the video at that point when they come back or on refresh
b) Include HLS (h.264/mp4) support to provide better video quality depending on the connection.
The API for saving and retrieving a user's timestamp is already in place, and using the excellent HLS plugin, the video player works almost fine in all browsers as expected. The following code is used to initialize the player and jump to the saved time:
videojs.options.flash.swf = '../video-js/video-js.swf';
var player = videojs(videoId);
supportHLS = videojs.Hls.isSupported();
player.ready(function() {
[[event listeners for media controls]]
this.on('seeked', function() { console.log('seeked');});
this.on('seeking',function() { console.log('seeking');});
var PLAYER_LOADED = 'loadedmetadata';
if(!supportHLS) { PLAYER_LOADED = 'canplay';}
this.one(PLAYER_LOADED, function() {
this.one('canplay', function() {
this.play();
});
this.currentTime(savedPosition);
lastViewed = savedPosition;
});
});
(Reason for the roundabout logic: Chrome had issues with playing the video before the new data (after the seek) had loaded, which caused a number of problems with the data in the buffer. Also, Safari 7.1 would break if you tried this during the 'loadedmetadata' event)
However, there's still one problem, specific to Safari. The loading spinner doesn't always go away when you refresh the page. Examining the logs and listeners seems to indicate that the 'seeking' and 'seeked' events fire at about the same time, but in different orders; the problem always arises whenever 'seeked' fires first, and never occurs when 'seeking' is first. Furthermore, any seeking after the video is playing removes the spinner, so it has to be caused by the initial seek.
It's interesting that Safari supports HLS streaming natively, yet consistently causes the most problems with this player implementation. This is the last Safari bug to iron out, but though it's small it still has a negative impact on user experience.
What causes Safari to fire the 'seeked' and 'seeking' events out of order like this? What can I do to work around it, or is there a cleaner solution for what I'm trying to accomplish?

How to set position correctly in SoundJS for Firefox, IE

I'm trying to use SoundJS to play sn mp3 file and seek to a specific position. I'm using:
instance.setPosition(10000);
which works correctly in Google Chrome. But in Mozilla Firefox I hear the sound playing from the correct position, and a second instance of the sound also playing from another position.
In Internet Explorer, the sound starts playing again from the beginning.
Here's a jsFiddle (with autoplaying sound) and here is the complete javascript:
createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin, createjs.FlashPlugin]);
createjs.Sound.addEventListener("fileload", handleLoad);
createjs.Sound.registerSound("http://ivdemo.chaseits.co.uk/enron/20050204-4026(7550490)a.mp3", "sound");
function handleLoad(event) {
var instance = createjs.Sound.play("sound");
var ten = document.getElementById('ten-secs');
ten.addEventListener('click', function (event) {
instance.setPosition(10000);
});
}
What am I doing wrong for Firefox and IE?
As I commented on in your other question, there was a bug with in a previous version of SoundJS which should be fixed in the latest available on github. You can test this behavior yourself with the TestSuite example.
Nice use of jsfiddle to demonstrate the issue, by the by.
Hope that helps.

Setting currentTime for HTML5 video on Android not working properly

I have created a set of custom navigation elements for a video, to simulate walking around a building (for fire training).
When an overlay is pressed, the routine jumps to a predetermined spot using vidElmt.currentTime = 5; (for example). This works fine on Windows (Chrome, FF, and IE 11) and on the iPad (Safari), but when I try it on my Android phone (4.3, using Chrome or the built-in browser), the videos jump to the wrong spots. For example, if I set it to jump to the 5 second spot, it looks like it jumps to 2, 3 or 4 second spot.
I know some people may point out that I could be trying to jump to a spot not yet loaded, but I know the parts of the video I'm jumping to are definitely already loaded.
I wonder if it's something about my video format (mp4). I've searched to see if anyone has problems with the video tag and currentTime on Android, but I'm not finding anything.
Here is my demo link, if you want to check it out for yourself: http://eqsim.com/fesim/ when the playhead arrives at side/location, it should loop that specific section, and you can press the arrow keys that are lit up to change locations.
I'd appreciate any suggestions!
-jonathan
I suspect you might need to keep querying the video in an interval until the frame you want is seekable. A full working example can be found in this jsbin, but the relevant code is this:
function isSeekable(time) {
for (var i=0; i<video.seekable.length; i++) {
if (video.currentTime > video.seekable.start(i) && video.currentTime < video.seekable.end(i)){
return true
}
}
return false
}
Does that work for you? It seems to work in my Android 4.3 stock browser. If not, can you tell me more about how you encoded your video? Adding more keyframes could help with frame accuracy.

play a video in reverse using HTML5 video element

I am working on a functionality explained below-
Once a video is loaded/with a button click, it has to play in reverse. The target devices are smart phones and tablet devices. I am trying to do this using HTML5 tag and read about the playBackRate attribute. Further down, I am using the HTML5 stuff to generate my mobile apps using Phonegap.
Here's a link I found interesting but partially working -
http://www.w3.org/2010/05/video/mediaevents.html
The playbackrate, when changed doesn't do anything except it pushes the video back, by whatever number is given there.
I read it here that when playBackRate is set to -1, the reverse playback should happen.
I am not clear on how to exactly implement this. Does the playbackrate actually do this reversing? or should I opt on doing something else?
NEW LINE HERE:
I am almost there.. found a working example here. But this is not working when I am trying it on my system. I am not sure where I am making it wrong.
This is an old thread so I'm not sure how useful the following will be.
The Mozilla developer notes point out that:
Negative values [for playbackRate] don't currently play the media backwards.
Same goes for Chrome, but Safari on Mac works.
This page from w3c is great at observing and understanding events:
http://www.w3.org/2010/05/video/mediaevents.html
I took the jsfiddle you mentioned and added some extra controls for fast forward/rewind speeds:
http://jsfiddle.net/uvLgbqoa/
However, though this works fine for me with Chrome/Firefox/Safari, I should point out that it doesn't really address your key questions.
Firstly, the approach assumes that negative playback rates don't work (which at the time I write this, is largely true AFAICS). Instead, it fakes it by calculating and setting the current time in the video:
function rewind(rewindSpeed) {
clearInterval(intervalRewind);
var startSystemTime = new Date().getTime();
var startVideoTime = video.currentTime;
intervalRewind = setInterval(function(){
video.playbackRate = 1.0;
if(video.currentTime == 0){
clearInterval(intervalRewind);
video.pause();
} else {
var elapsed = new Date().getTime()-startSystemTime;
log.textContent='Rewind Elapsed: '+elapsed.toFixed(3);
video.currentTime = Math.max(startVideoTime - elapsed*rewindSpeed/1000.0, 0);
}
}, 30);
}
Chrome handles this quite seamlessly, even playing snippets of audio as it goes.
Secondly, I think you want to play the video in reverse as soon as the page loads. I can't imagine a use case for this, but the first issue I see is that the whole video will need to be downloaded prior to playback, so you'll need to wait - but download probably won't happen until you start playing. So you could set the currentTime to near the end and wait for the canPlay event, and then start playing in reverse. Even then, this seems very awkward.
I think there are these broad options:
Use a native video widget rather than HTML. I'm guessing (without checking) that the native API supports reverse playback.
Generate a proper reversed video and play it as normal. For example, on a server somewhere use a program like ffmpeg to reverse the video. Then your app downloads the video and plays it normally, which looks to the user like reverse.
Assuming it really does make sense to have an application that plays a video in reverse when you load it, then I'd personally go for #2.

How to get the progress event working with jplayer

I am using jQuery 1.5 and jPlayer 2.0.0, please ignore the fact that this is going to auto play music, I am going to supply enough warning before it starts, the user has to press a big button to initiate the page and I will provide a big STOP button.
I would like the audio file to begin playing and a function be called after the page is ready and the audio is loaded.
I have the following javascript (I have modified the code so it can be understood better).
function FemeMusic() {
FemeMusic.prototype.addMusic = function(actionAfterMusic) {
$("#jp").jPlayer({
ready: function() {
var jPlayerElement = $(this);
jPlayerElement.jPlayer('setMedia', {
mp3: 'aSongByJamesBlunt.mp3'
});
jPlayerElement.bind($.jPlayer.event.progress,
function(event) {
if (event.jPlayer.status.seekPercent === 100) {
jPlayerElement.jPlayer("play");
}
if (actionAfterMusic) {
actionAfterMusic.call();
}
});
},
swfPath: "/flash",
preload: "auto"
});
}
}
I have this function to trigger the above code.
$(document).ready(function() {
var femeMusic = new FemeMusic();
femeMusic.addMusic(killMyself);
});
I was using the same code but with the $.jPlayer.event.loadeddata event without the if statement instead of $.jPlayer.event.progress and it worked fine in some browsers but isn't compatible when it comes to using flash because it doesn't fire the event (Also I had a problem with it in firefox 3.5 but I don't know why). The above seems to work in Firefox
I read this
"I suggest you use the progress event instead and check that the:
event.jPlayer.status.seekPercent === 100. "
On this post http://groups.google.com/group/jplayer/browse_thread/thread/9dc9736f9d6947bd?pli=1 by the creator
Any one got any suggestions?
Edit
Having not got this working in chrome and safari I tested this on a new version 3.6 of Firefox (which I should have done in the first place) and it worked as expected, despite the fact that in the documentation event.progress id described as:
A robust jPlayer event supported by Flash and HTML5 browsers
and in the link above the creator suggests to use event.progress to get round browser problems I can only assume it's a browser specific issue.
Would be nice to get some clarification on this though.
From the creator of jPlayer:
So your goal here is to auto-play AFTER the media is buffered?
If you want the short answer. Forget it. x-browser buffering is a mine
field. Some simply ignore it as you have found. Just setMedia and play it.
If you really want to try and do it. Then a play then pause would help,
since a media.play() is better x-browser than a media.load() i.e. its
operation varies less. The iOS Safari would ignore the play completely
though. The user would need to click on something that starts the
operation i.e. a play button.
That last point applies to trying any form of autoplay, so ensure that there
is a play button available. The jPlayer interface will cope with iOS not
playing through feedback from the browser events i.e. stalled.
I had problems with the progress event with flash and html5 backend in most browsers. as far as I can see the timeupdate event is working much better.

Categories