ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
audio.c File Reference

🔊 Client audio management: capture thread, sample processing, and playback coordination More...

Go to the source code of this file.

Data Structures

struct  audio_send_packet_t
 Audio packet for async sending. More...
 

Macros

#define AUDIO_SEND_QUEUE_SIZE   32
 
#define AUDIO_VOLUME_BOOST   1.0f
 
#define OPUS_FRAME_SAMPLES   960
 
#define OPUS_MAX_PACKET_SIZE   500
 
#define CAPTURE_READ_SIZE   (OPUS_FRAME_SAMPLES * 4)
 
#define MAX_BATCH_FRAMES   8
 
#define BATCH_TIMEOUT_NS   (40LL * NS_PER_MS_INT)
 

Functions

void audio_sender_init (void)
 Initialize async audio sender queue and thread.
 
void audio_sender_cleanup (void)
 Cleanup async audio sender.
 
void audio_sender_finalize (void)
 
void audio_process_received_samples (const float *samples, int num_samples)
 Process received audio samples from server.
 
int audio_client_init (void)
 Initialize audio subsystem.
 
int audio_start_thread (void)
 Start audio capture thread.
 
void audio_stop_thread (void)
 Stop audio capture thread.
 
bool audio_thread_exited (void)
 Check if audio capture thread has exited.
 
void audio_cleanup (void)
 Cleanup audio subsystem.
 
client_audio_pipeline_t * audio_get_pipeline (void)
 Get the audio pipeline (for advanced usage)
 
int audio_decode_opus (const uint8_t *opus_data, size_t opus_len, float *output, int max_samples)
 Decode Opus packet using the audio pipeline.
 
audio_context_t * audio_get_context (void)
 Get the global audio context for use by other subsystems.
 

Detailed Description

🔊 Client audio management: capture thread, sample processing, and playback coordination

The audio system implements a dual-thread architecture:

  • Capture Thread: Records microphone input and transmits to server
  • Playback System: Receives server audio and plays through speakers
  • Processing Pipeline: Real-time audio enhancement and filtering
  • Coordination: Thread-safe communication between capture and playback

Audio Processing Pipeline

Both incoming and outgoing audio undergo comprehensive processing:

  1. High-pass Filter: Removes low-frequency rumble and noise
  2. Noise Gate: Eliminates background noise during silence
  3. Dynamic Range: Soft clipping to prevent harsh distortion
  4. Volume Control: Configurable boost for optimal listening levels
  5. Batching: Groups samples for efficient network transmission

Capture Thread Management

Audio capture runs in a dedicated thread:

  • Continuous Recording: Real-time microphone sample capture
  • Processing Chain: Applies filters and enhancement algorithms
  • Network Transmission: Sends processed samples to server
  • Adaptive Quality: Noise gate reduces traffic during silence
  • Thread Safety: Coordinated shutdown and resource management

Batching and Network Efficiency

Audio samples are batched for network efficiency:

  • Batch Accumulation: Collect multiple sample packets
  • Smart Transmission: Send batches when full or gate closes
  • Reduced Overhead: Fewer network packets for better performance
  • Quality Preservation: Maintain audio quality while optimizing bandwidth

Platform Audio Integration

Uses PortAudio for cross-platform audio support:

  • Device Enumeration: Automatic microphone and speaker detection
  • Format Negotiation: Optimal sample rate and bit depth selection
  • Low Latency: Optimized for real-time audio processing
  • Error Handling: Graceful handling of device conflicts and changes

Integration Points

  • main.c: Audio subsystem lifecycle and initialization
  • server.c: Audio packet transmission to server
  • protocol.c: Incoming audio packet processing and dispatch
  • lib/audio.c: Low-level PortAudio device management
  • lib/mixer.c: Audio filtering and processing algorithms

Error Handling

Audio errors handled with graceful degradation:

  • Device Unavailable: Continue without audio, log warnings
  • Processing Errors: Skip problematic samples, maintain stream
  • Network Errors: Continue processing, let connection management handle
  • Resource Errors: Clean shutdown with proper resource release

Resource Management

Careful audio resource lifecycle:

  • Context Management: Proper PortAudio context initialization/cleanup
  • Thread Coordination: Clean thread shutdown and resource release
  • Buffer Management: Efficient sample buffer allocation and reuse
  • Device Release: Proper microphone and speaker device cleanup
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
2025

Definition in file src/client/audio.c.

Macro Definition Documentation

◆ AUDIO_SEND_QUEUE_SIZE

#define AUDIO_SEND_QUEUE_SIZE   32

Ring buffer queue for async audio packets

Definition at line 208 of file src/client/audio.c.

◆ AUDIO_VOLUME_BOOST

#define AUDIO_VOLUME_BOOST   1.0f

Audio volume boost multiplier for received samples

Definition at line 430 of file src/client/audio.c.

◆ BATCH_TIMEOUT_NS

#define BATCH_TIMEOUT_NS   (40LL * NS_PER_MS_INT)

◆ CAPTURE_READ_SIZE

#define CAPTURE_READ_SIZE   (OPUS_FRAME_SAMPLES * 4)

◆ MAX_BATCH_FRAMES

#define MAX_BATCH_FRAMES   8

◆ OPUS_FRAME_SAMPLES

#define OPUS_FRAME_SAMPLES   960

◆ OPUS_MAX_PACKET_SIZE

#define OPUS_MAX_PACKET_SIZE   500

Function Documentation

◆ audio_sender_cleanup()

void audio_sender_cleanup ( void  )

Cleanup async audio sender.

Signal the asynchronous audio sender to stop before worker threads are joined.

Definition at line 387 of file src/client/audio.c.

387 {
388 // Signal thread to exit
389 if (lifecycle_is_initialized(&g_audio_send_queue_lc)) {
390 atomic_store_bool(&g_audio_sender_should_exit, true);
391 mutex_lock(&g_audio_send_queue_mutex);
392 cond_signal(&g_audio_send_queue_cond);
393 mutex_unlock(&g_audio_send_queue_mutex);
394 }
395
396 // The worker is joined by thread_pool_stop_all() in protocol_stop_connection().
397 // Keep the queue synchronization objects alive until that join completes.
398 if (THREAD_IS_CREATED(g_audio_sender_thread_created)) {
399 log_debug("Audio sender thread will be joined by thread pool");
400 }
401}
void atomic_store_bool(atomic_t *a, bool value)
Atomically store a boolean value.
Definition atomic.c:177
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
#define mutex_lock(mutex)
Lock a mutex (with debug tracking in debug builds)
int cond_signal(cond_t *cond)
Signal a condition variable (wake one waiting thread)
#define mutex_unlock(mutex)
Unlock a mutex (with debug tracking in debug builds)
#define THREAD_IS_CREATED(created_flag)
bool lifecycle_is_initialized(const lifecycle_t *lc)
Definition lifecycle.c:155

References atomic_store_bool(), cond_signal(), lifecycle_is_initialized(), log_debug, mutex_lock, mutex_unlock, and THREAD_IS_CREATED.

Referenced by audio_cleanup(), and protocol_stop_connection().

◆ audio_sender_finalize()

void audio_sender_finalize ( void  )

Release asynchronous audio sender resources after its worker has been joined.

Definition at line 403 of file src/client/audio.c.

403 {
404 if (!lifecycle_is_initialized(&g_audio_send_queue_lc)) {
405 return;
406 }
407
408 // thread_pool_stop_all() normally joins this worker. If the sender was
409 // blocked in transport I/O when the pool timeout elapsed, wait for the
410 // shutdown signal to be observed before destroying its queue mutex.
411 for (int i = 0; i < 200 && !atomic_load_bool(&g_audio_sender_exited); i++) {
413 }
414 if (!atomic_load_bool(&g_audio_sender_exited)) {
415 log_warn("Audio sender thread did not exit before queue cleanup");
416 return;
417 }
418
419 mutex_destroy(&g_audio_send_queue_mutex);
420 cond_destroy(&g_audio_send_queue_cond);
421 lifecycle_shutdown(&g_audio_send_queue_lc);
422 g_audio_sender_thread_created = false;
423}
bool atomic_load_bool(atomic_t *a)
Atomically load a boolean value.
Definition atomic.c:169
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
#define US_PER_MS_INT
Definition time.h:160
void platform_sleep_us(unsigned int us)
High-precision sleep function with microsecond precision.
int cond_destroy(cond_t *cond)
Destroy a condition variable.
int mutex_destroy(mutex_t *mutex)
Destroy a mutex.
Definition threading.c:22
bool lifecycle_shutdown(lifecycle_t *lc)
Definition lifecycle.c:108

References atomic_load_bool(), cond_destroy(), lifecycle_is_initialized(), lifecycle_shutdown(), log_warn, mutex_destroy(), platform_sleep_us(), and US_PER_MS_INT.

Referenced by protocol_stop_connection().