Skip to main content

Streaming Audio Capture Guide

Hyperscape captures game audio (music and sound effects) for RTMP streams using PulseAudio virtual sinks. This guide covers the setup, configuration, and troubleshooting.

Architecture

Flow:
  1. Chrome outputs audio to PulseAudio virtual sink (chrome_audio)
  2. FFmpeg captures from the sink’s monitor (chrome_audio.monitor)
  3. FFmpeg encodes to AAC and muxes with video
  4. Combined stream sent to RTMP destinations

PulseAudio Setup

User-Mode Configuration

The deployment uses user-mode PulseAudio (more reliable than system mode):

Virtual Sink

The chrome_audio sink is a null sink (virtual audio device) that:
  • Accepts audio from Chrome browser
  • Provides a monitor source for FFmpeg to capture
  • Doesn’t output to physical speakers (headless server)
Create sink manually:

Verification

Check PulseAudio status:
List sinks:
List sources (monitors):
Check default sink:

FFmpeg Audio Capture

Capture Configuration

FFmpeg captures from the PulseAudio monitor with buffering and stability features:
Parameters:
  • thread_queue_size 1024 - Buffer 1024 audio packets to prevent underruns
  • use_wallclock_as_timestamps 1 - Use wall clock for accurate timing
  • f pulse - PulseAudio input format
  • ac 2 - 2 audio channels (stereo)
  • ar 44100 - 44.1kHz sample rate
  • i chrome_audio.monitor - Capture from monitor source

Audio Filter

Async resampling recovers from audio drift:
Parameters:
  • async=1000 - Resample if drift exceeds 1000 samples (22ms at 44.1kHz)
  • first_pts=0 - Start PTS at 0 for consistent timing
This prevents audio dropouts when video/audio streams desync.

Audio Encoding

Parameters:
  • c:a aac - AAC audio codec (required for RTMP)
  • b:a 128k - 128 kbps bitrate (configurable via STREAM_AUDIO_BITRATE_KBPS)
  • ar 44100 - 44.1kHz output sample rate
  • flags +global_header - Required for RTMP muxing

Fallback to Silent Audio

If PulseAudio is not accessible, FFmpeg uses a silent audio source:
This ensures RTMP servers that require an audio track still work.

Chrome Browser Configuration

Audio Output

Chrome must be configured to output to PulseAudio:
Verification in Chrome:

Troubleshooting

PulseAudio Not Running

Symptoms:
  • FFmpeg errors: pulse: Connection refused
  • No audio in stream
  • pactl commands fail
Fix:

chrome_audio Sink Missing

Symptoms:
  • pactl list short sinks doesn’t show chrome_audio
  • FFmpeg errors: pulse: No such device
Fix:

No Audio in Stream

Check PulseAudio:
Check FFmpeg:
Check Chrome:

Audio Dropouts or Stuttering

Symptoms:
  • Intermittent audio gaps
  • Audio desync from video
  • FFmpeg warnings about buffer underruns
Fix 1: Increase thread_queue_size
Fix 2: Check async resampling
Fix 3: Remove -shortest flag

Audio/Video Desync

Symptoms:
  • Audio plays ahead or behind video
  • Gradual drift over time
Fix:

Permission Errors

Symptoms:
  • FFmpeg errors: pulse: Access denied
  • pactl commands fail with permission errors
Fix:

Environment Variables

Required

Optional

Testing Audio Capture

Test PulseAudio Capture

Test FFmpeg Capture

Test Full Pipeline

Performance Considerations

CPU Usage

Audio encoding adds ~5-10% CPU overhead:
  • AAC encoding: ~5% CPU (single core)
  • PulseAudio: ~2-3% CPU
  • Async resampling: ~1-2% CPU
Optimization:
  • Use hardware audio encoding if available (rare on Linux)
  • Reduce audio bitrate: STREAM_AUDIO_BITRATE_KBPS=96
  • Disable audio: STREAM_AUDIO_ENABLED=false

Memory Usage

PulseAudio uses ~20-30MB RAM:
  • Virtual sink buffer: ~10MB
  • Module overhead: ~10MB
  • Monitor source: ~5MB

Latency

Audio latency breakdown:
  • PulseAudio buffer: ~20-50ms
  • FFmpeg capture buffer: ~50-100ms (thread_queue_size=1024)
  • Async resampling: ~20-40ms
  • Total: ~100-200ms
For lower latency:
  • Reduce thread_queue_size: 512 (may cause underruns)
  • Enable low latency mode: STREAM_LOW_LATENCY=true (disables async resampling)

Advanced Configuration

Custom PulseAudio Config

Edit /root/.config/pulse/default.pa:
Restart PulseAudio:

Multiple Audio Sources

To capture from multiple sources (e.g., game + microphone):

Audio Filters

FFmpeg supports various audio filters:

Integration with Streaming

FFmpeg Command (CDP Direct Mode)

Full FFmpeg command with audio capture:

Ecosystem Config

Environment variables in ecosystem.config.cjs:

Troubleshooting

No Audio in Stream

1. Check PulseAudio is running:
2. Check chrome_audio sink exists:
3. Check FFmpeg is capturing:
4. Check audio is flowing:
5. Check PULSE_SERVER environment:

Audio Dropouts

Symptoms:
  • Intermittent audio gaps
  • Audio cuts out during video buffering
Causes:
  • -shortest flag (removed in recent commits)
  • Insufficient thread_queue_size
  • Audio drift without async resampling
Fix:

Audio/Video Desync

Symptoms:
  • Audio plays ahead or behind video
  • Gradual drift over time
Fix:

PulseAudio Permission Errors

Symptoms:
  • FFmpeg errors: pulse: Access denied
  • pactl commands fail
Fix:

Buffer Underruns

Symptoms:
  • FFmpeg warnings: Thread message queue blocking
  • Audio stuttering
  • Dropped frames
Fix:

Audio Encoding Errors

Symptoms:
  • FFmpeg errors: aac: Encoding error
  • Stream fails to start
Fix:

Performance Optimization

Reduce CPU Usage

Reduce Latency

Improve Quality

Monitoring

Real-time Audio Levels

Audio Statistics