From 09ea5443e7f6b73a33afb53a749b3d88b0be8c5e Mon Sep 17 00:00:00 2001 From: SineVector241 <69619913+SineVector241@users.noreply.github.com> Date: Fri, 8 Nov 2024 18:05:59 +1100 Subject: [PATCH 1/4] Add Opus Handlers. --- .gitignore | 3 + .../Discord.Net.V4.Audio.csproj | 1 + src/Discord.Net.V4.Audio/Opus/NativeOpus.cs | 229 ++++++++++++++++++ .../SafeHandlers/OpusDREDDecoderSafeHandle.cs | 19 ++ .../Opus/SafeHandlers/OpusDREDSafeHandle.cs | 19 ++ .../SafeHandlers/OpusDecoderSafeHandle.cs | 19 ++ .../SafeHandlers/OpusEncoderSafeHandle.cs | 19 ++ .../SafeHandlers/OpusMSDecoderSafeHandle.cs | 19 ++ .../SafeHandlers/OpusMSEncoderSafeHandle.cs | 19 ++ .../OpusRepacketizerSafeHandle.cs | 19 ++ 10 files changed, 366 insertions(+) create mode 100644 src/Discord.Net.V4.Audio/Opus/NativeOpus.cs create mode 100644 src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDDecoderSafeHandle.cs create mode 100644 src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDSafeHandle.cs create mode 100644 src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDecoderSafeHandle.cs create mode 100644 src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusEncoderSafeHandle.cs create mode 100644 src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSDecoderSafeHandle.cs create mode 100644 src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSEncoderSafeHandle.cs create mode 100644 src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusRepacketizerSafeHandle.cs diff --git a/.gitignore b/.gitignore index 46a337a86e..dcc0b0c668 100644 --- a/.gitignore +++ b/.gitignore @@ -210,3 +210,6 @@ docs/api/\.manifest # Codealike UID codealike.json + +# This is so coderush data isn't included... +.cr/ \ No newline at end of file diff --git a/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj b/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj index 37b94d6b45..b81be1d983 100644 --- a/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj +++ b/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj @@ -8,6 +8,7 @@ True false Discord.Audio + true diff --git a/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs b/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs new file mode 100644 index 0000000000..47a0b463ae --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs @@ -0,0 +1,229 @@ +using Discord.Audio.Opus.SafeHandlers; +using System.Runtime.InteropServices; +namespace Discord.Audio.Opus +{ + /// + /// Native opus handler that directly calls the exported opus functions. + /// + internal static class NativeOpus + { +#if ANDROID + private const string DllName = "libopus.so"; +#elif LINUX + private const string DllName = "libopus.so.0.10.1"; +#elif WINDOWS + private const string DllName = "opus.dll"; +#elif MACOS || IOS || MACCATALYST + private const string DllName = "__Internal__"; +#else + private const string DllName = "opus"; +#endif + + //Encoder + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_encoder_get_size(int channels); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern OpusEncoderSafeHandle opus_encoder_create(int Fs, int application, int* error); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_encoder_init(OpusEncoderSafeHandle st, int Fs, int channels, int application); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_encode(OpusEncoderSafeHandle st, short* pcm, int frame_size, byte* data, int max_data_bytes); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_encode_float(OpusEncoderSafeHandle st, float* pcm, int frame_size, byte* data, int max_data_bytes); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern void opus_encoder_destroy(IntPtr st); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_encoder_ctl(OpusEncoderSafeHandle st, int request, void* data); + + //Decoder + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_decoder_get_size(int channels); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern OpusDecoderSafeHandle opus_decoder_create(int Fs, int channels, int* error); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_decoder_init(OpusDecoderSafeHandle st, int Fs, int channels); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_decode(OpusDecoderSafeHandle st, byte* data, int len, short* pcm, int frame_size, int decode_fec); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_decode_float(OpusDecoderSafeHandle st, byte* data, int len, float* pcm, int frame_size, int decode_fec); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_decoder_ctl(OpusDecoderSafeHandle st, int request, void* data); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern void opus_decoder_destroy(IntPtr st); + + //Dred Decoder + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_dred_decoder_get_size(); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern OpusDREDDecoderSafeHandle opus_dred_decoder_create(int* error); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_dred_decoder_init(OpusDREDDecoderSafeHandle dec); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern void opus_dred_decoder_destroy(IntPtr dec); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_dred_decoder_ctl(OpusDREDDecoderSafeHandle dred_dec, int request, void* data); + + //Dred Packet? + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_dred_get_size(); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern OpusDREDSafeHandle opus_dred_alloc(int* error); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern void opus_dred_free(IntPtr dec); //I'M JUST FOLLOWING THE DOCS! + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_dred_parse(OpusDREDDecoderSafeHandle dred_dec, OpusDREDSafeHandle dred, byte* data, int len, int max_dred_samples, int sampling_rate, int* dred_end, int defer_processing); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_dred_process(OpusDREDDecoderSafeHandle dred_dec, OpusDREDSafeHandle src, OpusDREDSafeHandle dst); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_decoder_dred_decode(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, int* pcm, int frame_size); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_decoder_dred_decode_float(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, float* pcm, int frame_size); + + //Opus Packet Parsers + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_packet_parse(byte* data, int len, byte* out_toc, byte* frames, short* size, int* payload_offset); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_packet_get_bandwidth(byte* data); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_packet_get_samples_per_frame(byte* data, int Fs); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_packet_get_nb_channels(byte* data); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_packet_get_nb_frames(byte* packet, int len); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_packet_get_nb_samples(byte* packet, int len, int Fs); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_packet_has_lbrr(byte* packet, int len); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_packet_get_nb_samples(OpusDecoderSafeHandle dec, byte* packet, int len); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern void opus_pcm_soft_clip(float* pcm, int frame_size, int channels, float* softclip_mem); + + //Repacketizer + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_repacketizer_get_size(); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern OpusRepacketizerSafeHandle opus_repacketizer_init(OpusRepacketizerSafeHandle rp); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern OpusRepacketizerSafeHandle opus_repacketizer_create(); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern void opus_repacketizer_destroy(IntPtr rp); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_repacketizer_cat(OpusRepacketizerSafeHandle rp, byte* data, int len); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_repacketizer_out_range(OpusRepacketizerSafeHandle rp, int begin, int end, byte* data, int maxlen); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_repacketizer_get_nb_frames(OpusRepacketizerSafeHandle rp); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_repacketizer_out(OpusRepacketizerSafeHandle rp, byte* data, int maxlen); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_packet_pad(byte* data, int len, int new_len); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_packet_unpad(byte* data, int len); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_packet_pad(byte* data, int len, int new_len, int nb_streams); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_packet_unpad(byte* data, int len, int nb_streams); + + //Multistream Encoder + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_multistream_encoder_get_size(int streams, int coupled_streams); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_multistream_surround_encoder_get_size(int channels, int mapping_family); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern OpusMSEncoderSafeHandle opus_multistream_encoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, int application, int* error); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern OpusMSEncoderSafeHandle opus_multistream_surround_encoder_create(int Fs, int channels, int mapping_family, int* streams, int* coupled_streams, byte* mapping, int application, int* error); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_encoder_init(OpusMSEncoderSafeHandle st, int Fs, int channels, int streams, int coupled_streams, byte* mapping, int application); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_surround_encoder_init(OpusMSEncoderSafeHandle st, int Fs, int channels, int mapping_family, int* streams, int* coupled_streams, byte* mapping, int application); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_encode(OpusMSEncoderSafeHandle st, byte* pcm, int frame_size, byte* data, int max_data_bytes); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_encode_float(OpusMSEncoderSafeHandle st, float* pcm, int frame_size, byte* data, int max_data_bytes); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern void opus_multistream_encoder_destroy(IntPtr st); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_encoder_ctl(OpusMSEncoderSafeHandle st, int request, void* data); + + //Multistream Decoder + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern int opus_multistream_decoder_get_size(int streams, int coupled_streams); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern OpusMSDecoderSafeHandle opus_multistream_decoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, int* error); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_decoder_init(OpusMSDecoderSafeHandle st, int Fs, int channels, int streams, int coupled_streams, byte* mapping); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_decode(OpusMSDecoderSafeHandle st, byte* data, int len, short* pcm, int frame_size, int decode_fec); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_decode_float(OpusMSDecoderSafeHandle st, byte* data, int len, float* pcm, int frame_size, int decode_fec); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int opus_multistream_decoder_ctl(OpusMSDecoderSafeHandle st, int request, void* data); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static extern void opus_multistream_decoder_destroy(IntPtr st); + + //Library Information + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern byte* opus_strerror(int error); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern byte* opus_get_version_string(); + } +} \ No newline at end of file diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDDecoderSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDDecoderSafeHandle.cs new file mode 100644 index 0000000000..661b5bf2ed --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDDecoderSafeHandle.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace Discord.Audio.Opus.SafeHandlers +{ + public class OpusDREDDecoderSafeHandle : SafeHandle + { + public OpusDREDDecoderSafeHandle() : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() + { + NativeOpus.opus_dred_decoder_destroy(handle); + return true; + } + } +} diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDSafeHandle.cs new file mode 100644 index 0000000000..8acd03fb35 --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDSafeHandle.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace Discord.Audio.Opus.SafeHandlers +{ + public class OpusDREDSafeHandle : SafeHandle + { + public OpusDREDSafeHandle() : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() + { + NativeOpus.opus_dred_free(handle); + return true; + } + } +} diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDecoderSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDecoderSafeHandle.cs new file mode 100644 index 0000000000..965575fb38 --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDecoderSafeHandle.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace Discord.Audio.Opus.SafeHandlers +{ + public class OpusDecoderSafeHandle : SafeHandle + { + public OpusDecoderSafeHandle() : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() + { + NativeOpus.opus_decoder_destroy(handle); + return true; + } + } +} diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusEncoderSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusEncoderSafeHandle.cs new file mode 100644 index 0000000000..3093449c9e --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusEncoderSafeHandle.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace Discord.Audio.Opus.SafeHandlers +{ + public class OpusEncoderSafeHandle : SafeHandle + { + public OpusEncoderSafeHandle(): base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() + { + NativeOpus.opus_encoder_destroy(handle); + return true; + } + } +} diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSDecoderSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSDecoderSafeHandle.cs new file mode 100644 index 0000000000..782b9c5b11 --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSDecoderSafeHandle.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace Discord.Audio.Opus.SafeHandlers +{ + public class OpusMSDecoderSafeHandle : SafeHandle + { + public OpusMSDecoderSafeHandle() : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() + { + NativeOpus.opus_multistream_decoder_destroy(handle); + return true; + } + } +} diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSEncoderSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSEncoderSafeHandle.cs new file mode 100644 index 0000000000..5172cae1fc --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSEncoderSafeHandle.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace Discord.Audio.Opus.SafeHandlers +{ + public class OpusMSEncoderSafeHandle : SafeHandle + { + public OpusMSEncoderSafeHandle() : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() + { + NativeOpus.opus_multistream_encoder_destroy(handle); + return true; + } + } +} diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusRepacketizerSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusRepacketizerSafeHandle.cs new file mode 100644 index 0000000000..0afb911d34 --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusRepacketizerSafeHandle.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace Discord.Audio.Opus.SafeHandlers +{ + public class OpusRepacketizerSafeHandle : SafeHandle + { + public OpusRepacketizerSafeHandle() : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() + { + NativeOpus.opus_repacketizer_destroy(handle); + return true; + } + } +} From 5354e854c90976d2402921408462022327e21466 Mon Sep 17 00:00:00 2001 From: SineVector241 <69619913+SineVector241@users.noreply.github.com> Date: Fri, 8 Nov 2024 18:54:22 +1100 Subject: [PATCH 2/4] Add opusInfo. Converted all DllImport Attributes to use LibraryImport attribute instead for AOT compatibility. Needed to also convert net6.0 to net7.0 to support LibraryImport attribute. --- Discord.Net.sln | 8 +- .../Discord.Net.V4.Audio.csproj | 2 +- src/Discord.Net.V4.Audio/Opus/NativeOpus.cs | 266 +++++++++--------- src/Discord.Net.V4.Audio/Opus/OpusInfo.cs | 31 ++ 4 files changed, 169 insertions(+), 138 deletions(-) create mode 100644 src/Discord.Net.V4.Audio/Opus/OpusInfo.cs diff --git a/Discord.Net.sln b/Discord.Net.sln index b514c20cd1..60ed017c89 100644 --- a/Discord.Net.sln +++ b/Discord.Net.sln @@ -16,15 +16,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.V4.Rest", "src\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.V4.Core", "src\Discord.Net.V4.Core\Discord.Net.V4.Core.csproj", "{3277421C-AD38-43A7-89EB-D4E1F866004E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.V4.Audio", "src\Discord.Net.V4.Audio\Discord.Net.V4.Audio.csproj", "{EE97E2F3-8A85-46D4-A5D6-EE985047F9F6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.V4.Audio", "src\Discord.Net.V4.Audio\Discord.Net.V4.Audio.csproj", "{EE97E2F3-8A85-46D4-A5D6-EE985047F9F6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Models", "src\Discord.Net.Models\Discord.Net.Models.csproj", "{2EC5A01A-91CB-4E3F-AFBD-7DDAEC61FF15}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Models", "src\Discord.Net.Models\Discord.Net.Models.csproj", "{2EC5A01A-91CB-4E3F-AFBD-7DDAEC61FF15}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SourceGenerators", "SourceGenerators", "{C1C763AF-3DC5-4F7D-8551-0A65B6011305}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Hanz", "sourcegen\Discord.Net.Hanz\Discord.Net.Hanz.csproj", "{595DFC73-902A-4A2B-BE33-16B627134451}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Hanz", "sourcegen\Discord.Net.Hanz\Discord.Net.Hanz.csproj", "{595DFC73-902A-4A2B-BE33-16B627134451}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FeatureSamples", "samples\FeatureSamples\FeatureSamples.csproj", "{2A082FC0-B17A-4109-9B73-2B2F721F49E8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FeatureSamples", "samples\FeatureSamples\FeatureSamples.csproj", "{2A082FC0-B17A-4109-9B73-2B2F721F49E8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj b/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj index b81be1d983..7a1284c5c4 100644 --- a/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj +++ b/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj @@ -1,7 +1,7 @@ - net6.0;net8.0 + net7.0;net8.0 enable 12.0 enable diff --git a/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs b/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs index 47a0b463ae..13f8a33ff4 100644 --- a/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs +++ b/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs @@ -5,7 +5,7 @@ namespace Discord.Audio.Opus /// /// Native opus handler that directly calls the exported opus functions. /// - internal static class NativeOpus + internal static partial class NativeOpus { #if ANDROID private const string DllName = "libopus.so"; @@ -20,210 +20,210 @@ internal static class NativeOpus #endif //Encoder - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_encoder_get_size(int channels); + [LibraryImport(DllName)] + public static partial int opus_encoder_get_size(int channels); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern OpusEncoderSafeHandle opus_encoder_create(int Fs, int application, int* error); + [LibraryImport(DllName)] + public static unsafe partial OpusEncoderSafeHandle opus_encoder_create(int Fs, int application, int* error); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_encoder_init(OpusEncoderSafeHandle st, int Fs, int channels, int application); + [LibraryImport(DllName)] + public static partial int opus_encoder_init(OpusEncoderSafeHandle st, int Fs, int channels, int application); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_encode(OpusEncoderSafeHandle st, short* pcm, int frame_size, byte* data, int max_data_bytes); + [LibraryImport(DllName)] + public static unsafe partial int opus_encode(OpusEncoderSafeHandle st, short* pcm, int frame_size, byte* data, int max_data_bytes); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_encode_float(OpusEncoderSafeHandle st, float* pcm, int frame_size, byte* data, int max_data_bytes); + [LibraryImport(DllName)] + public static unsafe partial int opus_encode_float(OpusEncoderSafeHandle st, float* pcm, int frame_size, byte* data, int max_data_bytes); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern void opus_encoder_destroy(IntPtr st); + [LibraryImport(DllName)] + public static partial void opus_encoder_destroy(IntPtr st); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_encoder_ctl(OpusEncoderSafeHandle st, int request, void* data); + [LibraryImport(DllName)] + public static unsafe partial int opus_encoder_ctl(OpusEncoderSafeHandle st, int request, void* data); //Decoder - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_decoder_get_size(int channels); + [LibraryImport(DllName)] + public static partial int opus_decoder_get_size(int channels); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern OpusDecoderSafeHandle opus_decoder_create(int Fs, int channels, int* error); + [LibraryImport(DllName)] + public static unsafe partial OpusDecoderSafeHandle opus_decoder_create(int Fs, int channels, int* error); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_decoder_init(OpusDecoderSafeHandle st, int Fs, int channels); + [LibraryImport(DllName)] + public static partial int opus_decoder_init(OpusDecoderSafeHandle st, int Fs, int channels); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_decode(OpusDecoderSafeHandle st, byte* data, int len, short* pcm, int frame_size, int decode_fec); + [LibraryImport(DllName)] + public static unsafe partial int opus_decode(OpusDecoderSafeHandle st, byte* data, int len, short* pcm, int frame_size, int decode_fec); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_decode_float(OpusDecoderSafeHandle st, byte* data, int len, float* pcm, int frame_size, int decode_fec); + [LibraryImport(DllName)] + public static unsafe partial int opus_decode_float(OpusDecoderSafeHandle st, byte* data, int len, float* pcm, int frame_size, int decode_fec); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_decoder_ctl(OpusDecoderSafeHandle st, int request, void* data); + [LibraryImport(DllName)] + public static unsafe partial int opus_decoder_ctl(OpusDecoderSafeHandle st, int request, void* data); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern void opus_decoder_destroy(IntPtr st); + [LibraryImport(DllName)] + public static partial void opus_decoder_destroy(IntPtr st); //Dred Decoder - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_dred_decoder_get_size(); + [LibraryImport(DllName)] + public static partial int opus_dred_decoder_get_size(); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern OpusDREDDecoderSafeHandle opus_dred_decoder_create(int* error); + [LibraryImport(DllName)] + public static unsafe partial OpusDREDDecoderSafeHandle opus_dred_decoder_create(int* error); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_dred_decoder_init(OpusDREDDecoderSafeHandle dec); + [LibraryImport(DllName)] + public static partial int opus_dred_decoder_init(OpusDREDDecoderSafeHandle dec); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern void opus_dred_decoder_destroy(IntPtr dec); + [LibraryImport(DllName)] + public static partial void opus_dred_decoder_destroy(IntPtr dec); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_dred_decoder_ctl(OpusDREDDecoderSafeHandle dred_dec, int request, void* data); + [LibraryImport(DllName)] + public static unsafe partial int opus_dred_decoder_ctl(OpusDREDDecoderSafeHandle dred_dec, int request, void* data); //Dred Packet? - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_dred_get_size(); + [LibraryImport(DllName)] + public static partial int opus_dred_get_size(); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern OpusDREDSafeHandle opus_dred_alloc(int* error); + [LibraryImport(DllName)] + public static unsafe partial OpusDREDSafeHandle opus_dred_alloc(int* error); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern void opus_dred_free(IntPtr dec); //I'M JUST FOLLOWING THE DOCS! + [LibraryImport(DllName)] + public static partial void opus_dred_free(IntPtr dec); //I'M JUST FOLLOWING THE DOCS! - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_dred_parse(OpusDREDDecoderSafeHandle dred_dec, OpusDREDSafeHandle dred, byte* data, int len, int max_dred_samples, int sampling_rate, int* dred_end, int defer_processing); + [LibraryImport(DllName)] + public static unsafe partial int opus_dred_parse(OpusDREDDecoderSafeHandle dred_dec, OpusDREDSafeHandle dred, byte* data, int len, int max_dred_samples, int sampling_rate, int* dred_end, int defer_processing); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_dred_process(OpusDREDDecoderSafeHandle dred_dec, OpusDREDSafeHandle src, OpusDREDSafeHandle dst); + [LibraryImport(DllName)] + public static partial int opus_dred_process(OpusDREDDecoderSafeHandle dred_dec, OpusDREDSafeHandle src, OpusDREDSafeHandle dst); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_decoder_dred_decode(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, int* pcm, int frame_size); + [LibraryImport(DllName)] + public static unsafe partial int opus_decoder_dred_decode(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, int* pcm, int frame_size); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_decoder_dred_decode_float(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, float* pcm, int frame_size); + [LibraryImport(DllName)] + public static unsafe partial int opus_decoder_dred_decode_float(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, float* pcm, int frame_size); //Opus Packet Parsers - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_packet_parse(byte* data, int len, byte* out_toc, byte* frames, short* size, int* payload_offset); + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_parse(byte* data, int len, byte* out_toc, byte* frames, short* size, int* payload_offset); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_packet_get_bandwidth(byte* data); + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_get_bandwidth(byte* data); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_packet_get_samples_per_frame(byte* data, int Fs); + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_get_samples_per_frame(byte* data, int Fs); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_packet_get_nb_channels(byte* data); + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_get_nb_channels(byte* data); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_packet_get_nb_frames(byte* packet, int len); + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_get_nb_frames(byte* packet, int len); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_packet_get_nb_samples(byte* packet, int len, int Fs); + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_get_nb_samples(byte* packet, int len, int Fs); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_packet_has_lbrr(byte* packet, int len); + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_has_lbrr(byte* packet, int len); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_packet_get_nb_samples(OpusDecoderSafeHandle dec, byte* packet, int len); + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_get_nb_samples(OpusDecoderSafeHandle dec, byte* packet, int len); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern void opus_pcm_soft_clip(float* pcm, int frame_size, int channels, float* softclip_mem); + [LibraryImport(DllName)] + public static unsafe partial void opus_pcm_soft_clip(float* pcm, int frame_size, int channels, float* softclip_mem); //Repacketizer - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_repacketizer_get_size(); + [LibraryImport(DllName)] + public static partial int opus_repacketizer_get_size(); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern OpusRepacketizerSafeHandle opus_repacketizer_init(OpusRepacketizerSafeHandle rp); + [LibraryImport(DllName)] + public static partial OpusRepacketizerSafeHandle opus_repacketizer_init(OpusRepacketizerSafeHandle rp); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern OpusRepacketizerSafeHandle opus_repacketizer_create(); + [LibraryImport(DllName)] + public static partial OpusRepacketizerSafeHandle opus_repacketizer_create(); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern void opus_repacketizer_destroy(IntPtr rp); + [LibraryImport(DllName)] + public static partial void opus_repacketizer_destroy(IntPtr rp); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_repacketizer_cat(OpusRepacketizerSafeHandle rp, byte* data, int len); + [LibraryImport(DllName)] + public static unsafe partial int opus_repacketizer_cat(OpusRepacketizerSafeHandle rp, byte* data, int len); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_repacketizer_out_range(OpusRepacketizerSafeHandle rp, int begin, int end, byte* data, int maxlen); + [LibraryImport(DllName)] + public static unsafe partial int opus_repacketizer_out_range(OpusRepacketizerSafeHandle rp, int begin, int end, byte* data, int maxlen); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_repacketizer_get_nb_frames(OpusRepacketizerSafeHandle rp); + [LibraryImport(DllName)] + public static partial int opus_repacketizer_get_nb_frames(OpusRepacketizerSafeHandle rp); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_repacketizer_out(OpusRepacketizerSafeHandle rp, byte* data, int maxlen); + [LibraryImport(DllName)] + public static unsafe partial int opus_repacketizer_out(OpusRepacketizerSafeHandle rp, byte* data, int maxlen); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_packet_pad(byte* data, int len, int new_len); + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_pad(byte* data, int len, int new_len); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_packet_unpad(byte* data, int len); + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_unpad(byte* data, int len); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_packet_pad(byte* data, int len, int new_len, int nb_streams); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_packet_pad(byte* data, int len, int new_len, int nb_streams); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_packet_unpad(byte* data, int len, int nb_streams); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_packet_unpad(byte* data, int len, int nb_streams); //Multistream Encoder - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_multistream_encoder_get_size(int streams, int coupled_streams); + [LibraryImport(DllName)] + public static partial int opus_multistream_encoder_get_size(int streams, int coupled_streams); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_multistream_surround_encoder_get_size(int channels, int mapping_family); + [LibraryImport(DllName)] + public static partial int opus_multistream_surround_encoder_get_size(int channels, int mapping_family); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern OpusMSEncoderSafeHandle opus_multistream_encoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, int application, int* error); + [LibraryImport(DllName)] + public static unsafe partial OpusMSEncoderSafeHandle opus_multistream_encoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, int application, int* error); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern OpusMSEncoderSafeHandle opus_multistream_surround_encoder_create(int Fs, int channels, int mapping_family, int* streams, int* coupled_streams, byte* mapping, int application, int* error); + [LibraryImport(DllName)] + public static unsafe partial OpusMSEncoderSafeHandle opus_multistream_surround_encoder_create(int Fs, int channels, int mapping_family, int* streams, int* coupled_streams, byte* mapping, int application, int* error); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_encoder_init(OpusMSEncoderSafeHandle st, int Fs, int channels, int streams, int coupled_streams, byte* mapping, int application); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_encoder_init(OpusMSEncoderSafeHandle st, int Fs, int channels, int streams, int coupled_streams, byte* mapping, int application); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_surround_encoder_init(OpusMSEncoderSafeHandle st, int Fs, int channels, int mapping_family, int* streams, int* coupled_streams, byte* mapping, int application); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_surround_encoder_init(OpusMSEncoderSafeHandle st, int Fs, int channels, int mapping_family, int* streams, int* coupled_streams, byte* mapping, int application); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_encode(OpusMSEncoderSafeHandle st, byte* pcm, int frame_size, byte* data, int max_data_bytes); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_encode(OpusMSEncoderSafeHandle st, byte* pcm, int frame_size, byte* data, int max_data_bytes); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_encode_float(OpusMSEncoderSafeHandle st, float* pcm, int frame_size, byte* data, int max_data_bytes); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_encode_float(OpusMSEncoderSafeHandle st, float* pcm, int frame_size, byte* data, int max_data_bytes); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern void opus_multistream_encoder_destroy(IntPtr st); + [LibraryImport(DllName)] + public static partial void opus_multistream_encoder_destroy(IntPtr st); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_encoder_ctl(OpusMSEncoderSafeHandle st, int request, void* data); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_encoder_ctl(OpusMSEncoderSafeHandle st, int request, void* data); //Multistream Decoder - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern int opus_multistream_decoder_get_size(int streams, int coupled_streams); + [LibraryImport(DllName)] + public static partial int opus_multistream_decoder_get_size(int streams, int coupled_streams); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern OpusMSDecoderSafeHandle opus_multistream_decoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, int* error); + [LibraryImport(DllName)] + public static unsafe partial OpusMSDecoderSafeHandle opus_multistream_decoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, int* error); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_decoder_init(OpusMSDecoderSafeHandle st, int Fs, int channels, int streams, int coupled_streams, byte* mapping); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_decoder_init(OpusMSDecoderSafeHandle st, int Fs, int channels, int streams, int coupled_streams, byte* mapping); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_decode(OpusMSDecoderSafeHandle st, byte* data, int len, short* pcm, int frame_size, int decode_fec); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_decode(OpusMSDecoderSafeHandle st, byte* data, int len, short* pcm, int frame_size, int decode_fec); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_decode_float(OpusMSDecoderSafeHandle st, byte* data, int len, float* pcm, int frame_size, int decode_fec); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_decode_float(OpusMSDecoderSafeHandle st, byte* data, int len, float* pcm, int frame_size, int decode_fec); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern int opus_multistream_decoder_ctl(OpusMSDecoderSafeHandle st, int request, void* data); + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_decoder_ctl(OpusMSDecoderSafeHandle st, int request, void* data); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static extern void opus_multistream_decoder_destroy(IntPtr st); + [LibraryImport(DllName)] + public static partial void opus_multistream_decoder_destroy(IntPtr st); //Library Information - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern byte* opus_strerror(int error); + [LibraryImport(DllName)] + public static unsafe partial byte* opus_strerror(int error); - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - public static unsafe extern byte* opus_get_version_string(); + [LibraryImport(DllName)] + public static unsafe partial byte* opus_get_version_string(); } } \ No newline at end of file diff --git a/src/Discord.Net.V4.Audio/Opus/OpusInfo.cs b/src/Discord.Net.V4.Audio/Opus/OpusInfo.cs new file mode 100644 index 0000000000..9f7cdae6d2 --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/OpusInfo.cs @@ -0,0 +1,31 @@ +using System.Runtime.InteropServices; + +namespace Discord.Audio.Opus +{ + /// + /// Provides information about the opus DLL. + /// + public class OpusInfo + { + /// + /// Gets the libopus version string. + /// + /// Version string. + public static unsafe string Version() + { + byte* version = NativeOpus.opus_get_version_string(); + return Marshal.PtrToStringAnsi((IntPtr)version) ?? ""; + } + + /// + /// Converts an opus error code into a human readable string. + /// + /// Error number. + /// Error string. + public static unsafe string StringError(int error) + { + byte* stringError = NativeOpus.opus_strerror(error); + return Marshal.PtrToStringAnsi((IntPtr)stringError) ?? ""; + } + } +} From c6c18dbd30effb71ab2d35569688625886341814 Mon Sep 17 00:00:00 2001 From: SineVector241 <69619913+SineVector241@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:44:27 +1100 Subject: [PATCH 3/4] Update and fixes with documentation. --- .../Discord.Net.V4.Audio.csproj | 5 - src/Discord.Net.V4.Audio/Opus/NativeOpus.cs | 531 +++++++++++++++++- .../SafeHandlers/OpusDREDDecoderSafeHandle.cs | 10 +- .../Opus/SafeHandlers/OpusDREDSafeHandle.cs | 10 +- .../SafeHandlers/OpusDecoderSafeHandle.cs | 12 +- .../SafeHandlers/OpusEncoderSafeHandle.cs | 10 +- .../SafeHandlers/OpusMSDecoderSafeHandle.cs | 10 +- .../SafeHandlers/OpusMSEncoderSafeHandle.cs | 10 +- .../OpusRepacketizerSafeHandle.cs | 10 +- 9 files changed, 573 insertions(+), 35 deletions(-) diff --git a/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj b/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj index 7a1284c5c4..0562934006 100644 --- a/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj +++ b/src/Discord.Net.V4.Audio/Discord.Net.V4.Audio.csproj @@ -11,11 +11,6 @@ true - - - - - diff --git a/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs b/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs index 13f8a33ff4..f17b23dfd2 100644 --- a/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs +++ b/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs @@ -7,223 +7,710 @@ namespace Discord.Audio.Opus /// internal static partial class NativeOpus { -#if ANDROID - private const string DllName = "libopus.so"; -#elif LINUX - private const string DllName = "libopus.so.0.10.1"; -#elif WINDOWS - private const string DllName = "opus.dll"; -#elif MACOS || IOS || MACCATALYST +#if MACOS || IOS || MACCATALYST private const string DllName = "__Internal__"; #else private const string DllName = "opus"; #endif //Encoder + /// + /// Gets the size of an structure. + /// + /// Number of channels. This must be 1 or 2. + /// The size in bytes. [LibraryImport(DllName)] public static partial int opus_encoder_get_size(int channels); - [LibraryImport(DllName)] - public static unsafe partial OpusEncoderSafeHandle opus_encoder_create(int Fs, int application, int* error); - + /// + /// Allocates and initializes an encoder state. + /// + /// Sampling rate of input signal (Hz) This must be one of 8000, 12000, 16000, 24000, or 48000. + /// Number of channels (1 or 2) in input signal. + /// Coding mode (one of , or ) + /// Success or . + /// + [LibraryImport(DllName)] + public static unsafe partial OpusEncoderSafeHandle opus_encoder_create(int Fs, int channels, int application, int* error); + + /// + /// Initializes a previously allocated state. The memory pointed to by st must be at least the size returned by . + /// + /// Encoder state. + /// Sampling rate of input signal (Hz) This must be one of 8000, 12000, 16000, 24000, or 48000. + /// Number of channels (1 or 2) in input signal. + /// >Coding mode (one of , or ) + /// [LibraryImport(DllName)] public static partial int opus_encoder_init(OpusEncoderSafeHandle st, int Fs, int channels, int application); + /// + /// Encodes an Opus frame. + /// + /// Encoder state. + /// Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(short) + /// Number of samples per channel in the input signal. This must be an Opus frame size for the encoder's sampling rate. For example, at 48 kHz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10 ms (480 samples at 48 kHz) will prevent the encoder from using the LPC or hybrid modes. + /// Output payload. This must contain storage for at least max_data_bytes. + /// Size of the allocated memory for the output payload. This may be used to impose an upper limit on the instant bitrate, but should not be used as the only bitrate control. Use to control the bitrate. + /// The length of the encoded packet (in bytes) on success or a negative error code (see ) on failure. [LibraryImport(DllName)] public static unsafe partial int opus_encode(OpusEncoderSafeHandle st, short* pcm, int frame_size, byte* data, int max_data_bytes); + /// + /// Encodes an Opus frame from floating point input. + /// + /// Encoder state. + /// Input in float format (interleaved if 2 channels), with a normal range of +/-1.0. Samples with a range beyond +/-1.0 are supported but will be clipped by decoders using the integer API and should only be used if it is known that the far end supports extended dynamic range. length is frame_size*channels*sizeof(float) + /// Number of samples per channel in the input signal. This must be an Opus frame size for the encoder's sampling rate. For example, at 48 kHz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10 ms (480 samples at 48 kHz) will prevent the encoder from using the LPC or hybrid modes. + /// Output payload. This must contain storage for at least max_data_bytes. + /// Size of the allocated memory for the output payload. This may be used to impose an upper limit on the instant bitrate, but should not be used as the only bitrate control. Use to control the bitrate. + /// The length of the encoded packet (in bytes) on success or a negative error code (see ) on failure. [LibraryImport(DllName)] public static unsafe partial int opus_encode_float(OpusEncoderSafeHandle st, float* pcm, int frame_size, byte* data, int max_data_bytes); + /// + /// Frees an allocated by . + /// + /// State to be freed. [LibraryImport(DllName)] public static partial void opus_encoder_destroy(IntPtr st); + /// + /// Perform a CTL function on an . + /// + /// Encoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in or . + /// The data to input/output. + /// [LibraryImport(DllName)] public static unsafe partial int opus_encoder_ctl(OpusEncoderSafeHandle st, int request, void* data); + /// + /// Perform a CTL function on an Opus encoder. + /// + /// Encoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in or . + /// The data to input/output. + /// The second data to input/output. + /// + [LibraryImport(DllName)] + public static unsafe partial int opus_encoder_ctl(OpusEncoderSafeHandle st, int request, void* data, void* data2); + //Decoder + /// + /// Gets the size of an structure. + /// + /// Number of channels. This must be 1 or 2. + /// The size in bytes. [LibraryImport(DllName)] public static partial int opus_decoder_get_size(int channels); + /// + /// Allocates and initializes a state. + /// + /// Sample rate to decode at (Hz). This must be one of 8000, 12000, 16000, 24000, or 48000. + /// Number of channels (1 or 2) to decode. + /// Success or . + /// [LibraryImport(DllName)] public static unsafe partial OpusDecoderSafeHandle opus_decoder_create(int Fs, int channels, int* error); + /// + /// Initializes a previously allocated state. + /// + /// Decoder state. + /// Sampling rate to decode to (Hz). This must be one of 8000, 12000, 16000, 24000, or 48000. + /// Number of channels (1 or 2) to decode. + /// Success or . [LibraryImport(DllName)] public static partial int opus_decoder_init(OpusDecoderSafeHandle st, int Fs, int channels); + /// + /// Decode an Opus packet. + /// + /// Decoder state. + /// Input payload. Use a NULL pointer to indicate packet loss. + /// Number of bytes in payload. + /// Output signal (interleaved if 2 channels). length is frame_size*channels*sizeof(short). + /// Number of samples per channel of available space in pcm. If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), then frame_size needs to be exactly the duration of audio that is missing, otherwise the decoder will not be in the optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size must be a multiple of 2.5 ms. + /// Flag (0 or 1) to request that any in-band forward error correction data be decoded. If no such data is available, the frame is decoded as if it were lost. + /// Number of decoded samples or . [LibraryImport(DllName)] public static unsafe partial int opus_decode(OpusDecoderSafeHandle st, byte* data, int len, short* pcm, int frame_size, int decode_fec); + /// + /// Decode an Opus packet with floating point output. + /// + /// Decoder state. + /// Input payload. Use a NULL pointer to indicate packet loss. + /// Number of bytes in payload. + /// Output signal (interleaved if 2 channels). length is frame_size*channels*sizeof(float). + /// Number of samples per channel of available space in pcm. If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), then frame_size needs to be exactly the duration of audio that is missing, otherwise the decoder will not be in the optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size must be a multiple of 2.5 ms. + /// Flag (0 or 1) to request that any in-band forward error correction data be decoded. If no such data is available the frame is decoded as if it were lost. + /// Number of decoded samples or [LibraryImport(DllName)] public static unsafe partial int opus_decode_float(OpusDecoderSafeHandle st, byte* data, int len, float* pcm, int frame_size, int decode_fec); + /// + /// Perform a CTL function on an . + /// + /// Decoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in or . + /// The data to input or output. + /// [LibraryImport(DllName)] public static unsafe partial int opus_decoder_ctl(OpusDecoderSafeHandle st, int request, void* data); + /// + /// Frees an allocated by . + /// + /// State to be freed. [LibraryImport(DllName)] public static partial void opus_decoder_destroy(IntPtr st); //Dred Decoder + /// + /// Gets the size of an structure. + /// + /// The size in bytes. [LibraryImport(DllName)] public static partial int opus_dred_decoder_get_size(); + /// + /// Allocates and initializes an state. + /// + /// Success or . + /// [LibraryImport(DllName)] public static unsafe partial OpusDREDDecoderSafeHandle opus_dred_decoder_create(int* error); + /// + /// Initializes an state. + /// + /// State to be initialized. + /// [LibraryImport(DllName)] public static partial int opus_dred_decoder_init(OpusDREDDecoderSafeHandle dec); + /// + /// Frees an allocated by . + /// + /// State to be freed. [LibraryImport(DllName)] public static partial void opus_dred_decoder_destroy(IntPtr dec); + /// + /// Perform a CTL function on an . + /// + /// DRED Decoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in or . + /// The data to input or output. + /// [LibraryImport(DllName)] public static unsafe partial int opus_dred_decoder_ctl(OpusDREDDecoderSafeHandle dred_dec, int request, void* data); //Dred Packet? + /// + /// Gets the size of an structure. + /// + /// The size in bytes. [LibraryImport(DllName)] public static partial int opus_dred_get_size(); + /// + /// Allocates and initializes a state. + /// + /// Success or . + /// [LibraryImport(DllName)] public static unsafe partial OpusDREDSafeHandle opus_dred_alloc(int* error); + /// + /// Frees an allocated by . + /// + /// State to be freed. [LibraryImport(DllName)] public static partial void opus_dred_free(IntPtr dec); //I'M JUST FOLLOWING THE DOCS! + /// + /// Decode an Opus DRED packet. + /// + /// DRED Decoder state. + /// DRED state. + /// Input payload. + /// Number of bytes in payload. + /// Maximum number of DRED samples that may be needed (if available in the packet). + /// Sampling rate used for max_dred_samples argument. Needs not match the actual sampling rate of the decoder. + /// Number of non-encoded (silence) samples between the DRED timestamp and the last DRED sample. + /// Flag (0 or 1). If set to one, the CPU-intensive part of the DRED decoding is deferred until is called. + /// Offset (positive) of the first decoded DRED samples, zero if no DRED is present, or [LibraryImport(DllName)] public static unsafe partial int opus_dred_parse(OpusDREDDecoderSafeHandle dred_dec, OpusDREDSafeHandle dred, byte* data, int len, int max_dred_samples, int sampling_rate, int* dred_end, int defer_processing); + /// + /// Finish decoding an packet. + /// + /// DRED Decoder state. + /// Source DRED state to start the processing from. + /// Destination DRED state to store the updated state after processing. + /// [LibraryImport(DllName)] public static partial int opus_dred_process(OpusDREDDecoderSafeHandle dred_dec, OpusDREDSafeHandle src, OpusDREDSafeHandle dst); - [LibraryImport(DllName)] - public static unsafe partial int opus_decoder_dred_decode(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, int* pcm, int frame_size); - + /// + /// Decode audio from an packet with floating point output. + /// + /// Decoder state. + /// DRED state. + /// position of the redundancy to decode (in samples before the beginning of the real audio data in the packet). + /// Output signal (interleaved if 2 channels). length is frame_size*channels*sizeof(short) + /// Number of samples per channel to decode in pcm. frame_size must be a multiple of 2.5 ms. + /// Number of decoded samples or . + [LibraryImport(DllName)] + public static unsafe partial int opus_decoder_dred_decode(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, short* pcm, int frame_size); + + /// + /// Decode audio from an packet with floating point output. + /// + /// Decoder state. + /// DRED state. + /// position of the redundancy to decode (in samples before the beginning of the real audio data in the packet). + /// Output signal (interleaved if 2 channels). length is frame_size*channels*sizeof(float). + /// Number of samples per channel to decode in pcm. frame_size must be a multiple of 2.5 ms. + /// Number of decoded samples or . [LibraryImport(DllName)] public static unsafe partial int opus_decoder_dred_decode_float(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, float* pcm, int frame_size); //Opus Packet Parsers - [LibraryImport(DllName)] - public static unsafe partial int opus_packet_parse(byte* data, int len, byte* out_toc, byte* frames, short* size, int* payload_offset); - + /// + /// Parse an opus packet into one or more frames. + /// + /// Opus packet to be parsed. + /// size of data. + /// TOC pointer. + /// encapsulated frames. + /// sizes of the encapsulated frames. + /// returns the position of the payload within the packet (in bytes). + /// number of frames. + [LibraryImport(DllName)] + public static unsafe partial int opus_packet_parse(byte* data, int len, byte* out_toc, byte*[] frames, short[] size, int* payload_offset); + + /// + /// Gets the bandwidth of an Opus packet. + /// + /// Opus packet. + /// or [LibraryImport(DllName)] public static unsafe partial int opus_packet_get_bandwidth(byte* data); + /// + /// Gets the number of samples per frame from an Opus packet. + /// + /// Opus packet. This must contain at least one byte of data. + /// Sampling rate in Hz. This must be a multiple of 400, or inaccurate results will be returned. + /// Number of samples per frame. [LibraryImport(DllName)] public static unsafe partial int opus_packet_get_samples_per_frame(byte* data, int Fs); + /// + /// Gets the number of channels from an Opus packet. + /// + /// Opus packet. + /// Number of channels or . [LibraryImport(DllName)] public static unsafe partial int opus_packet_get_nb_channels(byte* data); + /// + /// Gets the number of frames in an Opus packet. + /// + /// Opus packet. + /// Length of packet. + /// Number of frames or . [LibraryImport(DllName)] public static unsafe partial int opus_packet_get_nb_frames(byte* packet, int len); + /// + /// Gets the number of samples of an Opus packet. + /// + /// Opus packet. + /// Length of packet. + /// Sampling rate in Hz. This must be a multiple of 400, or inaccurate results will be returned. + /// Number of samples or . [LibraryImport(DllName)] public static unsafe partial int opus_packet_get_nb_samples(byte* packet, int len, int Fs); + /// + /// Checks whether an Opus packet has LBRR. + /// + /// Opus packet. + /// Length of packet. + /// 1 is LBRR is present, 0 otherwise or [LibraryImport(DllName)] public static unsafe partial int opus_packet_has_lbrr(byte* packet, int len); + /// + /// Gets the number of samples of an Opus packet. + /// + /// Decoder state. + /// Opus packet. + /// Length of packet. + /// Number of samples or . [LibraryImport(DllName)] - public static unsafe partial int opus_packet_get_nb_samples(OpusDecoderSafeHandle dec, byte* packet, int len); + public static unsafe partial int opus_decoder_get_nb_samples(OpusDecoderSafeHandle dec, byte* packet, int len); + /// + /// Applies soft-clipping to bring a float signal within the [-1,1] range. + /// + /// Input PCM and modified PCM. + /// Number of samples per channel to process. + /// Number of channels. + /// State memory for the soft clipping process (one float per channel, initialized to zero). [LibraryImport(DllName)] public static unsafe partial void opus_pcm_soft_clip(float* pcm, int frame_size, int channels, float* softclip_mem); //Repacketizer + /// + /// Gets the size of an structure. + /// + /// The size in bytes. [LibraryImport(DllName)] public static partial int opus_repacketizer_get_size(); + /// + /// (Re)initializes a previously allocated state. + /// + /// The state to (re)initialize. + /// [LibraryImport(DllName)] public static partial OpusRepacketizerSafeHandle opus_repacketizer_init(OpusRepacketizerSafeHandle rp); + /// + /// Allocates memory and initializes the new with . + /// + /// [LibraryImport(DllName)] public static partial OpusRepacketizerSafeHandle opus_repacketizer_create(); + /// + /// Frees an allocated by . + /// + /// State to be freed. [LibraryImport(DllName)] public static partial void opus_repacketizer_destroy(IntPtr rp); + /// + /// Add a packet to the current state. + /// + /// The repacketizer state to which to add the packet. + /// The packet data. The application must ensure this pointer remains valid until the next call to or . + /// The number of bytes in the packet data. + /// [LibraryImport(DllName)] public static unsafe partial int opus_repacketizer_cat(OpusRepacketizerSafeHandle rp, byte* data, int len); + /// + /// Construct a new packet from data previously submitted to the state via . + /// + /// The repacketizer state from which to construct the new packet. + /// The index of the first frame in the current repacketizer state to include in the output. + /// One past the index of the last frame in the current repacketizer state to include in the output. + /// The buffer in which to store the output packet. + /// The maximum number of bytes to store in the output buffer. In order to guarantee success, this should be at least 1276 for a single frame, or for multiple frames, 1277*(end-begin). However, 1*(end-begin) plus the size of all packet data submitted to the repacketizer since the last call to or is also sufficient, and possibly much smaller. + /// The total size of the output packet on success, or an on failure. [LibraryImport(DllName)] public static unsafe partial int opus_repacketizer_out_range(OpusRepacketizerSafeHandle rp, int begin, int end, byte* data, int maxlen); + /// + /// Return the total number of frames contained in packet data submitted to the state so far via since the last call to or . + /// + /// The repacketizer state containing the frames. + /// The total number of frames contained in the packet data submitted to the repacketizer state. [LibraryImport(DllName)] public static partial int opus_repacketizer_get_nb_frames(OpusRepacketizerSafeHandle rp); + /// + /// Construct a new packet from data previously submitted to the state via . + /// + /// The repacketizer state from which to construct the new packet. + /// The buffer in which to store the output packet. + /// The maximum number of bytes to store in the output buffer. In order to guarantee success, this should be at least 1277*opus_repacketizer_get_nb_frames(rp). However, 1*opus_repacketizer_get_nb_frames(rp) plus the size of all packet data submitted to the repacketizer since the last call to opus_repacketizer_init() or opus_repacketizer_create() is also sufficient, and possibly much smaller. + /// The total size of the output packet on success, or an on failure. [LibraryImport(DllName)] public static unsafe partial int opus_repacketizer_out(OpusRepacketizerSafeHandle rp, byte* data, int maxlen); + /// + /// Pads a given Opus packet to a larger size (possibly changing the TOC sequence). + /// + /// The buffer containing the packet to pad. + /// The size of the packet. This must be at least 1. + /// The desired size of the packet after padding. This must be at least as large as len. + /// [LibraryImport(DllName)] public static unsafe partial int opus_packet_pad(byte* data, int len, int new_len); + /// + /// Remove all padding from a given Opus packet and rewrite the TOC sequence to minimize space usage. + /// + /// The buffer containing the packet to strip. + /// The size of the packet. This must be at least 1. + /// The new size of the output packet on success, or an on failure. [LibraryImport(DllName)] public static unsafe partial int opus_packet_unpad(byte* data, int len); + /// + /// Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence). + /// + /// The buffer containing the packet to pad. + /// The size of the packet. This must be at least 1. + /// The desired size of the packet after padding. This must be at least 1. + /// The number of streams (not channels) in the packet. This must be at least as large as len. + /// [LibraryImport(DllName)] public static unsafe partial int opus_multistream_packet_pad(byte* data, int len, int new_len, int nb_streams); + /// + /// Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to minimize space usage. + /// + /// The buffer containing the packet to strip. + /// The size of the packet. This must be at least 1. + /// The number of streams (not channels) in the packet. This must be at least 1. + /// The new size of the output packet on success, or an on failure. [LibraryImport(DllName)] public static unsafe partial int opus_multistream_packet_unpad(byte* data, int len, int nb_streams); //Multistream Encoder + /// + /// Gets the size of an structure. + /// + /// The total number of streams to encode from the input. This must be no more than 255. + /// Number of coupled (2 channel) streams to encode. This must be no larger than the total number of streams. Additionally, The total number of encoded channels (streams + coupled_streams) must be no more than 255. + /// The size in bytes on success, or a negative error code (see ) on error. [LibraryImport(DllName)] public static partial int opus_multistream_encoder_get_size(int streams, int coupled_streams); + /// + /// N.A. + /// + /// + /// + /// [LibraryImport(DllName)] public static partial int opus_multistream_surround_encoder_get_size(int channels, int mapping_family); + /// + /// Allocates and initializes a state. + /// + /// Sampling rate of the input signal (in Hz). This must be one of 8000, 12000, 16000, 24000, or 48000. + /// Number of channels in the input signal. This must be at most 255. It may be greater than the number of coded channels (streams + coupled_streams). + /// The total number of streams to encode from the input. This must be no more than the number of channels. + /// Number of coupled (2 channel) streams to encode. This must be no larger than the total number of streams. Additionally, The total number of encoded channels (streams + coupled_streams) must be no more than the number of input channels. + /// Mapping from encoded channels to input channels, as described in Opus Multistream API. As an extra constraint, the multistream encoder does not allow encoding coupled streams for which one channel is unused since this is never a good idea. + /// The target encoder application. This must be one of the following: , or . + /// Returns on success, or an error code (see ) on failure. + /// [LibraryImport(DllName)] public static unsafe partial OpusMSEncoderSafeHandle opus_multistream_encoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, int application, int* error); + /// + /// N.A. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// [LibraryImport(DllName)] public static unsafe partial OpusMSEncoderSafeHandle opus_multistream_surround_encoder_create(int Fs, int channels, int mapping_family, int* streams, int* coupled_streams, byte* mapping, int application, int* error); + /// + /// Initialize a previously allocated state. + /// + /// Multistream encoder state to initialize. + /// Sampling rate of the input signal (in Hz). This must be one of 8000, 12000, 16000, 24000, or 48000. + /// Number of channels in the input signal. This must be at most 255. It may be greater than the number of coded channels (streams + coupled_streams). + /// The total number of streams to encode from the input. This must be no more than the number of channels. + /// Number of coupled (2 channel) streams to encode. This must be no larger than the total number of streams. Additionally, The total number of encoded channels (streams + coupled_streams) must be no more than the number of input channels. + /// Mapping from encoded channels to input channels, as described in Opus Multistream API. As an extra constraint, the multistream encoder does not allow encoding coupled streams for which one channel is unused since this is never a good idea. + /// The target encoder application. This must be one of the following: , or . + /// on success, or an error code (see ) on failure. [LibraryImport(DllName)] public static unsafe partial int opus_multistream_encoder_init(OpusMSEncoderSafeHandle st, int Fs, int channels, int streams, int coupled_streams, byte* mapping, int application); + /// + /// N.A. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// [LibraryImport(DllName)] public static unsafe partial int opus_multistream_surround_encoder_init(OpusMSEncoderSafeHandle st, int Fs, int channels, int mapping_family, int* streams, int* coupled_streams, byte* mapping, int application); - [LibraryImport(DllName)] - public static unsafe partial int opus_multistream_encode(OpusMSEncoderSafeHandle st, byte* pcm, int frame_size, byte* data, int max_data_bytes); - + /// + /// Encodes a multistream Opus frame. + /// + /// Multistream encoder state. + /// The input signal as interleaved samples. This must contain frame_size*channels samples. + /// Number of samples per channel in the input signal. This must be an Opus frame size for the encoder's sampling rate. For example, at 48 kHz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10 ms (480 samples at 48 kHz) will prevent the encoder from using the LPC or hybrid modes. + /// Output payload. This must contain storage for at least max_data_bytes. + /// Size of the allocated memory for the output payload. This may be used to impose an upper limit on the instant bitrate, but should not be used as the only bitrate control. Use to control the bitrate. + /// The length of the encoded packet (in bytes) on success or a negative error code (see ) on failure. + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_encode(OpusMSEncoderSafeHandle st, short* pcm, int frame_size, byte* data, int max_data_bytes); + + /// + /// Encodes a multistream Opus frame from floating point input. + /// + /// Multistream encoder state. + /// The input signal as interleaved samples with a normal range of +/-1.0. Samples with a range beyond +/-1.0 are supported but will be clipped by decoders using the integer API and should only be used if it is known that the far end supports extended dynamic range. This must contain frame_size*channels samples. + /// Number of samples per channel in the input signal. This must be an Opus frame size for the encoder's sampling rate. For example, at 48 kHz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10 ms (480 samples at 48 kHz) will prevent the encoder from using the LPC or hybrid modes. + /// Output payload. This must contain storage for at least max_data_bytes. + /// Size of the allocated memory for the output payload. This may be used to impose an upper limit on the instant bitrate, but should not be used as the only bitrate control. Use to control the bitrate. + /// The length of the encoded packet (in bytes) on success or a negative error code (see ) on failure. [LibraryImport(DllName)] public static unsafe partial int opus_multistream_encode_float(OpusMSEncoderSafeHandle st, float* pcm, int frame_size, byte* data, int max_data_bytes); + /// + /// Frees an allocated by . + /// + /// Multistream encoder state to be freed. [LibraryImport(DllName)] public static partial void opus_multistream_encoder_destroy(IntPtr st); + /// + /// Perform a CTL function on a . + /// + /// Multistream encoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in , , or specific encoder and decoder CTLs. + /// The input/output data. + /// [LibraryImport(DllName)] public static unsafe partial int opus_multistream_encoder_ctl(OpusMSEncoderSafeHandle st, int request, void* data); + /// + /// Perform a CTL function on a . + /// + /// Multistream encoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in , , or specific encoder and decoder CTLs. + /// The input/output data. + /// The input/output data. + /// + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_encoder_ctl(OpusMSEncoderSafeHandle st, int request, void* data, void* data2); + //Multistream Decoder + /// + /// Gets the size of an structure. + /// + /// The total number of streams coded in the input. This must be no more than 255. + /// Number streams to decode as coupled (2 channel) streams. This must be no larger than the total number of streams. Additionally, The total number of coded channels (streams + coupled_streams) must be no more than 255. + /// The size in bytes on success, or a negative error code (see ) on error. [LibraryImport(DllName)] public static partial int opus_multistream_decoder_get_size(int streams, int coupled_streams); + /// + /// Allocates and initializes a state. + /// + /// Sampling rate to decode at (in Hz). This must be one of 8000, 12000, 16000, 24000, or 48000. + /// Number of channels to output. This must be at most 255. It may be different from the number of coded channels (streams + coupled_streams). + /// The total number of streams coded in the input. This must be no more than 255. + /// Number of streams to decode as coupled (2 channel) streams. This must be no larger than the total number of streams. Additionally, The total number of coded channels (streams + coupled_streams) must be no more than 255. + /// Mapping from coded channels to output channels, as described in Opus Multistream API. + /// Returns on success, or an error code (see ) on failure. + /// [LibraryImport(DllName)] public static unsafe partial OpusMSDecoderSafeHandle opus_multistream_decoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, int* error); + /// + /// Intialize a previously allocated state object. + /// + /// Multistream encoder state to initialize. + /// Sampling rate to decode at (in Hz). This must be one of 8000, 12000, 16000, 24000, or 48000. + /// Number of channels to output. This must be at most 255. It may be different from the number of coded channels (streams + coupled_streams). + /// The total number of streams coded in the input. This must be no more than 255. + /// Number of streams to decode as coupled (2 channel) streams. This must be no larger than the total number of streams. Additionally, The total number of coded channels (streams + coupled_streams) must be no more than 255. + /// Mapping from coded channels to output channels, as described in Opus Multistream API. + /// on success, or an error code (see ) on failure. [LibraryImport(DllName)] public static unsafe partial int opus_multistream_decoder_init(OpusMSDecoderSafeHandle st, int Fs, int channels, int streams, int coupled_streams, byte* mapping); + /// + /// Decode a multistream Opus packet. + /// + /// Multistream decoder state. + /// Input payload. Use a NULL pointer to indicate packet loss. + /// Number of bytes in payload. + /// Output signal, with interleaved samples. This must contain room for frame_size*channels samples. + /// The number of samples per channel of available space in pcm. If this is less than the maximum packet duration (120 ms; 5760 for 48kHz), this function will not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), then frame_size needs to be exactly the duration of audio that is missing, otherwise the decoder will not be in the optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size must be a multiple of 2.5 ms. + /// Flag (0 or 1) to request that any in-band forward error correction data be decoded. If no such data is available, the frame is decoded as if it were lost. + /// Number of samples decoded on success or a negative error code (see ) on failure. [LibraryImport(DllName)] public static unsafe partial int opus_multistream_decode(OpusMSDecoderSafeHandle st, byte* data, int len, short* pcm, int frame_size, int decode_fec); + /// + /// Decode a multistream Opus packet with floating point output. + /// + /// Multistream decoder state. + /// Input payload. Use a NULL pointer to indicate packet loss. + /// Number of bytes in payload. + /// Output signal, with interleaved samples. This must contain room for frame_size*channels samples. + /// The number of samples per channel of available space in pcm. If this is less than the maximum packet duration (120 ms; 5760 for 48kHz), this function will not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), then frame_size needs to be exactly the duration of audio that is missing, otherwise the decoder will not be in the optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size must be a multiple of 2.5 ms. + /// Flag (0 or 1) to request that any in-band forward error correction data be decoded. If no such data is available, the frame is decoded as if it were lost. + /// Number of samples decoded on success or a negative error code (see ) on failure. [LibraryImport(DllName)] public static unsafe partial int opus_multistream_decode_float(OpusMSDecoderSafeHandle st, byte* data, int len, float* pcm, int frame_size, int decode_fec); + /// + /// Perform a CTL function on a . + /// + /// Multistream decoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in , , or specific encoder and decoder CTLs. + /// The input/output data. + /// [LibraryImport(DllName)] public static unsafe partial int opus_multistream_decoder_ctl(OpusMSDecoderSafeHandle st, int request, void* data); + /// + /// Perform a CTL function on a . + /// + /// Multistream decoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in , , or specific encoder and decoder CTLs. + /// The input/output data. + /// The input/output data. + /// + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_decoder_ctl(OpusMSDecoderSafeHandle st, int request, void* data, void* data2); + + /// + /// Frees an allocated by . + /// + /// Multistream decoder state to be freed. [LibraryImport(DllName)] public static partial void opus_multistream_decoder_destroy(IntPtr st); //Library Information + /// + /// Gets the libopus version string. + /// + /// Version string [LibraryImport(DllName)] - public static unsafe partial byte* opus_strerror(int error); + public static unsafe partial byte* opus_get_version_string(); + /// + /// Converts an opus error code into a human readable string. + /// + /// Error number. + /// Error string. [LibraryImport(DllName)] - public static unsafe partial byte* opus_get_version_string(); + public static unsafe partial byte* opus_strerror(int error); } } \ No newline at end of file diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDDecoderSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDDecoderSafeHandle.cs index 661b5bf2ed..651b2fadf1 100644 --- a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDDecoderSafeHandle.cs +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDDecoderSafeHandle.cs @@ -2,14 +2,22 @@ namespace Discord.Audio.Opus.SafeHandlers { - public class OpusDREDDecoderSafeHandle : SafeHandle + /// + /// Managed wrapper over the OpusDREDDecoder state. + /// + internal class OpusDREDDecoderSafeHandle : SafeHandle { + /// + /// Creates a new . + /// public OpusDREDDecoderSafeHandle() : base(IntPtr.Zero, true) { } + /// public override bool IsInvalid => handle == IntPtr.Zero; + /// protected override bool ReleaseHandle() { NativeOpus.opus_dred_decoder_destroy(handle); diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDSafeHandle.cs index 8acd03fb35..55ffeba8b6 100644 --- a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDSafeHandle.cs +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDREDSafeHandle.cs @@ -2,14 +2,22 @@ namespace Discord.Audio.Opus.SafeHandlers { - public class OpusDREDSafeHandle : SafeHandle + /// + /// Managed wrapper over the OpusDRED state. + /// + internal class OpusDREDSafeHandle : SafeHandle { + /// + /// Creates a new . + /// public OpusDREDSafeHandle() : base(IntPtr.Zero, true) { } + /// public override bool IsInvalid => handle == IntPtr.Zero; + /// protected override bool ReleaseHandle() { NativeOpus.opus_dred_free(handle); diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDecoderSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDecoderSafeHandle.cs index 965575fb38..805b8cbe79 100644 --- a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDecoderSafeHandle.cs +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusDecoderSafeHandle.cs @@ -2,14 +2,22 @@ namespace Discord.Audio.Opus.SafeHandlers { - public class OpusDecoderSafeHandle : SafeHandle + /// + /// Managed wrapper over the OpusDecoder state. + /// + internal class OpusDecoderSafeHandle : SafeHandle { + /// + /// Create a new . + /// public OpusDecoderSafeHandle() : base(IntPtr.Zero, true) { } - + + /// public override bool IsInvalid => handle == IntPtr.Zero; + /// protected override bool ReleaseHandle() { NativeOpus.opus_decoder_destroy(handle); diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusEncoderSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusEncoderSafeHandle.cs index 3093449c9e..1aeef3e2b6 100644 --- a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusEncoderSafeHandle.cs +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusEncoderSafeHandle.cs @@ -2,14 +2,22 @@ namespace Discord.Audio.Opus.SafeHandlers { - public class OpusEncoderSafeHandle : SafeHandle + /// + /// Managed wrapper over the OpusEncoder state. + /// + internal class OpusEncoderSafeHandle : SafeHandle { + /// + /// Creates a new . + /// public OpusEncoderSafeHandle(): base(IntPtr.Zero, true) { } + /// public override bool IsInvalid => handle == IntPtr.Zero; + /// protected override bool ReleaseHandle() { NativeOpus.opus_encoder_destroy(handle); diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSDecoderSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSDecoderSafeHandle.cs index 782b9c5b11..09bbb287a0 100644 --- a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSDecoderSafeHandle.cs +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSDecoderSafeHandle.cs @@ -2,14 +2,22 @@ namespace Discord.Audio.Opus.SafeHandlers { - public class OpusMSDecoderSafeHandle : SafeHandle + /// + /// Managed wrapper over the OpusMultistreamDecoder state. + /// + internal class OpusMSDecoderSafeHandle : SafeHandle { + /// + /// Creates a new . + /// public OpusMSDecoderSafeHandle() : base(IntPtr.Zero, true) { } + /// public override bool IsInvalid => handle == IntPtr.Zero; + /// protected override bool ReleaseHandle() { NativeOpus.opus_multistream_decoder_destroy(handle); diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSEncoderSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSEncoderSafeHandle.cs index 5172cae1fc..5d422328c3 100644 --- a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSEncoderSafeHandle.cs +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusMSEncoderSafeHandle.cs @@ -2,14 +2,22 @@ namespace Discord.Audio.Opus.SafeHandlers { - public class OpusMSEncoderSafeHandle : SafeHandle + /// + /// Managed wrapper over the OpusMultistreamEncoder state. + /// + internal class OpusMSEncoderSafeHandle : SafeHandle { + /// + /// Creates a new . + /// public OpusMSEncoderSafeHandle() : base(IntPtr.Zero, true) { } + /// public override bool IsInvalid => handle == IntPtr.Zero; + /// protected override bool ReleaseHandle() { NativeOpus.opus_multistream_encoder_destroy(handle); diff --git a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusRepacketizerSafeHandle.cs b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusRepacketizerSafeHandle.cs index 0afb911d34..aa790e09bd 100644 --- a/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusRepacketizerSafeHandle.cs +++ b/src/Discord.Net.V4.Audio/Opus/SafeHandlers/OpusRepacketizerSafeHandle.cs @@ -2,14 +2,22 @@ namespace Discord.Audio.Opus.SafeHandlers { - public class OpusRepacketizerSafeHandle : SafeHandle + /// + /// Managed wrapper over the OpusRepacketizer state. + /// + internal class OpusRepacketizerSafeHandle : SafeHandle { + /// + /// Creates a new . + /// public OpusRepacketizerSafeHandle() : base(IntPtr.Zero, true) { } + /// public override bool IsInvalid => handle == IntPtr.Zero; + /// protected override bool ReleaseHandle() { NativeOpus.opus_repacketizer_destroy(handle); From a53a4732664d8ba12f46e426bdebe4417f082ba5 Mon Sep 17 00:00:00 2001 From: SineVector241 <69619913+SineVector241@users.noreply.github.com> Date: Sun, 10 Nov 2024 21:45:28 +1100 Subject: [PATCH 4/4] Add encoder, decoder and enums/CTL's. --- src/Discord.Net.V4.Audio/Opus/Enums.cs | 418 ++++++++++++++++++ src/Discord.Net.V4.Audio/Opus/NativeOpus.cs | 45 ++ src/Discord.Net.V4.Audio/Opus/OpusDecoder.cs | 225 ++++++++++ src/Discord.Net.V4.Audio/Opus/OpusEncoder.cs | 254 +++++++++++ .../Opus/OpusException.cs | 26 ++ 5 files changed, 968 insertions(+) create mode 100644 src/Discord.Net.V4.Audio/Opus/Enums.cs create mode 100644 src/Discord.Net.V4.Audio/Opus/OpusDecoder.cs create mode 100644 src/Discord.Net.V4.Audio/Opus/OpusEncoder.cs create mode 100644 src/Discord.Net.V4.Audio/Opus/OpusException.cs diff --git a/src/Discord.Net.V4.Audio/Opus/Enums.cs b/src/Discord.Net.V4.Audio/Opus/Enums.cs new file mode 100644 index 0000000000..39cff6dab9 --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/Enums.cs @@ -0,0 +1,418 @@ +namespace Discord.Audio.Opus +{ + /// + /// Error codes for opus. + /// + public enum OpusErrorCodes + { + /// + /// No error. + /// + OPUS_OK = 0, + + /// + /// One or more invalid/out of range arguments. + /// + OPUS_BAD_ARG = -1, + + /// + /// Not enough bytes allocated in the buffer. + /// + OPUS_BUFFER_TOO_SMALL = -2, + + /// + /// An internal error was detected. + /// + OPUS_INTERNAL_ERROR = -3, + + /// + /// The compressed data passed is corrupted. + /// + OPUS_INVALID_PACKET = -4, + + /// + /// Invalid/unsupported request number. + /// + OPUS_UNIMPLEMENTED = -5, + + /// + /// An encoder or decoder structure is invalid or already freed. + /// + OPUS_INVALID_STATE = -6, + + /// + /// Memory allocation has failed. + /// + OPUS_ALLOC_FAIL = -7 + } + + /// + /// Pre-defined values for CTL interface. + /// + public enum OpusPredefinedValues + { + /// + /// Auto/default setting. + /// + OPUS_AUTO = -1000, + + /// + /// Maximum bitrate. + /// + OPUS_BITRATE_MAX = -1, + + /// + /// Best for most VoIP/Video Conference applications where listening quality and intelligibility matter most. + /// + OPUS_APPLICATION_VOIP = 2048, + + /// + /// Best for broadcast/high-fidelity application where the decoded audio should be as close as possible to the input. + /// + OPUS_APPLICATION_AUDIO = 2049, + + /// + /// Only use when lowest-achievable latency is what matters most. Voice-optimized modes cannot be used. + /// + OPUS_APPLICATION_RESTRICTED_LOWDELAY = 2051, + + /// + /// Signal being encoded is voice. + /// + OPUS_SIGNAL_VOICE = 3001, + + /// + /// Signal being encoded is music. + /// + OPUS_SIGNAL_MUSIC = 3002, + + /// + /// 4 kHz bandpass. + /// + OPUS_BANDWIDTH_NARROWBAND = 1101, + + /// + /// 6 kHz bandpass. + /// + OPUS_BANDWIDTH_MEDIUMBAND = 1102, + + /// + /// 8 kHz bandpass. + /// + OPUS_BANDWIDTH_WIDEBAND = 1103, + + /// + /// 12 kHz bandpass. + /// + OPUS_BANDWIDTH_SUPERWIDEBAND = 1104, + + /// + /// 20 kHz bandpass. + /// + OPUS_BANDWIDTH_FULLBAND = 1105, + + /// + /// Select frame size from the argument (default). + /// + OPUS_FRAMESIZE_ARG = 5000, + + /// + /// Use 2.5 ms frames. + /// + OPUS_FRAMESIZE_2_5_MS = 5001, + + /// + /// Use 5 ms frames. + /// + OPUS_FRAMESIZE_5_MS = 5002, + + /// + /// Use 10 ms frames. + /// + OPUS_FRAMESIZE_10_MS = 5003, + + /// + /// Use 20 ms frames. + /// + OPUS_FRAMESIZE_20_MS = 5004, + + /// + /// Use 40 ms frames. + /// + OPUS_FRAMESIZE_40_MS = 5005, + + /// + /// Use 60 ms frames. + /// + OPUS_FRAMESIZE_60_MS = 5006, + + /// + /// Use 80 ms frames. + /// + OPUS_FRAMESIZE_80_MS = 5007, + + /// + /// Use 100 ms frames. + /// + OPUS_FRAMESIZE_100_MS = 5008, + + /// + /// Use 120 ms frames. + /// + OPUS_FRAMESIZE_120_MS = 5009 + } + + /// + /// These macros are used with the opus_decoder_ctl and opus_encoder_ctl calls to generate a particular request. + /// + public enum GenericCTL + { + /// + /// Resets the codec state to be equivalent to a freshly initialized state. + /// + OPUS_RESET_STATE = 4028, + + /// + /// Gets the final state of the codec's entropy coder. + /// + OPUS_GET_FINAL_RANGE = 4031, + + /// + /// Gets the encoder's configured bandpass or the decoder's last bandpass. + /// + OPUS_GET_BANDWIDTH = 4009, + + /// + /// Gets the sampling rate the encoder or decoder was initialized with. + /// + OPUS_GET_SAMPLE_RATE = 4029, + + /// + /// If set to 1, disables the use of phase inversion for intensity stereo, improving the quality of mono down-mixes, but slightly reducing normal stereo quality. + /// + OPUS_SET_PHASE_INVERSION_DISABLED = 4046, + + /// + /// Gets the encoder's configured phase inversion status. + /// + OPUS_GET_PHASE_INVERSION_DISABLED = 4047, + } + + /// + /// These are convenience macros for use with the opus_encoder_ctl interface. + /// + public enum EncoderCTL + { + /// + /// Configures the encoder's intended application. + /// + OPUS_SET_APPLICATION = 4000, + + /// + /// Gets the encoder's configured application. + /// + OPUS_GET_APPLICATION = 4001, + + /// + /// Configures the bitrate in the encoder. + /// + OPUS_SET_BITRATE = 4002, + + /// + /// Gets the encoder's bitrate configuration. + /// + OPUS_GET_BITRATE = 4003, + + /// + /// Configures the maximum bandpass that the encoder will select automatically. + /// + OPUS_SET_MAX_BANDWIDTH = 4004, + + /// + /// Gets the encoder's configured maximum allowed bandpass. + /// + OPUS_GET_MAX_BANDWIDTH = 4005, + + /// + /// Enables or disables variable bitrate (VBR) in the encoder. + /// + OPUS_SET_VBR = 4006, + + /// + /// Determine if variable bitrate (VBR) is enabled in the encoder. + /// + OPUS_GET_VBR = 4007, + + /// + /// Sets the encoder's bandpass to a specific value. + /// + OPUS_SET_BANDWIDTH = 4008, + + /// + /// Configures the encoder's computational complexity. + /// + OPUS_SET_COMPLEXITY = 4010, + + /// + /// Gets the encoder's complexity configuration. + /// + OPUS_GET_COMPLEXITY = 4011, + + /// + /// Configures the encoder's use of in-band forward error correction (FEC). + /// + OPUS_SET_INBAND_FEC = 4012, + + /// + /// Gets encoder's configured use of in-band forward error correction. + /// + OPUS_GET_INBAND_FEC = 4013, + + /// + /// Configures the encoder's expected packet loss percentage. + /// + OPUS_SET_PACKET_LOSS_PERC = 4014, + + /// + /// Gets the encoder's configured packet loss percentage. + /// + OPUS_GET_PACKET_LOSS_PERC = 4015, + + /// + /// Configures the encoder's use of discontinuous transmission (DTX). + /// + OPUS_SET_DTX = 4016, + + /// + /// Gets encoder's configured use of discontinuous transmission. + /// + OPUS_GET_DTX = 4017, + + /// + /// Enables or disables constrained VBR in the encoder. + /// + OPUS_SET_VBR_CONSTRAINT = 4020, + + /// + /// Determine if constrained VBR is enabled in the encoder. + /// + OPUS_GET_VBR_CONSTRAINT = 4021, + + /// + /// Configures mono/stereo forcing in the encoder. + /// + OPUS_SET_FORCE_CHANNELS = 4022, + + /// + /// Gets the encoder's forced channel configuration. + /// + OPUS_GET_FORCE_CHANNELS = 4023, + + /// + /// Configures the type of signal being encoded. + /// + OPUS_SET_SIGNAL = 4024, + + /// + /// Gets the encoder's configured signal type. + /// + OPUS_GET_SIGNAL = 4025, + + /// + /// Gets the total samples of delay added by the entire codec. + /// + OPUS_GET_LOOKAHEAD = 4027, + + /// + /// Configures the depth of signal being encoded. + /// + OPUS_SET_LSB_DEPTH = 4036, + + /// + /// Gets the encoder's configured signal depth. + /// + OPUS_GET_LSB_DEPTH = 4037, + + /// + /// Configures the encoder's use of variable duration frames. + /// + OPUS_SET_EXPERT_FRAME_DURATION = 4040, + + /// + /// Gets the encoder's configured use of variable duration frames. + /// + OPUS_GET_EXPERT_FRAME_DURATION = 4041, + + /// + /// If set to 1, disables almost all use of prediction, making frames almost completely independent. This reduces quality. + /// + OPUS_SET_PREDICTION_DISABLED = 4042, + + /// + /// Gets the encoder's configured prediction status. + /// + OPUS_GET_PREDICTION_DISABLED = 4043, + + /// + /// Gets the DTX state of the encoder. + /// + OPUS_GET_IN_DTX = 4049, //Encoder only, seems to be listed as generic in docs though. + + /// + /// If non-zero, enables Deep Redundancy (DRED) and use the specified maximum number of 10-ms redundant frames. + /// + OPUS_SET_DRED_DURATION = 4050, + + /// + /// Gets the encoder's configured Deep Redundancy (DRED) maximum number of frames. + /// + OPUS_GET_DRED_DURATION = 4051, + + /// + /// Provide external DNN weights from binary object (only when explicitly built without the weights). + /// + OPUS_SET_DNN_BLOB = 4052, + } + + /// + /// These are convenience macros for use with the opus_decoder_ctl interface + /// + public enum DecoderCTL + { + /// + /// Configures decoder gain adjustment. + /// + OPUS_SET_GAIN = 4034, + + /// + /// Gets the decoder's configured gain adjustment. + /// + OPUS_GET_GAIN = 4045,/* Should have been 4035 */ + + /// + /// Gets the duration (in samples) of the last packet successfully decoded or concealed. + /// + OPUS_GET_LAST_PACKET_DURATION = 4039, + + /// + /// Gets the pitch of the last decoded frame, if available. + /// + OPUS_GET_PITCH = 4033, + } + + /// + /// These are convenience macros that are specific to the opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl() interface. + /// + public enum MultistreamCTL + { + /// + /// Gets the encoder state for an individual stream of a multi-stream encoder. + /// + OPUS_MULTISTREAM_GET_ENCODER_STATE = 5120, + + /// + /// Gets the decoder state for an individual stream of a multi-stream decoder. + /// + OPUS_MULTISTREAM_GET_DECODER_STATE = 5122 + } +} diff --git a/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs b/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs index f17b23dfd2..af75e24bea 100644 --- a/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs +++ b/src/Discord.Net.V4.Audio/Opus/NativeOpus.cs @@ -75,6 +75,15 @@ internal static partial class NativeOpus [LibraryImport(DllName)] public static partial void opus_encoder_destroy(IntPtr st); + /// + /// Perform a CTL function on an . + /// + /// Encoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in or . + /// + [LibraryImport(DllName)] + public static unsafe partial int opus_encoder_ctl(OpusEncoderSafeHandle st, int request); //Apparently GenericCTL.OPUS_RESET_STATE exists. + /// /// Perform a CTL function on an . /// @@ -151,6 +160,15 @@ internal static partial class NativeOpus [LibraryImport(DllName)] public static unsafe partial int opus_decode_float(OpusDecoderSafeHandle st, byte* data, int len, float* pcm, int frame_size, int decode_fec); + /// + /// Perform a CTL function on an . + /// + /// Decoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in or . + /// + [LibraryImport(DllName)] + public static unsafe partial int opus_decoder_ctl(OpusDecoderSafeHandle st, int request); //Apparently GenericCTL.OPUS_RESET_STATE exists. + /// /// Perform a CTL function on an . /// @@ -199,6 +217,15 @@ internal static partial class NativeOpus [LibraryImport(DllName)] public static partial void opus_dred_decoder_destroy(IntPtr dec); + /// + /// Perform a CTL function on an . + /// + /// DRED Decoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in or . + /// + [LibraryImport(DllName)] + public static unsafe partial int opus_dred_decoder_ctl(OpusDREDDecoderSafeHandle dred_dec, int request); //Apparently GenericCTL.OPUS_RESET_STATE exists. + /// /// Perform a CTL function on an . /// @@ -586,6 +613,15 @@ internal static partial class NativeOpus [LibraryImport(DllName)] public static partial void opus_multistream_encoder_destroy(IntPtr st); + /// + /// Perform a CTL function on a . + /// + /// Multistream encoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in , , or specific encoder and decoder CTLs. + /// + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_encoder_ctl(OpusMSEncoderSafeHandle st, int request); //Apparently GenericCTL.OPUS_RESET_STATE exists. + /// /// Perform a CTL function on a . /// @@ -669,6 +705,15 @@ internal static partial class NativeOpus [LibraryImport(DllName)] public static unsafe partial int opus_multistream_decode_float(OpusMSDecoderSafeHandle st, byte* data, int len, float* pcm, int frame_size, int decode_fec); + /// + /// Perform a CTL function on a . + /// + /// Multistream decoder state. + /// This and all remaining parameters should be replaced by one of the convenience macros in , , or specific encoder and decoder CTLs. + /// + [LibraryImport(DllName)] + public static unsafe partial int opus_multistream_decoder_ctl(OpusMSDecoderSafeHandle st, int request); //Apparently GenericCTL.OPUS_RESET_STATE exists. + /// /// Perform a CTL function on a . /// diff --git a/src/Discord.Net.V4.Audio/Opus/OpusDecoder.cs b/src/Discord.Net.V4.Audio/Opus/OpusDecoder.cs new file mode 100644 index 0000000000..d945fa14ee --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/OpusDecoder.cs @@ -0,0 +1,225 @@ +using Discord.Audio.Opus.SafeHandlers; + +namespace Discord.Audio.Opus +{ + /// + /// An opus decoder. + /// + public class OpusDecoder : IDisposable + { + private OpusDecoderSafeHandle _handler; + private bool _disposed; + + /// + /// Creates a new opus decoder. + /// + /// The sample rate, this must be one of 8000, 12000, 16000, 24000, or 48000. + /// Number of channels, this must be 1 or 2. + /// + public unsafe OpusDecoder(int sample_rate, int channels) + { + int error = 0; + _handler = NativeOpus.opus_decoder_create(sample_rate, channels, &error); + CheckError(error); + } + + /// + /// Decodes an opus encoded frame. + /// + /// Input payload. Use null to indicate packet loss + /// Number of bytes in payload. + /// Output signal (interleaved if 2 channels). length is frame_size*channels. + /// Number of samples per channel of available space in pcm. If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=true), then frame_size needs to be exactly the duration of audio that is missing, otherwise the decoder will not be in the optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size must be a multiple of 2.5 ms. + /// Request that any in-band forward error correction data be decoded. If no such data is available, the frame is decoded as if it were lost. + /// Number of decoded samples or . + public unsafe int Decode(Span input, int length, Span output, int frame_size, bool decode_fec) + { + ThrowIfDisposed(); + + fixed (byte* inputPtr = input) + fixed (byte* outputPtr = output) + { + var result = NativeOpus.opus_decode(_handler, inputPtr, length, (short*)outputPtr, frame_size, decode_fec ? 1 : 0); + CheckError(result); + return result; + } + } + + /// + /// Decodes an opus encoded frame. + /// + /// Input payload. Use null to indicate packet loss + /// Number of bytes in payload. + /// Output signal (interleaved if 2 channels). length is frame_size*channels*sizeof(short) + /// Number of samples per channel of available space in pcm. If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=true), then frame_size needs to be exactly the duration of audio that is missing, otherwise the decoder will not be in the optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size must be a multiple of 2.5 ms. + /// Request that any in-band forward error correction data be decoded. If no such data is available, the frame is decoded as if it were lost. + /// Number of decoded samples or . + public unsafe int Decode(Span input, int length, Span output, int frame_size, bool decode_fec) + { + ThrowIfDisposed(); + + fixed (byte* inputPtr = input) + fixed (short* outputPtr = output) + { + var result = NativeOpus.opus_decode(_handler, inputPtr, length, outputPtr, frame_size, decode_fec ? 1 : 0); + CheckError(result); + return result; + } + } + + /// + /// Decodes an opus encoded frame. + /// + /// Input payload. Use null to indicate packet loss + /// Number of bytes in payload. + /// Output signal (interleaved if 2 channels). length is frame_size*channels*sizeof(float) + /// Number of samples per channel of available space in pcm. If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=true), then frame_size needs to be exactly the duration of audio that is missing, otherwise the decoder will not be in the optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size must be a multiple of 2.5 ms. + /// Request that any in-band forward error correction data be decoded. If no such data is available, the frame is decoded as if it were lost. + /// Number of decoded samples or . + public unsafe int Decode(Span input, int length, Span output, int frame_size, bool decode_fec) + { + ThrowIfDisposed(); + + fixed (byte* inputPtr = input) + fixed (float* outputPtr = output) + { + var result = NativeOpus.opus_decode_float(_handler, inputPtr, length, outputPtr, frame_size, decode_fec ? 1 : 0); + CheckError(result); + return result; + } + } + + /// + /// Decodes an opus encoded frame. + /// + /// Input payload. Use null to indicate packet loss + /// Number of bytes in payload. + /// Output signal (interleaved if 2 channels). length is frame_size*channels + /// Number of samples per channel of available space in pcm. If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=true), then frame_size needs to be exactly the duration of audio that is missing, otherwise the decoder will not be in the optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size must be a multiple of 2.5 ms. + /// Request that any in-band forward error correction data be decoded. If no such data is available, the frame is decoded as if it were lost. + /// Number of decoded samples or . + public unsafe int Decode(byte[]? input, int length, byte[] output, int frame_size, bool decode_fec) => Decode(input.AsSpan(), length, output.AsSpan(), frame_size, decode_fec); + + /// + /// Decodes an opus encoded frame. + /// + /// Input payload. Use null to indicate packet loss + /// Number of bytes in payload. + /// Output signal (interleaved if 2 channels). length is frame_size*channels*sizeof(short) + /// Number of samples per channel of available space in pcm. If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=true), then frame_size needs to be exactly the duration of audio that is missing, otherwise the decoder will not be in the optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size must be a multiple of 2.5 ms. + /// Request that any in-band forward error correction data be decoded. If no such data is available, the frame is decoded as if it were lost. + /// Number of decoded samples or . + public unsafe int Decode(byte[]? input, int length, short[] output, int frame_size, bool decode_fec) => Decode(input.AsSpan(), length, output.AsSpan(), frame_size, decode_fec); + + /// + /// Decodes an opus encoded frame. + /// + /// Input payload. Use null to indicate packet loss + /// Number of bytes in payload. + /// Output signal (interleaved if 2 channels). length is frame_size*channels*sizeof(float) + /// Number of samples per channel of available space in pcm. If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=true), then frame_size needs to be exactly the duration of audio that is missing, otherwise the decoder will not be in the optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size must be a multiple of 2.5 ms. + /// Request that any in-band forward error correction data be decoded. If no such data is available, the frame is decoded as if it were lost. + /// Number of decoded samples or . + public unsafe int Decode(byte[]? input, int length, float[] output, int frame_size, bool decode_fec) => Decode(input.AsSpan(), length, output.AsSpan(), frame_size, decode_fec); + + /// + /// Performs a ctl request. + /// + /// The type you want to input/output. + /// The request you want to specify. + /// The input/output value. + /// The result code of the request. See . + /// + /// + public unsafe int Ctl(DecoderCTL request, ref T value) where T : unmanaged + { + ThrowIfDisposed(); + fixed (void* valuePtr = &value) + { + var result = NativeOpus.opus_decoder_ctl(_handler, (int)request, valuePtr); + CheckError(result); + return result; + } + } + + /// + /// Performs a ctl request. + /// + /// The request you want to specify. + /// The result code of the request. See . + /// + /// + public unsafe int Ctl(GenericCTL request) + { + ThrowIfDisposed(); + var result = NativeOpus.opus_decoder_ctl(_handler, (int)request); + CheckError(result); + return result; + } + + /// + /// Performs a ctl request. + /// + /// The type you want to input/output. + /// The request you want to specify. + /// The input/output value. + /// The result code of the request. See . + /// + /// + public unsafe int Ctl(GenericCTL request, ref T value) where T : unmanaged + { + ThrowIfDisposed(); + fixed (void* valuePtr = &value) + { + var result = NativeOpus.opus_decoder_ctl(_handler, (int)request, valuePtr); + CheckError(result); + return result; + } + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Dispose logic. + /// + /// Set to true if fully disposing. + protected virtual void Dispose(bool disposing) + { + if (_disposed) return; + + if (disposing) + { + if (!_handler.IsClosed) + _handler.Close(); + } + + _disposed = true; + } + + /// + /// Throws an exception if this object is disposed or the handler is closed. + /// + /// + protected virtual void ThrowIfDisposed() + { + if (_disposed || _handler.IsClosed) + throw new ObjectDisposedException(GetType().FullName); + } + + /// + /// Checks if there is an opus error and throws if the error is a negative value. + /// + /// The error code to input. + /// + protected void CheckError(int error) + { + if (error < 0) + throw new OpusException(((OpusErrorCodes)error).ToString()); + } + } +} diff --git a/src/Discord.Net.V4.Audio/Opus/OpusEncoder.cs b/src/Discord.Net.V4.Audio/Opus/OpusEncoder.cs new file mode 100644 index 0000000000..bd9ed496ac --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/OpusEncoder.cs @@ -0,0 +1,254 @@ +using Discord.Audio.Opus.SafeHandlers; + +namespace Discord.Audio.Opus +{ + /// + /// An opus encoder. + /// + public class OpusEncoder : IDisposable + { + private OpusEncoderSafeHandle _handler; + private bool _disposed; + + /// + /// Creates a new opus encoder. + /// + /// The sample rate, this must be one of 8000, 12000, 16000, 24000, or 48000. + /// Number of channels, this must be 1 or 2. + /// Coding mode (one of , or + /// + public unsafe OpusEncoder(int sample_rate, int channels, OpusPredefinedValues application) + { + int error = 0; + _handler = NativeOpus.opus_encoder_create(sample_rate, channels, (int)application, &error); + CheckError(error); + } + + /// + /// Encodes a pcm frame. + /// + /// Input signal (interleaved if 2 channels). length is frame_size*channels. + /// The frame size of the pcm data. This must be an Opus frame size for the encoder's sampling rate. For example, at 48 kHz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10 ms (480 samples at 48 kHz) will prevent the encoder from using the LPC or hybrid modes. + /// Output payload. This must contain storage for at least max_data_bytes. + /// Size of the allocated memory for the output payload. This may be used to impose an upper limit on the instant bitrate, but should not be used as the only bitrate control. Use to control the bitrate. + /// The length of the encoded packet (in bytes). + /// + /// + public unsafe int Encode(Span input, int frame_size, Span output, int max_data_bytes) + { + ThrowIfDisposed(); + fixed (byte* inputPtr = input) + fixed (byte* outputPtr = output) + { + var result = NativeOpus.opus_encode(_handler, (short*)inputPtr, frame_size, outputPtr, max_data_bytes); + CheckError(result); + return result; + } + } + + /// + /// Encodes a pcm frame. + /// + /// Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(short). + /// The frame size of the pcm data. This must be an Opus frame size for the encoder's sampling rate. For example, at 48 kHz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10 ms (480 samples at 48 kHz) will prevent the encoder from using the LPC or hybrid modes. + /// Output payload. This must contain storage for at least max_data_bytes. + /// Size of the allocated memory for the output payload. This may be used to impose an upper limit on the instant bitrate, but should not be used as the only bitrate control. Use to control the bitrate. + /// The length of the encoded packet (in bytes). + /// + /// + public unsafe int Encode(Span input, int frame_size, Span output, int max_data_bytes) + { + ThrowIfDisposed(); + fixed (short* inputPtr = input) + fixed (byte* outputPtr = output) + { + var result = NativeOpus.opus_encode(_handler, inputPtr, frame_size, outputPtr, max_data_bytes); + CheckError(result); + return result; + } + } + + /// + /// Encodes a floating point pcm frame. + /// + /// Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(float). + /// The frame size of the pcm data. This must be an Opus frame size for the encoder's sampling rate. For example, at 48 kHz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10 ms (480 samples at 48 kHz) will prevent the encoder from using the LPC or hybrid modes. + /// Output payload. This must contain storage for at least max_data_bytes. + /// Size of the allocated memory for the output payload. This may be used to impose an upper limit on the instant bitrate, but should not be used as the only bitrate control. Use to control the bitrate. + /// The length of the encoded packet (in bytes). + /// + /// + public unsafe int Encode(Span input, int frame_size, Span output, int max_data_bytes) + { + ThrowIfDisposed(); + fixed (float* inputPtr = input) + fixed (byte* outputPtr = output) + { + var result = NativeOpus.opus_encode_float(_handler, inputPtr, frame_size, outputPtr, max_data_bytes); + CheckError(result); + return result; + } + } + + /// + /// Encodes a pcm frame. + /// + /// Input signal (interleaved if 2 channels). length is frame_size*channels. + /// The frame size of the pcm data. This must be an Opus frame size for the encoder's sampling rate. For example, at 48 kHz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10 ms (480 samples at 48 kHz) will prevent the encoder from using the LPC or hybrid modes. + /// Output payload. This must contain storage for at least max_data_bytes. + /// Size of the allocated memory for the output payload. This may be used to impose an upper limit on the instant bitrate, but should not be used as the only bitrate control. Use to control the bitrate. + /// The length of the encoded packet (in bytes). + /// + /// + public int Encode(byte[] input, int frame_size, byte[] output, int max_data_bytes) => Encode(input.AsSpan(), frame_size, output.AsSpan(), max_data_bytes); + + /// + /// Encodes a pcm frame. + /// + /// Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(short). + /// The frame size of the pcm data. This must be an Opus frame size for the encoder's sampling rate. For example, at 48 kHz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10 ms (480 samples at 48 kHz) will prevent the encoder from using the LPC or hybrid modes. + /// Output payload. This must contain storage for at least max_data_bytes. + /// Size of the allocated memory for the output payload. This may be used to impose an upper limit on the instant bitrate, but should not be used as the only bitrate control. Use to control the bitrate. + /// The length of the encoded packet (in bytes). + /// + /// + public int Encode(short[] input, int frame_size, byte[] output, int max_data_bytes) => Encode(input.AsSpan(), frame_size, output.AsSpan(), max_data_bytes); + + /// + /// Encodes a floating point pcm frame. + /// + /// Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(float). + /// The frame size of the pcm data. This must be an Opus frame size for the encoder's sampling rate. For example, at 48 kHz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10 ms (480 samples at 48 kHz) will prevent the encoder from using the LPC or hybrid modes. + /// Output payload. This must contain storage for at least max_data_bytes. + /// Size of the allocated memory for the output payload. This may be used to impose an upper limit on the instant bitrate, but should not be used as the only bitrate control. Use to control the bitrate. + /// The length of the encoded packet (in bytes). + /// + /// + public int Encode(float[] input, int frame_size, byte[] output, int max_data_bytes) => Encode(input.AsSpan(), frame_size, output.AsSpan(), max_data_bytes); + + /// + /// Performs a ctl request. + /// + /// The type you want to input/output. + /// The request you want to specify. + /// The input/output value. + /// The result code of the request. See . + /// + /// + public unsafe int Ctl(EncoderCTL request, ref T value) where T : unmanaged + { + ThrowIfDisposed(); + fixed (void* valuePtr = &value) + { + var result = NativeOpus.opus_encoder_ctl(_handler, (int)request, valuePtr); + CheckError(result); + return result; + } + } + + /// + /// Performs a ctl request. + /// + /// The type you want to input/output. + /// The second type you want to input/output. + /// The request you want to specify. + /// The input/output value. + /// The second input/output value. + /// The result code of the request. See . + /// + /// + public unsafe int Ctl(EncoderCTL request, ref T value, ref T2 value2) + where T : unmanaged + where T2 : unmanaged + { + ThrowIfDisposed(); + fixed (void* valuePtr = &value) + fixed (void* value2Ptr = &value2) + { + var result = NativeOpus.opus_encoder_ctl(_handler, (int)request, valuePtr, value2Ptr); + CheckError(result); + return result; + } + } + + /// + /// Performs a ctl request. + /// + /// The request you want to specify. + /// The result code of the request. See . + /// + /// + public unsafe int Ctl(GenericCTL request) + { + ThrowIfDisposed(); + var result = NativeOpus.opus_encoder_ctl(_handler, (int)request); + CheckError(result); + return result; + } + + /// + /// Performs a ctl request. + /// + /// The type you want to input/output. + /// The request you want to specify. + /// The input/output value. + /// The result code of the request. See . + /// + /// + public unsafe int Ctl(GenericCTL request, ref T value) where T : unmanaged + { + ThrowIfDisposed(); + fixed (void* valuePtr = &value) + { + var result = NativeOpus.opus_encoder_ctl(_handler, (int)request, valuePtr); + CheckError(result); + return result; + } + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Dispose logic. + /// + /// Set to true if fully disposing. + protected virtual void Dispose(bool disposing) + { + if (_disposed) return; + + if (disposing) + { + if (!_handler.IsClosed) + _handler.Close(); + } + + _disposed = true; + } + + /// + /// Throws an exception if this object is disposed or the handler is closed. + /// + /// + protected virtual void ThrowIfDisposed() + { + if (_disposed || _handler.IsClosed) + throw new ObjectDisposedException(GetType().FullName); + } + + /// + /// Checks if there is an opus error and throws if the error is a negative value. + /// + /// The error code to input. + /// + protected void CheckError(int error) + { + if (error < 0) + throw new OpusException(((OpusErrorCodes)error).ToString()); + } + } +} diff --git a/src/Discord.Net.V4.Audio/Opus/OpusException.cs b/src/Discord.Net.V4.Audio/Opus/OpusException.cs new file mode 100644 index 0000000000..cd5c09e1c2 --- /dev/null +++ b/src/Discord.Net.V4.Audio/Opus/OpusException.cs @@ -0,0 +1,26 @@ +namespace Discord.Audio.Opus +{ + /// + /// An opus exception. + /// + public class OpusException : Exception + { + /// + /// Constructs an opus exception. + /// + public OpusException() { } + + /// + /// Constructs an opus exception. + /// + /// The message of the exception. + public OpusException(string message) : base(message) { } + + /// + /// Constructs an opus exception. + /// + /// The message of the exception. + /// The root exception. + public OpusException(string message, Exception innerException) : base(message, innerException) { } + } +}