Feature Request: Windows/Linux Support via Browser Audio Playback
Summary
Add cross-platform support for the voice system by streaming audio to a browser client instead of relying on macOS afplay.
Current Behavior
- Voice system uses
afplay for audio playback (macOS only)
- Windows/Linux users cannot use voice notifications
Proposed Enhancement
Architecture
Hook (Stop) → events.jsonl → Observability Server → WebSocket → Browser → Voice Server → ElevenLabs → Audio
Instead of playing audio locally via afplay, the voice server returns audio data to a browser client that handles playback.
1. Voice Server Returns Audio (instead of playing locally)
// POST /tts returns audio/mpeg instead of playing via afplay
return new Response(audioBuffer, {
headers: {
"Content-Type": "audio/mpeg",
"Access-Control-Allow-Origin": "*"
}
});
2. Browser Client Fetches and Plays Audio
const response = await fetch(`${voiceServerUrl}/tts`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: text, speaker: speaker })
});
const audioBlob = await response.blob();
const audio = new Audio(URL.createObjectURL(audioBlob));
await audio.play();
3. Audio Queue for Sequential Playback
Prevent overlapping speech when multiple events arrive:
const audioQueue: { text: string; speaker: string }[] = []
let isPlaying = false
async function processAudioQueue(): Promise<void> {
if (audioQueue.length === 0) {
isPlaying = false;
return;
}
isPlaying = true;
const item = audioQueue.shift()!;
// fetch and play...
currentAudio.onended = () => processAudioQueue();
}
4. WebSocket Event Streaming
Observability server watches the events JSONL file and streams new events via WebSocket:
// Server watches file, broadcasts new events
ws.send(JSON.stringify({ type: 'event', data: newEvent }));
// Client receives and triggers TTS
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (shouldSpeak(data.data)) {
queueSpeech(extractMessage(data.data), data.data.agent_name);
}
};
Benefits
- Works on Windows, Linux, and macOS
- Browser handles audio context/permissions
- No platform-specific audio commands needed
- Can run on headless server with remote browser
Implementation Notes
- Voice server needs CORS headers for browser access
- Browser requires user interaction to unlock audio context (one-time)
- Fallback to browser's built-in SpeechSynthesis if ElevenLabs fails
Testing Done
- Tested on Windows with Dutch voices
- Audio queue prevents race conditions
- Works with multiple speakers/agents
Submitted by: Marko (happy PAI user)
Reference implementation: Custom observability + voice server setup
Feature Request: Windows/Linux Support via Browser Audio Playback
Summary
Add cross-platform support for the voice system by streaming audio to a browser client instead of relying on macOS
afplay.Current Behavior
afplayfor audio playback (macOS only)Proposed Enhancement
Architecture
Instead of playing audio locally via
afplay, the voice server returns audio data to a browser client that handles playback.1. Voice Server Returns Audio (instead of playing locally)
2. Browser Client Fetches and Plays Audio
3. Audio Queue for Sequential Playback
Prevent overlapping speech when multiple events arrive:
4. WebSocket Event Streaming
Observability server watches the events JSONL file and streams new events via WebSocket:
Benefits
Implementation Notes
Testing Done
Submitted by: Marko (happy PAI user)
Reference implementation: Custom observability + voice server setup