mirror of
https://github.com/SevaSk/ecoute.git
synced 2025-03-11 06:53:55 +00:00
82 lines
3.1 KiB
Python
82 lines
3.1 KiB
Python
import pyaudio
|
|
import queue
|
|
|
|
def get_device_list():
|
|
devices = []
|
|
p = pyaudio.PyAudio()
|
|
info = p.get_host_api_info_by_index(0)
|
|
numdevices = info.get('deviceCount')
|
|
for i in range(0, numdevices):
|
|
if (p.get_device_info_by_host_api_device_index(0, i).get('maxInputChannels')) > 0:
|
|
devices.append(p.get_device_info_by_host_api_device_index(0, i).get('name'))
|
|
if (p.get_device_info_by_host_api_device_index(0, i).get('maxOutputChannels')) > 0:
|
|
devices.append(p.get_device_info_by_host_api_device_index(0, i).get('name'))
|
|
return devices
|
|
|
|
class AudioStream(object):
|
|
"""Opens a recording stream as a generator yielding the audio chunks."""
|
|
|
|
def __init__(self, rate, input_device_index):
|
|
self._rate = rate
|
|
self._chunk = int(rate / 10) # 100ms for 16000Hz
|
|
self.input_device_index = input_device_index
|
|
# Create a thread-safe buffer of audio data
|
|
self._buff = queue.Queue()
|
|
self.closed = True
|
|
|
|
def __enter__(self):
|
|
self._audio_interface = pyaudio.PyAudio()
|
|
self._audio_stream = self._audio_interface.open(
|
|
format=pyaudio.paInt16,
|
|
# The API currently only supports 1-channel (mono) audio
|
|
# https://goo.gl/z757pE
|
|
channels=1,
|
|
rate=self._rate,
|
|
input=True,
|
|
frames_per_buffer=self._chunk,
|
|
# Run the audio stream asynchronously to fill the buffer object.
|
|
# This is necessary so that the input device's buffer doesn't
|
|
# overflow while the calling thread makes network requests, etc.
|
|
stream_callback=self._fill_buffer,
|
|
input_device_index=self.input_device_index,
|
|
)
|
|
|
|
self.closed = False
|
|
|
|
return self
|
|
|
|
def __exit__(self, type, value, traceback):
|
|
self._audio_stream.stop_stream()
|
|
self._audio_stream.close()
|
|
self.closed = True
|
|
# Signal the generator to terminate so that the client's
|
|
# streaming_recognize method will not block the process termination.
|
|
self._buff.put(None)
|
|
self._audio_interface.terminate()
|
|
|
|
def _fill_buffer(self, in_data, frame_count, time_info, status_flags):
|
|
"""Continuously collect data from the audio stream, into the buffer."""
|
|
self._buff.put(in_data)
|
|
return None, pyaudio.paContinue
|
|
|
|
def generator(self):
|
|
while not self.closed:
|
|
# Use a blocking get() to ensure there's at least one chunk of
|
|
# data, and stop iteration if the chunk is None, indicating the
|
|
# end of the audio stream.
|
|
chunk = self._buff.get()
|
|
if chunk is None:
|
|
return
|
|
data = [chunk]
|
|
|
|
# Now consume whatever other data's still buffered.
|
|
while True:
|
|
try:
|
|
chunk = self._buff.get(block=False)
|
|
if chunk is None:
|
|
return
|
|
data.append(chunk)
|
|
except queue.Empty:
|
|
break
|
|
|
|
yield b"".join(data) |