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
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 |
|
} |
|
} |