Migrate to Python daemon
This commit is contained in:
parent
49ef349d48
commit
d81f3dbffe
42 changed files with 660 additions and 1816 deletions
70
src/recorder.py
Normal file
70
src/recorder.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@dataclass
|
||||
class RecordResult:
|
||||
wav_path: str
|
||||
temp_dir: str
|
||||
|
||||
|
||||
def _resolve_ffmpeg_path(explicit: str) -> str:
|
||||
if explicit:
|
||||
return explicit
|
||||
appdir = os.getenv("APPDIR")
|
||||
if appdir:
|
||||
candidate = Path(appdir) / "usr" / "bin" / "ffmpeg"
|
||||
if candidate.exists():
|
||||
return str(candidate)
|
||||
return "ffmpeg"
|
||||
|
||||
|
||||
def _ffmpeg_input_args(spec: str) -> list[str]:
|
||||
if not spec:
|
||||
spec = "pulse:default"
|
||||
kind = spec
|
||||
name = "default"
|
||||
if ":" in spec:
|
||||
kind, name = spec.split(":", 1)
|
||||
return ["-f", kind, "-i", name]
|
||||
|
||||
|
||||
def start_recording(ffmpeg_input: str, ffmpeg_path: str) -> tuple[subprocess.Popen, RecordResult]:
|
||||
tmpdir = tempfile.mkdtemp(prefix="lel-")
|
||||
wav = str(Path(tmpdir) / "mic.wav")
|
||||
|
||||
args = ["-hide_banner", "-loglevel", "error"]
|
||||
args += _ffmpeg_input_args(ffmpeg_input)
|
||||
args += ["-ac", "1", "-ar", "16000", "-c:a", "pcm_s16le", wav]
|
||||
|
||||
proc = subprocess.Popen(
|
||||
[_resolve_ffmpeg_path(ffmpeg_path), *args],
|
||||
preexec_fn=os.setsid,
|
||||
)
|
||||
return proc, RecordResult(wav_path=wav, temp_dir=tmpdir)
|
||||
|
||||
|
||||
def stop_recording(proc: subprocess.Popen, timeout_sec: float = 5.0) -> None:
|
||||
if proc.poll() is None:
|
||||
try:
|
||||
os.killpg(proc.pid, signal.SIGINT)
|
||||
except ProcessLookupError:
|
||||
return
|
||||
start = time.time()
|
||||
while proc.poll() is None:
|
||||
if time.time() - start > timeout_sec:
|
||||
try:
|
||||
os.killpg(proc.pid, signal.SIGKILL)
|
||||
except ProcessLookupError:
|
||||
pass
|
||||
break
|
||||
time.sleep(0.05)
|
||||
|
||||
# ffmpeg returns 255 on SIGINT; treat as success
|
||||
if proc.returncode not in (0, 255, None):
|
||||
raise RuntimeError(f"ffmpeg exited with status {proc.returncode}")
|
||||
Loading…
Add table
Add a link
Reference in a new issue