ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
include/ascii-chat/audio/audio.h
Go to the documentation of this file.
1#pragma once
2
60#include <stdbool.h>
61#include <ascii-chat/atomic.h>
62#include <portaudio.h>
63#ifdef __linux__
64#include <sched.h>
65#include <sys/resource.h>
66#elif defined(__APPLE__)
67#include <mach/mach.h>
68#include <mach/thread_policy.h>
69#include <mach/kern_return.h>
70#endif
71
72#include "../common.h"
73#include "../platform/thread.h"
74#include "../platform/mutex.h"
75#include "../platform/cond.h"
76#include "../ringbuffer.h"
77#include "../options/options.h"
78
79/* ============================================================================
80 * Audio Configuration Constants
81 * ============================================================================
82 */
83
85#define AUDIO_SAMPLE_RATE 48000
87#define AUDIO_FRAMES_PER_BUFFER 480
89#define AUDIO_CHANNELS 1
91#define AUDIO_BUFFER_SIZE (AUDIO_FRAMES_PER_BUFFER * AUDIO_CHANNELS)
92
93/* ============================================================================
94 * Data Structures
95 * ============================================================================
96 */
97
129typedef struct {
130 // PortAudio streams
134
135 // New architecture: 5 ring buffers for lock-free callback → worker → network
139
140 // Legacy ring buffers (will be migrated to new architecture)
144
145 // Worker thread for heavy processing (AEC3, filters)
151
152 // Pre-allocated worker buffers (avoid malloc in worker loop)
156
157 // State flags
159 bool running;
164
165 // Audio pipeline and device info
169 double sample_rate;
179
180/* ============================================================================
181 * Audio Context Lifecycle
182 * @{
183 */
184
203
218
230
245void audio_set_pipeline(audio_context_t *ctx, void *pipeline);
246
249/* ============================================================================
250 * Full-Duplex Audio Control
251 * @{
252 */
253
281
295
298/* ============================================================================
299 * Audio I/O Operations
300 * @{
301 */
302
323asciichat_error_t audio_read_samples(audio_context_t *ctx, float *buffer, int num_samples);
324
345asciichat_error_t audio_write_samples(audio_context_t *ctx, const float *buffer, int num_samples);
346
349/* ============================================================================
350 * Real-Time Priority Scheduling
351 * @{
352 */
353
381
384/* ============================================================================
385 * Audio Device Enumeration
386 * @{
387 */
388
390#define AUDIO_DEVICE_NAME_MAX 256
391
409
426asciichat_error_t audio_list_input_devices(audio_device_info_t **out_devices, unsigned int *out_count);
427
444asciichat_error_t audio_list_output_devices(audio_device_info_t **out_devices, unsigned int *out_count);
445
456
459/* ============================================================================
460 * Protocol Helper Functions - Audio Format Conversion
461 * @{
462 */
463
484asciichat_error_t audio_dequantize_samples(const uint8_t *samples_ptr, uint32_t total_samples, float *out_samples);
485
488/* ============================================================================
489 * Audio Ring Buffer Management
490 * @{
491 */
492
511
529
542
553void audio_ring_buffer_register_atomics(audio_ring_buffer_t *rb, const char *context_name);
554
564
576
596asciichat_error_t audio_ring_buffer_write(audio_ring_buffer_t *rb, const float *data, int samples);
597
618size_t audio_ring_buffer_read(audio_ring_buffer_t *rb, float *data, size_t samples);
619
633size_t audio_ring_buffer_peek(audio_ring_buffer_t *rb, float *data, size_t samples);
634
650
666
669/* ============================================================================
670 * Audio Resampling Utilities
671 * @{
672 */
673
700void resample_linear(const float *src, size_t src_samples, float *dst, size_t dst_samples, double src_rate,
701 double dst_rate);
702
705/* ============================================================================
706 * Audio Batch Packet Format
707 * @{
708 */
709
728typedef struct {
729 uint32_t batch_count;
730 uint32_t total_samples;
731 uint32_t sample_rate;
732 uint32_t channels;
734
768asciichat_error_t audio_parse_batch_header(const void *data, size_t len, audio_batch_info_t *out_batch);
769
799
819
831
864bool audio_should_enable_microphone(audio_capture_source_t source, bool has_media_audio);
865
⚛️ Atomic operations abstraction layer with debug tracking
bool audio_should_enable_microphone(audio_capture_source_t source, bool has_media_audio)
Determine if microphone should be enabled based on audio source setting and media state.
size_t audio_ring_buffer_read(audio_ring_buffer_t *rb, float *data, size_t samples)
Read audio samples from ring buffer.
void audio_free_device_list(audio_device_info_t *devices)
Free device list allocated by audio_list_input_devices/audio_list_output_devices.
asciichat_error_t audio_ring_buffer_write(audio_ring_buffer_t *rb, const float *data, int samples)
Write audio samples to ring buffer.
void audio_ring_buffer_destroy(audio_ring_buffer_t *rb)
Destroy an audio ring buffer.
asciichat_error_t audio_init(audio_context_t *ctx)
Initialize audio context and PortAudio.
asciichat_error_t audio_set_realtime_priority(void)
Request real-time priority for current thread.
audio_ring_buffer_t * audio_ring_buffer_create(void)
Create a new audio ring buffer (for playback with jitter buffering)
bool audio_is_supported_sample_rate(uint32_t sample_rate)
Check if a sample rate is a standard/supported rate.
size_t audio_ring_buffer_available_read(audio_ring_buffer_t *rb)
Get number of samples available for reading.
asciichat_error_t audio_start_duplex(audio_context_t *ctx)
Start full-duplex audio (simultaneous capture and playback)
void audio_ring_buffer_register_atomics(audio_ring_buffer_t *rb, const char *context_name)
Register audio ring buffer atomic fields for debug tracking.
asciichat_error_t audio_parse_batch_header(const void *data, size_t len, audio_batch_info_t *out_batch)
Parse an audio batch packet header from raw packet data.
void audio_destroy(audio_context_t *ctx)
Destroy audio context and clean up resources.
asciichat_error_t audio_stop_duplex(audio_context_t *ctx)
Stop full-duplex audio.
void audio_ring_buffer_unregister_atomics(audio_ring_buffer_t *rb)
Unregister audio ring buffer atomic fields.
asciichat_error_t audio_write_samples(audio_context_t *ctx, const float *buffer, int num_samples)
Write audio samples to playback buffer.
void audio_terminate_portaudio_final(void)
Terminate PortAudio and free all device resources.
void audio_flush_playback_buffers(audio_context_t *ctx)
Flush all audio buffers to synchronize with seek operations.
void audio_set_pipeline(audio_context_t *ctx, void *pipeline)
Set audio pipeline for echo cancellation.
audio_ring_buffer_t * audio_ring_buffer_create_for_capture(void)
Create a new audio ring buffer for capture (without jitter buffering)
size_t audio_ring_buffer_peek(audio_ring_buffer_t *rb, float *data, size_t samples)
Peek at available samples without consuming them (for AEC3 render signal)
asciichat_error_t audio_validate_batch_params(const audio_batch_info_t *batch)
Validate audio batch parameters for sanity.
asciichat_error_t audio_list_input_devices(audio_device_info_t **out_devices, unsigned int *out_count)
List available audio input devices (microphones)
asciichat_error_t audio_dequantize_samples(const uint8_t *samples_ptr, uint32_t total_samples, float *out_samples)
Dequantize network audio samples from int32 to float.
asciichat_error_t audio_list_output_devices(audio_device_info_t **out_devices, unsigned int *out_count)
List available audio output devices (speakers)
void audio_ring_buffer_clear(audio_ring_buffer_t *rb)
Clear all audio samples from ring buffer.
asciichat_error_t audio_read_samples(audio_context_t *ctx, float *buffer, int num_samples)
Read captured audio samples from capture buffer.
void resample_linear(const float *src, size_t src_samples, float *dst, size_t dst_samples, double src_rate, double dst_rate)
Resample audio using linear interpolation.
size_t audio_ring_buffer_available_write(audio_ring_buffer_t *rb)
Get number of sample slots available for writing.
unsigned int uint32_t
Definition common.h:58
unsigned char uint8_t
Definition common.h:56
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
#define ASCIICHAT_API
Export symbols on Unix platforms (Linux, macOS)
Definition api.h:82
void audio_ring_buffer_discard_pending(audio_ring_buffer_t *rb)
#define AUDIO_DEVICE_NAME_MAX
Maximum length of audio device name.
void * asciichat_thread_t
Stub PortAudio header for WASM builds.
void PaStream
Definition portaudio.h:13
ClangTool/LibTooling compatibility shim for stdbool.h.
Atomic value wrapper for integral/boolean types.
Definition atomic.h:76
Parsed audio batch packet header information.
Audio context for full-duplex capture and playback.
bool initialized
True if context has been initialized.
audio_ring_buffer_t * raw_render_rb
Callback → Worker: Raw speaker samples (AEC3 reference)
double input_device_rate
Native sample rate of input device.
audio_ring_buffer_t * playback_buffer
OLD: Network → Worker (will become network_playback_rb)
float * worker_render_batch
Pre-allocated buffer for batch render processing.
float input_resample_previous
Last input sample used at a block boundary.
PaStream * input_stream
Separate input stream (when full-duplex unavailable)
bool worker_running
True if worker thread is running.
atomic_t shutting_down
True when shutdown started - callback outputs silence.
bool monitor_local_media
Play local file audio in solo sessions.
cond_t worker_cond
Condition variable for worker signaling.
atomic_t worker_should_stop
Signal worker thread to exit.
bool input_resample_has_previous
Whether a prior input block has been processed.
void * capture_media_source
Borrowed local media audio; configure before starting duplex.
bool separate_streams
True if using separate input/output streams.
double sample_rate
Actual sample rate of streams (48kHz)
audio_ring_buffer_t * capture_buffer
OLD: Worker → Network (will become processed_capture_rb)
void * audio_pipeline
Client audio pipeline for AEC3 echo cancellation (opaque pointer)
bool running
True if duplex stream is active.
float output_resample_previous
Last source sample used at an output boundary.
audio_ring_buffer_t * render_buffer
Ring buffer for render reference (separate streams mode)
audio_ring_buffer_t * raw_capture_rb
Callback → Worker: Raw mic samples (no processing)
double output_device_rate
Native sample rate of output device.
float * worker_playback_batch
Pre-allocated buffer for batch playback processing.
double output_resample_phase
48 kHz source position carried between output callbacks
mutex_t worker_mutex
Mutex protecting worker state.
mutex_t state_mutex
Mutex protecting context state.
asciichat_thread_t worker_thread
Worker thread for audio processing.
float * worker_capture_batch
Pre-allocated buffer for batch capture processing.
bool playback_only
True for playback-only mode (mirror), skip microphone capture.
audio_ring_buffer_t * processed_playback_rb
Worker → Callback: Ready for speakers.
PaStream * duplex_stream
PortAudio full-duplex stream (simultaneous input+output)
double input_resample_phase
Source position carried between native-rate input blocks.
PaStream * output_stream
Separate output stream (when full-duplex unavailable)
bool output_resample_has_previous
Whether a prior output block has been processed.
Audio device information structure.
int max_output_channels
Maximum output channels (0 if input only)
int max_input_channels
Maximum input channels (0 if output only)
int index
PortAudio device index.
double default_sample_rate
Default sample rate in Hz.
bool is_default_output
True if this is the default output device.
bool is_default_input
True if this is the default input device.
Audio ring buffer for real-time audio streaming.
Definition ringbuffer.h:205
Condition variable type (POSIX: pthread_cond_t with debug tracking)
Definition cond.h:63
Mutex type (POSIX: pthread_mutex_t with debug tracking)