Whenever I run this code
var blob = new Blob(["ninja.mp3"], {type:"audio/mp3"});
var audio = new Audio(URL.createObjectURL(blob));
audio.play().catch(err => console.log(err));
I am given the following error
DOMException index.html:3
I expect it to play the audio file ninja.mp3 but instead I'm faced with this error. Any help would be greatly appreciated.
When you do
var blob = new Blob(["ninja.mp3"], {type:"audio/mp3"});
What you just created is a Binary file in your browser's memory which holds the USVString ninja.mp3, and for which the browser will send a Content-Type: audio/mp3 header in some network actions.
Id est, you just created an UTF-8 text file. And yes, the MediaElement is not able to read that.
var blob = new Blob(["ninja.mp3"], {type:"audio/mp3"});
// read as text
new Response(blob).text().then(console.log);
For a comparison, here is what a real mp3 file looks like when read as text:
fetch("https://dl.dropboxusercontent.com/s/agepbh2agnduknz/camera.mp3")
.then(resp => resp.text())
.then(console.log)
Blob constructor doesn't expect an URL, but a list of Blob parts (which are either USVStrings, Blobs or ArrayBuffers), but in no way will it ever fetch anything.
So what you want seems to be as simple as
var audio = new Audio("ninja.mp3");
audio.play().catch(console.log);
But if one day you need to build a Blob (which you don't now), then be sure that what you pass in the Blob() constructor is actually the binary content of your file.
The DOMException interface represents an abnormal event (called an exception) which occurs as a result of calling a method or accessing a property of a web API. This is basically how error conditions are described in web APIs.
I think you call the method wrongly. Pls Check it.
Related
I am trying to record and upload audio from javascript. I can successfullly record audio Blobs from a MediaRecorder. My understanding is that after recording several chunks into blobs, I would concatenate them as a new Blob(audioBlobs) and upload that. Unfortunately, the result on the server-side keeps being more or less gibberish. I'm currently running a localhost connection, so converting to uncompressed WAV isn't a problem (might be come one later, but that's a separate issue). Here is what I have so far
navigator.mediaDevices.getUserMedia({audio: true, video: false})
.then(stream => {
const mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start(1000);
const audioChunks = [];
mediaRecorder.addEventListener("dataavailable", event => {
audioChunks.push(event.data);
});
function sendData () {
const audioBlob = new Blob(audioChunks);
session.call('my.app.method', [XXXXXX see below XXXXXX])
}
})
The session object here is an autobahn.js websockets connection to a python server (using soundfile. I tried a number of arguments in the place that was labelled by XXXXX in the code.
Just pass the audioBlob. In that case, the python side just receives an empty dictionary.
Pass audioBlob.text() in that case, I get something that looks somewhat binary (starts with OggS), but it can't be decoded.
Pass audioBlob.arrayBuffer(). In that case the python side receives an empty dictionary.
A possible solution could be to convert the data to WAV on the serverside (just changing the mime-type on the blob doesn't work) or to find a way to interpret the .text() output on the server side.
The solution was to use recorder.js and then use the getBuffer method in there to get the wave data as a Float32Array.
I have a problem (or may be two) with saving files using HTML5 File API.
A files comes from the server as a byte array and I need to save it. I tried several ways described on SO:
creating blob and opening it in a new tab
creating a hidden anchor tag with "data:" in href attribute
using FileSaver.js
All approaches allow to save the file but with breaking it by changing the encoding to UTF-8, while the file (in current test case) is in ANSI. And it seems that I have to problems: at the server side and at the client side.
Server side:
Server side is ASP.NET Web API 2 app, which controller sends the file using HttpResponseMessage with StreamContent. The ContentType is correct and corresponds with actual file type.
But as can be seen on the screenshot below server's answer (data.length) is less then actual file size calculated at upload (file.size). Also here could be seen that HTML5 File object has yet another size (f.size).
If I add CharSet with value "ANSI" to server's response message's ContentType property, file data will be the same as it was uploaded, but on saving result file still has wrong size and become broken:
Client side:
I tried to set charset using the JS File options, but it didn't help. As could be found here and here Eli Grey, the author of FileUplaod.js says that
The encoding/charset in the type is just metadata for the browser, not an encoding directive.
which means, if I understood it right, that it is impossible to change the encoding of the file.
Issue result: at the end I can successfully download broken files which are unable to open.
So I have two questions:
How can I save file "as is" using File API. At present time I cannot use simple way with direct link and 'download' attribute because of serverside check for access_token in request header. May be this is the "bottle neck" of the problem?
How can I avoid setting CharSet at server side and also send byte array "as is"? While this problem could be hacked in some way I guess it's more critical. For example, while "ANSI" charset solves the problem with the current file, WinMerge shows that it's encoding is Cyrillic 'Windows-1251' and also can any other.
P.S. the issue is related to all file types (extensions) except *.txt.
Update
Server side code:
public HttpResponseMessage DownloadAttachment(Guid fileId)
{
var stream = GetFileStream(fileId);
var message = new HttpResponseMessage(HttpStatusCode.OK);
message.Content = new StreamContent(stream);
message.Content.Headers.ContentLength = file.Size;
message.Content.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType)
{
// without this charset files sent with bigger size
// than they are as shown on image 1
CharSet = "ANSI"
};
message.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = file.FileName + file.Extension,
Size = file.Size
};
return message;
}
Client side code (TypeScript):
/*
* Handler for click event on download <a> tag
*/
private downloadFile(file: Models.File) {
var self = this;
this.$service.downloadAttachment(this.entityId, file.fileId).then(
// on success
function (data, status, headers, config) {
var fileName = file.fileName + file.extension;
var clientFile = new File([data], fileName);
// here's the issue ---^
saveAs(clientFile, fileName);
},
// on fail
function (error) {
self.alertError(error);
});
}
My code is almost the same as in answers on related questions on SO: instead of setting direct link in 'a' tag, I handle click on it and download file content via XHR (in my case using Angularjs $http service). Getting the file content I create a Blob object (in my case I use File class that derives from Blob) and then try to save it using FileSaver.js. I also tried approach with encoded URL to Blob in href attribute, but it only opens a new tab with a file broken the same way. I found that the problem is in Blob class - calling it's constructor with 'normal' file data I get an instance with 'wrong' size as could be seen on first two screenshots. So, as I understand, my problem not in the way I try to save my file, but in the way I create it - File API
I am reading a local CSV file using a web UI, and the HTML5 FileReader interface to handle the local file stream. This works great.
However, sometimes I want the file being read to be updated continuously, after the initial load. I am having problems, and I think it might have something to do with the FileReader API. Specifically, after the initial file load, I maintain a reference to the file. Then, when I detect that the size of the file has increased, I slice off the new part of the file, and get a new Blob object. However, there appears to be no data in these new Blobs.
I am using PapaParse to handle the CSV parsing, though I don't think that is the source of the problem (though it may be).
The source code is too voluminous to post here, but here is some pseudocode:
var reader = new FileReader();
reader.onload = loadChunk;
var file = null;
function readLocalFile(event) {
file = event.target.files[0];
// code that divides file up into chunks.
// for each chunk:
readChunk(chunk);
}
function readChunk(chunk) {
reader.readAsText(chunk);
}
function loadChunk(event) {
return event.target.result;
}
// this is run when file size has increased
function readUpdatedFile(oldLength, newLength) {
var newData = file.slice(oldLength, newLength);
readChunk(newData);
}
The output of loadChunk when the file is first loading is a string, but after the file has been updated it is a blank string. I am not sure if the problem is with my slice method, or if there is something going on with FileReader that I am not aware of.
The spec for File objects shouldn't allow this: http://www.w3.org/TR/FileAPI/#file -- it's supposed to be like a snapshot.
The fact that you can detect that the size has changed is probably a shortcoming of an implementation.
I've searched related questions but wasn't able to find any relevant info.
I'm trying to get the Web Audio API to play an mp3 file which is encoded in another file container, so what I'm doing so far is parsing said container, and feeding the result binary data (arraybuffer) to the audioContext.decodeAudioData method, which supposedly accepts any kind of arraybuffer containing audio data. However, it always throws the error callback.
I only have a faint grasp of what I'm doing so probably the whole approach is wrong. Or maybe it's just not possible.
Has any of you tried something like this before? Any help is appreciated!
Here's some of the code to try to illustrate this better. The following just stores the arraybuffer:
newFile: function(filename){
var that=this;
var oReq = new XMLHttpRequest();
oReq.open("GET", filename, true);
oReq.responseType = "arraybuffer";
oReq.onload = function (oEvent) {
var arrayBuffer = oReq.response; //
if (arrayBuffer) {
that.arrayBuffer=arrayBuffer;
that.parsed=true;
}
};
oReq.send(null);
And this is what I'm doing in the decoding part:
newTrack: function(tracknumber){
var that=this;
var arraybuffer=Parser.arrayBuffer;
that.audioContext.decodeAudioData(arraybuffer,function(buffer){
var track={};
track.trackBuffer=buffer;
track.isLoaded=true;
track.trackSource=null;
track.gainNode=that.audioContext.createGainNode();
that.tracklist.push(track);
},alert('error'));
Where Parser is an object literal that I've used to parse and store the arraybuffer (which has the newFile function)
So, to sum up, I don't know if I'm doing something wrong or it simply cannot be done.
Without the container, I'm not sure how decodeAudioData would know that it's an MP3. Or what the bitrate is. Or how many channels it has. Or a lot of other pretty important information. Basically, you need to tell decodeAudioData how to interpret that ArrayBuffer.
The only thing I could think of on the client side is trying to use a Blob. You'd basically have to write the header yourself, and then readAsArrayBuffer before passing it in to decodeAudioData.
If you're interested in trying that out, here's a spec:
http://www.mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm
And here's RecorderJS, which would show you how to create the Blob (although it writes RIFF/WAV headers instead of MP3):
https://github.com/mattdiamond/Recorderjs/blob/master/recorderWorker.js
You'd want to look at the encodeWAV method.
Anyway, I would strongly recommend getting this sorted out on the server instead, if you can.
I want to use the HTML5 FileApi to read a SWF to an OBJECT (or EMBED, if it's better to do?).
My current code crashes on Chrome/Iron (the only stable browser which also supports the xmlhttprequest v2 FormData). I got it to read image data into a on-the-fly created IMG. But the object one crashes the current tab in the browser.
else if (file.type == "application/x-shockwave-flash") {
var show = document.createElement("object");
show.type = "application/x-shockwave-flash"
show.style.width = "100%";
show.style.height = "100%";
show.id = "thumb";
document.getElementById("thumbnails").appendChild(show);
var reader = new FileReader();
reader.onload = (function (aImg) {
return function (e) { aImg.data = e.target.result; };
})(show);
reader.readAsDataURL(file);
Do I really read to the object.data part? How is it done right? Anybody know? Or is this incomplete and I have to wait for better implementation?
A few things I'd recommend trying (in order of increasing complexity):
base64 encode the data with btoa and set it using a data: URI,
instead of creating the object using createElement, construct the <object> tag with all attributes as an HTML string (including the base64 advice above), then inject it into a DOM element with innerHTML,
create a reflector web service where you POST the swf content, it gives you a URL, then pass the URL off to the object,
similar to the previous, create a reflector web service where you POST the swf content, targeting a full-screen IFRAM as the target, have the service spits back an HTML doc including an <object> pointing back to the server.
The later of these options is more intense, and requires round-trips from the server that you'd probably want to avoid - just some more options you might want to consider.
ActionScript 3 has a Loader which may be useful as well. I don't know if it supports data: URI's, but if it does, you could write a boot loader SWF which runs the contents of the local swf file directly.