'use strict' const record = require('node-record-lpcm16') const stream = require('stream') const { Detector, Models } = require('snowboy') var fs = require('fs'); var ts=require('../../timeStamp.js') var fd=null; const ERROR = { NOT_STARTED: "NOT_STARTED", INVALID_INDEX: "INVALID_INDEX" } var writelog = function(string){ if(fd == null){ fd=fs.openSync('/home/pi/sonus.log','a',fs.O_APPEND) } fs.writeFileSync(fd,ts.timeStamp()+" "+string+"\n") } const CloudSpeechRecognizer = {} CloudSpeechRecognizer.init = recognizer => { const csr = new stream.Writable() csr.listening = false csr.recognizer = recognizer return csr } CloudSpeechRecognizer.startStreaming = (options, audioStream, cloudSpeechRecognizer) => { if (cloudSpeechRecognizer.listening) { writelog('cloudSpeechRecognizer already listening') return } let hasResults = false cloudSpeechRecognizer.listening = true writelog('cloudSpeechRecognizer setup to listen') const request = { config: { encoding: 'LINEAR16', sampleRateHertz: 16000, languageCode: options.language, speechContexts: options.speechContexts || null }, singleUtterance: true, interimResults: true, } const recognitionStream = cloudSpeechRecognizer.recognizer .streamingRecognize(request) .on('error', err => { cloudSpeechRecognizer.emit('error', err) writelog('cloudSpeechRecognizer error ='+err) stopStream() }) .on('data', data => { writelog('cloudSpeechRecognizer data') if (data.results[0] && data.results[0].alternatives[0]) { writelog('cloudSpeechRecognizer some data') hasResults = true; // Emit partial or final results and end the stream if (data.error) { cloudSpeechRecognizer.emit('error', data.error) writelog('cloudSpeechRecognizer data error='+ data.error) stopStream() } else if (data.results[0].isFinal) { cloudSpeechRecognizer.emit('final-result', data.results[0].alternatives[0].transcript) writelog('cloudSpeechRecognizer data final') stopStream() } else { cloudSpeechRecognizer.emit('partial-result', data.results[0].alternatives[0].transcript) writelog('cloudSpeechRecognizer data partial='+data.results[0].alternatives[0].transcript) } } else { writelog('cloudSpeechRecognizer data something else') // Reached transcription time limit if(!hasResults){ writelog('cloudSpeechRecognizer data something else no prior results') cloudSpeechRecognizer.emit('final-result', '') } stopStream() } }) const stopStream = () => { cloudSpeechRecognizer.listening = false audioStream.unpipe(recognitionStream) recognitionStream.end() writelog('module detector csr no longer listening') } audioStream.pipe(recognitionStream) } const Sonus = {} Sonus.annyang = require('./lib/annyang-core.js') Sonus.init = (options, recognizer) => { // don't mutate options const opts = Object.assign({}, options), models = new Models(), sonus = new stream.Writable(), csr = CloudSpeechRecognizer.init(recognizer) sonus.mic = {} sonus.recordProgram = opts.recordProgram sonus.device = opts.device sonus.started = false // If we don't have any hotwords passed in, add the default global model opts.hotwords = opts.hotwords || [1] opts.hotwords.forEach(model => { models.add({ file: model.file || 'node_modules/snowboy/resources/snowboy.umdl', sensitivity: model.sensitivity || '0.5', hotwords: model.hotword || 'default' }) }) // defaults opts.models = models opts.resource = opts.resource || 'node_modules/snowboy/resources/common.res' opts.audioGain = opts.audioGain || 2.0 opts.language = opts.language || 'en-US' //https://cloud.google.com/speech/docs/languages const detector = sonus.detector = new Detector(opts) detector.on('silence', () => {writelog('module detector silence');sonus.emit('silence')}) detector.on('sound', () => {writelog('module detector sound');sonus.emit('sound')}) // When a hotword is detected pipe the audio stream to speech detection detector.on('hotword', (index, hotword) => { writelog('sonus trigger hotword') sonus.trigger(index, hotword) writelog('module detector ready for more') }) // Handel speech recognition requests csr.on('error', error => {writelog('module detector csr error '+error);sonus.emit('error', { streamingError: error })}) csr.on('partial-result', transcript => {writelog('module detector csr partial '+transcript);sonus.emit('partial-result', transcript)}) csr.on('final-result', transcript => { writelog('module detector csr final result '+transcript) sonus.emit('final-result', transcript) Sonus.annyang.trigger(transcript) }) sonus.trigger = (index, hotword) => { if (sonus.started) { try { let triggerHotword = (index == 0) ? hotword : models.lookup(index) writelog('module detector trigger hotword') sonus.emit('hotword', index, triggerHotword) CloudSpeechRecognizer.startStreaming(opts, sonus.mic, csr) writelog('module detector trigger streaming ready') } catch (e) { writelog('module detector trigger start streaming error='+e) throw ERROR.INVALID_INDEX } } else { writelog('module detector trigger start streaming error=not started') throw ERROR.NOT_STARTED } } sonus.pause = () => { record.pause() } sonus.resume = () => { record.resume() } return sonus } Sonus.start = sonus => { sonus.mic = record.start({ threshold: 0, device: sonus.device || null, recordProgram: sonus.recordProgram || "rec", verbose: false }) sonus.mic.pipe(sonus.detector) sonus.started = true } Sonus.trigger = (sonus, index, hotword) => { writelog('module detector trigger');sonus.trigger(index, hotword);} Sonus.pause = sonus => { sonus.mic.pause(); writelog('module detector pause');sonus.emit('partial-result', "pause recording"); } Sonus.resume = sonus => { sonus.mic.resume(); writelog('module detector resume') ;sonus.emit('partial-result', "resume recording");} Sonus.stop = () => { record.stop(); writelog('module detector stop');sonus.emit('partial-result', "stop recording") ;} module.exports = Sonus