[GnomeMeeting-devel-list] New Snap, kaput?



I've done the following changes:

1) ALSA

It is now possible to change the audio volumes using OSS or ALSA during
calls.

2) STARTUP

The bug reported by dominance and matti about GM not starting is PERHAPS
fixed, please tell me.

3) MUTEXES
I've made huge changes to the mutexes system to really make sure to
prevent any race conditions. However, it could also bring new deadlocks
or new crashes. I expect things to be severely broken, really. But I
think those changes are needed for 1.00. Please please please help
testing and debugging this. The basic H.323 features are most probably
broken!

I've put the number of tests to do inside brackets for each change. Each
set of tests should be repeated a few times to ensure there are no
problems.
When I tell that there are 2 tests for "changing the device on the fly
during calls or not", it means that you have to try to change it during
a call, but also when you are not in a call, but those 2 tests should be
repeated several times.

Here are the potentially affected things :

- Answering incoming calls / calling other users / calling other users
and interrupting the call, also check auto answer and do not disturb /
being call and refusing the call / being called and letting the call
time out with either reject or forwarding on no answer (8 tests)
Silly but true!

- The VideoGrabber usage : 
	* Changing the brightness/whiteness/... when the device is opening or
closing (4 x 2 tests)
	* Changing the device on the fly during calls or not while the video is
displayed in the video window (2 tests)
	* Doing calls with video preview active or not active (2 tests)
	* Receiving calls with video preview active or not active (2 tests)

- Transferring a call when you are in a call (1 test)

- Call forwarding, the 3 modes (3 tests)

- Changing the silence detection during a call or not, especially
interesting to try to change it while the call is starting (2 tests)

- Changing the minimum fps setting during a call or not, especially
interesting to try to change it while the call is starting (2 tests)

- Changing the transmitted video quality setting during a call or not,
especially interesting to try to change it while the call is starting (2
tests)

- Changing the max video bandwidth setting during a call or not,
especially interesting to try to change it while the call is starting (2
tests)

- Changing the min and max jitter buffer settings during a call or not,
especially interesting to try to change it while the call is starting (4
tests)

- The stats display (just do calls, you will see)

- Using the dialpad during calls and when calls are starting (2 tests)

- Using the text chat during calls and when calls are starting (2 tests)

Don't forge to continue testing weird things with the plugins system.
Thanks to all of you who will test.

PS: Do not report bugs for CVS to bugzilla. No need to flood bugzilla
with bugs, I know there are many in the current CVS build due to my
changes.
-- 
Damien Sandras <dsandras seconix com>
#include <ptlib.h>
#include <ptlib/plugins.h>

#include <alsa/asoundlib.h>

class PAudioDelay : public PObject
{
  PCLASSINFO(PAudioDelay, PObject);

  public:
    PAudioDelay();
    BOOL Delay(int time);
    void Restart();
    int  GetError();

  protected:
    PTime  previousTime;
    BOOL   firstTime;
    int    error;
};

#define MIN_HEADROOM    30
#define MAX_HEADROOM    60

class SoundHandleEntry : public PObject {

  PCLASSINFO(SoundHandleEntry, PObject)

  public:
    SoundHandleEntry();

    int handle;
    int direction;

    unsigned numChannels;
    unsigned sampleRate;
    unsigned bitsPerSample;
    unsigned fragmentValue;
    BOOL isInitialised;
};

#define LOOPBACK_BUFFER_SIZE 5000
#define BYTESINBUF ((startptr<endptr)?(endptr-startptr):(LOOPBACK_BUFFER_SIZE+endptr-startptr))

class PSoundChannelALSA: public PSoundChannel
{
 public:
  PSoundChannelALSA();
  void Construct();
  PSoundChannelALSA(const PString &device,
		   PSoundChannel::Directions dir,
		   unsigned numChannels,
		   unsigned sampleRate,
		   unsigned bitsPerSample);
  ~PSoundChannelALSA();
  static PStringArray GetDeviceNames(PSoundChannel::Directions);
  static PString GetDefaultDevice(PSoundChannel::Directions);
  BOOL Open(const PString & _device,
       Directions _dir,
       unsigned _numChannels,
       unsigned _sampleRate,
       unsigned _bitsPerSample);
  BOOL Setup();
  BOOL Close();
  BOOL Write(const void * buf, PINDEX len);
  BOOL Read(void * buf, PINDEX len);
  BOOL SetFormat(unsigned numChannels,
	    unsigned sampleRate,
	    unsigned bitsPerSample);
  unsigned GetChannels() const;
  unsigned GetSampleRate() const;
  unsigned GetSampleSize() const;
  BOOL SetBuffers(PINDEX size, PINDEX count);
  BOOL GetBuffers(PINDEX & size, PINDEX & count);
  BOOL PlaySound(const PSound & sound, BOOL wait);
  BOOL PlayFile(const PFilePath & filename, BOOL wait);
  BOOL HasPlayCompleted();
  BOOL WaitForPlayCompletion();
  BOOL RecordSound(PSound & sound);
  BOOL RecordFile(const PFilePath & filename);
  BOOL StartRecording();
  BOOL IsRecordBufferFull();
  BOOL AreAllRecordBuffersFull();
  BOOL WaitForRecordBufferFull();
  BOOL WaitForAllRecordBuffersFull();
  BOOL Abort();
  BOOL SetVolume (unsigned);
  BOOL GetVolume (unsigned &);
  BOOL IsOpen() const;

 private:

  BOOL Volume (BOOL, unsigned, unsigned &);

  snd_pcm_t *os_handle; /* Handle, different fromt the PChannel handle */
  int card_nr;
  int frame_bytes; /* Number of bytes in a frame */
  int period_size;
  int periods;
  PMutex device_mutex;
};
/*
 * sound_alsa.cxx
 *
 * Sound driver implementation.
 *
 * Portable Windows Library
 *
 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is Portable Windows Library.
 *
 * The Initial Developer of the Original ALSA Code is 
 * Damien Sandras <dsandras seconix com>
 *
 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
 * All Rights Reserved.
 *
 * Contributor(s): /
 *
 * $Log: sound_alsa.cxx,v $
 */

#include "sound_alsa.h"

#if !P_USE_INLINES
#include <ptlib/contain.inl>
#endif

#include <ptlib.h>

DECLARE_PLUGIN("ALSA", PDeviceManager::SoundIn | PDeviceManager::SoundOut);
DECLARE_PLUGIN_SOUNDINPUT(PSoundChannelALSA);
DECLARE_PLUGIN_SOUNDOUTPUT(PSoundChannelALSA);

///////////////////////////////////////////////////////////////////////////////
    
PAudioDelay::PAudioDelay()
{
  firstTime = TRUE;
  error = 0;
}
    
void PAudioDelay::Restart()
{
  firstTime = TRUE;
}
  
BOOL PAudioDelay::Delay(int frameTime)
{
  if (firstTime) {
    firstTime = FALSE;
    previousTime = PTime();
    return TRUE;
  }

  error += frameTime;

  PTime now;
  PTimeInterval delay = now - previousTime;
  error -= (int)delay.GetMilliSeconds();
  previousTime = now;

  if (error > 0)
#ifdef P_LINUX
    usleep(error * 1000);
#else
    PThread::Current()->Sleep(error);
#endif

  return error <= -frameTime;

  //if (headRoom > MAX_HEADROOM)
  //  PThread::Current()->Sleep(headRoom - MIN_HEADROOM);
}

///////////////////////////////////////////////////////////////////////////////
// declare type for sound handle dictionary

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(PSoundChannelALSA::GetDefaultDevice(PSoundChannelALSA::Player),
                        PSoundChannelALSA::Player);
  if (!channel.IsOpen())
    return FALSE;

  return channel.PlaySound(*this, TRUE);
}


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

  return channel.PlayFile(file, wait);
}


///////////////////////////////////////////////////////////////////////////////

SoundHandleEntry::SoundHandleEntry()
{
  handle    = -1;
  direction = 0;
}

static PStringArray playback_devices;
static PStringArray capture_devices;

///////////////////////////////////////////////////////////////////////////////

PSoundChannelALSA::PSoundChannelALSA()
{
  PSoundChannelALSA::Construct();
}


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


void PSoundChannelALSA::Construct()
{
  frame_bytes = 0;
  period_size = 0;
  periods = 0;
  card_nr = 0;
  os_handle = NULL;
}


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


PStringArray PSoundChannelALSA::GetDeviceNames (Directions dir)
{
  int card = -1, dev = -1;
  
  snd_ctl_t *handle = NULL;
  snd_ctl_card_info_t *info = NULL;
  snd_pcm_info_t *pcminfo = NULL;
  snd_pcm_stream_t stream;

  char *name = NULL;
  char card_id [32];

  if (dir == Recorder) {

    stream = SND_PCM_STREAM_CAPTURE;
    capture_devices = PStringArray ();
  }
  else {

    stream = SND_PCM_STREAM_PLAYBACK;
    playback_devices = PStringArray ();
  }

  snd_ctl_card_info_alloca (&info);
  snd_pcm_info_alloca (&pcminfo);

  /* No sound card found */
  if (snd_card_next (&card) < 0 || card < 0) {

    return PStringArray ();
  }


  while (card >= 0) {

    snprintf (card_id, 32, "hw:%d", card);
    
    snd_ctl_open (&handle, card_id, 0);
    snd_ctl_card_info (handle, info);

    while (1) {

      snd_ctl_pcm_next_device (handle, &dev);

      if (dev < 0)
        break;

      snd_pcm_info_set_device (pcminfo, dev);
      snd_pcm_info_set_subdevice (pcminfo, 0);
      snd_pcm_info_set_stream (pcminfo, stream);

      if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
    
	snd_card_get_name (card, &name);
	if (dir == Recorder) {

	  if (capture_devices.GetStringsIndex (name) == P_MAX_INDEX)
	    capture_devices.AppendString (name);
	}
	else {

	  if (playback_devices.GetStringsIndex (name) == P_MAX_INDEX)
	    playback_devices.AppendString (name);
	}
	    
	free (name);
      }
    }


    snd_ctl_close(handle);
    snd_card_next (&card);
  }


  snd_pcm_info_free (pcminfo);

  if (dir == Recorder)
    return capture_devices;
  else 
    return playback_devices;
}


PString PSoundChannelALSA::GetDefaultDevice(Directions dir)
{
  PStringArray devicenames;
  devicenames = PSoundChannelALSA::GetDeviceNames (dir);

  return devicenames[0];
}


BOOL PSoundChannelALSA::Open (const PString & _device,
                              Directions _dir,
			      unsigned _numChannels,
			      unsigned _sampleRate,
			      unsigned _bitsPerSample)
{
  PString real_device_name;
  PINDEX i = 0;
  snd_pcm_stream_t stream;

  Close();

  os_handle = NULL;

  if (_dir == Recorder)
    stream = SND_PCM_STREAM_CAPTURE;
  else
    stream = SND_PCM_STREAM_PLAYBACK;

  /* Open in NONBLOCK mode */
  if ((i = (_dir == Recorder) ? capture_devices.GetStringsIndex (_device) : playback_devices.GetStringsIndex (_device)) != P_MAX_INDEX) {

    real_device_name = "plughw:" + PString (i);
    card_nr = i;
  }
  else {
    
    PTRACE (1, "ALSA\tDevice unavailable");
    return FALSE;
  }

  if (snd_pcm_open (&os_handle, real_device_name, stream, 0) < 0) {

    PTRACE (1, "ALSA\tOpen Failed");
    return FALSE;
  }
  else 
    snd_pcm_nonblock (os_handle, 0);
   
  /* save internal parameters */
  direction = _dir;
  device = real_device_name;
  mNumChannels = _numChannels;
  mSampleRate = _sampleRate;
  mBitsPerSample = _bitsPerSample;
  isInitialised = FALSE;

  PTRACE (1, "ALSA\tDevice " << real_device_name << " Opened");

  return TRUE;
}


BOOL PSoundChannelALSA::Setup()
{
  snd_pcm_hw_params_t *hw_params = NULL;
  int err = 0;
  enum _snd_pcm_format val = SND_PCM_FORMAT_UNKNOWN;
  BOOL no_error = TRUE;


  if (os_handle == NULL) {

    PTRACE(6, "ALSA\tSkipping setup of " << device << " as not open");
    return FALSE;
  }

  if (isInitialised) {

    PTRACE(6, "ALSA\tSkipping setup of " << device << " as instance already initialised");
    return TRUE;
  }


#if PBYTE_ORDER == PLITTLE_ENDIAN
  val = (mBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_U8;
#else
  val = (mbitsPerSample == 16) ? SND_PCM_FORMAT_S16_BE : SND_PCM_FORMAT_U8;
#endif

  frame_bytes = (mNumChannels * (snd_pcm_format_width (val) / 8));

  snd_pcm_hw_params_alloca (&hw_params);


  if ((err = snd_pcm_hw_params_any (os_handle, hw_params)) < 0) {

    PTRACE (1, "ALSA\tCannot initialize hardware parameter structure " <<
	    snd_strerror (err));
    no_error = FALSE;
  }


  if ((err = snd_pcm_hw_params_set_access (os_handle, hw_params, 
				    SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {

    PTRACE (1, "ALSA\tCannot set access type " <<
	    snd_strerror (err));
    no_error = FALSE;
  }


  if ((err = snd_pcm_hw_params_set_format (os_handle, hw_params, val)) < 0) {

    PTRACE (1, "ALSA\tCannot set sample format " <<
             snd_strerror (err));
    no_error = FALSE;
  }


  if ((err = snd_pcm_hw_params_set_rate (os_handle, hw_params, 
					 mSampleRate, 0)) < 0) {

    PTRACE (1, "ALSA\tCannot set sample rate " <<
	    snd_strerror (err));
    no_error = FALSE;
  }


  if ((err = snd_pcm_hw_params_set_channels (os_handle, hw_params, 
					     mNumChannels)) < 0) {

    PTRACE (1, "ALSA\tCannot set channel count " <<
             snd_strerror (err));
    no_error = FALSE;
  }


  // Ignore errors here 
  if (periods && period_size) {

    if ((err = snd_pcm_hw_params_set_period_size_near (os_handle, 
						       hw_params, 
						       period_size/frame_bytes, 
						       0)) < 0)
      PTRACE (1, "ALSA\tCannot set period size " <<
	      snd_strerror (err));
    
    if ((err = snd_pcm_hw_params_set_periods (os_handle, 
					      hw_params, 
					      periods, 0)) < 0)
      PTRACE (1, "ALSA\tCannot set number of periods " <<
	      snd_strerror (err));

    if ((err = snd_pcm_hw_params_set_buffer_size_near (os_handle, 
						       hw_params, 
						       periods*period_size/frame_bytes)) < 0)
      PTRACE (1, "ALSA\tCannot set buffer size " <<
	      snd_strerror (err));
  }


  if ((err = snd_pcm_hw_params (os_handle, hw_params)) < 0) {

    PTRACE (1, "ALSA\tCannot set parameters " <<
	    snd_strerror (err));
    no_error = FALSE;
  }


  isInitialised = TRUE;

  return no_error;
}


BOOL PSoundChannelALSA::Close()
{
  PWaitAndSignal m(device_mutex);

  /* if the channel isn't open, do nothing */
  if (!os_handle)
    return FALSE;

  if (isInitialised)
    Abort ();

  snd_pcm_close (os_handle);
  os_handle = NULL;

  return TRUE;
}


BOOL PSoundChannelALSA::Write (const void *buf, PINDEX len)
{
  long r = 0;
  char *buf2 = (char *) buf;
  int pos = 0, max_try = 0;

  PWaitAndSignal m(device_mutex);

  if (!isInitialised && !Setup() || !len || !os_handle)
    return FALSE;


  do {

    /* the number of frames to read is the buffer length 
       divided by the size of one frame */
    r = snd_pcm_writei (os_handle, (char *) &buf2 [pos], len / frame_bytes);

    if (r > 0) {

      pos += r * frame_bytes;
      len -= r * frame_bytes;
    }
    else {

      if (r == -EPIPE) {    /* under-run */

	snd_pcm_prepare (os_handle);
      
      } else if (r == -ESTRPIPE) {

	while ((r = snd_pcm_resume (os_handle)) == -EAGAIN)
	  sleep(1);       /* wait until the suspend flag is released */
      
	if (r < 0) 
	  snd_pcm_prepare (os_handle);
      }

      PTRACE (1, "ALSA\tCould not write");
      max_try++;
    }
  } while (len > 0 && max_try < 5);


  if (len != 0) {

    memset ((char *) &buf2 [pos], 0, len);

    PTRACE (1, "ALSA\tWrite Error, filling with zeros");
  }

  return TRUE;
}


BOOL PSoundChannelALSA::Read (void * buf, PINDEX len)
{
  long r = 0;

  char *buf2 = (char *) buf;
  int pos = 0, max_try = 0;

  lastReadCount = 0;

  PWaitAndSignal m(device_mutex);

  if (!isInitialised && !Setup() || !len || !os_handle)
    return FALSE;

  do {

    /* the number of frames to read is the buffer length 
       divided by the size of one frame */
    r = snd_pcm_readi (os_handle, (char *) &buf2 [pos], len / frame_bytes);

    if (r > 0) {

      pos += r * frame_bytes;
      len -= r * frame_bytes;
      lastReadCount += r * frame_bytes;
    }
    else {

      if (r == -EPIPE) {    /* under-run */

	snd_pcm_prepare (os_handle);
      
      } else if (r == -ESTRPIPE) {

	while ((r = snd_pcm_resume (os_handle)) == -EAGAIN)
	  sleep(1);       /* wait until the suspend flag is released */

	if (r < 0) 
	  snd_pcm_prepare (os_handle);
      }

      PTRACE (1, "ALSA\tCould not read");
      max_try++;
    }
  } while (len > 0 && max_try < 5);

 
  if (len != 0) {

    memset ((char *) &buf2 [pos], 0, len);
    lastReadCount += len;

    PTRACE (1, "ALSA\tRead Error, filling with zeros");
  }

  return TRUE;
}


BOOL PSoundChannelALSA::SetFormat (unsigned numChannels,
				   unsigned sampleRate,
				   unsigned bitsPerSample)
{
  if (!os_handle)
    return SetErrorValues(NotOpen, EBADF);

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

  mNumChannels   = numChannels;
  mSampleRate    = sampleRate;
  mBitsPerSample = bitsPerSample;
 
  /* mark this channel as uninitialised */
  isInitialised = FALSE;

  return TRUE;
}


unsigned PSoundChannelALSA::GetChannels()   const
{
  return mNumChannels;
}


unsigned PSoundChannelALSA::GetSampleRate() const
{
  return mSampleRate;
}


unsigned PSoundChannelALSA::GetSampleSize() const
{
  return mBitsPerSample;
}


BOOL PSoundChannelALSA::SetBuffers (PINDEX size, PINDEX count)
{
  periods = count;
  period_size = size;

  return TRUE;
}


BOOL PSoundChannelALSA::GetBuffers(PINDEX & size, PINDEX & count)
{
  return FALSE;
}


BOOL PSoundChannelALSA::PlaySound(const PSound & sound, BOOL wait)
{
  return FALSE;
}


BOOL PSoundChannelALSA::PlayFile(const PFilePath & filename, BOOL wait)
{
  return FALSE;
}


BOOL PSoundChannelALSA::HasPlayCompleted()
{
  return TRUE;
}


BOOL PSoundChannelALSA::WaitForPlayCompletion()
{
  return TRUE;
}


BOOL PSoundChannelALSA::RecordSound(PSound & sound)
{
  return FALSE;
}


BOOL PSoundChannelALSA::RecordFile(const PFilePath & filename)
{
  return FALSE;
}


BOOL PSoundChannelALSA::StartRecording()
{
  return FALSE;
}


BOOL PSoundChannelALSA::IsRecordBufferFull()
{
  return TRUE;
}


BOOL PSoundChannelALSA::AreAllRecordBuffersFull()
{
  return TRUE;
}


BOOL PSoundChannelALSA::WaitForRecordBufferFull()
{
  return TRUE;
}


BOOL PSoundChannelALSA::WaitForAllRecordBuffersFull()
{
  return FALSE;
}


BOOL PSoundChannelALSA::Abort()
{
  int r = 0;

  if (!os_handle)
    return FALSE;

  if ((r = snd_pcm_drop (os_handle)) < 0) {

    PTRACE (1, "ALSA\tCannot abort" <<
	    snd_strerror (r));
    return FALSE;
  }
  else
    return TRUE;
}



BOOL PSoundChannelALSA::SetVolume (unsigned newVal)
{
  unsigned i = 0;

  return Volume (TRUE, newVal, i);
}


BOOL  PSoundChannelALSA::GetVolume(unsigned &devVol)
{
  return Volume (FALSE, 0, devVol);
}
  

BOOL PSoundChannelALSA::IsOpen () const
{
  return (os_handle != NULL);
}


BOOL PSoundChannelALSA::Volume (BOOL set, unsigned set_vol, unsigned &get_vol)
{
  int err = 0;
  snd_mixer_t *handle;
  snd_mixer_elem_t *elem;
  snd_mixer_selem_id_t *sid;

  const char *play_mix_name = (direction == Player) ? "Master": "Mic";
  PString card_name;

  long pmin = 0, pmax = 0;
  long int vol = 0;

  if (!os_handle)
    return FALSE;

  card_name = "hw:" + PString (card_nr);

  //allocate simple id
  snd_mixer_selem_id_alloca (&sid);

  //sets simple-mixer index and name
  snd_mixer_selem_id_set_index (sid, 0);
  snd_mixer_selem_id_set_name (sid, play_mix_name);

  if ((err = snd_mixer_open (&handle, 0)) < 0) {

    PTRACE (1, "alsa-control: mixer open error: " << snd_strerror (err));
    return FALSE;
  }


  if ((err = snd_mixer_attach (handle, card_name)) < 0) {

    PTRACE (1, "alsa-control: mixer attach " << card_name << " error: " 
	    << snd_strerror(err));
    snd_mixer_close(handle);
    return FALSE;
  }


  if ((err = snd_mixer_selem_register (handle, NULL, NULL)) < 0) {

    PTRACE (1, "alsa-control: mixer register error: " << snd_strerror(err));
    snd_mixer_close(handle);
    return FALSE;
  }


  err = snd_mixer_load(handle);
  if (err < 0) {

    PTRACE (1, "alsa-control: mixer load error: " << snd_strerror(err));
    snd_mixer_close(handle);
    return FALSE;
  }

  elem = snd_mixer_find_selem (handle, sid);

  if (!elem) {

    PTRACE (1, "alsa-control: unable to find simple control "
	    << snd_mixer_selem_id_get_name(sid) << "," 
	    << snd_mixer_selem_id_get_index(sid));
    snd_mixer_close(handle);
    return FALSE;
  }

  snd_mixer_selem_get_playback_volume_range (elem, &pmin, &pmax);

  if (set) {

    vol = (set_vol * (pmax?pmax:31)) / 100;
    snd_mixer_selem_set_playback_volume (elem, 
					 SND_MIXER_SCHN_FRONT_LEFT, vol);
    snd_mixer_selem_set_playback_volume (elem, 
					 SND_MIXER_SCHN_FRONT_RIGHT, vol);
    
    PTRACE (4, "Set volume to " << vol);
  }
  else {

    snd_mixer_selem_get_playback_volume (elem, 
					 SND_MIXER_SCHN_FRONT_LEFT, &vol);
    get_vol = (vol * 100) / (pmax?pmax:31);
    PTRACE (4, "Got volume " << vol);
  }

  snd_mixer_close(handle);

  return TRUE;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]