Skip to content
This repository has been archived by the owner on Sep 8, 2024. It is now read-only.

prevent audio playing between mic record and utt handling #2621

Merged
merged 3 commits into from
Jun 29, 2020

Conversation

krisgesling
Copy link
Contributor

Description

This creates a separate restore_volume handler for the end of mic recording. Previously the same handler was used for speech and recording.

When the recording finishes, there should either be an utterance to be handled, or a speech.recognition.unknown message meaning the transcription failed because the user didn't say anything (or it was a false activation).

If the latter and no utterance was detected, then we immediately restore the volume. Otherwise we do not restore the volume, and the utterance is passed onto the intent handlers. Once Mycroft responds to that utterance, the _restore_volume handler attached to the audio_output_end message is triggered.

This means that if audio is playing and:

  • a user says "Hey Mycroft, stop"
    • then no more audio plays
  • a user asks a question such as "Hey Mycroft, what's 7 times 3"
    • then audio is paused until the response is complete.
      Once the response has finished, audio resumes.

Need to confirm

Are there other paths that I'm not considering?
Is there a chance that neither a failed transcription, nor Mycroft replying would occur and therefore leave the audio in an undesired state?

How to test

Hey Mycroft, what's the news
Hey Mycroft, what time is it
Hey Mycroft, stop

Ensure that no snippets of news audio are played during interactions. Should still play between questions.

Contributor license agreement signed?

@devops-mycroft devops-mycroft added the CLA: Yes Contributor License Agreement exists (see https://github.com/MycroftAI/contributors) label Jun 19, 2020
@devops-mycroft
Copy link

Voight Kampff Integration Test Failed (Results)

@forslund
Copy link
Collaborator

Would there be an issue with skill handlers that don't produce a spoken sentence, for example just using the skill.acknowledge()?

@krisgesling
Copy link
Contributor Author

I've been trying to think of the best way to know that "a Skill has finished". It's also possible that Skills do something and don't respond at all, even an acknowledge tone. Certainly not recommended but still very possible.

So perhaps we can re-use the VK then_wait method with a timeout of ~4 seconds (?), and if no speak command was detected then we restore the volume anyway. This should give most Skills plenty of time to do something. That way even if an expected action isn't taken, it falls back to restoring audio playback.

@forslund
Copy link
Collaborator

Sounds like a good solution. An alternative is to add something to the on_end() skill handler callback, but the timeout should probably be there first step since it'll be pretty safe.

@pep8speaks
Copy link

pep8speaks commented Jun 25, 2020

Hello @krisgesling! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2020-06-29 05:01:08 UTC

@krisgesling
Copy link
Contributor Author

Have now modified so that the volume will restore after 8 seconds regardless of what happens. So if a Skill consumes an intent and does absolutely nothing or just plays an acknowledgement beep, the playing audio will be restored.

Had to push it to a higher 8 seconds as unknown intents take longer to respond. This should be the minority of cases so I don't see it as a problem that the audio stops playing for slightly longer.

@devops-mycroft
Copy link

Voight Kampff Integration Test Failed (Results)

2 similar comments
@devops-mycroft
Copy link

Voight Kampff Integration Test Failed (Results)

@devops-mycroft
Copy link

Voight Kampff Integration Test Failed (Results)

Copy link
Collaborator

@forslund forslund left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks real nice and seems to work very well! I noted a couple of nit-picks, I'm going to duplicate this setup in the spotify-skill. Perhaps also add it to the volume skill?

LOG.debug('restoring volume')
self.current.restore_volume()

def wait_for_speak(bus, timeout=8):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bus doesn't seem to be used (instead the one associated with the class is used)? can the argument be removed?

Args:
message: message bus message, not used but required
"""
def __restore_volume():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need the __ it's local so it won't need to be made anonymous?

bus (Mycroft MessageBus): Bus instance to listen on
timeout (int): how long to wait, defaults to 8 sec
"""
self.speak_msg_detected = False
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like this can be a local variable instead of an object variable to keep things encapsulated.
speak_msg_detected = False here

and in detected_speak have a line
nonlocal speak_message_detected

feels like otherwise there could be issues with re-entrancy.

self.bus.remove('speak', detected_speak)
return self.speak_msg_detected

if self.current is None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably a personal opinion but perhaps invert this logic for clarity

        if self.current:
            self.bus.on('recognizer_loop:speech.recognition.unknown',
                        __restore_volume)
            speak_msg_detected = wait_for_speak(self.bus)
            if not speak_msg_detected:
                __restore_volume()
            self.bus.remove('recognizer_loop:speech.recognition.unknown',
                            __restore_volume)
        else:
            LOG.debug("No audio service to restore volume of")

@krisgesling
Copy link
Contributor Author

Great feedback, thanks Ake :)

Have changed each of them.

@devops-mycroft
Copy link

Voight Kampff Integration Test Failed (Results)

@devops-mycroft
Copy link

Voight Kampff Integration Test Succeeded (Results)

@krisgesling krisgesling merged commit 37a4791 into dev Jun 29, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
CLA: Yes Contributor License Agreement exists (see https://github.com/MycroftAI/contributors)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants