libivon 0.1.0
Voice-over-IP library
Loading...
Searching...
No Matches
libivon API Reference

libivon is a real-time multi-party voice communication library. It provides a stable C ABI for maximum portability and header-only C++ wrappers for ergonomic use from C++ consumers. This reference covers the public API surface: voice sessions, client networking, audio processing, and server administration.


Headers at a Glance

All public headers live under include/libivon/public/ within each component. Include them with #include "libivon/public/...".

Header Purpose
ivon_voice_session.h High-level API — bundles client + audio into one object
ivon_voice_session_wrapper.hpp C++ RAII wrapper for the voice session
ivon_voice_session_types.h Opaque handles, enums, and config for the voice session
ivon_client.h Network client — connect, message, groups
ivon_client_wrapper.hpp C++ RAII wrapper for the client
ivon_client_interface.hpp Abstract C++ interface for the client
ivon_client_types.h Opaque handles, enums, and callbacks for the client
ivon_audio.h Audio processor — encode, decode, mix
ivon_audio_wrapper.hpp C++ RAII wrapper for the audio processor
ivon_audio_interface.hpp Abstract C++ interface for the audio processor
ivon_audio_types.h Opaque handles, enums, frame duration, and constants
ivon_server.h Server — accept connections, manage groups
ivon_server_wrapper.hpp C++ RAII wrapper for the server
ivon_server_interface.hpp Abstract C++ interface for the server
ivon_server_types.h Opaque handles, enums, and callbacks for the server
ivon_common_types.h Shared callback typedefs
ivon_types.hpp C++ value types — NegotiationError, AudioOutputFrame, enums, callbacks

Each *_types.h header defines the opaque handles, enumerations, config structs, and callback typedefs used by the corresponding API header.


Quick Start — Voice Session (C++)

The voice session is the recommended entry point for most consumers. It wires the client and audio processor together automatically.

#include <iostream>
#include <span>
#include <vector>
// Application-provided stubs (replace with real implementations)
bool capture_mic(float *buf, size_t n); // fill buf with n mono samples
void play_audio(const float *buf, size_t n);
volatile bool running = true;
int main() {
// 1. Configure
cfg.client.server_address = "192.168.1.100";
cfg.client.server_port = 9129;
cfg.client.client_id = "alice";
cfg.voice_group_id = "voice"; // auto-join after connect
cfg.audio.output_channels = 2; // stereo output
// 2. Create session
// 3. Set PCM source (called each frame while speaking)
session.set_pcm_source([](std::span<float> pcm_out) -> bool {
// Fill pcm_out with mono float samples from your mic.
// The span size equals the runtime frame size (e.g. 480 for 10 ms).
return capture_mic(pcm_out.data(), pcm_out.size());
});
// 4. TOFU key verification (accept all keys in this example)
session.on_tofu_verify([](const std::string &, auto, auto, auto) {
return true;
});
// 5. React to speaking state changes
session.on_speaking([](const ivon::VoiceSessionWrapper::SpeakingInfo &info) {
std::cout << info.client_id
<< (info.speaking ? " started" : " stopped")
<< " speaking\n";
});
// 6. Connect (blocking)
auto result = session.connect();
if (!result) {
std::cerr << "Connect failed: " << result.error().message()
<< " — " << result.error().detail() << "\n";
return 1;
}
// 7. Start audio processing
session.start_audio();
session.start_speaking(IVON_SPEAKING_MODE_VAD);
// 8. Read mixed output in your audio thread.
// IVON_AUDIO_FRAME_SIZE (960) is the compile-time maximum;
// the actual frame size may be smaller when the server
// configures a shorter frame duration.
std::vector<float> pcm(IVON_AUDIO_FRAME_SIZE * 2); // stereo max
while (running) {
auto frame = session.audio().try_read_output(pcm.data(), pcm.size());
if (frame.valid) {
play_audio(pcm.data(),
static_cast<size_t>(frame.frame_size) * frame.channels);
}
}
// 9. Cleanup (RAII handles the rest)
session.audio().stop_speaking();
session.disconnect();
}
Consumer-facing C++ wrapper around the voice session C ABI.
Definition ivon_voice_session_wrapper.hpp:47
@ IVON_SPEAKING_MODE_VAD
Voice-activity detection.
Definition ivon_audio_types.h:44
#define IVON_AUDIO_FRAME_SIZE
Samples per channel per frame (960).
Definition ivon_audio_types.h:106
uint8_t output_channels
Output channel count: 1 = mono, 2 = stereo.
Definition ivon_audio_wrapper.hpp:60
uint16_t server_port
Server TCP port.
Definition ivon_client_wrapper.hpp:54
std::string server_address
Server hostname or IP address to connect to.
Definition ivon_client_wrapper.hpp:53
std::string client_id
Unique identifier for this client in the session.
Definition ivon_client_wrapper.hpp:55
Combined configuration for the voice session.
Definition ivon_voice_session_wrapper.hpp:52
AudioWrapper::Config audio
Definition ivon_voice_session_wrapper.hpp:57
ClientWrapper::Config client
Definition ivon_voice_session_wrapper.hpp:54
std::string voice_group_id
Definition ivon_voice_session_wrapper.hpp:60
Speaking state change with client ID mapping.
Definition ivon_voice_session_wrapper.hpp:73
bool speaking
True = started speaking, false = stopped speaking.
Definition ivon_voice_session_wrapper.hpp:77
std::string client_id
Human-readable client name (empty if sender is unknown)
Definition ivon_voice_session_wrapper.hpp:75

Quick Start — Voice Session (C)

#include <stdio.h>
/* Application-provided stubs (replace with real implementations) */
int capture_mic(float *buf, int n); /* fill buf with n mono samples */
void play_audio(const float *buf, int n);
volatile int running = 1;
static int pcm_source(float *pcm_out, int frame_size, void *user_data) {
(void)user_data;
/* Fill pcm_out with frame_size mono float samples */
return capture_mic(pcm_out, frame_size);
}
static int tofu_verify(const char *server_id, ivon_tofu_verify_result_t result,
const uint8_t server_key[IVON_PUBLIC_KEY_SIZE],
const uint8_t *stored, void *user_data) {
(void)server_id; (void)result; (void)server_key;
(void)stored; (void)user_data;
return 1; /* Accept all keys */
}
int main(void) {
/* 1. Build configuration via opaque config handles */
ivon_client_config_set_server_address(c_cfg, "192.168.1.100");
ivon_audio_config_set_output_channels(a_cfg, 2); /* stereo */
/* 2. Create session (copies config internally) */
if (!session) { return 1; }
/* 3. Register callbacks */
ivon_voice_session_set_pcm_source(session, pcm_source, NULL);
/* Set TOFU on the client handle */
ivon_client_set_on_tofu_verify(client, tofu_verify, NULL);
/* 4. Connect */
if (!r.success) {
fprintf(stderr, "Connect failed: %s\n", r.message);
return 1;
}
/* 5. Start audio and speaking */
/* 6. Read mixed output via audio handle.
* IVON_AUDIO_FRAME_SIZE (960) is the compile-time maximum;
* the actual frame size may be smaller depending on the
* server's frame_duration_ms property. */
float pcm[IVON_AUDIO_FRAME_SIZE * 2];
while (running) {
ivon_audio_try_read_output(audio, pcm, sizeof(pcm)/sizeof(pcm[0]));
if (frame.valid) {
play_audio(pcm, frame.frame_size * frame.channels);
}
}
/* 7. Cleanup */
ivon_voice_session_destroy(session); /* NULL-safe */
}
void ivon_audio_stop_speaking(ivon_audio_t audio)
Stop speaking (PTT released).
void ivon_audio_config_destroy(ivon_audio_config_t config)
Destroy an audio configuration handle. NULL is a safe no-op.
ivon_audio_config_t ivon_audio_config_create(void)
Create a new audio configuration with sane defaults.
void ivon_audio_config_set_output_channels(ivon_audio_config_t config, uint8_t channels)
Set output channel count: 1 = mono, 2 = stereo.
ivon_audio_output_frame_t ivon_audio_try_read_output(ivon_audio_t audio, float *pcm_out, size_t max_samples)
Try to read a mixed output frame (copy-out).
struct ivon_audio * ivon_audio_t
C ABI types for the libivon audio processor.
Definition ivon_audio_types.h:30
struct ivon_audio_config * ivon_audio_config_t
Opaque audio processor configuration handle.
Definition ivon_audio_types.h:122
void ivon_client_config_destroy(ivon_client_config_t config)
Destroy a client configuration handle. NULL is a safe no-op.
ivon_client_config_t ivon_client_config_create(void)
Create a new client configuration with sane defaults.
void ivon_client_config_set_server_address(ivon_client_config_t config, const char *address)
Set the server address (e.g. "127.0.0.1"). The string is copied.
void ivon_client_set_on_tofu_verify(ivon_client_t client, ivon_tofu_verify_fn callback, void *user_data)
Set the TOFU key verification callback.
void ivon_client_config_set_port(ivon_client_config_t config, uint16_t port)
Set the server port (default 9129).
void ivon_client_config_set_client_id(ivon_client_config_t config, const char *client_id)
Set the client identifier. The string is copied.
enum ivon_tofu_verify_result ivon_tofu_verify_result_t
TOFU verification results (mirrors TofuVerifyResult).
#define IVON_PUBLIC_KEY_SIZE
PUBLIC_KEY_SIZE from the C++ side.
Definition ivon_client_types.h:205
struct ivon_client_config * ivon_client_config_t
Opaque client configuration handle.
Definition ivon_client_types.h:132
struct ivon_client * ivon_client_t
C ABI types for the libivon client.
Definition ivon_client_types.h:32
void ivon_voice_session_config_destroy(ivon_voice_session_config_t config)
Destroy a voice session configuration. NULL is a safe no-op.
void ivon_voice_session_config_set_client(ivon_voice_session_config_t config, ivon_client_config_t client)
Set the client sub-configuration.
ivon_client_t ivon_voice_session_client_handle(ivon_voice_session_t session)
Get the underlying client handle.
void ivon_voice_session_destroy(ivon_voice_session_t session)
Destroy a voice session and free all resources.
ivon_connect_result_t ivon_voice_session_connect(ivon_voice_session_t session)
Connect to the server (blocking).
ivon_voice_session_t ivon_voice_session_create(ivon_voice_session_config_t config)
Create a new voice session.
void ivon_voice_session_start_speaking(ivon_voice_session_t session, ivon_speaking_mode_t mode)
Start speaking (PTT activated).
ivon_audio_t ivon_voice_session_audio_handle(ivon_voice_session_t session)
Get the underlying audio processor handle (non-owning).
void ivon_voice_session_config_set_audio(ivon_voice_session_config_t config, ivon_audio_config_t audio)
Set the audio sub-configuration.
ivon_voice_session_config_t ivon_voice_session_config_create(void)
Create a new voice session configuration with defaults.
void ivon_voice_session_set_pcm_source(ivon_voice_session_t session, ivon_audio_pcm_source_fn callback, void *user_data)
Set the PCM source callback for local audio capture.
void ivon_voice_session_disconnect(ivon_voice_session_t session)
Disconnect from the server.
void ivon_voice_session_start_audio(ivon_voice_session_t session)
Start the audio processor (tick coordinator + worker threads).
void ivon_voice_session_config_set_voice_group_id(ivon_voice_session_config_t config, const char *group_id)
Set the voice group to auto-join after connection.
struct ivon_voice_session * ivon_voice_session_t
C ABI types for the libivon voice session helper.
Definition ivon_voice_session_types.h:36
struct ivon_voice_session_config * ivon_voice_session_config_t
Opaque voice session configuration handle.
Definition ivon_voice_session_types.h:50
Mixed audio output frame (copy-out).
Definition ivon_audio_types.h:214
int valid
Non-zero if frame data is valid.
Definition ivon_audio_types.h:215
uint8_t channels
Number of channels in the output.
Definition ivon_audio_types.h:217
int frame_size
Samples per channel actually written.
Definition ivon_audio_types.h:216
Result of a connect() call.
Definition ivon_client_types.h:141
int success
Non-zero on success.
Definition ivon_client_types.h:142
const char * message
Human-readable error message (static lifetime, do not free).
Definition ivon_client_types.h:147

Quick Start — Server

#include <iostream>
#include <thread>
int main() {
cfg.address = "0.0.0.0";
cfg.port = 9129;
cfg.groups = {"voice", "team-a", "team-b"};
// Load identity keys from files
cfg.key_files.public_key_file = "server.pub";
cfg.key_files.private_key_file = "server.key";
// Optional: password authentication
cfg.require_password = true;
cfg.password = "secret";
// Create the wrapper — callbacks must be set BEFORE construction
ivon::ServerWrapper server(cfg);
// run() blocks; stop from another thread or signal handler
std::thread stopper([&server] {
wait_for_shutdown_signal();
server.stop();
});
server.run(); // blocks until stop()
stopper.join();
}
Server configuration.
Definition ivon_server_wrapper.hpp:55
struct ivon::ServerWrapper::Config::@1 key_files
Key files — set ONE of raw_keys or key_files.
bool require_password
Require password from clients.
Definition ivon_server_wrapper.hpp:62
std::string public_key_file
Path to public key file.
Definition ivon_server_wrapper.hpp:83
uint16_t port
Listen port.
Definition ivon_server_wrapper.hpp:58
std::string password
Expected password.
Definition ivon_server_wrapper.hpp:63
std::string private_key_file
Path to private key file.
Definition ivon_server_wrapper.hpp:84
std::string address
Listen address.
Definition ivon_server_wrapper.hpp:57
std::vector< std::string > groups
Groups created at startup.
Definition ivon_server_wrapper.hpp:66
RAII wrapper around the libivon server C ABI.
Definition ivon_server_wrapper.hpp:43

ServerWrapper callbacks (admission gates, auth hooks, connect/disconnect events) can be set before or after construction. Post-construction calls update the live server handle atomically:

ivon::ServerWrapper server(cfg);
// Callbacks can be installed at any time
server.on_client_connected([](const std::string &client_id, uint64_t session_id) {
std::cout << client_id << " connected (session " << session_id << ")\n";
});
server.on_connection_admission([](const std::string &ip, uint16_t port) -> bool {
return ip != "10.0.0.1"; // block a specific IP
});

For the C API, use ivon_server_config_set_on_*() on the config handle before calling ivon_server_create():

/* Gates and events — set on config before creating server */
ivon_server_config_destroy(cfg); /* safe after create */
ivon_server_run(server); /* blocks */
void ivon_server_config_destroy(ivon_server_config_t config)
Destroy a server configuration handle.
void ivon_server_config_set_on_client_disconnected(ivon_server_config_t config, ivon_server_client_disconnected_fn callback, void *user_data)
Set the client disconnected event callback.
void ivon_server_run(ivon_server_t server)
Run the server (blocks until stop() is called).
ivon_server_t ivon_server_create(ivon_server_config_t config)
Create a new server instance from a populated config.
ivon_server_config_t ivon_server_config_create(void)
Create a new server configuration handle.
void ivon_server_destroy(ivon_server_t server)
Destroy a server instance and free all resources.
void ivon_server_config_add_group(ivon_server_config_t config, const char *group_id)
Add a group to be created at server startup.
void ivon_server_config_set_on_client_connected(ivon_server_config_t config, ivon_server_client_connected_fn callback, void *user_data)
Set the client connected event callback.
void ivon_server_config_set_address(ivon_server_config_t config, const char *address)
Set the listening address (default "0.0.0.0").
void ivon_server_config_set_port(ivon_server_config_t config, uint16_t port)
Set the listening port (default 9129).
struct ivon_server * ivon_server_t
C ABI types for the libivon server.
Definition ivon_server_types.h:32
struct ivon_server_config * ivon_server_config_t
Opaque handle to a server configuration (builder pattern).
Definition ivon_server_types.h:35

Architecture

Threading Model

The library creates internal worker threads. Callbacks are invoked from these threads — they must be thread-safe and non-blocking.

Thread Fires
Decoder workers (N) on_speaking_event, on_pre_dsp
Pipeline workers (N) on_post_spatial, on_post_mix
Encoder drain worker (internal — drains encoded packets)
IO threads (server) All server gate/event callbacks
Client IO thread on_client_message, on_client_joined/left, group callbacks

Audio Format

Property Value
Sample rate 48 000 Hz
Frame duration 20 ms default; configurable via frame_duration (2.5, 5, 10, 20, 40 ms)
Frame size 960 samples/channel at 20 ms; query at runtime with pcm_frame_size() / ivon_audio_frame_size()
Capture format Mono float (PCM source callback)
Output format Interleaved float (try_read_output)
Codec Opus
Max output channels 8 (default 2 — stereo); query with output_channels() / ivon_audio_output_channels()

Object Ownership

All wrappers are RAII, move-only, non-copyable. The destructor stops the processor/server/client and frees all resources. Passing NULL to any C _destroy() function is a safe no-op.

The voice session owns its internal client and audio handles. Access the client handle via client_handle() for chat/presence callbacks, but do not destroy it or replace the audio/group callbacks that the session manages internally.


Standalone Client + Audio (Advanced)

For full control over the client and audio processor independently:

// Create client
client_cfg.server_address = "192.168.1.100";
client_cfg.client_id = "bob";
ivon::ClientWrapper client(client_cfg);
// Create audio processor
audio_cfg.output_channels = 2;
audio_cfg.decoder_workers = 4;
ivon::AudioWrapper audio(audio_cfg);
// Wire fanout data → audio decoder
client.on_fanout_data([&audio](const std::string &group_id, uint64_t sender_id,
uint64_t seq, const unsigned char *data, size_t len) {
audio.submit_packet(sender_id, data, len);
});
// Wire encoded audio → client send
// (run in your own drain loop)
std::array<unsigned char, 2048> pkt;
size_t n = audio.try_read_packet(pkt.data(), pkt.size());
if (n > 0) {
client.send_group_data("voice", pkt.data(), n);
}
// Set up PCM source, connect, join group, start audio...
Consumer-facing C++ wrapper around the libivon audio C ABI.
Definition ivon_audio_wrapper.hpp:44
Consumer-facing C++ wrapper around the libivon C ABI.
Definition ivon_client_wrapper.hpp:47
Configuration for creating an audio processor.
Definition ivon_audio_wrapper.hpp:52
uint8_t decoder_workers
Number of Opus decoder worker threads.
Definition ivon_audio_wrapper.hpp:57
Configuration for creating a client (mirrors ivon_client_config_t).
Definition ivon_client_wrapper.hpp:52

This is what the voice session does internally. Use this pattern when you need custom routing, multiple groups, or separate lifecycle control.


DSP Pipeline

The audio processor exposes three hook points in the decode → mix pipeline. Each callback receives a writeable PCM buffer — modify in-place to apply effects. Return IVON_DSP_ACTION_STOP to discard the frame.

Opus decode
┌──────────────────┐
│ on_pre_dsp │ Mono per-sender (frame_size float samples)
│ (CONTINUE/STOP) │ Use for: per-speaker gain, noise gate, AGC
└──────────────────┘
Channel expansion (mono → stereo/surround)
┌──────────────────┐
│ on_post_spatial │ Expanded per-sender (frame_size × channels floats)
│ (CONTINUE/STOP) │ Use for: spatial positioning, HRTF, panning
└──────────────────┘
Additive mix (all senders summed)
┌──────────────────┐
│ on_post_mix │ Final mix (frame_size × channels floats)
│ (CONTINUE/STOP) │ Use for: limiter, master EQ, recording
└──────────────────┘
Output ring buffer → try_read_output()

frame_size is pcm_frame_size() (C++) or ivon_audio_frame_size() (C). The default is 960 (20 ms at 48 kHz), but the server may negotiate a different value.

audio.on_pre_dsp([](ivon_pre_dsp_context_t &ctx) -> ivon_dsp_action_t {
// Apply per-sender noise gate
float rms = compute_rms(ctx.pcm, ctx.frame_size);
if (rms < threshold) {
std::fill_n(ctx.pcm, ctx.frame_size, 0.0f);
}
});
@ IVON_DSP_ACTION_CONTINUE
Continue to next pipeline stage.
Definition ivon_audio_types.h:63
enum ivon_dsp_action ivon_dsp_action_t
DSP callback return value — controls pipeline continuation.
Context for pre-DSP callbacks (mono per-sender).
Definition ivon_audio_types.h:172
int frame_size
Samples per channel.
Definition ivon_audio_types.h:178
float * pcm
Mono PCM buffer (writeable)
Definition ivon_audio_types.h:177

Error Handling

Layer C C++
Object creation Returns NULL Throws std::runtime_error
Connection ivon_connect_result_t with error codes and message expected_void<NegotiationError>
Group operations Status enum in result struct Same struct passed through
Async operations int success in completion callback std::function<void(bool)>

Connection errors carry both a negotiation code (protocol/auth level) and a connection code (transport level). Check is_connection_error() to distinguish:

auto result = session.connect();
if (!result) {
auto &err = result.error();
if (err.is_connection_error()) {
// Transport failure — check err.connection_code()
} else {
// Auth/protocol failure — check err.negotiation_code()
}
std::cerr << err.message() << "\n" << err.detail() << "\n";
}

TOFU Key Verification

The client uses Trust-On-First-Use for server identity. The TOFU callback receives the server's public key and a result indicating whether the key is new, trusted, or changed:

Result Meaning Recommended action
IVON_TOFU_TRUSTED Key matches stored key Accept
IVON_TOFU_NEW_KEY First connection, no stored key Prompt user or accept
IVON_TOFU_KEY_CHANGED Key differs from stored Warn user — possible MITM
IVON_TOFU_VERIFICATION_ERROR Key verification failed Reject
session.on_tofu_verify([](const std::string &server_id,
const std::array<uint8_t, ivon::PUBLIC_KEY_SIZE> &server_key,
const std::optional<std::array<uint8_t, ivon::PUBLIC_KEY_SIZE>> &stored_key) -> bool {
std::cerr << "WARNING: Server key changed for " << server_id << "\n";
return false; // Reject
}
return true; // Accept new or trusted keys
});
TofuVerifyResult
Result of TOFU (Trust-On-First-Use) key verification.
Definition ivon_types.hpp:325
@ key_changed
Server seen before but key has changed.

Server Authentication Pipeline

The server supports a multi-stage admission pipeline. Each gate is a callback that returns true (accept) or false (reject):

TCP connect
┌────────────────────────┐
│ on_connection_admission│ Gate: IP/port filtering
└────────────────────────┘
┌────────────────────────┐
│ on_client_id_check │ Gate: validate client ID format/uniqueness
└────────────────────────┘
┌────────────────────────┐
│ on_password_validate │ Gate: custom password check (if require_password)
└────────────────────────┘
┌────────────────────────┐
│ on_client_approve │ Gate: final approval before visibility
└────────────────────────┘
┌────────────────────────┐
│ on_client_connected │ Event: client is now registered
└────────────────────────┘

All gates are optional. If a gate callback is not set, the stage is automatically approved.


Configuration Reference

Audio (<tt>ivon_audio_config_t</tt> / <tt>AudioWrapper::Config</tt>)

Field Default Description
frame_duration IVON_FRAME_DURATION_20_MS Codec frame duration (2.5, 5, 10, 20, 40 ms)
packet_pool_chunks 4 Packet pool chunks (1024 buffers each)
frame_pool_chunks 4 Frame pool chunks (256 frames each)
decoder_workers 2 Decoder thread count
jitter_depth 2 Frames to buffer before playback (0 = bypass)
pipeline_workers 2 Pipeline (mix) thread count
output_channels 2 Output channels (1=mono, 2=stereo, up to 8)
output_buffer_frames 200 Output ring buffer capacity in frames
encoder_bitrate 64000 Opus target bitrate (bps)
encoder_fec 1 Enable Opus forward error correction
encoder_fec_loss_percent 5 Expected packet loss hint for FEC tuning
encoder_complexity 5 Opus complexity (0–10, higher = better quality)

Client (<tt>ivon_client_config_t</tt> / <tt>ClientWrapper::Config</tt>)

Field Default Description
server_address "127.0.0.1" Server hostname or IP
server_port 9129 Server TCP port
client_id Unique identifier for this client
key_store_path NULL Path to TOFU key store file (NULL = in-memory)
sync_timeout_seconds 30 Initial sync timeout (0 = infinite)

Server (<tt>ivon_server_config_t</tt> / <tt>ServerWrapper::Config</tt>)

Field Default Description
address "0.0.0.0" Listen address
port 9129 Listen port
network_interface Bind to specific interface (Linux only)
num_threads 1 IO thread count
require_password false Require client authentication
password Expected password
max_password_attempts 3 Attempts before rejection
groups Groups created at startup
fanout_base_port 10300 Base UDP port for audio multicast
fanout_advertise_address "127.0.0.1" Address advertised to clients
key_rotation_on_leave true Rotate group keys when members leave
key_rotation_debounce_ms 1000 Debounce interval for key rotation
key_rotation_interval_ms 0 Periodic key rotation (0 = disabled)

Voice Session (<tt>ivon_voice_session_config_t</tt> / <tt>VoiceSessionWrapper::Config</tt>)

Field Default Description
client Nested client configuration
audio Nested audio configuration
voice_group_id NULL Auto-join this group after connect
poll_interval_ms 10 Worker drain interval (ms)

Statistics

Both the audio processor and voice session expose runtime statistics:

auto stats = session.get_audio_stats();
// Pipeline health
stats.current_tick; // Ticks elapsed since start
stats.max_drift_us; // Maximum clock drift (microseconds)
stats.dropped_ticks; // Ticks that couldn't keep up with real-time
// Decoder (across all workers and senders)
stats.packets_decoded; // Normal Opus decodes
stats.fec_recovered; // Frames recovered via FEC
stats.plc_frames; // Packet-loss concealment frames
stats.silence_frames; // Extended-loss silence insertions
// Encoder
stats.packets_encoded; // Opus frames encoded for transmission

API Versioning

Each subsystem has compile-time and runtime version macros/functions:

/* Compile-time */
#if IVON_AUDIO_API_VERSION_MAJOR >= 2
/* Use v2 API */
#endif
/* Runtime (check against loaded shared library) */
int ivon_audio_api_version_major(void)
Get the major version of the audio C ABI at runtime.
int ivon_audio_api_version_minor(void)
Get the minor version of the audio C ABI at runtime.

The C++ wrappers delegate to the same C ABI and share the version numbers.


Dynamic Loader (Runtime Loading)

Each profile generates a loader header that allows consumers to load the shared library at runtime via dlopen/LoadLibrary instead of linking against it at build time. This is useful for plugin architectures, optional dependencies, or applications that want to ship without bundling the .so.

The generated loader header provides:

  • Function-pointer typedefs for every exported C function
  • A global vtable struct populated at load time
  • Platform-aware dlopen/LoadLibrary open/close functions
  • Inline trampolines that match the original symbol names, so existing code compiles unchanged

Loader-Only Install

Each profile has a dedicated _loader install component that installs the loader header, all type headers, and the C++ wrapper headers — but not the shared library:

$ cmake --install build --component libivon_client_loader
$ cmake --install build --component libivon_server_loader
$ cmake --install build --component libivon_audio_loader

This gives consumers everything they need to compile against the API without requiring the .so at build time.

CMake Integration

In-tree targets can link against the loader INTERFACE target instead of the shared library:

target_link_libraries(my_app PRIVATE libivon_client_loader_target)

This target automatically provides:

  • Include directories for type headers and the generated loader header
  • The platform dl library on Linux
  • The LIBIVON_USE_CLIENT_LOADER compile definition, which tells the C++ wrappers to route through the loader trampolines instead of linked symbols

C++ Wrapper Compatibility

The C++ wrappers (ClientWrapper, AudioWrapper, VoiceSessionWrapper, ServerWrapper) work transparently in loader mode. When the LIBIVON_USE_<PROFILE>_LOADER define is active, the wrappers include the loader header instead of the C API header. Since the loader's inline trampolines provide the same symbol names as the linked library, no wrapper code changes are needed.

Usage (C)

Include the generated loader header directly. It provides the loader open/close functions and inline trampolines for every C API function. No library linking is required at build time — only -ldl on Linux:

$ gcc -I/path/to/includes/libivon my_app.c -ldl -o my_app
// Define the main-unit macro in exactly ONE translation unit
#define LIBIVON_CLIENT_LOADER_H_MAIN
#include "libivon/ivon_client_loader.h"
int main(void) {
// Load the .so/.dll at runtime (NULL = default search path)
if (ivon_client_loader_open(NULL) != 0)
return 1;
// All C API functions are now available as normal calls
// ... use the API normally ...
ivon_client_loader_close();
return 0;
}
ivon_client_t ivon_client_create(ivon_client_config_t config)
Create a new client instance.
void ivon_client_destroy(ivon_client_t client)
Destroy a client instance and free all associated resources.

Usage (C++ with Wrapper)

Define LIBIVON_USE_CLIENT_LOADER before including the wrapper header. This tells the wrapper to pull in the loader header instead of the normal C API header, making the loader open/close functions and all API trampolines available:

Using a compile argument:

$ g++ -DLIBIVON_USE_CLIENT_LOADER -I/path/to/includes/libivon my_app.cpp -ldl -o my_app

Or inline:

#define LIBIVON_USE_CLIENT_LOADER
int main() {
// Load the .so/.dll at runtime
if (ivon_client_loader_open(nullptr) != 0)
return 1;
{
cfg.server_address = "127.0.0.1";
cfg.server_port = 9129;
cfg.client_id = "my_app";
ivon::ClientWrapper client(cfg);
// ... use the C++ wrapper normally ...
} // ClientWrapper destructor calls ivon_client_destroy() through the loader
ivon_client_loader_close();
return 0;
}

Note: If using the libivon CMake build tree, linking against libivon_client_loader_target sets LIBIVON_USE_CLIENT_LOADER, the include paths, and -ldl automatically — no manual flags needed.