#include "pcmdma.h"
#include <pthread.h>
#include <alsa/asoundlib.h>
#include <signal.h>

struct Sample {
  short l;
  short r;
}__attribute__((packed));

static constexpr unsigned BufLen = FULL_LEN;

static const char *device = "default";
static snd_pcm_t  *handle;

static int open_alsa_device (int channels, int srate) {
  int err;
  if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
    printf("Playback open error: %s\n", snd_strerror(err));
    return 0;
  }
  if ((err = snd_pcm_set_params(handle,
                                SND_PCM_FORMAT_S16_LE,
                                SND_PCM_ACCESS_RW_INTERLEAVED,
                                channels,
                                srate,
                                1,
                                500000)) < 0) { /* 0.5sec */
    printf("Playback open error: %s\n", snd_strerror(err));
    return 0;
  }
  return 1;
}
int alsa_write (const void * buf, int len) {
  snd_pcm_sframes_t frames;
  int err = 0;
  frames = snd_pcm_writei(handle, buf, len);
  if (frames < 0)
    frames = snd_pcm_recover(handle, frames, 0);
  if (frames < 0) {
    printf("snd_pcm_writei failed: %s\n", snd_strerror(err));
    return 0;
  }
  if (frames > 0 && frames < (long)sizeof(buf))
    printf("Short write (expected %i, wrote %li)\n", len, frames);
  return len;
}
void sig_handler (int signum) {
  printf(" - Received signal %d\n", signum);
  ::exit (0);
}

static constexpr int CC = MAXPWM / 2;

static pthread_t rc;

void * WriteHandler (void * data) {
  printf ("Start thread\n");
  PcmDma * pA = (PcmDma *) data;
  Sample buf [BufLen];
  uint16_t * pbuf = pA->getBuff();
  for (;;) {
    pA->send (false);
    pA->send (true);
    //printf ("pass\n");
    for (unsigned i=0; i<BufLen; i++) {
      const short s = (pbuf [i] - CC) * 10;
      buf[i].l = s; buf[i].r = s;
    }
    alsa_write (buf, BufLen);
  }
  return NULL;
}

PcmDma::PcmDma() noexcept : pL(buffer), pH(buffer + HALF_LEN), src(nullptr) {
  signal (SIGINT, sig_handler);
  open_alsa_device(2, 24000);
  pthread_create (&rc, NULL, WriteHandler,  this);
}