I have a very simple application I am making that needs to load 30 second m4a files from a couch server. I am able to receive the files but can not get them to load in a player. The files are uploaded through Fauxton and have been deleted and reuploaded to be sure the issue was not in the upload.
I have also loaded the object url into a link and tried to download the file which can not be played.
I have tried both using the source directly in the audio tag as well as adding the source tag.
I have tested the files in the audio player and they work fine locally.
I think I there is something wrong with the way I am creating the blob or url.
<audio controls id="mediaPlayer"></audio>
var db = new PouchDB('http://user:password#localhost:5984/music');
db.get('9d3f17d01be8283c461eaa01940329b4', { attachments:true } ).then(function (doc){
// Load first file
var media = Object.values(doc._attachments)[0];
// Get Player
var player = document.getElementById('mediaPlayer');
// Create blob from data - media content type is
var blob = new Blob([ media.data ], { type: media.content_type });
// Create url from blob
var afile = URL.createObjectURL(blob);
// Set source and load
player.src = afile;
player.load();
});
I solved my own issue. This was a complete oversight on my end. Fauxton uploads all attachments as Base64 not blobs. I had to simply decode the data before converting it to a blob. I am using node so I used buffer to decode the string before creating the blob.
If you are using raw vanilla js you should be able to use atob(media.data) in place of the buffer, but I did not test it.
import { Buffer } from 'buffer';
var db = new PouchDB('http://user:password#localhost:5984/music');
db.get('9d3f17d01be8283c461eaa01940329b4', { attachments:true } ).then(function (doc){
// Load first file
var media = Object.values(doc._attachments)[0];
// Get Player
var player = document.getElementById('mediaPlayer');
// Remove Encoding
var raw = Buffer.from(media.data, 'base64');
// Create blob from data
var blob = new Blob([ raw ], { type: media.content_type });
// Create url from blob
var afile = URL.createObjectURL(blob);
// Set source and load
player.src = afile;
player.load();
});
Related
I am trying to work with the Google Cloud Speech API to transcribe the audio to text. I have a working prototype where I have a mp3/wav (prerecorded) file that is correct and accepted by the API to do the request when it is sent as base64 format. However the problem I am having now is, that in an other prototype where I capture the sound from the user (client-side) and save it as mp3/wav, the base64 doesn't correspond with the file-type (it sees it as video/webm instead of audio/mp3 / audio/x-wav).
Sidenote: The audio recordings are fine and playable.
Tried saving the blob file as mp3
Tried recorder.js
const mime = ['audio/wav', 'audio/mpeg', 'audio/webm', 'audio/ogg']
.filter(MediaRecorder.isTypeSupported)[0];
const mediaRecorder = new MediaRecorder(mediaStreamObj, {
mimeType: mime
});
//the stop event
mediaRecorder.onstop = (ev)=>{
let blob = new Blob(chunks, { type : 'audio/mp3;' });
chunks = [];
let audioURL = window.URL.createObjectURL(blob);
audioSave.src = audioURL;
}
I expect to have a file with the filetype/mimetype audio/mp3 and not video/webm
I'm using the getUserMedia API to allow a user to record a short Audio clip on the client. After finishing the recording, I initialize a FileReader, create a Blob from all the Audio chunks, and read the reader of the blob as a DataURL. That gets appended as Text to a webform that's then sent to a Rails5 API, where I'm having a very difficult time converting the Binary Audio into a working .mp3 file.
Here is what the code looks like:
When the recorder goes inactive, the chunks are collected and used to instantiate a new Blob with the type 'audio/mpeg'.
var chunks = [];
if (recorder.state == 'inactive') {
var blob = new Blob(chunks, { type: 'audio/mpeg' });
App.mediaStream.encodeBase64(blob);
}
The Blob is then passed to a function that creates a base64 encoded DataURL.
encodeBase64: function(blob) {
var reader = new FileReader();
reader.onloadend = function() {
App.mediaStream.appendToForm(reader.result);
};
reader.readAsDataURL(blob);
},
The result from the reader is a dataURL that follows this pattern, data:[type];base64,[data] - so it's a String that looks like:
"data:audio/mpeg;base64,GkXfo59ChoEBQveBAULygQRC84EIQoKEd2VibUKHgQRChYECGFOAZwH/////////FUmpZpkq17GDD0JATYCGQ2hyb21lV0GGQ2hyb21lFlSua7uuudeBAXPFh+bmBbc......."
I'm appending this DataURL to a form, that sends it to my Rails 5 API along with some other data. Here is where I'm running into trouble. On the server side, I have a ruby method that parses the dataURL, and writes it to a file as so:
def binary_to_audio_file(dataURL)
data = dataURL.split(',').last
filename = SecureRandom.hex
File.open("public/#{filename}.mp3", 'wb') do |f|
f.write Base64.decode64(data)
end
end
This is successfully creating a new file in the specified directory that has the decoded audio binary written to the file. That file can be opened by QuickTime, Itunes, or any other media play. It even plays for the same duration that the recording lasted. HOWEVER, there is NO sound.
I promise my speakers are not turned off... any hints?
I'm generating a PDF using the PDFKit library and I would like to insert the generated PDF into a MongoDB collection. On the client side a user should be able to see the list of files in the collection and choose one of these files to download.
As of now I'm saving the PDF in the collection as a Uint8Array and I can then click on the file at the front end to download it.
However, my problem is that the file seems to be corrupt. It will not open in Adobe Reader or in Chrome.
I've tried saving it to the collection with and without PDFKits compression.
Is this possible to do? Or do I have a bad approach to this.
Any help with this would be great and thanks in advance!
Server Side
Most of the code here is based off of this post on the PDFKit GitHub
var doc = new PDFDocument();
var stream = require('stream');
var converter = new stream.PassThrough();
doc.pipe(converter);
var data = [];
converter.on('data', function(chunk) {
data.push(chunk);
});
converter.on('end', Meteor.bindEnvironment( function () {
var buffer = Buffer.concat(data);
PdfFiles.insert({ data:buffer, userID:userId });
}));
// Adding content to the PDF
doc.end();
Client Side
'click .downloadPDF': function (event) {
event.preventDefault();
var file = UserFiles.findOne({userID:Meteor.userId()});
var FileSaver = require('file-saver');
var blob = new Blob(file.data, {type: "application/pdf"});
FileSaver.saveAs(blob, "AwesomePDF");
}
I got the code to work as intended simply by changing:
var blob = new Blob(file.data, {type: "application/pdf"});
to
var blob = new Blob([file.data], {type: "application/pdf"});
So I have a website (using AngularJS) that lets users upload files via tag
<input type="file" ng-model="image" id="trigger" onchange="angular.element(this).scope().setFile(this)" accept="image/*">
When I handle the upload in the controller the image gets stored as a File object. This is my method that saves the file and also sets variables to preview the image
$scope.setFile = function (element) {
$scope.image = element.files[0]; // This is my image as a File
var reader = new FileReader();
//This is for previewing the image
reader.onload = function (event) {
$scope.image_source = event.target.result;
$scope.$apply();
}
reader.readAsDataURL(element.files[0]);
}
Now I am trying to compress the image using J-I-C library found here: https://github.com/brunobar79/J-I-C/blob/master/src/JIC.js
But this library accepts an image object as its parameter and returns it as a compressed image object. I can't seem to find a way to convert my $scope.image File object into an Image object. How would I go about doing this?
I would also need to convert the compressed image object back into a File so I can upload it to my Azure storage.
You just need to create an Image instance, and set it's src to your data url. Then pass it to JIC:
var img = new Image();
img.src = $scope.image_source;
jic.compress(img,...)
It then just uses a canvas element to manipulate the image, generate a new data url, and creates a new Image instance, setting its src to the data url. So when you get the compressed image back just take the src and use atob to decode the base64 encoded data back into binary and create a Blob. You can use Blob in most places that you would use File, for instance like uploading through ajax.
var newImg = jic.compress(oldImg,...);
//replace 'image/png' with the proper image mime type
var base64data = newImg.src.replace("data:image/png;base64,","");
var bs = atob(base64data);
var buffer = new ArrayBuffer(bs.length);
var ba = new Uint8Array(buffer);
for (var i = 0; i < bs.length; i++) {
ba[i] = bs.charCodeAt(i);
}
var blob = new Blob([ba],{type:"image/png"});
//now use blob like you would any other File object
I am trying to upload a video to server, and on client end. I am reading it using FileReader's readAsBinaryString().
Now, my problem is, I don't know how to read duration of this video file.
If i try reading the file, and assigning the reader's data to a video tag's source, then none of the events associated to the video tag are fired. I need to find the duration of file uploaded on client end.
Can somebody please suggest me something?
You can do something like this for that to work:
read the file as ArrayBuffer (this can be posted directly to server as a binary stream later)
wrap it in a Blob object
create an object URL for the blob
and finally set the url as the video source.
When the video object triggers the loadedmetadata event you should be able to read the duration.
You could use data-uri too, but notice that browsers may apply size limits (as well as other disadvantages) for them which is essential when it comes to video files, and there is a significant encoding/decoding overhead due to the Base-64 process.
Example
Select a video file you know the browser can handle (in production you should of course filter accepted file types based on video.canPlayType()).
The duration will show after the above steps has performed (no error handling included in the example, adjust as needed).
var fileEl = document.querySelector("input");
fileEl.onchange = function(e) {
var file = e.target.files[0], // selected file
mime = file.type, // store mime for later
rd = new FileReader(); // create a FileReader
rd.onload = function(e) { // when file has read:
var blob = new Blob([e.target.result], {type: mime}), // create a blob of buffer
url = (URL || webkitURL).createObjectURL(blob), // create o-URL of blob
video = document.createElement("video"); // create video element
video.preload = "metadata"; // preload setting
video.addEventListener("loadedmetadata", function() { // when enough data loads
document.querySelector("div")
.innerHTML = "Duration: " + video.duration + "s"; // show duration
(URL || webkitURL).revokeObjectURL(url); // clean up
// ... continue from here ...
});
video.src = url; // start video load
};
rd.readAsArrayBuffer(file); // read file object
};
<input type="file"><br><div></div>
you can do something like below, the trick is to use readAsDataURL:
var reader = new FileReader();
reader.onload = function() {
var media = new Audio(reader.result);
media.onloadedmetadata = function(){
media.duration; // this would give duration of the video/audio file
};
};
reader.readAsDataURL(file);
Fiddle Demo