Events & Reference
Event argument types, enumerations, constants, and threading best practices.
Events Reference
AudioStateChangedEventArgs
Raised by OwnaudioNet.AudioStateChanged and by each audio source's StateChanged event.
| Property | Type | Description |
|---|---|---|
PreviousState | AudioState | State before the transition. |
CurrentState | AudioState | New state after the transition. |
Timestamp | DateTime | When the transition occurred. |
OwnaudioNet.AudioStateChanged += (_, e) =>
{
Console.WriteLine($"{e.PreviousState} → {e.CurrentState} at {e.Timestamp:T}");
};BufferUnderrunEventArgs
Raised by OwnaudioNet.BufferUnderrun when the audio output buffer runs dry.
| Property | Type | Description |
|---|---|---|
UnderrunCount | int | Cumulative underrun count since engine start. |
Timestamp | DateTime | When the underrun occurred. |
AudioErrorEventArgs
Raised by OwnaudioNet.AudioError on engine-level errors.
| Property | Type | Description |
|---|---|---|
Message | string | Human-readable error description. |
Exception | Exception? | Original exception (if any). |
Timestamp | DateTime | When the error occurred. |
TrackDropoutEventArgs
Raised by AudioMixer.TrackDropout when a hard-sync correction (Red Zone) occurs. See Drift Correction Zones.
| Property | Type | Description |
|---|---|---|
TrackId | Guid | ID of the source that dropped out. |
TrackName | string | Source name or type string. |
MasterTimestamp | double | Clock position in seconds when dropout occurred. |
MasterSamplePosition | long | Clock position in samples. |
MissedFrames | int | Number of frames that were silent due to the dropout. |
Reason | string | Human-readable cause description. |
EventTimestamp | DateTime | Wall-clock time of the event. |
AudioDeviceInfo
Returned by OwnaudioNet.GetOutputDevices() and GetInputDevices().
| Property | Type | Description |
|---|---|---|
DeviceId | string | Unique device identifier — pass to AudioConfig.OutputDeviceId. |
Name | string | Human-readable device name. |
EngineName | string | Backend: Wasapi, CoreAudio, PulseAudio, … |
IsInput / IsOutput | bool | Device direction. |
IsDefault | bool | System default device for its direction. |
MaxInputChannels / MaxOutputChannels | int | Hardware channel limits. |
State | AudioDeviceState | Active, Disabled, NotPresent, Unplugged. |
Enumerations
AudioState
AudioState.Stopped // Not playing, position at 0
AudioState.Playing // Actively reading and outputting audio
AudioState.Paused // Paused, resumes from current position
AudioState.EndOfStream // Reached end (Loop = false)
AudioState.Error // Fatal error in sourceClockMode
ClockMode.Realtime // Non-blocking — dropouts produce silence (live playback)
ClockMode.Offline // Blocking — waits for data (deterministic file rendering)
ClockMode.NetworkServer // Broadcasts clock to LAN clients
ClockMode.NetworkClient // Follows a remote server clockEngineStatus
EngineStatus.Idle // Initialized, not started
EngineStatus.Running // Processing audio
EngineStatus.DeviceDisconnected // Device unplugged (monitoring for reconnect)
EngineStatus.Error // Fatal engine errorEngineHostType
EngineHostType.None // Auto-select (recommended default)
EngineHostType.WASAPI // Windows Audio Session API
EngineHostType.ASIO // ASIO — Windows, ultra-low latency
EngineHostType.CoreAudio // macOS Core Audio
EngineHostType.ALSA // Linux ALSA
EngineHostType.Miniaudio // Cross-platform fallback
EngineHostType.Portaudio // PortAudio backendBest Practices
Thread Safety
| Operation | Safe Thread | Notes |
|---|---|---|
OwnaudioNet.Initialize() | Background / Task.Run | Blocks 50ms–5s (Linux PulseAudio). Use InitializeAsync(). |
OwnaudioNet.Stop() / Shutdown() | Background / Task.Run | Waits for audio thread join (up to 2s). Use async variants. |
mixer.Start(), mixer.Stop() | Any | Thread-safe. |
mixer.AddSource() / RemoveSource() | Any | Lock-free hot-swap. |
source.Volume = …, source.Tempo = … | Any | Atomic property writes. |
OwnaudioNet.Send() | Any | Lock-free ring buffer write, never blocks. |
Never call Initialize(), Stop(), or Shutdown() from a UI thread. These operations block and will freeze your application. Always use the async variants or Task.Run.
Recommended Startup Pattern
protected override async Task OnInitializedAsync()
{
var config = OwnaudioNet.CreateDefaultConfig();
config.EnableInput = false;
if (OperatingSystem.IsWindows())
config.HostType = EngineHostType.WASAPI;
await OwnaudioNet.InitializeAsync(config);
OwnaudioNet.Start();
_mixer = new AudioMixer(OwnaudioNet.Engine!.UnderlyingEngine, bufferSizeInFrames: 1024);
_mixer.Start();
}Recommended Shutdown Pattern
public async Task DisposeAsync()
{
_mixer?.Stop();
_mixer?.Dispose();
await OwnaudioNet.ShutdownAsync();
}Zero-Allocation Rules
Never allocate memory inside the audio render loop. Use Span<T>, pre-allocated buffers, and pool-returned arrays. Always call ReturnInputBuffer() after Receive() — omitting this call leaks native memory.
var buffer = OwnaudioNet.Receive();
if (buffer != null)
{
try
{
// Process buffer.Data ...
}
finally
{
OwnaudioNet.ReturnInputBuffer(buffer); // MUST always be called
}
}VU Metering Pattern
// Poll at ~10 Hz — do not poll faster than the audio buffer interval
_vuTimer = new Timer(_ =>
{
float leftDb = 20f * MathF.Log10(Math.Max(_mixer.LeftPeak, 1e-6f));
float rightDb = 20f * MathF.Log10(Math.Max(_mixer.RightPeak, 1e-6f));
LeftDb = Math.Max(leftDb, -60f); // clamp to -60 dBFS floor
RightDb = Math.Max(rightDb, -60f);
// Per-track stereo levels
var (l, r) = source.OutputLevels;
}, null, 0, 100);Position Tracking Pattern
private double _lastEnginePos;
private double _lastEnginePosAt;
private readonly Stopwatch _watch = Stopwatch.StartNew();
// Update at ~30 Hz (33 ms timer)
private void OnPositionTimer()
{
double enginePos = _mixer.MasterClock.CurrentTimestamp;
double nowSec = _watch.Elapsed.TotalSeconds;
if (enginePos != _lastEnginePos)
{
_lastEnginePos = enginePos;
_lastEnginePosAt = nowSec;
}
// Interpolate between engine callbacks for smooth UI
double displayPos = _lastEnginePos + (nowSec - _lastEnginePosAt);
CurrentPositionSeconds = displayPos;
}
// Or use ISynchronizable for sample-accurate per-source position
if (source is ISynchronizable sync)
{
int sampleRate = OwnaudioNet.Engine!.Config.SampleRate;
double posSeconds = sync.SamplePosition / (double)sampleRate;
}AudioConstants
AudioConstants.MaxAudioSources // 25 — maximum simultaneous sources per mixer
AudioConstants.MinTempo // 0.8 — minimum tempo multiplier (80% speed)
AudioConstants.MaxTempo // 1.2 — maximum tempo multiplier (120% speed)Volume Range
All source Volume properties accept values from 0.0 (silence) to 20.0 (maximum amplification). The default is 1.0 (unity gain). Values above 1.0 amplify the signal and may clip without a limiter.
Pitch Shift Range
The PitchShift property on audio sources accepts values from -12 to +12 semitones. Use in combination with Tempo to time-stretch without changing pitch.