You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
3.2 KiB

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 OpusError EncoderCtl(IntPtr st, OpusCtl request, int value);
public AudioApplication Application { get; }
public int BitRate { get;}
public OpusEncoder(int bitrate, AudioApplication application, int packetLoss)
{
if (bitrate < 1 || bitrate > DiscordVoiceAPIClient.MaxBitrate)
throw new ArgumentOutOfRangeException(nameof(bitrate));
Application = application;
BitRate = bitrate;
OpusApplication opusApplication;
OpusSignal opusSignal;
switch (application)
{
case AudioApplication.Mixed:
opusApplication = OpusApplication.MusicOrMixed;
opusSignal = OpusSignal.Auto;
break;
case AudioApplication.Music:
opusApplication = OpusApplication.MusicOrMixed;
opusSignal = OpusSignal.Music;
break;
case AudioApplication.Voice:
opusApplication = OpusApplication.Voice;
opusSignal = OpusSignal.Voice;
break;
default:
throw new ArgumentOutOfRangeException(nameof(application));
}
_ptr = CreateEncoder(SamplingRate, Channels, (int)opusApplication, out var error);
CheckError(error);
CheckError(EncoderCtl(_ptr, OpusCtl.SetSignal, (int)opusSignal));
CheckError(EncoderCtl(_ptr, OpusCtl.SetPacketLossPercent, packetLoss)); //%
CheckError(EncoderCtl(_ptr, OpusCtl.SetInbandFEC, 1)); //True
CheckError(EncoderCtl(_ptr, OpusCtl.SetBitrate, bitrate));
}
public unsafe int EncodeFrame(byte[] input, int inputOffset, byte[] output, int outputOffset)
{
int result = 0;
fixed (byte* inPtr = input)
fixed (byte* outPtr = output)
result = Encode(_ptr, inPtr + inputOffset, FrameSamplesPerChannel, outPtr + outputOffset, output.Length - outputOffset);
CheckError(result);
return result;
}
protected override void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (_ptr != IntPtr.Zero)
DestroyEncoder(_ptr);
base.Dispose(disposing);
}
}
}
}