You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
19 KiB
448 lines
19 KiB
4 years ago
|
using System;
|
||
|
using System.Runtime.InteropServices;
|
||
|
|
||
|
namespace AX.AudioSystem
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Opus C API Bindings。具体请参考 http://www.opus-codec.org/docs/。
|
||
|
/// </summary>
|
||
|
internal static class OpusNative
|
||
|
{
|
||
|
#region Opus Encoder
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_encoder_get_size(int channels);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern IntPtr opus_encoder_create(int Fs, int channels, int application, out int error);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_encoder_init(IntPtr st, int Fs, int channels, int application);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_encode(IntPtr st, short* pcm, int frame_size, byte* data, int max_data_bytes);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_encode_float(IntPtr st, float* pcm, int frame_size, byte* data, int max_data_bytes);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern void opus_encoder_destroy(IntPtr st);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_encoder_ctl(IntPtr st, int request);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_encoder_get_ctl(IntPtr st, int request, out int value);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_encoder_set_ctl(IntPtr st, int request, int value);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_encoder_reset(IntPtr st);
|
||
|
|
||
|
public static IntPtr OpusEncoderCreate(SamplingRate Fs, Channel channels, OpusApplication application)
|
||
|
{
|
||
|
var size = opus_encoder_get_size((int)channels);
|
||
|
var intptr = Marshal.AllocHGlobal(size);
|
||
|
var error = opus_encoder_init(intptr, (int)Fs, (int)channels, (int)application);
|
||
|
|
||
|
if (error != (int)OpusErrorCode.OK && intptr != IntPtr.Zero)
|
||
|
{
|
||
|
OpusEncoderDestroy(intptr);
|
||
|
ThrowOpusException(error);
|
||
|
}
|
||
|
|
||
|
return intptr;
|
||
|
}
|
||
|
|
||
|
public static void OpusEncoderDestroy(IntPtr st)
|
||
|
{
|
||
|
Marshal.FreeHGlobal(st);
|
||
|
}
|
||
|
|
||
|
public static int OpusEncode(IntPtr st, short[] pcm, int frame_size, byte[] data)
|
||
|
{
|
||
|
return OpusEncode(st, pcm, 0, frame_size, data);
|
||
|
}
|
||
|
|
||
|
public static unsafe int OpusEncode(IntPtr st, short[] pcm, int pcmOffset, int frame_size, byte[] data)
|
||
|
{
|
||
|
fixed (short* pcmPtr = &pcm[pcmOffset])
|
||
|
fixed (byte* dataPtr = &data[0])
|
||
|
{
|
||
|
var result = opus_encode(st, pcmPtr, frame_size, dataPtr, data.Length);
|
||
|
|
||
|
if (result < 0)
|
||
|
ThrowOpusException(result);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static int OpusEncode(IntPtr st, float[] pcm, int frame_size, byte[] data)
|
||
|
{
|
||
|
return OpusEncode(st, pcm, 0, frame_size, data);
|
||
|
}
|
||
|
|
||
|
public static unsafe int OpusEncode(IntPtr st, float[] pcm, int pcmOffset, int frame_size, byte[] data)
|
||
|
{
|
||
|
fixed (float* pcmPtr = &pcm[pcmOffset])
|
||
|
fixed (byte* dataPtr = &data[0])
|
||
|
{
|
||
|
var result = opus_encode_float(st, pcmPtr, frame_size, dataPtr, data.Length);
|
||
|
|
||
|
if (result < 0)
|
||
|
ThrowOpusException(result);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static int OpusEncoderGetCtl(IntPtr st, OpusEncoderGetRequest request)
|
||
|
{
|
||
|
int result = 0;
|
||
|
|
||
|
var error = opus_encoder_get_ctl(st, (int)request, out result);
|
||
|
|
||
|
if (error != (int)OpusErrorCode.OK)
|
||
|
ThrowOpusException(error);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public static void OpusEncoderSetCtl(IntPtr st, OpusEncoderSetRequest request, int value)
|
||
|
{
|
||
|
var error = opus_encoder_set_ctl(st, (int)request, value);
|
||
|
|
||
|
if (error != (int)OpusErrorCode.OK)
|
||
|
ThrowOpusException(error);
|
||
|
}
|
||
|
|
||
|
public static void OpusEncoderReset(IntPtr st)
|
||
|
{
|
||
|
var error = opus_encoder_reset(st);
|
||
|
|
||
|
if (error != (int)OpusErrorCode.OK)
|
||
|
ThrowOpusException(error);
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Opus Decoder
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_decoder_get_size(int channels);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern IntPtr opus_decoder_create(int Fs, int channels, out int error);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_decoder_init(IntPtr st, int Fs, int channels);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_decode(IntPtr st, byte* data, int len, short* pcm, int frame_size, int decode_fec);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_decode_float(IntPtr st, byte* data, int len, float* pcm, int frame_size, int decode_fec);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_decoder_ctl(IntPtr st, int request);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_decoder_get_ctl(IntPtr st, int request, out int value);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_decoder_set_ctl(IntPtr st, int request, int value);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_decoder_reset(IntPtr st);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern void opus_decoder_destroy(IntPtr st);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_packet_parse(byte* data, int len, byte* out_toc, [MarshalAs(UnmanagedType.LPArray, SizeConst = 48)]byte[] frames, [MarshalAs(UnmanagedType.LPArray, SizeConst = 48 * 2)]short[] size, int* payload_offset);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_packet_get_bandwidth(byte[] data);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_packet_get_samples_per_frame(byte[] data, int Fs);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_packet_get_nb_channels(byte[] data);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_packet_get_nb_frames(byte[] packet, int len);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_packet_get_nb_samples(byte[] packet, int len, int Fs);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_decoder_get_nb_samples(IntPtr dec, byte[] packet, int len);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe void opus_pcm_soft_clip(float* pcm, int frame_size, int channels, float* softclip_mem);
|
||
|
|
||
|
public static IntPtr OpusDecoderCreate(SamplingRate Fs, Channel channels)
|
||
|
{
|
||
|
var size = opus_decoder_get_size((int)channels);
|
||
|
var intptr = Marshal.AllocHGlobal(size);
|
||
|
var error = opus_decoder_init(intptr, (int)Fs, (int)channels);
|
||
|
|
||
|
if (error != (int)OpusErrorCode.OK && intptr != IntPtr.Zero)
|
||
|
{
|
||
|
OpusDecoderDestroy(intptr);
|
||
|
ThrowOpusException(error);
|
||
|
}
|
||
|
|
||
|
return intptr;
|
||
|
}
|
||
|
|
||
|
public static void OpusDecoderDestroy(IntPtr st)
|
||
|
{
|
||
|
Marshal.FreeHGlobal(st);
|
||
|
}
|
||
|
|
||
|
public static unsafe int OpusDecode(IntPtr st, byte[] data, short[] pcm, int channels, int decode_fec)
|
||
|
{
|
||
|
if (st == IntPtr.Zero)
|
||
|
throw new ObjectDisposedException("OpusDecoder");
|
||
|
|
||
|
int samplesDecoded = 0;
|
||
|
|
||
|
fixed (short* pcmPtr = &pcm[0])
|
||
|
{
|
||
|
if (data != null)
|
||
|
{
|
||
|
fixed (byte* dataPtr = &data[0])
|
||
|
{
|
||
|
samplesDecoded = opus_decode(st, dataPtr, data.Length, pcmPtr, pcm.Length / channels, decode_fec);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
samplesDecoded = opus_decode(st, null, 0, pcmPtr, pcm.Length / channels, decode_fec);
|
||
|
}
|
||
|
|
||
|
if (samplesDecoded == (int)OpusErrorCode.InvalidPacket)
|
||
|
return 0;
|
||
|
|
||
|
if (samplesDecoded <= (int)OpusErrorCode.OK)
|
||
|
ThrowOpusException(samplesDecoded);
|
||
|
|
||
|
return samplesDecoded;
|
||
|
}
|
||
|
|
||
|
public static unsafe int OpusDecode(IntPtr st, byte[] data, float[] pcm, int channels, int decode_fec)
|
||
|
{
|
||
|
if (st == IntPtr.Zero)
|
||
|
throw new ObjectDisposedException("OpusDecoder");
|
||
|
|
||
|
int samplesDecoded = 0;
|
||
|
|
||
|
fixed (float* pcmPtr = &pcm[0])
|
||
|
{
|
||
|
if (data != null)
|
||
|
{
|
||
|
fixed (byte* dataPtr = &data[0])
|
||
|
{
|
||
|
samplesDecoded = opus_decode_float(st, dataPtr, data.Length, pcmPtr, pcm.Length / channels, decode_fec);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
samplesDecoded = opus_decode_float(st, null, 0, pcmPtr, pcm.Length / channels, decode_fec);
|
||
|
}
|
||
|
|
||
|
if (samplesDecoded == (int)OpusErrorCode.InvalidPacket)
|
||
|
return 0;
|
||
|
|
||
|
if (samplesDecoded <= (int)OpusErrorCode.OK)
|
||
|
ThrowOpusException(samplesDecoded);
|
||
|
|
||
|
return samplesDecoded;
|
||
|
}
|
||
|
|
||
|
public static int OpusDecoderGetCtl(IntPtr st, OpusDecoderGetRequest request)
|
||
|
{
|
||
|
int result = 0;
|
||
|
|
||
|
var error = opus_decoder_get_ctl(st, (int)request, out result);
|
||
|
|
||
|
if (error != (int)OpusErrorCode.OK)
|
||
|
ThrowOpusException(error);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public static void OpusDecoderSetCtl(IntPtr st, OpusDecoderSetRequest request, int value)
|
||
|
{
|
||
|
var error = opus_decoder_set_ctl(st, (int)request, value);
|
||
|
|
||
|
if (error != (int)OpusErrorCode.OK)
|
||
|
ThrowOpusException(error);
|
||
|
}
|
||
|
|
||
|
public static void OpusDecoderReset(IntPtr st)
|
||
|
{
|
||
|
var error = opus_decoder_reset(st);
|
||
|
|
||
|
if (error != (int)OpusErrorCode.OK)
|
||
|
ThrowOpusException(error);
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Repacketizer
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_repacketizer_get_size();
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern IntPtr opus_repacketizer_init(IntPtr rp);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern IntPtr opus_repacketizer_create();
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern void opus_repacketizer_destroy(IntPtr rp);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_repacketizer_cat(IntPtr rp, byte* data, int len);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_repacketizer_out_range(IntPtr rp, int begin, int end, byte* data, int maxlen);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_repacketizer_get_nb_frames(IntPtr rp);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_repacketizer_out(IntPtr rp, byte* data, int maxlen);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_packet_pad(byte* data, int len, int new_len);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_packet_unpad(byte* data, int len);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_multistream_packet_pad(byte* data, int len, int new_len, int nb_streams);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_multistream_packet_unpad(byte* data, int len, int nb_streams);
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Opus Multistream API
|
||
|
|
||
|
#region Multistream encoder functions
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_encoder_get_size(int streams, int coupled_streams);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_surround_encoder_get_size(int channels, int mapping_family);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe IntPtr opus_multistream_encoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, int application, out int error);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe IntPtr opus_multistream_surround_encoder_create(int Fs, int channels, int mapping_family, int* streams, int* coupled_streams, byte* mapping, int application, out int error);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_multistream_encoder_init(IntPtr st, int Fs, int channels, int streams, int coupled_streams, byte* mapping, int application);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_multistream_surround_encoder_init(IntPtr st, int Fs, int channels, int mapping_family, int* streams, int* coupled_streams, byte* mapping, int application);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_multistream_encode(IntPtr st, short* pcm, int frame_size, byte* data, int max_data_bytes);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_multistream_encode_float(IntPtr st, float* pcm, int frame_size, byte* data, int max_data_bytes);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern void opus_multistream_encoder_destroy(IntPtr st);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_encoder_ctl(IntPtr st, int request);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_encoder_get_ctl(IntPtr st, int request, out int value);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_encoder_set_ctl(IntPtr st, int request, int value);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_encoder_reset(IntPtr st);
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Multistream decoder functions
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_decoder_get_size(int streams, int coupled_streams);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe IntPtr opus_multistream_decoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, out int error);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_multistream_decoder_init(IntPtr st, int Fs, int channels, int streams, int coupled_streams, byte* mapping);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_multistream_decode(IntPtr st, byte* data, int len, short* pcm, int frame_size, int decode_fec);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern unsafe int opus_multistream_decode_float(IntPtr st, byte* data, int len, float* pcm, int frame_size, int decode_fec);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_decoder_ctl(IntPtr st, int request);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_decoder_get_ctl(IntPtr st, int request, out int value);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_decoder_set_ctl(IntPtr st, int request, int value);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern int opus_multistream_decoder_reset(IntPtr st);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern void opus_multistream_decoder_destroy(IntPtr st);
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Opus library information functions
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern IntPtr opus_strerror(int error);
|
||
|
|
||
|
[DllImport("opus", CallingConvention = CallingConvention.Cdecl)]
|
||
|
internal static extern IntPtr opus_get_version_string();
|
||
|
|
||
|
public static string OpusStringError(OpusErrorCode errorCode)
|
||
|
{
|
||
|
return Marshal.PtrToStringAnsi(opus_strerror((int)errorCode));
|
||
|
}
|
||
|
|
||
|
public static string OpusGetVersionString()
|
||
|
{
|
||
|
return Marshal.PtrToStringAnsi(opus_get_version_string());
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Opus Custom
|
||
|
#endregion
|
||
|
|
||
|
#region Others
|
||
|
|
||
|
public static void ThrowOpusException(int error)
|
||
|
{
|
||
|
throw new OpusException((OpusErrorCode)error, OpusStringError((OpusErrorCode)error));
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
}
|
||
|
}
|