Необходимо добавить в веб-приложение систему односторонних голосовых сообщений - супервайзер нажимает на копку и что-то сообщает удалённому работнику. Сложность состоит в формировании аудио-контента нужного формата. Разобрался с как записывать с MediaRecorder API, но результат использования не совсем соответствует задаче - при просмотре информации о полученных файлах в MPC-HC, оказалось, что там частота аж 48 KHz, когда надо лишь 8 для голоса, чтобы трафика меньше ело, плюс Chrome и Firefox используют разные медиаконтейнеры для сохранения дянных - webm у "хрома" и ogg у "лисы", кодек opus.
Нужно просто снимать сырые WAV семплы по 100 мс с частотой 8 KHz, сжимать их Vorbis-ом, и не пакуя ни в какой контейнер просто отдавать по сети.
Как это сделать на JavaScript (и HTML5)?
Текущий код с MediaRecorder:
Файл audiostreamer.js
var mediaRecorder;
var recording = false;
var recorder = navigator.mediaDevices.getUserMedia({audio:true});
var interval;
function Start(){
recorder.then(stream => {
mediaRecorder = new MediaRecorder(stream);
recording = true;
mediaRecorder.start();
console.log(mediaRecorder.mimeType);
const audioChunks = [];
mediaRecorder.ondataavailable = (event) => {
console.log(audioChunks.length);
var request = new XMLHttpRequest();
request.open("POST", "test_recorder.php");
request.responseType = "arraybuffer";
request.send(event.data);
audioChunks.push(event.data);
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks);
const audioUrl = URL.createObjectURL(audioBlob);
const audio = new Audio(audioUrl);
audio.play();
};
interval = setInterval(function(){mediaRecorder.requestData();},100);
});
}
function Stop(){
if( recording ){
recording = false;
clearInterval(interval);
mediaRecorder.stop();
}
}
Приём сообщений (для теста) test_recorder.php
<?php
if( filter_input(INPUT_SERVER, "REQUEST_METHOD") === "POST" ){
$agent = filter_input(INPUT_SERVER, "HTTP_USER_AGENT");
if( strpos($agent, "Firefox") !== FALSE )
file_put_contents("test.ogg", file_get_contents("php://input"), FILE_APPEND);
else if(strpos($agent, "Chrom") !== FALSE )
file_put_contents("test.webm", file_get_contents("php://input"), FILE_APPEND);
else exit("Unsupported");
}
Тестовая страничка stream.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>stream</title>
<script src="audiostreamer.js"></script>
</head>
<body>
<input type="button" value="Hold to Rec" onmousedown="Start()" onmouseup="Stop()"><br>
</body>
</html>
Нашёл как получить сырой PCM для дальнейших операций:
// Сразу получаем разрешение на микрофон, чтобы потом без запросов работать с контролами
var Media = navigator.mediaDevices.getUserMedia({ audio: true, video: false });
// триггер для старта/остановки записи
var rec = false;
var handleSuccess = function(stream){
var context = new AudioContext();
var source = context.createMediaStreamSource(stream);
var processor = context.createScriptProcessor(1024, 1, 1);
// подключаем аудиопроцессор - тут и начинается снятие звука с устройства
source.connect(processor);
rec = true;
processor.onaudioprocess = function(e){
if( rec ){
// Тут обрабатываем e.inputBuffer.getChannelData(0) (если моно)
// e.inputBuffer.getChannelData(0) это и есть 1-й аудио канал с сырой ИКМ
// Прослушать PCM можно например в Audacity импортировав RawData
var request = new XMLHttpRequest();
request.open("POST", "test_recorder.php");
request.responseType = "arraybuffer";
request.send(e.inputBuffer.getChannelData(0));
}
else{
// отключаем аудиопроцессор
source.disconnect(processor);
}
};
};
function Start(){Media.then(handleSuccess);}
function Stop(){rec = false;}
Ну а алгоритм кодирования в vorbis на js думаю можно найти в гугле. ;)
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Можно ли избавиться от webpack модулей в mainjs? Или есть ещё какие-то методы , чтобы сделать мой код на выходе читаемым? Добавил свой пример и то что...
Всем привет ,как будет выглядеть если явную работу с DOM тут заменить на refs? У меня что-то не выходит так заменить
В data-url ссылка на конкретный объект, однако "поделиться" срабатывает на всю страницу