using System;
namespace Opus.Net
{
/// Opus codec wrapper.
public class OpusEncoder : IDisposable
{
private readonly IntPtr _encoder;
/// Gets the bit rate of the encoder.
public const int BitRate = 16;
/// Gets the input sampling rate of the encoder.
public int InputSamplingRate { get; private set; }
/// Gets the number of channels of the encoder.
public int InputChannels { get; private set; }
/// Gets the milliseconds per frame.
public int FrameLength { get; private set; }
/// Gets the number of samples per frame.
public int SamplesPerFrame { get; private set; }
/// Gets the bytes per sample.
public int SampleSize { get; private set; }
/// Gets the bytes per frame.
public int FrameSize { get; private set; }
/// Gets the coding mode of the encoder.
public Application Application { get; private set; }
/// Creates a new Opus encoder.
/// Sampling rate of the input signal (Hz). Supported Values: 8000, 12000, 16000, 24000, or 48000.
/// Number of channels (1 or 2) in input signal.
/// Length, in milliseconds, that each frame takes. Supported Values: 2.5, 5, 10, 20, 40, 60
/// Coding mode.
/// A new OpusEncoder
public OpusEncoder(int samplingRate, int channels, int frameLength, Application application)
{
if (samplingRate != 8000 && samplingRate != 12000 &&
samplingRate != 16000 && samplingRate != 24000 &&
samplingRate != 48000)
throw new ArgumentOutOfRangeException("inputSamplingRate");
if (channels != 1 && channels != 2)
throw new ArgumentOutOfRangeException("inputChannels");
InputSamplingRate = samplingRate;
InputChannels = channels;
Application = application;
FrameLength = frameLength;
SampleSize = (BitRate / 8) * channels;
SamplesPerFrame = samplingRate / 1000 * FrameLength;
FrameSize = SamplesPerFrame * SampleSize;
Error error;
_encoder = API.opus_encoder_create(samplingRate, channels, (int)application, out error);
if (error != Error.OK)
throw new InvalidOperationException("Error occured while creating encoder: " + error.ToString());
SetForwardErrorCorrection(true);
}
/// Produces Opus encoded audio from PCM samples.
/// PCM samples to encode.
/// Length of encoded audio.
/// Opus encoded audio buffer.
public unsafe int EncodeFrame(byte[] pcmSamples, byte[] outputBuffer)
{
if (disposed)
throw new ObjectDisposedException("OpusEncoder");
IntPtr encodedPtr;
int length = 0;
fixed (byte* bPtr = outputBuffer)
{
encodedPtr = new IntPtr((void*)bPtr);
length = API.opus_encode(_encoder, pcmSamples, SamplesPerFrame, encodedPtr, outputBuffer.Length);
}
if (length < 0)
throw new Exception("Encoding failed: " + ((Error)length).ToString());
return length;
}
/// Gets or sets whether Forward Error Correction is enabled.
public void SetForwardErrorCorrection(bool value)
{
if (_encoder == IntPtr.Zero)
throw new ObjectDisposedException("OpusEncoder");
var ret = API.opus_encoder_ctl(_encoder, Ctl.SetInbandFECRequest, value ? 1 : 0);
if (ret < 0)
throw new Exception("Encoder error - " + ((Error)ret).ToString());
}
private bool disposed;
public void Dispose()
{
if (disposed)
return;
GC.SuppressFinalize(this);
if (_encoder != IntPtr.Zero)
API.opus_encoder_destroy(_encoder);
disposed = true;
}
~OpusEncoder()
{
Dispose();
}
}
}