Illegal invocation with start/noteOn using Web Audio API - javascript

So basically I've tested this in Chrome and maybe the order of codes is off or whatever, trying to cover some of the functionality of HTML5 audio using "web audio" due to the range requests bug, for the making of games with looping sound effects and music...
I get an "illegal exception" error. Here's the code:
var url='example.mp3';
var a_result=new Object();
a_result.loaded=false;
a_result.evalstring='';
a_result.loop=false;
a_result.play=function(){
var asrc=a_result.source;
asrc.loop=a_result.loop;
//try{
var playfunc=asrc.start||asrc.noteOn;
playfunc(0);
//}catch(e){
/* do nothing */
//}
}
a_result.pause=function(){
var asrc=a_result.source;
try{
var stopfunc=asrc.stop||asrc.noteOff;
stopfunc(0);
}catch(e){
/* do nothing */
}
}
var asrc=actx.createBufferSource();
asrc.connect(actx.destination);
var req=new XMLHttpRequest();
req.open('GET',url,true);
req.responseType='arraybuffer';
req.onload=function(){
if(a_result.loaded==false){
asrc.buffer=actx.createBuffer(req.response,false);
a_result.source=asrc;
a_result.loaded=true;
}
var cont=a_result;
eval(cont.evalstring);
}
req.onerror = function() {
if(a_result.loaded==false){
a_result.loaded=true;
}
}
try{
req.send(null);
}catch(e){
req.onerror();
}
return a_result;
And then later on after the sound has loaded I do something like:
a_result.play();
And instead of playing it gives the error.
Here is a sound test that uses the above code with the fix suggested below, and it works in Chrome, successfully working around the range requests issue on a crappy web server. Here is another that has issues (throwing some kind of "invalid string" error at asrc.buffer=actx.createBuffer(req.response,false); in Iron and silently screwing up in Chrome).
Here is the code edited according to the suggestions:
var url='example.mp3'
var a_result=new Object();
a_result.loaded=false;
a_result.evalstring='';
a_result.loop=false;
a_result.play=function(){
var asrc=a_result.source;
asrc.loop=a_result.loop;
try{
if(asrc.start){
asrc.start(0);
}else{
asrc.noteOn(0);
}
}catch(e){
/* do nothing */
}
}
a_result.pause=function(){
var asrc=a_result.source;
try{
if(asrc.stop){
asrc.stop(0);
}else{
asrc.noteOff(0);
}
}catch(e){
/* do nothing */
}
}
var asrc=actx.createBufferSource();
asrc.connect(actx.destination);
var req=new XMLHttpRequest();
req.open('GET',url,true);
req.responseType='arraybuffer';
req.onload=function(){
actx.decodeAudioData(req.response,function(buffer){
if(buffer){
if(a_result.loaded==false){
asrc.buffer=buffer;
a_result.source=asrc;
a_result.loaded=true;
}
var cont=a_result;
eval(cont.evalstring);
}
});
}
req.onerror = function() {
if(a_result.loaded==false){
a_result.loaded=true;
}
}
try{
req.send(null);
}catch(e){
req.onerror();
}
return a_result;
It no longer appears to have a syntax error, however, it does not seem to solve the playability issues on Chrome (second test case above updated). Specifically, after a sound is stopped it does not want to play again. -- Apparently because it's in the spec. The buffer has to be applied to a new sound source every time you play.

In your new page, you're calling createBuffer(data, false) on the results of an XMLHTTPRequest. You almost certainly want to be calling decodeAudioData() on those results, instead - createBuffer doesn't have a 2-parameter version, and doesn't match the parameters you're passing even if you're trying to push arbitrary data into a buffer. It appears from a browse of your code that you're pulling down MP3 or Ogg files - you need to decode them.

The play method (either start() or noteOn()) needs to be invoked ON the buffersourcenode object, not disassociated from it. You have a few options:
1) I'd strongly recommend just including my audio context monkeypatch library (https://github.com/cwilso/AudioContext-MonkeyPatch/) and using the new (start()) syntax. no muss, no fuss.
2) You can just use an if statement instead of using playfunc to switch:
if (asrc.start)
asrc.start(0);
else
asrc.noteOn(0);
3) You can bind() the play function to the object and keep your code essentially the same:
var playfunc=asrc.start ? asrc.start.bind(asrc) || asrc.noteOn.bind(asrc);
playfunc(0);
4) You can push the playfunc() method onto the object itself (I think this will work):
asrc.playfunc=asrc.start||asrc.noteOn;
asrc.playfunc(0);

Related

Firefox CORS issue with JSON

I'm trying to use the API from https://www.themoviedb.org/. (The key is free and can be changed easily, so I'll include it because without it, you can’t even test their functions).
Now my JavaScript is working fine in FF when it's hosted local, but not on GitHub pages.
Here is a function that doesn’t work. Error is:
NetworkError: A network error occurred.
…and it appears to happen after bhttp.send();.
function getMovieDetails() {
var reqURL = "https://api.themoviedb.org/3/movie/latest?api_key=afe4e10abbb804e2b4a4f8a3ef067ad5&language=en-US";
var bhttp = new XMLHttpRequest();
bhttp.open("GET", reqURL, false);
bhttp.setRequestHeader("Content-type", "json");
bhttp.send();
var response = JSON.parse(bhttp.responseText);
var str = JSON.stringify(response, null, 2);
return response;
}
console.log(getMovieDetails());
It works fine in Chrome. Googling appears to indicate it’s a CORS problem, but as far as I know GitHub pages supports CORS, so I don't know what I'm doing wrong.
I'm not a firefox user, so you will need to test this. But if the theory of async blocking is true this should work.
I've modified it to use a simple callback, personally I wouldn't use callbacks but would make into promises, but that's another question :)
function getMovieDetails(callback) {
var reqURL = "https://api.themoviedb.org/3/movie/latest?api_key=afe4e10abbb804e2b4a4f8a3ef067ad5&language=en-US";
var bhttp = new XMLHttpRequest();
bhttp.open("GET", reqURL, true);
bhttp.setRequestHeader("Content-type", "json");
bhttp.onload = function() {
if (bhttp.readyState === 4) {
if (bhttp.status === 200) {
callback(JSON.parse(bhttp.responseText));
} else {
console.error(bhttp.statusText);
}
}
};
bhttp.send();
}
getMovieDetails(function (movie) {
console.log(movie);
});
Alright looks like skirtle was correct, the issue was the firefox addon Privacy-Badger blocking the API. I feel pretty stupid now but at least my code is now pretty clean.

Recursive calls to a server using AJAX not working in Internet Explorer

I am developing a web-application on File Management System in which I have to access various directories on my system and list them on my web page. I have used AJAX to make rest calls to the server. I have created a rest-controller to handle the requests.
I am encountering a problem in the execution of a java-script function which I have to call recursively on the basis of a counter. The function is to navigate backwards in a directory. If the value of count is zero, I will display the result on the web page, else I will recursively call the function. The function works as expected in Chrome but not in IE-11.
I want to make multiple calls to the server based on the counter value. Hence I am calling the function recursively, but the call to the server is made only once. This problem occurs in IE-11. In Chrome, it works perfectly.
The function is:
function gobackDir(count) {
var back_count = count;
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","http://neha:8080/myServer/goback",true);
xmlhttp.send();
xmlhttp.onreadystatechange=function($event) {
if ($event.currentTarget.readyState==4 && $event.currentTarget.status==200) {
back_count--;
if (back_count > 0) {
gobackDir(back_count);
}
else {
var server_response = JSON.parse($event.currentTarget.response);
set_currentDirectory(server_response);
set_directoryContent(server_response);
}
}
}
}
In IE, you need to bust the cache:
var bustCache = (new Date()).getTime();
xmlhttp.open("GET","http://neha:8080/myServer/goback?" + bustCache,true);

php not returning any result to javascript ajax object

I'm trying to use ajax, I've used it before, copied the code from my previous html file and altered the values sent, php file to process the code and I'm using the POST method. However, the php script does not return anything to the html page. I've checked all i can, so I'm here now.
function look () {
var x = document.getElementsByTagName('option')[document.getElementById("region").selectedIndex].value;
var ajaxRequest; // The variable that makes Ajax possible!
try{
// Opera 8.0+, Firefox, Safari
ajaxRequest = new XMLHttpRequest();
}catch (e){
// Internet Explorer Browsers
try{
ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
}catch (e) {
try{
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
}catch (e){
// Something went wrong
alert("Your browser broke!");
return false;
}
}
}
// Create a function that will receive data
// sent from the server and will update
// modal section in the same page.
ajaxRequest.onreadystatechange = function(){
if(ajaxRequest.readyState == 4){
var ajaxDisplay = document.getElementById("accordion");
ajaxDisplay.innerHTML = ajaxRequest.responseText;
}
}
// Now get the value from user and pass it to
// server script.
ajaxRequest.open("POST", "search.php", true);
ajaxRequest.setRequestHeader("Content-type","application/x-www-form-urlencoded");
alert(x);
ajaxRequest.send("region=" + x);
}
The php code is a simple
<?php
echo "The world is blue.";
?>
yet, it returns nothing to the chosen div.
You've probably not posted enough information for us to answer your question. But, I acknowledge that you probably are not sure what questions you need to ask in the first place.
First, I must agree with #cgf. jQuery or the alike will make this easier.
But lets focus on the problem at hand. We need to know what is happening behind the scenes.
The best way to do this is through a developer tool bar such as firebug. Chrome has one built in.
So, load up chrome and hit F12. This should bring up a very busy looking pane on the bottom of your window. Select the Network tab and then request your page / trigger your javascript. What output do you get in the network tab? Mainly, under status do you get 200, 500 (server error) or perhaps 404 (not found)? Update your question above with what you see / get.
My hope is that this should point you in the right direction.

Chrome/WebKit XHR File Upload

I have searched relentlessly but just can't figure this one out. Why will this XHR connection work perfectly fine in Firefox but breaks in Chrome? I'm using this in conjunction with AngularJS, by the way.
$scope.upload = function(project, file) {
var formData = new FormData(); //Not really sure why we have to use FormData(). Oh yeah, browsers suck.
formData.append('', file.file); //The real file object is stored in this file container
file.xhr = new XMLHttpRequest();
file.xhr.open('PUT', '/api/projects/'+project._id+'/files', true);
//Progress event listener
file.xhr.upload.onprogress = function(event) {
if(event.lengthComputable) {
file.uploadPercent = Math.round(event.loaded / event.total * 100);
}
};
//Upload complete listener
file.xhr.upload.onload = function(event) {
file.uploaded = true;
};
//Every time the status changes
file.xhr.onreadystatechange = function(event) {
if(event.target.readyState == 4) {
//The file has been added, so tag the ID onto the file object
console.log(event.target.responseText);
file._id = JSON.parse(event.target.responseText)._id;
} else {
return;
}
};
file.xhr.send(formData);
};
In Firefox, the file is sent just fine to my server, and the responseText is returned exactly like I'd expect. However, in Chrome, I get this error: Error: INVALID_STATE_ERR: DOM Exception 11
Error: An attempt was made to use an object that is not, or is no longer, usable., which would be more helpful if it told me exactly what object was attempted to be used. I've read here that I should try to set async to false and use onreadystatechange, but I'm not sure how that helps, since I'm already using onreadystatechange.
Bug from 2009: XMLHttpRequest doesn't work while submitting a form - https://bugs.webkit.org/show_bug.cgi?id=23933

AJAX polling and looping

My project is basically like a Reddit feed that updates in real-time. I'm trying to use AJAX to poll the server at intervals for updates on 15 items at a time.
I wrote a for loop but it caused the browser to lock up (I'm guessing too many XHRs?).
How can I poll each item on the Reddit-esque feed without locking up the browser? What is the most efficient way to do this?
Should I use long-polling if there are 100+ clients using the web app at the same time? Or should I opt for smart polling (increasing the wait time between requests if no data)?
Thanks! I'm still new to AJAX!
for (var i=0; i < id_array_len; i++) {
// Grab current reply count
var reply = $("#repl"+item_id).html();
var url= *php function here*
var ajaxRequest;
try{
// Opera 8.0+, Firefox, Safari
ajaxRequest = new XMLHttpRequest();
} catch (e){
// Internet Explorer Browsers
try{
ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try{
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e){
// Something went wrong
alert("Your browser does not support AJAX!");
return false;
}
}
}
ajaxRequest.onreadystatechange = function(){
if (ajaxRequest.readystate == 4){
live_feed_data_tot = ajaxRequest.responseText;
if (live_feed_data_tot.trim() == "no change" || live_feed_data_tot.trim() == "no meme" || live_feed_data_tot.trim() == "no response"){
console.log("(no update)");
} else {
var live_feed_data = live_feed_data_tot.split(',');
if (live_feed_data[1] == 'reply') {
// Reply count has changed
new_reply = live_feed_data[0].trim();
// Update actual number
$("#repl"+item_id).html(new_reply);
}
}
}
}
ajaxRequest.open('POST', url, true);
ajaxRequest.send();
Use longpolling with a long (appropriate for your app of course) timeout. Your call needs to be asynchronous of course. As long as there is no data to deliver, the server holds the answer back, until the timeout is about to be reached. As soon as the client gets an answer, trigger the next longpoll in your complete()-Block. This way you can minimize the number of requests.
EDIT: after seeing your code i see you use native ajax but use jQuery for selecting. I suggest you to use jQuery for your ajax requests as well (jQuery .ajax() Doku).
Your code should look something like this:
function doAjaxLongpollingCall(){
$.ajax({
url: "...",
timeout: <prettylong>,
success: function(){
//process your data
},
complete: function(){
doAjaxLongpollingCall();
}
});
}
If you are doing a lot of users, switch to socket.io and save yourself the hassle. It uses websockets (which use a push mechanism) and does fallbacks to other mechanisms like flash sockets or long polling if thats not available in the browser. Requires you to create this piece of your app in node.js though.

Categories

Resources