must be a simple question but I've been struggling for a week with it. I have a super simple jquery based audio capture - what I just want is to save it as a file based on a controller action. The problem is that I can't figure out how to pass blob file to the controller. This is the code I have to capture audio (see below). With image I can just use
document.getElementById("canvas").toDataURL("image/png");
then pass it to controller and save it as image, something like this:
using (FileStream fs = new FileStream(fileNameWitPath, FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
byte[] data = Convert.FromBase64String(imageData);
bw.Write(data);
bw.Close();
}
fs.Close();
}
so ideally I would want something akin to how I save images.
$(function () {
$('body').append(
$('<button/>')
.attr("id", "start")
.html("start")
).append(
$('<button/>')
.attr("id", "stop")
.html("stop")
).append(
$('<div/>').
attr("id", "ul")
)
let log = console.log.bind(console),
ul = $('#ul')[0],
start = $('#start')[0],
stop = $('#stop')[0],
stream,
recorder,
counter = 1,
chunks,
media;
media = {
tag: 'audio',
type: 'audio/ogg',
ext: '.ogg',
gUM: { audio: true }
}
navigator.mediaDevices.getUserMedia(media.gUM).then(_stream => {
stream = _stream;
recorder = new MediaRecorder(stream);
recorder.ondataavailable = e => {
chunks.push(e.data);
if (recorder.state == 'inactive') makeLink();
};
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 makeLink() {
let blob = new Blob(chunks, { type: media.type })
, url = URL.createObjectURL(blob)
, div = document.createElement('div')
, mt = document.createElement(media.tag)
, hf = document.createElement('a')
;
mt.controls = true;
mt.src = url;
hf.href = url;
hf.download = `${counter++}${media.ext}`;
hf.innerHTML = `donwload ${hf.download}`;
div.appendChild(mt);
ul.appendChild(div);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Much appreciated
So just in case anyone else stumples on it, as expected it was quite simple (not the cleanest code but here you go):
create a new Blob value:
recorder.ondataavailable = e => {
chunks.push(e.data);
superBuffer = new Blob(chunks, { type: 'audio/ogg' });
if (recorder.state == 'inactive') makeLink(); //console.log(e.data)
Then use Ajax to send this to server:
var reader = new window.FileReader();
reader.readAsDataURL(superBuffer);
reader.onloadend = function () {
base64 = reader.result;
base64 = base64.split(',')[1];
$.ajax({
url: 'MyController/Action1',
type: 'POST',
data: {
audioname: "hello",//obviously change to something dynamic
chunks: base64
},
success: function (response) { console.log(response); },
error: function (response) { console.log(response); }
});
Then in the code-behind:
[HttpPost]
public IActionResult Action1(string audioname, string chunks)
{
string fileNameWitPath = Path.Combine(_hostingEnvironment.WebRootPath, "audio", "test.ogg");
using (FileStream fs = new FileStream(fileNameWitPath, FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
byte[] data = Convert.FromBase64String(chunks);
bw.Write(data);
bw.Close();
}
fs.Close();
}
return Content(chunks) ;//this is for testing - sends back full chunk on success, would probably just want some confirm all is good message
}
Note this is work in progress obviously with things to fill, but in general works