[alsa-devel] is statically linking libasound supported? because if i do it, i cant open the device!

John Utz John.Utz at dmx.com
Wed Mar 28 03:05:50 CEST 2007


i have a test app that works successfully with hw:0,1 on gnto if i link it dynamically:

dmx-gnto jutz # ./atestminhw1 
Playback device is hw:0,1
Stream parameters are 48000Hz, S16_LE, 6 channels
Rate set to 48000Hz (requested 48000Hz)
Buffer size range from 6 to 5461
Period size range from 3 to 2730
Using max buffer size 5460
Periods = 4
was set period_size = 1365
was set buffer_size = 5460
Channel: 0 Freq: 220.000000



but it fails to find hw:0,1 if i link it statically, is that expected behavior?

dmx-gnto jutz # ./atestminhw1 
Playback device is hw:0,1
Stream parameters are 48000Hz, S16_LE, 6 channels
ALSA lib pcm.c:2109:(snd_pcm_open_conf) symbol _snd_pcm_hw_open is not defined inside (null)
Failed: No such device or address


this line succeeds with a dynamic linking and fails with

if(0 > (iErr = snd_pcm_open(&pPcm, gs_pcNameDev, SND_PCM_STREAM_PLAYBACK, 0))) goto fin;


here is my static link arguments:

gcc -g -static -o atestminhw1 atestmin.c -lasound -lm -lpthread -ldl


here is my dynamic link arguments:

gcc -g -o atestminhw1 atestmin.c -lasound


and, for completeness, here is my lame test app, derived from other test apps that come with the source:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <errno.h>
#include <getopt.h>
#include <inttypes.h>
#include <ctype.h>
#include <byteswap.h>

#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API
#include <alsa/asoundlib.h>
#include <sys/time.h>
#include <math.h>


#define MAX_CHANNELS	16

static char              *gs_pcNameDev = "hw:0,1";           /* playback device */
//static char              *gs_pcNameDev = "plughw";           /* playback device */
//static char              *gs_pcNameDev = "default";           /* playback device */
static snd_pcm_format_t   gs_SndPcmFmt = SND_PCM_FORMAT_S16; /* sample format */
static unsigned int       gs_uRate     = 48000;	             /* stream rate */
static unsigned int       gs_uCntChan  = 6;	             /* count of channels */
static unsigned int       gs_uTimBuf   = 0;	             /* ring buffer length in us */
static unsigned int       gs_uTimPer   = 0;	             /* period time in us */
static unsigned int       gs_uCntPer   = 4;                  /* number of periods */
static double             gs_dFreq     = 440;                /* sinusoidal wave frequency in Hz */
static snd_pcm_uframes_t  gs_uSizBuf;
static snd_pcm_uframes_t  gs_uSizPer;


static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access)
{
  unsigned int       uRate;
  int                iErr;
  snd_pcm_uframes_t  period_size_min;
  snd_pcm_uframes_t  period_size_max;
  snd_pcm_uframes_t  buffer_size_min;
  snd_pcm_uframes_t  buffer_size_max;

  /* choose all parameters */
  
  if (0 > (iErr = snd_pcm_hw_params_any(handle, params)))
  {
    printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(iErr));
    return iErr;
  }

  /* set the interleaved read/write format */
  
  if (0 > (iErr = snd_pcm_hw_params_set_access(handle, params, access)))
  {
    printf("Access type not available for playback: %s\n", snd_strerror(iErr));
    return iErr;
  }

  /* set the sample format */
  
  if (0 > (iErr = snd_pcm_hw_params_set_format(handle, params, gs_SndPcmFmt)))
  {
    printf("Sample format not available for playback: %s\n", snd_strerror(iErr));
    return iErr;
  }

  /* set the count of channels */
  
  if (0 > (iErr = snd_pcm_hw_params_set_channels(handle, params, gs_uCntChan)))
  {
    printf("Channels count (%i) not available for playbacks: %s\n", gs_uCntChan, snd_strerror(iErr));
    return iErr;
  }

  /* set the stream rate */
  uRate = gs_uRate;

  if (0 > (iErr = snd_pcm_hw_params_set_rate(handle, params, gs_uRate, 0)))
  {
    printf("Rate %iHz not available for playback: %s\n", gs_uRate, snd_strerror(iErr));
    return iErr;
  }

  if (uRate != gs_uRate)
  {
    printf("Rate doesn't match (requested %iHz, get %iHz, err %d)\n", gs_uRate, uRate, iErr);
    return -EINVAL;
  }

  printf("Rate set to %iHz (requested %iHz)\n", uRate, gs_uRate);

  /* set the buffer time */

  iErr = snd_pcm_hw_params_get_buffer_size_min(params, &buffer_size_min);
  iErr = snd_pcm_hw_params_get_buffer_size_max(params, &buffer_size_max);
  iErr = snd_pcm_hw_params_get_period_size_min(params, &period_size_min, NULL);
  iErr = snd_pcm_hw_params_get_period_size_max(params, &period_size_max, NULL);

  printf("Buffer size range from %lu to %lu\n",buffer_size_min, buffer_size_max);
  printf("Period size range from %lu to %lu\n",period_size_min, period_size_max);

  if (gs_uTimPer > 0)
  {
    printf("Requested period time %u us\n", gs_uTimPer);
    
    if (0 > (iErr = snd_pcm_hw_params_set_period_time_near(handle, params, &gs_uTimPer, NULL))) 
    {
      printf("Unable to set period time %u us for playback: %s\n",
	     gs_uTimPer, snd_strerror(iErr));
      return iErr;
    }
  }

  if (gs_uTimBuf > 0)
  {
    printf("Requested buffer time %u us\n", gs_uTimBuf);
    
    if (0 > (iErr = snd_pcm_hw_params_set_buffer_time_near(handle, params, &gs_uTimBuf, NULL)))
    {
      printf("Unable to set buffer time %u us for playback: %s\n",
	     gs_uTimBuf, snd_strerror(iErr));
      return iErr;
    }
  }

  if (! gs_uTimBuf && ! gs_uTimPer)
  {
    gs_uSizBuf = buffer_size_max;
    if (! gs_uTimPer) gs_uSizBuf = (gs_uSizBuf / gs_uCntPer) * gs_uCntPer;

    printf("Using max buffer size %lu\n", gs_uSizBuf);
    
    if (0 > (iErr = snd_pcm_hw_params_set_buffer_size_near(handle, params, &gs_uSizBuf)))
    {
      printf("Unable to set buffer size %lu for playback: %s\n",
	     gs_uSizBuf, snd_strerror(iErr));
      return iErr;
    }
  }

  if (! gs_uTimBuf || ! gs_uTimPer) 
  {
    printf("Periods = %u\n", gs_uCntPer);
    
    if (0 > (iErr = snd_pcm_hw_params_set_periods_near(handle, params, &gs_uCntPer, NULL))) 
    {
      printf("Unable to set nperiods %u for playback: %s\n",
	     gs_uCntPer, snd_strerror(iErr));
      return iErr;
    }
  }

  snd_pcm_hw_params_get_buffer_size(params, &gs_uSizBuf);
  snd_pcm_hw_params_get_period_size(params, &gs_uSizPer, NULL);
  printf("was set period_size = %lu\n",gs_uSizPer);
  printf("was set buffer_size = %lu\n",gs_uSizBuf);
  if (2*gs_uSizPer > gs_uSizBuf) {
    printf("buffer to small, could not use\n");
    return iErr;
  }

  /* write the parameters to device */
  iErr = snd_pcm_hw_params(handle, params);
  if (iErr < 0) {
    printf("Unable to set hw params for playback: %s\n", snd_strerror(iErr));
    return iErr;
  }

  return 0;
}

static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
{
  int iErr;

  /* get the current swparams */
  
  if (0 > (iErr = snd_pcm_sw_params_current(handle, swparams)))
  {
    printf("Unable to determine current swparams for playback: %s\n", snd_strerror(iErr));
    return iErr;
  }

  /* start the transfer when a buffer is full */
  
  if (0 > (iErr = snd_pcm_sw_params_set_start_threshold(handle, swparams, gs_uSizBuf)))
  {
    printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(iErr));
    return iErr;
  }

  /* allow the transfer when at least period_size frames can be processed */
  
  if (0 > (iErr = snd_pcm_sw_params_set_avail_min(handle, swparams, gs_uSizPer)))
  {
    printf("Unable to set avail min for playback: %s\n", snd_strerror(iErr));
    return iErr;
  }

  /* align all transfers to 1 sample */
  
  if (0 > (iErr = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1)))
  {
    printf("Unable to set transfer align for playback: %s\n", snd_strerror(iErr));
    return iErr;
  }

  /* write the parameters to the playback device */
  
  if (0 > (iErr = snd_pcm_sw_params(handle, swparams)))
  {
    printf("Unable to set sw params for playback: %s\n", snd_strerror(iErr));
    return iErr;
  }

  return 0;
}


static void generate_sine(uint8_t *pu8Frames, int iChannel, int iCntFrames, double *pdPhase, float fFreq)
{
  double    dPhase    = *pdPhase;
  double    dPhaseMax = 1.0 / fFreq;
  double    dSizStep  = 1.0 / (double)gs_uRate;
  double    dRes;
  int       iIdxChan;
  int32_t   i32Res;
  int16_t *pi16Samp   = (int16_t*) pu8Frames;

  while (iCntFrames-- > 0) 
  {
    for(iIdxChan=0;iIdxChan<gs_uCntChan;iIdxChan++) 
      if (iIdxChan==iChannel) 
      {
	dRes        = (sin((dPhase * 2 * M_PI) / dPhaseMax - M_PI)) * 0x03fffffff; /* Don't use MAX volume */
	i32Res      = dRes;
	*pi16Samp++ = i32Res >>16;
      } 
      else *pi16Samp++ = 0;

    dPhase += dSizStep;

    if (dPhase >= dPhaseMax)
      dPhase -= dPhaseMax;
  }

  *pdPhase = dPhase;
}


/*
 *   Underrun and suspend recovery
 */

static int xrun_recovery(snd_pcm_t *pPcm, int iErr) 
{
  if (iErr == -EPIPE) {	/* under-run */
    iErr = snd_pcm_prepare(pPcm);
    if (iErr < 0)
      printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(iErr));
    return 0;
  } 
  else if (iErr == -ESTRPIPE) {

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

    if (iErr < 0) {
      iErr = snd_pcm_prepare(pPcm);
      if (iErr < 0)
        printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(iErr));
    }

    return 0;
  }

  return iErr;
}


static int write_loop(snd_pcm_t *pPcm, int iChan, int iNumPer, uint8_t *pu8Frames)
{
  double phase = 0;
  int    iErr, iIdxPer, iCntFrames;
  uint8_t *pu8FramesLocal;
  float  fFreq = gs_dFreq*(iChan+1)/2; // provide an audible chan change cue

  printf("Channel: %d Freq: %f\n", iChan, fFreq);

  for(iIdxPer = 0; iIdxPer < iNumPer; iIdxPer++) 
  {
    iCntFrames     = gs_uSizPer;
    pu8FramesLocal = pu8Frames;

    generate_sine(pu8FramesLocal, iChan, gs_uSizPer, &phase, fFreq);

    while (0 < iCntFrames) 
    {
      if (-EAGAIN == (iErr = snd_pcm_writei(pPcm, pu8FramesLocal, iCntFrames)))
	continue;

      if (0 > iErr) 
      {
	printf("Write error: %d,%s\n", iErr, snd_strerror(iErr));
        if (0 > xrun_recovery(pPcm, iErr)) 
        {
	  printf("xrun_recovery failed: %d,%s\n", iErr, snd_strerror(iErr));
	  return -1;
	}
	break;	// skip one period
      }

      pu8FramesLocal += snd_pcm_frames_to_bytes(pPcm, iErr);
      iCntFrames -= iErr;
   }
  }
  
  if (gs_uSizBuf > iIdxPer * gs_uSizPer) 
  {
    snd_pcm_drain(pPcm);
    snd_pcm_prepare(pPcm );
  }
  return 0;
}


int main(int argc, char *argv[]) 
{
  int                    iErr;
  int                    iIdxChan;
  uint8_t              *pu8Frames = NULL;
  snd_pcm_t            *pPcm = NULL;
  snd_pcm_hw_params_t  *hwparams;
  snd_pcm_sw_params_t  *swparams;

  snd_pcm_hw_params_alloca(&hwparams);
  snd_pcm_sw_params_alloca(&swparams);
 
  printf("Playback device is %s\n", gs_pcNameDev);
  printf("Stream parameters are %iHz, %s, %i channels\n", gs_uRate, snd_pcm_format_name(gs_SndPcmFmt), gs_uCntChan);

  if(0 > (iErr = snd_pcm_open(&pPcm, gs_pcNameDev, SND_PCM_STREAM_PLAYBACK, 0))) goto fin;

  if(0 > (iErr = set_hwparams(pPcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED))) goto fin;

  if(0 > (iErr = set_swparams(pPcm, swparams)))                                goto fin;

  if(!(pu8Frames = malloc(snd_pcm_frames_to_bytes(pPcm, gs_uSizPer))))         goto fin;

  while(1)
    for(iIdxChan = 0; iIdxChan < gs_uCntChan; iIdxChan++)
      if (0> (iErr = write_loop(pPcm, iIdxChan, (gs_uRate*3)/gs_uSizPer, pu8Frames)))
	goto fin;
     
  iErr = EXIT_SUCCESS;

 fin:

  if(iErr)      printf("Failed: %s\n",snd_strerror(iErr));

  if(pu8Frames) free(pu8Frames);

  if(pPcm)      snd_pcm_close(pPcm);

  exit(iErr);
}



More information about the Alsa-devel mailing list