问题描述:
利用recorder.js+XMLHttpRequest+flask post(upload) 网页录音 to server,
已实现在线录音,期望利用XMLHttpRequest把录音传回服务器,然后保存到服务器本地。
但是把录音post 到服务器出现400错误(BAD REQUEST)
(
The browser (or proxy) sent a request that this server could not understand.
)程序部分
flask app.py
from flask import Flask, render_template,request
import os
app=Flask(__name__)
@app.route('/', methods=['POST','GET'])
def post_to_server():
if request.method =="POST":
f = request.form['audio_data']
f.save(os.path.join("uploads", f.filename))
return render_template('index.html')
else:
return render_template('index.html')
if __name__=='__main__':
# app.run(host="0.0.0.0", port=7003)
app.run(port=7005)
index.html部分
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Simple WebAudioRecorder.js demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/style.css') }}">
</head>
<body>
<p>Convert recorded audio to:<br>
<select id="encodingTypeSelect">
<option value="wav">Waveform Audio (.wav)</option>
<option value="mp3">MP3 (MPEG-1 Audio Layer III) (.mp3)</option>
<option value="ogg">Ogg Vorbis (.ogg)</option>
</select>
</p>
<div id="controls">
<button id="recordButton">Record</button>
<button id="stopButton" disabled>Stop</button>
</div>
<div id="formats"></div>
<h3>Log</h3>
<pre id="log"></pre>
<h3>Recordings</h3>
<ol id="recordingsList"></ol>
<!-- inserting these scripts at the end to be able to use all the elements in the DOM -->
<script src="{{ url_for('static',filename='js/WebAudioRecorder.min.js') }}"></script>
<script src="{{ url_for('static',filename='js/app.js') }}"></script>
</body>
</html>
app.js部分
//webkitURL is deprecated but nevertheless
URL = window.URL || window.webkitURL;
var gumStream; //stream from getUserMedia()
var recorder; //WebAudioRecorder object
var input; //MediaStreamAudioSourceNode we'll be recording
var encodingType; //holds selected encoding for resulting audio (file)
var encodeAfterRecord = true; // when to encode
// shim for AudioContext when it's not avb.
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext; //new audio context to help us record
var encodingTypeSelect = document.getElementById("encodingTypeSelect");
var recordButton = document.getElementById("recordButton");
var stopButton = document.getElementById("stopButton");
//add events to those 2 buttons
recordButton.addEventListener("click", startRecording);
stopButton.addEventListener("click", stopRecording);
function startRecording() {
console.log("startRecording() called");
/*
Simple constraints object, for more advanced features see
https://addpipe.com/blog/audio-constraints-getusermedia/
*/
var constraints = { audio: true, video:false }
/*
We're using the standard promise based getUserMedia()
https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
*/
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
__log("getUserMedia() success, stream created, initializing WebAudioRecorder...");
/*
create an audio context after getUserMedia is called
sampleRate might change after getUserMedia is called, like it does on macOS when recording through AirPods
the sampleRate defaults to the one set in your OS for your playback device
*/
audioContext = new AudioContext();
//update the format
document.getElementById("formats").innerHTML="Format: 2 channel "+encodingTypeSelect.options[encodingTypeSelect.selectedIndex].value+" @ "+audioContext.sampleRate/1000+"kHz"
//assign to gumStream for later use
gumStream = stream;
/* use the stream */
input = audioContext.createMediaStreamSource(stream);
//stop the input from playing back through the speakers
//input.connect(audioContext.destination)
//get the encoding
encodingType = encodingTypeSelect.options[encodingTypeSelect.selectedIndex].value;
//disable the encoding selector
encodingTypeSelect.disabled = true;
recorder = new WebAudioRecorder(input, {
workerDir: "static/js/", // must end with slash
encoding: encodingType,
numChannels:2, //2 is the default, mp3 encoding supports only 2
onEncoderLoading: function(recorder, encoding) {
// show "loading encoder..." display
__log("Loading "+encoding+" encoder...");
},
onEncoderLoaded: function(recorder, encoding) {
// hide "loading encoder..." display
__log(encoding+" encoder loaded");
}
});
recorder.onComplete = function(recorder, blob) {
__log("Encoding complete");
createDownloadLink(blob,recorder.encoding);
encodingTypeSelect.disabled = false;
}
recorder.setOptions({
timeLimit:120,
encodeAfterRecord:encodeAfterRecord,
ogg: {quality: 0.5},
mp3: {bitRate: 160}
});
//start the recording process
recorder.startRecording();
__log("Recording started");
}).catch(function(err) {
//enable the record button if getUSerMedia() fails
recordButton.disabled = false;
stopButton.disabled = true;
});
//disable the record button
recordButton.disabled = true;
stopButton.disabled = false;
}
function stopRecording() {
console.log("stopRecording() called");
//stop microphone access
gumStream.getAudioTracks()[0].stop();
//disable the stop button
stopButton.disabled = true;
recordButton.disabled = false;
//tell the recorder to finish the recording (stop recording + encode the recorded audio)
recorder.finishRecording();
__log('Recording stopped');
}
function createDownloadLink(blob,encoding) {
var url = URL.createObjectURL(blob);
var au = document.createElement('audio');
var li = document.createElement('li');
var link = document.createElement('a');
var filename = new Date().toISOString()
//add controls to the <audio> element
au.controls = true;
au.src = url;
//link the a element to the blob
link.href = url;
link.download = new Date().toISOString() + '.'+encoding;
link.innerHTML = link.download;
//add the new audio and a elements to the li element
li.appendChild(au);
li.appendChild(link);
//upload link
var upload = document.createElement('a');
upload.href="#";
upload.innerHTML = "Upload";
upload.addEventListener("click", function(event){
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","/",true);
xhr.send(fd);
})
li.appendChild(document.createTextNode (" "))//add a space in between
li.appendChild(upload)//add the upload link to li
//add the li element to the ol
recordingsList.appendChild(li);
}
//helper function
function __log(e, data) {
log.innerHTML += "\n" + e + " " + (data || '');
}