What solved my problem is the combination of a few sources.
First, installing gRPC (thanks to murgatroid99 and Nicolas Noble):
npm rebuild grpc --runtime=electron --target=4.0.3
I assume this installs the gRPC
binaries so I can use them on Electron 4.0.3
(not the latest because it seems that it doesn't work on the latest)
Though since it just installs gRPC
, I still need to install Electron
separately, so:
yarn add -D electron@4.0.3
If you want to keep it in one line:
npm rebuild grpc --runtime=electron --target=4.0.3 && yarn add -D electron@4.0.3
Then I received this error and Googled it, though didn't find a clear answer.
Then I realized, thanks to this article (translated to English), that the module node-record-lpcm16 was just being used as a bridge from my software to SoX.
So in fact, this error is just about not being able to use the sox
program from Command Line (can't spawn a process), at least not purely based on just typing sox
(I could on CMD, but for some reason my application couldn't).
Hence I:
1) Changed recordProgram: 'rec'
to recordProgram: 'sox'
(renderer.ts
)
2) Entered node_modules\node-record-lpcm16\index.js
3) Changed
case 'sox':
var cmd = 'sox';
var cmdArgs = [
'-q', // show no progress
'-t', 'waveaudio', // audio type
'-d', // use default recording device
'-r', options.sampleRate, // sample rate
'-c', options.channels, // channels
'-e', 'signed-integer', // sample encoding
'-b', '16', // precision (bits)
'-', // pipe
// end on silence
'silence', '1', '0.1', options.thresholdStart || options.threshold + '%',
'1', options.silence, options.thresholdEnd || options.threshold + '%'
];
break
to
case 'sox':
var cmd = 'C:\\Program Files (x86)\\sox-14-4-2\\sox.exe';
var cmdArgs = [ // ^ SPECIFYING FULL PATH
'-q', // show no progress
'-t', 'waveaudio', // audio type
'-d', // use default recording device
'-r', options.sampleRate, // sample rate
'-c', options.channels, // channels
'-e', 'signed-integer', // sample encoding
'-b', '16', // precision (bits)
'-', // pipe
// end on silence
'silence', '1', '0.1', options.thresholdStart || options.threshold + '%',
'1', options.silence, options.thresholdEnd || options.threshold + '%'
];
break
Then, turns out that without adding an extra bit that's mentioned in the aforementioned article,, recording the microphone wouldn't work, so:
case 'sox':
var cmd = 'C:\\Program Files (x86)\\sox-14-4-2\\sox.exe';
var cmdArgs = [
'-q', // show no progress
'-t', 'waveaudio', // audio type
'-d', // use default recording device
'-r', options.sampleRate, // sample rate
'-c', options.channels, // channels
'-e', 'signed-integer', // sample encoding
'-t', 'raw', // Added
'-b', '16', // precision (bits)
'-', // pipe
// end on silence
'silence', '1', '0.1', options.thresholdStart || options.threshold + '%',
'1', options.silence, options.thresholdEnd || options.threshold + '%'
];
break
If you're getting Google Cloud credential authentication issues, refer to this answer
And these resolved my problems of being able to record!
Then I had a problem that Google limits the audio stream to 65 seconds, so via the stack trace lines, I traced down the lines that caused the problem & commented those lines, until I reached the 2nd possible output in renderer.ts
(output Reached transcription time limit, press Ctrl+C
), so I just wrapped the variable & record functions inside a function and called the function recursively, like so:
function startRecording() {
// Create a recognize stream
const recognizeStream = client
.streamingRecognize(request)
.on('error', console.error)
.on('data', data => {
if (data.results[0] && data.results[0].alternatives[0]) {
console.log(`Transcription: ${data.results[0].alternatives[0].transcript}\n`);
} else {
console.log(`\n\nReached transcription time limit, press Ctrl+C\n`);
startRecording();
}
});
// Start recording and send the microphone input to the Speech API
record
.start({
sampleRateHertz: sampleRateHertz,
threshold: 0,
// Other options, see https://www.npmjs.com/package/node-record-lpcm16#options
verbose: false,
recordProgram: 'sox', // Try also "arecord" or "sox"
silence: '10.0',
})
.on('error', console.error)
.pipe(recognizeStream);
}
startRecording();
And this solution seems to solve that problem!