├── OpusDotNet
├── NuGet
│ ├── opus
│ │ ├── win-x64
│ │ │ ├── opus.dll
│ │ │ ├── OpusDotNet.opus.win-x64.props
│ │ │ ├── OpusDotNet.opus.win-x64.nuspec
│ │ │ └── LICENSE.txt
│ │ └── win-x86
│ │ │ ├── opus.dll
│ │ │ ├── OpusDotNet.opus.win-x86.props
│ │ │ ├── OpusDotNet.opus.win-x86.nuspec
│ │ │ └── LICENSE.txt
│ ├── OpusDotNet.targets
│ └── OpusDotNet.nuspec
├── OpusDotNet.csproj
├── ForceChannels.cs
├── SafeDecoderHandle.cs
├── SafeEncoderHandle.cs
├── Control.cs
├── Application.cs
├── Bandwidth.cs
├── OpusError.cs
├── OpusException.cs
├── API.cs
├── OpusDecoder.cs
└── OpusEncoder.cs
├── LICENSE.md
├── OpusDotNet.sln
├── README.md
├── .gitattributes
└── .gitignore
/OpusDotNet/NuGet/opus/win-x64/opus.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrphil2105/OpusDotNet/HEAD/OpusDotNet/NuGet/opus/win-x64/opus.dll
--------------------------------------------------------------------------------
/OpusDotNet/NuGet/opus/win-x86/opus.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrphil2105/OpusDotNet/HEAD/OpusDotNet/NuGet/opus/win-x86/opus.dll
--------------------------------------------------------------------------------
/OpusDotNet/OpusDotNet.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | true
6 | true
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/OpusDotNet/NuGet/opus/win-x64/OpusDotNet.opus.win-x64.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/OpusDotNet/NuGet/opus/win-x86/OpusDotNet.opus.win-x86.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/OpusDotNet/ForceChannels.cs:
--------------------------------------------------------------------------------
1 | namespace OpusDotNet
2 | {
3 | ///
4 | /// Specifies the modes for forced mono/stereo.
5 | ///
6 | public enum ForceChannels
7 | {
8 | ///
9 | /// Not forced.
10 | ///
11 | None = -1000,
12 | ///
13 | /// Forced mono.
14 | ///
15 | Mono = 1,
16 | ///
17 | /// Forced stereo.
18 | ///
19 | Stereo = 2
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/OpusDotNet/SafeDecoderHandle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Runtime.ConstrainedExecution;
4 |
5 | namespace OpusDotNet
6 | {
7 | internal sealed class SafeDecoderHandle : SafeHandle
8 | {
9 | private SafeDecoderHandle() : base(IntPtr.Zero, true)
10 | {
11 | }
12 |
13 | public override bool IsInvalid => handle == IntPtr.Zero;
14 |
15 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
16 | protected override bool ReleaseHandle()
17 | {
18 | API.opus_decoder_destroy(handle);
19 | return true;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/OpusDotNet/SafeEncoderHandle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Runtime.ConstrainedExecution;
4 |
5 | namespace OpusDotNet
6 | {
7 | internal sealed class SafeEncoderHandle : SafeHandle
8 | {
9 | private SafeEncoderHandle() : base(IntPtr.Zero, true)
10 | {
11 | }
12 |
13 | public override bool IsInvalid => handle == IntPtr.Zero;
14 |
15 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
16 | protected override bool ReleaseHandle()
17 | {
18 | API.opus_encoder_destroy(handle);
19 | return true;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/OpusDotNet/Control.cs:
--------------------------------------------------------------------------------
1 | namespace OpusDotNet
2 | {
3 | internal enum Control
4 | {
5 | SetBitrate = 4002,
6 | //GetBitrate = 4003,
7 |
8 | SetMaxBandwidth = 4004,
9 | GetMaxBandwidth = 4005,
10 |
11 | SetVBR = 4006,
12 | GetVBR = 4007,
13 |
14 | SetComplexity = 4010,
15 | GetComplexity = 4011,
16 |
17 | SetInbandFEC = 4012,
18 | GetInbandFEC = 4013,
19 |
20 | SetPacketLossPerc = 4014,
21 | GetPacketLossPerc = 4015,
22 |
23 | SetDTX = 4016,
24 | GetDTX = 4017,
25 |
26 | SetForceChannels = 4022,
27 | GetForceChannels = 4023
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/OpusDotNet/Application.cs:
--------------------------------------------------------------------------------
1 | namespace OpusDotNet
2 | {
3 | ///
4 | /// Specifies the intended applications.
5 | ///
6 | public enum Application
7 | {
8 | ///
9 | /// Process signal for improved speech intelligibility.
10 | ///
11 | VoIP = 2048,
12 | ///
13 | /// Favor faithfulness to the original input.
14 | ///
15 | Audio = 2049,
16 | ///
17 | /// Configure the minimum possible coding delay by disabling certain modes of operation.
18 | ///
19 | RestrictedLowDelay = 2051
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/OpusDotNet/Bandwidth.cs:
--------------------------------------------------------------------------------
1 | namespace OpusDotNet
2 | {
3 | ///
4 | /// Specifies the bandpasses.
5 | ///
6 | public enum Bandwidth
7 | {
8 | ///
9 | /// 4 kHz passband.
10 | ///
11 | NarrowBand = 1101,
12 | ///
13 | /// 6 kHz passband.
14 | ///
15 | MediumBand = 1102,
16 | ///
17 | /// 8 kHz passband.
18 | ///
19 | WideBand = 1103,
20 | ///
21 | /// 12 kHz passband.
22 | ///
23 | SuperWideBand = 1104,
24 | ///
25 | /// 20 kHz passband.
26 | ///
27 | FullBand = 1105
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/OpusDotNet/NuGet/opus/win-x64/OpusDotNet.opus.win-x64.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | OpusDotNet.opus.win-x64
5 | 1.3.1
6 | Contains 64-bit binaries for OpusDotNet.
7 | The Opus Audio Codec Authors
8 | LICENSE.txt
9 | true
10 | https://opus-codec.org/
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/OpusDotNet/NuGet/opus/win-x86/OpusDotNet.opus.win-x86.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | OpusDotNet.opus.win-x86
5 | 1.3.1
6 | Contains 32-bit binaries for OpusDotNet.
7 | The Opus Audio Codec Authors
8 | LICENSE.txt
9 | true
10 | https://opus-codec.org/
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/OpusDotNet/NuGet/OpusDotNet.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | %(RecursiveDir)%(Filename)%(Extension)
11 | PreserveNewest
12 |
13 |
14 |
15 |
16 |
17 | %(RecursiveDir)%(Filename)%(Extension)
18 | PreserveNewest
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 mrphil2105
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/OpusDotNet/OpusError.cs:
--------------------------------------------------------------------------------
1 | namespace OpusDotNet
2 | {
3 | ///
4 | /// Specifies the possible errors when using Opus.
5 | ///
6 | public enum OpusError
7 | {
8 | ///
9 | /// One or more invalid/out of range arguments.
10 | ///
11 | BadArg = -1,
12 | ///
13 | /// Not enough bytes allocated in the buffer.
14 | ///
15 | BufferTooSmall = -2,
16 | ///
17 | /// An internal error was detected.
18 | ///
19 | InternalError = -3,
20 | ///
21 | /// The compressed data passed is corrupted.
22 | ///
23 | InvalidPacket = -4,
24 | ///
25 | /// Invalid/unsupported request number.
26 | ///
27 | Unimplemented = -5,
28 | ///
29 | /// An encoder or decoder structure is invalid or already freed.
30 | ///
31 | InvalidState = -6,
32 | ///
33 | /// Memory allocation has failed.
34 | ///
35 | AllocFail = -7,
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/OpusDotNet.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29001.49
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpusDotNet", "OpusDotNet\OpusDotNet.csproj", "{2606A4D3-51DF-4AFD-ADAC-4A758D101672}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {2606A4D3-51DF-4AFD-ADAC-4A758D101672}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {2606A4D3-51DF-4AFD-ADAC-4A758D101672}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {2606A4D3-51DF-4AFD-ADAC-4A758D101672}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {2606A4D3-51DF-4AFD-ADAC-4A758D101672}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {990DFEAD-8C86-4B0A-8BE4-AEDC73C1E432}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/OpusDotNet/NuGet/OpusDotNet.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | OpusDotNet
5 | 1.0.3
6 | An easy-to-use library for encoding and decoding 16-bit audio using the Opus Audio Codec. NOTE: This library is a wrapper around the official libopus, and does not contain code for parsing .opus container files.
7 | mrphil2105
8 | MIT
9 | https://github.com/mrphil2105/OpusDotNet
10 | Copyright © 2019 mrphil2105
11 | Opus, Audio, Codec, Encoder, Decoder, VoIP
12 |
13 |
14 |
15 |
16 |
17 | Added improved encode and decode methods. IMPORTANT: Deprecated the old encode and decode methods.
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OpusDotNet
2 | [](https://www.nuget.org/packages/OpusDotNet)
3 |
4 | OpusDotNet is a wrapper around the official `libopus`, and makes it easy to encode and decode audio.
5 | The library is mainly suited for VoIP applications and at the moment only provides `libopus` binaries for Windows (compiled with the Win10 SDK).
6 |
7 | ## Getting Started
8 | ### Installation
9 | Install OpusDotNet via the NuGet Package Manager:
10 | ```
11 | Install-Package OpusDotNet
12 | ```
13 |
14 | ### Basic Usage
15 | A simple example of encoding and decoding audio:
16 | ```csharp
17 | using (var encoder = new OpusEncoder(Application.Audio, 48000, 2)
18 | {
19 | Bitrate = 128000, // 128 kbps
20 | VBR = true // Variable bitrate
21 | })
22 | using (var decoder = new OpusDecoder(48000, 2))
23 | {
24 | // 40 ms of silence at 48 KHz (2 channels).
25 | byte[] inputPCMBytes = new byte[40 * 48000 / 1000 * 2 * 2];
26 | byte[] opusBytes = encoder.Encode(inputPCMBytes, inputPCMBytes.Length, out int encodedLength);
27 | byte[] outputPCMBytes = decoder.Decode(opusBytes, encodedLength, out int decodedLength);
28 | }
29 | ```
30 |
31 | ## Licenses
32 | - This project is licensed under the [MIT License](LICENSE.md).
33 | - **Opus Audio Codec** is licensed under the [BSD License](https://opus-codec.org/license/).
34 |
--------------------------------------------------------------------------------
/OpusDotNet/OpusException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OpusDotNet
4 | {
5 | ///
6 | /// The exception that is thrown when an Opus error occurs.
7 | ///
8 | public class OpusException : Exception
9 | {
10 | ///
11 | /// Initializes a new instance, with the specified Opus error code.
12 | ///
13 | /// The Opus error code.
14 | public OpusException(int errorCode) : base(GetMessage((OpusError)errorCode))
15 | {
16 | Error = (OpusError)errorCode;
17 | }
18 |
19 | ///
20 | /// The Opus error.
21 | ///
22 | public OpusError Error { get; }
23 |
24 | private static string GetMessage(OpusError error)
25 | {
26 | switch (error)
27 | {
28 | case OpusError.BadArg:
29 | return "One or more invalid/out of range arguments.";
30 | case OpusError.BufferTooSmall:
31 | return "Not enough bytes allocated in the buffer.";
32 | case OpusError.InternalError:
33 | return "An internal error was detected.";
34 | case OpusError.InvalidPacket:
35 | return "The compressed data passed is corrupted.";
36 | case OpusError.Unimplemented:
37 | return "Invalid/unsupported request number.";
38 | case OpusError.InvalidState:
39 | return "An encoder or decoder structure is invalid or already freed.";
40 | case OpusError.AllocFail:
41 | return "Memory allocation has failed.";
42 | default:
43 | return "An unknown error has occurred.";
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/OpusDotNet/NuGet/opus/win-x64/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
2 | Jean-Marc Valin, Timothy B. Terriberry,
3 | CSIRO, Gregory Maxwell, Mark Borgerding,
4 | Erik de Castro Lopo
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions
8 | are met:
9 |
10 | - Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 |
13 | - Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in the
15 | documentation and/or other materials provided with the distribution.
16 |
17 | - Neither the name of Internet Society, IETF or IETF Trust, nor the
18 | names of specific contributors, may be used to endorse or promote
19 | products derived from this software without specific prior written
20 | permission.
21 |
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 |
34 | Opus is subject to the royalty-free patent licenses which are
35 | specified at:
36 |
37 | Xiph.Org Foundation:
38 | https://datatracker.ietf.org/ipr/1524/
39 |
40 | Microsoft Corporation:
41 | https://datatracker.ietf.org/ipr/1914/
42 |
43 | Broadcom Corporation:
44 | https://datatracker.ietf.org/ipr/1526/
45 |
--------------------------------------------------------------------------------
/OpusDotNet/NuGet/opus/win-x86/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
2 | Jean-Marc Valin, Timothy B. Terriberry,
3 | CSIRO, Gregory Maxwell, Mark Borgerding,
4 | Erik de Castro Lopo
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions
8 | are met:
9 |
10 | - Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 |
13 | - Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in the
15 | documentation and/or other materials provided with the distribution.
16 |
17 | - Neither the name of Internet Society, IETF or IETF Trust, nor the
18 | names of specific contributors, may be used to endorse or promote
19 | products derived from this software without specific prior written
20 | permission.
21 |
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 |
34 | Opus is subject to the royalty-free patent licenses which are
35 | specified at:
36 |
37 | Xiph.Org Foundation:
38 | https://datatracker.ietf.org/ipr/1524/
39 |
40 | Microsoft Corporation:
41 | https://datatracker.ietf.org/ipr/1914/
42 |
43 | Broadcom Corporation:
44 | https://datatracker.ietf.org/ipr/1526/
45 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/OpusDotNet/API.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Runtime.ConstrainedExecution;
4 |
5 | namespace OpusDotNet
6 | {
7 | internal static class API
8 | {
9 | // Encoder
10 |
11 | [DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
12 | public static extern SafeEncoderHandle opus_encoder_create(int Fs, int channels, int application, out int error);
13 |
14 | [DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
15 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
16 | public static extern void opus_encoder_destroy(IntPtr st);
17 |
18 | [DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
19 | public static extern int opus_encode(SafeEncoderHandle st, IntPtr pcm, int frame_size, IntPtr data, int max_data_bytes);
20 |
21 | [DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
22 | public static extern int opus_encoder_ctl(SafeEncoderHandle st, int request, out int value);
23 |
24 | [DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
25 | public static extern int opus_encoder_ctl(SafeEncoderHandle st, int request, int value);
26 |
27 | // Decoder
28 |
29 | [DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
30 | public static extern SafeDecoderHandle opus_decoder_create(int Fs, int channels, out int error);
31 |
32 | [DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
33 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
34 | public static extern void opus_decoder_destroy(IntPtr st);
35 |
36 | [DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
37 | public static extern int opus_decode(SafeDecoderHandle st, IntPtr data, int len, IntPtr pcm, int frame_size, int decode_fec);
38 |
39 | // Helper Methods
40 |
41 | public static int GetSampleCount(double frameSize, int sampleRate)
42 | {
43 | // Number of samples per channel.
44 | return (int)(frameSize * sampleRate / 1000);
45 | }
46 |
47 | public static int GetPCMLength(int samples, int channels)
48 | {
49 | // 16-bit audio contains a sample every 2 (16 / 8) bytes, so we multiply by 2.
50 | return samples * channels * 2;
51 | }
52 |
53 | public static double GetFrameSize(int pcmLength, int sampleRate, int channels)
54 | {
55 | return (double)pcmLength / sampleRate / channels / 2 * 1000;
56 | }
57 |
58 | public static void ThrowIfError(int result)
59 | {
60 | if (result < 0)
61 | {
62 | throw new OpusException(result);
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | [Aa][Rr][Mm]/
24 | [Aa][Rr][Mm]64/
25 | bld/
26 | [Bb]in/
27 | [Oo]bj/
28 | [Ll]og/
29 |
30 | # Visual Studio 2015/2017 cache/options directory
31 | .vs/
32 | # Uncomment if you have tasks that create the project's static files in wwwroot
33 | #wwwroot/
34 |
35 | # Visual Studio 2017 auto generated files
36 | Generated\ Files/
37 |
38 | # MSTest test Results
39 | [Tt]est[Rr]esult*/
40 | [Bb]uild[Ll]og.*
41 |
42 | # NUNIT
43 | *.VisualState.xml
44 | TestResult.xml
45 |
46 | # Build Results of an ATL Project
47 | [Dd]ebugPS/
48 | [Rr]eleasePS/
49 | dlldata.c
50 |
51 | # Benchmark Results
52 | BenchmarkDotNet.Artifacts/
53 |
54 | # .NET Core
55 | project.lock.json
56 | project.fragment.lock.json
57 | artifacts/
58 |
59 | # StyleCop
60 | StyleCopReport.xml
61 |
62 | # Files built by Visual Studio
63 | *_i.c
64 | *_p.c
65 | *_h.h
66 | *.ilk
67 | *.meta
68 | *.obj
69 | *.iobj
70 | *.pch
71 | *.pdb
72 | *.ipdb
73 | *.pgc
74 | *.pgd
75 | *.rsp
76 | *.sbr
77 | *.tlb
78 | *.tli
79 | *.tlh
80 | *.tmp
81 | *.tmp_proj
82 | *_wpftmp.csproj
83 | *.log
84 | *.vspscc
85 | *.vssscc
86 | .builds
87 | *.pidb
88 | *.svclog
89 | *.scc
90 |
91 | # Chutzpah Test files
92 | _Chutzpah*
93 |
94 | # Visual C++ cache files
95 | ipch/
96 | *.aps
97 | *.ncb
98 | *.opendb
99 | *.opensdf
100 | *.sdf
101 | *.cachefile
102 | *.VC.db
103 | *.VC.VC.opendb
104 |
105 | # Visual Studio profiler
106 | *.psess
107 | *.vsp
108 | *.vspx
109 | *.sap
110 |
111 | # Visual Studio Trace Files
112 | *.e2e
113 |
114 | # TFS 2012 Local Workspace
115 | $tf/
116 |
117 | # Guidance Automation Toolkit
118 | *.gpState
119 |
120 | # ReSharper is a .NET coding add-in
121 | _ReSharper*/
122 | *.[Rr]e[Ss]harper
123 | *.DotSettings.user
124 |
125 | # JustCode is a .NET coding add-in
126 | .JustCode
127 |
128 | # TeamCity is a build add-in
129 | _TeamCity*
130 |
131 | # DotCover is a Code Coverage Tool
132 | *.dotCover
133 |
134 | # AxoCover is a Code Coverage Tool
135 | .axoCover/*
136 | !.axoCover/settings.json
137 |
138 | # Visual Studio code coverage results
139 | *.coverage
140 | *.coveragexml
141 |
142 | # NCrunch
143 | _NCrunch_*
144 | .*crunch*.local.xml
145 | nCrunchTemp_*
146 |
147 | # MightyMoose
148 | *.mm.*
149 | AutoTest.Net/
150 |
151 | # Web workbench (sass)
152 | .sass-cache/
153 |
154 | # Installshield output folder
155 | [Ee]xpress/
156 |
157 | # DocProject is a documentation generator add-in
158 | DocProject/buildhelp/
159 | DocProject/Help/*.HxT
160 | DocProject/Help/*.HxC
161 | DocProject/Help/*.hhc
162 | DocProject/Help/*.hhk
163 | DocProject/Help/*.hhp
164 | DocProject/Help/Html2
165 | DocProject/Help/html
166 |
167 | # Click-Once directory
168 | publish/
169 |
170 | # Publish Web Output
171 | *.[Pp]ublish.xml
172 | *.azurePubxml
173 | # Note: Comment the next line if you want to checkin your web deploy settings,
174 | # but database connection strings (with potential passwords) will be unencrypted
175 | *.pubxml
176 | *.publishproj
177 |
178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
179 | # checkin your Azure Web App publish settings, but sensitive information contained
180 | # in these scripts will be unencrypted
181 | PublishScripts/
182 |
183 | # NuGet Packages
184 | *.nupkg
185 | # The packages folder can be ignored because of Package Restore
186 | **/[Pp]ackages/*
187 | # except build/, which is used as an MSBuild target.
188 | !**/[Pp]ackages/build/
189 | # Uncomment if necessary however generally it will be regenerated when needed
190 | #!**/[Pp]ackages/repositories.config
191 | # NuGet v3's project.json files produces more ignorable files
192 | *.nuget.props
193 | *.nuget.targets
194 |
195 | # Microsoft Azure Build Output
196 | csx/
197 | *.build.csdef
198 |
199 | # Microsoft Azure Emulator
200 | ecf/
201 | rcf/
202 |
203 | # Windows Store app package directories and files
204 | AppPackages/
205 | BundleArtifacts/
206 | Package.StoreAssociation.xml
207 | _pkginfo.txt
208 | *.appx
209 |
210 | # Visual Studio cache files
211 | # files ending in .cache can be ignored
212 | *.[Cc]ache
213 | # but keep track of directories ending in .cache
214 | !?*.[Cc]ache/
215 |
216 | # Others
217 | ClientBin/
218 | ~$*
219 | *~
220 | *.dbmdl
221 | *.dbproj.schemaview
222 | *.jfm
223 | *.pfx
224 | *.publishsettings
225 | orleans.codegen.cs
226 |
227 | # Including strong name files can present a security risk
228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
229 | #*.snk
230 |
231 | # Since there are multiple workflows, uncomment next line to ignore bower_components
232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
233 | #bower_components/
234 |
235 | # RIA/Silverlight projects
236 | Generated_Code/
237 |
238 | # Backup & report files from converting an old project file
239 | # to a newer Visual Studio version. Backup files are not needed,
240 | # because we have git ;-)
241 | _UpgradeReport_Files/
242 | Backup*/
243 | UpgradeLog*.XML
244 | UpgradeLog*.htm
245 | ServiceFabricBackup/
246 | *.rptproj.bak
247 |
248 | # SQL Server files
249 | *.mdf
250 | *.ldf
251 | *.ndf
252 |
253 | # Business Intelligence projects
254 | *.rdl.data
255 | *.bim.layout
256 | *.bim_*.settings
257 | *.rptproj.rsuser
258 | *- Backup*.rdl
259 |
260 | # Microsoft Fakes
261 | FakesAssemblies/
262 |
263 | # GhostDoc plugin setting file
264 | *.GhostDoc.xml
265 |
266 | # Node.js Tools for Visual Studio
267 | .ntvs_analysis.dat
268 | node_modules/
269 |
270 | # Visual Studio 6 build log
271 | *.plg
272 |
273 | # Visual Studio 6 workspace options file
274 | *.opt
275 |
276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
277 | *.vbw
278 |
279 | # Visual Studio LightSwitch build output
280 | **/*.HTMLClient/GeneratedArtifacts
281 | **/*.DesktopClient/GeneratedArtifacts
282 | **/*.DesktopClient/ModelManifest.xml
283 | **/*.Server/GeneratedArtifacts
284 | **/*.Server/ModelManifest.xml
285 | _Pvt_Extensions
286 |
287 | # Paket dependency manager
288 | .paket/paket.exe
289 | paket-files/
290 |
291 | # FAKE - F# Make
292 | .fake/
293 |
294 | # JetBrains Rider
295 | .idea/
296 | *.sln.iml
297 |
298 | # CodeRush personal settings
299 | .cr/personal
300 |
301 | # Python Tools for Visual Studio (PTVS)
302 | __pycache__/
303 | *.pyc
304 |
305 | # Cake - Uncomment if you are using it
306 | # tools/**
307 | # !tools/packages.config
308 |
309 | # Tabs Studio
310 | *.tss
311 |
312 | # Telerik's JustMock configuration file
313 | *.jmconfig
314 |
315 | # BizTalk build output
316 | *.btp.cs
317 | *.btm.cs
318 | *.odx.cs
319 | *.xsd.cs
320 |
321 | # OpenCover UI analysis results
322 | OpenCover/
323 |
324 | # Azure Stream Analytics local run output
325 | ASALocalRun/
326 |
327 | # MSBuild Binary and Structured Log
328 | *.binlog
329 |
330 | # NVidia Nsight GPU debugger configuration file
331 | *.nvuser
332 |
333 | # MFractors (Xamarin productivity tool) working folder
334 | .mfractor/
335 |
336 | # Local History for Visual Studio
337 | .localhistory/
338 |
339 | # BeatPulse healthcheck temp database
340 | healthchecksdb
--------------------------------------------------------------------------------
/OpusDotNet/OpusDecoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OpusDotNet
4 | {
5 | ///
6 | /// Provides audio decoding with Opus.
7 | ///
8 | public class OpusDecoder : IDisposable
9 | {
10 | private readonly SafeDecoderHandle _handle;
11 | // Number of samples in the frame size, per channel.
12 | private readonly int _samples;
13 | private readonly int _pcmLength;
14 |
15 | private bool _fec;
16 |
17 | ///
18 | /// Initializes a new instance, with 48000 Hz sample rate and 2 channels.
19 | ///
20 | public OpusDecoder() : this(60, 48000, 2, false)
21 | {
22 | }
23 |
24 | ///
25 | /// Initializes a new instance, with the specified frame size, 48000 Hz sample rate and 2 channels.
26 | ///
27 | /// The frame size used when encoding, 2.5, 5, 10, 20, 40 or 60 ms.
28 | [Obsolete("This constructor was used for the old decode method and is deprecated, please use the new decode method instead.")]
29 | public OpusDecoder(double frameSize) : this(frameSize, 48000, 2, true)
30 | {
31 | }
32 |
33 | ///
34 | /// Initializes a new instance, with the specified sample rate and channels.
35 | ///
36 | /// The sample rate to decode to, 48000, 24000, 16000, 12000 or 8000 Hz.
37 | /// The channels to decode to, mono or stereo.
38 | public OpusDecoder(int sampleRate, int channels) : this(60, sampleRate, channels, false)
39 | {
40 | }
41 |
42 | ///
43 | /// Initializes a new instance, with the specified frame size, sample rate and channels.
44 | ///
45 | /// The frame size used when encoding, 2.5, 5, 10, 20, 40 or 60 ms.
46 | /// The sample rate to decode to, 48000, 24000, 16000, 12000 or 8000 Hz.
47 | /// The channels to decode to, mono or stereo.
48 | [Obsolete("This constructor was used for the old decode method and is deprecated, please use the new decode method instead.")]
49 | public OpusDecoder(double frameSize, int sampleRate, int channels) : this(frameSize, sampleRate, channels, true)
50 | {
51 | }
52 |
53 | private OpusDecoder(double frameSize, int sampleRate, int channels, bool frameSizeWasSpecified)
54 | {
55 | switch (frameSize)
56 | {
57 | case 2.5:
58 | case 5:
59 | case 10:
60 | case 20:
61 | case 40:
62 | case 60:
63 | break;
64 | default:
65 | throw new ArgumentException("Value must be one of the following: 2.5, 5, 10, 20, 40 or 60.", nameof(frameSize));
66 | }
67 |
68 | switch (sampleRate)
69 | {
70 | case 8000:
71 | case 12000:
72 | case 16000:
73 | case 24000:
74 | case 48000:
75 | break;
76 | default:
77 | throw new ArgumentException("Value must be one of the following: 8000, 12000, 16000, 24000 or 48000.", nameof(sampleRate));
78 | }
79 |
80 | if (channels < 1 || channels > 2)
81 | {
82 | throw new ArgumentOutOfRangeException(nameof(channels), "Value must be between 1 and 2.");
83 | }
84 |
85 | if (frameSizeWasSpecified)
86 | {
87 | FrameSize = frameSize;
88 | }
89 |
90 | SampleRate = sampleRate;
91 | Channels = channels;
92 |
93 | _samples = API.GetSampleCount(frameSize, sampleRate);
94 | _pcmLength = API.GetPCMLength(_samples, channels);
95 |
96 | _handle = API.opus_decoder_create(sampleRate, channels, out int error);
97 | API.ThrowIfError(error);
98 | }
99 |
100 | ///
101 | /// Gets the frame size, or null if not specified when constructing the current instance.
102 | ///
103 | [Obsolete("This property was used for the old decode method and is deprecated, please use the new decode method instead.")]
104 | public double? FrameSize { get; }
105 |
106 | ///
107 | /// Gets the sample rate, 48000, 24000, 16000, 12000 or 8000 Hz.
108 | ///
109 | public int SampleRate { get; }
110 |
111 | ///
112 | /// Gets the channels, mono or stereo.
113 | ///
114 | public int Channels { get; }
115 |
116 | ///
117 | /// Gets or sets whether to use FEC (forward error correction). NOTE: This can only be set if is set,
118 | /// and only works if the encoder also uses FEC. You also need to indicate when a packet has been lost
119 | /// (by calling with null and -1 as the arguments).
120 | ///
121 | [Obsolete("This property was used for the old decode method and is deprecated, please use the new decode method instead.")]
122 | public bool FEC
123 | {
124 | get => _fec;
125 | set
126 | {
127 | if (FrameSize == null)
128 | {
129 | throw new InvalidOperationException("A frame size has to be specified in the constructor for FEC to work.");
130 | }
131 |
132 | _fec = value;
133 | }
134 | }
135 |
136 | ///
137 | /// Decodes an Opus packet, or indicates packet loss (if is enabled).
138 | ///
139 | /// The Opus packet, or null to indicate packet loss (if is enabled).
140 | /// The maximum number of bytes to use from , or -1 to indicate packet loss
141 | /// (if is enabled).
142 | /// The length of the decoded audio.
143 | /// A byte array containing the decoded audio.
144 | [Obsolete("This method is deprecated, please use the new decode method instead.")]
145 | public unsafe byte[] Decode(byte[] opusBytes, int length, out int decodedLength)
146 | {
147 | if (opusBytes == null && !FEC)
148 | {
149 | throw new ArgumentNullException(nameof(opusBytes), "Value cannot be null when FEC is disabled.");
150 | }
151 |
152 | if (length < 0 && (!FEC || opusBytes != null))
153 | {
154 | throw new ArgumentOutOfRangeException(nameof(length), $"Value cannot be negative when {nameof(opusBytes)} is not null or FEC is disabled.");
155 | }
156 |
157 | if (opusBytes != null && opusBytes.Length < length)
158 | {
159 | throw new ArgumentOutOfRangeException(nameof(length), $"Value cannot be greater than the length of {nameof(opusBytes)}.");
160 | }
161 |
162 | ThrowIfDisposed();
163 |
164 | byte[] pcmBytes = new byte[_pcmLength];
165 | int result;
166 |
167 | fixed (byte* input = opusBytes)
168 | fixed (byte* output = pcmBytes)
169 | {
170 | var inputPtr = (IntPtr)input;
171 | var outputPtr = (IntPtr)output;
172 |
173 | if (opusBytes != null)
174 | {
175 | result = API.opus_decode(_handle, inputPtr, length, outputPtr, _samples, 0);
176 | }
177 | else
178 | {
179 | // If forward error correction is enabled, this will indicate a packet loss.
180 | result = API.opus_decode(_handle, IntPtr.Zero, 0, outputPtr, _samples, FEC ? 1 : 0);
181 | }
182 | }
183 |
184 | API.ThrowIfError(result);
185 |
186 | decodedLength = result * Channels * 2;
187 | return pcmBytes;
188 | }
189 |
190 | ///
191 | /// Decodes an Opus packet or any FEC (forward error correction) data.
192 | ///
193 | /// The Opus packet, or null to indicate packet loss.
194 | /// The maximum number of bytes to read from , or -1 to indicate packet loss.
195 | /// The buffer that the decoded audio will be stored in.
196 | /// The maximum number of bytes to write to .
197 | /// When using FEC (forward error correction) this must be a valid frame size that matches the duration of the missing audio.
198 | /// The number of bytes written to .
199 | public unsafe int Decode(byte[] opusBytes, int opusLength, byte[] pcmBytes, int pcmLength)
200 | {
201 | if (opusLength < 0 && opusBytes != null)
202 | {
203 | throw new ArgumentOutOfRangeException(nameof(opusLength), $"Value cannot be negative when {nameof(opusBytes)} is not null.");
204 | }
205 |
206 | if (opusBytes != null && opusBytes.Length < opusLength)
207 | {
208 | throw new ArgumentOutOfRangeException(nameof(opusLength), $"Value cannot be greater than the length of {nameof(opusBytes)}.");
209 | }
210 |
211 | if (pcmBytes == null)
212 | {
213 | throw new ArgumentNullException(nameof(pcmBytes));
214 | }
215 |
216 | if (pcmLength < 0)
217 | {
218 | throw new ArgumentOutOfRangeException(nameof(pcmLength), "Value cannot be negative.");
219 | }
220 |
221 | if (pcmBytes.Length < pcmLength)
222 | {
223 | throw new ArgumentOutOfRangeException(nameof(pcmLength), $"Value cannot be greater than the length of {nameof(pcmBytes)}.");
224 | }
225 |
226 | double frameSize = API.GetFrameSize(pcmLength, SampleRate, Channels);
227 |
228 | if (opusBytes == null)
229 | {
230 | switch (frameSize)
231 | {
232 | case 2.5:
233 | case 5:
234 | case 10:
235 | case 20:
236 | case 40:
237 | case 60:
238 | break;
239 | default:
240 | throw new ArgumentException("When using FEC the frame size must be one of the following: 2.5, 5, 10, 20, 40 or 60.", nameof(pcmLength));
241 | }
242 | }
243 |
244 | ThrowIfDisposed();
245 |
246 | int result;
247 | int samples = API.GetSampleCount(frameSize, SampleRate);
248 |
249 | fixed (byte* input = opusBytes)
250 | fixed (byte* output = pcmBytes)
251 | {
252 | var inputPtr = (IntPtr)input;
253 | var outputPtr = (IntPtr)output;
254 |
255 | if (opusBytes != null)
256 | {
257 | result = API.opus_decode(_handle, inputPtr, opusLength, outputPtr, samples, 0);
258 | }
259 | else
260 | {
261 | // If forward error correction is enabled, this will indicate a packet loss.
262 | result = API.opus_decode(_handle, IntPtr.Zero, 0, outputPtr, samples, 1);
263 | }
264 | }
265 |
266 | API.ThrowIfError(result);
267 | return API.GetPCMLength(result, Channels);
268 | }
269 |
270 | ///
271 | /// Releases all resources used by the current instance.
272 | ///
273 | public void Dispose()
274 | {
275 | _handle?.Dispose();
276 | }
277 |
278 | private void ThrowIfDisposed()
279 | {
280 | if (_handle.IsClosed)
281 | {
282 | throw new ObjectDisposedException(GetType().FullName);
283 | }
284 | }
285 | }
286 | }
287 |
--------------------------------------------------------------------------------
/OpusDotNet/OpusEncoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OpusDotNet
4 | {
5 | ///
6 | /// Provides audio encoding with Opus.
7 | ///
8 | public class OpusEncoder : IDisposable
9 | {
10 | private readonly SafeEncoderHandle _handle;
11 |
12 | private int _bitrate;
13 |
14 | ///
15 | /// Initializes a new instance, with the specified intended application, 48000 Hz sample rate and 2 channels.
16 | ///
17 | /// The intended application.
18 | public OpusEncoder(Application application) : this(application, 48000, 2)
19 | {
20 | }
21 |
22 | ///
23 | /// Initializes a new instance, with the specified intended application, sample rate and channels.
24 | ///
25 | /// The intended application.
26 | /// The sample rate in the input audio, 48000, 24000, 16000, 12000 or 8000 Hz.
27 | /// The channels in the input audio, mono or stereo.
28 | public OpusEncoder(Application application, int sampleRate, int channels)
29 | {
30 | if (!Enum.IsDefined(typeof(Application), application))
31 | {
32 | throw new ArgumentException("Value is not defined in the enumeration.", nameof(application));
33 | }
34 |
35 | switch (sampleRate)
36 | {
37 | case 8000:
38 | case 12000:
39 | case 16000:
40 | case 24000:
41 | case 48000:
42 | break;
43 | default:
44 | throw new ArgumentException("Value must be one of the following: 8000, 12000, 16000, 24000 or 48000.", nameof(sampleRate));
45 | }
46 |
47 | if (channels < 1 || channels > 2)
48 | {
49 | throw new ArgumentOutOfRangeException(nameof(channels), "Value must be between 1 and 2.");
50 | }
51 |
52 | Application = application;
53 | SampleRate = sampleRate;
54 | Channels = channels;
55 | Bitrate = 128000;
56 |
57 | _handle = API.opus_encoder_create(sampleRate, channels, (int)application, out int error);
58 | API.ThrowIfError(error);
59 |
60 | // Setting to -1 (OPUS_BITRATE_MAX) enables bitrate to be regulated by the output buffer length.
61 | int result = API.opus_encoder_ctl(_handle, (int)Control.SetBitrate, -1);
62 | API.ThrowIfError(result);
63 | }
64 |
65 | ///
66 | /// Gets the intended application.
67 | ///
68 | public Application Application { get; }
69 |
70 | ///
71 | /// Gets the sample rate, 48000, 24000, 16000, 12000 or 8000 Hz.
72 | ///
73 | public int SampleRate { get; }
74 |
75 | ///
76 | /// Gets the channels, mono or stereo.
77 | ///
78 | public int Channels { get; }
79 |
80 | ///
81 | /// Gets or sets the bitrate, 8000 - 512000 bps.
82 | ///
83 | [Obsolete("This property was used for the old encode method and is deprecated, please use the new encode method instead.")]
84 | public int Bitrate
85 | {
86 | get => _bitrate;
87 | set
88 | {
89 | if (value < 8000 || value > 512000)
90 | {
91 | throw new ArgumentOutOfRangeException(nameof(value), "Value must be between 8000 and 512000.");
92 | }
93 |
94 | _bitrate = value;
95 | }
96 | }
97 |
98 | ///
99 | /// Gets or sets whether VBR (variable bitrate) is enabled.
100 | ///
101 | public bool VBR
102 | {
103 | get
104 | {
105 | ThrowIfDisposed();
106 | int result = API.opus_encoder_ctl(_handle, (int)Control.GetVBR, out int value);
107 | API.ThrowIfError(result);
108 |
109 | return value == 1;
110 | }
111 | set
112 | {
113 | ThrowIfDisposed();
114 | int result = API.opus_encoder_ctl(_handle, (int)Control.SetVBR, value ? 1 : 0);
115 | API.ThrowIfError(result);
116 | }
117 | }
118 |
119 | ///
120 | /// Gets or sets the maximum bandpass.
121 | ///
122 | public Bandwidth MaxBandwidth
123 | {
124 | get
125 | {
126 | ThrowIfDisposed();
127 | int result = API.opus_encoder_ctl(_handle, (int)Control.GetMaxBandwidth, out int value);
128 | API.ThrowIfError(result);
129 |
130 | return (Bandwidth)value;
131 | }
132 | set
133 | {
134 | if (!Enum.IsDefined(typeof(Bandwidth), value))
135 | {
136 | throw new ArgumentException("Value is not defined in the enumeration.", nameof(value));
137 | }
138 |
139 | ThrowIfDisposed();
140 | int result = API.opus_encoder_ctl(_handle, (int)Control.SetMaxBandwidth, (int)value);
141 | API.ThrowIfError(result);
142 | }
143 | }
144 |
145 | ///
146 | /// Gets or sets the computational complexity, 0 - 10. Decreasing this will decrease CPU time, at the expense of quality.
147 | ///
148 | public int Complexity
149 | {
150 | get
151 | {
152 | ThrowIfDisposed();
153 | int result = API.opus_encoder_ctl(_handle, (int)Control.GetComplexity, out int value);
154 | API.ThrowIfError(result);
155 |
156 | return value;
157 | }
158 | set
159 | {
160 | if (value < 0 || value > 10)
161 | {
162 | throw new ArgumentOutOfRangeException(nameof(value), "Value must be between 0 and 10.");
163 | }
164 |
165 | ThrowIfDisposed();
166 | int result = API.opus_encoder_ctl(_handle, (int)Control.SetComplexity, value);
167 | API.ThrowIfError(result);
168 | }
169 | }
170 |
171 | ///
172 | /// Gets or sets whether to use FEC (forward error correction). You need to adjust
173 | /// before FEC takes effect.
174 | ///
175 | public bool FEC
176 | {
177 | get
178 | {
179 | ThrowIfDisposed();
180 | int result = API.opus_encoder_ctl(_handle, (int)Control.GetInbandFEC, out int value);
181 | API.ThrowIfError(result);
182 |
183 | return value == 1;
184 | }
185 | set
186 | {
187 | ThrowIfDisposed();
188 | int result = API.opus_encoder_ctl(_handle, (int)Control.SetInbandFEC, value ? 1 : 0);
189 | API.ThrowIfError(result);
190 | }
191 | }
192 |
193 | ///
194 | /// Gets or sets the expected packet loss percentage when using FEC (forward error correction). Increasing this will
195 | /// improve quality under loss, at the expense of quality in the absence of packet loss.
196 | ///
197 | public int ExpectedPacketLoss
198 | {
199 | get
200 | {
201 | ThrowIfDisposed();
202 | int result = API.opus_encoder_ctl(_handle, (int)Control.GetPacketLossPerc, out int value);
203 | API.ThrowIfError(result);
204 |
205 | return value;
206 | }
207 | set
208 | {
209 | if (value < 0 || value > 100)
210 | {
211 | throw new ArgumentOutOfRangeException(nameof(value), "Value must be between 0 and 100.");
212 | }
213 |
214 | ThrowIfDisposed();
215 | int result = API.opus_encoder_ctl(_handle, (int)Control.SetPacketLossPerc, value);
216 | API.ThrowIfError(result);
217 | }
218 | }
219 |
220 | ///
221 | /// Gets or sets whether to use DTX (discontinuous transmission). When enabled the encoder will produce
222 | /// packets with a length of 2 bytes or less during periods of no voice activity.
223 | ///
224 | public bool DTX
225 | {
226 | get
227 | {
228 | ThrowIfDisposed();
229 | int result = API.opus_encoder_ctl(_handle, (int)Control.GetDTX, out int value);
230 | API.ThrowIfError(result);
231 |
232 | return value == 1;
233 | }
234 | set
235 | {
236 | ThrowIfDisposed();
237 | int result = API.opus_encoder_ctl(_handle, (int)Control.SetDTX, value ? 1 : 0);
238 | API.ThrowIfError(result);
239 | }
240 | }
241 |
242 | ///
243 | /// Gets or sets the forced mono/stereo mode.
244 | ///
245 | public ForceChannels ForceChannels
246 | {
247 | get
248 | {
249 | ThrowIfDisposed();
250 | int result = API.opus_encoder_ctl(_handle, (int)Control.GetForceChannels, out int value);
251 | API.ThrowIfError(result);
252 |
253 | return (ForceChannels)value;
254 | }
255 | set
256 | {
257 | if (!Enum.IsDefined(typeof(ForceChannels), value))
258 | {
259 | throw new ArgumentException("Value is not defined in the enumeration.", nameof(value));
260 | }
261 |
262 | ThrowIfDisposed();
263 | int result = API.opus_encoder_ctl(_handle, (int)Control.SetForceChannels, (int)value);
264 | API.ThrowIfError(result);
265 | }
266 | }
267 |
268 | ///
269 | /// Encodes an Opus frame, the frame size must be one of the following: 2.5, 5, 10, 20, 40 or 60 ms.
270 | ///
271 | /// The Opus frame.
272 | /// The maximum number of bytes to use from .
273 | /// The length of the encoded audio.
274 | /// A byte array containing the encoded audio.
275 | [Obsolete("This method is deprecated, please use the new encode method instead.")]
276 | public unsafe byte[] Encode(byte[] pcmBytes, int length, out int encodedLength)
277 | {
278 | if (pcmBytes == null)
279 | {
280 | throw new ArgumentNullException(nameof(pcmBytes));
281 | }
282 |
283 | if (length < 0)
284 | {
285 | throw new ArgumentOutOfRangeException(nameof(length), "Value cannot be negative.");
286 | }
287 |
288 | if (pcmBytes.Length < length)
289 | {
290 | throw new ArgumentOutOfRangeException(nameof(length), $"Value cannot be greater than the length of {nameof(pcmBytes)}.");
291 | }
292 |
293 | double frameSize = API.GetFrameSize(length, SampleRate, Channels);
294 |
295 | switch (frameSize)
296 | {
297 | case 2.5:
298 | case 5:
299 | case 10:
300 | case 20:
301 | case 40:
302 | case 60:
303 | break;
304 | default:
305 | throw new ArgumentException("The frame size must be one of the following: 2.5, 5, 10, 20, 40 or 60.", nameof(length));
306 | }
307 |
308 | ThrowIfDisposed();
309 |
310 | byte[] opusBytes = new byte[(int)(frameSize * Bitrate / 8 / 1000)];
311 | int result;
312 |
313 | int samples = API.GetSampleCount(frameSize, SampleRate);
314 |
315 | fixed (byte* input = pcmBytes)
316 | fixed (byte* output = opusBytes)
317 | {
318 | var inputPtr = (IntPtr)input;
319 | var outputPtr = (IntPtr)output;
320 | result = API.opus_encode(_handle, inputPtr, samples, outputPtr, opusBytes.Length);
321 | }
322 |
323 | API.ThrowIfError(result);
324 |
325 | encodedLength = result;
326 | return opusBytes;
327 | }
328 |
329 | ///
330 | /// Encodes an Opus frame, the frame size must be one of the following: 2.5, 5, 10, 20, 40 or 60 ms.
331 | ///
332 | /// The Opus frame.
333 | /// The maximum number of bytes to read from .
334 | /// The buffer that the encoded audio will be stored in.
335 | /// The maximum number of bytes to write to .
336 | /// This will determine the bitrate in the encoded audio.
337 | /// The number of bytes written to .
338 | public unsafe int Encode(byte[] pcmBytes, int pcmLength, byte[] opusBytes, int opusLength)
339 | {
340 | if (pcmBytes == null)
341 | {
342 | throw new ArgumentNullException(nameof(pcmBytes));
343 | }
344 |
345 | if (pcmLength < 0)
346 | {
347 | throw new ArgumentOutOfRangeException(nameof(pcmLength), "Value cannot be negative.");
348 | }
349 |
350 | if (pcmBytes.Length < pcmLength)
351 | {
352 | throw new ArgumentOutOfRangeException(nameof(pcmLength), $"Value cannot be greater than the length of {nameof(pcmBytes)}.");
353 | }
354 |
355 | if (opusBytes == null)
356 | {
357 | throw new ArgumentNullException(nameof(opusBytes));
358 | }
359 |
360 | if (opusLength < 0)
361 | {
362 | throw new ArgumentOutOfRangeException(nameof(opusLength), "Value cannot be negative.");
363 | }
364 |
365 | if (opusBytes.Length < opusLength)
366 | {
367 | throw new ArgumentOutOfRangeException(nameof(opusLength), $"Value cannot be greater than the length of {nameof(opusBytes)}.");
368 | }
369 |
370 | double frameSize = API.GetFrameSize(pcmLength, SampleRate, Channels);
371 |
372 | switch (frameSize)
373 | {
374 | case 2.5:
375 | case 5:
376 | case 10:
377 | case 20:
378 | case 40:
379 | case 60:
380 | break;
381 | default:
382 | throw new ArgumentException("The frame size must be one of the following: 2.5, 5, 10, 20, 40 or 60.", nameof(pcmLength));
383 | }
384 |
385 | ThrowIfDisposed();
386 |
387 | int result;
388 | int samples = API.GetSampleCount(frameSize, SampleRate);
389 |
390 | fixed (byte* input = pcmBytes)
391 | fixed (byte* output = opusBytes)
392 | {
393 | var inputPtr = (IntPtr)input;
394 | var outputPtr = (IntPtr)output;
395 | result = API.opus_encode(_handle, inputPtr, samples, outputPtr, opusLength);
396 | }
397 |
398 | API.ThrowIfError(result);
399 | return result;
400 | }
401 |
402 | ///
403 | /// Releases all resources used by the current instance.
404 | ///
405 | public void Dispose()
406 | {
407 | _handle?.Dispose();
408 | }
409 |
410 | private void ThrowIfDisposed()
411 | {
412 | if (_handle.IsClosed)
413 | {
414 | throw new ObjectDisposedException(GetType().FullName);
415 | }
416 | }
417 | }
418 | }
419 |
--------------------------------------------------------------------------------