#!/usr/bin/env python3 import ctypes import json import os import struct import subprocess import sys ASSET_ROOT = "/opt/roverd/googletts" LIB_PATH = os.path.join(ASSET_ROOT, "libchrometts.so") VOICE_DIR = os.path.join(ASSET_ROOT, "en-us-x-multi-r30") PIPELINE = "pipeline.pb" PLAYBACK_DEVICE = "tts" SAMPLE_RATE = "24000" MAX_TEXT_CHARS = 512 VOICES = { "sfg": "female", "iob": "female", "iog": "female", "iol": "male", "iom": "male", "tpc": "female", "tpd": "male", "tpf": "female", } DEFAULT_VOICE = "tpf" DEFAULT_PITCH = 1.0 DEFAULT_SPEED = 1.0 MIN_PITCH = 0.5 MAX_PITCH = 2.0 MIN_SPEED = 0.5 MAX_SPEED = 2.0 def varint(value): out = bytearray() while value >= 0x80: out.append((value & 0x7F) | 0x80) value >>= 7 out.append(value) return bytes(out) def field_bytes(number, payload): return varint((number << 3) | 2) + varint(len(payload)) + payload def field_float(number, value): return varint((number << 3) | 5) + struct.pack(" 0: frames = int(frames_written.value) if frames > 0: player.stdin.write(ctypes.string_at(self.buffer, frames * ctypes.sizeof(ctypes.c_float))) player.stdin.close() rc = player.wait() if rc != 0: raise RuntimeError(f"aplay exited with {rc}") finally: if player.poll() is None: player.kill() player.wait() def shutdown(self): self.lib.GoogleTtsShutdown() def respond(payload): sys.stdout.write(json.dumps(payload, separators=(",", ":")) + "\n") sys.stdout.flush() def clamp_float(value, minimum, maximum, fallback): try: value = float(value) except (TypeError, ValueError): return fallback if value <= 0: return fallback if value < minimum: return minimum if value > maximum: return maximum return value def main(): try: tts = ChromeTTS() except Exception as exc: respond({"ok": False, "error": str(exc)}) return 1 respond({"ok": True, "ready": True}) try: for line in sys.stdin: line = line.strip() if not line: continue try: request = json.loads(line) tts.speak_to_aplay( str(request.get("text") or ""), str(request.get("voice") or DEFAULT_VOICE), request.get("pitch", DEFAULT_PITCH), request.get("speed", DEFAULT_SPEED), ) respond({"ok": True}) except Exception as exc: respond({"ok": False, "error": str(exc)}) finally: tts.shutdown() return 0 if __name__ == "__main__": raise SystemExit(main())