I have created a voice recorder in HTML.
first, it will request stream, after allowing request stream it will show two buttons, like "start" and "Stop". After recording it will convert blob URL to base64 data.
Now what I want is, I have a table SQLserver I want to store base64 data in that table. I am creating this web page using ASP .NET MVC. The base64 data is in javascript. I don't know how to connect to the server.
Please help me.
Thanks.
Html Page code:
<body>
<h1> Audio Recorder</h1>
<p> For now it is supported only in Firefox(v25+) and Chrome(v47+)</p>
<div id='gUMArea'>
<div>
Record:
</div>
<button class="btn btn-default mediaAudio" id='gUMbtn'>Request Stream</button>
</div>
<div id='btns'>
<button class="btn btn-default" id='start'>Start</button>
<button class="btn btn-default" id='stop'>Stop</button>
</div>
<div>
<ul class="list-unstyled" id='ul'></ul>
</div>
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="~/script.js"></script>
</body>
JavaScript Code:
'use strict'
let log = console.log.bind(console),
id = val => document.getElementById(val),
ul = id('ul'),
gUMbtn = id('gUMbtn'),
start = id('start'),
stop = id('stop'),
stream,
recorder,
counter=1,
chunks,
media;
gUMbtn.onclick = e => {
let mv = id('.mediaAudio'),
mediaOptions = {
audio: {
tag: 'audio',
type: 'audio/mpeg',
ext: '.mp3',
gUM: {audio: true}
}
};
media = mediaOptions.audio;
navigator.mediaDevices.getUserMedia(media.gUM).then(_stream => {
stream = _stream;
id('btns').style.display = 'inherit';
start.removeAttribute('disabled');
recorder = new MediaRecorder(stream);
recorder.ondataavailable = e => {
chunks.push(e.data);
if (recorder.state == 'inactive') saveLink()
};
log('got media successfully');
}).catch(log);
}
start.onclick = e => {
start.disabled = true;
stop.removeAttribute('disabled');
chunks=[];
recorder.start();
}
stop.onclick = e => {
stop.disabled = true;
recorder.stop();
start.removeAttribute('disabled');
}
function saveLink() {
let blob = new Blob(chunks, { type: media.type })
;
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
var base64data = reader.result;
console.log(base64data.substr(base64data.indexOf(',') + 1));
alert(base64data.substr(base64data.indexOf(',') + 1));
}
}
Now it have base64 data in base64data variable, I want to store this variable sql server.
Regards.
Your solution has 2 parts:
Getting a blob out of the blob url
Sending that blob to the server
For first part you can use "Fake ajax" technique just pass blob url (url of download.ogg) as the url of your ajax
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
var result = this.response
}
}
xhr.open('GET', 'blob:http://example.com/bbdaabf8-ddf2-40d3-975d-ade742417c71');
xhr.responseType = 'blob';
xhr.send();
After ajax completes result will hold a blob now you just send it to ther server using this answer
Related
I am using this
<button onclick="startRecording(this);">record</button>
<button onclick="stopRecording(this);" disabled>stop</button>
<h2>Recordings</h2>
<ul id="recordingslist"></ul>
<h2>Log</h2>
<pre id="log"></pre>
<script>
function __log(e, data) {
log.innerHTML += "\n" + e + " " + (data || '');
}
var audio_context;
var recorder;
function startUserMedia(stream) {
var input = audio_context.createMediaStreamSource(stream);
__log('Media stream created.' );
__log("input sample rate " +input.context.sampleRate);
// Feedback!
//input.connect(audio_context.destination);
__log('Input connected to audio context destination.');
recorder = new Recorder(input, {
numChannels: 1
});
__log('Recorder initialised.');
}
function startRecording(button) {
recorder && recorder.record();
button.disabled = true;
button.nextElementSibling.disabled = false;
__log('Recording...');
}
function stopRecording(button) {
recorder && recorder.stop();
button.disabled = true;
button.previousElementSibling.disabled = false;
__log('Stopped recording.');
// create WAV download link using audio data blob
createDownloadLink();
recorder.clear();
}
function createDownloadLink() {
recorder && recorder.exportWAV(function(blob) {
/*var url = URL.createObjectURL(blob);
var li = document.createElement('li');
var au = document.createElement('audio');
var hf = document.createElement('a');
au.controls = true;
au.src = url;
hf.href = url;
hf.download = new Date().toISOString() + '.wav';
hf.innerHTML = hf.download;
li.appendChild(au);
li.appendChild(hf);
recordingslist.appendChild(li);*/
});
}
window.onload = function init() {
try {
// webkit shim
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
window.URL = window.URL || window.webkitURL;
audio_context = new AudioContext;
__log('Audio context set up.');
__log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));
} catch (e) {
alert('No web audio support in this browser!');
}
navigator.getUserMedia({audio: true}, startUserMedia, function(e) {
__log('No live audio input: ' + e);
});
};
</script>
<script src="js/jquery-1.11.0.min.js"></script>
<script src="recordmp3.js"></script>
To capture audio and offer an mp3 download but what I really need to do is upload the recordings to the server and as a bonus if I could rename the files before upload that would make it perfect! Can't show an example of what I've tried as I have no idea where to start on this one, any help greatly appreciated.
The flow would be to capture a handful of short recordings, rename them then hit an upload button which will upload them as mp3's then redirect to a success page.
Full code here https://github.com/Audior/Recordmp3js
You should upload the data as a XMLHttpRequest, however on the server side you should save it to a file with a custom name. This is also safer, since you can very easily avoid file traversal attacks by not specifying a path (From what I've understood, other people can't upload files to your computer/server, however I still believe you should approach this method because it is a great introduction to protecting an application with basic security measures).
You can use the following (modified) answer, taken from here, to do the job. This is how the JS function createDownloadLink should look after the modifications:
function createDownloadLink() {
recorder && recorder.exportWAV(function(blob) {
// Generate the 'File'
var data = new FormData();
data.append('file', blob);
// Make the HTTP request
var oReq = new XMLHttpRequest();
// POST the data to upload.php
oReq.open("POST", 'upload.php', true);
oReq.onload = function(oEvent) {
// Data has been uploaded
};
oReq.send(data);
});
}
On the PHP side, however, you should also make some modifications, since this is now a classic file upload, rather than a POST request with the data being sent as a parameter. Modify upload.php like so (information about moving uploaded files taken from here):
<?php
// Make sure recordings folder exists
if(!is_dir("recordings")){
$res = mkdir("recordings",0777);
}
// Declare file name
$filename = 'recordings/' . 'audio_recording_' . date( 'Y-m-d-H-i-s' ) .'.mp3';
// Move the uploaded file to the directory
move_uploaded_file($_FILES['file']['tmp_name'], $filename));
?>
I am trying to make an audio file converter that lets a user submit a file. Then uses JavaScripts Web Audio API to convert the pitch and stretch the file. I have gotten as far as uploading the file, use file reader to onload a function that stretches and converts the pitch. Now I am trying to export that file with the changes and I can right now only download the original file but not with the changes. I dont know how to assign file = buffer because it's from another class. How should I got by making this happen?
convertFile () {
var fileInput = document.getElementById('audio-file')
var ctx = new AudioContext()
var convertFiles = document.getElementById('convert_button')
//load audio file listener
convertFiles.addEventListener("click", function() {
if (fileInput.files[0] == undefined) {
console.log("no file found")
return false
}
var reader1 = new FileReader()
reader1.onload = function(ev) {
ctx.decodeAudioData(ev.target.result). then(function(buffer){
var soundSource = ctx.createBufferSource()
soundSource.buffer = buffer
// create the stretch
soundSource.playbackRate.linearRampToValueAtTime(0.0185, ctx.currentTime)
//connect source
soundSource.connect(ctx.destination)
// convert pitch
var pitchChange = ctx.createBiquadFilter()
pitchChange.type = 'highpass'
pitchChange.frequency.value = 432
pitchChange.connect(ctx.destination)
})
}
reader1.readAsArrayBuffer(fileInput.files[0])
})
let file = fileInput.files[0]
let url = URL.createObjectURL(file)
let link = document.createElement('a')
link.href = url
link.download = file.name
link.click()
link = null
URL.revokeObjectURL(url)
}
render() {
return (
<div className="sec2">
<input type="file" id="audio-file" accept="audio/mpeg, audio/ogg, audio/*" name="file" onChange={this.uploadFile} />
<button type="button" id="convert_button" onClick={this.convertFile}>Convert to 432Hz</button>
<download onClick={this.downloadFile}>Download File</download>
</div>
)
}
}
export default ConverterSec2
I started looking into this... I fixed a couple issues such as the audio file being loaded twice. However this is work in progress answer... I haven't figure out the saving part yet.
class ConverterSec2 extends React.Component {
uploadFile = ({ target: { files } }) => {
console.log(files[0])
let data = new FormData()
data.append('file', files[0])
}
convertFile () {
var fileInput = document.getElementById('audio-file')
var ctx = new AudioContext()
var convertFiles = document.getElementById('convert_button')
//load audio file listener
if (fileInput.files[0] == undefined) {
console.log("no file found")
return false
}
var soundSource = ctx.createBufferSource();
var reader1 = new FileReader()
reader1.onload = function(ev) {
ctx.decodeAudioData(ev.target.result).then(function(buffer){
soundSource.buffer = buffer
// create the stretch
soundSource.playbackRate.linearRampToValueAtTime(0.0185, ctx.currentTime)
//connect source
soundSource.connect(ctx.destination)
// convert pitch
var pitchChange = ctx.createBiquadFilter()
pitchChange.type = 'highpass'
pitchChange.frequency.value = 432
pitchChange.connect(ctx.destination)
})
}
reader1.readAsArrayBuffer(fileInput.files[0]);
}
downloadFile() {
let fileInput = document.getElementById('audio-file')
let file = fileInput.files[0]
let url = URL.createObjectURL(file)
let link = document.createElement('a')
link.href = url
link.download = file.name
link.click()
link = null
URL.revokeObjectURL(url)
}
render() {
return (
<div className="sec2">
<input type="file" id="audio-file" accept="audio/mpeg, audio/ogg, audio/*" name="file" onChange={this.uploadFile} />
<button type="button" id="convert_button" onClick={this.convertFile}>Convert to 432Hz</button>
<button onClick={this.downloadFile}>Download File</button>
</div>
)
}
}
Live Demo
Issue
I have a page where users can upload files with the help of FormData and an XMLHttpRequest.
Uploading the file works fine. But the upload.onprogress is only working when uploading from an HTTP connection.
HTTPS
HTTP
I've tested this on Heroku and on an Amazon EC2 instance. But it's always the same:
Progress is shown when uploading via HTTP
Progress event is never triggered when uploading via HTTPS
Javascript (Angular 7)
const xhr = new XMLHttpRequest();
let progress = 0;
/** THIS EVENT IS NOT WORKING WITH HTTPS */
xhr.upload.onprogress = (event: ProgressEvent) => {
if (event.lengthComputable) {
progress = 100 * (event.loaded / event.total);
}
};
xhr.responseType = 'json';
xhr.open('POST', `${API_URL}/${this.API_PATH}/upload`, true);
xhr.setRequestHeader('authorization', this.authService.getAuthToken());
xhr.send(payload);
xhr.onload = () => {
observer.next(xhr.response);
observer.complete();
};
Node.Js
const busboyBodyParser = require('busboy-body-parser');
app.use(busboyBodyParser())
const busboy = new Busboy({ headers: req.headers })
busboy.on('finish', async () => {
const fileData = req.files.file
const fileId = req.body.fileId
const params = {
Body: fileData.data,
Bucket: awsConfig.bucket,
ContentType: fileData.mimetype,
Key: fileId,
StorageClass: 'ONEZONE_IA',
}
awsConfig.s3.upload(params, (err, data) => { /* ... */ }
})
req.pipe(busboy)
What I've also tried
I also tried to use the .addEventListener syntax for listening for progress:
xhr.upload.addEventListener("progress", uploadProgress, false);
But this didn't work, either.
Source Code
Node.Js (server.js)
Node.Js (upload-file.js)
Angular Service (editor-file.service.ts)
Notes
Please note, that I have already asked a question about this topic. But I got no working answer and I really need this to work.
Old question: XHR upload onprogress Event not Working on HTTPS Connection
It's important to set Listener between:
xhr.open('POST'...);
...put you listener here....
xhr.send(data)
In this case it gonna work!
I'm doing just the same with one of my webapps but without any angular, just JS and PHP.
My xhr works like a charm and is looking like this:
var totalSize = 0;
var xhr = new XMLHttpRequest(); // den AJAX Request anlegen
xhr.open('POST', 'data/upload.php'); // Angeben der URL und des Requesttyps
xhr.upload.addEventListener("progress", handleProgress);
xhr.addEventListener("load", handleComplete);
and this my handleProgess method:
handleProgress = function(event){
var progress = totalProgress + event.loaded;
document.getElementById('progress').innerHTML = 'Aktueller Fortschritt: ' + ((progress - totalSize < 0) ? Math.floor(progress / totalSize * 10000) / 100 : 100) + '%';
}
As I've tried to reproduce this problem, I didn't face the same issue. Could you please check below simple Heroku app that I've created to test this specific problem? Also, if there is any missing part that I am not seeing, please inform me.
Heroku Test-Purpose App: https://erdsav-test-app.herokuapp.com/
Below is the JS code that I am tried to build on top of your code and it simply uploads the zip data and downloads it afterwards (cannot store on Heroku because of having Ephemeral filesystem) to ensure that the file is uploaded successfully;
import { Observable } from "../js/Observable.js";
document.addEventListener("DOMContentLoaded", function(event) {
var progressBar = document.getElementById("progress"),
fileNameSpan = document.getElementById("file_name"),
fileSizeSpan = document.getElementById("file_size"),
fileUploadComp = document.getElementById("file_upload"),
loadButton = document.getElementById("upload_button"),
displaySpan = document.getElementById("progress_display"),
fileDetails = document.getElementById("file_details"),
selectButton = document.getElementById("select_button"),
formData = null;
function hideElements(){
fileDetails.style.display = "none";
}
function showElements(){
fileDetails.style.display = "block";
}
function upload(payload, fileName){
return new Observable(observer => {
const xhr = new XMLHttpRequest();
let progress = 0;
/** THIS EVENT IS NOT WORKING WITH HTTPS */
xhr.upload.onprogress = (event => {
if (event.lengthComputable) {
progressBar.max = event.total;
progressBar.value = event.loaded;
progress = Math.floor((event.loaded / event.total) * 100);
displaySpan.innerText = progress + '%';
observer.next(progress);
}
});
xhr.upload.onloadstart = function(e) {
progressBar.value = 0;
displaySpan.innerText = '0%';
}
xhr.upload.onloadend = function(e) {
progressBar.value = e.loaded;
loadButton.disabled = false;
loadButton.innerHTML = 'Start Upload Process';
}
xhr.responseType = 'blob';
xhr.open('POST', "https://erdsav-test-app.herokuapp.com/upload.php", true);
xhr.send(payload);
xhr.returnedFileName = fileName;
xhr.onload = () => {
download(xhr.response, xhr.returnedFileName, "application/zip");
observer.next(100);
observer.complete();
};
});
}
function showUploadedFile(file){
var fileName = file.name;
var fileSize = file.size;
fileNameSpan.innerText = fileName;
fileSizeSpan.innerText = Math.floor(fileSize / 1000) + ' KB';
}
function buildFormData(file) {
if (formData) {
formData.append("file", file);
}
return formData;
}
hideElements();
if (window.FormData) {
formData = new FormData();
}
else{
alert("FormData is not supported in this browser!");
}
fileUploadComp.onchange = function(){
var file = fileUploadComp.files[0];
if(file){
showElements();
showUploadedFile(file);
}
else{
hideElements();
}
}
selectButton.addEventListener("click", function(e){
fileUploadComp.value = "";
hideElements();
fileUploadComp.click();
e.preventDefault();
});
loadButton.addEventListener("click", function(e) {
if(fileUploadComp.files !== undefined && fileUploadComp.files.length > 0){
this.disabled = true;
this.innerHTML = "Uploading. Please wait...";
var obs = upload(buildFormData(fileUploadComp.files[0]), fileUploadComp.files[0].name);
obs.subscribe(
function valueHandler(value){
console.log("UPLOADING");
if(value){
console.log(value);
}
},
function errorHandler(err){
console.log("THERE IS AN ERROR");
},
function completeHandler(){
console.log("COMPLETE");
}
);
}
else{
alert("No file is selected");
}
e.preventDefault();
});
});
PHP side
<?php
if ($_FILES['file']['error'] != $UPLOAD_ERR_OK) {
//writeLog($_FILES['file']['error']);
echo 'An error occurred!';
exit();
}
else {
$filePath = $_FILES['file']['tmp_name'];
$fileName = $_FILES['file']['name'];
if (file_exists($filePath)) {
ob_start();
$fileSize = readfile($filePath);
$content = ob_get_clean();
header('Content-Type: application/octet-stream;');
header("Content-Disposition: attachment; filename=\"" . $fileName . "\"");
header('Expires: 0');
header('Pragma: no cache');
header('Content-Length: ' . $fileSize);
echo $content;
}
else{
echo 'File is not found';
exit();
}
}
?>
HTML page source
<!DOCTYPE html>
<html lang="en">
<title>ProgressBar Progress Test</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="ProgressBar Progress Test">
<body>
<form method="post" enctype="multipart/form-data">
<input type="file" id="file_upload" accept="application/zip" style="width:0px" />
<button id="select_button">Choose File to Upload</button>
<progress id="progress" value="0"></progress>
<span id="progress_display"></span>
<button type="submit" id="upload_button">Start Upload Process</button>
</form>
<div id="file_details" style="display: none">
<h3>Selected File Details</h3>
<span id="file_name"></span><br>
<span id="file_size"></span>
</div>
<script type="module" src="js/Observable.js"></script>
<script src="js/download.js"></script>
<script type="module" src="js/main.js"></script>
</body>
</html>
Below image is captured by slowing the network to see the current percentage while uploading process continues;
Browsers used in testing;
Firefox Developer Edition 67.0b13 (64-bit/Up-to-date)
Google Chrome 74.0.3729.108 (64-bit/Up-to-date)
Now in 2022
The 2016's specifications are outdated, here is the new standard for XMLHttpRequest.
The upload is a getter that returns an XMLHttpRequestUpload object
The XMLHttpRequestUpload object implements the XMLHttpRequestEventTarget interface, which handles the onprogress event.
Now here's what MDN says about this:
Note: The spec also seems to indicate that event listeners should be attached after open(). However, browsers are buggy on this matter, and often need the listeners to be registered before open() to work.
I'm trying to record audio from a website user and save the audio to my server. Many of the posts I have studied so far have referenced Matt Diamond's recorderjs. I attempted to recreate the demo at http://webaudiodemos.appspot.com/AudioRecorder/index.html by opening the source code through my browser. I copied the html, "audiodisplay.js", "recorder.js", and "main.js" and put them on my server. I also added the "recorderWorker.js" file from his GitHub site. In the recorder.js file, I changed var WORKER_PATH = 'js/recorderjs/recorderWorker.js' to var WORKER_PATH = 'recorderWorker.js';
When I run the demo I set up, I'm getting the "would you like to share your microphone.." warning and I can start the recording by pressing the mic icon on the right side. However, when I stop recording, the audio waveform doesn't show up below like in Matt's demo and the save icon doesn't become activated.
If I can get the demo up and running, the next problem I have is saving the wav file to the server instead of locally like in the demo. I've found several posts saying to use XMLHttpRequest(), however I can't really figure out how to connect those examples to recorderjs. Saving WAV File Recorded in Chrome to Server HTML5 & getUserMedia - Record Audio & Save to Web Server after Certain Time RecorderJS uploading recorded blob via AJAX
Using XMLHttpRequest to post wav or mp3 blobs to server is simple.
Just run this code wherever you have access to the blob element:
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("audio_data",blob, "filename");
xhr.open("POST","upload.php",true);
xhr.send(fd);
I prefer XMLHttpRequest to $.ajax() because it does not require jQuery.
Server-side, upload.php is as simple as:
$input = $_FILES['audio_data']['tmp_name']; //temporary name that PHP gave to the uploaded file
$output = $_FILES['audio_data']['name'].".wav"; //letting the client control the filename is a rather bad idea
//move the file from temp name to local folder using $output name
move_uploaded_file($input, $output)
Source: https://blog.addpipe.com/using-recorder-js-to-capture-wav-audio-in-your-html5-web-site/
Live demo: https://addpipe.com/simple-recorderjs-demo/
I figured out one solution, but would still welcome others related to recorderjs. I used MP3RecorderJS at https://github.com/icatcher-at/MP3RecorderJS. The demo html works if you change the top of the html from src="js/jquery.min.js" and src="js/mp3recorder.js" to wherever they're located in your server. For me, it is src="jquery.min.js" and src="mp3recorder.js" I also had to do the same thing to the "mp3recorder.js" file: var RECORDER_WORKER_PATH = 'js/recorderWorker.js'; var ENCODER_WORKER_PATH = 'js/mp3Worker.js'; changed to var RECORDER_WORKER_PATH = 'recorderWorker.js'; var ENCODER_WORKER_PATH = 'mp3Worker.js';
The program is set up to record both mp3 and wav. I wanted wav, so I made a few more adjustments to the html file. At line 55 you'll find:
recorderObject.exportMP3(function(base64_mp3_data) {
var url = 'data:audio/mp3;base64,' + base64_mp3_data;
var au = document.createElement('audio');
I changed that to:
recorderObject.exportWAV(function(base64_wav_data) {
var url = 'data:audio/wav;base64,' + base64_wav_data;
var au = document.createElement('audio');
The demo appends a new player each time you record. To prevent this, I deleted (commented out) the $recorder.append(au); part, made a new div to store the audio player, and then I clear that div each time, before the audio player is created. To upload to my server, I used a technique I learned from uploading images to a server save canvas image to server Basically, the "url" variable in line 56 was what I needed, but couldn't figure out how to put it in a universal variable to use by another function. So, I made a hidden div and made the contents of it equal to "url". I then referenced that div in a new function called "upload". I then used a php file called "uploadWav.php". I still have to figure out a way to activate and deactivate the upload button to prevent the user from uploading a blank file before recording, but that's another issue. Here's the final html and php that worked for me:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>MP3 Recorder test</title>
</head>
<body id="index" onload="">
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="mp3recorder.js"></script>
<script type="text/javascript">
var audio_context;
function __log(e, data) {
log.innerHTML += "\n" + e + " " + (data || '');
}
$(function() {
try {
// webkit shim
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
window.URL = window.URL || window.webkitURL;
var audio_context = new AudioContext;
__log('Audio context set up.');
__log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));
} catch (e) {
alert('No web audio support in this browser!');
}
$('.recorder .start').on('click', function() {
$this = $(this);
$recorder = $this.parent();
navigator.getUserMedia({audio: true}, function(stream) {
var recorderObject = new MP3Recorder(audio_context, stream, { statusContainer: $recorder.find('.status'), statusMethod: 'replace' });
$recorder.data('recorderObject', recorderObject);
recorderObject.start();
}, function(e) { });
});
$('.recorder .stop').on('click', function() {
$this = $(this);
$recorder = $this.parent();
recorderObject = $recorder.data('recorderObject');
recorderObject.stop();
recorderObject.exportWAV(function(base64_wav_data) {
var url = 'data:audio/wav;base64,' + base64_wav_data;
var au = document.createElement('audio');
document.getElementById("playerContainer").innerHTML = "";
//console.log(url)
var duc = document.getElementById("dataUrlcontainer");
duc.innerHTML = url;
au.controls = true;
au.src = url;
//$recorder.append(au);
$('#playerContainer').append(au);
recorderObject.logStatus('');
});
});
});
</script>
<script>
function upload(){
var dataURL = document.getElementById("dataUrlcontainer").innerHTML;
$.ajax({
type: "POST",
url: "uploadWav.php",
data: {
wavBase64: dataURL
}
}).done(function(o) {
console.log('saved');
});
}
</script>
<div class="recorder">
Recorder 1
<input type="button" class="start" value="Record" />
<input type="button" class="stop" value="Stop" />
<pre class="status"></pre>
</div>
<div><button onclick="upload()">Upload</button></div>
<div id="playerContainer"></div>
<div id="dataUrlcontainer" hidden></div>
<pre id="log"></pre>
</body>
</html>
and the "uploadWav.php" file:
<?php
// requires php5
define('UPLOAD_DIR', 'uploads/');
$img = $_POST['wavBase64'];
$img = str_replace('data:audio/wav;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . uniqid() . '.wav';
$success = file_put_contents($file, $data);
print $success ? $file : 'Unable to save the file.';
?>
//**Server Side Code**
package myPack;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
#WebServlet("/MyServlet")
#MultipartConfig
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public MyServlet() {
super();
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
try {
String name = request.getParameter("fname");
String url = request.getParameter("myUrl");
url = url.replace("data:audio/wav;base64,", "");
url = url.replace(" ", "+");
byte[] bytes = url.getBytes();
byte[] valueDecoded = Base64.decodeBase64(bytes);
FileOutputStream os = new FileOutputStream(new File("D://" + name
+ ".wav"));
os.write(valueDecoded);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
**Client Side Code**
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>MP3 Recorder test</title>
</head>
<body id="index" onload="">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/recorder.js"></script>
<script type="text/javascript">
var audio_context;
function __log(e, data) {
log.innerHTML += "\n" + e + " " + (data || '');
}
$(function() {
try {
// webkit shim
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
window.URL = window.URL || window.webkitURL;
var audio_context = new AudioContext;
__log('Audio context set up.');
__log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));
} catch (e) {
alert('No web audio support in this browser!');
}
$('.recorder .start').on('click', function() {
$this = $(this);
$recorder = $this.parent();
navigator.getUserMedia({audio: true}, function(stream) {
var recorderObject = new MP3Recorder(audio_context, stream, { statusContainer: $recorder.find('.status'), statusMethod: 'replace' });
$recorder.data('recorderObject', recorderObject);
recorderObject.start();
}, function(e) { });
});
$('.recorder .stop').on('click', function() {
$this = $(this);
$recorder = $this.parent();
recorderObject = $recorder.data('recorderObject');
recorderObject.stop();
recorderObject.exportWAV(function(base64_wav_data) {
var url = 'data:audio/wav;base64,' + base64_wav_data;
var au = document.createElement('audio');
document.getElementById("playerContainer").innerHTML = "";
//console.log(url)
var duc = document.getElementById("dataUrlcontainer");
duc.innerHTML = url;
au.controls = true;
au.src = url;
//$recorder.append(au);
$('#playerContainer').append(au);
var fd = new FormData();
fd.append('fname', 'test.wav');
fd.append('myUrl', duc.innerHTML);
$.ajax({
type: "POST",
url: "/audioPart2/MyServlet",
data: fd,
processData: false,
contentType: false
});
recorderObject.logStatus('');
});
});
});
</script>
<div class="recorder">
Recorder 1 <input type="button" class="start" value="Record" /> <input
type="button" class="stop" value="Stop" />
<div id="playerContainer"></div>
<div id="dataUrlcontainer" hidden></div>
<pre class="status"></pre>
</div>
<!-- <div class="recorder"> -->
<!-- Recorder 2 <input type="button" class="start" value="Record" /> <input -->
<!-- type="button" class="stop" value="Stop" /> -->
<!-- <pre class="status"></pre> -->
<!-- </div> -->
<pre id="log"></pre>
</body>
</html>
**// Required JS
1)jquery.min.js
2) recorder.js**
**recorder.js is below**
(function(window){
var RECORDER_WORKER_PATH = 'js/recorderWorker.js';
var ENCODER_WORKER_PATH = 'js/mp3Worker.js';
var MP3Recorder = function(context, stream, cfg) {
var config = cfg || { statusContainer: null, statusMethod: 'append' }
var bufferLen = 4096;
var recording = false;
this.source = context.createMediaStreamSource(stream);
this.node = (context.createScriptProcessor || context.createJavaScriptNode).call(context, bufferLen, 1, 1);
var recorderWorker = new Worker(RECORDER_WORKER_PATH);
var encoderWorker = new Worker(ENCODER_WORKER_PATH);
var exportCallback;
// initialize the Recorder Worker
recorderWorker.postMessage({ cmd: 'init', sampleRate: context.sampleRate });
// the recording loop
this.node.onaudioprocess = function(e) {
if(!recording) return;
recorderWorker.postMessage({ cmd: 'record', buffer: e.inputBuffer.getChannelData(0) });
}
this.start = function() {
recording = true;
this.logStatus('recording...');
}
this.stop = function() {
recording = false;
this.logStatus('stopping...');
}
this.destroy = function() { recorderWorker.postMessage({ cmd: 'destroy' }); }
this.logStatus = function(status) {
if(config.statusContainer) {
if(config.statusMethod == 'append') {
config.statusContainer.text(config.statusContainer.text + "\n" + status);
} else {
config.statusContainer.text(status);
}
}
}
this.exportBlob = function(cb) {
exportCallback = cb;
if (!exportCallback) throw new Error('Callback not set');
recorderWorker.postMessage({ cmd: 'exportBlob' });
}
this.exportWAV = function(cb) {
// export the blob from the worker
this.exportBlob(function(blob) {
var fileReader = new FileReader();
// read the blob as array buffer and convert it
// to a base64 encoded WAV buffer
fileReader.addEventListener("loadend", function() {
var resultBuffer = new Uint8Array(this.result);
cb(encode64(resultBuffer));
});
fileReader.readAsArrayBuffer(blob);
});
}
this.exportMP3 = function(cb) {
this.logStatus('converting...');
// export the blob from the worker
this.exportBlob(function(blob) {
var fileReader = new FileReader();
fileReader.addEventListener("loadend", function() {
var wavBuffer = new Uint8Array(this.result);
var wavData = parseWav(wavBuffer);
encoderWorker.addEventListener('message', function(e) {
if (e.data.cmd == 'data') {
cb(encode64(e.data.buffer));
}
});
encoderWorker.postMessage({ cmd: 'init', config: { mode: 3, channels: 1, samplerate: wavData.sampleRate, bitrate: wavData.bitsPerSample } });
encoderWorker.postMessage({ cmd: 'encode', buf: Uint8ArrayToFloat32Array(wavData.samples) });
encoderWorker.postMessage({ cmd: 'finish' });
});
fileReader.readAsArrayBuffer(blob);
});
}
// event listener for return values of the recorderWorker
recorderWorker.addEventListener('message', function(e) {
switch(e.data.from) {
case 'exportBlob':
exportCallback(e.data.blob);
break;
};
});
// HELPER FUNCTIONS
function encode64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for(var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
function parseWav(wav) {
function readInt(i, bytes) {
var ret = 0, shft = 0;
while(bytes) {
ret += wav[i] << shft; shft += 8;
i++; bytes--;
}
return ret;
}
if(readInt(20, 2) != 1) throw 'Invalid compression code, not PCM';
if(readInt(22, 2) != 1) throw 'Invalid number of channels, not 1';
return { sampleRate: readInt(24, 4), bitsPerSample: readInt(34, 2), samples: wav.subarray(44) };
}
function Uint8ArrayToFloat32Array(u8a){
var f32Buffer = new Float32Array(u8a.length);
for (var i = 0; i < u8a.length; i++) {
var value = u8a[i<<1] + (u8a[(i<<1)+1]<<8);
if (value >= 0x8000) value |= ~0x7FFF;
f32Buffer[i] = value / 0x8000;
}
return f32Buffer;
}
this.source.connect(this.node);
this.node.connect(context.destination); // this should not be necessary
}
window.MP3Recorder = MP3Recorder;
})(window);
I have been working on this problem for the last few days. With no luck on trying to display the stream on <embed src> tag, I just tried to display it on a new window.
The new window shows PDF controls only )
Any idea why the content of the pdf is not showing?
CODE:
$http.post('/fetchBlobURL',{myParams}).success(function (data) {
var file = new Blob([data], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
});
You need to set the responseType to arraybuffer if you would like to create a blob from your response data:
$http.post('/fetchBlobURL',{myParams}, {responseType: 'arraybuffer'})
.success(function (data) {
var file = new Blob([data], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
});
more information: Sending_and_Receiving_Binary_Data
If you set { responseType: 'blob' }, no need to create Blob on your own. You can simply create url based with response content:
$http({
url: "...",
method: "POST",
responseType: "blob"
}).then(function(response) {
var fileURL = URL.createObjectURL(response.data);
window.open(fileURL);
});
I use AngularJS v1.3.4
HTML:
<button ng-click="downloadPdf()" class="btn btn-primary">download PDF</button>
JS controller:
'use strict';
angular.module('xxxxxxxxApp')
.controller('MathController', function ($scope, MathServicePDF) {
$scope.downloadPdf = function () {
var fileName = "test.pdf";
var a = document.createElement("a");
document.body.appendChild(a);
MathServicePDF.downloadPdf().then(function (result) {
var file = new Blob([result.data], {type: 'application/pdf'});
var fileURL = window.URL.createObjectURL(file);
a.href = fileURL;
a.download = fileName;
a.click();
});
};
});
JS services:
angular.module('xxxxxxxxApp')
.factory('MathServicePDF', function ($http) {
return {
downloadPdf: function () {
return $http.get('api/downloadPDF', { responseType: 'arraybuffer' }).then(function (response) {
return response;
});
}
};
});
Java REST Web Services - Spring MVC:
#RequestMapping(value = "/downloadPDF", method = RequestMethod.GET, produces = "application/pdf")
public ResponseEntity<byte[]> getPDF() {
FileInputStream fileStream;
try {
fileStream = new FileInputStream(new File("C:\\xxxxx\\xxxxxx\\test.pdf"));
byte[] contents = IOUtils.toByteArray(fileStream);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/pdf"));
String filename = "test.pdf";
headers.setContentDispositionFormData(filename, filename);
ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
return response;
} catch (FileNotFoundException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
return null;
}
// I used this code with the fpdf library.
// Este código lo usé con la libreria fpdf.
var datas = json1;
var xhr = new XMLHttpRequest();
xhr.open("POST", "carpeta/archivo.php");
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.responseType = "blob";
xhr.onload = function () {
if (this.status === 200) {
var blob = new Blob([xhr.response], {type: 'application/pdf'});
const url = window.URL.createObjectURL(blob);
window.open(url,"_blank");
setTimeout(function () {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(datas)
, 100
})
}
};
xhr.send("men="+datas);
You are not required to set the response type if your data is a byte array, make sure you convert it to Uint8Array before passing it to blob.
Example:
let byteArray = new Uint8Array(data)
let file = new Blob(
[byteArray],
{type: 'application/pdf'}
)
It works for me.
If your data is not byteArray, make sure to convert it to byteArray and follow above-mentioned steps to make it work.
//For example if your data is base-64 encoded string.
let byteChars = atob(data); //To decrypt data
let dataArray = = new Array(byteChars.length);
for(let i=0; i< byteChars.length; i++){
dataArray[i] = byteChars.charCodeAt(i);
}
let byteArray = new Uint8Array(dataArray)
let file = new Blob(
[byteArray],
{type: 'application/pdf'}
)
I know this is old but since this pointed me in the right direction, I thought I would share what I am doing in case someone else lands here. I am not using Angular btw.
The user can view or download the file. The choice is given with 2 buttons or 2 links
<button type="button" class="btn btn-primary btn-sm show_tooltip download-form" title="Download File" data-formid="{{ #your-id }}" data-forcedownload="1">
<i class="fas fa-file-download"></i>
</button>
<button type="button" class="btn btn-primary btn-sm show_tooltip download-form" title="View File" data-formid="{{ #your-id }}" data-forcedownload="0">
<i class="fas fa-search"></i>
</button>
I am using jQuery with the native plugin for xhr2. This handles the link/buttons
$('.download-form').click(function(event) {
event.preventDefault();
let fid = $(this).data('formid');
let force_download = $(this).data('forcedownload');
$.ajax({
url: '/download',
dataType: 'native',
type: 'POST',
xhrFields: {
responseType: 'blob'
},
data: {
//you can send any parameters via POST here
personID: "{{ #personID }}",
file_record_id: pfid,
file_type: "contract_form",
dept: "your-dept",
file_category: "fcategory",
force_download: force_download
},
success: function(blob, status, xhr){
if (xhr.getResponseHeader('Custom-FileError')>1) {
alertify.error(xhr.getResponseHeader('Custom-ErrorMsg'));
}else{
//I thought this would work when viewing the PDF but it does not.
blob.name = xhr.getResponseHeader('Custom-FileName');
var fileURL = URL.createObjectURL(blob);
if (xhr.getResponseHeader('Custom-ForceDownload')==1) {
window.open(fileURL);
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download=xhr.getResponseHeader('Custom-FileName');
link.click();
}else{
file_modal(fileURL,'Any Title');
}
}
}
})
});
Then, some more javascript for the modal
function file_modal(blob,the_title)
{
let spinner = "<div class='text-center'><i class='fa fa-spinner fa-spin fa-5x fa-fw'></i></div>";
$("#modal_static_label").html('Loading');
$("#modal_static .modal-body").html(spinner);
if (blob.length > 1) {
$("#modal_static").modal("show");
$("#modal_static_label").html(the_title);
$("#modal_static .modal-body").empty().append('<iframe src='+blob+' width="100%" height="500px" style="border:none;"></iframe>');
}else{
$("#modal_static .modal-body").empty().html('File error');
}
$("#modal_static .modal-footer").html('<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>');
}
On the server side you will need to send custom headers like this [PHP]
header("Content-length: $file_size");
header("Custom-FileError: 0");
header("Custom-FileName: ".$this->params['original_filename']);
header("Custom-ForceDownload: ".$this->params['force_download']);
header('Content-Type: '.$web->mime($this->full_path.$this->new_file_name));
readfile($this->full_path.$this->new_file_name);
If the user clicks "view", a modal will display the PDF if they click "download", the download window will show up with the filename of your choosing. I have tested this with PDF files less than 10mb and it works as expected.
I hope someone finds this useful.
I have been struggling for days finally the solution which worked for me is given below. I had to make the window.print() for PDF in new window needs to work.
var xhr = new XMLHttpRequest();
xhr.open('GET', pdfUrl, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this['status'] == 200) {
var blob = new Blob([this['response']], {type: 'application/pdf'});
var url = URL.createObjectURL(blob);
var printWindow = window.open(url, '', 'width=800,height=500');
printWindow.print()
}
};
xhr.send();
Some notes on loading PDF & printing in a new window.
Loading pdf in a new window via an iframe will work, but the print will not work if url is an external url.
Browser pop ups must be allowed, then only it will work.
If you try to load iframe from external url and try window.print() you will get empty print or elements which excludes iframe. But you can trigger print manually, which will work.
problem is, it is not converted to proper format. Use function "printPreview(binaryPDFData)" to get print preview dialog of binary pdf data.
you can comment script part if you don't want print dialog open.
printPreview = (data, type = 'application/pdf') => {
let blob = null;
blob = this.b64toBlob(data, type);
const blobURL = URL.createObjectURL(blob);
const theWindow = window.open(blobURL);
const theDoc = theWindow.document;
const theScript = document.createElement('script');
function injectThis() {
window.print();
}
theScript.innerHTML = `window.onload = ${injectThis.toString()};`;
theDoc.body.appendChild(theScript);
};
b64toBlob = (content, contentType) => {
contentType = contentType || '';
const sliceSize = 512;
// method which converts base64 to binary
const byteCharacters = window.atob(content);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {
type: contentType
}); // statement which creates the blob
return blob;
};
I ended up just downloading my pdf using below code
function downloadPdfDocument(fileName){
var req = new XMLHttpRequest();
req.open("POST", "/pdf/" + fileName, true);
req.responseType = "blob";
fileName += "_" + new Date() + ".pdf";
req.onload = function (event) {
var blob = req.response;
//for IE
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
}
};
req.send();
}
Note: this.file should be you base64 file