Logo Search packages:      
Sourcecode: pwlib version File versions

qsa.cxx

/*
 * qsa.cxx
 *
 * QNX Sound Architecture
 */

#pragma implementation "sound.h"

#include <ptlib.h>
#include <stdio.h>
#include <sys/asoundlib.h>

typedef struct _SoundHandleEntry {
      struct _SoundHandleEntry *next;
      
      int handle;
      int direction;

      unsigned numChannels;
      unsigned sampleRate;
      unsigned bitsPerSample;
      unsigned fragmentValue;
      BOOL isInitialised;
      
      snd_pcm_t   *pcm_handle;
      int         card;
      int         dev;
      snd_mixer_t *mixer_handle;
      snd_mixer_group_t group;
} SoundHandleEntry;

static SoundHandleEntry *SoundHandleList;
static pthread_rwlock_t SoundHandleLock = PTHREAD_RWLOCK_INITIALIZER;

static int snd_openmode[2] = {SND_PCM_OPEN_CAPTURE, SND_PCM_OPEN_PLAYBACK};
static int snd_chnmode[2]  = {SND_PCM_CHANNEL_CAPTURE, SND_PCM_CHANNEL_PLAYBACK};

PSound::PSound(unsigned channels,
               unsigned samplesPerSecond,
               unsigned bitsPerSample,
               PINDEX   bufferSize,
               const BYTE * buffer)
{
      encoding = 0;
      numChannels = channels;
      sampleRate = samplesPerSecond;
      sampleSize = bitsPerSample;
      SetSize(bufferSize);
      if (buffer != NULL)
        memcpy(GetPointer(), buffer, bufferSize);
}


PSound::PSound(const PFilePath & filename)
{
      encoding = 0;
      numChannels = 1;
      sampleRate = 8000;
      sampleSize = 16;
      Load(filename);
}


PSound & PSound::operator=(const PBYTEArray & data)
{
      PBYTEArray::operator=(data);
      return *this;
}


void PSound::SetFormat(unsigned channels,
                       unsigned samplesPerSecond,
                       unsigned bitsPerSample)
{
      encoding = 0;
      numChannels = channels;
      sampleRate = samplesPerSecond;
      sampleSize = bitsPerSample;
      formatInfo.SetSize(0);
}


BOOL PSound::Load(const PFilePath & /*filename*/)
{
      return FALSE;
}


BOOL PSound::Save(const PFilePath & /*filename*/)
{
      return FALSE;
}


BOOL PSound::Play()
{
      PSoundChannel channel(PSoundChannel::GetDefaultDevice(PSoundChannel::Player),
                                      PSoundChannel::Player);
      if (!channel.IsOpen())
        return FALSE;
      
      return channel.PlaySound(*this, TRUE);
}


BOOL PSound::PlayFile(const PFilePath & file, BOOL wait)
{
      PSoundChannel channel(PSoundChannel::GetDefaultDevice(PSoundChannel::Player),
                                      PSoundChannel::Player);
      if (!channel.IsOpen())
        return FALSE;
      
      return channel.PlayFile(file, wait);
}


PSoundChannel::PSoundChannel()
{
      Construct();
}


PSoundChannel::PSoundChannel(const PString & device,
                             Directions dir,
                             unsigned numChannels,
                             unsigned sampleRate,
                             unsigned bitsPerSample)
{
      Construct();
      Open(device, dir, numChannels, sampleRate, bitsPerSample);
}


void PSoundChannel::Construct()
{
      os_handle = -1;
}


PSoundChannel::~PSoundChannel()
{
      Close();
}


PStringArray PSoundChannel::GetDeviceNames(Directions dir)
{
      PStringList devices;
      PDirectory  devdir = "/dev/snd";
      
      if (!devdir.Open())
        return NULL;

      do {
            PString filename = devdir.GetEntryName();
            PString devname = devdir + filename;

            if ((filename.GetLength() > 3) && (filename.Left(3) == "pcm") &&
                  (filename.Right(1) == (dir == Recorder ? "r" : "p")))
            {
                  int fd = ::open(filename, O_RDONLY);
                  if (fd >= 0) {
                        devices.AppendString(filename);
                        ::close(fd);
                  }
            }
      } while (devdir.Next());
      return devices;
}


PString PSoundChannel::GetDefaultDevice(Directions dir)
{
      PString filename;
      
      if (dir == Player)
        filename = "/dev/snd/pcmPreferredp";
      else
        filename = "/dev/snd/pcmPreferredc";
      
      int fd = ::open(filename, O_RDONLY);
//    PTRACE(1, "GetDefaultDevice; fd = " << fd << ", filename ='" << filename <<"'\n");
      if (fd >=0) {
            ::close (fd);
            return filename;
      } else {
            return (filename = "/dev/null");
      }
}


BOOL PSoundChannel::Open(const PString & _device,
                                     Directions _dir,
                                     unsigned _numChannels,
                                     unsigned _sampleRate,
                                     unsigned _bitsPerSample)
{
      Close();
      
      // make the direction value 1 or 2
      int dir = _dir + 1;

      SoundHandleEntry *entry;
      
      pthread_rwlock_wrlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle; entry = entry->next);
      
      if (entry) {

            PTRACE(6, "OSS\tOpen occured for existing entry");
            
            // see if the sound channel is already open in this direction
            if ((entry->direction & dir) != 0) {
                  pthread_rwlock_unlock(&SoundHandleLock);
                  return FALSE;
            }
            
            // flag this entry as open in this direction
            entry->direction |= dir;
            os_handle = entry->handle;
      } else {
            
            PTRACE(6, "OSS\tOpen occured for new entry");
            
            SoundHandleEntry *entry = (SoundHandleEntry *)::malloc(sizeof(*entry));
            
            if (!entry) {
                  pthread_rwlock_unlock(&SoundHandleLock);
                  return FALSE;
            }

            // this is the first time this device has been used
            // open the device in read/write mode always
            if (((_dir == Player) && _device == "/dev/snd/pcmPreferredp") ||
                  ((_dir == Recorder) && _device == "/dev/snd/pcmPreferredc"))
            {
                  os_handle = snd_pcm_open_preferred(&entry->pcm_handle, &entry->card, &entry->dev, snd_openmode[_dir]);
            } else {
                  if (sscanf(_device, "/dev/snd/pcmC%iD%i", &entry->card, &entry->dev) != 2) {
                        errno = ESRCH;
                        return ConvertOSError(os_handle);
                  }
                  os_handle = snd_pcm_open(&entry->pcm_handle, entry->card, entry->dev, snd_openmode[_dir]);
            }
            
            if (os_handle < 0) {
                  errno = -os_handle;
                  os_handle = 0;
                  return ConvertOSError(os_handle);
            }

            if (snd_pcm_plugin_set_disable(entry->pcm_handle, PLUGIN_DISABLE_MMAP) < 0)
              return FALSE;
      
            // save the information into the dictionary entry
            os_handle            = snd_pcm_file_descriptor(entry->pcm_handle, snd_chnmode[_dir]);
            entry->handle        = os_handle;
            entry->direction     = dir;
            entry->numChannels   = mNumChannels     = _numChannels;
            entry->sampleRate    = actualSampleRate = mSampleRate    = _sampleRate;
            entry->bitsPerSample = mBitsPerSample   = _bitsPerSample;
            entry->isInitialised = FALSE;
            entry->fragmentValue = 0x7fff0008;
            entry->mixer_handle  = 0;
            
            entry->next          = SoundHandleList;
            SoundHandleList      = entry;
      }
      pthread_rwlock_unlock(&SoundHandleLock);
      
      // save the direction and device
      direction     = _dir;
      device        = _device;
      isInitialised = FALSE;
      
      return TRUE;
}

BOOL PSoundChannel::Setup()
{
      if (os_handle < 0) {
            PTRACE(6, "OSS\tSkipping setup of " << device << " as not open");
            return FALSE;
      }
      
      if (isInitialised) {
            PTRACE(6, "OSS\tSkipping setup of " << device << " as instance already initialised");
            return TRUE;
      }

      SoundHandleEntry *entry;
      pthread_rwlock_rdlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle;
             entry = entry->next);
      
      // set default return status
      BOOL stat = TRUE;
      
      // do not re-initialise initialised devices
      if (entry->isInitialised) {
            pthread_rwlock_unlock(&SoundHandleLock);
            PTRACE(6, "OSS\tSkipping setup for " << device << " as already initialised");
            return stat;
      }
      
      PTRACE(6, "OSS\tInitialising " << device << "(" << (void *)(&entry) << ")");

    stat = FALSE;
      
      mBitsPerSample = entry->bitsPerSample;
      mNumChannels = entry->numChannels;
      mSampleRate = entry->sampleRate;

      snd_pcm_channel_params_t pp;

      memset(&pp, 0, sizeof(pp));
      pp.channel = snd_chnmode[direction];
      pp.mode = SND_PCM_MODE_BLOCK;
      pp.start_mode = (direction == Player) ? SND_PCM_START_FULL : SND_PCM_START_DATA;
      pp.stop_mode = SND_PCM_STOP_STOP;
      pp.buf.block.frags_min = 1;
      pp.buf.block.frag_size = 1 << (entry->fragmentValue & 0xffff);
      pp.buf.block.frags_max = ((unsigned)entry->fragmentValue >> 16) & 0x7fff;
      if (pp.buf.block.frags_max == 0)
        pp.buf.block.frags_max = 65536;
            
      pp.format.interleave = 1;
      pp.format.rate = entry->sampleRate;
      pp.format.voices = entry->numChannels;
            
#if PBYTE_ORDER == PLITTLE_ENDIAN
      pp.format.format = (entry->bitsPerSample == 16) ? SND_PCM_SFMT_S16_LE : SND_PCM_SFMT_U8;
#else
      pp.format.format = (entry->bitsPerSample == 16) ? SND_PCM_SFMT_S16_BE : SND_PCM_SFMT_U8;
#endif
      
      if (snd_pcm_plugin_params(entry->pcm_handle, &pp) < 0) {
            pthread_rwlock_unlock(&SoundHandleLock);
            return stat;
      }
      
      if (snd_pcm_plugin_prepare(entry->pcm_handle, snd_chnmode[direction]) < 0) {
            pthread_rwlock_unlock(&SoundHandleLock);
            return stat;
      }
      
      /* also open the mixer */
      snd_pcm_channel_setup_t setup;
      
      memset(&setup, 0, sizeof(setup));
      memset(&entry->group, 0, sizeof(entry->group));
      setup.channel = snd_chnmode[direction];
      setup.mixer_gid = &entry->group.gid;
      
      if (snd_pcm_plugin_setup(entry->pcm_handle, &setup) < 0) {
            pthread_rwlock_unlock(&SoundHandleLock);
            return FALSE;
      }
            
      if (snd_mixer_open(&entry->mixer_handle, entry->card, setup.mixer_device) < 0) {
            pthread_rwlock_unlock(&SoundHandleLock);
            return FALSE;
      }
      
      actualSampleRate = setup.format.rate;
      stat = TRUE;

#if PTRACING
      PTRACE(4, "QSA: Frag Size = " << setup.buf.block.frag_size
                     << ", Rate = " << setup.format.rate
                   << ", Mixer Pcm Group [" << entry->group.gid.name << "]\n");
#endif

      pthread_rwlock_unlock(&SoundHandleLock);
      // ensure device is marked as initialised
      isInitialised        = TRUE;
      entry->isInitialised = TRUE;
      
      return stat;
}

BOOL PSoundChannel::Close()
{
      // if the channel isn't open, do nothing
      if (os_handle < 0)
        return TRUE;
      
      SoundHandleEntry *entry, **entryp;
      
      pthread_rwlock_wrlock(&SoundHandleLock);
      for (entryp = &SoundHandleList, entry = *entryp; entry && entry->handle != os_handle;
             entryp = &entry->next, entry = *entryp);
        
      if (!entry) {
            pthread_rwlock_unlock(&SoundHandleLock);
            return TRUE;
      }
      
      // modify the directions bit mask in the dictionary
      entry->direction ^= (direction+1);
      
      // if this is the last usage of this entry, then remove it
      if (entry->direction == 0) {
            snd_mixer_close(entry->mixer_handle);
            snd_pcm_plugin_flush(entry->pcm_handle, snd_chnmode[direction]);
            snd_pcm_close(entry->pcm_handle);
            *entryp = entry->next;
            ::free(entry);
            os_handle = -1;
            pthread_rwlock_unlock(&SoundHandleLock);
            return PChannel::Close();
      }
      
      // flag this channel as closed
      pthread_rwlock_unlock(&SoundHandleLock);
      return TRUE;
}

BOOL PSoundChannel::Write(const void * buf, PINDEX len)
{
      if (!Setup())
        return FALSE;
      
      if (os_handle < 0)
        return FALSE;
      
      SoundHandleEntry * entry;
      pthread_rwlock_rdlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle;
             entry = entry->next);
      
      snd_pcm_channel_status_t status;
      int written = 0;
      
      while ((written += snd_pcm_plugin_write(entry->pcm_handle, buf, len)) < len)
      {
            memset(&status, 0, sizeof(status));
            status.channel = SND_PCM_CHANNEL_PLAYBACK;
            if (snd_pcm_plugin_status(entry->pcm_handle, &status) < 0) {
                  pthread_rwlock_unlock(&SoundHandleLock);
                  return FALSE;
            }
            if (status.status == SND_PCM_STATUS_READY ||
                  status.status == SND_PCM_STATUS_UNDERRUN)
            {
                  if (snd_pcm_plugin_prepare(entry->pcm_handle, snd_chnmode[direction]) < 0) {
                        pthread_rwlock_unlock(&SoundHandleLock);                    
                        return FALSE;
                  }
            }
            if (written < 0)
              written = 0;
      }     
      pthread_rwlock_unlock(&SoundHandleLock);
      return TRUE;
}

BOOL PSoundChannel::Read(void * buf, PINDEX len)
{
      lastReadCount = 0;

      if (!Setup())
        return FALSE;

      if (os_handle < 0)
        return FALSE;

      SoundHandleEntry * entry;
      pthread_rwlock_rdlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle;
             entry = entry->next);
      
      PTRACE(6, "QSA\tRead start");
      
      lastReadCount = snd_pcm_plugin_read(entry->pcm_handle, buf, len);
      
    if (lastReadCount < len) {
            snd_pcm_channel_status_t status;
            
            memset(&status, 0, sizeof(status));
            status.channel = SND_PCM_CHANNEL_CAPTURE;
            if (snd_pcm_plugin_status(entry->pcm_handle, &status) < 0) {
                  pthread_rwlock_unlock(&SoundHandleLock);
                  PTRACE(6, "QSA\tRead failed");              
                  return FALSE;
            }
            
            if (status.status == SND_PCM_STATUS_READY ||
                  status.status == SND_PCM_STATUS_OVERRUN) {
                  if (snd_pcm_plugin_prepare(entry->pcm_handle, SND_PCM_CHANNEL_CAPTURE) < 0) {
                        pthread_rwlock_unlock(&SoundHandleLock);
                        PTRACE(6, "QSA\tRead failed");              
                        return FALSE;
                  }
            }
            PTRACE(6, "QSA\tRead completed short - " << lastReadCount << " vs " << len);
      } else {
            PTRACE(6, "QSA\tRead completed");
      }
      pthread_rwlock_unlock(&SoundHandleLock);
    return TRUE;
}

BOOL PSoundChannel::SetFormat(unsigned numChannels,
                              unsigned sampleRate,
                              unsigned bitsPerSample)
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);

      // check parameters
      PAssert((bitsPerSample == 8) || (bitsPerSample == 16), PInvalidParameter);
      PAssert(numChannels >= 1 && numChannels <= 2, PInvalidParameter);

      SoundHandleEntry * entry;
      pthread_rwlock_rdlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle;
             entry = entry->next);
      
      if (entry->isInitialised) {
            if ((numChannels   != entry->numChannels) ||
                  (sampleRate    != entry->sampleRate) ||
                  (bitsPerSample != entry->bitsPerSample)) {
                  pthread_rwlock_unlock(&SoundHandleLock);
                  PTRACE(6, "OSS\tTried to change read/write format without stopping");
                  return FALSE;
            }
            pthread_rwlock_unlock(&SoundHandleLock);
            return TRUE;
      }

      if (direction == Player) {
            snd_pcm_plugin_playback_drain(entry->pcm_handle);
      }

      entry->numChannels   = numChannels;
      entry->sampleRate    = sampleRate;
      entry->bitsPerSample = bitsPerSample;
      entry->isInitialised  = FALSE;
      pthread_rwlock_unlock(&SoundHandleLock);
      
      // mark this channel as uninitialised
      isInitialised = FALSE;
      
      return TRUE;
}

// Get  the number of channels (mono/stereo) in the sound.
unsigned PSoundChannel::GetChannels()   const
{
      return mNumChannels;
}

// Get the sample rate in samples per second.
unsigned PSoundChannel::GetSampleRate() const
{
      return actualSampleRate;
}

// Get the sample size in bits per sample.
unsigned PSoundChannel::GetSampleSize() const
{
      return mBitsPerSample;
}


BOOL PSoundChannel::SetBuffers(PINDEX size, PINDEX count)
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);

      //PINDEX totalSize = size * count;
      
      //size = 16;
      //count = (totalSize + 15) / 16;
      
      PAssert(size > 0 && count > 0 && count < 65536, PInvalidParameter);
      int arg = 1;
      while (size > (PINDEX)(1 << arg))
        arg++;
      
      arg |= count << 16;
      
      SoundHandleEntry * entry;
      pthread_rwlock_rdlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle;
             entry = entry->next);
      
      if (entry->isInitialised) {
            if (entry->fragmentValue != (unsigned)arg) {
                  pthread_rwlock_unlock(&SoundHandleLock);
                  PTRACE(6, "OSS\tTried to change buffers without stopping");
                  return FALSE;
            }
            pthread_rwlock_unlock(&SoundHandleLock);
            return TRUE;
      }
      
      if (direction == Player) {
            snd_pcm_plugin_playback_drain(entry->pcm_handle);
      }
      
      // set information in the common record
      entry->fragmentValue = arg;
      entry->isInitialised = FALSE;
      pthread_rwlock_unlock(&SoundHandleLock);
      
      // flag this channel as not initialised
      isInitialised       = FALSE;
      
      return TRUE;
}


BOOL PSoundChannel::GetBuffers(PINDEX & size, PINDEX & count)
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);
      
      SoundHandleEntry * entry;
      pthread_rwlock_rdlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle;
             entry = entry->next);
      
      int arg = entry->fragmentValue;
      
      count = arg >> 16;
      size = 1 << (arg&0xffff);
      pthread_rwlock_unlock(&SoundHandleLock);
      
      return TRUE;
}


BOOL PSoundChannel::PlaySound(const PSound & sound, BOOL wait)
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);
      
      Abort();
      
      if (!Write((const BYTE *)sound, sound.GetSize()))
        return FALSE;
      
      if (wait)
        return WaitForPlayCompletion();
      
      return TRUE;
}


BOOL PSoundChannel::PlayFile(const PFilePath & filename, BOOL wait)
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);
      
      PFile file(filename, PFile::ReadOnly);
      if (!file.IsOpen())
        return FALSE;
      
      for (;;) {
            BYTE buffer[256];
            if (!file.Read(buffer, 256))
              break;
            PINDEX len = file.GetLastReadCount();
            if (len == 0)
              break;
            if (!Write(buffer, len))
              break;
      }
      
      file.Close();
      
      if (wait)
        return WaitForPlayCompletion();
      
      return TRUE;
}


BOOL PSoundChannel::HasPlayCompleted()
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);
      
      SoundHandleEntry * entry;
      pthread_rwlock_rdlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle;
             entry = entry->next);
      
      snd_pcm_channel_status_t status;
      memset(&status, 0, sizeof(status));
      status.channel = snd_chnmode[direction];

      if (snd_pcm_plugin_status(entry->pcm_handle, &status) < 0) {
            pthread_rwlock_unlock(&SoundHandleLock);
            return FALSE;
      }

      int ret = (abs(status.free) / (entry->bitsPerSample / 8));
      pthread_rwlock_unlock(&SoundHandleLock);
      return ret;
}

BOOL PSoundChannel::WaitForPlayCompletion()
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);

      SoundHandleEntry * entry;
      pthread_rwlock_rdlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle;
             entry = entry->next);
      
      if (snd_pcm_playback_flush(entry->pcm_handle) < 0) {
            pthread_rwlock_unlock(&SoundHandleLock);
            return FALSE;
      }
      
      pthread_rwlock_unlock(&SoundHandleLock);
      return TRUE;
}


BOOL PSoundChannel::RecordSound(PSound & sound)
{
  if (os_handle < 0)
    return SetErrorValues(NotOpen, EBADF);

  return FALSE;
}


BOOL PSoundChannel::RecordFile(const PFilePath & filename)
{
  if (os_handle < 0)
    return SetErrorValues(NotOpen, EBADF);

  return FALSE;
}


BOOL PSoundChannel::StartRecording()
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);

      int fd = os_handle;
      fd_set fds;
      FD_ZERO(&fds);
      FD_SET(fd, &fds);
      struct timeval instant = {0, 0};
      return ConvertOSError(::select(fd + 1, &fds, NULL, NULL, &instant));
}


BOOL PSoundChannel::IsRecordBufferFull()
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);

      PTRACE(1, "IsRecordBufferFull()\n");
      /* do I suppose to get the status, and check sth ? */
      return TRUE;
}


BOOL PSoundChannel::AreAllRecordBuffersFull()
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);

      PTRACE(1, "AreAllRecordBuffersFull()\n");
      /* do I suppose to get the status, and check sth ? */
      return TRUE;
}


BOOL PSoundChannel::WaitForRecordBufferFull()
{
      if (os_handle < 0)
        return SetErrorValues(NotOpen, EBADF);
      
      PTRACE(1, "WaitForRecordBufferFull()\n");
      return PXSetIOBlock(PXReadBlock, readTimeout);
}


BOOL PSoundChannel::WaitForAllRecordBuffersFull()
{
      PTRACE(1, "WaitForAllRecordBuffersFull()\n");
      return FALSE;
}


BOOL PSoundChannel::Abort()
{
      if (direction == Player && os_handle != -1) {
      SoundHandleEntry * entry;
            pthread_rwlock_rdlock(&SoundHandleLock);
            for (entry = SoundHandleList; entry && entry->handle != os_handle;
                   entry = entry->next);
            
            snd_pcm_plugin_playback_drain(entry->pcm_handle);
            pthread_rwlock_unlock(&SoundHandleLock);
      }
      return TRUE;
}


BOOL PSoundChannel::SetVolume(unsigned newVal)
{
      if (os_handle < 0)
      {
            return FALSE;
      }

      SoundHandleEntry *entry;
      pthread_rwlock_rdlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle;
             entry = entry->next);
      
      int ret;
      
      if ((ret = snd_mixer_group_read(entry->mixer_handle, &entry->group)) < 0)
      {
            pthread_rwlock_unlock(&SoundHandleLock);
            cerr << "snd_mixer_group_read: " << strerror(-ret) << endl;
            return FALSE;
      }

      /* QSA treat the newVal as a percentage */
      newVal = (newVal  * (entry->group.max - entry->group.min) / 100) + entry->group.min;
      
      entry->group.volume.names.front_left = newVal;
      entry->group.volume.names.front_right = newVal;
      
      if ((ret = snd_mixer_group_write(entry->mixer_handle, &entry->group)) < 0)
      {
            pthread_rwlock_unlock(&SoundHandleLock);
            cerr << "snd_mixer_group_write: " << strerror(-ret) << endl;
            return FALSE;
      }
      pthread_rwlock_unlock(&SoundHandleLock);  
      return TRUE;
}

BOOL  PSoundChannel::GetVolume(unsigned &devVol)
{
      if (os_handle == 0)
      {
            return FALSE;
      }
  
      SoundHandleEntry *entry;
      pthread_rwlock_rdlock(&SoundHandleLock);
      for (entry = SoundHandleList; entry && entry->handle != os_handle;
             entry = entry->next);
      
      int ret;
      
      if ((ret = snd_mixer_group_read(entry->mixer_handle, &entry->group)) < 0)
      {
            pthread_rwlock_unlock(&SoundHandleLock);
            return FALSE;
      }
      pthread_rwlock_unlock(&SoundHandleLock);
      
      /* return the percentage */
      devVol = (unsigned)(entry->group.volume.names.front_left - entry->group.min) * 100
        / (entry->group.max - entry->group.min);

      return TRUE;
}
  


// End of file

Generated by  Doxygen 1.6.0   Back to index