Как сохранить вывод MediaRecorder Web API на диск с помощью потока - PullRequest
1 голос
/ 28 марта 2020

Я экспериментирую с MediaStream Recording API в Electron (следовательно, Node.js) и wi sh для обработки вывода в виде потока. Обработка в виде потока позволила бы мне обработать вывод MediaRecorder перед сохранением на диск - например, я мог бы зашифровать его. В моем конкретном случае использования c меня интересует только звук, поэтому у меня нет записи любых видеоэлементов.

Мой самый основной вариант использования c заключается в простом сохранении вывода на диск с использованием потока , но я не могу достичь этой фундаментальной задачи, поэтому я сосредоточу этот вопрос на достижении этого.

Вопрос: Как сохранить вывод MediaRecorder Web API на диск с помощью потока.

Я могу сохранить файл на диск, используя загрузочный файл «hack», предоставлено и описано Google как таковое и успешно использует node.js fs для открытия, преобразования (шифрования), сохранения нового зашифрованного файла и удаления незашифрованного файла. Это означает, что мне в конечном итоге придется сохранять незашифрованные данные на диск. Даже если в течение короткого промежутка времени это выглядит как компромисс в плане безопасности, который, как я думал, будет легко избежать, зашифровав перед сохранением.

Существует риск, что я получаю довольно много проводов, пересекающихся между различными объектами потока , но я удивлен, что я еще не нашел решения в Интернете - поэтому я выскакиваю из своего вишневого вопроса StackOverflow.

Проект, освещающий все, что я пробовал, приведен ниже. Код ключа - запись. js, в функции save ().

В конечном итоге я пытаюсь создать подходящий readStream для подключения к writeStream, созданному с помощью const writeStream = fs.createWriteStream(fPath); с использованием readStream.pipe(writeStream).

Итак, я попробовал следующее:

1. Blob в readStream

Я не могу преобразовать Blob в readStream, только ReadableStream, ReadableStreamDefaultReader или Uint8Array

2. Blob до file (в памяти), а затем используйте fs.createReadStream()

Кажется, я не могу использовать ObjectURL в fs.createReadStream(url), он настаивает на добавлении локального пути. Ответ на на этот вопрос предполагает, что это ограничение fs.createReadStream(), и использование http.get() или request() не подходит в моем случае, потому что я не пытаюсь получить доступ к удаленному ресурсу.

3. Blob до buffer, а затем используйте fs.createReadStream()

Я не могу преобразовать Blob в buffer, который может использоваться в fs.createReadStream(buffer), только arrayBuffer или один с null байтов

Любая помощь будет принята с благодарностью!


Проект:

Узел 12.13.0, Chrome 80.0.3987.158 и Electron 8.2.0.

Настройка:

  • четыре файла: main. js, package. json, index. html, record. js - все одноуровневые в папка проекта.

Содержимое каждого файла:

пакет. json:

{
  "name": "mediarecorderapi",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "electron ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^8.2.0"
  }
}

main. js:

const { app, BrowserWindow, ipcMain } = require('electron');

function createWindow () {
  // Create the browser window.
  let win = new BrowserWindow({
    width: 1000,
    height: 800,
    x:0,
    y:0,
    title: "Media Recorder Example",
    webPreferences: {
      nodeIntegration: true,
      devTools: true
    } 
  })
  win.openDevTools();
  win.loadFile('index.html')
}

app.whenReady().then(createWindow)

index. html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <!-- https://electronjs.org/docs/tutorial/security#csp-meta-tag -->
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using node <script>document.write(process.versions.node)</script>,
    Chrome <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.
    <br/><br/>
    <div>
      <button id="button_rec">Record</button>
      <p>recorder state: <span id="rec_status">inactive</span></p>
    </div>
  </body>

  <script src="record.js"></script>

</html>

запись. js:

Выполните следующее:

npm install -D electron
npm start

1 Ответ

0 голосов
/ 15 апреля 2020

Хорошо, я взломал это ... В конечном счете, суть проблемы была:

как преобразовать blob в readablestream в node.js.

В любом случае, в итоге я нашел следующие шаги: blob> arrayBuffer> array> buffer> readStream

Мне понадобилась следующая функция для преобразования буфер в поток. Ссылка и Node.js документы :

let { Readable } = require('stream') ;

function bufferToStream(buffer) {
    let stream = new Readable ();
    stream.push(buffer);
    stream.push(null);
    return stream;
}

Остальные этапы преобразования являются однострочными, а функция полного сохранения здесь:

save = async function (audioToSave, fPath) {
    console.log(`Trying to save to: ${fPath}`);

    // create the writeStream - this line creates the 0kb file, ready to be written to
    const writeStream = fs.createWriteStream(fPath);
    console.log(writeStream); // WriteStream {...}

    // The incoming data 'audioToSave' is an array containing a single blob of data.
    console.log(audioToSave); // [Blob]

    // Lets convert the data to a Blob
    var audioBlob = new Blob(audioToSave, {
        type: "audio/webm"
    });
    console.log(audioBlob); // Blob {size: 17955, type: "audio/webm"}
    // note: audioBlob = audio[0] has same effect

    // now we go through the following process: blob > arrayBuffer > array > buffer > readStream:
    const arrayBuffer = await audioBlob.arrayBuffer();
    console.log(arrayBuffer); // ArrayBuffer(17955) {}

    const array = new Uint8Array(arrayBuffer);
    console.log(array); // Uint8Array(17955) [26, 69, ... ]

    const buffer = Buffer.from(array);
    console.log(buffer); // Buffer(17955) [26, 69, ... ]

    let readStream = bufferToStream(buffer);
    console.log(readStream); // Readable {_readableState: ReadableState, readable: true, ... }

    // and now we can pipe:
    readStream.pipe(writeStream);

}

И, наконец, я могу передать и продолжить использовать другие функции потока между данными и сохранением, например, шифрование. :)

Надеюсь, это поможет кому-то еще.

...