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.

PropertyTypeDescription
PreviousStateAudioStateState before the transition.
CurrentStateAudioStateNew state after the transition.
TimestampDateTimeWhen the transition occurred.
C#
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.

PropertyTypeDescription
UnderrunCountintCumulative underrun count since engine start.
TimestampDateTimeWhen the underrun occurred.

AudioErrorEventArgs

Raised by OwnaudioNet.AudioError on engine-level errors.

PropertyTypeDescription
MessagestringHuman-readable error description.
ExceptionException?Original exception (if any).
TimestampDateTimeWhen the error occurred.

TrackDropoutEventArgs

Raised by AudioMixer.TrackDropout when a hard-sync correction (Red Zone) occurs. See Drift Correction Zones.

PropertyTypeDescription
TrackIdGuidID of the source that dropped out.
TrackNamestringSource name or type string.
MasterTimestampdoubleClock position in seconds when dropout occurred.
MasterSamplePositionlongClock position in samples.
MissedFramesintNumber of frames that were silent due to the dropout.
ReasonstringHuman-readable cause description.
EventTimestampDateTimeWall-clock time of the event.

AudioDeviceInfo

Returned by OwnaudioNet.GetOutputDevices() and GetInputDevices().

PropertyTypeDescription
DeviceIdstringUnique device identifier — pass to AudioConfig.OutputDeviceId.
NamestringHuman-readable device name.
EngineNamestringBackend: Wasapi, CoreAudio, PulseAudio, …
IsInput / IsOutputboolDevice direction.
IsDefaultboolSystem default device for its direction.
MaxInputChannels / MaxOutputChannelsintHardware channel limits.
StateAudioDeviceStateActive, Disabled, NotPresent, Unplugged.

Enumerations

AudioState

C#
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 source

ClockMode

C#
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 clock

EngineStatus

C#
EngineStatus.Idle               // Initialized, not started
EngineStatus.Running            // Processing audio
EngineStatus.DeviceDisconnected // Device unplugged (monitoring for reconnect)
EngineStatus.Error              // Fatal engine error

EngineHostType

C#
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 backend

Best Practices

Thread Safety

OperationSafe ThreadNotes
OwnaudioNet.Initialize()Background / Task.RunBlocks 50ms–5s (Linux PulseAudio). Use InitializeAsync().
OwnaudioNet.Stop() / Shutdown()Background / Task.RunWaits for audio thread join (up to 2s). Use async variants.
mixer.Start(), mixer.Stop()AnyThread-safe.
mixer.AddSource() / RemoveSource()AnyLock-free hot-swap.
source.Volume = …, source.Tempo = …AnyAtomic property writes.
OwnaudioNet.Send()AnyLock-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

C#
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

C#
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.

C# — Correct buffer return
var buffer = OwnaudioNet.Receive();
if (buffer != null)
{
    try
    {
        // Process buffer.Data ...
    }
    finally
    {
        OwnaudioNet.ReturnInputBuffer(buffer); // MUST always be called
    }
}

VU Metering Pattern

C#
// 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

C# — High-precision display with interpolation
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

C#
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.