Skip to content

Commit 8b9cf60

Browse files
Merge pull request #32 from AvionBlock/dev
v1.6.0 release.
2 parents b8b2697 + 1dde69e commit 8b9cf60

26 files changed

Lines changed: 472 additions & 395 deletions

File tree

.github/workflows/OpusCompile.yml

Lines changed: 122 additions & 361 deletions
Large diffs are not rendered by default.

OpusSharp.Core/Enums.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,16 @@ public enum EncoderCTL
374374
/// Provide external DNN weights from binary object (only when explicitly built without the weights).
375375
/// </summary>
376376
OPUS_SET_DNN_BLOB = 4052,
377+
378+
/// <summary>
379+
/// If set to 1, enables quality extension (QEXT), otherwise disables it (default). Warning: This will hurt audio quality unless operating at a very high bitrate.
380+
/// </summary>
381+
OPUS_SET_QEXT = 4056,
382+
383+
/// <summary>
384+
/// Gets the encoder's configured quality extension (QEXT).
385+
/// </summary>
386+
OPUS_GET_QEXT = 4057
377387
}
378388

379389
/// <summary>
@@ -400,6 +410,26 @@ public enum DecoderCTL
400410
/// Gets the pitch of the last decoded frame, if available.
401411
/// </summary>
402412
OPUS_GET_PITCH = 4033,
413+
414+
/// <summary>
415+
/// Enables blind bandwidth extension for wideband signals if decoding sampling rate is 48 kHz.
416+
/// </summary>
417+
OPUS_SET_OSCE_BWE = 4054,
418+
419+
/// <summary>
420+
/// Gets blind bandwidth extension flag for wideband signals if decoding sampling rate is 48 kHz.
421+
/// </summary>
422+
OPUS_GET_OSCE_BWE = 4055,
423+
424+
/// <summary>
425+
/// If set to 1, the decoder will ignore all extensions found in the padding area (does not affect DRED, which is decoded separately).
426+
/// </summary>
427+
OPUS_SET_IGNORE_EXTENSIONS = 4058,
428+
429+
/// <summary>
430+
/// Gets whether the decoder is ignoring extensions.
431+
/// </summary>
432+
OPUS_GET_IGNORE_EXTENSIONS = 4059,
403433
}
404434

405435
/// <summary>

OpusSharp.Core/Extensions/OpusDecoderExtensions.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,58 @@ public static int GetPitch(this OpusDecoder decoder)
6161
decoder.Ctl(DecoderCTL.OPUS_GET_PITCH, ref pitch);
6262
return pitch;
6363
}
64+
65+
/// <summary>
66+
/// Enables or disables the decoder's OSCE BWE module.
67+
/// </summary>
68+
/// <param name="decoder">The decoder state.</param>
69+
/// <param name="enabled">Whether to enable or disable the OSCE BWE module.</param>
70+
/// <exception cref="OpusException" />
71+
/// <exception cref="ObjectDisposedException" />
72+
public static void SetOsceBwe(this OpusDecoder decoder, bool enabled)
73+
{
74+
decoder.Ctl(DecoderCTL.OPUS_SET_OSCE_BWE, enabled ? 1 : 0);
75+
}
76+
77+
/// <summary>
78+
/// Determines whether the decoder's OSCE BWE module is enabled or not.
79+
/// </summary>
80+
/// <param name="decoder">The decoder state.</param>
81+
/// <returns>Whether the OSCE BWE module is enabled or not.</returns>
82+
/// <exception cref="OpusException" />
83+
/// <exception cref="ObjectDisposedException" />
84+
public static bool GetOsceBwe(this OpusDecoder decoder)
85+
{
86+
var value = 0;
87+
decoder.Ctl(DecoderCTL.OPUS_GET_OSCE_BWE, ref value);
88+
return value == 1;
89+
}
90+
91+
/// <summary>
92+
/// Sets whether the decoder should ignore extensions in the padding area.
93+
/// </summary>
94+
/// <param name="decoder">The decoder state.</param>
95+
/// <param name="disabled">Whether to disable all found extensions in the padding area.</param>
96+
/// <exception cref="OpusException" />
97+
/// <exception cref="ObjectDisposedException" />
98+
public static void SetIgnoreExtensions(this OpusDecoder decoder, bool disabled)
99+
{
100+
decoder.Ctl(DecoderCTL.OPUS_SET_IGNORE_EXTENSIONS, disabled ? 1 : 0);
101+
}
102+
103+
/// <summary>
104+
/// Determines whether the decoder is ignoring extensions found in the padding area.
105+
/// </summary>
106+
/// <param name="decoder">The decoder state.</param>
107+
/// <returns>Whether the decoder is ignoring extensions.</returns>
108+
/// <exception cref="OpusException" />
109+
/// <exception cref="ObjectDisposedException" />
110+
public static bool GetIgnoreExtensions(this OpusDecoder decoder)
111+
{
112+
var value = 0;
113+
decoder.Ctl(DecoderCTL.OPUS_GET_IGNORE_EXTENSIONS, ref value);
114+
return value == 1;
115+
}
64116

65117
/// <summary>
66118
/// Resets the codec state to be equivalent to a freshly initialized state.

OpusSharp.Core/Extensions/OpusEncoderExtensions.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,32 @@ public static int GetInDtx(this OpusEncoder encoder)
414414
return value;
415415
}
416416

417+
/// <summary>
418+
/// Configures the encoder's QEXT extension.
419+
/// </summary>
420+
/// <param name="encoder">The encoder state.</param>
421+
/// <param name="enabled">Whether to enable the QEXT extension or not.</param>
422+
/// <exception cref="OpusException" />
423+
/// <exception cref="ObjectDisposedException" />
424+
public static void SetQext(this OpusEncoder encoder, bool enabled)
425+
{
426+
encoder.Ctl(EncoderCTL.OPUS_SET_QEXT, enabled ? 1 : 0);
427+
}
428+
429+
/// <summary>
430+
/// Determine if the QEXT extension is enabled in the encoder.
431+
/// </summary>
432+
/// <param name="encoder">The encoder state.</param>
433+
/// <returns>Whether the QEXT extension is enabled or not.</returns>
434+
/// <exception cref="OpusException" />
435+
/// <exception cref="ObjectDisposedException" />
436+
public static bool GetQext(this OpusEncoder encoder)
437+
{
438+
var value = 0;
439+
encoder.Ctl(EncoderCTL.OPUS_GET_QEXT, ref value);
440+
return value == 1;
441+
}
442+
417443
/// <summary>
418444
/// Resets the codec state to be equivalent to a freshly initialized state.
419445
/// </summary>

OpusSharp.Core/NativeOpus.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ public static class NativeOpus
5656
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
5757
public static extern unsafe int opus_encode(OpusEncoderSafeHandle st, short* pcm, int frame_size, byte* data, int max_data_bytes);
5858

59+
/// <summary>
60+
/// Encodes an Opus frame.
61+
/// </summary>
62+
/// <param name="st">Encoder state.</param>
63+
/// <param name="pcm">Input signal (interleaved if 2 channels) representing (or slightly exceeding) 24-bit values. length is frame_size*channels*sizeof(int)</param>
64+
/// <param name="frame_size">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.</param>
65+
/// <param name="data">Output payload. This must contain storage for at least max_data_bytes.</param>
66+
/// <param name="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 <see cref="EncoderCTL.OPUS_SET_BITRATE"/> to control the bitrate.</param>
67+
/// <returns>The length of the encoded packet (in bytes) on success or a negative error code (see <see cref="OpusErrorCodes"/>) on failure.</returns>
68+
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
69+
public static extern unsafe int opus_encode24(OpusEncoderSafeHandle st, int* pcm, int frame_size, byte* data, int max_data_bytes);
70+
5971
/// <summary>
6072
/// Encodes an Opus frame from floating point input.
6173
/// </summary>
@@ -179,6 +191,19 @@ public static class NativeOpus
179191
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
180192
public static extern unsafe int opus_decode(OpusDecoderSafeHandle st, byte* data, int len, short* pcm, int frame_size, int decode_fec);
181193

194+
/// <summary>
195+
/// Decode an Opus packet.
196+
/// </summary>
197+
/// <param name="st">Decoder state.</param>
198+
/// <param name="data">Input payload. Use a NULL pointer to indicate packet loss.</param>
199+
/// <param name="len">Number of bytes in payload.</param>
200+
/// <param name="pcm">Output signal (interleaved if 2 channels). length is frame_size*channels*sizeof(int).</param>
201+
/// <param name="frame_size">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.</param>
202+
/// <param name="decode_fec">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.</param>
203+
/// <returns>Number of decoded samples or <see cref="OpusErrorCodes"/>.</returns>
204+
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
205+
public static extern unsafe int opus_decode24(OpusDecoderSafeHandle st, byte* data, int len, int* pcm, int frame_size, int decode_fec);
206+
182207
/// <summary>
183208
/// Decode an Opus packet with floating point output.
184209
/// </summary>
@@ -338,6 +363,18 @@ public static class NativeOpus
338363
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
339364
public static extern unsafe int opus_decoder_dred_decode(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, short* pcm, int frame_size);
340365

366+
/// <summary>
367+
/// Decode audio from an <see cref="OpusDREDSafeHandle"/> packet with floating point output.
368+
/// </summary>
369+
/// <param name="st">Decoder state.</param>
370+
/// <param name="dred">DRED state.</param>
371+
/// <param name="dred_offset">position of the redundancy to decode (in samples before the beginning of the real audio data in the packet).</param>
372+
/// <param name="pcm">Output signal (interleaved if 2 channels). length is frame_size*channels*sizeof(int)</param>
373+
/// <param name="frame_size">Number of samples per channel to decode in pcm. frame_size must be a multiple of 2.5 ms.</param>
374+
/// <returns>Number of decoded samples or <see cref="OpusErrorCodes"/>.</returns>
375+
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
376+
public static extern unsafe int opus_decoder_dred_decode24(OpusDecoderSafeHandle st, OpusDREDSafeHandle dred, int dred_offset, int* pcm, int frame_size);
377+
341378
/// <summary>
342379
/// Decode audio from an <see cref="OpusDREDSafeHandle"/> packet with floating point output.
343380
/// </summary>
@@ -636,6 +673,18 @@ public static class NativeOpus
636673
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
637674
public static extern unsafe int opus_multistream_encode(OpusMSEncoderSafeHandle st, short* pcm, int frame_size, byte* data, int max_data_bytes);
638675

676+
/// <summary>
677+
/// Encodes a multistream Opus frame.
678+
/// </summary>
679+
/// <param name="st">Multistream encoder state.</param>
680+
/// <param name="pcm">The input signal as interleaved samples. This must contain frame_size*channels samples.</param>
681+
/// <param name="frame_size">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.</param>
682+
/// <param name="data">Output payload. This must contain storage for at least max_data_bytes.</param>
683+
/// <param name="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 <see cref="EncoderCTL.OPUS_SET_BITRATE"/> to control the bitrate.</param>
684+
/// <returns>The length of the encoded packet (in bytes) on success or a negative error code (see <see cref="OpusErrorCodes"/>) on failure.</returns>
685+
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
686+
public static extern unsafe int opus_multistream_encode24(OpusMSEncoderSafeHandle st, int* pcm, int frame_size, byte* data, int max_data_bytes);
687+
639688
/// <summary>
640689
/// Encodes a multistream Opus frame from floating point input.
641690
/// </summary>
@@ -766,6 +815,19 @@ public static class NativeOpus
766815
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
767816
public static extern unsafe int opus_multistream_decode(OpusMSDecoderSafeHandle st, byte* data, int len, short* pcm, int frame_size, int decode_fec);
768817

818+
/// <summary>
819+
/// Decode a multistream Opus packet.
820+
/// </summary>
821+
/// <param name="st">Multistream decoder state.</param>
822+
/// <param name="data">Input payload. Use a NULL pointer to indicate packet loss.</param>
823+
/// <param name="len">Number of bytes in payload.</param>
824+
/// <param name="pcm">Output signal, with interleaved samples. This must contain room for frame_size*channels samples.</param>
825+
/// <param name="frame_size">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.</param>
826+
/// <param name="decode_fec">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.</param>
827+
/// <returns>Number of samples decoded on success or a negative error code (see <see cref="OpusErrorCodes"/>) on failure.</returns>
828+
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
829+
public static extern unsafe int opus_multistream_decode24(OpusMSDecoderSafeHandle st, int* data, int len, short* pcm, int frame_size, int decode_fec);
830+
769831
/// <summary>
770832
/// Decode a multistream Opus packet with floating point output.
771833
/// </summary>

OpusSharp.Core/OpusDecoder.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,34 @@ public unsafe int Decode(Span<byte> input, int length, Span<short> output, int f
9999
return result;
100100
}
101101
}
102+
103+
/// <summary>
104+
/// Decodes an opus encoded frame.
105+
/// </summary>
106+
/// <param name="input">Input payload. Use null to indicate packet loss</param>
107+
/// <param name="length">Number of bytes in payload.</param>
108+
/// <param name="output">Output signal (interleaved if 2 channels). length is frame_size*channels.</param>
109+
/// <param name="frame_size">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.</param>
110+
/// <param name="decode_fec">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.</param>
111+
/// <returns>Number of decoded samples or <see cref="OpusErrorCodes"/>.</returns>
112+
/// <exception cref="OpusException" />
113+
/// <exception cref="ObjectDisposedException" />
114+
public unsafe int Decode(Span<byte> input, int length, Span<int> output, int frame_size, bool decode_fec)
115+
{
116+
ThrowIfDisposed();
117+
118+
fixed (byte* inputPtr = input)
119+
fixed (int* outputPtr = output)
120+
{
121+
var result = _useStatic
122+
? StaticNativeOpus.opus_decode24(_handler, inputPtr, length, outputPtr, frame_size,
123+
decode_fec ? 1 : 0)
124+
: NativeOpus.opus_decode24(_handler, inputPtr, length, outputPtr, frame_size,
125+
decode_fec ? 1 : 0);
126+
CheckError(result);
127+
return result;
128+
}
129+
}
102130

103131
/// <summary>
104132
/// Decodes an opus encoded frame.
@@ -156,6 +184,20 @@ public int Decode(byte[]? input, int length, byte[] output, int frame_size, bool
156184
public int Decode(byte[]? input, int length, short[] output, int frame_size, bool decode_fec) =>
157185
Decode(input.AsSpan(), length, output.AsSpan(), frame_size, decode_fec);
158186

187+
/// <summary>
188+
/// Decodes an opus encoded frame.
189+
/// </summary>
190+
/// <param name="input">Input payload. Use null to indicate packet loss</param>
191+
/// <param name="length">Number of bytes in payload.</param>
192+
/// <param name="output">Output signal (interleaved if 2 channels). length is (frame_size*channels)/2. Note: I don't know if this is correct.</param>
193+
/// <param name="frame_size">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.</param>
194+
/// <param name="decode_fec">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.</param>
195+
/// <returns>Number of decoded samples or <see cref="OpusErrorCodes"/>.</returns>
196+
/// <exception cref="OpusException" />
197+
/// <exception cref="ObjectDisposedException" />
198+
public int Decode(byte[]? input, int length, int[] output, int frame_size, bool decode_fec) =>
199+
Decode(input.AsSpan(), length, output.AsSpan(), frame_size, decode_fec);
200+
159201
/// <summary>
160202
/// Decodes an opus encoded frame.
161203
/// </summary>

0 commit comments

Comments
 (0)