namespace VoiceCat.Codec; public enum OpusApplication { Voip = 2048, Audio = 2049, LowDelay = 2051 } public sealed record OpusOptions { public int SampleRate { get; init; } = 48000; public int Channels { get; init; } = 1; public int FrameDurationMilliseconds { get; init; } = 20; public int Bitrate { get; init; } = 24000; public int MaximumBandwidthHz { get; init; } public int Complexity { get; init; } = 10; public int ExpectedPacketLossPercent { get; init; } public bool ForwardErrorCorrection { get; init; } = true; public bool DiscontinuousTransmission { get; init; } public bool DeepRedundancy { get; init; } public OpusApplication Application { get; init; } = OpusApplication.Voip; public int SamplesPerChannel => SampleRate / 1000 * FrameDurationMilliseconds; internal void Validate() { if (SampleRate is not (8000 or 12000 or 16000 or 24000 or 48000)) throw new ArgumentOutOfRangeException(nameof(SampleRate)); if (Channels is not (1 or 2)) throw new ArgumentOutOfRangeException(nameof(Channels)); if (FrameDurationMilliseconds is not (10 or 20 or 40 or 60)) throw new ArgumentOutOfRangeException(nameof(FrameDurationMilliseconds)); if (Application == OpusApplication.LowDelay && FrameDurationMilliseconds > 20) throw new ArgumentException("Low-delay Opus requires frames of at most 20 ms."); if (!Enum.IsDefined(Application)) throw new ArgumentOutOfRangeException(nameof(Application)); if (Bitrate is < 500 or > 512000) throw new ArgumentOutOfRangeException(nameof(Bitrate)); if (Complexity is < 0 or > 10) throw new ArgumentOutOfRangeException(nameof(Complexity)); if (ExpectedPacketLossPercent is < 0 or > 100) throw new ArgumentOutOfRangeException(nameof(ExpectedPacketLossPercent)); ArgumentOutOfRangeException.ThrowIfNegative(MaximumBandwidthHz); } }