9 import speech_recognition as sr
10 from pyutils import logging_utils
12 logger = logging.getLogger(__file__)
15 class HotwordListener(object):
21 input_device_index=None,
22 library_path=pvporcupine.LIBRARY_PATH,
23 model_path=pvporcupine.MODEL_PATH,
25 self._queue = command_queue
26 self._library_path = library_path
27 self._model_path = model_path
28 self._keyword_paths = keyword_paths
29 self._sensitivities = sensitivities
30 self._input_device_index = input_device_index
32 @logging_utils.LoggingContext(logger, prefix="listener:")
33 def listen_forever(self):
35 for x in self._keyword_paths:
36 keywords.append(os.path.basename(x).replace(".ppn", "").split("_")[0])
42 porcupine = pvporcupine.create(
43 library_path=self._library_path,
44 model_path=self._model_path,
45 keyword_paths=self._keyword_paths,
46 sensitivities=self._sensitivities,
48 recognizer = sr.Recognizer()
49 pa = pyaudio.PyAudio()
51 audio_stream = pa.open(
52 rate=porcupine.sample_rate,
54 format=pyaudio.paInt16,
56 frames_per_buffer=porcupine.frame_length,
57 input_device_index=self._input_device_index,
60 logger.info("Listening {")
61 for keyword, sensitivity in zip(keywords, self._sensitivities):
62 logger.info(" %s (%.2f)" % (keyword, sensitivity))
66 raw = audio_stream.read(
67 porcupine.frame_length, exception_on_overflow=False
69 pcm = struct.unpack_from("h" * porcupine.frame_length, raw)
70 result = porcupine.process(pcm)
72 cmd = "aplay /var/www/kiosk/attention.wav"
74 "Running %s (attention tone) because I heard the wake-word", cmd
78 ">>>>>>>>>>>>> Detected wakeword %s" % keywords[result]
82 0, int(porcupine.sample_rate / porcupine.frame_length * 4)
84 raw += audio_stream.read(
85 porcupine.frame_length, exception_on_overflow=False
88 f">>>>>>>>>>>>>> Recognizing command... {len(raw)} bytes"
90 speech = sr.AudioData(
91 frame_data=bytes(raw),
92 sample_rate=porcupine.sample_rate,
93 sample_width=2, # 16 bits
95 command = recognizer.recognize_google(speech)
96 logger.debug(">>>>>>>>>>>>> Google says command was %s" % command)
97 logger.info("Enqueued command=%s", command)
98 self._queue.put(command)
101 logger.exception("Stopping listener because of unexpected exception!")
103 except KeyboardInterrupt:
104 logger.exception("Stopping listener because of ^C!")
107 logger.debug("Cleaning up... one sec...")
108 if porcupine is not None:
111 if audio_stream is not None:
118 def show_audio_devices(cls):
119 fields = ("index", "name", "defaultSampleRate", "maxInputChannels")
120 pa = pyaudio.PyAudio()
121 for i in range(pa.get_device_count()):
122 info = pa.get_device_info_by_index(i)
123 print(", ".join("'%s': '%s'" % (k, str(info[k])) for k in fields))
128 keyword_paths = [pvporcupine.KEYWORD_PATHS[x] for x in ["blueberry", "bumblebee"]]
129 sensitivities = [0.85, 0.95]
137 if __name__ == "__main__":