using System;
using System.Collections.Generic;

namespace Inspectron.HawkEye.RTSP
{
    // This class handles the AAC-hbd (High Bitrate) Payload
    // It has methods to process the RTP Payload

    // (c) 2018 Roger Hardiman, RJH Technical Consultancy Ltd


    /*
    RFC 3640
    3.3.6.  High Bit-rate AAC

    This mode is signaled by mode=AAC-hbr.This mode supports the
    transportation of variable size AAC frames.In one RTP packet,
    either one or more complete AAC frames are carried, or a single
    fragment of an AAC frame is carried.In this mode, the AAC frames
    are allowed to be interleaved and hence receivers MUST support de-
    interleaving.The maximum size of an AAC frame in this mode is 8191
    octets.

    In this mode, the RTP payload consists of the AU Header Section,
    followed by either one AAC frame, several concatenated AAC frames or
    one fragmented AAC frame.The Auxiliary Section MUST be empty.  For
    each AAC frame contained in the payload, there MUST be an AU-header
    in the AU Header Section to provide:

    a) the size of each AAC frame in the payload and

    b) index information for computing the sequence(and hence timing) of
       each AAC frame.

       To code the maximum size of an AAC frame requires 13 bits.
       Therefore, in this configuration 13 bits are allocated to the AU-
       size, and 3 bits to the AU-Index(-delta) field.Thus, each AU-header
       has a size of 2 octets.Each AU-Index field MUST be coded with the
       value 0.  In the AU Header Section, the concatenated AU-headers MUST
       be preceded by the 16-bit AU-headers-length field, as specified in
       section 3.2.1.

        In addition to the required MIME format parameters, the following
        parameters MUST be present: sizeLength, indexLength, and
        indexDeltaLength.AAC frames always have a fixed duration per Access
        Unit; when interleaving in this mode, this specific duration MUST be
        signaled by the MIME format parameter constantDuration.In addition,
        the parameter maxDisplacement MUST be present when interleaving.

    For example:

        m= audio 49230 RTP/AVP 96
        a= rtpmap:96 mpeg4-generic/48000/6
        a= fmtp:96 streamtype= 5; profile-level-id= 16; mode= AAC-hbr;config= 11B0; sizeLength= 13; indexLength= 3;indexDeltaLength= 3; constantDuration= 1024

    The hexadecimal value of the "config" parameter is the AudioSpecificConfig(), as defined in ISO/IEC 14496-3.
    AudioSpecificConfig() specifies a 5.1 channel AAC stream with a sampling rate of 48 kHz.For the description of MIME parameters, see
    section 4.1.

    */


    public class AACPayload
    {
        public uint ObjectType = 0;
        public uint FrequencyIndex = 0;
        public uint ChannelConfiguration = 0;

        // Constructor
        public AACPayload(String config_string)
        {
            /***
            5 bits: object type
                if (object type == 31)
                6 bits + 32: object type
            4 bits: frequency index
                if (frequency index == 15)
                24 bits: frequency
            4 bits: channel configuration
            var bits: AOT Specific Config
             ***/

            // config is a string in hex eg 1490 or 0x1210
            // Read each ASCII character and add to a bit array
            BitStream bs = new BitStream();
            bs.AddHexString(config_string);

            // Read 5 bits
            ObjectType = bs.Read(5);

            // Read 4 bits
            FrequencyIndex = bs.Read(4);

            // Read 4 bits
            ChannelConfiguration = bs.Read(4);
        }

        public List<byte[]> Process_AAC_RTP_Packet(byte[] rtp_payload, int rtp_marker) {

            // RTP Payload for MPEG4-GENERIC can consist of multple blocks.
            // Each block has 3 parts
            // Part 1 - Acesss Unit Header Length + Header
            // Part 2 - Access Unit Auxiliary Data Length + Data (not used in AAC High Bitrate)
            // Part 3 - Access Unit Audio Data

            // The rest of the RTP packet is the AMR data
            List<byte[]> audio_data = new List<byte[]>();

            int ptr = 0;

            while (true) {
                if (ptr + 4 > rtp_payload.Length) break; // 2 bytes for AU Header Length, 2 bytes of AU Header payload

                // Get Size of the AU Header
                int au_headers_length_bits = (((rtp_payload[ptr] << 8) + (rtp_payload[ptr + 1] << 0))); // 16 bits
                int au_headers_length = (int)Math.Ceiling((double)au_headers_length_bits / 8.0);
                ptr += 2;

                // Examine the AU Header. Get the size of the AAC data
                int aac_frame_size = (((rtp_payload[ptr] << 8) + (rtp_payload[ptr+1] << 0)) >> 3); // 13 bits
                int aac_index_delta = rtp_payload[ptr+1] & 0x03; // 3 bits
                ptr += au_headers_length;

                // extract the AAC block
                if (ptr + aac_frame_size > rtp_payload.Length) break; // not enough data to copy
                byte[] aac_data = new byte[aac_frame_size];
                System.Array.Copy(rtp_payload, ptr, aac_data, 0, aac_frame_size);
                audio_data.Add(aac_data);
                ptr += aac_frame_size;
            }

            return audio_data;
        }

    }
}
