evancohen / sonus

:speech_balloon: /so.nus/ STT (speech to text) for Node with offline hotword detection
MIT License
625 stars 79 forks source link

pause() and resume() not working #48

Closed evancohen closed 7 years ago

evancohen commented 7 years ago

As reported in #47 (comment). I'll investigate ASAP.

16alexanders commented 7 years ago

Same problem we are having... Sonus won't can't be stopped or pause and always hits the 60 second Google cloud audio streaming request limit

evancohen commented 7 years ago

Guessing this has to do with the Google Cloud Speech GA (they changed their endpointer types). I should be able to look at this tomorrow.

sharmmoh1983 commented 7 years ago

After stopping Sonus recording stops using Sonus.stop();

But when I want to start the recording by calling Sonus.start(sonus); and triggering hotword I am getting:

events.js:160 throw er; // Unhandled 'error' event ^

Error: write after end at writeAfterEnd (_stream_writable.js:166:12) at PassThrough.Writable.write (_stream_writable.js:217:5) at Socket. (/Applications/MAMP/htdocs/project/node_modules/node-record-lpcm16/index.js:58:15) at emitOne (events.js:96:13) at Socket.emit (events.js:188:7) at readableAddChunk (_stream_readable.js:177:18) at Socket.Readable.push (_stream_readable.js:135:10) at Pipe.onread (net.js:542:20)

Kindly let me know the best way to start the recording for next utterance from the user after stopping the recording after calling Sonus.stop()

16alexanders commented 7 years ago

I believe I found the error... You need to change END_OF_SINGLE_UTTERANCE -> END_OF_UTTERANCE

I am away from keyboard on mobile so can't do a pull request.

We ran into similar issues elsewhere for example Google changed speechContext to speechContexts and sampleRate to sampleRateHerz...

16alexanders commented 7 years ago

@sharmmoh1983 I found in a Google Forums thread that @evancohen specifically created pause and resume as alternatives to stopping and starting as that produces the error you noted.

https://groups.google.com/a/kitt.ai/forum/#!topic/snowboy-discussion/9ebzZiHC6po

To test whether Sonus.pause("nameOfInstance") and Sonus.resume("nameOfInstance") are working... enable the verbose flag in index.js on Sonus.start("nameOfInstance"), pause it, and then see if it continues recording.

sonus.on('final-result', result => {
  console.log("Final", result);
  Sonus.pause(sonus);
  if (trigger == "snowboy" || trigger == "viewglass" || trigger == "smartglass") {
    // collapse commands
    result = result.replace("navigate to", "go");
    result = result.replace("navigate", "go");
    result = result.replace("go to", "go");

    var results = result.split(" ");
    console.log(result, results);
    if (results.length > 1) {
        var command = results[0];
        switch(command) {
            case "go":
                let commandBody = result.replace(command, "");
                var args = {
                    path: { command: "handleSms" }, // path substitution var
                    parameters: { body: result, controllerid: controllerID }
                };
                client.methods.navigateCommand(args, function (data, response) {
                    // parsed response body as js object
                    console.log(data);
                    // raw response
                    // console.log(response);
                });
            break;
            default: 
                console.log("Unknown command: "+command)
            break;
        }

    }
  }
  Sonus.resume(sonus);
})

This is the code I am using to try to pause the mic when a final result comes in, then resume it again afterwards. Honestly without pause() and resume() working Sonus is useless in our application because we can only issue one command that inevitably runs over the 60 seconds of audio allowed by Google and you will get a GRPC Deadline Error.

16alexanders commented 7 years ago

I'm not really sure how Sonus.pause() and Sonus.resume() are even working:

Sonus.pause = sonus => sonus.mic.pause() Sonus.resume = sonus => sonus.mic.resume()

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
}

const record = require('node-record-lpcm16')

https://github.com/gillesdemey/node-record-lpcm16

I don't see anything about "pause" or "resume" in this library....

I'm probably going to try to use this library https://github.com/ashishbajaj99/mic since it provides unless @evancohen manages to fix the code in Sonus... we are using the library for a prototype demo installation that needs to setup and running for tomorrow.

evancohen commented 7 years ago

@16alexanders pause() and resume() are native to Node buffers (which is what record.start() returns).

Check out my comment from the other day for the correct usage: https://github.com/evancohen/sonus/issues/47#issuecomment-306249217

As for Sonus.stop(), this is the expected behavior.

sharmmoh1983 commented 7 years ago

@evancohen Sonus.stop() is working fine but how to properly start the sonus after stopping it as it is giving me error @16alexanders can you create a pull request of your changes(mic library) which are working as the changes you have mentioned are not working

sharmmoh1983 commented 7 years ago

@16alexanders Where I need to make this change:

END_OF_SINGLE_UTTERANCE -> END_OF_UTTERANCE

16alexanders commented 7 years ago

@sharmmoh1983 you can make the change in index.js for Sonus but it didnt fix the issue. Like you, I can stop Sonus using Sonus.stop() but I can't restart it. @evancohen in its current form it's impossible to give Sonus more than one command. If I don't stop Sonus in the .on('final-result') function then I exceed the 1 minute of audio for Google Speech API and get an error..... if I do stop it there is no error but I simply can't restart it again.

@evancohen I'm confused as to how anyone is using Sonus successfully in their projects because of this issue?

This is my code... very short and simple https://pastebin.com/TU4qm7FQ

16alexanders commented 7 years ago

If I use Sonus.pause(sonus) instead of Sonus.stop(sonus) it doesn't stop the recording and again... I end up with a GRPC deadline error because it exceeds 1 minute of audio

sharmmoh1983 commented 7 years ago

This is my code... very short and simple https://pastebin.com/TU4qm7FQ

@16alexanders Is this working code. Is Sonus start working in this code

evancohen commented 7 years ago

@sharmmoh1983 you shouldn't be using stop on line 45 because once that is called you can't call .start again.

I think there's an issue with the deprecation of the v1beta google speech API. I'll be looking at it tonight.

16alexanders commented 7 years ago

@sharmmoh1983 try to be constructive and read the information I'm posting instead of just searching for code that works... Maybe you could help look into this. If you follow the thread I already said that it wasn't working. Hopefully @evancohen can take a look and help us fix this issue so both of our projects can be up and running. :)

sharmmoh1983 commented 7 years ago

@16alexanders : I have some code which is kind of doing what is required, but does not seem to be the right approach so i have done some constructive work ,it was just out of curiosity searching for working code ...my bad for missing your point in the thread

evancohen commented 7 years ago

Got a fix in the works here: gillesdemey/node-record-lpcm16#38

sharmmoh1983 commented 7 years ago

Thanks @evancohen for your support ...it is working now

16alexanders commented 7 years ago

@evancohen Works good... the only issue I'm having is that I still end up eventually exceeding the maximum allowed stream duration.

sonus.on('final-result', result => {
  console.log("Final", result);
  Sonus.pause(sonus);
  if (trigger == "snowboy" || trigger == "viewglass" || trigger == "smartglass") {
    // collapse commands
    result = result.replace("navigate to", "go");
    result = result.replace("navigate", "go");
    result = result.replace("go to", "go");

    var results = result.split(" ");
    if (results.length > 1) {
    console.log(result, results);
        var command = results[0];
        switch(command) {
            case "go":
                let commandBody = result.replace(command, "");
                var args = {
                    path: { command: "handleSms" }, // path substitution var
                    parameters: { body: result, controllerid: controllerID }
                };
                client.methods.navigateCommand(args, function (data, response) {
                    // parsed response body as js object
                    console.log(data);
                    // raw response
                    // console.log(response);
                });
            break;
            default: 
                console.log("Unknown command: "+command)
            break;
        }

    }
  }
  Sonus.resume(sonus);
});

Should I be doing this differently?

16alexanders commented 7 years ago

@evancohen Nevermind... I ended up doing a workaround... in the error handler I simply restart Sonus with Sonus.start(sonus) after it complains about exceeding the max length of audio stream.

evancohen commented 7 years ago

You shouldn't be getting errors about max audio length after this change: https://github.com/evancohen/sonus/commit/466e3357f2db6124400f9f3690b47d447f48270a#diff-168726dbe96b3ce427e7fedce31bb0bcR49

Can you confirm that you have this line?

evancohen commented 7 years ago

Closing this issue because this is no longer a problem