我正在Electronic(因此是node.js)中试验纵隔流记录API,希望将输出作为流处理。作为流处理将允许我在保存到磁盘之前处理MediaCorder输出-例如,我可以加密它。对于我的特定用例,我只关心音频,所以我没有任何视频元素记录。
下面是一个突出我所尝试的项目。中的关键代码是record.js,在save()函数中。
最终,我将尝试创建一个合适的readstream
来插入使用常量writeStream=fs.createwritestream(fPath)创建的
使用writeStream
;readstream.pipe(writeStream)
。
总结起来,我尝试了以下几种:
无法将blob
转换为readstream
,只能将readablestream
、readablestreamdefaultreader
或uint8array
转换为readstream
2.blob
到文件
(在内存中),然后使用fs.createeadstream()
我似乎不能在fs.createReadStream(url)
中使用objecturl
,它坚持要附加一个本地路径。对此问题的回答表明这是fs.createReadStream()
的限制,在我的情况下使用http.get()
或request()
不合适,因为我不是试图访问远程资源。
3.blob
到buffer
,然后使用fs.createeadstream()
我无法将blob
转换为可在fs.createReadStream(buffer)
中使用的buffer
中使用的buffer
只能转换为arraybuffer
或具有null
字节
非常感谢任何帮助!
项目:
节点12.13.0、铬80.0.3987.158和电子8.2.0。
{
"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"
}
}
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)
<!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>
record.js:
console.log("hello world from record.js()");
const remote = require('electron').remote;
const path = require('path');
const fs = require('fs');
const appDir = remote.app.getPath('userData');
var recButton = document.getElementById("button_rec");
var recStatusSpan = document.getElementById("rec_status");
var recorder;
init = async function () {
// html page event handlers:
recButton.addEventListener("click", () => {record()});
// SET UP MEDIA RECORDER:
var audioStream = await navigator.mediaDevices.getUserMedia({audio: true});
recorder = new MediaRecorder(audioStream, {mimeType: 'audio/webm'});
chunks = [];
recorder.onstart = (event) => {
// ...
}
recorder.ondataavailable = (event) => {
chunks.push(event.data);
}
recorder.onstop = async (event) => {
let fileName = `audiofile_${Date.now().toString()}.webm`;
// download(chunks, fileName); // <== This works at downloading the file to disk, but this is not a stream. Use to prove that audio is being recorded and that it can be saved.
save(chunks, fileName); // <== Trying to save using a stream
chunks = [];
}
}
record = function() {
if(recorder.state == "inactive"){
recorder.start();
recButton.innerHTML = "Stop Recording";
} else {
recorder.stop();
recButton.innerHTML = "Record";
}
recStatusSpan.innerHTML = recorder.state;
}
download = function (audioToSave, fName) {
let audioBlob = new Blob(audioToSave, {
type: "audio/webm"
});
let url = URL.createObjectURL(audioBlob);
let a = document.createElement("a");
a.style = "display: none";
a.href = url;
document.body.appendChild(a);
a.download = fName;
a.click();
// release / remove
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}
save = async function (audioToSave, fName){
let fPath = path.join(appDir, fName);
console.log(`Tring 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 following lines are ultimately trying to get to a suitable readStream to pipe into the writeStream using readStream.pipe(writeStream):
// Multiple attempts written out - uncomment the method you are trying...
// The incoming data 'audioToSave' is an array containing a single blob of data.
console.log(audioToSave); // [Blob]
// ================
// METHOD 1: Stream a Blob:
// Issue: I cannot find a method to convert a Blob to a "readStream"
// ================
// Lets convert the data to a Blob
var audioBlob = new Blob(audioToSave, {
type: "audio/webm"
});
console.log(audioBlob); // Blob {size: 9876, type: "audio/webm"}
// And lets convert the Blob to a Stream
var audioBlobReadableStream = audioBlob.stream(); // https://developer.mozilla.org/en-US/docs/Web/API/Blob/stream
console.log(audioBlobReadableStream ); // ReadableStream {locked: false}
// audioBlobReadableStream.pipe(writeStream); // ERROR: Uncaught (in promise) TypeError: audioBlobReadableStream .pipe is not a function
// audioBlobReadableStream.pipeTo(writeStream); // ERROR: TypeError: Failed to execute 'pipeTo' on 'audioBlobReadableStream': Illegal invocation
// converting the ReadableStream into a ReadableStreamDefaultReader:
var audioBlobReadableStreamDefaultReader = await audioBlobReadableStream.getReader();
console.log(audioBlobReadableStreamDefaultReader) // ReadableStreamDefaultReader {closed: Promise}
// audioBlobReadableStreamDefaultReader.pipe(writeStream); // ERROR: TypeError: audioBlobReadableStreamDefaultReader.pipe is not a function
// audioBlobReadableStreamDefaultReader.pipeTo(writeStream); // ERROR: TypeError: audioBlobReadableStreamDefaultReader.pipeTo is not a function
// And read the reader:
var audioBlobReadStream = await audioBlobReadableStreamDefaultReader.read();
console.log(audioBlobReadStream); // {value: Uint8Array(9876), done: false}
// audioBlobReadStream.pipe(writeStream); // ERROR: TypeError: audioBlobReadStream.pipe is not a function
// audioBlobReadStream.pipeTo(writeStream); // ERROR: TypeError: audioBlobReadStream.pipeTo is not a function
// ================
// METHOD 2: Blob to file, use fs
// Note, fs.createReadStream() requires a string, Buffer, or URL
// Issue: I cannot convert a Blob to a file i can access with fs without downloading it
// ================
// // Or convert to a file (to try to help fs.read)
var audioFile = new File([audioBlob], "audioFileName", { type: 'audio/webm' });
console.log(audioFile); // File {...}
// ====
// a: url
// Issue: fs.createReadStream(url) adds a local path to the objectURL created, and this local path obviously doesn't exist
// ====
var url = URL.createObjectURL(audioFile);
console.log(url); // blob:file:///{GUID}
const fileReadStream = fs.createReadStream(url); // ERROR: events.js:187 ENOENT: no such file or directory, open 'C:\... [Local Path] ...\blob:file:\19428f7d-768a-4eff-b551-4068daa8ceb6'
console.log(fileReadStream); // ReadStream {... path: "blob:file:///{GUID}" ...}
// fileReadStream.pipe(writeStream);
// ====
// b: buffer
// Issue: I cannot convert a blob to a buffer that I can insert into fs.createReadStream(buffer)
// ====
var audioArrayBuffer = await audioBlob.arrayBuffer();
console.log(audioArrayBuffer); // ArrayBuffer(9876)
// bufferReadStream = fs.createReadStream(audioArrayBuffer); // ERROR: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be one of type string, Buffer, or URL. Received type object
let audioBuffer = toBuffer(audioArrayBuffer)
console.log(audioBuffer);
let bufferReadStream = fs.createReadStream(audioBuffer); // ERROR: TypeError [ERR_INVALID_ARG_VALUE]: The argument 'path' must be a string or Uint8Array without null bytes. Received <Buffer 1a 45 ...
function toBuffer(ab) {
// FROM: https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer
var buf = Buffer.alloc(ab.byteLength);
var view = new Uint8Array(ab);
for (var i = 0; i < buf.length; ++i) {
buf[i] = view[i];
}
return buf;
}
}
init();
运行以下操作:
npm install -D electron
npm start
好的,我破解了……最终,挑战的关键是:
如何在node.js中将blob
转换为readablestream
。
总之,总而言之,我发现工作的步骤是:blob
>arraybuffer
>array
>buffer
>readstream
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);
}
我终于可以管道并可以继续在数据和保存之间使用其他流函数,例如,加密。:)
希望这也能帮助别人。
问题内容: 几天前,我被要求检查从互联网下载视频时播放视频的难度。我知道这很容易,因为有人在不久前告诉我。所以,我检查了一下,这非常容易。 问题是我想将视频保存到磁盘上,而不是强迫用户一次又一次地下载它。 问题是访问缓冲区并将其存储到磁盘。 Stackoverflow中的许多答案都说不可能。特别是视频。 我播放视频的原始代码: 问题答案: 解决此问题的方法是使用和: 第一步是添加一条通知,以了解视
问题内容: 我已经使用JavaScript 将源内容从html标记转换为base64String。图像显示清晰。现在,我想使用javascript将该图像保存到用户磁盘。 当我将图像路径设置为html标签的源代码时,此代码效果很好。但是,当我将source传递为base64String时不起作用。 如何实现我想要的? 问题答案: 仅允许用户下载图像或其他文件,您可以使用HTML5 属性。 静态文件
问题内容: 我尝试使用,但它并没有涉及整个结构和层次结构。 另一方面这样做,但我无法保存。 在输出中,我可以将所有子项一个一个地展开,然后选择并复制/粘贴,但是结构非常重要。 问题答案: 更新: 您现在可以右键单击 在“控制台”面板中右键单击>另存为,将记录的消息保存到文件中。 原始答案: 您可以使用下面显示的devtools片段创建console.save方法。它从输入中创建一个FileBlob
问题内容: 当前不支持在file.contents为流时向多个目标发送消息。解决此问题的方法是什么? 问题答案: 当前,在将file.contents用作流时,每个目标必须使用两个流。将来可能会解决此问题。 编辑:此错误现已在gulp中修复。您原始帖子中的代码应该可以正常工作。
我试图深入理解火花洗牌过程。当我开始阅读时,我发现了以下一点。 Spark在完成后将映射任务(ShuffleMapTask)输出直接写入磁盘。 如果有很多小的中间文件作为输出,spark如何处理网络和I/O瓶颈?
问题内容: 我想将此命令保存到另一个文本:awk’{print $ 2}’,它从文本中提取出来。现在我想将输出另存为文本。谢谢 问题答案: =>这将重定向到文件。如果文件不存在,它将创建它。如果文件存在,它将清除(有效)内容并向其中写入新数据 =>这与上面的意思相同,但是如果文件存在,它将向其追加新数据。 例如: 或者,您可以使用命令进行重定向。该命令将重定向到指定的文件以及终端屏幕 有关外壳重定