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); }