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

Commit

Permalink
Feature button behavior (#365)
Browse files Browse the repository at this point in the history
* Several changes related to button pressing on the Mycroft unit:
- Pressing the button when it isn't listening starts it listening
- Pressing the button when listening will stop the listen
- Added a mycroft.util.signal() mechanism for out-of-thread communication
- Pressing the button now creates an "buttonPress" signal from the Enclosure
- The viseme playback and aplay check for the 'buttonPress' signal to abort
- Removed "Sorry I didn't catch that", irritating during false activations

* Fixed spacing that pep8 yelled about
  • Loading branch information
Steve authored and aatchison committed Sep 22, 2016
1 parent 1be93c2 commit cac955f
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 4 deletions.
2 changes: 2 additions & 0 deletions mycroft/client/enclosure/enclosure.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from mycroft.messagebus.client.ws import WebsocketClient
from mycroft.messagebus.message import Message
from mycroft.util import play_wav
from mycroft.util import create_signal
from mycroft.util import str2bool
from mycroft.util.audio_test import record
from mycroft.util.log import getLogger
Expand Down Expand Up @@ -80,6 +81,7 @@ def process(self, data):
self.client.emit(Message(data))

if "mycroft.stop" in data:
create_signal('buttonPress')
self.client.emit(Message("mycroft.stop"))

if "volume.up" in data:
Expand Down
3 changes: 3 additions & 0 deletions mycroft/client/enclosure/mouth.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@


from mycroft.util.log import getLogger
from mycroft.util import check_for_signal
import time

__author__ = 'jdorleans'
Expand Down Expand Up @@ -69,6 +70,8 @@ def viseme(self, event=None):
lisPairs = visCmds.split(",")
timeStart = time.time()
for pair in lisPairs:
if check_for_signal('buttonPress'):
return # abort! (aplay should have already been killed)
vis_dur = pair.split(":")
if vis_dur[0] >= "0" and vis_dur[0] <= "6":
elap = time.time() - timeStart
Expand Down
2 changes: 1 addition & 1 deletion mycroft/client/speech/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def process_audio(self, audio):
self.transcribe([audio])
except sr.UnknownValueError: # TODO: Localization
logger.warn("Speech Recognition could not understand audio")
self.__speak("Sorry, I didn't catch that.")
# self.__speak("Sorry, I didn't catch that.")

def __speak(self, utterance):
payload = {
Expand Down
30 changes: 27 additions & 3 deletions mycroft/client/speech/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@
from mycroft.tts import tts_factory
from mycroft.util.log import getLogger
from mycroft.util import kill, connected
from mycroft.util import play_mp3

logger = getLogger("SpeechClient")
client = None
tts = tts_factory.create()
mutex = Lock()
mutexTalking = Lock()
loop = None

config = ConfigurationManager.get()
Expand All @@ -58,17 +59,39 @@ def handle_utterance(event):
client.emit(Message('recognizer_loop:utterance', event))


# class TalkThread (Thread):
# def __init__(self, utterance, loop, tts, client, mutex):
# Thread.__init__(self)
# self.utterance = utterance
# self.tts = tts
# self.loop = loop
# self.client = client
# self.mutex = mutex
#
# def run(self):
# try:
# # logger.info("Speak: " + utterance)
# self.loop.mute()
# self.tts.execute(self.utterance, self.client)
# finally:
# self.loop.unmute()
# self.mutexTalking.release()
# self.client.emit(Message("recognizer_loop:audio_output_end"))


def mute_and_speak(utterance):
mutex.acquire()
mutexTalking.acquire()
client.emit(Message("recognizer_loop:audio_output_start"))
try:
logger.info("Speak: " + utterance)
loop.mute()
tts.execute(utterance, client)
finally:
loop.unmute()
mutex.release()
mutexTalking.release()
client.emit(Message("recognizer_loop:audio_output_end"))
# threadTalk = TalkThread(utterance, loop, tts, client, mutexClient)
# threadTalk.start()


def handle_multi_utterance_intent_failure(event):
Expand All @@ -94,6 +117,7 @@ def handle_wake_up(event):

def handle_stop(event):
kill([config.get('tts').get('module')])
kill(["aplay"])


def connect():
Expand Down
9 changes: 9 additions & 0 deletions mycroft/client/speech/mic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import collections
import audioop
import os
import os.path
from time import sleep

import pyaudio
Expand All @@ -30,6 +32,7 @@

from mycroft.configuration import ConfigurationManager
from mycroft.util.log import getLogger
from mycroft.util import check_for_signal

listener_config = ConfigurationManager.get().get('listener')
logger = getLogger(__name__)
Expand Down Expand Up @@ -223,6 +226,8 @@ def decrease_noise(level):
recorded_too_much_silence = num_chunks > max_chunks_of_silence
if quiet_enough and (was_loud_enough or recorded_too_much_silence):
phrase_complete = True
if check_for_signal('buttonPress'):
phrase_complete = True

return byte_data

Expand All @@ -247,6 +252,10 @@ def wait_until_wake_word(self, source, sec_per_buffer):

said_wake_word = False
while not said_wake_word:
if check_for_signal('buttonPress'):
said_wake_word = True
continue

chunk = self.record_sound_chunk(source)

energy = self.calc_energy(chunk, source.SAMPLE_WIDTH)
Expand Down
18 changes: 18 additions & 0 deletions mycroft/util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@


import os
import os.path
import subprocess
from os.path import dirname
import socket

import psutil
import tempfile

__author__ = 'jdorleans'

Expand Down Expand Up @@ -109,5 +111,21 @@ def connected(host="8.8.8.8", port=53, timeout=3):
return False


def create_signal(signalName):
try:
f = open(tempfile.gettempdir()+'/'+signalName, 'w')
return True
except IOError:
return False


def check_for_signal(signalName):
if os.path.isfile(tempfile.gettempdir()+'/'+signalName):
os.remove(tempfile.gettempdir()+'/'+signalName)
return True

return False


class CerberusAccessDenied(Exception):
pass

0 comments on commit cac955f

Please sign in to comment.