|
|
|
|
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);
|
|
|
|
|
[DllImport("opus", EntryPoint = "opus_decoder_ctl", CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
private static extern int DecoderCtl(IntPtr st, OpusCtl request, int value);
|
|
|
|
|
|
|
|
|
|
public OpusDecoder()
|
|
|
|
|
{
|
|
|
|
|
_ptr = CreateDecoder(SamplingRate, Channels, out var error);
|
|
|
|
|
CheckError(error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public unsafe int DecodeFrame(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset, bool decodeFEC)
|
|
|
|
|
{
|
|
|
|
|
int result = 0;
|
|
|
|
|
fixed (byte* inPtr = input)
|
|
|
|
|
fixed (byte* outPtr = output)
|
|
|
|
|
result = Decode(_ptr, inPtr + inputOffset, inputCount, outPtr + outputOffset, FrameSamplesPerChannel, decodeFEC ? 1 : 0);
|
|
|
|
|
CheckError(result);
|
|
|
|
|
return result * SampleBytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (!_isDisposed)
|
|
|
|
|
{
|
|
|
|
|
if (_ptr != IntPtr.Zero)
|
|
|
|
|
DestroyDecoder(_ptr);
|
|
|
|
|
base.Dispose(disposing);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|