From d3ffad9190e48c8efd06ac135efb34b4b7789e0f Mon Sep 17 00:00:00 2001 From: Andrew Stoltz Date: Thu, 16 Apr 2026 16:19:48 -0500 Subject: [PATCH] =?UTF-8?q?fix(telephony):=20PiperUrl=2010.0.57.15=20?= =?UTF-8?q?=E2=86=92=20.17=20+=20shared-tts=20hostPath=20for=20TTS=20playb?= =?UTF-8?q?ack?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Piper was never reachable on 10.0.57.15 — edge1's actual address is 10.0.57.17 (SSH config, project_edge1_sdcard memory). Every telephony prompt hit the 8s HttpClient timeout and fell back to the built-in sound map (vm-advopts, vm-goodbye, beep) instead of speaking the real workflow text. Verified from noc1: `curl http://10.0.57.17:8500/health` returns HTTP 200 in 6ms, `POST /tts` returns a 16kHz mono WAV in 606ms. Changes: - apps/telephony/telephony.yaml - `Tts.PiperUrl` → `http://10.0.57.17:8500` - NetworkPolicy egress allow → `10.0.57.17/32:8500` - Header comment now documents the POST /tts {"text":"..."} contract - telephony-web pod mounts `/shared-tts` from hostPath `/tmp/tts-audio` (rke2-agent1). This is where `AsteriskProvider.SpeakTextAsync` writes the synthesized .sln16 before calling ARI `Play sound:tts/`. - apps/asterisk/deployment.yaml - Asterisk pod mounts the same hostPath at `/var/lib/asterisk/sounds/tts` so it can read and play what telephony-web wrote. Both deployments have `nodeSelector: kubernetes.io/hostname: rke2-agent1` so the hostPath is guaranteed to be the same directory. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/asterisk/deployment.yaml | 9 ++++ apps/telephony/telephony.yaml | 77 +++++++++++++++++++---------------- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/apps/asterisk/deployment.yaml b/apps/asterisk/deployment.yaml index 2598f57..e81dd9d 100644 --- a/apps/asterisk/deployment.yaml +++ b/apps/asterisk/deployment.yaml @@ -106,6 +106,11 @@ spec: mountPath: /var/log/asterisk - name: sounds mountPath: /var/lib/asterisk/sounds/en + # Shared TTS audio — telephony-web writes .sln16 files here (as + # /shared-tts), Asterisk plays them via `sound:tts/` which + # resolves to this mount. Both pods are pinned to rke2-agent1. + - name: shared-tts + mountPath: /var/lib/asterisk/sounds/tts resources: requests: cpu: 100m @@ -177,3 +182,7 @@ spec: emptyDir: {} - name: sounds emptyDir: {} + - name: shared-tts + hostPath: + path: /tmp/tts-audio + type: DirectoryOrCreate diff --git a/apps/telephony/telephony.yaml b/apps/telephony/telephony.yaml index 9f848b2..02d508a 100644 --- a/apps/telephony/telephony.yaml +++ b/apps/telephony/telephony.yaml @@ -1,7 +1,7 @@ # FlowerCore.Telephony - Blazor Server + REST API + Twilio IVR # ArgoCD managed - BlueJay Lab # Credentials: 1Password → OnePasswordItem CRD → K8s Secret (twilio-credentials) -# TTS: Piper on edge1 (10.0.57.15:8500) +# TTS: Piper on edge1 (10.0.57.17:8500) — endpoint /tts with {"text":"..."} # Public: telephony.flowercore.io via Cloudflare origin cert --- apiVersion: v1 @@ -46,31 +46,31 @@ data: "Twilio": { "VoiceUrl": "https://telephony.flowercore.io/api/twilio/webhooks/voice/incoming", "StatusCallbackUrl": "https://telephony.flowercore.io/api/twilio/webhooks/voice/status" - }, - "Asterisk": { - "BaseUrl": "http://10.0.56.12:8088", - "Username": "flowercore", - "Password": "bluejay-asterisk-ari", - "Application": "flowercore-pbx", - "ReconnectDelaySeconds": 5, - "MaxReconnectDelaySeconds": 60 - } - }, - "Ari": { - "BaseUrl": "http://10.0.56.12:8088", - "Username": "flowercore", - "Password": "bluejay-asterisk-ari", - "Application": "flowercore-pbx", - "ReconnectDelaySeconds": 5, - "MaxReconnectDelaySeconds": 60 - }, - "Sip": { - "Domain": "10.0.56.207", - "Port": 5060, - "Transport": "udp" - }, - "Tts": { - "PiperUrl": "http://10.0.57.15:8500", + }, + "Asterisk": { + "BaseUrl": "http://10.0.56.12:8088", + "Username": "flowercore", + "Password": "bluejay-asterisk-ari", + "Application": "flowercore-pbx", + "ReconnectDelaySeconds": 5, + "MaxReconnectDelaySeconds": 60 + } + }, + "Ari": { + "BaseUrl": "http://10.0.56.12:8088", + "Username": "flowercore", + "Password": "bluejay-asterisk-ari", + "Application": "flowercore-pbx", + "ReconnectDelaySeconds": 5, + "MaxReconnectDelaySeconds": 60 + }, + "Sip": { + "Domain": "10.0.56.207", + "Port": 5060, + "Transport": "udp" + }, + "Tts": { + "PiperUrl": "http://10.0.57.17:8500", "DefaultEngine": "piper", "SampleRate": 8000 }, @@ -117,12 +117,12 @@ spec: labels: app: telephony-web spec: - securityContext: - fsGroup: 1654 - nodeSelector: - kubernetes.io/hostname: rke2-agent1 - initContainers: - - name: fix-data-perms + securityContext: + fsGroup: 1654 + nodeSelector: + kubernetes.io/hostname: rke2-agent1 + initContainers: + - name: fix-data-perms image: busybox:latest command: ["sh", "-c", "chown -R 1654:1654 /data"] volumeMounts: @@ -170,6 +170,11 @@ spec: readOnly: true - name: telephony-data mountPath: /data + # Shared TTS audio — we write Piper .sln16 output here; Asterisk + # pod reads the same hostPath at /var/lib/asterisk/sounds/tts and + # plays via `sound:tts/`. Both pods are pinned to rke2-agent1. + - name: shared-tts + mountPath: /shared-tts resources: requests: memory: 256Mi @@ -196,6 +201,10 @@ spec: - name: telephony-data persistentVolumeClaim: claimName: telephony-data + - name: shared-tts + hostPath: + path: /tmp/tts-audio + type: DirectoryOrCreate --- # ClusterIP service apiVersion: v1 @@ -282,10 +291,10 @@ spec: protocol: UDP - port: 53 protocol: TCP - # Allow Piper TTS on edge1 (10.0.57.15:8500) + # Allow Piper TTS on edge1 (10.0.57.17:8500) - to: - ipBlock: - cidr: 10.0.57.15/32 + cidr: 10.0.57.17/32 ports: - port: 8500 protocol: TCP