HTML5 MP3 <audio> not loading correctly - javascript

Ok, my new website has just gone live, delivered through Google Apps. On a lark, I decided to include a javascript / HTML5 Lunar Lander clone (Martian Lander) which I wrote as an exercise a while back. The game works fine when I open it locally, but when it's delivered through GAE, the sounds don't seem to load on every system. In mobile safari, none of them load. In safari on the desktop, they all load reliably on my computer, but not on some other computers. In Chrome (on the desktop) it seems to work, but in Chrome in iOS, only one sound loads. On the desktop, it always seems to be the same sound which fails to load (explode1.mp3), which is the smallest of the sounds I'm loading. As you can see, if you click that link, the sound downloads fine from the server...
At first the problem seemed to be related to case sensitivity, so I switched the case in the filename, but that fix didn't keep working. This is a problem, as my loading bar is directly tied to how many resources have loaded, so it just sits there waiting for a GET request with no reply... Has anyone experienced anything like this, where a GET receives no reply on a specific resource, but loading the resource directly works fine?
I should say that I'm very new to most of these technologies, so it seems quite likely to me that I just made some novice mistake. Unfortunately, I'm not sure what those novice mistakes would be, seeing as I'm a novice!
Here's the code I use to load the sounds:
function loadSound(soundName) {
var newElement = document.createElement("audio");
newElement.addEventListener("canplaythrough", assetLoaded, false);
document.body.appendChild(newElement);
var audioType = supportedAudioFormat(newElement);
if (audioType == "") {
alert("no audio support");
return;
}
newElement.setAttribute("src", "lander/sounds/" + soundName + "." + audioType);
console.log("loading sound " + newElement.src + "...");
return newElement;
}
and...
function assetLoaded() {
var assetName = this.src;
numAssetsLoaded++;
console.log("loaded asset " + numAssetsLoaded + " (" + assetName + ")");
if (numAssetsLoaded >= numAssetsToLoad) {
shipSpriteSheet.removeEventListener("load", assetLoaded, false);
pointImage.removeEventListener("load", assetLoaded, false);
thrustAudioElement.removeEventListener("canplaythrough", assetLoaded, false);
explosionAudioElement.removeEventListener("canplaythrough", assetLoaded, false);
victoryAudioElement.removeEventListener("canplaythrough", assetLoaded, false);
musicTrackElement.removeEventListener("canplaythrough", assetLoaded, false);
gameState = GAME_STATE_INIT;
}
}
If you take a look at the console output, you'll see that all of the sounds begin loading (particularly explode1.mp3) but don't necessarily finish and call assetLoaded...
UPDATE:
It seems to be the consensus is that I should not be using mp3 (incidentally, I'm already using mp3, AAC, AND ogg, but defaulting to mp3), and also that I should use the Web Audio API. These are both welcome pieces of input, and I will make the necessary changes. However, I still don't have an answer to the original question, which is, "Why does one particular sound not load reliably on desktop while the others load with no problem?" Anybody wanna take a crack at that one? Or is the answer going to be something like, "These things are highly unpredictable, and there's no way to fix it except by switching to a more dependable methodology, like Web Audio API"?
UDATE:
Here's an excerpt from my app.yaml file, which, I gather, helps GAE setup the server.
- url: /(.*\.(mp3|ogg|wav))
static_files: \1
upload: (.*\.(mp3|ogg|wav))

Some things to be aware of:
You shouldn't use MP3 for HTML5 games.
You will need to dual-encode all your sounds to both AAC (.m4a) and Ogg Vorbis (.ogg) to ensure they can be played everywhere, since there is no one format which can be played everywhere.
You must ensure your server has the correct MIME types for the audio files. Some browsers will happily play audio if the server says it has the wrong MIME type; others will fail silently. For AAC and Ogg Vorbis the types are audio/mp4 and audio/ogg respectively.
Most mobile devices can only play one sound at a time, and iOS generally doesn't let you play audio unless it's in a user-initiated input event (such as touchstart).
You'll probably want to use the Web Audio API where supported (Chrome and iOS 6+) since playback is more reliable and polyphonic even on iOS - but note iOS still mutes the Web Audio API until a user input event.

This is not a direct answer to your question why sound is not being played, but more like what you should do with your game sound effects.
For game sound effects I suggest you use HTML5 Web Audio API which gives more control over how sounds are played (pitch of the sound effect, less delay in playback, etc):
http://www.html5rocks.com/en/tutorials/webaudio/intro/
iOS 6+ supports Web Audio https://developer.apple.com/technologies/ios6/
Web audio is not supported in FF yet, but the support is coming

Related

How to use MediaRecorder as MediaSource

As an exercise in learning WebRTC I am trying to to show the local webcam and side by side with a delayed playback of the webcam. In order to achieve this I am trying to pass recorded blobs to a BufferSource and use the corresponding MediaSource as source for a video element.
// the ondataavailable callback for the MediaRecorder
async function handleDataAvailable(event) {
// console.log("handleDataAvailable", event);
if (event.data && event.data.size > 0) {
recordedBlobs.push(event.data);
}
if (recordedBlobs.length > 5) {
if (recordedBlobs.length === 5)
console.log("buffered enough for delayed playback");
if (!updatingBuffer) {
updatingBuffer = true;
const bufferedBlob = recordedBlobs.shift();
const bufferedAsArrayBuffer = await bufferedBlob.arrayBuffer();
if (!sourceBuffer.updating) {
console.log("appending to buffer");
sourceBuffer.appendBuffer(bufferedAsArrayBuffer);
} else {
console.warn("Buffer still updating... ");
recordedBlobs.unshift(bufferedBlob);
}
}
}
}
// connecting the media source to the video element
recordedVideo.src = null;
recordedVideo.srcObject = null;
recordedVideo.src = window.URL.createObjectURL(mediaSource);
recordedVideo.controls = true;
try {
await recordedVideo.play();
} catch (e) {
console.error(`Play failed: ${e}`);
}
All code: https://jsfiddle.net/43rm7258/1/
When I run this in Chromium 78 I get an NotSupportedError: Failed to load because no supported source was found. from the play element of the video element.
I have no clue what I am doing wrong or how to proceed at this point.
This is about something similar, but does not help me: MediaSource randomly stops video
This example was my starting point: https://webrtc.github.io/samples/src/content/getusermedia/record/
In Summary
Getting it to work in Firefox and Chrome is easy: you just need to add an audio codec to your codecs list! video/webm;codecs=opus,vp8
Getting it to work in Safari is significantly more complicated. MediaRecorder is an "experimental" feature that has to be manually enabled under the developer options. Once enabled, Safari lacks an isTypeSupported method, so you need to handle that. Finally, no matter what you request from the MediaRecorder, Safari will always hand you an MP4 file - which cannot be streamed the way WEBM can. This means you need to perform transmuxing in JavaScript to convert the video container format on the fly
Android should work if Chrome works
iOS does not support Media Source Extensions, so SourceBuffer is not defined on iOS and the whole solution will not work
Original Post
Looking at the JSFiddle you posted, one quick fix before we get started:
You reference a variable errorMsgElement which is never defined. You should add a <div> to the page with an appropriate ID and then create a const errorMsgElement = document.querySelector(...) line to capture it
Now something to note when working with Media Source Extensions and MediaRecorder is that support is going to be very different per browser. Even though this is a "standardized" part of the HTML5 spec, it's not very consistent across platforms. In my experience getting MediaRecorder to work in Firefox doesn't take too much effort, getting it to work in Chrome is a bit harder, getting it to work in Safari is damned-near impossible, and getting it to work on iOS is literally not something you can do.
I went through and debugged this on a per-browser basis and recorded my steps, so that you can understand some of the tools available to you when debugging media issues
Firefox
When I checked out your JSFiddle in Firefox, I saw the following error in the console:
NotSupportedError: An audio track cannot be recorded: video/webm;codecs=vp8 indicates an unsupported codec
I recall that VP8 / VP9 were big pushes by Google and as such may not work in Firefox, so I tried making one small tweak to your code. I removed the , options) parameter from your call to new MediaRecorder(). This tells the browser to use whatever codec it wants, so you will likely get different output in every browser (but it should at least work in every browser)
This worked in Firefox, so I checked out Chrome.
Chrome
This time I got a new error:
(index):409 Uncaught (in promise) DOMException: Failed to execute 'appendBuffer' on 'SourceBuffer': This SourceBuffer has been removed from the parent media source.
at MediaRecorder.handleDataAvailable (https://fiddle.jshell.net/43rm7258/1/show/:409:22)
So I headed over to chrome://media-internals/ in my browser and saw this:
Audio stream codec opus doesn't match SourceBuffer codecs.
In your code you're specifying a video codec (VP9 or VP8) but not an audio codec, so the MediaRecorder is letting the browser choose any audio codec it wants. It looks like in Chrome's MediaRecorder by default chooses "opus" as the audio codec, but Chrome's SourceBuffer by default chooses something else. This was trivially fixed. I updated your two lines that set the options.mimeType like so:
options = { mimeType: "video/webm;codecs=opus, vp9" };
options = { mimeType: "video/webm;codecs=opus, vp8" };
Since you use the same options object for declaring the MediaRecorder and the SourceBuffer, adding the audio codec to the list means the SourceBuffer is now declared with a valid audio codec and the video plays
For good measure I tested the new code (with an audio codec) on Firefox. This worked! So we're 2 for 2 just by adding the audio codec to the options list (and leaving it in the parameters for declaring the MediaRecorder)
It looks like VP8 and opus work in Firefox, but aren't the defaults (although unlike Chrome, the default for MediaRecorder and SourceBuffer are the same, which is why removing the options parameter entirely worked)
Safari
This time we got an error that we may not be able to work through:
Unhandled Promise Rejection: ReferenceError: Can't find variable: MediaRecorder
The first thing I did was Google "Safari MediaRecorder", which turned up this article. I thought I'd give it a try, so I took a look. Sure enough:
I clicked on this to enable MediaRecorder and was met with the following in the console:
Unhandled Promise Rejection: TypeError: MediaRecorder.isTypeSupported is not a function. (In 'MediaRecorder.isTypeSupported(options.mimeType)', 'MediaRecorder.isTypeSupported' is undefined)
So Safari doesn't have the isTypeSupported method. Not to worry, we'll just say "if this method doesn't exist, assume it's Safari and set the type accordingly"
if (MediaRecorder.isTypeSupported) {
options = { mimeType: "video/webm;codecs=vp9" };
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = { mimeType: "video/webm;codecs=vp8" };
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = { mimeType: "video/webm" };
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = { mimeType: "" };
}
}
}
} else {
options = { mimeType: "" };
}
Now I just had to find a mimeType that Safari supported. Some light Googling suggests that H.264 is supported, so I tried:
options = { mimeType: "video/webm;codecs=h264" };
This successfully gave me MediaRecorder started, but failed at the line addSourceBuffer with the new error:
NotSupportedError: The operation is not supported.
I will continue to try and diagnose how to get this working in Safari, but for now I've at least addresses Firefox and Chrome
Update 1
I've continued to work on Safari. Unfortunately Safari lacks the tooling of Chrome and Firefox to dig deep into media internals, so there's a lot of guesswork involved.
I had previously figured out that we were getting an error "The operation is not supported" when trying to call addSourceBuffer. So I created a one-off page to try and call just this method under different circumstances:
Maybe add a source buffer before play is called on the video
Maybe add a source buffer before the media source has been attached to a video element
Maybe add a source buffer with different codecs
etc
I found that the issue was the codec still, and that the error messaging about the "operation" not being permitted was slightly misleading. It was the parameters that were not permitted. Simply supplying "h264" worked for the MediaRecorder, but the SourceBuffer needed me to pass along the codec parameters.
One of the first things I tried was heading to the MDN sample page and copying the codecs they used there: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'. This gave the same "operation not permitted" error. Digging into the meaning of these codec parameters (like what the heck does 42E01E even mean?). While I wish I had a better answer, while Googling it I stumbled upon this StackOverflow post which mentioned using 'video/mp4; codecs="avc1.64000d,mp4a.40.2"' on Safari. I gave it a try and the console errors were gone!
Although the console errors are gone now, I'm still not seeing any video. So there is still work to do.
Update 2
Further investigation in the Debugger in Safari (placing multiple breakpoints and inspecting variables at each step of the process) found that handleDataAvailable was never being called in Safari. It looks like in Firefox and Chrome mediaRecorder.start(100) will properly follow the spec and call ondatavailable every 100 milliseconds, but Safari ignores the parameter and buffers everything into one massive Blob. Calling mediaRecorder.stop() manually caused ondataavailable to be called with everything that had been recorded up until that point
I tried using setInterval to call mediaRecorder.requestData() every 100 milliseconds, but requestData was not defined in Safari (much like how isTypeSupported was not defined). This put me in a bit of a bind.
Next I tried cleaning up the whole MediaRecorder object and creating a new one every 100 milliseconds, but this threw an error on the line await bufferedBlob.arrayBuffer(). I'm still investigating why that one failed
Update 3
One thing I recall about the MP4 format is that the "moov" atom is required in order to play back any content. This is why you can't download the middle half of an MP4 file and play it. You need to download the WHOLE file. So I wondered if the fact that I selected MP4 was the reason I was not getting regular updates.
I tried changing video/mp4 to a few different values and got varying results:
video/webm -- Operation is not supported
video/x-m4v -- Behaved like MP4, I only got data when .stop() was called
video/3gpp -- Behaved like MP4
video/flv -- Operation is not supported
video/mpeg -- Behaved like MP4
Everything behaving like MP4 led me to inspect the data that was actually being passed to handleDataAvailable. That's when I noticed this:
No matter what I selected for the video format, Safari was always giving me an MP4!
Suddenly I remembered why Safari was such a nightmare, and why I had mentally classified it as "damned-near impossible". In order to stitch together several MP4s would require a JavaScript transmuxer
That's when I remembered, that's exactly what I had done before. I worked with MediaRecorder and SourceBuffer just over a year ago to try and create a JavaScript RTMP player. Once the player was done, I wanted to add support for DVR (seeking back to parts of the video that had already been streamed), which I did by using MediaRecorder and keeping a ring buffer in memory of 1-second video blobs. On Safari I ran these video blobs through the transmuxer I had coded to convert them from MP4 to ISO-BMFF so I could concatenate them together.
I wish I could share the code with you, but it's all owned by my old employer - so at this point the solution has been lost to me. I know that someone went through the trouble of compiling FFMPEG to JavaScript using emscripten, so you may be able to take advantage of that.
Additionally, I suffered issues with MediaRecorder. At the time of Audio Record, Mime Types are different like
Mac chrome - Mime Type:audio/webm;codecs=opus
Mac Safari - Mime Type:audio/mp4
Windows/Android - Mime Type:audio/webm;codecs=opus
Iphone Chrome - Mime Type:audio/mp4
In PC, I was saving the file as M4a but Audio was not running in IOS. After some analysis and Testing. I decided to convert the file after Upload in Server and used ffmpeg and It worked like a charm.
<!-- https://mvnrepository.com/artifact/org.bytedeco/ffmpeg-platform -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>4.3.2-1.5.5</version>
</dependency>
/**
* Convert the file into MP4 using H264 Codac in order to make it work in IOS Mobile Device
* #param file
* #param outputFile
*/
private void convertToM4A(File file, File outputFile) {
try {
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
ProcessBuilder pb = new ProcessBuilder(ffmpeg, "-i", file.getPath(), "-vcodec", "h264", outputFile.getPath());
pb.inheritIO().start().waitFor();
}catch (Exception e ){
e.printStackTrace();
}
}

Asp Net Core FileContentResult Audio File to Safari

In Safari (11), a static audio file loaded into a src via html or javascript works, albeit with the limitations of requiring user input before playing.
ex.
<audio src="static.mp3">
or
var audio = new Audio('static.mp3');
audio.play();
work fine.
However, I need to load audio files from the database, so I was using a controller action like so:
public FileContentResult GetAudio(int audioId)
{
if (!DbContext.Audios.Any(a => a.Id == audioId))
{
return null;
}
var audio = DbContext.Audios.Single(a => a.Id == audioId);
return File(audio.File, "audio/mp3");
}
and set like
<audio src="getaudio?audioId=1">
or
var audio = new Audio('getaudio?audioId=1');
it will not play in MacOS (Safari) or iOS, but works fine in Chrome and Edge (except on iOS). Depending on how I configure things, I get some form of Unhandled Promise error. I've also tried loading into a Web Audio buffer, with the same exact success and failures.
Does anyone have a solution or workaround to load my audio files on Safari?
EDIT
Ok, so on further testing, I discovered that it's not so much whether the files were sent via action or static file, it's how they were saved to the database in the first place. I'm now working to figure out why files I save (as byte[]) and then reload are not recognized by Safari.
OK, so it turns out, I was making the recordings with MediaRecorder, which is a fairly new feature in Chrome and a few other browsers. It didn't matter what format I told it to save as, because only webm is supported. And guess who doesn't support webm format? Safari. Any other browser was picking it up fine, regardless of what incorrect extension I put on the file.
When I find a webm to m4a conversion, I will add it here. I'm sure there are some solutions out there.

HTML5 audio how to prevent browser microphones pick up all sounds

In my sample asp.net/vb.net project for HTML5 audio, using Matt Diamond's recorder.js, when I grant any browser access to my microphone, I can hear every noise around me in the headset speakers (e.g., someone typing next to me, people speaking, etc). I'm using a Logitech USB headset, but am not sure the specific model as they're provided through work.
Does anyone know if this is a browser-related issue with the microphone (or possibly resulting from the headset I'm using)? I'm trying to find a different headset to test with, but work typically buys the same model for everyone.
I've tried a few other sites that have demos for recording and play back, and can still hear everything around me once I grant the microphone access (although some demos seem do better at not picking up the background noises).
My knowledge of audio is very limited as I've never worked with audio at the level of normalizing, setting gain, etc. Any resources or suggestions would be greatly appreciated!
I can include a copy of the aspx and vb.net pages from my sample project if that would be helpful. Thanks!
Well, the issue turned out to be my fault due to uncommenting a line of Javascript that caused the audio to feedback directly. Guess that's part of learning something new. :)
Here's the function I used from Matt Diamond's example with the line commented out that I must have incorrectly uncommented at some point...
function startUserMedia(stream) {
var input = audio_context.createMediaStreamSource(stream);
console.log('Media stream created.');
// Uncomment if you want the audio to feedback directly
// input.connect(audio_context.destination);
try {
recorder = new Recorder(input);
} catch (e) {
alert('Error: Unable to record. Please check your sound settings, and allow the browser access to your microphone when prompted.');
console.log('Error: Recorder object could not be created. Msg: ' + e.toString());
}
}
Thank you for the responses that were provided! I'm sure I'll have more audio questions to come, lol.

How can I allow JavaScript to run in the background, in Firefox? [duplicate]

In app I can use http://developer.android.com/reference/android/os/PowerManager.WakeLock.html
but is there a way to keep webpage running and prevent from going to sleep?
It would be nice if it runs at least on android.
You can use: https://github.com/richtr/NoSleep.js
Prevent display sleep and enable wake lock in any Android or iOS web browser.
Note that the library has some reliability/performance issues on some platforms/browsers. Users have found solutions that are listed in the issue comments and pull requests, but they have not been added since the repo owner appears not to be active currently.
It's recommended that you check those pull requests (and/or issues) for potential improvements before using in production.
You can use the Wake Lock web API (check support)
https://web.dev/wakelock/
In an app there are a couple of ways you can do it, but I guess you mean just in a mobile web page, viewed in any browser via Android. With normal HTML/Javascript/etc., I really, really doubt it.
It actually may be possible using Flash (on flash-enabled phones with plugins enabled), though, at least in specific circumstances. I say this because, in a test app without the WAKE_LOCK permission, loading this swf file into a WebView caused the following exception on some devices:
java.lang.SecurityException: Neither
user ##### nor current process has
android.permission.WAKE_LOCK
Even if this did work, however, it would run the risk of crashing apps or browsers that did not have the WAKE_LOCK permission. It may be possible due to bad code in the Adobe Flash Player plugin, rather than any intentional functionality.
Play fake looped VIDEO or AUDIO on your page
You can use this a quick example to add a looped video with fake data to your page and prevent mobile device from sleep:
// Create the root video element
var video = document.createElement('video');
video.setAttribute('loop', '');
// Add some styles if needed
video.setAttribute('style', 'position: fixed;');
// A helper to add sources to video
function addSourceToVideo(element, type, dataURI) {
var source = document.createElement('source');
source.src = dataURI;
source.type = 'video/' + type;
element.appendChild(source);
}
// A helper to concat base64
var base64 = function(mimeType, base64) {
return 'data:' + mimeType + ';base64,' + base64;
};
// Add Fake sourced
addSourceToVideo(video,'webm', base64('video/webm', 'GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA='));
addSourceToVideo(video, 'mp4', base64('video/mp4', 'AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAG21kYXQAAAGzABAHAAABthADAowdbb9/AAAC6W1vb3YAAABsbXZoZAAAAAB8JbCAfCWwgAAAA+gAAAAAAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIVdHJhawAAAFx0a2hkAAAAD3wlsIB8JbCAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAIAAAACAAAAAABsW1kaWEAAAAgbWRoZAAAAAB8JbCAfCWwgAAAA+gAAAAAVcQAAAAAAC1oZGxyAAAAAAAAAAB2aWRlAAAAAAAAAAAAAAAAVmlkZW9IYW5kbGVyAAAAAVxtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAEcc3RibAAAALhzdHNkAAAAAAAAAAEAAACobXA0dgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAIAAgASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAAFJlc2RzAAAAAANEAAEABDwgEQAAAAADDUAAAAAABS0AAAGwAQAAAbWJEwAAAQAAAAEgAMSNiB9FAEQBFGMAAAGyTGF2YzUyLjg3LjQGAQIAAAAYc3R0cwAAAAAAAAABAAAAAQAAAAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAFHN0c3oAAAAAAAAAEwAAAAEAAAAUc3RjbwAAAAAAAAABAAAALAAAAGB1ZHRhAAAAWG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAK2lsc3QAAAAjqXRvbwAAABtkYXRhAAAAAQAAAABMYXZmNTIuNzguMw=='));
// Append the video to where ever you need
document.body.appendChild(video);
// Start playing video after any user interaction.
// NOTE: Running video.play() handler without a user action may be blocked by browser.
var playFn = function() {
video.play();
document.body.removeEventListener('touchend', playFn);
};
document.body.addEventListener('touchend', playFn);
If you build a WebViewGold/WebView app on Android (while having the actual webpage/web app in such a wrapper), all these mentioned approaches here will not work. But then you can also do set
PREVENT_SLEEP = TRUE;
in Config.java which should do the trick.
On iOS devices, just refreshing the page in Javascript every few seconds will keep the screen awake. This seems to be the correct strategy, hopefully Android will adopt this in a future version.

my javascript sounds wont play in windows XP?

new Audio('sounds/mysound.mp3').play();
Im using the above javascript to play sounds on a web project, everything works fine at home on my laptop which is running Windows 7 , tested in both Firefox, and Google Chrome.
The problem i have is that on Windows XP, the sounds wont play at all? I do understand that browser support for the above is a bit sketchy at the moment, as mp3 is not fully supported apparently, in firefox for example.. so im a bit confused?? why does it play on my windows 7 machine, but not on windows xp machines, even in the same browser?
I may well have to look at doing the sounds with a plugin or something, can jPlayer play sounds with no visbable player icons etc.. as all the demos show some form of player on screen?
Any help appreciated.
Thanks Paul
EDIT***
I think if OGG files will work, i`ll have to have both sound file formats in my sounds folder, and then use a javascript variable to add the .ext required depending on what broswer is being used.
check which browser
extVariable = either '.mp3' or '.ogg' accordingly
new Audio('sounds/mysound'+extVariable).play();
That way i dont need if else statments everytime i wish to call a sound :) just set the .ext variable up at the top of page.
i made the following audio test over at http://codepen.io/PaulBrUK1972/full/pGdza
and just as i thought using windows XP, the ogg file will play in firefox, but the mp3 wont. It would be interesting to know if the mp3 plays on other peoples windows 7 machines, like it does on mine, even though it shouldnt??
Firefox relies on codex available on the machine to play mp3 to get around licensing issues, so that could cause issues.
If you are looking for a sound library to abstract away the issues of supporting audio on browsers with variable support, I'd recommend SoundJS, which I help develop. It uses the latest audio standards when available, and has a flash fallback for older browsers and systems. using SoundJS, you can write a single codebase that is broadly supported, including on mobile devices.
Hope that helps.
Internet Explorer 9+ can play: MP3
Firefox 3.6+ can play: WAV and OGG
Chrome 3+ can play: MP3 and OGG
Safari 4+ can play: MP3 and WAV
Opera 9.5+ can play: WAV and OGG
The above is the list of music file types that can be played in the given browser, that is something i took from the book Pro HTML5 Games - Aditya Ravi Shankar. It's a good book i am still working through it though.
If the browser is not causing an issue you should check the following:
Check you have speakers/headset/earphones plugged in.
Check that the volume is not too low.
Check that other audio is working on your PC, play a track on YouTube, or some media player.
Check the sound/volume settings and adjust the settings, you may be sending audio out the incorrect channels.
Check that you have an up to date sound driver.
If that doesn't work check that your sound card is not broken.
What most html5 sound libraries, such as sm2, do to get around the fact that some browsers support only certain audio types is call document.createElement("audio").canPlayType(type) before creating the audio element for the sound.
So I suggest you make a helper function in creating your audio sounds that could look something as what follows (sorry if theres errors untested):
var audioTypes = {
"ogg": "audio/ogg",
"mp3": "audio/mp3"//etc
}
//src is an array of sources for a type
var createAudio = function(src, options) {
var audio = document.createElement("audio");
for (var i = 0; i < src.length; i++) {
var type = src[i].slice(src[i].lastIndexOf(".") + 1);
if(audio.canPlayType(audioTypes[type]) {
audio.type = audioTypes[type];
audio.src = src[i];
return audio;
}
}
throw "Unsupported audio";
}
Now just call
var mySound = createAudio(["sounds/mySound.ogg", "sounds/mySound.mp3"]);

Categories

Resources