mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-21 22:53:56 +08:00
fix: 优化唤醒词音频采集
This commit is contained in:
@@ -1,6 +1,4 @@
|
|||||||
import logging
|
import logging
|
||||||
import threading
|
|
||||||
from collections import deque
|
|
||||||
from typing import Protocol
|
from typing import Protocol
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@@ -16,7 +14,6 @@ class AudioListener(Protocol):
|
|||||||
|
|
||||||
|
|
||||||
class MicrophoneListener:
|
class MicrophoneListener:
|
||||||
_MAX_QUEUE_SIZE = 10
|
|
||||||
|
|
||||||
def __init__(self, config: RuntimeConfig) -> None:
|
def __init__(self, config: RuntimeConfig) -> None:
|
||||||
self.config = config
|
self.config = config
|
||||||
@@ -26,11 +23,8 @@ class MicrophoneListener:
|
|||||||
self._sample_rate = self.config.audio.sample_rate
|
self._sample_rate = self.config.audio.sample_rate
|
||||||
self._channels = self.config.audio.channels
|
self._channels = self.config.audio.channels
|
||||||
self._device = self.config.audio.input_device
|
self._device = self.config.audio.input_device
|
||||||
self._block_duration_ms = 100
|
self._block_duration_ms = 30
|
||||||
self._block_size = int(self._sample_rate * (self._block_duration_ms / 1000))
|
self._block_size = int(self._sample_rate * (self._block_duration_ms / 1000))
|
||||||
self._audio_queue: deque = deque(maxlen=self._MAX_QUEUE_SIZE)
|
|
||||||
self._queue_event = threading.Event()
|
|
||||||
self._consumer_thread = None
|
|
||||||
|
|
||||||
def add_audio_listener(self, listener: AudioListener) -> None:
|
def add_audio_listener(self, listener: AudioListener) -> None:
|
||||||
if listener not in self._listeners:
|
if listener not in self._listeners:
|
||||||
@@ -48,13 +42,6 @@ class MicrophoneListener:
|
|||||||
"Missing dependency: sounddevice. Install runtime dependencies before starting microphone listener."
|
"Missing dependency: sounddevice. Install runtime dependencies before starting microphone listener."
|
||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
self._running = True
|
|
||||||
self._audio_queue.clear()
|
|
||||||
self._consumer_thread = threading.Thread(
|
|
||||||
target=self._consume_loop, daemon=True, name="mic-consumer"
|
|
||||||
)
|
|
||||||
self._consumer_thread.start()
|
|
||||||
|
|
||||||
self._stream = sd.InputStream(
|
self._stream = sd.InputStream(
|
||||||
device=self._device,
|
device=self._device,
|
||||||
samplerate=self._sample_rate,
|
samplerate=self._sample_rate,
|
||||||
@@ -65,6 +52,7 @@ class MicrophoneListener:
|
|||||||
latency="low",
|
latency="low",
|
||||||
)
|
)
|
||||||
self._stream.start()
|
self._stream.start()
|
||||||
|
self._running = True
|
||||||
|
|
||||||
logger.info("microphone listener started")
|
logger.info("microphone listener started")
|
||||||
logger.info("microphone sample rate: %s", self._sample_rate)
|
logger.info("microphone sample rate: %s", self._sample_rate)
|
||||||
@@ -77,10 +65,6 @@ class MicrophoneListener:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self._running = False
|
self._running = False
|
||||||
self._queue_event.set()
|
|
||||||
if self._consumer_thread is not None:
|
|
||||||
self._consumer_thread.join(timeout=2)
|
|
||||||
self._consumer_thread = None
|
|
||||||
if self._stream is not None:
|
if self._stream is not None:
|
||||||
try:
|
try:
|
||||||
self._stream.stop()
|
self._stream.stop()
|
||||||
@@ -91,7 +75,7 @@ class MicrophoneListener:
|
|||||||
|
|
||||||
def _input_callback(self, indata, frames, time_info, status) -> None:
|
def _input_callback(self, indata, frames, time_info, status) -> None:
|
||||||
_ = frames, time_info
|
_ = frames, time_info
|
||||||
if status:
|
if status and "overflow" not in str(status).lower():
|
||||||
logger.warning("microphone status: %s", status)
|
logger.warning("microphone status: %s", status)
|
||||||
|
|
||||||
audio = np.copy(indata)
|
audio = np.copy(indata)
|
||||||
@@ -100,17 +84,8 @@ class MicrophoneListener:
|
|||||||
else:
|
else:
|
||||||
audio = audio.reshape(-1)
|
audio = audio.reshape(-1)
|
||||||
|
|
||||||
self._audio_queue.append(audio)
|
for listener in list(self._listeners):
|
||||||
self._queue_event.set()
|
try:
|
||||||
|
listener.on_audio_data(audio)
|
||||||
def _consume_loop(self) -> None:
|
except Exception:
|
||||||
while self._running:
|
logger.exception("audio listener callback failed")
|
||||||
self._queue_event.wait(timeout=0.5)
|
|
||||||
self._queue_event.clear()
|
|
||||||
while self._audio_queue:
|
|
||||||
audio = self._audio_queue.popleft()
|
|
||||||
for listener in list(self._listeners):
|
|
||||||
try:
|
|
||||||
listener.on_audio_data(audio)
|
|
||||||
except Exception:
|
|
||||||
logger.exception("audio listener callback failed")
|
|
||||||
|
|||||||
Reference in New Issue
Block a user