|
@@ -12,14 +12,12 @@ namespace Discord.Audio |
|
|
[DllImport("opus", EntryPoint = "opus_encode", CallingConvention = CallingConvention.Cdecl)] |
|
|
[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); |
|
|
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)] |
|
|
[DllImport("opus", EntryPoint = "opus_encoder_ctl", CallingConvention = CallingConvention.Cdecl)] |
|
|
private static extern int EncoderCtl(IntPtr st, OpusCtl request, int value); |
|
|
|
|
|
|
|
|
private static extern OpusError EncoderCtl(IntPtr st, OpusCtl request, int value); |
|
|
|
|
|
|
|
|
/// <summary> Gets the coding mode of the encoder. </summary> |
|
|
|
|
|
public AudioApplication Application { get; } |
|
|
public AudioApplication Application { get; } |
|
|
public int BitRate { get;} |
|
|
public int BitRate { get;} |
|
|
|
|
|
|
|
|
public OpusEncoder(int samplingRate, int channels, int bitrate, AudioApplication application) |
|
|
|
|
|
: base(samplingRate, channels) |
|
|
|
|
|
|
|
|
public OpusEncoder(int bitrate, AudioApplication application) |
|
|
{ |
|
|
{ |
|
|
if (bitrate < 1 || bitrate > DiscordVoiceAPIClient.MaxBitrate) |
|
|
if (bitrate < 1 || bitrate > DiscordVoiceAPIClient.MaxBitrate) |
|
|
throw new ArgumentOutOfRangeException(nameof(bitrate)); |
|
|
throw new ArgumentOutOfRangeException(nameof(bitrate)); |
|
@@ -47,57 +45,31 @@ namespace Discord.Audio |
|
|
throw new ArgumentOutOfRangeException(nameof(application)); |
|
|
throw new ArgumentOutOfRangeException(nameof(application)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
OpusError error; |
|
|
|
|
|
_ptr = CreateEncoder(samplingRate, channels, (int)opusApplication, out error); |
|
|
|
|
|
if (error != OpusError.OK) |
|
|
|
|
|
throw new Exception($"Opus Error: {error}"); |
|
|
|
|
|
|
|
|
|
|
|
var result = EncoderCtl(_ptr, OpusCtl.SetSignal, (int)opusSignal); |
|
|
|
|
|
if (result < 0) |
|
|
|
|
|
throw new Exception($"Opus Error: {(OpusError)result}"); |
|
|
|
|
|
|
|
|
|
|
|
result = EncoderCtl(_ptr, OpusCtl.SetPacketLossPercent, 30); //%% |
|
|
|
|
|
if (result < 0) |
|
|
|
|
|
throw new Exception($"Opus Error: {(OpusError)result}"); |
|
|
|
|
|
|
|
|
|
|
|
result = EncoderCtl(_ptr, OpusCtl.SetInbandFEC, 1); //True |
|
|
|
|
|
if (result < 0) |
|
|
|
|
|
throw new Exception($"Opus Error: {(OpusError)result}"); |
|
|
|
|
|
|
|
|
|
|
|
result = EncoderCtl(_ptr, OpusCtl.SetBitrate, bitrate); |
|
|
|
|
|
if (result < 0) |
|
|
|
|
|
throw new Exception($"Opus Error: {(OpusError)result}"); |
|
|
|
|
|
|
|
|
|
|
|
/*if (application == AudioApplication.Music) |
|
|
|
|
|
{ |
|
|
|
|
|
result = EncoderCtl(_ptr, OpusCtl.SetBandwidth, 1105); |
|
|
|
|
|
if (result < 0) |
|
|
|
|
|
throw new Exception($"Opus Error: {(OpusError)result}"); |
|
|
|
|
|
}*/ |
|
|
|
|
|
|
|
|
_ptr = CreateEncoder(SamplingRate, Channels, (int)opusApplication, out var error); |
|
|
|
|
|
CheckError(error); |
|
|
|
|
|
CheckError(EncoderCtl(_ptr, OpusCtl.SetSignal, (int)opusSignal)); |
|
|
|
|
|
CheckError(EncoderCtl(_ptr, OpusCtl.SetPacketLossPercent, 30)); //% |
|
|
|
|
|
CheckError(EncoderCtl(_ptr, OpusCtl.SetInbandFEC, 1)); //True |
|
|
|
|
|
CheckError(EncoderCtl(_ptr, OpusCtl.SetBitrate, bitrate)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// <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) |
|
|
|
|
|
|
|
|
public unsafe int EncodeFrame(byte[] input, int inputOffset, byte[] output, int outputOffset) |
|
|
{ |
|
|
{ |
|
|
int result = 0; |
|
|
int result = 0; |
|
|
fixed (byte* inPtr = input) |
|
|
fixed (byte* inPtr = input) |
|
|
fixed (byte* outPtr = output) |
|
|
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}"); |
|
|
|
|
|
|
|
|
result = Encode(_ptr, inPtr + inputOffset, FrameSamplesPerChannel, outPtr + outputOffset, output.Length - outputOffset); |
|
|
|
|
|
CheckError(result); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
protected override void Dispose(bool disposing) |
|
|
protected override void Dispose(bool disposing) |
|
|
{ |
|
|
{ |
|
|
if (_ptr != IntPtr.Zero) |
|
|
|
|
|
|
|
|
if (!_isDisposed) |
|
|
{ |
|
|
{ |
|
|
DestroyEncoder(_ptr); |
|
|
|
|
|
_ptr = IntPtr.Zero; |
|
|
|
|
|
|
|
|
if (_ptr != IntPtr.Zero) |
|
|
|
|
|
DestroyEncoder(_ptr); |
|
|
|
|
|
base.Dispose(disposing); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|