diff --git a/src/JT1078.Flv/Audio/AdpcmCodec.cs b/src/JT1078.Flv/Audio/AdpcmCodec.cs
new file mode 100644
index 0000000..cc325d9
--- /dev/null
+++ b/src/JT1078.Flv/Audio/AdpcmCodec.cs
@@ -0,0 +1,265 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Audio
+{
+    public class State
+    {
+        /// <summary>
+        /// 上一个采样数据,当index为0是该值应该为未压缩的原数据
+        /// </summary>
+        public short Valprev { get; set; }
+
+        /// <summary>
+        /// 保留数据(未使用)
+        /// </summary>
+        public byte Reserved { get; set; }
+
+        /// <summary>
+        /// 上一个block最后一个index,第一个block的index=0
+        /// </summary>
+        public byte Index { get; set; }
+    }
+    public class AdpcmCodec
+    {
+        static readonly int[] indexTable = {
+            -1, -1, -1, -1, 2, 4, 6, 8,
+            -1, -1, -1, -1, 2, 4, 6, 8
+        };
+
+        static readonly int[] stepsizeTable = {
+            7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+            19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+            50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+            130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+            337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+            876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+            2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+            5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+            15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+        };
+        public static byte[] ToAdpcm(short[] indata, State state)
+        {
+            int val;            /* Current input sample value */
+            int sign;           /* Current adpcm sign bit */
+            int delta;          /* Current adpcm output value */
+            int diff;           /* Difference between val and valprev */
+            int step;           /* Stepsize */
+            int valpred;        /* Predicted output value */
+            int vpdiff;         /* Current change to valpred */
+            int index;          /* Current step change index */
+            int outputbuffer = 0;       /* place to keep previous 4-bit value */
+            int bufferstep;     /* toggle between outputbuffer/output */
+
+            List<byte> outp = new List<byte>();
+            short[] inp = indata;
+            var len = indata.Length;
+            valpred = state.Valprev;
+            index = state.Index;
+            step = stepsizeTable[index];
+
+            bufferstep = 1;
+
+            int k = 0;
+            for (int i = 0; len > 0; len--, i++)
+            {
+                val = inp[i];
+
+                /* Step 1 - compute difference with previous value */
+                diff = val - valpred;
+                sign = (diff < 0) ? 8 : 0;
+                if (sign != 0) diff = (-diff);
+
+                /* Step 2 - Divide and clamp */
+                /* Note:
+                ** This code *approximately* computes:
+                **    delta = diff*4/step;
+                **    vpdiff = (delta+0.5)*step/4;
+                ** but in shift step bits are dropped. The net result of this is
+                ** that even if you have fast mul/div hardware you cannot put it to
+                ** good use since the fixup would be too expensive.
+                */
+                delta = 0;
+                vpdiff = (step >> 3);
+
+                if (diff >= step)
+                {
+                    delta = 4;
+                    diff -= step;
+                    vpdiff += step;
+                }
+                step >>= 1;
+                if (diff >= step)
+                {
+                    delta |= 2;
+                    diff -= step;
+                    vpdiff += step;
+                }
+                step >>= 1;
+                if (diff >= step)
+                {
+                    delta |= 1;
+                    vpdiff += step;
+                }
+
+                /* Step 3 - Update previous value */
+                if (sign != 0)
+                    valpred -= vpdiff;
+                else
+                    valpred += vpdiff;
+
+                /* Step 4 - Clamp previous value to 16 bits */
+                if (valpred > 32767)
+                    valpred = 32767;
+                else if (valpred < -32768)
+                    valpred = -32768;
+
+                /* Step 5 - Assemble value, update index and step values */
+                delta |= sign;
+
+                index += indexTable[delta];
+                if (index < 0) index = 0;
+                if (index > 88) index = 88;
+                step = stepsizeTable[index];
+
+                /* Step 6 - Output value */
+                if (bufferstep != 0)
+                {
+                    outputbuffer = (delta << 4) & 0xf0;
+                }
+                else
+                {
+                    outp.Add((byte)((delta & 0x0f) | outputbuffer));
+                }
+                bufferstep = bufferstep == 0 ? 1 : 0;
+            }
+
+            /* Output last step, if needed */
+            if (bufferstep == 0)
+                outp.Add((byte)outputbuffer);
+
+            state.Valprev = (short)valpred;
+            state.Index = (byte)index;
+            return outp.ToArray();
+        }
+
+        /// <summary>
+        /// 将adpcm转为pcm
+        /// </summary>
+        /// <see cref="https://github.com/ctuning/ctuning-programs/blob/master/program/cbench-telecom-adpcm-d/adpcm.c"/>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        public byte[] ToPcm(byte[] data, State state)
+        {
+            // signed char *inp;		/* Input buffer pointer */
+            // short *outp;		/* output buffer pointer */
+            int sign;           /* Current adpcm sign bit */
+            int delta;          /* Current adpcm output value */
+            int step;           /* Stepsize */
+            int valpred = state.Valprev;        /* Predicted value */
+            int vpdiff;         /* Current change to valpred */
+            byte index = state.Index;          /* Current step change index */
+            int inputbuffer = 0;        /* place to keep next 4-bit value */
+            bool bufferstep = false;     /* toggle between inputbuffer/input */
+
+            step = stepsizeTable[index];
+
+            var outdata = new List<byte>();
+            var len = data.Length * 2;
+            for (int i = 0; len > 0; len--)
+            {
+                /* Step 1 - get the delta value */
+                if (bufferstep)
+                {
+                    delta = inputbuffer & 0xf;
+                }
+                else
+                {
+                    inputbuffer = data[i++];
+                    delta = (inputbuffer >> 4) & 0xf;
+                }
+                bufferstep = !bufferstep;
+
+                /* Step 2 - Find new index value (for later) */
+                index += (byte)indexTable[delta];
+                if (index < 0) index = 0;
+                if (index > 88) index = 88;
+
+                /* Step 3 - Separate sign and magnitude */
+                sign = delta & 8;
+                delta &= 7;
+
+                /* Step 4 - Compute difference and new predicted value */
+                /*
+                ** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
+                ** in adpcm_coder.
+                */
+                vpdiff = step >> 3;
+                if ((delta & 4) > 0) vpdiff += step;
+                if ((delta & 2) > 0) vpdiff += step >> 1;
+                if ((delta & 1) > 0) vpdiff += step >> 2;
+
+                if (sign != 0)
+                    valpred -= vpdiff;
+                else
+                    valpred += vpdiff;
+
+                /* Step 5 - clamp output value */
+                if (valpred > 32767)
+                    valpred = 32767;
+                else if (valpred < -32768)
+                    valpred = -32768;
+
+                /* Step 6 - Update step value */
+                step = stepsizeTable[index];
+
+                /* Step 7 - Output value */
+                outdata.AddRange(BitConverter.GetBytes((short)valpred));
+            }
+            state.Valprev = (short)valpred;
+            state.Index = index;
+            return outdata.ToArray();
+        }
+    }
+
+    public static class AdpcmDecoderExtension
+    {
+        /// <summary>
+        /// 添加wav头
+        /// 仅用于测试pcm是否转成成功,因此没考虑性能,因为播放器可播——#
+        /// </summary>
+        /// <param name="input">pcm数据</param>
+        /// <param name="frequency">采样率</param>
+        /// <param name="bitDepth">位深</param>
+        /// <returns></returns>
+        public static byte[] ToWav(this byte[] input, uint frequency, byte bitDepth = 16)
+        {
+            byte[] output = new byte[input.Length + 44];
+            Array.Copy(Encoding.ASCII.GetBytes("RIFF"), 0, output, 0, 4);
+            WriteUint(4, (uint)output.Length - 8, output);
+            Array.Copy(Encoding.ASCII.GetBytes("WAVE"), 0, output, 8, 4);
+            Array.Copy(Encoding.ASCII.GetBytes("fmt "), 0, output, 12, 4);
+            WriteUint(16, 16, output); //Header size
+            output[20] = 1; //PCM
+            output[22] = 1; //1 channel
+            WriteUint(24, frequency, output); //Sample Rate
+            WriteUint(28, (uint)(frequency * (bitDepth / 8)), output); //Bytes per second
+            output[32] = (byte)(bitDepth >> 3); //Bytes per sample
+            output[34] = bitDepth; //Bits per sample
+            Array.Copy(Encoding.ASCII.GetBytes("data"), 0, output, 36, 4);
+            WriteUint(40, (uint)output.Length, output); //Date size
+            Array.Copy(input, 0, output, 44, input.Length);
+            return output;
+        }
+
+        private static void WriteUint(uint offset, uint value, byte[] destination)
+        {
+            for (int i = 0; i < 4; i++)
+            {
+                destination[offset + i] = (byte)(value & 0xFF);
+                value >>= 8;
+            }
+        }
+    }
+}
diff --git a/src/JT1078.Flv/Audio/FaacEncoder.cs b/src/JT1078.Flv/Audio/FaacEncoder.cs
new file mode 100644
index 0000000..50a58ef
--- /dev/null
+++ b/src/JT1078.Flv/Audio/FaacEncoder.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Linq;
+using System.Runtime.InteropServices;
+using JT1078.Flv.Extensions;
+
+namespace JT1078.Flv.Audio
+{
+    public class FaacEncoder : IDisposable
+    {
+        private IntPtr faacEncHandle = IntPtr.Zero;
+        private readonly int inputSamples;
+        private readonly int maxOutput;
+        public readonly int frameSize;
+        private List<byte> frameCache = new List<byte>();
+        public FaacEncoder(int sampleRate, int channels, int sampleBit)
+        {
+            var inputSampleBytes = new byte[4];
+            var maxOutputBytes = new byte[4];
+
+            faacEncHandle = FaacEncOpen(sampleRate, channels, inputSampleBytes, maxOutputBytes);
+            inputSamples = BitConverter.ToInt32(inputSampleBytes, 0);
+            maxOutput = BitConverter.ToInt32(maxOutputBytes, 0);
+            frameSize = inputSamples * channels * sampleBit / 8;
+
+            var ptr = FaacEncGetCurrentConfiguration(faacEncHandle);
+            var configuration = InteropExtensions.IntPtrToStruct<FaacEncConfiguration>(ptr);
+            configuration.inputFormat = 1;
+            configuration.outputFormat = 0;
+            configuration.useTns = 0;
+            configuration.useLfe = 0;
+            configuration.aacObjectType = 2;
+            configuration.shortctl = 0;
+            configuration.quantqual = 100;
+            configuration.bandWidth = 0;
+            configuration.bitRate = 0;
+            InteropExtensions.IntPtrSetValue(ptr, configuration);
+
+            if (FaacEncSetConfiguration(faacEncHandle, ptr) < 0) throw new Exception("set faac configuration failed!");
+        }
+
+        public byte[] Encode(byte[] bytes)
+        {
+            frameCache.AddRange(bytes);
+            if (frameCache.Count() < frameSize)//faac必须达到一帧数据后才能正常编码
+                return new byte[0];
+            var outputBytes = new byte[maxOutput];
+            var len = FaacEncEncode(faacEncHandle, frameCache.Take(frameSize).ToArray(), inputSamples, outputBytes, maxOutput);
+            frameCache = frameCache.Skip(frameSize).ToList();
+            if (len <= 0)
+                return new byte[0];
+            return outputBytes.Take(len).ToArray();
+        }
+
+        public void Dispose()
+        {
+            if (faacEncHandle != IntPtr.Zero)
+            {
+                FaacEncClose(faacEncHandle);
+                faacEncHandle = IntPtr.Zero;
+            }
+        }
+
+
+
+        const string DLLFile = @"Libs/libfaac.dll";
+
+        [DllImport(DLLFile, EntryPoint = "faacEncGetVersion", CallingConvention = CallingConvention.StdCall)]
+        //int FAACAPI faacEncGetVersion(char **faac_id_string, char **faac_copyright_string);
+        private extern static int FaacEncGetVersion(ref IntPtr faac_id_string, ref IntPtr faac_copyright_string);
+
+
+
+        [DllImport(DLLFile, EntryPoint = "faacEncGetCurrentConfiguration", CallingConvention = CallingConvention.StdCall)]
+        //faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(faacEncHandle hEncoder);
+        private extern static IntPtr FaacEncGetCurrentConfiguration(IntPtr hEncoder);
+
+
+        [DllImport(DLLFile, EntryPoint = "faacEncSetConfiguration", CallingConvention = CallingConvention.StdCall)]
+        //int FAACAPI faacEncSetConfiguration(faacEncHandle hEncoder,faacEncConfigurationPtr config);
+        private extern static int FaacEncSetConfiguration(IntPtr hEncoder, IntPtr config);
+
+        [DllImport(DLLFile, EntryPoint = "faacEncOpen", CallingConvention = CallingConvention.StdCall)]
+        //faacEncHandle FAACAPI faacEncOpen(unsigned long sampleRate, unsigned int numChannels, unsigned long *inputSamples, unsigned long *maxOutputBytes);
+        private extern static IntPtr FaacEncOpen(int sampleRate, int numChannels, byte[] inputSamples, byte[] maxOutputBytes);
+
+
+        [DllImport(DLLFile, EntryPoint = "faacEncGetDecoderSpecificInfo", CallingConvention = CallingConvention.StdCall)]
+        //int FAACAPI faacEncGetDecoderSpecificInfo(faacEncHandle hEncoder, unsigned char **ppBuffer,unsigned long *pSizeOfDecoderSpecificInfo);
+        private extern static IntPtr FaacEncGetDecoderSpecificInfo(IntPtr hEncoder, ref IntPtr ppBuffer, ref int pSizeOfDecoderSpecificInfo);
+
+
+        [DllImport(DLLFile, EntryPoint = "faacEncEncode", CallingConvention = CallingConvention.StdCall)]
+        //int FAACAPI faacEncEncode(faacEncHandle hEncoder, int32_t * inputBuffer, unsigned int samplesInput, unsigned char *outputBuffer, unsigned int bufferSize);
+        private extern static int FaacEncEncode(IntPtr hEncoder, IntPtr inputBuffer, int samplesInput, IntPtr outputBuffer, int bufferSize);
+        [DllImport(DLLFile, EntryPoint = "faacEncEncode", CallingConvention = CallingConvention.StdCall)]
+        private extern static int FaacEncEncode(IntPtr hEncoder, byte[] inputBuffer, int samplesInput, byte[] outputBuffer, int bufferSize);
+
+        [DllImport(DLLFile, EntryPoint= "faacEncClose", CallingConvention = CallingConvention.StdCall)]
+        //int FAACAPI faacEncClose(faacEncHandle hEncoder);
+        private extern static IntPtr FaacEncClose(IntPtr hEncoder);
+
+        #region 配置结构
+        [StructLayout(LayoutKind.Sequential, Pack = 1)]
+        private struct FaacEncConfiguration
+        {
+            /* config version */
+
+            public int version;
+
+            /* library version */
+            public IntPtr name;
+
+            /* copyright string */
+            public IntPtr copyright;
+
+            /* MPEG version, 2 or 4 */
+            public uint mpegVersion;
+
+            /* AAC object type
+             *  #define MAIN 1
+                #define LOW  2
+                #define SSR  3
+                #define LTP  4
+             * */
+
+            public uint aacObjectType;
+
+            /* Allow mid/side coding */
+            public uint allowMidside;
+
+            /* Use one of the channels as LFE channel */
+            public uint useLfe;
+
+            /* Use Temporal Noise Shaping */
+            public uint useTns;
+
+            /* bitrate / channel of AAC file */
+            public uint bitRate;
+
+            /* AAC file frequency bandwidth */
+            public uint bandWidth;
+
+            /* Quantizer quality */
+            public uint quantqual;
+
+            /* Bitstream output format (0 = Raw; 1 = ADTS) */
+            public int outputFormat;
+
+            /* psychoacoustic model list */
+            public IntPtr psymodellist;
+
+            /* selected index in psymodellist */
+            public int psymodelidx;
+
+            /*
+                PCM Sample Input Format
+                0	FAAC_INPUT_NULL			invalid, signifies a misconfigured config
+                1	FAAC_INPUT_16BIT		native endian 16bit
+                2	FAAC_INPUT_24BIT		native endian 24bit in 24 bits		(not implemented)
+                3	FAAC_INPUT_32BIT		native endian 24bit in 32 bits		(DEFAULT)
+                4	FAAC_INPUT_FLOAT		32bit floating point
+            */
+            public int inputFormat;
+
+            /* block type enforcing (SHORTCTL_NORMAL/SHORTCTL_NOSHORT/SHORTCTL_NOLONG) */
+            // #define FAAC_INPUT_NULL    0
+            //#define FAAC_INPUT_16BIT   1
+            //#define FAAC_INPUT_24BIT   2
+            //#define FAAC_INPUT_32BIT   3
+            //#define FAAC_INPUT_FLOAT   4
+
+            //#define SHORTCTL_NORMAL    0
+            //#define SHORTCTL_NOSHORT   1
+            //#define SHORTCTL_NOLONG    2
+            public int shortctl;
+
+            /*
+                Channel Remapping
+
+                Default			0, 1, 2, 3 ... 63  (64 is MAX_CHANNELS in coder.h)
+
+                WAVE 4.0		2, 0, 1, 3
+                WAVE 5.0		2, 0, 1, 3, 4
+                WAVE 5.1		2, 0, 1, 4, 5, 3
+                AIFF 5.1		2, 0, 3, 1, 4, 5 
+            */
+            [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 64)]
+            public int[] channel_map;
+
+        }
+        #endregion
+    }
+}
diff --git a/src/JT1078.Flv/Audio/G711ACodec.cs b/src/JT1078.Flv/Audio/G711ACodec.cs
new file mode 100644
index 0000000..8344c83
--- /dev/null
+++ b/src/JT1078.Flv/Audio/G711ACodec.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Audio
+{
+    public class G711ACodec
+    {
+        private readonly int SIGN_BIT = 0x80;
+        private readonly int QUANT_MASK = 0xf;
+        private readonly int SEG_SHIFT = 4;
+        private readonly int SEG_MASK = 0x70;
+        private readonly short[] seg_end = { 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF };
+
+        static short Search(short val, short[] table, short size)
+        {
+            for (short i = 0; i < size; i++)
+            {
+                if (val <= table[i])
+                {
+                    return i;
+                }
+            }
+            return size;
+        }
+
+        byte LinearToAlaw(short pcm_val)
+        {
+            short mask;
+            short seg;
+            char aval;
+            if (pcm_val >= 0)
+            {
+                mask = 0xD5;
+            }
+            else
+            {
+                mask = 0x55;
+                pcm_val = (short)(-pcm_val - 1);
+                if (pcm_val < 0)
+                {
+                    pcm_val = 32767;
+                }
+            }
+
+            //Convert the scaled magnitude to segment number.
+            seg = Search(pcm_val, seg_end, 8);
+
+            //Combine the sign, segment, and quantization bits.
+            if (seg >= 8)
+            {
+                //out of range, return maximum value.
+                return (byte)(0x7F ^ mask);
+            }
+            else
+            {
+                aval = (char)(seg << SEG_SHIFT);
+                if (seg < 2) aval |= (char)((pcm_val >> 4) & QUANT_MASK);
+                else aval |= (char)((pcm_val >> (seg + 3)) & QUANT_MASK);
+                return (byte)(aval ^ mask);
+            }
+        }
+
+
+        short AlawToLinear(byte value)
+        {
+            short t;
+            short seg;
+
+            value ^= 0x55;
+
+            t = (short)((value & QUANT_MASK) << 4);
+            seg = (short)((value & SEG_MASK) >> SEG_SHIFT);
+            switch (seg)
+            {
+                case 0:
+                    t += 8;
+                    break;
+                case 1:
+                    t += 0x108;
+                    break;
+                default:
+                    t += 0x108;
+                    t <<= seg - 1;
+                    break;
+            }
+            return (value & SIGN_BIT) != 0 ? t : (short)-t;
+        }
+
+        /// <summary>
+        /// 转至PCM
+        /// </summary>
+        /// <param name="g711data"></param>
+        /// <returns></returns>
+        public byte[] ToPcm(byte[] g711data)
+        {
+            byte[] pcmdata = new byte[g711data.Length * 2];
+            for (int i = 0, offset = 0; i < g711data.Length; i++)
+            {
+                short value = AlawToLinear(g711data[i]);
+                pcmdata[offset++] = (byte)((value >> 8) & 0xff);
+                pcmdata[offset++] = (byte)(value & 0xff);
+            }
+            return pcmdata;
+        }
+
+        /// <summary>
+        /// 转至G711
+        /// </summary>
+        /// <param name="pcmdata"></param>
+        /// <returns></returns>
+        public byte[] ToG711(byte[] pcmdata)
+        {
+            byte[] g711data = new byte[pcmdata.Length / 2];
+            for (int i = 0, k = 0; i < pcmdata.Length; i += 2, k++)
+            {
+                short v = (short)((pcmdata[i + 1] << 8) | (pcmdata[i]));
+                g711data[k] = LinearToAlaw(v);
+            }
+            return g711data;
+        }
+    }
+}
diff --git a/src/JT1078.Flv/Audio/G711UCodec.cs b/src/JT1078.Flv/Audio/G711UCodec.cs
new file mode 100644
index 0000000..641999c
--- /dev/null
+++ b/src/JT1078.Flv/Audio/G711UCodec.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Audio
+{
+    public class G711UCodec
+    {
+        /* 16384 entries per table (16 bit) */
+        readonly byte[] linearToUlawTable = new byte[65536];
+
+        /* 16384 entries per table (8 bit) */
+        readonly short[] ulawToLinearTable = new short[256];
+        readonly int SIGN_BIT = 0x80;
+        readonly int QUANT_MASK = 0x0f;
+        readonly int SEG_SHIFT = 0x04;
+        readonly int SEG_MASK = 0x70;
+        readonly int BIAS = 0x84;
+        readonly int CLIP = 8159;
+        readonly short[] seg_uend = { 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF };
+
+        public G711UCodec()
+        {
+            // 初始化ulaw表
+            for (int i = 0; i < 256; i++) ulawToLinearTable[i] = Ulaw2linear((byte)i);
+            // 初始化ulaw2linear表
+            for (int i = 0; i < 65535; i++) linearToUlawTable[i] = Linear2ulaw((short)i);
+        }
+
+        short Ulaw2linear(byte ulawValue)
+        {
+            ulawValue = (byte)(~ulawValue);
+            short t = (short)(((ulawValue & QUANT_MASK) << 3) + BIAS);
+            t <<= (ulawValue & SEG_MASK) >> SEG_SHIFT;
+
+            return ((ulawValue & SIGN_BIT) > 0 ? (short)(BIAS - t) : (short)(t - BIAS));
+        }
+
+        byte Linear2ulaw(short pcmValue)
+        {
+            short mask;
+            short seg;
+            byte uval;
+
+            pcmValue = (short)(pcmValue >> 2);
+            if (pcmValue < 0)
+            {
+                pcmValue = (short)(-pcmValue);
+                mask = 0x7f;
+            }
+            else
+            {
+                mask = 0xff;
+            }
+
+            if (pcmValue > CLIP) pcmValue = (short)CLIP;
+            pcmValue += (short)(BIAS >> 2);
+
+            seg = Search(pcmValue, seg_uend, 8);
+
+            if (seg >= 8)
+            {
+                return (byte)(0x7f ^ mask);
+            }
+            else
+            {
+                uval = (byte)((seg << 4) | ((pcmValue >> (seg + 1)) & 0xF));
+                return (byte)(uval ^ mask);
+            }
+        }
+
+        short Search(short val, short[] table, short size)
+        {
+            for (short i = 0; i < size; i++)
+            {
+                if (val <= table[i]) return i;
+            }
+            return size;
+        }
+
+        byte[] UlawToPcm16(byte[] samples)
+        {
+            var pcmSamples = new byte[samples.Length * 2];
+            for (int i = 0, k = 0; i < samples.Length; i++)
+            {
+                short s = ulawToLinearTable[samples[i] & 0xff];
+                pcmSamples[k++] = (byte)(s & 0xff);
+                pcmSamples[k++] = (byte)((s >> 8) & 0xff);
+            }
+            return pcmSamples;
+        }
+
+        private byte[] Pcm16ToUlaw(byte[] pcmSamples)
+        {
+            short[] dst = new short[pcmSamples.Length / 2];
+            byte[] ulawSamples = new byte[pcmSamples.Length / 2];
+            for (int i = 0, k = 0; i < pcmSamples.Length;)
+            {
+                dst[k++] = (short)((pcmSamples[i++] & 0xff) | ((pcmSamples[i++] & 0xff) << 8));
+            }
+            for (int i = 0, k = 0; i < dst.Length; i++)
+            {
+                ulawSamples[k++] = Linear2ulaw(dst[i]);
+            }
+            return ulawSamples;
+        }
+
+        public byte[] ToPcm(byte[] data) => UlawToPcm16(data);
+
+        public byte[] ToG711(byte[] data) => Pcm16ToUlaw(data);
+    }
+}
diff --git a/src/JT1078.Flv/Enums/AACPacketType.cs b/src/JT1078.Flv/Enums/AACPacketType.cs
new file mode 100644
index 0000000..a4e9cfb
--- /dev/null
+++ b/src/JT1078.Flv/Enums/AACPacketType.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Enums
+{
+    /// <summary>
+    /// Aac tag-body数据包类型
+    /// </summary>
+    public enum AACPacketType
+    {
+        /// <summary>
+        /// 音频序列配置
+        /// </summary>
+        AudioSpecificConfig = 0,
+        /// <summary>
+        /// 音频帧
+        /// </summary>
+        AudioFrame = 1
+    }
+}
diff --git a/src/JT1078.Flv/Enums/AudioFormat.cs b/src/JT1078.Flv/Enums/AudioFormat.cs
new file mode 100644
index 0000000..3fe87d0
--- /dev/null
+++ b/src/JT1078.Flv/Enums/AudioFormat.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Enums
+{
+    /// <summary>
+    /// 音频格式
+    /// </summary>
+    public enum AudioFormat
+    {
+        /// <summary>
+        /// Linear PCM, platform endian
+        /// </summary>
+        Pcm_Platform = 0,
+        /// <summary>
+        /// ADPCM
+        /// </summary>
+        ADPCM = 1,
+        /// <summary>
+        /// MP3
+        /// </summary>
+        MP3,
+        /// <summary>
+        /// Linear PCM, little endian
+        /// </summary>
+        Pcm_Little = 3,
+        /// <summary>
+        ///  16-kHz mono
+        /// </summary>
+        Nellymoser_16Khz = 4,
+        /// <summary>
+        ///  8-kHz mono
+        /// </summary>
+        Nellymoser_8Khz = 5,
+        /// <summary>
+        /// Nellymoser
+        /// </summary>
+        Nellymoser = 6,
+        /// <summary>
+        ///  A-law logarithmic PCM
+        /// </summary>
+        G711_A_law = 7,
+        /// <summary>
+        /// mu-law logarithmic PCM
+        /// </summary>
+        G711_mu_law = 8,
+        /// <summary>
+        /// AAC
+        /// </summary>
+        AAC = 10,
+        /// <summary>
+        /// Speex
+        /// </summary>
+        Speex = 11,
+        /// <summary>
+        /// MP3 8-Khz
+        /// </summary>
+        MP3_8Khz = 14
+    }
+}
diff --git a/src/JT1078.Flv/Enums/ChannelType.cs b/src/JT1078.Flv/Enums/ChannelType.cs
new file mode 100644
index 0000000..b7cf0f9
--- /dev/null
+++ b/src/JT1078.Flv/Enums/ChannelType.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Enums
+{
+    /// <summary>
+    /// 声道类型
+    /// </summary>
+    public enum ChannelType
+    {
+        /// <summary>
+        /// 单声道
+        /// </summary>
+        Mono,
+        /// <summary>
+        /// 立体声
+        /// </summary>
+        Stereo
+    }
+}
diff --git a/src/JT1078.Flv/Enums/SampleBit.cs b/src/JT1078.Flv/Enums/SampleBit.cs
new file mode 100644
index 0000000..e788781
--- /dev/null
+++ b/src/JT1078.Flv/Enums/SampleBit.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Enums
+{
+    /// <summary>
+    /// 采样位深
+    /// </summary>
+    public enum SampleBit
+    {
+        /// <summary>
+        /// 8位
+        /// </summary>
+        Bit_8 = 0,
+        /// <summary>
+        /// 16位
+        /// </summary>
+        Bit_16 = 1
+    }
+}
diff --git a/src/JT1078.Flv/Extensions/InteropExtensions.cs b/src/JT1078.Flv/Extensions/InteropExtensions.cs
new file mode 100644
index 0000000..72a7e52
--- /dev/null
+++ b/src/JT1078.Flv/Extensions/InteropExtensions.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace JT1078.Flv.Extensions
+{
+    public static class InteropExtensions
+    {
+        public static T BytesToStruct<T>(byte[] bytes, int startIndex, int length)
+        {
+            T local;
+            T local2;
+            if (bytes == null)
+            {
+                local2 = default;
+                local = local2;
+            }
+            else if (bytes.Length <= 0)
+            {
+                local2 = default;
+                local = local2;
+            }
+            else
+            {
+                IntPtr destination = Marshal.AllocHGlobal(length);
+                try
+                {
+                    Marshal.Copy(bytes, startIndex, destination, length);
+                    local = (T)Marshal.PtrToStructure(destination, typeof(T));
+                }
+                catch (Exception exception)
+                {
+                    throw new Exception("Error in BytesToStruct ! " + exception.Message);
+                }
+                finally
+                {
+                    Marshal.FreeHGlobal(destination);
+                }
+            }
+            return local;
+        }
+
+        public static void IntPtrSetValue(IntPtr intptr, object structObj)
+        {
+            IntPtrSetValue(intptr, StructToBytes(structObj));
+        }
+
+        public static void IntPtrSetValue(IntPtr intptr, byte[] bytes)
+        {
+            Marshal.Copy(bytes, 0, intptr, bytes.Length);
+        }
+
+        public static T IntPtrToStruct<T>(IntPtr intptr)
+        {
+            int index = 0;
+            return IntPtrToStruct<T>(intptr, index, Marshal.SizeOf(typeof(T)));
+        }
+
+        public static T IntPtrToStruct<T>(IntPtr intptr, int index, int length)
+        {
+            byte[] destination = new byte[length];
+            Marshal.Copy(intptr, destination, index, length);
+            return BytesToStruct<T>(destination, 0, destination.Length);
+        }
+
+        public static byte[] StructToBytes(object structObj)
+        {
+            int size = Marshal.SizeOf(structObj);
+            return StructToBytes(structObj, size);
+        }
+
+        public static byte[] StructToBytes(object structObj, int size)
+        {
+            byte[] buffer2;
+            IntPtr ptr = Marshal.AllocHGlobal(size);
+            try
+            {
+                Marshal.StructureToPtr(structObj, ptr, false);
+                byte[] destination = new byte[size];
+                Marshal.Copy(ptr, destination, 0, size);
+                buffer2 = destination;
+            }
+            catch (Exception exception)
+            {
+                throw new Exception("Error in StructToBytes ! " + exception.Message);
+            }
+            finally
+            {
+                Marshal.FreeHGlobal(ptr);
+            }
+            return buffer2;
+        }
+    }
+}
diff --git a/src/JT1078.Flv/FlvEncoder.cs b/src/JT1078.Flv/FlvEncoder.cs
index 1548f4f..1a69f3a 100644
--- a/src/JT1078.Flv/FlvEncoder.cs
+++ b/src/JT1078.Flv/FlvEncoder.cs
@@ -27,7 +27,7 @@ namespace JT1078.Flv
         private static readonly H264Decoder H264Decoder;
         private static readonly ConcurrentDictionary<string, SPSInfo> VideoSPSDict;
         private static readonly ConcurrentDictionary<string, FlvFrameInfo> FlvFrameInfoDict;
-        internal static readonly ConcurrentDictionary<string, (uint PreviousTagSize,byte[] Buffer,bool Changed)> FirstFlvFrameCache;
+        internal static readonly ConcurrentDictionary<string, (uint PreviousTagSize, byte[] Buffer, bool Changed)> FirstFlvFrameCache;
         private readonly ILogger logger;
         static FlvEncoder()
         {
@@ -117,11 +117,11 @@ namespace JT1078.Flv
                             }
                             //cache PreviousTagSize
                             FlvFrameInfoDict.TryAdd(key, new FlvFrameInfo
-                                {
-                                    PreviousTagSize = firstFlvKeyFrame.PreviousTagSize,
-                                    Interval = (uint)(pps.Timestamp - sps.Timestamp),
-                                    Timestamp = pps.Timestamp,
-                                }
+                            {
+                                PreviousTagSize = firstFlvKeyFrame.PreviousTagSize,
+                                Interval = (uint)(pps.Timestamp - sps.Timestamp),
+                                Timestamp = pps.Timestamp,
+                            }
                             );
                             FirstFlvFrameCache.TryAdd(key, (firstFlvKeyFrame.PreviousTagSize, firstFlvKeyFrame.Buffer, false));
                             VideoSPSDict.TryAdd(key, spsInfo);
@@ -203,7 +203,7 @@ namespace JT1078.Flv
         /// <param name="key">由于获取的SIM卡可能为000000000000,所以如果有替换JT1078Package.GetKey()的值</param>
         /// <param name="minimumLength">默认65535</param>
         /// <returns></returns>
-        public byte[] CreateFlvFrame(JT1078Package package,string key=null,int minimumLength = 65535)
+        public byte[] CreateFlvFrame(JT1078Package package, string key = null, int minimumLength = 65535)
         {
             var nalus = H264Decoder.ParseNALU(package);
             if (nalus == null || nalus.Count <= 0) return default;
@@ -215,7 +215,7 @@ namespace JT1078.Flv
         /// <param name="key">设备号+通道号(1111111_1)</param>
         /// <param name="currentBufferFlvFrame">当前接收到的flv数据</param>
         /// <returns></returns>
-        public byte[] GetFirstFlvFrame(string key,byte[] currentBufferFlvFrame)
+        public byte[] GetFirstFlvFrame(string key, byte[] currentBufferFlvFrame)
         {
             if (FirstFlvFrameCache.TryGetValue(key, out var firstBuffer))
             {
@@ -248,7 +248,7 @@ namespace JT1078.Flv
                 {
                     FlvArrayPool.Return(buffer);
                 }
-             }
+            }
             return default;
         }
 
@@ -428,10 +428,20 @@ namespace JT1078.Flv
         /// 1078当前时间戳
         /// </summary>
         public ulong Timestamp { get; set; }
+
+        /// <summary>
+        /// 1078当前音频时间戳
+        /// </summary>
+        public ulong AudioTimestamp { get; set; }
         /// <summary>
         /// 与flv上一帧相减的时间间隔
         /// </summary>
         public uint Interval { get; set; }
+
+        /// <summary>
+        /// 上一帧音频的时间间隔
+        /// </summary>
+        public uint AudioInterval { get; set; }
         /// <summary>
         /// 1078数据类型
         /// </summary>
diff --git a/src/JT1078.Flv/FlvTags.cs b/src/JT1078.Flv/FlvTags.cs
index 13376e1..620621c 100644
--- a/src/JT1078.Flv/FlvTags.cs
+++ b/src/JT1078.Flv/FlvTags.cs
@@ -27,6 +27,10 @@ namespace JT1078.Flv
         /// </summary>
         public VideoTags VideoTagsData { get; set; }
         /// <summary>
+        /// 音频数据
+        /// </summary>
+        public AudioTags AudioTagsData { get; set; }
+        /// <summary>
         /// 根据tag类型
         /// </summary>
         public Amf3 DataTagsData { get; set; }
diff --git a/src/JT1078.Flv/JT1078.Flv.csproj b/src/JT1078.Flv/JT1078.Flv.csproj
index 2c5805c..871a9bd 100644
--- a/src/JT1078.Flv/JT1078.Flv.csproj
+++ b/src/JT1078.Flv/JT1078.Flv.csproj
@@ -44,4 +44,9 @@
   <ItemGroup>
     <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.0.0" />
   </ItemGroup>
+  <ItemGroup>
+    <None Update="Libs\libfaac.dll">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
 </Project>
diff --git a/src/JT1078.Flv/JT1078.Flv.xml b/src/JT1078.Flv/JT1078.Flv.xml
index 420425a..ad37679 100644
--- a/src/JT1078.Flv/JT1078.Flv.xml
+++ b/src/JT1078.Flv/JT1078.Flv.xml
@@ -4,11 +4,153 @@
         <name>JT1078.Flv</name>
     </assembly>
     <members>
+        <member name="P:JT1078.Flv.Audio.State.Valprev">
+            <summary>
+            上一个采样数据,当index为0是该值应该为未压缩的原数据
+            </summary>
+        </member>
+        <member name="P:JT1078.Flv.Audio.State.Reserved">
+            <summary>
+            保留数据(未使用)
+            </summary>
+        </member>
+        <member name="P:JT1078.Flv.Audio.State.Index">
+            <summary>
+            上一个block最后一个index,第一个block的index=0
+            </summary>
+        </member>
+        <member name="M:JT1078.Flv.Audio.AdpcmCodec.ToPcm(System.Byte[],JT1078.Flv.Audio.State)">
+            <summary>
+            将adpcm转为pcm
+            </summary>
+            <see cref="!:https://github.com/ctuning/ctuning-programs/blob/master/program/cbench-telecom-adpcm-d/adpcm.c"/>
+            <param name="data"></param>
+            <returns></returns>
+        </member>
+        <member name="M:JT1078.Flv.Audio.AdpcmDecoderExtension.ToWav(System.Byte[],System.UInt32,System.Byte)">
+            <summary>
+            添加wav头
+            仅用于测试pcm是否转成成功,因此没考虑性能,因为播放器可播——#
+            </summary>
+            <param name="input">pcm数据</param>
+            <param name="frequency">采样率</param>
+            <param name="bitDepth">位深</param>
+            <returns></returns>
+        </member>
+        <member name="M:JT1078.Flv.Audio.G711ACodec.ToPcm(System.Byte[])">
+            <summary>
+            转至PCM
+            </summary>
+            <param name="g711data"></param>
+            <returns></returns>
+        </member>
+        <member name="M:JT1078.Flv.Audio.G711ACodec.ToG711(System.Byte[])">
+            <summary>
+            转至G711
+            </summary>
+            <param name="pcmdata"></param>
+            <returns></returns>
+        </member>
         <member name="T:JT1078.Flv.FlvBufferWriter">
             <summary>
             <see cref="!:System.Buffers.Writer"/>
             </summary>
         </member>
+        <member name="T:JT1078.Flv.Enums.AACPacketType">
+            <summary>
+            Aac tag-body数据包类型
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AACPacketType.AudioSpecificConfig">
+            <summary>
+            音频序列配置
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AACPacketType.AudioFrame">
+            <summary>
+            音频帧
+            </summary>
+        </member>
+        <member name="T:JT1078.Flv.Enums.AudioFormat">
+            <summary>
+            音频格式
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.Pcm_Platform">
+            <summary>
+            Linear PCM, platform endian
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.ADPCM">
+            <summary>
+            ADPCM
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.MP3">
+            <summary>
+            MP3
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.Pcm_Little">
+            <summary>
+            Linear PCM, little endian
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.Nellymoser_16Khz">
+            <summary>
+             16-kHz mono
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.Nellymoser_8Khz">
+            <summary>
+             8-kHz mono
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.Nellymoser">
+            <summary>
+            Nellymoser
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.G711_A_law">
+            <summary>
+             A-law logarithmic PCM
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.G711_mu_law">
+            <summary>
+            mu-law logarithmic PCM
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.AAC">
+            <summary>
+            AAC
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.Speex">
+            <summary>
+            Speex
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.AudioFormat.MP3_8Khz">
+            <summary>
+            MP3 8-Khz
+            </summary>
+        </member>
+        <member name="T:JT1078.Flv.Enums.ChannelType">
+            <summary>
+            声道类型
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.ChannelType.Mono">
+            <summary>
+            单声道
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.ChannelType.Stereo">
+            <summary>
+            立体声
+            </summary>
+        </member>
         <member name="F:JT1078.Flv.Enums.FrameType.KeyFrame">
             <summary>
             ‭00010000‬
@@ -34,6 +176,21 @@
             01010000
             </summary>
         </member>
+        <member name="T:JT1078.Flv.Enums.SampleBit">
+            <summary>
+            采样位深
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.SampleBit.Bit_8">
+            <summary>
+            8位
+            </summary>
+        </member>
+        <member name="F:JT1078.Flv.Enums.SampleBit.Bit_16">
+            <summary>
+            16位
+            </summary>
+        </member>
         <member name="T:JT1078.Flv.Extensions.HexExtensions">
             <summary>
             
@@ -94,11 +251,21 @@
             1078当前时间戳
             </summary>
         </member>
+        <member name="P:JT1078.Flv.FlvFrameInfo.AudioTimestamp">
+            <summary>
+            1078当前音频时间戳
+            </summary>
+        </member>
         <member name="P:JT1078.Flv.FlvFrameInfo.Interval">
             <summary>
             与flv上一帧相减的时间间隔
             </summary>
         </member>
+        <member name="P:JT1078.Flv.FlvFrameInfo.AudioInterval">
+            <summary>
+            上一帧音频的时间间隔
+            </summary>
+        </member>
         <member name="P:JT1078.Flv.FlvFrameInfo.LastDataType">
             <summary>
             1078数据类型
@@ -127,11 +294,21 @@
             根据tag类型
             </summary>
         </member>
+        <member name="P:JT1078.Flv.FlvTags.AudioTagsData">
+            <summary>
+            音频数据
+            </summary>
+        </member>
         <member name="P:JT1078.Flv.FlvTags.DataTagsData">
             <summary>
             根据tag类型
             </summary>
         </member>
+        <member name="P:JT1078.Flv.Metadata.AacPacke.RawData">
+            <summary>
+            元数据
+            </summary>
+        </member>
         <member name="P:JT1078.Flv.Metadata.Amf3.DataType">
             <summary>
             AMF3数据类型
@@ -147,6 +324,48 @@
             <see cref="!:typeof(JT1078.Flv.Enums.CodecId.AvcVideoPacke)"/>
             </summary>
         </member>
+        <member name="P:JT1078.Flv.Metadata.AudioSpecificConfig.ChannelConfiguration">
+            <summary>
+            其实有很多,这里就固定为立体声
+            </summary>
+        </member>
+        <member name="T:JT1078.Flv.Metadata.AudioSpecificConfig.AudioObjectType">
+            <summary>
+            音频类型
+            其实有很多,这里就列几个,如有需要再加
+            </summary>
+        </member>
+        <member name="P:JT1078.Flv.Metadata.AudioTags.SampleRate">
+            <summary>
+            采样率
+            AAC固定为3
+            0 = 5.5-kHz
+            1 = 11-kHz
+            2 = 22-kHz
+            3 = 44-kHz
+            </summary>
+        </member>
+        <member name="P:JT1078.Flv.Metadata.AudioTags.SampleBit">
+            <summary>
+            采样位深
+            </summary>
+        </member>
+        <member name="P:JT1078.Flv.Metadata.AudioTags.Channel">
+            <summary>
+            声道
+            AAC永远是1
+            </summary>
+        </member>
+        <member name="P:JT1078.Flv.Metadata.AudioTags.SoundType">
+            <summary>
+            音频格式
+            </summary>
+        </member>
+        <member name="P:JT1078.Flv.Metadata.AudioTags.AacPacke">
+            <summary>
+            元数据
+            </summary>
+        </member>
         <!-- Badly formed XML comment ignored for member "T:JT1078.Flv.Metadata.AVCDecoderConfigurationRecord" -->
         <member name="P:JT1078.Flv.Metadata.IAmf3Metadata.FieldNameLength">
             <summary>
diff --git a/src/JT1078.Flv/Libs/libfaac.dll b/src/JT1078.Flv/Libs/libfaac.dll
new file mode 100644
index 0000000..c9f2e45
Binary files /dev/null and b/src/JT1078.Flv/Libs/libfaac.dll differ
diff --git a/src/JT1078.Flv/Metadata/AacPacke.cs b/src/JT1078.Flv/Metadata/AacPacke.cs
new file mode 100644
index 0000000..0c8fcb7
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/AacPacke.cs
@@ -0,0 +1,32 @@
+using JT1078.Flv.Enums;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Metadata
+{
+    public class AacPacke
+    {
+        public AacPacke(AACPacketType packetType, byte[] data = null)
+        {
+            AACPacketType = packetType;
+            if (packetType == AACPacketType.AudioSpecificConfig)
+            {
+                Data.Add(0);
+                Data.AddRange(new AudioSpecificConfig().ToArray());
+            }
+            else
+            {
+                Data.Add(1);
+                Data.AddRange(data ?? throw new NullReferenceException("data cannot be null"));
+            }
+        }
+        public AACPacketType AACPacketType { get; private set; }
+
+        List<byte> Data { get; set; } = new List<byte>();
+        /// <summary>
+        /// 元数据
+        /// </summary>
+        public byte[] RawData => Data.ToArray();
+    }
+}
diff --git a/src/JT1078.Flv/Metadata/AudioSpecificConfig.cs b/src/JT1078.Flv/Metadata/AudioSpecificConfig.cs
new file mode 100644
index 0000000..4218b39
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/AudioSpecificConfig.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Metadata
+{
+    public class AudioSpecificConfig
+    {
+        public AudioObjectType AudioType { get; set; } = AudioObjectType.AAC_LC;
+        public SamplingFrequency SamplingFrequencyIndex { get; set; } = SamplingFrequency.Index_8000;
+        /// <summary>
+        /// 其实有很多,这里就固定为立体声
+        /// </summary>
+        public int ChannelConfiguration { get; set; } = 1;
+
+        public byte[] ToArray()
+        {
+            var value = Convert.ToInt16($"{Convert.ToString((int)AudioType, 2).PadLeft(5, '0')}{Convert.ToString((int)SamplingFrequencyIndex, 2).PadLeft(4, '0')}{Convert.ToString(ChannelConfiguration, 2).PadLeft(4, '0')}000", 2);
+            return new byte[] { (byte)(value >> 8), (byte)value, 0x56, 0xe5, 0x00 };
+        }
+        /// <summary>
+        /// 音频类型
+        /// 其实有很多,这里就列几个,如有需要再加
+        /// </summary>
+        public enum AudioObjectType
+        {
+            AAC_MAIN = 1,
+            AAC_LC = 2,
+            AAC_SSR = 3,
+            AAC_LTP = 4,
+            SBR = 5,
+            AAC_SCALABLE
+        }
+        public enum SamplingFrequency
+        {
+            Index_96000 = 0x00,
+            Index_88200 = 0x01,
+            Index_64000 = 0x02,
+            Index_48000 = 0x03,
+            Index_44100 = 0x04,
+            Index_32000 = 0x05,
+            Index_24000 = 0x06,
+            Index_22050 = 0x07,
+            Index_16000 = 0x08,
+            Index_12000 = 0x09,
+            Index_11025 = 0x0a,
+            Index_8000 = 0x0b,
+            Index_7350 = 0x0c,
+            ESCAPE = 0x0f
+        }
+    }
+}
diff --git a/src/JT1078.Flv/Metadata/AudioTags.cs b/src/JT1078.Flv/Metadata/AudioTags.cs
new file mode 100644
index 0000000..e0cbf10
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/AudioTags.cs
@@ -0,0 +1,53 @@
+using JT1078.Flv.Enums;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Metadata
+{
+    public class AudioTags
+    {
+        public AudioTags(AACPacketType packetType = AACPacketType.AudioSpecificConfig, byte[] aacFrameData = null)
+        {
+            AacPacke = new AacPacke(packetType, aacFrameData);
+        }
+        /// <summary>
+        /// 采样率
+        /// AAC固定为3
+        /// 0 = 5.5-kHz
+        /// 1 = 11-kHz
+        /// 2 = 22-kHz
+        /// 3 = 44-kHz
+        /// </summary>
+        public int SampleRate => 3;
+        /// <summary>
+        /// 采样位深
+        /// </summary>
+        public SampleBit SampleBit { get; set; } = SampleBit.Bit_16;
+        /// <summary>
+        /// 声道
+        /// AAC永远是1
+        /// </summary>
+        public ChannelType Channel => ChannelType.Stereo;
+        /// <summary>
+        /// 音频格式
+        /// </summary>
+        public AudioFormat SoundType => AudioFormat.AAC;
+
+        /// <summary>
+        /// 元数据
+        /// </summary>
+        private AacPacke AacPacke { get; set; }
+
+        public byte[] ToArray()
+        {
+            var value = $"{Convert.ToString((int)SoundType, 2).PadLeft(4, '0')}{Convert.ToString(SampleRate, 2).PadLeft(2, '0')}{(int)SampleBit}{(int)Channel}";
+            var data = new List<byte>
+            {
+                Convert.ToByte(value, 2)
+            };
+            data.AddRange(AacPacke.RawData);
+            return data.ToArray();
+        }
+    }
+}