HTML5 запись аудио в файл
В конечном итоге я хочу сделать запись с микрофона пользователя и загрузить файл на сервер, когда они будут готовы. До сих пор мне удалось создать поток для элемента со следующим кодом:
var audio = document.getElementById("audio_preview");
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
navigator.getUserMedia({video: false, audio: true}, function(stream) {
audio.src = window.URL.createObjectURL(stream);
}, onRecordFail);
var onRecordFail = function (e) {
console.log(e);
}
Как мне перейти от этого к записи в файл?
9 ответов
Достаточно полная демонстрация записи доступна по адресу: http://webaudiodemos.appspot.com/AudioRecorder/index.html
Это позволяет вам записывать аудио в браузере, а затем дает вам возможность экспортировать и загружать то, что вы записали.
Вы можете просмотреть исходный код этой страницы, чтобы найти ссылки на javascript, но в итоге, есть Recorder
объект, который содержит exportWAV
метод и forceDownload
метод.
Приведенный ниже код защищен авторским правом Matt Diamond и доступен для использования по лицензии MIT. Оригинальные файлы здесь:
- http://webaudiodemos.appspot.com/AudioRecorder/index.html
- http://webaudiodemos.appspot.com/AudioRecorder/js/recorderjs/recorderWorker.js
Сохраните эти файлы и используйте
(function(window){
var WORKER_PATH = 'recorderWorker.js';
var Recorder = function(source, cfg){
var config = cfg || {};
var bufferLen = config.bufferLen || 4096;
this.context = source.context;
this.node = this.context.createJavaScriptNode(bufferLen, 2, 2);
var worker = new Worker(config.workerPath || WORKER_PATH);
worker.postMessage({
command: 'init',
config: {
sampleRate: this.context.sampleRate
}
});
var recording = false,
currCallback;
this.node.onaudioprocess = function(e){
if (!recording) return;
worker.postMessage({
command: 'record',
buffer: [
e.inputBuffer.getChannelData(0),
e.inputBuffer.getChannelData(1)
]
});
}
this.configure = function(cfg){
for (var prop in cfg){
if (cfg.hasOwnProperty(prop)){
config[prop] = cfg[prop];
}
}
}
this.record = function(){
recording = true;
}
this.stop = function(){
recording = false;
}
this.clear = function(){
worker.postMessage({ command: 'clear' });
}
this.getBuffer = function(cb) {
currCallback = cb || config.callback;
worker.postMessage({ command: 'getBuffer' })
}
this.exportWAV = function(cb, type){
currCallback = cb || config.callback;
type = type || config.type || 'audio/wav';
if (!currCallback) throw new Error('Callback not set');
worker.postMessage({
command: 'exportWAV',
type: type
});
}
worker.onmessage = function(e){
var blob = e.data;
currCallback(blob);
}
source.connect(this.node);
this.node.connect(this.context.destination); //this should not be necessary
};
Recorder.forceDownload = function(blob, filename){
var url = (window.URL || window.webkitURL).createObjectURL(blob);
var link = window.document.createElement('a');
link.href = url;
link.download = filename || 'output.wav';
var click = document.createEvent("Event");
click.initEvent("click", true, true);
link.dispatchEvent(click);
}
window.Recorder = Recorder;
})(window);
//ADDITIONAL JS recorderWorker.js
var recLength = 0,
recBuffersL = [],
recBuffersR = [],
sampleRate;
this.onmessage = function(e){
switch(e.data.command){
case 'init':
init(e.data.config);
break;
case 'record':
record(e.data.buffer);
break;
case 'exportWAV':
exportWAV(e.data.type);
break;
case 'getBuffer':
getBuffer();
break;
case 'clear':
clear();
break;
}
};
function init(config){
sampleRate = config.sampleRate;
}
function record(inputBuffer){
recBuffersL.push(inputBuffer[0]);
recBuffersR.push(inputBuffer[1]);
recLength += inputBuffer[0].length;
}
function exportWAV(type){
var bufferL = mergeBuffers(recBuffersL, recLength);
var bufferR = mergeBuffers(recBuffersR, recLength);
var interleaved = interleave(bufferL, bufferR);
var dataview = encodeWAV(interleaved);
var audioBlob = new Blob([dataview], { type: type });
this.postMessage(audioBlob);
}
function getBuffer() {
var buffers = [];
buffers.push( mergeBuffers(recBuffersL, recLength) );
buffers.push( mergeBuffers(recBuffersR, recLength) );
this.postMessage(buffers);
}
function clear(){
recLength = 0;
recBuffersL = [];
recBuffersR = [];
}
function mergeBuffers(recBuffers, recLength){
var result = new Float32Array(recLength);
var offset = 0;
for (var i = 0; i < recBuffers.length; i++){
result.set(recBuffers[i], offset);
offset += recBuffers[i].length;
}
return result;
}
function interleave(inputL, inputR){
var length = inputL.length + inputR.length;
var result = new Float32Array(length);
var index = 0,
inputIndex = 0;
while (index < length){
result[index++] = inputL[inputIndex];
result[index++] = inputR[inputIndex];
inputIndex++;
}
return result;
}
function floatTo16BitPCM(output, offset, input){
for (var i = 0; i < input.length; i++, offset+=2){
var s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}
function writeString(view, offset, string){
for (var i = 0; i < string.length; i++){
view.setUint8(offset + i, string.charCodeAt(i));
}
}
function encodeWAV(samples){
var buffer = new ArrayBuffer(44 + samples.length * 2);
var view = new DataView(buffer);
/* RIFF identifier */
writeString(view, 0, 'RIFF');
/* file length */
view.setUint32(4, 32 + samples.length * 2, true);
/* RIFF type */
writeString(view, 8, 'WAVE');
/* format chunk identifier */
writeString(view, 12, 'fmt ');
/* format chunk length */
view.setUint32(16, 16, true);
/* sample format (raw) */
view.setUint16(20, 1, true);
/* channel count */
view.setUint16(22, 2, true);
/* sample rate */
view.setUint32(24, sampleRate, true);
/* byte rate (sample rate * block align) */
view.setUint32(28, sampleRate * 4, true);
/* block align (channel count * bytes per sample) */
view.setUint16(32, 4, true);
/* bits per sample */
view.setUint16(34, 16, true);
/* data chunk identifier */
writeString(view, 36, 'data');
/* data chunk length */
view.setUint32(40, samples.length * 2, true);
floatTo16BitPCM(view, 44, samples);
return view;
}
<html>
<body>
<audio controls autoplay></audio>
<script type="text/javascript" src="recorder.js"> </script>
<fieldset><legend>RECORD AUDIO</legend>
<input onclick="startRecording()" type="button" value="start recording" />
<input onclick="stopRecording()" type="button" value="stop recording and play" />
</fieldset>
<script>
var onFail = function(e) {
console.log('Rejected!', e);
};
var onSuccess = function(s) {
var context = new webkitAudioContext();
var mediaStreamSource = context.createMediaStreamSource(s);
recorder = new Recorder(mediaStreamSource);
recorder.record();
// audio loopback
// mediaStreamSource.connect(context.destination);
}
window.URL = window.URL || window.webkitURL;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
var recorder;
var audio = document.querySelector('audio');
function startRecording() {
if (navigator.getUserMedia) {
navigator.getUserMedia({audio: true}, onSuccess, onFail);
} else {
console.log('navigator.getUserMedia not present');
}
}
function stopRecording() {
recorder.stop();
recorder.exportWAV(function(s) {
audio.src = window.URL.createObjectURL(s);
});
}
</script>
</body>
</html>
Обновите сейчас Chrome также поддерживает MediaRecorder API от v47. То же самое, что сделать, это использовать его (предполагая, что собственный метод записи должен быть быстрее, чем обходные пути), API действительно прост в использовании, и вы найдете тонны ответов о том, как загрузить большой двоичный объект на сервер.,
Демо-версия - будет работать в Chrome и Firefox, намеренно исключая передачу BLOB-объектов на сервер...
В настоящее время есть три способа сделать это:
- как
wav
[весь код на стороне клиента, несжатая запись], вы можете проверить -> Recorderjs. Проблема: размер файла довольно большой, требуется большая пропускная способность. - как
mp3
[весь код на стороне клиента, сжатая запись], вы можете проверить -> mp3Recorder. Проблема: лично я считаю, что качество плохое, также есть проблема с лицензированием. как
ogg
[клиент + сервер (node.js
) код, сжатая запись, бесконечные часы записи без сбоя браузера], вы можете проверить -> recordOpus, либо только запись на стороне клиента, либо связывание клиент-сервер, выбор за вами.Пример записи ogg (только Firefox):
var mediaRecorder = new MediaRecorder(stream); mediaRecorder.start(); // to start recording. ... mediaRecorder.stop(); // to stop recording. mediaRecorder.ondataavailable = function(e) { // do something with the data. }
Скрипка Демо для OGG записи.
Вопрос очень старый, и многие ответы не поддерживаются в текущей версии браузера. Я пытался создать диктофон, используя простой
html
,
css
, а также
js
. Далее я использовал тот же код в электронном виде для создания кроссплатформенного приложения.
<html>
<head>
<title>Recorder App</title>
</head>
<h2>Recorder App</h2>
<p>
<button type="button" id="record">Record</button>
<button type="button" id="stopRecord" disabled>Stop</button>
</p>
<p>
<audio id=recordedAudio></audio>
</p>
<script>
navigator.mediaDevices.getUserMedia({audio:true})
.then(stream => {handlerFunction(stream)})
function handlerFunction(stream) {
rec = new MediaRecorder(stream);
rec.ondataavailable = e => {
audioChunks.push(e.data);
if (rec.state == "inactive"){
let blob = new Blob(audioChunks,{type:'audio/mp3'});
recordedAudio.src = URL.createObjectURL(blob);
recordedAudio.controls=true;
recordedAudio.autoplay=true;
sendData(blob)
}
}
}
function sendData(data) {}
record.onclick = e => {
record.disabled = true;
record.style.backgroundColor = "blue"
stopRecord.disabled=false;
audioChunks = [];
rec.start();
}
stopRecord.onclick = e => {
record.disabled = false;
stop.disabled=true;
record.style.backgroundColor = "red"
rec.stop();
}
</script>
</html>
Приведенный выше код работает в Windows 10, Mac, Linux и, очевидно, как в Google Chrome, так и в Firefox.
Это простой JavaScript-рекордер и редактор звука. Можешь попробовать.
https://www.danieldemmel.me/JSSoundRecorder/
Можете скачать отсюда
Вы можете использовать Recordmp3js из GitHub для достижения ваших требований. Вы можете записать с микрофона пользователя, а затем получить файл в формате mp3. Наконец загрузите его на свой сервер.
Я использовал это в моей демонстрации. Уже имеется образец, доступный с исходным кодом автора по этому адресу: https://github.com/Audior/Recordmp3js
Демо здесь: http://audior.ec/recordmp3js/
Но в настоящее время работает только на Chrome и Firefox.
Кажется, работает нормально и довольно просто. Надеюсь это поможет.
Вот проект gitHub, который делает именно это.
Он записывает аудио из браузера в формате mp3 и автоматически сохраняет его на веб-сервере. https://github.com/Audior/Recordmp3js
Вы также можете посмотреть подробное объяснение реализации: http://audior.ec/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/
Потоковое аудио в режиме реального времени, не дожидаясь окончания записи: https://github.com/noamtcohen/AudioStreamer
Это передает данные PCM, но вы можете изменить код для потоковой передачи mp3 или Speex
Если вам нужен только формат файла wav , вы можете использовать этот пакет npm без каких-либо изменений. https://www.npmjs.com/package/extendable-media-recorder
import { MediaRecorder, register } from 'extendable-media-recorder';
import { connect } from 'extendable-media-recorder-wav-encoder';
await register(await connect());
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/wav' });