const speech = require('@google-cloud/speech'); const portAudio = require('naudiodon'); // const rs = fs.createReadStream('rawAudio.wav'); // Creates a client const client = new speech.SpeechClient(); const encoding = 'LINEAR16'; const sampleRateHertz = 16000; const languageCode = 'en-US'; const audioContainer = { input: '', buffers: [] } const config = { encoding: encoding, sampleRateHertz: sampleRateHertz, languageCode: languageCode, }; /** * Note that transcription is limited to 60 seconds audio. * Use a GCS file for audio longer than 1 minute. */ async function transcribeSpeech (audio) { const request = { config: config, audio: audio, }; // Detects speech in the audio file. This creates a recognition job that you // can wait for now, or get its result later. const [operation] = await client.longRunningRecognize(request); // Get a Promise representation of the final result of the job const [response] = await operation.promise(); const transcription = response.results .map(result => result.alternatives[0].transcript) .join('\n'); console.log(`Transcription: ${transcription}`); } let record = true; // Create an instance of AudioIO with inOptions (defaults are as below), which will return a ReadableStream const ia = new portAudio.AudioIO({ inOptions: { channelCount: 1, sampleFormat: 16, sampleRate: 16000, deviceId: -1, closeOnError: false, }, }); ia.setEncoding('base64'); ia.start(); ia.on('data', (chunk) => { if (record) { console.log('recording data'); audioContainer.input += chunk; } else { if (audioContainer.input.length) audioContainer.input = ""; } }); const ao = new portAudio.AudioIO({ outOptions: { sampleFormat: 16, channelCount: 1, sampleRate: 16000, deviceId: -1, closeOnError: false, } }); ao.start(); let counter = 0; const tests = []; function testCallback() { play(tests[0]) } function splitArrayIntoChunksOfLen(buf, len) { const chunks = []; let i = 0; let L = len; console.log(buf.byteLength) while(i < buf.byteLength) { chunks.push(buf.slice(i, L)); i = L; L += len; } chunks.forEach(c => console.log(c)) return chunks; } function play(input) { let i = 0; const buf = Buffer.from(input, 'base64'); // format buffers into half their size to account for writable highwaterMark. const audio = splitArrayIntoChunksOfLen(buf, 8192); // call this fuction after last audio chunk has been written. const callback = () => { // TODO: clear portAudio writable buffer on write end. } write(); // iterate through audio array and write buffers to portAudio writable. function write() { let ok = true; do { if (i === audio.length - 1) { // write last chunk. ao.write(audio[i], null, callback); } else { // check for backpreassure. ok = ao.write(audio[i], null); } i++; } while (i < audio.length && ok); if (i < audio.length) { // Had to stop early! // Write some more once it drains. ao.once('drain', write); } } } // utility function used by play func function bufSplit(input){ const result = []; input.forEach((b) => { // split buffer into two. result.push(b.slice(0, b.length / 2), b.slice(b.length / 2, b.length)); }); return result; } async function test() { transcribeSpeech({ content: Buffer.from(audioContainer.input, 'base64') }); tests.push(audioContainer.input) counter++; console.log('audio string length:', audioContainer.input.length) console.log('buffers written: ', audioContainer.buffers.length) } setTimeout(async () => { record = false; test() }, 4000); // setTimeout(() => { // record = true; // }, 6000) // // setTimeout(async () => { // record = false; // test(); // }, 9000); // // setTimeout(() => { // record = true; // }, 11000) // // setTimeout(async () => { // record = false; // test(); // }, 14000); // setTimeout(async () => { ia.quit(); testCallback() return; }, 6000);