Websocket saturation in Chrome, blob points to data which does not exist - javascript

I've got one of this very difficult to debug problems in my app.
I'm using websockets to receive images from my server. I'm getting around 50 images per second in binary and showing them in a canvas as image.
Everything works ok, but sometimes I'm getting an error:
FileReader error. Name: NotFoundError Message: A requested file or directory could not be found at the time an operation was processed.
My code looks like this:
wsVisualizerManager.onMessage = function(e)
{
if (e.data instanceof Blob)
{
var blob = e.data;
this.reader.readAsArrayBuffer(blob);
}
}
Basically I get a blob and I read it with a FileReader object (this.reader) to be able to visualize it as an image.
As I said everything works, but sometimes, seems that due to receive more images that the ones it can handle I start getting this error.
When I start getting this error I don't get it once, I get it many times, so my app is blocked during a lot of time. If I launch chrome development tools the error stops immediately and my app works again (so maybe this developer tool is cleaning some buffers?).
So, I guess that It is some kind of buffer which get completely full, but the think is that If I have to lose old messages I'm ok with that, but why calling onMessage with a bad formated or inexistent blob?
I don't know exactly how to debug this error, because websocket API has just a few methods and no one allows me to access a buffer or clean it.
A way of generate this error manually (otherwise I get it just twice a day) is putting one breakpoint just at the beginning of onMessage and wait some time. What happens then is that when I press play I start getting this error and after some seconds I start receiving retarded images. So seems that it's not removing the received images or at least not all of them.
I'm developing the server part too. And I'm using C++ with the library websocket++. And my chrome version is: 43.0.2357.125 (64-bit)
Any clue of how to proceed debugging this error or trying to solve the problem?

Related

WebAudioAPI decodeAudioData() giving null error on iOS 14 Safari

I have an mp3 audio stream player that works well in every desktop browser, using MediaSourceExtensions with a fallback to WebAudioAPI for those browsers that do not support MSE. iOS Safari is one such browser, and should theoretically support mp3 decoding via the Web Audio API without issues.
I've been struggling to get iOS Safari to properly play the mp3 audio chunks that are being returned from the stream. So far, it's the only browser that seems to have issues and I can't for the life of me figure out what's going on. Sadly, there isn't a whole lot of information on corner cases like this and the other questions here on StackOverflow haven't been any help.
Here's the relevant part of my js code where things are getting hung up. It's a callback function for an async fetch() process that's grabbing the mp3 data from the stream.
async function pushStream(value) {
// Web Audio streaming for browsers that don't support MSE
if (usingWebAudio) {
// convert the stream UInt8Array to an ArrayBuffer
var dataBuffer = value.stream.buffer;
// decode the raw mp3 chunks
audCtx.decodeAudioData(dataBuffer, function(newData) {
// add the decoded data to the buffer
console.log("pushing new audio data to buffer");
webAudioBuffer.push(newData);
// if we have audio in the buffer, play it
if (webAudioBuffer.length) {
scheduleWebAudio();
}
}, function(e) {
console.error(e);
});
What I'm seeing is the error callback being fired and printing null: null as its error message (very helpful). Every so often, I will see the console print pushing new audio data to buffer, but this seems to only happen about once every few minutes while the stream is playing. Almost all the stream data is erroring out during the decode and the lack of useful error messages is preventing me from figuring out why.
As far as I can tell, iOS safari should support mp3 streams without any issues. It also should support the decodeAudioData() function. Most of the other answers I was able to find related to trying to play audio before the user interacts with the screen. In my case, I start the audio using a play button on the page so I don't believe that's the problem either.
One final thing, I'm developing on Windows and using the remotedebug iOS adapter. This could possibly be the reason why I'm not getting useful debug messages, however all other debug and error prints seem to work fine so I don't believe that's the case.
Thanks in advance for any help!
Unfortunately there is a bug in Safari which causes it to reject the decodeAudioData() promise with null. From my experience this happens in cases where it should actually reject the promise with an EncodingError instead.
The bug can be reproduced by asking Safari do decode an image. https://github.com/chrisguttandin/standardized-audio-context/blob/9c705bd2e5d8a774b93b07c3b203c8f343737988/test/expectation/safari/any/offline-audio-context-constructor.js#L648-L663
In general decodeAudioData() can only handle full files. It isn't capable of decoding a file in chunks. The WebCodecs API is meant to solve that but I guess it won't be available on iOS anytime soon.
However there is one trick that works with MP3s because of their internal structure. MP3s are built out of chunks themselves and any number of those chunks form a technically valid MP3. That means you can pre-process your data by making sure that each of the buffers that you pass on to decodeAudioData() begins and ends exactly at those internal chunk boundaries. The phonograph library does for example follow that principle.

How to confirm that file download completed successfully with webextensions?

downloads.download() would seem to be the easiest function to use for non-interactively dowloading & saving files in a webextension. However, it isn't the most-user friendly function in terms of error-handling. If I understand the documentation correctly, it resolves successfully once a download has started--but that doesn't mean that the download will complete successfully. And it only returns the id of the downloadItem object that has started to download, not a pointer to the object itself, which would seem to be what would be the more useful. (To get the object itself, I have been running downloads.search() queries based on the id. This extra step seems inefficient.)
In my tests, I am finding that even in the simple case of trying to download a file when supplying a url that points to a page-not-found (error 404) address, downloads.download() will happily download "a file" and resolve the promise with no error. The downloadItem's status will show "completed," the file will be shown as "exists," and the error status will be "undefined" (if following the change in the downloadItem's properties using an onChanged listener)--but inspection of the contents of the 4kb file that was generated will indicate that it was all just a 404 error.
My current strategy has been to attempt to download a file, wait for a listener to fire on a change to downloads items' statuses, and check the completion-status and errors properties for the downloadItems. But this all just seems hacky and inefficient. And I still haven't figured out the best way to efficiently detect, for example, 404 errors.
Is there an easier way to safely complete file downloads with webextensions that I am missing, maybe some API that I have overlooked?
(I have been trying to do this in Firefox webextensions, but if it's easier with chrome, I will try it that way instead.)

Browser throws error on creating an ObjectURL of an Image Blob after consuming lot of memory

Well, I'm running into a strange Error while programming a Web Application that receives Images from a Server via WebSockets. The Server sends about 8 images per second (.bmp) to the browser. Each image has a size of about 300KB. So that's around 2.4Mbps.
The browser receives the images as binary blob:
//WebSocket
var ws = new WebSocket("ws://192.168.0.10:1337");
//Image
var camImg = new Image();
ws.onmessage = function(msg)
{
var data = msg.data;
// handle binary messages from server
if (data instanceof Blob) camImg.src = window.URL.createObjectURL(data);
};
camImg.onload = function()
{
//draw image to canvas
canvasCont2D.drawImage(this,0,0);
//request next frame
ws.send("give me the next image!");
//delete ObjectURL
window.URL.revokeObjectURL(this.src);
};
So until this point everything runs fine. Now I'm coming for the first problem:
As I was testing this in Chrome I watched at the TaskManager to see how many resources this coding needs. I saw there one process of Chrome that started at about 90MB Memory. Each second there were add 2.4MB. So it looks like every image i receive stays in memory. Is there any possibility to prevent this? The received blobs seem to stay under resources in Chrome developer tools, btw.
Anyway this problem leads me to the second one: The memory consumption of this process rises and rises and after some time at about 400-500MB its kind of flushed and starts again at 90MB, again rising. So long, its just a memory problem. But sometimes it could happen, that the memory is not flushed and rises up to about 600MB. At this point I don't receive any new image. The console shows an error that says:
Failed to load resource: the server responded with a status of 404 (Not Found)
This error occurs in this line:
camImg.src = window.URL.createObjectURL(data);
At the moment I work around this issue by catching the error event:
camImg.onerror = function()
{
//request next frame anyway and wait for memory flush
ws.send("give me the next image!");
};
So I'm just requesting new images because after some time the memory gets flushed again (after a few seconds) and I can receive new Images.
The same problem(s) occure using Opera as well. I guess its mainly a problem with memory consumption. Maybe a bug in browsers? Or did I made a big programming error?
I would be very thankful for any help as I have no idea left, what could be causing this problem...
OS: Windows7 64bit
Chrome Version 35.0.1916.153 m
Chrome Version 38.0.2068.0 canary (64-bit) : (chrome://flags/#impl-side-painting setting makes no difference).
In a prototype I'm doing, I get exactly the same behaviour as this in chrome 35 and a recent canary build. Ok in IE and firefox. I'm running a localhost c++ websocket server about 10fps with 0.5MB images.
The chrome memory eventually goes up and something trashes the chrome too.
Moving forwards:
1) In image.onerror I call window.URL.revokeObjectURL(this.src); This seems to sort my memory leak out, but not the 404's.
2) When running under the F12 debugger things are so slow that I don't seem to get the problem. Thus on page I have 3 counters: 1) Blobs received count, 2) image.onload count and 3) image.onerror count.
After approx 900 successful loads I start getting load failures. then after maybe after 50 failures, I start getting successful loads again. This pattern keeps repeating, but the numbers seem random.( This all seems to smack of some GC related issue, but only a hunch based on experience).
3) I can fix (AKA 'bodge') this by changing ws.binaryType='arraybuffer'. I need a blob so I construct a new one based on a new Uint8Array(msg.data). Everything works fine, no load failures at all.
I'm making an unnecessary binary copy here, but it doesn't seem to make any noticeable speed difference. I'm not 100% sure what's going on here and how stable the fix is.
Most similar image loading examples on the internet don't have an onerror handler. Running such examples on my machine would result in a unexplainable memory leak. You wouldn't see the 404's unless under the debugger and lucky. There's lots of people on the internet complaining about memory leaks when loading images. Maybe it's related.
I'm going to raise this issue on the chromium forums.
hope this helps ... matt

Log JavaScript console into a log file with Firefox

We have a web application which runs in a kiosk mode Firefox, using the RKiosk extension to achieve this. We suspect that we have a very rare error in the system which yields in a JavaScript error. However because we can't access the JavaScript console we can't examine the log.
I'm searching for an option to make Firefox log all JavaScript console messages into a file regardless of the tab and page opened. I can't seem to find any extension for this. I'm already using log4javascript which sends errors back to the server, but it seems that our application crashes in a way that it skips the logging altogether.
Writing to a file sounds like a tedious task to me. It requires privileges that browser code doesn't normally have and you'd have to negotiate with an add-on you'd have to write in order to access file I/O.
From what I understand your issue is
I'd like to make Firefox log all errors
There are several approaches we can do to tackle this
First approach - log everything to localStorage too:
Now, rather than writing to an actual file, you can write to localStorage or IndexedDB instead.
localStorage["myApplog"] = localStorage["myApplog"] || "";
var oldLog = console.log;
console.log = function(){
oldLog.apply(console,arguments); // use the old console log
var message = "\n "+(new Date).toISOString() + " :: "+
Array.prototype.join.call(arguments," , "); // the arguments
localStorage["myApplog"] += message;
}
This is rather dirty and rather slow, but it should get the job done and you can access the log later in local storage. LocalStorage has a ~5MB limit if I recall correctly which I think is enough if you don't go crazy with logging. You can also run it selectively.
Second approach - log only errors
This is similar to what Pumbaa80 suggested. You can simply override window.onerror and only log errors.
// put an empty string in loggedWinErrors first
var oldError = window.onerror || function(){};
window.onerror = function(err,url,lineNumber){
oldError.call(this,err,url,lineNumber);
var err ="\n Error: (file: " + url+", error: "+err+", lineNumber: "+lineNumber+")");
localStorage["loggedWinErrors"] += err;
}
Third and drastic approach - use a VM.
This is the most powerful version, but it provides the most problematic user experience. You run the kiosk in a virtual machine, you detect an uncaught exception - when you do you freeze the machine and save its state, and run a backup VM instead. I've only had to do this when tackling the most fearsome errors and it's not pretty. Unless you really want the whole captured state - don't do this.
Really, do the extension before this - this is tedious but it gets very solid results.
In conclusion, I think the first approach or even just the second one are more than enough for what you need. localStorage is an abstracted storage that web pages get for saving state without security issues. If that's not big enough we can talk about an IndexedDB solution.
It all really depends on the use case you have.
You can use XULRunner...a Mozilla runtime environment for XUL applications. It uses Gecko like Firefox and:
You can access the file system or using the SQLite database to store logs.
You can render your kiosk in fullscreen mode without using extensions.
Have you tried jserrorcollector? We are using it and it works fine (only in Firefox). It's only for Java.
// Initialize
FirefoxProfile ffProfile = null;
ffProfile = new FirefoxProfile();
JavaScriptError.addExtension(ffProfile);
// Get the errors
List<JavaScriptError> jsErrors = JavaScriptError.readErrors(webDriver);
More information: https://github.com/mguillem/JSErrorCollector
Have you considered remote logging?
I commonly assign window.onerror to do send a request to a webserver storing the details of the error remotely. You could do the same with console.log if you preferred.
Try the following console export. It is a plugin for Firebug of Firefox. It's quite handy.
http://www.softwareishard.com/blog/consoleexport/
If you are able/willing to switch from Firefox to Chrome or Opera you would be able to use the Sandboxed Filesystem API to write a local file. See:
http://www.html5rocks.com/en/tutorials/file/filesystem/
http://caniuse.com/filesystem
Start in kiosk mode using chrome.exe --kiosk <url>
You would then want to disable Alt-F4 and Ctrl-Alt-Del which on Windows can be done with several third-party tools like Auto Hotkey (Disable Ctrl-Alt-Del Script).
You could use a remote logging script like Qbaka. It catches every JS error and sends it to the Qbaka server. There you can login and see all JS errors. Qbaka stores the exact error message, the script, line number, stack trace and the used browser for each error message.

DOM Exception 12 when trying to stream MP3 through websocket

I am currently working on a small project where I want to split an mp3 into frames, send them to a client (browser) through a websocket and then play them back using WebAudio (webkitAudioContext). My server is running nodejs and to transfer the data as binary, I use binaryJS. The browser I am testing with is Chrome 25.0.1354.0 dev, running on Ubuntu 12.04.
I have gotten as far as successfully splitting the mp3 into frames, or, at least, based on my tests, it seems to work. If I write the frames back into a file, mplayer has no problem playing back the file and also parses the header correctly. Each frame is stored in a nodejs Buffer of the correct size and the last byte of the buffer is always the first byte before the next sync word.
As an initial test, I am only sending the first MP3 frame. The client receives the frame successfully (stored in an ArrayBuffer), and the buffer contains the correct data. However, when I call decode, I get the following message:
Uncaught Error: SyntaxError: DOM Exception 12
My function, where I call decodeAudio, looks like this:
streamDone = ->
bArray = new Uint8Array(arr[0].byteLength)
console.log "Stream is done, bytes", bArray.length
context.decodeAudioData bArray, playAudio, err
The initial frame that I am trying to deocde, can be found here.
I have been banging my head in the wall for a couple of days now trying to solve this. Has anyone managed to solve this and sucessfully decoded mp3 frames, and see what I do wrong? I have found two related question on StackOverflow, but the answers did not help me solve my problem. However, according to the accepted answer here, my frame should qualify as a valid mp3 chunk and, thus, be decoded.
Thanks in advance for any help!
Turns out that a break and some fresh eyes can work wonders, a general code cleanup solved the issue. If anyone is interested in the code, I published it here.

Categories

Resources