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

soundcard.cpp

/***************************************************************************
                         soundcard.cpp  -  QSSTV
                             -------------------
    begin                : Wed Jan 17 13:46:56 CET 2001
    copyright            : (C) 2001 by Johan Maes - ON1MH
    email                : on1mh@pandora.be
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "soundcard.h"
#include <sys/soundcard.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <qtimer.h>

//#define DEBUGSOUNDCARD

#define MODE AFMT_S16_LE

soundcard::soundcard(int i_samplingrate)
{
      status=CLOSED;
      dspInfo.speed=i_samplingrate;
      timer1=new QTimer(this);
      timer2=new QTimer(this);
      started=FALSE;
#ifdef DEBUGSOUNDCARD
  debug("soundcard created");
#endif
      connect(timer1,SIGNAL(timeout()),SLOT(writeNext()));
      connect(timer2,SIGNAL(timeout()),SLOT(slotStop()));
}


soundcard::~soundcard()
{
#ifdef DEBUGSOUNDCARD
      debug("soundcard: deleted=%ux",this);
#endif
      stop();
//    delete timer1;
//    delete timer2;

}


void soundcard::setSamplingrate(int s)
{
 dspInfo.speed=s;
}

void  soundcard::stop()
{
#ifdef DEBUGSOUNDCARD
      debug("soundcard: stop=%x",this);
#endif
  if (status!=CLOSED)
    {      
      close(dspInfo.fdDSP);
      status=CLOSED;
      started=FALSE;
      emit signalStopped();
    }
    timer1->stop();
    timer2->stop();
    busy=FALSE;
}

/** returns the number of samples to be transmitted */
int soundcard::waitEnd()
{
  audio_buf_info info;
  ioctl(dspInfo.fdDSP, SNDCTL_DSP_GETOSPACE, &info);
  return((info.fragstotal-info.fragments)*audioBufferLen/sizeof(int));
}

bool  soundcard::setParam(int format, int fragsize,int channels,QString &errorString)
{
  uint fs;
  int temp;
  dspInfo.channels=channels;
  dspInfo.format=format;


  for (fs=0;fragsize>0;fs++)
    {
      fragsize>>=1;
    }

  dspInfo.fragSize=0xffff0000+fs;  // encoded as MMMMSSSS where SSSS is the power of 2
    
  // set number of channels
  if (ioctl (dspInfo.fdDSP, SNDCTL_DSP_CHANNELS,&(dspInfo.channels)))
    {
      errorString="Error on ioctl SNDCTL_DSP_CHANNELS";
      return FALSE;
    }
  /* set the format */
  int reqFormat=dspInfo.format;
  if (ioctl (dspInfo.fdDSP, SNDCTL_DSP_SETFMT, &(dspInfo.format)))
    {
      errorString="Error on ioctl SNDCTL_DSP_SETFMT";
      return FALSE;
    }
  
  if (dspInfo.format !=reqFormat )
    {
      errorString="Requested Format not supported";
      return FALSE;
    }
  
  /* set the sampling rate */
  if (ioctl (dspInfo.fdDSP, SNDCTL_DSP_SPEED, &(dspInfo.speed)))
    {
      errorString="Error on ioctl SNDCTL_DSP_SPEED";
      return FALSE;
    }
  ioctl(dspInfo.fdDSP,SOUND_PCM_READ_RATE,&temp)      ;

  if (ioctl (dspInfo.fdDSP, SNDCTL_DSP_SETFRAGMENT,&(dspInfo.fragSize)))
    {
#ifdef DEBUGSOUNDCARD
                  debug("soundcard: setfragment failed");
#endif
      // no action -we'll do our best...
    }
  // and read it back
  if(ioctl(dspInfo.fdDSP,SNDCTL_DSP_GETBLKSIZE,&(dspInfo.fragSize)))
    {
      errorString="Error on reading fragsize";
      return FALSE;
    }
  audioBufferLen=dspInfo.fragSize;
  return TRUE;  
}




bool soundcard::startReceive(const char *s,QString &errorString)
{
  stop();
#ifdef DEBUGSOUNDCARD
      debug("soundcard: startReceive=%x",this);
#endif
  if ((dspInfo.fdDSP = open (s, O_RDONLY)) == -1)
    {
      errorString="Cannot open sounddevice";
      return (FALSE);
    }
  if(setParam(MODE, AUDIOBUFFERSIZE,1,errorString)==FALSE)
    { 
      close(dspInfo.fdDSP);
      return FALSE;
    }
  status=OPENFORREAD;
  return TRUE;
}



bool soundcard::startTransmit(const char *s,QString &errorString)
{
  stop();
#ifdef DEBUGSOUNDCARD
      debug("soundcard: startTransmit=%x",this);
#endif
  if ((dspInfo.fdDSP = open (s, O_WRONLY,0)) == -1)
    {
      errorString="Cannot open sounddevice";
      return FALSE;
    }
  if(setParam(MODE, AUDIOBUFFERSIZE,1,errorString)==FALSE)
    {
      close(dspInfo.fdDSP);
      return FALSE;
    }

  status=OPENFORWRITE;
  return TRUE;
}

bool soundcard::startFullDuplex(const char *s,QString &errorString)
{
  stop();
  errorString="";
  if ((dspInfo.fdDSP = open (s, O_RDWR,0)) == -1)
    {
      errorString="Cannot open sounddevice";
      return FALSE;
    }
      if (ioctl(dspInfo.fdDSP, SNDCTL_DSP_SETDUPLEX, 0))
            {
                  errorString="Cannot set to duplex";
                  return FALSE;
            }
      if (ioctl(dspInfo.fdDSP, SNDCTL_DSP_GETCAPS, &dspInfo.caps))
            {
                  errorString="Cannot get caps";
                  return FALSE;
            }
            
      if ((dspInfo.caps&DSP_CAP_DUPLEX) != DSP_CAP_DUPLEX)  /* we have to have a full duplex audio */
            {
                  errorString="Cannot set to fullduplex";
                  return FALSE;
            }
  if(setParam(MODE , AUDIOBUFFERSIZE,1,errorString)==FALSE)
    {
      close(dspInfo.fdDSP);
      return FALSE;
    }
  status=OPENFORREADWRITE;
  return TRUE;
}

int soundcard::readBuffer(char * audioBuffer)
{
      audio_buf_info info;
      int len;
      if (started)
            {
                  ioctl(dspInfo.fdDSP, SNDCTL_DSP_GETISPACE, &info);
      if(info.fragments==0)
            {
                              return 0;
                        }
                  fragmentLatency=info.fragments;
            }
      else
            {
      started=TRUE;
            }
      len = ::read(dspInfo.fdDSP,audioBuffer,audioBufferLen);
#ifdef DEBUGSOUNDCARD
      debug("latency %d %d",fragmentLatency,len);
#endif
      return len;
}

int soundcard::writeBuffer(char * audioBuffer)
{
 audio_buf_info info;
#ifdef DEBUGSOUNDCARD
      if (status==CLOSED) debug("soundcard: status closed during write ");
#endif
 ioctl(dspInfo.fdDSP, SNDCTL_DSP_GETOSPACE, &info);
 if(info.fragments<=(info.fragstotal/2))
    {
      return 0;
    }
  int len;
      len = ::write(dspInfo.fdDSP,audioBuffer,audioBufferLen);
  return len;  
}



/** sends a complete buffer to the audio interface */
/** if called with length=0, the transmission is stopped */
bool soundcard::write(short int *iLongBuffer,uint length)
{
      if(busy) return FALSE;
      if (length==0)
            {
                  delayedStop();
            }
      else
            {
                  longBuffer=(char *)iLongBuffer;
                  writeLength=length*sizeof(short int);
                  
                  writeIndex=0;
                  timer1->start(0,TRUE);
                  busy=TRUE;
            }
      return TRUE;
}
      
void soundcard::writeNext()
{
  if(writeBuffer(&longBuffer[writeIndex])==0)
    {
      timer1->start(100,TRUE); //buffers are full -> wait
    }
  else
    {
      writeIndex+=audioBufferLen;
      if(writeIndex>writeLength)
                        {
                        busy=FALSE;
                        emit signalTransmitBufferAvailable();
                  }
      timer1->start(0,TRUE);
    }
}


void soundcard::delayedStop()
{
      int delay=(waitEnd()*1000)/dspInfo.speed;
#ifdef DEBUGSOUNDCARD
      debug("soundard: delayedstop %d",delay);
#endif

      timer2->start(delay,TRUE);
}

void soundcard::slotStop()
{
#ifdef DEBUGSOUNDCARD
      debug("soundcard: slotStop=%lx",(long unsigned int)this);
#endif      
      stop();
}

Generated by  Doxygen 1.6.0   Back to index