Skip to content

VoiceServer: afplay (macOS-only) breaks audio on Linux — silent failure #855

Description

@pkumaschow

Summary

VoiceServer/server.ts hardcodes /usr/bin/afplay for audio playback. afplay is macOS-only and does not exist on Linux, causing all TTS notifications to fail silently with ENOENT. Because the startup catchphrase is fired as a detached fire-and-forget curl, the error is never surfaced to the user — the voice server appears to work but produces no audio.

Affected Files

  • VoiceServer/server.tsplayAudio() function (~line 379)
  • VoiceServer/start.sh, stop.sh, restart.sh — use launchctl (macOS-only), fail silently on Linux

Error

{"status":"error","message":"TTS failed: ENOENT: no such file or directory, posix_spawn '/usr/bin/afplay'"}

Platform

  • Linux (tested on Fedora 43, kernel 6.18)
  • macOS unaffected

What Breaks

  • Startup catchphrase never plays
  • Algorithm phase voice announcements never play
  • All /notify POST calls return status: error
  • No visible error to the user (fire-and-forget curl swallows it)

Regression Vector

Every PAI migration/reinstall that overwrites VoiceServer/server.ts from the upstream repo reverts any local Linux fix, breaking voice again silently.

Proposed Fix

In playAudio(), detect the platform and use ffplay (part of ffmpeg, widely available on Linux) instead of afplay:

// Play audio — afplay on macOS, ffplay on Linux
async function playAudio(audioBuffer: ArrayBuffer, volume: number = FALLBACK_VOLUME): Promise<void> {
  const tempFile = `/tmp/voice-${Date.now()}.mp3`;
  await Bun.write(tempFile, audioBuffer);

  const isMac = process.platform === 'darwin';
  const player = isMac ? '/usr/bin/afplay' : '/usr/bin/ffplay';
  const args = isMac
    ? ['-v', volume.toString(), tempFile]
    : ['-nodisp', '-autoexit', '-volume', Math.round(volume * 100).toString(), tempFile];

  return new Promise((resolve, reject) => {
    const proc = spawn(player, args);
    proc.on('error', (error) => { reject(error); });
    proc.on('exit', (code) => {
      spawn('/bin/rm', [tempFile]);
      if (code === 0) resolve();
      else reject(new Error(`${isMac ? 'afplay' : 'ffplay'} exited with code ${code}`));
    });
  });
}

ffplay is available at /usr/bin/ffplay on most Linux distros via the ffmpeg package. For distros without ffmpeg, mpg123 is a lighter alternative for MP3 playback.

The start.sh/stop.sh/restart.sh scripts similarly need Linux-compatible process management (e.g. PID file approach) instead of launchctl.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions