webrtc audio record to python - javascript

I'm trying to record audio but the files as they are stored on server are only 10kb or less.
The file is being saved to server, and has the correct name, but is 10 kb or less.
In the browser the audio file is capable of being reviewed and plays as expected.
Server side python code:
def save_file(file, filename, path=''):
''' Little helper to save a file
'''
fd = open('%s/%s' % ('/root/ws911/media/', str(path) + str(filename)), 'wb')
#for chunk in file.chunks():
# fd.write(chunk)
fd.write(file)
fd.close()
JavaScript code excerpts:
// PostBlob method uses XHR2 and FormData to submit
// recorded blob to the PHP server
function PostBlob(blob, fileType, fileName) {
// FormData
var formData = new FormData();
formData.append(fileType + '-filename', fileName);
formData.append(fileType + '-blob', blob);
// POST the Blob using XHR2
xhr('xxxxxxxxxxxxxx/get_json/', formData, function(fileURL) {
});
}
var container = document.getElementById('container');
// var legalBufferValues = [256, 512, 1024, 2048, 4096, 8192, 16384];
// sample-rates in at least the range 22050 to 96000.
recordAudio = RecordRTC(stream, {
//bufferSize: 16384,
//sampleRate: 45000,
onAudioProcessStarted: function() {
if (!isFirefox) {
recordVideo.startRecording();
}
}
});
recordAudio.startRecording();
stop.disabled = false;
},
function(error) {
alert(JSON.stringify(error, null, '\t'));
});
};
var fileName;
stop.onclick = function() {
record.disabled = false;
stop.disabled = true;
preview.src = '';
fileName = Math.round(Math.random() * 99999999) + 99999999;
recordAudio.stopRecording(function(url) {
preview.src = url;
PostBlob(recordAudio.getBlob(), 'video', fileName + '.webm');
});
function xhr(url, data, callback) {
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
callback(request.responseText);
}
};

Related

Generate Zip file contain list of Files without JSZip library

Hello Developers,
I'm trying to download the list of files getting form XMLHttpRequest() request method and store it in the array of files. I wanted to zip all the files in an array using javascript without using any 3rd party library.
I have tried to achieve this by URL.createObjectURL(url) and URL.revokeObjectURL(url) method but the file I'm getting is corrupted.
I'm Sharing my code snippet please help me out
const URLS = [
'https://vr.josh.earth/assets/2dimages/saturnv.jpg',
'https://vr.josh.earth/assets/360images/hotel_small.jpg',
'https://vr.josh.earth/assets/360images/redwoods.jpg'
];
$(document).ready(function () {
debugger
$("#downloadAll").click(function () {
var blob = new Array();
var files = new Array();
URLS.forEach(function (url, i) {
getRawData(url, function (err, data) {
debugger
var mydata = data;
// mydata = btoa(encodeURIComponent(data));
// var blobData = b64toBlob(mydata , 'image/jpg');
var blobData = new Blob([mydata], { type: 'image/jpg' });
blob.push(blobData);
var filename = "testFiles" + i + ".jpg";
var file = blobToFile(blobData, filename);
files.push(file);
debugger
if (files.length == URLS.length) {
// saveData(blob, "fileName.zip");
var AllBlobData = new Blob([blob], { type: 'application/zip' });
saveData(AllBlobData, "Test.zip");
// saveFile("DownloadFiles.zip", "application/zip", files)
}
});
});
});
});
//Retriving record using XMLHttpRequest() method.
function getRawData(urlPath, callback, progress) {
var request = new XMLHttpRequest();
request.open("GET", urlPath, true);
request.setRequestHeader('Accept', '');
if ('responseType' in request)
request.responseType = "arraybuffer"
if (request.overrideMimeType)
request.overrideMimeType('text/plain; charset=x-user-defined');
request.send();
var file, err;
request.onreadystatechange = function () {
if (this.readyState === 4) {
request.onreadystatechange = null;
if (this.status === 200) {
try {
debugger
var file = request.response || request.responseText;
} catch (error) {
throw error;
}
callback(err, file);
} else {
debugger
callback(new Error("Ajax Error!!"))
}
} else {
debugger
}
}
}
//For Saving the file into zip
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
// var AllBlobs = new Blob([data], { type: "" });//application/zip //octet/stream
// var url = window.URL.createObjectURL(AllBlobs);
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
//Downloaded Zip File
enter image description here

Get Byte Position during Upload Loop

I am working on a function that will write data to a remote server in chunks using a 3rd party API. Through some help on Stack Overflow I was able to accomplish this, where it is now working as expected. The problem is that I can only get a single 16kb chunk to write as I will need to advance the pos of where the next bytes are written to.
The initial write starts at 0 easily enough. Due to my unfamiliarity with this though, I am unsure if the next pos should just be 16 or what. If it helps, the API call writeFileChunk() takes 3 parameters, filepath (str), pos (int64), and data (base64 encoded string).
reader.onload = function(evt)
{
// Get SERVER_ID from URL
var server_id = getUrlParameter('id');
$("#upload_status").text('Uploading File...');
$("#upload_progress").progressbar('value', 0);
var chunkSize = 16<<10;
var buffer = evt.target.result;
var fileSize = buffer.byteLength;
var segments = Math.ceil(fileSize / chunkSize); // How many segments do we need to divide into for upload
var count = 0;
// start the file upload
(function upload()
{
var segSize = Math.min(chunkSize, fileSize - count * chunkSize);
if (segSize > 0)
{
$("#upload_progress").progressbar('value', (count / segments));
var chunk = new Uint8Array(buffer, count++ * chunkSize, segSize); // get a chunk
var chunkEncoded = btoa(String.fromCharCode.apply(null, chunk));
// Send Chunk data to server
$.ajax({
type: "POST",
url: "filemanagerHandler.php",
data: { 'action': 'writeFileChunk', 'server_id': server_id, 'filepath': filepath, 'pos': 0, 'chunk': chunkEncoded },
dataType: 'json',
success: function(data)
{
console.log(data);
setTimeout(upload, 100);
},
error: function(XMLHttpRequest, textStatus, errorThrown)
{
alert("Status: " + textStatus); alert("Error: " + errorThrown); alert("Message: " + XMLHttpRequest.responseText);
}
});
}
else
{
$("#upload_status").text('Finished!');
$("#upload_progress").progressbar('value', 100);
getDirectoryListing(curDirectory);
}
})()
};
The current position for the file on client side would be represented by this line, or more specifically the second argument at the pre-incremental step:
var chunk = new Uint8Array(buffer, count++ * chunkSize, segSize);
though, in this case it advances (count++) before you can reuse it so if you need the actual position (below as pos) you can extract it by simply rewriting the line into:
var pos = count++ * chunkSize; // here chunkSize = 16kb
var chunk = new Uint8Array(buffer, pos, segSize);
Here each position update will increment 16kb as that is the chunk-size. For progress then it is calculated pos / fileSize * 100. This of course assuming using the unencoded buffer size.
The only special case is the last chunk, but when there are no more chunks left to read the position should be equal to the file length (fileSize) so it should be pretty straight-forward.
When the ajax call return the server should have the same position unless something went wrong (connection, write access change, disk full etc.).
You can use Filereader API to read the chunks and send it to your remote server.
HTML
<input type="file" id="files" name="file" /> Read bytes:
<span class="readBytesButtons">
<button>Read entire file in chuncks</button>
</span>
Javascript
// Post data to your server.
function postChunk(obj) {
var url = "https://your.remote.server";
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('post', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
resolve(xhr.response);
} else {
reject(status);
}
};
var params = "";
// check that obj has the proper keys and create the url parameters
if (obj.hasOwnProperty(action) && obj.hasOwnProperty(server_id) && obj.hasOwnProperty(filepath) && obj.hasOwnProperty(pos) && obj.hasOwnProperty(chunk)) {
params += "action="+obj[action]+"&server_id="+obj[server_id]+"&filepath="+obj[filepath]+"&pos="+obj[pos]+"&chunk="+obj[chunk];
}
if(params.length>0) {
xhr.send(params);
} else {
alert('Error');
}
});
}
// add chunk to "obj" object and post it to server
function addChunk(reader,obj,divID) {
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
obj.chunk = evt.target.result;
console.log(obj);
document.getElementById(divID).textContent +=
['Sending bytes: ', obj.pos*16000, ' - ', ((obj.pos*16000)+(obj.pos+1)*obj.chunk.length),
'\n'].join('');
// post data to server
postChunk(obj).then(function(data) {
if(data!=="" && data!==null && typeof data!=="undefined") {
// chunk was sent successfully
document.getElementById(divID).textContent +=
['Sent bytes: ', obj.pos*16000, ' - ', ((obj.pos*16000)+(obj.pos+1)*obj.chunk.length),'\n'].join('');
} else {
alert('Error! Empty response');
}
}, function(status) {
alert('Resolve Error');
});
}
};
}
// read and send Chunk
function readChunk() {
var files = document.getElementById('files').files;
if (!files.length) {
alert('Please select a file!');
return;
}
var file = files[0];
var size = parseInt(file.size);
var chunkSize = 16000;
var chunks = Math.ceil(size/chunkSize);
var start,stop = 0;
var blob = [];
for(i=0;i<chunks;i++) {
start = i*chunkSize;
stop = (i+1)*chunkSize-1;
if(i==(chunks-1)) {
stop = size;
}
var reader = new FileReader();
blob = file.slice(start, stop);
reader.readAsBinaryString(blob);
var obj = {action: 'writeFileChunk', server_id: 'sid', filepath: 'path', pos: i, chunk: ""};
var div = document.createElement('div');
div.id = "bytes"+i;
document.body.appendChild(div);
addChunk(reader,obj,div.id);
}
}
// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {
console.log(' Great success! All the File APIs are supported.');
} else {
alert('The File APIs are not fully supported in this browser.');
}
document.querySelector('.readBytesButtons').addEventListener('click', function(evt) {
if (evt.target.tagName.toLowerCase() == 'button') {
readChunk();
}
}, false);
You can check this example in this Fiddle

Length of uploaded couchDB attachment always 0 Bytes

So...I'm new to all this stuff and I'm developing an app for android with AngularJS and Ionic Framework and try to upload an audiofile I have recorded with the cordova capture Plugin like this:
// gets called from scope
$scope.captureAudio = function() {
var options = { limit: 1, duration: 10 };
$cordovaCapture.captureAudio(options).then(function(audioData) {
uploadFile(documentID, audioData);
}, function(err) {
console.log('error code: ' + err);
});
};
var uploadFile = function (document, file) {
var baseUrl = 'urltomydatabase';
var name = encodeURIComponent'test.3gpp'),
type = file[0].type,
fileReader = new FileReader(),
putRequest = new XMLHttpRequest();
$http.get(baseUrl + encodeURIComponent(document))
.success(function (data) {
putRequest.open('PUT', baseUrl + encodeURIComponent(document) + '/' + name + '?rev=' + data._rev, true);
putRequest.setRequestHeader('Content-Type', type);
fileReader.readAsArrayBuffer(file[0]);
fileReader.onload = function (readerEvent) {
putRequest.send(readerEvent);
};
putRequest.onreadystatechange = function (response) {
if (putRequest.readyState == 4) {
//success - be happy
}
};
})
.error(function () {
// failure
});
};
How the file looks in the console.log:
Playing the recorded file on the device works nice.
But everytime I upload the recording and the upload has finished, the uploaded attachment inside the document has the length '0' in the couchDB.
How the created file looks in the database after the upload:
What am I doing wrong?
EDIT: I just found out, when I upload an image, passed from this function as blob, it works well:
function upload(imageURL) {
var image = new Image();
var onload = function () {
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
canvas.toBlob(function (blob) {
uploadFile(documentID, blob);
});
};
image.onload = onload;
image.src = imageURL;
}
So maybe the solution is creating a blob from the audiofile? But everytime I try it, my blob has the size of 0 bytes even before uploading it and I don't find somewhere a great explanation of how to convert a MediaFile object to blob...
It looks like your code does not send the content of your file as multipart attachment. To see what is really send to couchdb, capture the traffic with wireshark (https://www.wireshark.org/) or such.
This thread brought me to the solution, PouchDB purifies it. Now my upload function looks like this and can handle every file format
// e.g capture Audio
$scope.captureAudio = function () {
var options = {limit: 1, duration: 10};
$cordovaCapture.captureAudio(options).then(function (audioData) {
uploadFile(documentID, audioData, 'audio');
}, function (err) {
console.log('error code: ' + err);
});
};
var uploadFile = function (id, file, mediatype) {
var fileName = makeID();
if (mediatype == 'image') var name = encodeURIComponent(fileName + '.jpg');
if (mediatype == 'audio') var name = encodeURIComponent(fileName + '.3gpp');
if (mediatype == 'video') var name = encodeURIComponent(fileName + '.3gp');
db.get(id).then(function (doc) {
var path = file.fullPath;
window.resolveLocalFileSystemURL(path, function (fileEntry) {
return fileEntry.file(function (data) {
var reader = new FileReader();
reader.onloadend = function (e) {
var blob = b64toBlobAlt(e.target.result, file.type);
if (blob) {
db.putAttachment(id, name, doc._rev, blob, file.type).then(function () {
if (mediatype == 'video' || mediatype == 'image') getMedia();
if (mediatype == 'audio') $scope.audios.push(source);
});
}
};
return reader.readAsDataURL(data);
});
});
});
};
// creating the blob from the base64 string
function b64toBlobAlt(dataURI, contentType) {
var ab, byteString, i, ia;
byteString = atob(dataURI.split(',')[1]);
ab = new ArrayBuffer(byteString.length);
ia = new Uint8Array(ab);
i = 0;
while (i < byteString.length) {
ia[i] = byteString.charCodeAt(i);
i++;
}
return new Blob([ab], {
type: contentType
});
}

RecordRTC FileSize and Tracking Problems for asp.net MVC 5 app

I am building an application for ASP.Net MVC 5, in which I need to record a live video and audio stream from the webcam/microphone. I have decided on a web app based solution, RecordRTC. I have used the demo from, Muaz-Khan's github as a starting point, and modified it for my specifications.
The problem I am having is that I am unable to determine how to reduce the size of the webm that is being created. Right now it is about 1.7MB a second, my goal is for it to be 4-10MB a minute.
Also the file that is created from this does not possess time metadata, meaning I cannot use the seek-bar to go to a specific time. i.e. it says 3 secs have elapsed 0 remain, and still runs.
Any help would be appreciated.
NOTE: I am aware that support for the below code will only work in Firefox. I will simply wait for Chrome to add support, and therefore have removed the workaround Muaz Khan has in the demo.
< script >
//script 1
document.createElement('article')< /script>
<script>
//script 2
function PostBlob(blob, fileType, fileName) {
/ / FormData
var formData = new FormData();
formData.append(fileType + '-filename', fileName);
formData.append(fileType + '-blob', blob);
// progress-bar
var hr = document.createElement('hr');
container.appendChild(hr);
var strong = document.createElement('strong');
strong.id = 'percentage';
strong.innerHTML = fileType + ' upload progress: ';
container.appendChild(strong);
var progress = document.createElement('progress');
container.appendChild(progress);
// POST the Blob using XHR2
xhr('/Video/PostRecordedAudioVideo', formData, progress, percentage, function(fName) {
container.appendChild(document.createElement('hr'));
var mediaElement = document.createElement(fileType);
var source = document.createElement('source');
source.src = location.href + 'Files/' + fName.replace(/"/g, '');
if (fileType == 'video') source.type = 'video/webm; codecs="vp8, vorbis"';
if (fileType == 'audio') source.type = 'audio/ogg';
mediaElement.appendChild(source);
mediaElement.controls = true;
container.appendChild(mediaElement);
mediaElement.play();
progress.parentNode.removeChild(progress);
strong.parentNode.removeChild(strong);
hr.parentNode.removeChild(hr);
});
}
var record = document.getElementById('record');
var stop = document.getElementById('stop');
var audio = document.querySelector('audio');
var recordVideo = document.getElementById('record-video');
var preview = document.getElementById('preview');
var container = document.getElementById('container');
var recordAudio, recordVideo;
record.onclick = function() {
record.disabled = true;
navigator.getUserMedia({
audio: {
mandatory: {
googEchoCancellation: false,
googAutoGainControl: false,
googNoiseSuppression: false,
googHighpassFilter: false,
sampleRate: true
},
optional: []
},
video: true
}, function(stream) {
preview.src = window.URL.createObjectURL(stream);
preview.play();
//var legalBufferValues = [256, 512, 1024, 2048, 4096, 8192, 16384];
// sample-rates in at least the range 22050 to 96000.
recordAudio = RecordRTC(stream, {
onAudioProcessStarted: function() {}
});
recordAudio.startRecording();
stop.disabled = false;
}, function(error) {
alert(JSON.stringify(error, null, '\t'));
});
};
var fileName;
stop.onclick = function() {
record.disabled = false;
stop.disabled = true;
preview.src = '';
fileName = Math.round(Math.random() * 99999999) + 99999999 + ".webm";
recordAudio.stopRecording(function(url) {
preview.src = url;
PostBlob(blob, 'video', fileName);
});
};
function xhr(url, data, progress, percentage, callback) {
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
callback(request.responseText);
}
};
if (url.indexOf('/Video/DeleteFile') == -1) {
request.upload.onloadstart = function() {
percentage.innerHTML = 'Upload started...';
};
request.upload.onprogress = function(event) {
progress.max = event.total;
progress.value = event.loaded;
percentage.innerHTML = 'Upload Progress ' + Math.round(event.loaded / event.total * 100) + "%";
};
request.upload.onload = function() {
percentage.innerHTML = 'Saved!';
};
}
request.open('POST', url);
request.send(data);
}; < /script>
#{ ViewBag.Title = "Video Record"; }
<--Script 1 goes here-->
<!-- script used for audio/video/gif recording -->
#Scripts.Render("~/bundles/RTCRecording")
<article>
<section class="experiment">
<p style="text-align:center;">
<video id="preview" controls style="border: 1px solid rgb(15, 158, 238);"></video>
</p>
<hr />
<button id="record">Record</button>
<button id="stop" disabled>Stop</button>
<div id="container" style="padding:1em 2em;"></div>
</section>
<--Script 2 goes here-->
</article>

Converting image dataUrl to Blob image for AJAX POST with javascript

I have the following code which will take an image, allow the user to crop (with other code not shown or necessary for this question), and then render the image in base64 from canvas.
I need to be able to convert the image to binary, as the API endpoint its being submitted to can't take base64. I have functionality to convert to a Blob, but I'm not sure how to implement it correctly:
$(function () {
var fileInput = document.getElementById("file"),
renderButton = $("#renderButton"),
submit = $(".submit"),
imgly = new ImglyKit({
container: "#container",
ratio: 1 / 1
});
// As soon as the user selects a file...
fileInput.addEventListener("change", function (event) {
var file;
var fileToBlob = event.target.files[0];
var blob = new Blob([fileToBlob], {
"type": fileToBlob.type
});
// do stuff with blob
console.log(blob);
// Find the selected file
if (event.target.files) {
file = event.target.files[0];
} else {
file = event.target.value;
}
// Use FileReader to turn the selected
// file into a data url. ImglyKit needs
// a data url or an image
var reader = new FileReader();
reader.onload = (function (file) {
return function (e) {
data = e.target.result;
// Run ImglyKit with the selected file
try {
imgly.run(data);
} catch (e) {
if (e.name == "NoSupportError") {
alert("Your browser does not support canvas.");
} else if (e.name == "InvalidError") {
alert("The given file is not an image");
}
}
};
})(file);
reader.readAsDataURL(file);
});
// As soon as the user clicks the render button...
// Listen for "Render final image" click
renderButton.click(function (event) {
var dataUrl;
imgly.renderToDataURL("image/jpeg", {
size: "1200"
}, function (err, dataUrl) {
// `dataUrl` now contains a resized rendered image
//Convert DataURL to Blob to send over Ajax
function dataURItoBlob(dataUrl) {
// convert base64 to raw binary data held in a string
var byteString = atob(dataUrl.split(',')[1]);
// separate out the mime component
var mimeString = dataUrl.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
//var bb = new BlobBuilder();
//bb.append(ab);
//return bb.getBlob(mimeString);
return new Blob([ab], {
type: 'image/jpeg'
});
}
var blob = dataURItoBlob(dataUrl);
//console.log("var blob: " + blob);
//var fd = new FormData(document.forms[0]);
var image = $("<img><br>").attr({
src: dataUrl
});
image.appendTo($(".result"))
$removeButton = $('<button class="btn btn-default remove">')
.text('Remove ' + imageid.value).appendTo($(".result"))
.on('click', function () {
panel.remove();
$(this).remove();
return false;
});
$submitButton = $('<div class="btn btn-default submit"></div>')
.text('Submit ' + imageid.value).appendTo($(".result"))
.on('click', function () {
var fd = new FormData;
fd.append('file', blob, 'image.png');
//console.log("var fd: " + fd);
var xhr = new XMLHttpRequest();
var saveImage = encodeURIComponent(dataUrl);
//console.log("SAVE IMAGE: " + saveImage);
//console.log(saveImage);
fd.append("myFile", blob);
xhr.open('POST', 'http://url.com/rest/v1/utils/guid/encode?' + saveImage + '&imageid=' + imageid.value, true);
xhr.send(fd);
});
});
});
});
On Submit, I get the following in the console:
http://url.com/rest/v1/utils/guid/encode?data%3Aimage%2Fjpeg%3Bbase64%2C%2F…CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP%2FZ
The current version in jsFiddle: LINK

Categories