Logo Search packages:      
Sourcecode: qarecord version File versions  Download package

capture.cpp

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <sys/mman.h>
#include <qsignal.h>
#include <qthread.h>
#include <qwaitcondition.h>
#include "recdata.h"
#include "capture.h"

Capture::Capture(long periodSize, RecData *p_recdata) {

  recdata = p_recdata;
}

Capture::~Capture(){        

  free(periodBuf);
}

snd_pcm_t *Capture::open_pcm() {
  
  snd_pcm_t *pcm_handle;
  snd_pcm_stream_t stream;
  snd_pcm_hw_params_t *hwparams;
  snd_pcm_uframes_t buffersize_return;
  unsigned int tmp;

  stream = SND_PCM_STREAM_CAPTURE; 
  if (snd_pcm_open(&pcm_handle, recdata->pcmName.latin1(), stream, 0) < 0) {
    fprintf(stderr, "Error opening PCM device %s\n", recdata->pcmName.latin1());
    return(NULL);
  }
  snd_pcm_hw_params_alloca(&hwparams);
  if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
    fprintf(stderr, "Can not configure this PCM device.\n");
    return(NULL);
  }
  if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
    fprintf(stderr, "Error setting access.\n");
    return(NULL);
  }
  if (recdata->samplesize == 2) {
    if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
      fprintf(stderr, "Error setting format.\n");
      return(NULL);
    }
  } else {
    if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S32_LE) < 0) {
      fprintf(stderr, "Error setting format.\n");
      return(NULL);
    }
  }
  tmp = (unsigned int)recdata->rate;
  if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &tmp, 0) < 0) {
    fprintf(stderr, "Error setting rate.\n");
    return(NULL);
  }
  if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, recdata->channels) < 0) {
    fprintf(stderr, "Error setting channels.\n");
    return(NULL);
  }
  if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, recdata->periods, 0) < 0) {
    fprintf(stderr, "Error setting periods.\n");
    return(NULL);
  }
  buffersize_return = recdata->periodsize * recdata->periods;
  if ((snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, 
                           &buffersize_return)) < 0) {
    fprintf(stderr, "Error setting buffersize.\n");
    return(NULL);
  }
  if (buffersize_return != (snd_pcm_uframes_t)(recdata->periodsize * recdata->periods)) {
    fprintf(stderr, "Periodsize %d is not available on your hardware. Using %d instead.\n", 
            recdata->periodsize, (int)buffersize_return / recdata->periods);
    recdata->periodsize = buffersize_return / recdata->periods;
    periodBuf = (unsigned char *)realloc(periodBuf, recdata->periodsize * recdata->framesize);
  }
  if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) {
    fprintf(stderr, "Error setting HW params.\n");
    return(NULL);
  }
  fprintf(stderr, "Using periodsize %d frames.\n", recdata->periodsize);
  return(pcm_handle);
}


void Capture::run() {

  int l1, pcmreturn;
  short s;
  int i, max[2];

  periodBuf = (unsigned char *)malloc(recdata->periodsize * recdata->framesize);
  if (!(capture_handle = open_pcm())) {
    fprintf(stderr, "Could not open PCM for capture.\n");
    recdata->doRecord = false;        
    recdata->doCapture = false;
  }
  recdata->writeOfs = 0;
  struct sched_param schp;
  memset(&schp, 0, sizeof(schp));
  schp.sched_priority = sched_get_priority_max(SCHED_FIFO);
  if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {
    fprintf(stderr, "can't set sched_setscheduler - using normal priority\n");
  } else {
    printf("set SCHED_FIFO\n");
  }
  recdata->validByteCount = 0;
  max[0] = 0;
  max[1] = 0;
  while(recdata->doCapture) {
    while ((pcmreturn = snd_pcm_readi(capture_handle, periodBuf, recdata->periodsize)) < 0) {
      snd_pcm_prepare(capture_handle);
      fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Overrun >>>>>>>>>>>>>>>\n");
    }
    for (l1 = 0; l1 < recdata->periodsize * recdata->framesize; l1++) {  
      recdata-> ringBuf[recdata->writeOfs++] = periodBuf[l1];
      if (recdata->writeOfs >= recdata->ringBufSize) recdata->writeOfs -= recdata->ringBufSize;
    }
    if (recdata->samplesize == 2) {
      for (l1 = 0; l1 < recdata->periodsize; l1++) {
        s = periodBuf[4*l1] | (periodBuf[4*l1 + 1] << 8);
        s = abs(s);
        if (s > max[0]) max[0] = s;
        s = periodBuf[4*l1 + 2] | (periodBuf[4*l1 + 3] << 8);
        s = abs(s);
        if (s > max[1]) max[1] = s;
      }
    } else {
      for (l1 = 0; l1 < recdata->periodsize; l1++) {
        i = periodBuf[8*l1] | (periodBuf[8*l1 + 1] << 8) | (periodBuf[8*l1 + 2] << 16) | (periodBuf[8*l1 + 3] << 24);
        i = abs(i);
        if (i > max[0]) max[0] = i;
        i = periodBuf[8*l1 + 4] | (periodBuf[8*l1 + 5] << 8) | (periodBuf[8*l1 + 6] << 16) | (periodBuf[8*l1 + 7] << 24);
        i = abs(i);
        if (i > max[1]) max[1] = i;
      }
    } 
    if (recdata->newMax) {
//      fprintf(stderr, "%d %d\n", max[0], max[1]);
      recdata->newMax = false;
      recdata->max[0] = max[0];
      recdata->max[1] = max[1];
      max[0] = 0;  
      max[1] = 0;  
    }
    if (recdata->doRecord) {
      recdata->validByteCount += recdata->periodsize * recdata->framesize;
      if (recdata->validByteCount > recdata->maxValidByteCount) {
        recdata->maxValidByteCount = recdata->validByteCount;
      }
      recdata->waitForData.wakeOne();
    }
    if (recdata->writeOfs >= recdata->ringBufSize) recdata->writeOfs -= recdata->ringBufSize;
  } 
  snd_pcm_close(capture_handle);
  free (periodBuf);
}

Generated by  Doxygen 1.6.0   Back to index