/*
 * audio_encap.c: The audio encapsulator implementation
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id: audio_encap.c,v 1.4 2005/10/31 14:29:13 cm Exp $
 */

#include <string.h>
#include "audio_encap.h"

// --- cEncapsulator ----------------------------------------------------------

cEncapsulator::cEncapsulator() :
  m_pcmChannels(0), m_pcmFrequency(0), m_pesStreamId(0),
  m_pesFlags(0), mp_offset(NULL) {
}

cEncapsulator::~cEncapsulator() {
}

int cEncapsulator::Data(const uint8_t *payload, int length) {
  memset(m_buffer, 0x00, PES_MAX_PACKSIZE);
  if (PES_MAX_PACKSIZE >= length + PES_HEADER_LEN + LPCM_HEADER_LEN) {
    mp_offset = m_buffer + (PES_MAX_PACKSIZE - length);
    memcpy(mp_offset, payload, length);
  } else
    return 0;

  return PES_MAX_PACKSIZE - (mp_offset - m_buffer);
}

void cEncapsulator::SetPcmParameters(uint8_t channels, uint16_t frequency) {
  m_pcmChannels = channels - 1;  // n - 1 = n channels

  switch (frequency) {
    case 48000:
      m_pcmFrequency = 0x00;
      break;
    case 96000:
      m_pcmFrequency = 0x10;
      break;
    case 44100:
      m_pcmFrequency = 0x20;
      break;
    case 32000:
      m_pcmFrequency = 0x30;
      break;
  }
}

int cEncapsulator::ToPcm(uint8_t **packet = NULL) {
  // LINEAR PULSE CODE MODULATION Packet
  // lpcm->sub_stream_id
  *(mp_offset-7) = 0xA0;
  // lpcm->number_of_frame_headers
  *(mp_offset-6) = 0xFF;
  // lpcm->first_access_unit_pointer:16
  // *(mp_offset-5) = 0x00;
  // *(mp_offset-4) = 0x00;
  // lpcm->audio_emphasis_flag:1
  // lpcm->audio_mute_flag:1
  // lpcm->reserved1:1
  // lpcm->audio_frame_number:5
  // *(mp_offset-3) = 0x00;
  // lpcm->quantisation_word_length:2
  // lpcm->audio_sample_frequency:2
  // lpcm->reserved2:1
  // lpcm->number_of_audio_channels:3
  *(mp_offset-2) = m_pcmFrequency | m_pcmChannels;
  // lpcm->dynamic_range_x:3
  // lpcm->dynamic_range_y:5
  *(mp_offset-1) = 0x80;

  mp_offset-=LPCM_HEADER_LEN;
  if (packet)
    *packet = mp_offset;

  return PES_MAX_PACKSIZE - (mp_offset - m_buffer);
}

void cEncapsulator::SetPesParameters(uint8_t streamId, uint16_t flags) {
  m_pesStreamId = streamId;
  m_pesFlags = flags;
}

int cEncapsulator::ToPes(uint8_t **packet = NULL) {
  int l = PES_MAX_PACKSIZE - (mp_offset - m_buffer);

  // PACKETIZED ELEMENTARY STREAM Packet
  // pes->packet_start_code_prefix[x]
  // *(p_offset-9) = *(p_offset-8) = 0x00;
  *(mp_offset-7) = 0x01;
  // pes->stream_id
  *(mp_offset-6) = m_pesStreamId;
  // pes->packet_length:16 ; AUDIO_PACKSIZE + LPCM_HEADER_LEN + 3 bytes of pes header ext
  *(mp_offset-5) = (uint8_t)(l >> 8);
  // add 3 bytes for pes header extension
  *(mp_offset-4) = (uint8_t)((l+3) & 0x00FF);
  // pes->header_flags:16
  *(mp_offset-3) = 0x80 | m_pesFlags >> 8;
  *(mp_offset-2) = m_pesFlags & 0x00FF;
  // pes->header_length
  // *(p_offset-1) = 0x00;

  mp_offset -= PES_HEADER_LEN;
  if (packet)
    *packet = mp_offset;

  return PES_MAX_PACKSIZE - (mp_offset - m_buffer);
}
