//*****************************************************************************
//
//! @file am_vos_audio_buffer.c
//!
//! @brief VoS audio ring buffers
//
//*****************************************************************************

//*****************************************************************************
//
// Copyright (c) 2024, Ambiq Micro, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision ambiqvos_r4.5-fdfa8cf6a4 of the AmbiqSuite Development Package.
//
//*****************************************************************************

//*****************************************************************************
//
// this is the source file of stereo audio application RAM optimization.
// In this application, there are 3 nested buffers:BUFFER_STEREO, BUFFER_MONO and BUFFER_ENCODED.
// Data flowing path as following:
//
// PDM_ISR -> BUFFER_STEREO ->BUFFER_MONO -> BUFFER_ENCODED -> BLE
//
// 3 BUFFERs share the same physical buffer: g_ringUniversalBuffer. Each buffer use its own read_head and write_tail.
//
// Align with the above data flowing chart:
//
// 0: AM_AUDIO_BUFFER_STEREO
// 1: AM_AUDIO_BUFFER_MONO
// 2: AM_AUDIO_BUFFER_ENCODED
//
// buffer2 nested to buffer1 nested to buffer0
//
// data will be pop from 0, after processing, push to 1;
//
// pop from 1, after encoded, push to 2
//
// pop from 2, then pushed to BLE.
//
// We will move ptrs' positions when we push the data into ring buffer and some conditions meet (the nested buffer is empty)
//
//*****************************************************************************

#include "am_vos_sys_config.h"

#include "am_mcu_apollo.h"
#include "am_vos_utils.h"
#include "am_vos_task.h"

#include "am_vos_audio_buffer.h"


uint8_t
am_vos_ring_buffer_empty(am_vos_ring_buffer_t *psBuffer)
{
    uint32_t ui32BufferTail_write = psBuffer->ui32BufferTail_write;
    uint32_t ui32BufferHead_read = psBuffer->ui32BufferHead_read;
    uint32_t ui32OverWriting = psBuffer->ui32OverWriting;
    return (ui32BufferTail_write == ui32BufferHead_read && (!ui32OverWriting));
}

uint8_t
am_vos_ring_buffer_full(am_vos_ring_buffer_t *psBuffer)
{
    uint32_t ui32BufferTail_write = psBuffer->ui32BufferTail_write;
    uint32_t ui32BufferHead_read = psBuffer->ui32BufferHead_read;
    uint32_t ui32OverWriting = psBuffer->ui32OverWriting;
    return (ui32BufferTail_write == ui32BufferHead_read && (ui32OverWriting));
}

uint8_t
am_vos_ring_buffer_overwrite(am_vos_ring_buffer_t *psBuffer)
{
    uint32_t ui32BufferTail_write = psBuffer->ui32BufferTail_write;
    uint32_t ui32BufferHead_read = psBuffer->ui32BufferHead_read;
    uint32_t ui32OverWriting = psBuffer->ui32OverWriting;
    return (ui32BufferTail_write != ui32BufferHead_read && (ui32OverWriting));
}

//*****************************************************************************
//
//! @brief Initializes a ring buffer structure.
//!
//! @param psBuffer is a pointer to the buffer structure to be initialized.
//!
//! @param pvArray is a pointer to the array that the new ringbuffer will use
//! for storage space
//!
//! @param ui32Bytes is the total number of bytes that the ringbuffer will be
//! allowed to use.
//!
//! This function should be called on a ring buffer structure before it is
//! used. If this function is called on a ring buffer that is already being
//! used, it will "erase" the buffer, effectively removing all of the buffer
//! contents from the perspective of the other ring buffer access functions.
//! The data will remain in memory, but it will be overwritten as the buffer is
//! used.
//!
//! @note This operation is not inherently thread-safe, so the caller must make
//! sure that it is appropriately guarded from interrupts and context switches.
//!
//! @return
//
//*****************************************************************************
void
am_vos_ring_buffer_init(am_vos_ring_buffer_t* ring_buffs, am_vos_ringbuff_setup_t setup)
{
    ring_buffs[setup.indx].ui32BufferHead_read = 0;
    ring_buffs[setup.indx].ui32BufferTail_write = 0;
    ring_buffs[setup.indx].ui32OverWriting = 0;
    ring_buffs[setup.indx].ui32Capacity = setup.ui32ByteSize;
    ring_buffs[setup.indx].pui8Data = setup.pData;
}

void
am_vos_ring_buffer_init_all(am_vos_ring_buffer_t* ring_buffs, const am_vos_ringbuff_setup_t* setup_array, 
                                    uint32_t ui32BufferCount)
{
    uint32_t ringbuff = 0;
    for(ringbuff =0; ringbuff<ui32BufferCount; ringbuff++)
    {
        am_vos_ring_buffer_init(ring_buffs,setup_array[ringbuff]);    
    }

}


//*****************************************************************************
// Function: ring buffer push function  
// Paras:
//      psBuffer: the target ring buffer needs to be pushed
//      pvSource: the data source
//      ui32Bytes: target transfer data length
//      bFullCheck: whether checking the target ring buffer full or not. If true, data can't be pushed when buffer is full. 
//                  If false, data could be pushed no matter buffer is full or not.
// Return:
//      bytes pushed into the ring buffer
//*****************************************************************************
uint32_t am_vos_ring_buffer_push(am_vos_ring_buffer_t *psBuffer, void *pvSource, uint32_t ui32Bytes, bool bFullCheck)
{
    uint32_t ui32CopyLen = 0;
    uint32_t ui32ReturnPushLen = 0;
    uint32_t ui32TempLen = 0;
    uint8_t *pui8Source;
    
    ui32CopyLen = ui32Bytes;
    pui8Source = (uint8_t*)pvSource;

    uint32_t ui32BufferTail_write = psBuffer->ui32BufferTail_write;
    uint32_t ui32BufferHead_read = psBuffer->ui32BufferHead_read;
    uint32_t ui32Capacity = psBuffer->ui32Capacity;
    
    if(bFullCheck == true)
    {
        AM_CRITICAL_BEGIN;
        // won't push any data if buffer is full
        if(am_vos_ring_buffer_full(psBuffer))
        {
            ui32CopyLen = 0;
            ui32ReturnPushLen =0;
            return ui32ReturnPushLen;
        }

        // push data until the buffer is full
        if(am_vos_ring_buffer_empty(psBuffer))
        {
            if(ui32CopyLen >= ui32Capacity)
            {      
                psBuffer->ui32OverWriting = 1;
                ui32CopyLen = ui32Capacity;
            }
        }
        else
        {
            if(((ui32BufferHead_read + ui32Capacity - ui32BufferTail_write) 
                % ui32Capacity) <= ui32CopyLen)
            {    
                psBuffer->ui32OverWriting = 1;
                ui32CopyLen = ((ui32BufferHead_read + ui32Capacity - ui32BufferTail_write) 
                % ui32Capacity);
            }

        }        
            
        ui32ReturnPushLen = ui32CopyLen;

        while((ui32BufferTail_write + ui32CopyLen) >= ui32Capacity)
        {
            ui32TempLen = ui32Capacity - ui32BufferTail_write;
            memcpy((void*)&psBuffer->pui8Data[ui32BufferTail_write], pui8Source, ui32TempLen);
            ui32BufferTail_write = psBuffer->ui32BufferTail_write = ((ui32BufferTail_write + ui32TempLen) % ui32Capacity);
            ui32CopyLen -= ui32TempLen;
        }
    //        configASSERT((ui32BufferTail_write + ui32CopyLen) < psBuffer->ui32Capacity);
        
        memcpy((void*)&psBuffer->pui8Data[ui32BufferTail_write], &pui8Source[ui32TempLen], ui32CopyLen);
        ui32BufferTail_write = psBuffer->ui32BufferTail_write = ((ui32BufferTail_write + ui32CopyLen) % ui32Capacity);
        AM_CRITICAL_END;
        return ui32ReturnPushLen;
    }
    else        // if no full check, the return bytes are always ui32Bytes.
    {
        AM_CRITICAL_BEGIN;
        // push data until the buffer is full
        if(am_vos_ring_buffer_empty(psBuffer))
        {
            if(ui32CopyLen >= ui32Capacity)
            {      
                psBuffer->ui32OverWriting = 1;
            }
        }
        else
        {
            if(((ui32BufferHead_read + ui32Capacity - ui32BufferTail_write) 
                % ui32Capacity) <= ui32CopyLen)
            {    
                psBuffer->ui32OverWriting = 1;
            }
        }        

        ui32ReturnPushLen = ui32CopyLen;
    
        while((ui32BufferTail_write + ui32CopyLen) >= ui32Capacity)
        {
            ui32TempLen = ui32Capacity - ui32BufferTail_write;
            memcpy((void*)&psBuffer->pui8Data[ui32BufferTail_write], pui8Source, ui32TempLen);
            ui32BufferTail_write = psBuffer->ui32BufferTail_write = ((ui32BufferTail_write + ui32TempLen) % ui32Capacity);
            ui32CopyLen -= ui32TempLen;
        }
//        configASSERT((ui32BufferTail_write + ui32CopyLen) < ui32Capacity);
        
        memcpy((void*)&psBuffer->pui8Data[ui32BufferTail_write], &pui8Source[ui32TempLen], ui32CopyLen);
        ui32BufferTail_write = psBuffer->ui32BufferTail_write = ((ui32BufferTail_write + ui32CopyLen) % ui32Capacity);
        
        //
        // Keep read and write at same position
        //
        if(psBuffer->ui32OverWriting == 1)
        {
            ui32BufferHead_read = psBuffer->ui32BufferHead_read = (ui32BufferTail_write);
        }
        AM_CRITICAL_END;
        return ui32ReturnPushLen;
    }
}


uint32_t am_vos_ring_buffer_pop(am_vos_ring_buffer_t *psBuffer, void *pvDest,
                         uint32_t ui32Bytes)
{
    uint32_t ui32CopyLen = 0;
    uint32_t ui32TempLen = 0;
    uint32_t ui32DataLen = 0;
    uint32_t ui32ReturnPopLen = 0;
    uint8_t *pui8Dest;

    uint32_t ui32BufferTail_write = psBuffer->ui32BufferTail_write;
    uint32_t ui32BufferHead_read = psBuffer->ui32BufferHead_read;
    uint32_t ui32Capacity = psBuffer->ui32Capacity;

    pui8Dest = (uint8_t *) pvDest;
    
    ui32DataLen = am_vos_get_ring_buffer_status(psBuffer);
   
    AM_CRITICAL_BEGIN;
    if(am_vos_ring_buffer_overwrite(psBuffer))
    {
        ui32BufferHead_read = psBuffer->ui32BufferHead_read = (ui32BufferTail_write);
       
    }

    // pop len can't exceed the length of buffer
    ui32CopyLen = ui32Bytes < ui32DataLen ? ui32Bytes : ui32DataLen;
    
    ui32ReturnPopLen = ui32CopyLen;

    while((ui32BufferHead_read + ui32CopyLen) >= ui32Capacity)
    {
        ui32TempLen = ui32Capacity - ui32BufferHead_read;
        memcpy(pui8Dest, (void*)&psBuffer->pui8Data[ui32BufferHead_read], ui32TempLen);
        ui32BufferHead_read = psBuffer->ui32BufferHead_read = ((ui32BufferHead_read + ui32TempLen) % ui32Capacity);
        ui32CopyLen -= ui32TempLen;
    }

    //configASSERT((ui32BufferHead_read + ui32CopyLen) < ui32Capacity);
    
    memcpy(&pui8Dest[ui32TempLen], (void*)&psBuffer->pui8Data[ui32BufferHead_read], ui32CopyLen);
    
    ui32BufferHead_read = psBuffer->ui32BufferHead_read = ((ui32BufferHead_read + ui32CopyLen) % ui32Capacity);
      
    psBuffer->ui32OverWriting = 0;
    AM_CRITICAL_END;
    return ui32ReturnPopLen;
}
//*****************************************************************************
//
//! @brief get the number of data left in ring buffer .
//!
//! @param psBuffer is the address of the ring buffer structure to be read.
//!
//! @note This operation is not inherently thread-safe, so the caller must make
//! sure that it is appropriately guarded from interrupts and context switches.
//!
//! @return The number of data left.
//
//*****************************************************************************
uint32_t
am_vos_get_ring_buffer_status(am_vos_ring_buffer_t *psBuffer)
{
    uint32_t ui32NewDataLen = 0;

    uint32_t ui32BufferTail_write = psBuffer->ui32BufferTail_write;
    uint32_t ui32BufferHead_read = psBuffer->ui32BufferHead_read;
    uint32_t ui32Capacity = psBuffer->ui32Capacity;
    
    if (am_vos_ring_buffer_overwrite(psBuffer) || am_vos_ring_buffer_full(psBuffer))
    {
        AM_CRITICAL_BEGIN;  
        ui32NewDataLen = ui32Capacity;
        AM_CRITICAL_END;
        return ui32NewDataLen;
    }
    AM_CRITICAL_BEGIN;
    ui32NewDataLen = ((ui32BufferTail_write + ui32Capacity - ui32BufferHead_read) % 
        ui32Capacity);
    AM_CRITICAL_END;
    return ui32NewDataLen; 

}

//*****************************************************************************
//
//! @brief flush the ring buffer 
//!
//! @param psBuffer is the address of the ring buffer which needs to be flushed.
//!
//! @note None.
//!
//! @return None.
//
//*****************************************************************************
void
am_vos_flush_ring_buffer(am_vos_ring_buffer_t *psBuffer)
{
    psBuffer->ui32OverWriting = 0;
    psBuffer->ui32BufferHead_read = psBuffer->ui32BufferTail_write;
}

//*****************************************************************************
//
//! @brief used in while loop to process all data in ring buffer
//!        e.g. while(am_vos_ring_process(src, dst, FRAME_SIZE))){}
//!
//! @param psSource: target ring buffer of ring processing
//!        pvDest: pointer of processing parameters (array)
//!        process_frame_bytes: number of bytes processed by a round
//!
//! @note None.
//!
//! @return None.
//
//*****************************************************************************
uint32_t am_vos_ring_process(am_vos_ring_buffer_t *psSource, void *pvDest, uint32_t process_frame_bytes)
{
    uint32_t ui32BuffDataBytes = 0;
    ui32BuffDataBytes = am_vos_get_ring_buffer_status(psSource);
    if(ui32BuffDataBytes >= process_frame_bytes)
    { 
        am_vos_ring_buffer_pop(psSource, pvDest, process_frame_bytes);
        return 1;
    }
    else
    {
        return 0;
    }
}

//*****************************************************************************
//
// fundamental functions: init, push, pop, rewind.
//
//*****************************************************************************
void am_audio_buffer_init(void)
{

    for(uint8_t i = 0; i < AM_AUDIO_BUFFER_MAX; i++)
    {
        g_sAmUtil.sRingBuf[i].ui32BufferHead_read = 0;
        g_sAmUtil.sRingBuf[i].ui32BufferTail_write = 0;
        g_sAmUtil.sRingBuf[i].ui32OverWriting = 0;
        g_sAmUtil.sRingBuf[i].ui32Capacity = BYTES_UNIVERSAL_BUFFER_SIZE;
        g_sAmUtil.sRingBuf[i].pui8Data = g_sAmUtil.pui8RingBuffer;
    }
}

// returns true if a push results in overwrite
bool am_audio_buffer_push(enum_audio_buffer_t buffer_type, void *pvSource, uint32_t ui32Bytes)
{
    if(buffer_type > AM_AUDIO_BUFFER_MAX)
    {
        // type error

    }
    else
    {
//        AM_CRITICAL_BEGIN_VOS;
        am_vos_ring_buffer_push(&(g_sAmUtil.sRingBuf[buffer_type]), pvSource, ui32Bytes, false);
//        AM_CRITICAL_END_VOS;
    }

    return(g_sAmUtil.sRingBuf[buffer_type].ui32OverWriting);
}


// returns the actual data bytes popped
uint32_t
am_audio_buffer_pop(enum_audio_buffer_t buffer_type, void *pvDest, uint32_t ui32Bytes)
{
    if(buffer_type > AM_AUDIO_BUFFER_MAX)
    {
        // type error
        return 0;
    }
    uint32_t ui32PopLen = 0;

//    AM_CRITICAL_BEGIN_VOS;
    ui32PopLen = am_vos_ring_buffer_pop(&(g_sAmUtil.sRingBuf[buffer_type]), pvDest, ui32Bytes);
//    AM_CRITICAL_END_VOS;

    return ui32PopLen;
}

bool am_audio_buffer_empty(enum_audio_buffer_t buffer_type)
{
    bool bRetValue = false;
    AM_CRITICAL_BEGIN_VOS;
    bRetValue = am_vos_ring_buffer_empty(&(g_sAmUtil.sRingBuf[buffer_type]));
    AM_CRITICAL_END_VOS;
    return bRetValue;
}

//
// rewind the index pointers of an audio buffer to a position in the past
// enum_audio_buffer_t buffer_type: buffer needs rewind
// offset_back: rewind bytes
// return: 
// offset_back: how many bytes are actual rewinded
uint32_t am_audio_buffer_rewind(enum_audio_buffer_t buffer_type, uint32_t offset_back)
{
    int8_t buff_indx = 0;
    uint32_t bytes_remain = 0;
    if(buffer_type > AM_AUDIO_BUFFER_MAX)
    {
        // type error
        return 0;
    }

    AM_CRITICAL_BEGIN_VOS;

    bytes_remain = am_vos_get_ring_buffer_status(&(g_sAmUtil.sRingBuf[buffer_type]));
    if(offset_back >= bytes_remain)
    {
        offset_back = bytes_remain;
    }
    g_sAmUtil.sRingBuf[buffer_type].ui32OverWriting = 0; // clear overwrite flag
    g_sAmUtil.sRingBuf[buffer_type].ui32BufferHead_read =
                        (g_sAmUtil.sRingBuf[buffer_type].ui32BufferTail_write + BYTES_UNIVERSAL_BUFFER_SIZE - offset_back) % BYTES_UNIVERSAL_BUFFER_SIZE;

    //AM_VOS_LOG_DEBUG("-- Buffer rewind: offset_back = %d, head = %d, tail = %d\n", offset_back, g_sAmUtil.sRingBuf[buffer_type].ui32BufferHead_read, g_sAmUtil.sRingBuf[buffer_type].ui32BufferTail_write);

    for(buff_indx=buffer_type+1; buff_indx<AM_AUDIO_BUFFER_MAX; buff_indx++)
    {
        am_vos_flush_ring_buffer(&(g_sAmUtil.sRingBuf[buff_indx]));
        g_sAmUtil.sRingBuf[buff_indx].ui32BufferHead_read = g_sAmUtil.sRingBuf[buffer_type].ui32BufferHead_read;
        g_sAmUtil.sRingBuf[buff_indx].ui32BufferTail_write = g_sAmUtil.sRingBuf[buffer_type].ui32BufferHead_read;
    }

    AM_CRITICAL_END_VOS;
    return offset_back;
}

//
// Set audio buffer index into a specific position.
// It's effective only when the buffer is empty.
// Return:
//      true  --the head and tail are successfully changed.
//      false --the head and tail are unchanged.
//

bool am_audio_buffer_index_set(enum_audio_buffer_t buffer_type, uint32_t index)
{
    if(buffer_type > AM_AUDIO_BUFFER_MAX)
    {
        // type error
        return false;
    }


    if(am_audio_buffer_empty(buffer_type))
    {
//        AM_CRITICAL_BEGIN_VOS;
        g_sAmUtil.sRingBuf[buffer_type].ui32BufferHead_read = index;//(index + 160) % BYTES_UNIVERSAL_BUFFER_SIZE;
        g_sAmUtil.sRingBuf[buffer_type].ui32BufferTail_write = index;//(index + 160) % BYTES_UNIVERSAL_BUFFER_SIZE;
//        AM_CRITICAL_END_VOS;
        return true;
    }
    else
        return false;
}

//*****************************************************************************
//
// specific-optimized functions: nested_push
// parameters:
//          buffer_push_to: the target ring buffer where we push data to
//          buffer_origin: consider it as parent buffer, where pvSource data comes from
//          pvSource: data source
//          ui32Bytes: how many bytes needs to be pushed
//
// Notice:
//      the difference between nested_push and push is: nested_push will move the
//      parent buffer head and tail to the tail of sub-buffer if parent buffer is empty.
//
//*****************************************************************************
void am_audio_buffer_nested_push(enum_audio_buffer_t buffer_push_to, void *pvSource, uint32_t ui32Bytes)
{
//    bool bReturnVal = true;
    int8_t buff_indx = 0;
    AM_CRITICAL_BEGIN_VOS;
    am_audio_buffer_push(buffer_push_to, pvSource, ui32Bytes);
    for(buff_indx=buffer_push_to-1; buff_indx >= 0; buff_indx--)
    {
        if(!am_audio_buffer_empty((enum_audio_buffer_t)buff_indx))
            break;
//        bReturnVal = am_audio_buffer_index_set((enum_audio_buffer_t)buff_indx, g_sAmUtil.sRingBuf[buffer_push_to].ui32BufferTail_write);
        am_audio_buffer_index_set((enum_audio_buffer_t)buff_indx, g_sAmUtil.sRingBuf[buffer_push_to].ui32BufferTail_write);
//        if(buff_indx == AM_AUDIO_BUFFER_STEREO)
//        {
//            AM_VOS_LOG_DEBUG("--\n");
//        }
    }
    AM_CRITICAL_END_VOS;
}

//*****************************************************************************
//
// specific-optimized functions: nested_pop
// parameters:
//          buffer_pop_from: the source ring buffer where we pop data from
//          buffer_dest: consider it as sub buffer, where the data go to finally
//          pvDest: buffer of destination
//          ui32Bytes: how many bytes needs to be pushed
//
// We don't move the ptrs while poping data
//
//*****************************************************************************
void am_audio_buffer_nested_pop(enum_audio_buffer_t buffer_pop_from, void *pvDest, uint32_t ui32Bytes)
{
    AM_CRITICAL_BEGIN_VOS;
    //
    // We don't move ptrs while poping
    //
    am_audio_buffer_pop(buffer_pop_from, pvDest, ui32Bytes);
    AM_CRITICAL_END_VOS;

}

//
// buffer overwritten check function(buff_1, buff_2)
// Usage:
//       check whether buff1 and buff2 overwritten with each other
//
// Return:
//       True:                  there is no over-write between 2 buffers
//       False:                 over-write happened between these 2 buffers!
bool am_audio_buffer_overwrite_check(am_vos_ring_buffer_t* p_nested_buff_1, am_vos_ring_buffer_t* p_nested_buff_2)
{
    //
    // check both 2 buffers empty or not.
    // if empty, there is no over-write could happen.
    //
    if(am_vos_ring_buffer_empty(p_nested_buff_1) || am_vos_ring_buffer_empty(p_nested_buff_2))
        return true;
    //
    // check whether nested_buff_1 tail is between head and tail of nested_buff_2
    //
    if(p_nested_buff_2->ui32BufferTail_write > p_nested_buff_2->ui32BufferHead_read)
    {
        if((p_nested_buff_1->ui32BufferTail_write > p_nested_buff_2->ui32BufferHead_read) &&
            (p_nested_buff_1->ui32BufferTail_write <= p_nested_buff_2->ui32BufferTail_write))
            return false;
    }
    if(p_nested_buff_2->ui32BufferTail_write < p_nested_buff_2->ui32BufferHead_read)
    {
        if((p_nested_buff_1->ui32BufferTail_write >p_nested_buff_2->ui32BufferHead_read) ||
            (p_nested_buff_1->ui32BufferTail_write <= p_nested_buff_2->ui32BufferTail_write))
            return false;
    }

    //
    // check whether nested_buff_2 tail is between head and tail of nested_buff_1
    //
    if(p_nested_buff_1->ui32BufferTail_write > p_nested_buff_1->ui32BufferHead_read)
    {
        if((p_nested_buff_2->ui32BufferTail_write > p_nested_buff_1->ui32BufferHead_read) &&
            (p_nested_buff_2->ui32BufferTail_write <= p_nested_buff_1->ui32BufferTail_write))
            return false;
    }
    if(p_nested_buff_1->ui32BufferTail_write < p_nested_buff_1->ui32BufferHead_read)
    {
        if((p_nested_buff_2->ui32BufferTail_write > p_nested_buff_1->ui32BufferHead_read) ||
            (p_nested_buff_2->ui32BufferTail_write <= p_nested_buff_1->ui32BufferTail_write))
            return false;
    }

    return true;
}

//
// buffer overwritten check function
// parameters:
//          nested_buff_list: the list of all paris of ptrs need to be checked.
//
//
bool am_audio_universal_buffer_status_check(am_vos_ring_buffer_t* nested_buff_list)
{
    uint32_t index = 0;
    uint32_t buff_indx_2 =0;
    for(index=0; index<AM_AUDIO_BUFFER_MAX; index++)
    {
        buff_indx_2 = index +1;

        while(buff_indx_2 < AM_AUDIO_BUFFER_MAX)
        {
            if(am_audio_buffer_overwrite_check(&nested_buff_list[index], &nested_buff_list[buff_indx_2]) == false)
                return false;
            buff_indx_2++;
        }

    }
    return true;

}

//
// return how many data left in the ring buffer
//
uint32_t am_audio_buffer_data_size_bytes(enum_audio_buffer_t buff_type)
{
    uint32_t ui32BuffDataSize = 0;
    if(buff_type > AM_AUDIO_BUFFER_MAX)
    {
        // type error
        return false;
    }
    AM_CRITICAL_BEGIN_VOS;
    ui32BuffDataSize = am_vos_get_ring_buffer_status(&(g_sAmUtil.sRingBuf[buff_type]));
    AM_CRITICAL_END_VOS;

    return ui32BuffDataSize;
}
