/*
 * audio_buffer.h: The audio buffer implementation
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id: audio_buffer.c,v 1.1.1.1 2005/12/20 14:11:45 cm Exp $
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "audio_buffer.h"


// --- cSimpleRingBuffer -------------------------------------------------------

cSimpleRingBuffer::cSimpleRingBuffer(unsigned long size) {
  m_bufferSize = size;
  m_bufferFree = 0;
  mp_buffer = m_readPtr = m_writePtr = NULL;

  Initialize();
}

cSimpleRingBuffer::~cSimpleRingBuffer() {
  free(mp_buffer);
}

void cSimpleRingBuffer::Initialize(void) {
  mp_buffer = (uint8_t *)malloc(sizeof(uint8_t) * m_bufferSize);

  if (NULL != mp_buffer) {
    memset(mp_buffer, 0x00, m_bufferSize);
    m_writePtr = m_readPtr = mp_buffer;
    m_bufferFree = m_bufferSize;
  }
}

unsigned long cSimpleRingBuffer::Put(const uint8_t *data, unsigned long count) {
  unsigned long wc = count, remaining = 0;
  // lock me baby
  cMutexLock oLock(&mo_BufferMutex);

  if (m_bufferFree < count)
    wc = m_bufferFree;

////  printf("%s %s: data=%p count=%ld wc=%ld bufferFree=%ld\n", __FILE__, __FUNCTION__, data, count, wc, m_bufferFree);

  if (m_writePtr + wc <= mp_buffer + m_bufferSize) {
    // no wrapping
    memcpy(m_writePtr, data, wc);
    m_writePtr += wc;
  } else {
    // wrapping around
    remaining = (m_writePtr + wc) - (mp_buffer + m_bufferSize);
    memcpy(m_writePtr, data, wc - remaining);
    memcpy(mp_buffer, data + (wc - remaining), remaining);
    m_writePtr = mp_buffer + remaining;
  }

  m_bufferFree -= wc;

  return wc;
}

unsigned long cSimpleRingBuffer::Get(uint8_t *data, unsigned long count) {
  unsigned long gc = count, remaining = 0;
  // lock me baby
  cMutexLock oLock(&mo_BufferMutex);

  if (count > (m_bufferSize - m_bufferFree))
    gc = m_bufferSize - m_bufferFree;

  if (m_readPtr + gc <= mp_buffer + m_bufferSize) {
    // no wrapping
    memcpy(data, m_readPtr, gc);
    m_readPtr += gc;
  } else {
    // wrapping around
    remaining = (m_readPtr + gc) - (mp_buffer + m_bufferSize);
    memcpy(data, m_readPtr, gc - remaining);
    memcpy(data + (gc - remaining), mp_buffer, remaining);
    m_readPtr = mp_buffer + remaining;
  }

  m_bufferFree += gc;

  return gc;
}

void cSimpleRingBuffer::Clear(void) {
  cMutexLock oLock(&mo_BufferMutex);

  m_bufferFree = m_bufferSize;
  m_writePtr = m_readPtr = mp_buffer;
}
