Concrete class prototype

This commit is contained in:
RogueException
2016-09-22 21:15:37 -03:00
parent ab42129eb9
commit 6319933ed0
394 changed files with 3648 additions and 3224 deletions

View File

@@ -0,0 +1,51 @@
using System;
namespace Discord.Audio
{
internal abstract class OpusConverter : IDisposable
{
protected IntPtr _ptr;
/// <summary> Gets the bit rate of this converter. </summary>
public const int BitsPerSample = 16;
/// <summary> Gets the bytes per sample. </summary>
public const int SampleSize = (BitsPerSample / 8) * MaxChannels;
/// <summary> Gets the maximum amount of channels this encoder supports. </summary>
public const int MaxChannels = 2;
/// <summary> Gets the input sampling rate of this converter. </summary>
public int SamplingRate { get; }
/// <summary> Gets the number of samples per second for this stream. </summary>
public int Channels { get; }
protected OpusConverter(int samplingRate, int channels)
{
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));
SamplingRate = samplingRate;
Channels = channels;
}
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);
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Discord.Audio
{
internal enum OpusCtl : int
{
SetBitrateRequest = 4002,
GetBitrateRequest = 4003,
SetInbandFECRequest = 4012,
GetInbandFECRequest = 4013
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Runtime.InteropServices;
namespace Discord.Audio
{
internal unsafe class OpusDecoder : OpusConverter
{
[DllImport("opus", EntryPoint = "opus_decoder_create", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr CreateDecoder(int Fs, int channels, out OpusError error);
[DllImport("opus", EntryPoint = "opus_decoder_destroy", CallingConvention = CallingConvention.Cdecl)]
private static extern void DestroyDecoder(IntPtr decoder);
[DllImport("opus", EntryPoint = "opus_decode", CallingConvention = CallingConvention.Cdecl)]
private static extern int Decode(IntPtr st, byte* data, int len, byte* pcm, int max_frame_size, int decode_fec);
public OpusDecoder(int samplingRate, int channels)
: base(samplingRate, channels)
{
OpusError error;
_ptr = CreateDecoder(samplingRate, channels, out error);
if (error != OpusError.OK)
throw new Exception($"Opus Error: {error}");
}
/// <summary> Produces PCM samples from Opus-encoded audio. </summary>
/// <param name="input">PCM samples to decode.</param>
/// <param name="inputOffset">Offset of the frame in input.</param>
/// <param name="output">Buffer to store the decoded frame.</param>
public unsafe int DecodeFrame(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
{
int result = 0;
fixed (byte* inPtr = input)
fixed (byte* outPtr = output)
result = Decode(_ptr, inPtr + inputOffset, inputCount, outPtr + outputOffset, (output.Length - outputOffset) / SampleSize / MaxChannels, 0);
if (result < 0)
throw new Exception($"Opus Error: {(OpusError)result}");
return result;
}
protected override void Dispose(bool disposing)
{
if (_ptr != IntPtr.Zero)
{
DestroyDecoder(_ptr);
_ptr = IntPtr.Zero;
}
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Runtime.InteropServices;
namespace Discord.Audio
{
internal unsafe class OpusEncoder : OpusConverter
{
[DllImport("opus", EntryPoint = "opus_encoder_create", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr CreateEncoder(int Fs, int channels, int application, out OpusError error);
[DllImport("opus", EntryPoint = "opus_encoder_destroy", CallingConvention = CallingConvention.Cdecl)]
private static extern void DestroyEncoder(IntPtr encoder);
[DllImport("opus", EntryPoint = "opus_encode", CallingConvention = CallingConvention.Cdecl)]
private 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)]
private static extern int EncoderCtl(IntPtr st, OpusCtl request, int value);
/// <summary> Gets the coding mode of the encoder. </summary>
public OpusApplication Application { get; }
public OpusEncoder(int samplingRate, int channels, OpusApplication application = OpusApplication.MusicOrMixed)
: base(samplingRate, channels)
{
Application = application;
OpusError error;
_ptr = CreateEncoder(samplingRate, channels, (int)application, out error);
if (error != OpusError.OK)
throw new Exception($"Opus Error: {error}");
}
/// <summary> Produces Opus encoded audio from PCM samples. </summary>
/// <param name="input">PCM samples to encode.</param>
/// <param name="output">Buffer to store the encoded frame.</param>
/// <returns>Length of the frame contained in outputBuffer.</returns>
public unsafe int EncodeFrame(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
{
int result = 0;
fixed (byte* inPtr = input)
fixed (byte* outPtr = output)
result = Encode(_ptr, inPtr + inputOffset, inputCount / SampleSize, outPtr + outputOffset, output.Length - outputOffset);
if (result < 0)
throw new Exception($"Opus Error: {(OpusError)result}");
return result;
}
/// <summary> Gets or sets whether Forward Error Correction is enabled. </summary>
public void SetForwardErrorCorrection(bool value)
{
var result = EncoderCtl(_ptr, OpusCtl.SetInbandFECRequest, value ? 1 : 0);
if (result < 0)
throw new Exception($"Opus Error: {(OpusError)result}");
}
/// <summary> Gets or sets whether Forward Error Correction is enabled. </summary>
public void SetBitrate(int value)
{
if (value < 1 || value > DiscordVoiceAPIClient.MaxBitrate)
throw new ArgumentOutOfRangeException(nameof(value));
var result = EncoderCtl(_ptr, OpusCtl.SetBitrateRequest, value * 1000);
if (result < 0)
throw new Exception($"Opus Error: {(OpusError)result}");
}
protected override void Dispose(bool disposing)
{
if (_ptr != IntPtr.Zero)
{
DestroyEncoder(_ptr);
_ptr = IntPtr.Zero;
}
}
}
}

View File

@@ -0,0 +1,14 @@
namespace Discord.Audio
{
internal enum OpusError : int
{
OK = 0,
BadArg = -1,
BufferToSmall = -2,
InternalError = -3,
InvalidPacket = -4,
Unimplemented = -5,
InvalidState = -6,
AllocFail = -7
}
}