Skip to content

Commit

Permalink
Merge pull request Kitt-AI#236 from carloalbertobarbano/master
Browse files Browse the repository at this point in the history
User can call start() again after terminate() in HotwordDetector. Useful for multithreaded applications with exclusive access to the audio input device.
  • Loading branch information
xuchen authored Aug 10, 2017
2 parents 0e0ffd2 + c6675f9 commit eb50efb
Showing 1 changed file with 25 additions and 20 deletions.
45 changes: 25 additions & 20 deletions examples/Python3/snowboydecoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@

class RingBuffer(object):
"""Ring buffer to hold audio from PortAudio"""
def __init__(self, size = 4096):

def __init__(self, size=4096):
self._buf = collections.deque(maxlen=size)

def extend(self, data):
Expand Down Expand Up @@ -69,16 +70,12 @@ class HotwordDetector(object):
default sensitivity in the model will be used.
:param audio_gain: multiply input volume by this factor.
"""

def __init__(self, decoder_model,
resource=RESOURCE_FILE,
sensitivity=[],
audio_gain=1):

def audio_callback(in_data, frame_count, time_info, status):
self.ring_buffer.extend(in_data)
play_data = chr(0) * len(in_data)
return play_data, pyaudio.paContinue

tm = type(decoder_model)
ts = type(sensitivity)
if tm is not list:
Expand All @@ -93,7 +90,7 @@ def audio_callback(in_data, frame_count, time_info, status):
self.num_hotwords = self.detector.NumHotwords()

if len(decoder_model) > 1 and len(sensitivity) == 1:
sensitivity = sensitivity*self.num_hotwords
sensitivity = sensitivity * self.num_hotwords
if len(sensitivity) != 0:
assert self.num_hotwords == len(sensitivity), \
"number of hotwords in decoder_model (%d) and sensitivity " \
Expand All @@ -104,16 +101,6 @@ def audio_callback(in_data, frame_count, time_info, status):

self.ring_buffer = RingBuffer(
self.detector.NumChannels() * self.detector.SampleRate() * 5)
self.audio = pyaudio.PyAudio()
self.stream_in = self.audio.open(
input=True, output=False,
format=self.audio.get_format_from_width(
self.detector.BitsPerSample() / 8),
channels=self.detector.NumChannels(),
rate=self.detector.SampleRate(),
frames_per_buffer=2048,
stream_callback=audio_callback)


def start(self, detected_callback=play_audio_file,
interrupt_check=lambda: False,
Expand All @@ -134,6 +121,23 @@ def start(self, detected_callback=play_audio_file,
:param float sleep_time: how much time in second every loop waits.
:return: None
"""
self._running = True

def audio_callback(in_data, frame_count, time_info, status):
self.ring_buffer.extend(in_data)
play_data = chr(0) * len(in_data)
return play_data, pyaudio.paContinue

self.audio = pyaudio.PyAudio()
self.stream_in = self.audio.open(
input=True, output=False,
format=self.audio.get_format_from_width(
self.detector.BitsPerSample() / 8),
channels=self.detector.NumChannels(),
rate=self.detector.SampleRate(),
frames_per_buffer=2048,
stream_callback=audio_callback)

if interrupt_check():
logger.debug("detect voice return")
return
Expand All @@ -150,7 +154,7 @@ def start(self, detected_callback=play_audio_file,

logger.debug("detecting...")

while True:
while self._running is True:
if interrupt_check():
logger.debug("detect voice break")
break
Expand All @@ -167,17 +171,18 @@ def start(self, detected_callback=play_audio_file,
message += time.strftime("%Y-%m-%d %H:%M:%S",
time.localtime(time.time()))
logger.info(message)
callback = detected_callback[ans-1]
callback = detected_callback[ans - 1]
if callback is not None:
callback()

logger.debug("finished.")

def terminate(self):
"""
Terminate audio stream. Users cannot call start() again to detect.
Terminate audio stream. Users can call start() again to detect.
:return: None
"""
self.stream_in.stop_stream()
self.stream_in.close()
self.audio.terminate()
self._running = False

0 comments on commit eb50efb

Please sign in to comment.