如何使用流将 MediaRecorder Web API 输出保存到磁盘

Ada*_*rsh 6 javascript stream node.js electron mediarecorder-api

我正在Electron(因此Node.js )中试验MediaStream Recording API,并希望将输出作为流处理。作为流处理将允许我在之前处理 MediaRecorder 输出- 例如,我可以对其进行加密。对于我的具体用例,我只关心音频,所以我没有录制任何视频元素。

\n\n

我最基本的用例是简单地使用流将输出保存到磁盘,但我似乎无法实现这一基本任务,所以我将把这个问题集中在实现这一点上。

\n\n

问题:如何使用流将 MediaRecorder Web API 输出保存到磁盘。

\n\n

我可以使用下载 \xe2\x80\x9chack\xe2\x80\x9d(由 Google 此处提供和描述)将文件保存到磁盘,并成功使用node.js fs打开、转换(加密)、保存新文件加密的文件,并删除未加密的文件。这意味着我最终必须将未加密的数据保存到磁盘上。即使时间很短,这也感觉像是一种安全妥协,我认为通过在保存之前加密可以很容易地避免这种情况。

\n\n

我存在在不同流对象之间交叉很多电线的风险,但令我惊讶的是我还没有在网上找到解决方案 - 因此我提出了我的 StackOverflow 问题樱桃。

\n\n

下面是一个突出显示我所尝试过的所有项目的项目。关键代码是record.js,在save()函数中。

\n\n

最终,我试图创建一个合适的插件readStream来插入使用 usingwriteStream创建的。const writeStream = fs.createWriteStream(fPath);readStream.pipe(writeStream)

\n\n

总而言之,我尝试了以下方法:

\n\n

1.BlobreadStream

\n\n

我无法转换BlobreadStream, only ReadableStream,ReadableStreamDefaultReaderUint8Array

\n\n

2.Blobfile(在内存中)然后使用fs.createReadStream()

\n\n

我似乎无法使用ObjectURLin fs.createReadStream(url),它坚持附加本地路径。\n这个问题fs.createReadStream()的答案表明这是使用http.get()或的限制request()不适合我的情况,因为我没有尝试访问远程资源。

\n\n

3.Blob然后buffer使用fs.createReadStream()

\n\n

我无法转换为可以在 中使用的Bloba ,只能转换为一个或 一个bufferfs.createReadStream(buffer)arrayBuffernull字节的

\n\n

任何帮助是极大的赞赏!

\n\n
\n\n

项目:

\n\n

节点 12.13.0、Chrome 80.0.3987.158 和 Electron 8.2.0。

\n\n

设置:

\n\n
    \n
  • 四个文件:main.jspackage.jsonindex.htmlrecord.js都是项目文件夹中的单层文件。
  • \n
\n\n

每个文件的内容:

\n\n

包.json:

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

main.js:

\n\n
const { app, BrowserWindow, ipcMain } = require(\'electron\');\n\nfunction createWindow () {\n  // Create the browser window.\n  let win = new BrowserWindow({\n    width: 1000,\n    height: 800,\n    x:0,\n    y:0,\n    title: "Media Recorder Example",\n    webPreferences: {\n      nodeIntegration: true,\n      devTools: true\n    } \n  })\n  win.openDevTools();\n  win.loadFile(\'index.html\')\n}\n\napp.whenReady().then(createWindow)\n
Run Code Online (Sandbox Code Playgroud)\n\n

索引.html:

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

记录.js:

\n\n

\r\n
\r\n
{\n  "name": "mediarecorderapi",\n  "version": "1.0.0",\n  "description": "",\n  "main": "main.js",\n  "scripts": {\n    "test": "echo \\"Error: no test specified\\" && exit 1",\n    "start": "electron ."\n  },\n  "keywords": [],\n  "author": "",\n  "license": "ISC",\n  "devDependencies": {\n    "electron": "^8.2.0"\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

运行以下命令:

\n\n
npm install -D electron\nnpm start\n
Run Code Online (Sandbox Code Playgroud)\n

Ada*_*rsh 8

好的,我破解了\xe2\x80\xa6\n最终,挑战的症结在于:

\n\n

如何blobreadablestream转换 node.js。

\n\n

无论如何,总而言之,我发现有效的步骤是:blob> arrayBuffer> array> buffer>readStream

\n\n

我需要以下函数将缓冲区转换为流。参考Node.js 文档

\n\n
let { Readable } = require(\'stream\') ;\n\nfunction bufferToStream(buffer) {\n    let stream = new Readable ();\n    stream.push(buffer);\n    stream.push(null);\n    return stream;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

其余的转换步骤都是简单的,完整的保存功能在这里:

\n\n
save = async function (audioToSave, fPath) {\n    console.log(`Trying to save to: ${fPath}`);\n\n    // create the writeStream - this line creates the 0kb file, ready to be written to\n    const writeStream = fs.createWriteStream(fPath);\n    console.log(writeStream); // WriteStream {...}\n\n    // The incoming data \'audioToSave\' is an array containing a single blob of data.\n    console.log(audioToSave); // [Blob]\n\n    // Lets convert the data to a Blob\n    var audioBlob = new Blob(audioToSave, {\n        type: "audio/webm"\n    });\n    console.log(audioBlob); // Blob {size: 17955, type: "audio/webm"}\n    // note: audioBlob = audio[0] has same effect\n\n    // now we go through the following process: blob > arrayBuffer > array > buffer > readStream:\n    const arrayBuffer = await audioBlob.arrayBuffer();\n    console.log(arrayBuffer); // ArrayBuffer(17955) {}\n\n    const array = new Uint8Array(arrayBuffer);\n    console.log(array); // Uint8Array(17955) [26, 69, ... ]\n\n    const buffer = Buffer.from(array);\n    console.log(buffer); // Buffer(17955) [26, 69, ... ]\n\n    let readStream = bufferToStream(buffer);\n    console.log(readStream); // Readable {_readableState: ReadableState, readable: true, ... }\n\n    // and now we can pipe:\n    readStream.pipe(writeStream);\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我终于可以通过管道并继续在数据和保存之间使用其他流函数,例如加密。:)

\n\n

希望这对其他人也有帮助。

\n