fix(voice_loop): PipeWire-Aufnahme (pw-record) als Standard via --recorder auto
- arecord scheiterte auf PipeWire-Systemen ("Fehler beim Öffnen des Gerätes")
- neue Option --recorder {auto,pw-record,parecord,arecord}; auto bevorzugt pw-record
- geraetespezifische Flags je Werkzeug (-D / --target / --device)
- Doku: Recorder-Hinweis + Troubleshooting-Eintrag fuer den arecord-Fehler
- verifiziert: auto -> pw-record; --file-Round-Trip weiterhin ok
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
7896f608fb
commit
d15e51eb0d
2 changed files with 56 additions and 11 deletions
|
|
@ -54,21 +54,52 @@ def _first_player() -> list[str] | None:
|
|||
return None
|
||||
|
||||
|
||||
def record_utterance(device: str | None, rate: int) -> bytes:
|
||||
def resolve_recorder(choice: str) -> str:
|
||||
"""Waehlt das Aufnahmewerkzeug. 'auto' bevorzugt PipeWire (pw-record)."""
|
||||
if choice != "auto":
|
||||
if not shutil.which(choice):
|
||||
sys.exit(f"Fehlt: Aufnahmewerkzeug '{choice}' nicht gefunden.")
|
||||
return choice
|
||||
for tool in ("pw-record", "parecord", "arecord"):
|
||||
if shutil.which(tool):
|
||||
return tool
|
||||
sys.exit("Kein Aufnahmewerkzeug gefunden (pw-record / parecord / arecord).")
|
||||
|
||||
|
||||
def _record_cmd(recorder: str, device: str | None, rate: int, outfile: str) -> list[str]:
|
||||
if recorder == "arecord":
|
||||
cmd = ["arecord", "-q", "-f", "S16_LE", "-r", str(rate), "-c", "1"]
|
||||
if device:
|
||||
cmd += ["-D", device]
|
||||
return cmd + [outfile]
|
||||
if recorder == "pw-record":
|
||||
cmd = ["pw-record", "--rate", str(rate), "--channels", "1", "--format", "s16"]
|
||||
if device:
|
||||
cmd += ["--target", device]
|
||||
return cmd + [outfile]
|
||||
if recorder == "parecord":
|
||||
cmd = ["parecord", f"--rate={rate}", "--channels=1", "--format=s16le",
|
||||
"--file-format=wav"]
|
||||
if device:
|
||||
cmd += [f"--device={device}"]
|
||||
return cmd + [outfile]
|
||||
sys.exit(f"Unbekanntes Aufnahmewerkzeug: {recorder}")
|
||||
|
||||
|
||||
def record_utterance(recorder: str, device: str | None, rate: int) -> bytes:
|
||||
"""Push-to-Talk: Enter startet, Enter stoppt die Aufnahme; gibt WAV-Bytes zurueck."""
|
||||
_require("arecord")
|
||||
tmp = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
|
||||
tmp.close()
|
||||
cmd = ["arecord", "-q", "-f", "S16_LE", "-r", str(rate), "-c", "1"]
|
||||
if device:
|
||||
cmd += ["-D", device]
|
||||
cmd.append(tmp.name)
|
||||
cmd = _record_cmd(recorder, device, rate, tmp.name)
|
||||
|
||||
input("\n[Enter] = Aufnahme START …")
|
||||
proc = subprocess.Popen(cmd)
|
||||
input("[Enter] = Aufnahme STOP …")
|
||||
proc.send_signal(signal.SIGINT)
|
||||
proc.wait(timeout=5)
|
||||
try:
|
||||
proc.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
with open(tmp.name, "rb") as fh:
|
||||
return fh.read()
|
||||
|
||||
|
|
@ -142,10 +173,13 @@ async def run(args) -> None:
|
|||
print(f"Sende Datei: {args.file}")
|
||||
await one_turn(ws, wav, start_frame)
|
||||
return
|
||||
recorder = resolve_recorder(args.recorder)
|
||||
print(f"Aufnahme mit: {recorder}"
|
||||
+ (f" (Gerät: {args.device})" if args.device else " (Standardgerät)"))
|
||||
print("Sprich nach 'START', stoppe mit Enter. Strg+C beendet den Loop.")
|
||||
while True:
|
||||
try:
|
||||
wav = record_utterance(args.device, args.rate)
|
||||
wav = record_utterance(recorder, args.device, args.rate)
|
||||
except KeyboardInterrupt:
|
||||
print("\nEnde.")
|
||||
return
|
||||
|
|
@ -160,7 +194,11 @@ def main() -> None:
|
|||
p.add_argument("--url", default="ws://127.0.0.1:8003/ws/voice")
|
||||
p.add_argument("--session", default="voice-loop")
|
||||
p.add_argument("--token", default=None, help="Bearer-Token, falls AUTH_ENABLED=true")
|
||||
p.add_argument("--device", default=None, help="Aufnahmegeraet (siehe: arecord -L)")
|
||||
p.add_argument("--device", default=None,
|
||||
help="Aufnahmegeraet (arecord: -L; pw-record: --target; parecord: --device)")
|
||||
p.add_argument("--recorder", default="auto",
|
||||
choices=["auto", "pw-record", "parecord", "arecord"],
|
||||
help="Aufnahmewerkzeug; 'auto' bevorzugt PipeWire (pw-record)")
|
||||
p.add_argument("--rate", type=int, default=16000)
|
||||
p.add_argument("--stt-provider", dest="stt_provider", default=None)
|
||||
p.add_argument("--llm-provider", dest="llm_provider", default=None)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue