using System; using System.Runtime.InteropServices; using System.Security; namespace Discord.Audio.Opus { internal enum OpusApplication : int { Voice = 2048, MusicOrMixed = 2049, LowLatency = 2051 } internal enum OpusError : int { OK = 0, BadArg = -1, BufferToSmall = -2, InternalError = -3, InvalidPacket = -4, Unimplemented = -5, InvalidState = -6, AllocFail = -7 } internal abstract class OpusConverter : IDisposable { protected enum Ctl : int { SetBitrateRequest = 4002, GetBitrateRequest = 4003, SetInbandFECRequest = 4012, GetInbandFECRequest = 4013 } #if NET45 [SuppressUnmanagedCodeSecurity] #endif protected unsafe static class UnsafeNativeMethods { [DllImport("opus", EntryPoint = "opus_encoder_create", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr CreateEncoder(int Fs, int channels, int application, out OpusError error); [DllImport("opus", EntryPoint = "opus_encoder_destroy", CallingConvention = CallingConvention.Cdecl)] public static extern void DestroyEncoder(IntPtr encoder); [DllImport("opus", EntryPoint = "opus_encode", CallingConvention = CallingConvention.Cdecl)] public static extern int Encode(IntPtr st, byte* pcm, int frame_size, byte[] data, int max_data_bytes); [DllImport("opus", EntryPoint = "opus_encoder_ctl", CallingConvention = CallingConvention.Cdecl)] public static extern int EncoderCtl(IntPtr st, Ctl request, int value); [DllImport("opus", EntryPoint = "opus_decoder_create", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr CreateDecoder(int Fs, int channels, out OpusError error); [DllImport("opus", EntryPoint = "opus_decoder_destroy", CallingConvention = CallingConvention.Cdecl)] public static extern void DestroyDecoder(IntPtr decoder); [DllImport("opus", EntryPoint = "opus_decode", CallingConvention = CallingConvention.Cdecl)] public static extern int Decode(IntPtr st, byte* data, int len, byte[] pcm, int frame_size, int decode_fec); } protected IntPtr _ptr; /// Gets the bit rate of this converter. public const int BitsPerSample = 16; /// Gets the input sampling rate of this converter. public int InputSamplingRate { get; } /// Gets the number of channels of this converter. public int InputChannels { get; } /// Gets the milliseconds per frame. public int FrameLength { get; } /// Gets the number of samples per frame. public int SamplesPerFrame { get; } /// Gets the bytes per frame. public int FrameSize { get; } /// Gets the bytes per sample. public int SampleSize { get; } protected OpusConverter(int samplingRate, int channels, int frameLength) { if (samplingRate != 8000 && samplingRate != 12000 && samplingRate != 16000 && samplingRate != 24000 && samplingRate != 48000) throw new ArgumentOutOfRangeException(nameof(samplingRate)); if (channels != 1 && channels != 2) throw new ArgumentOutOfRangeException(nameof(channels)); InputSamplingRate = samplingRate; InputChannels = channels; FrameLength = frameLength; SampleSize = (BitsPerSample / 8) * channels; SamplesPerFrame = samplingRate / 1000 * FrameLength; FrameSize = SamplesPerFrame * SampleSize; } #region IDisposable Support private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) disposedValue = true; } ~OpusConverter() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion } }