0

I trying to write ALSA application for recording audio, and when I try to set some parameters and then print them to the screen I getting some default numbers that i cant change

#include <alsa/asoundlib.h>

using namespace std;


typedef struct {  
  int audio;
  int recording;
  void *cons;
  snd_pcm_t *inhandle;
  snd_pcm_t *outhandle;
  unsigned long sampleIndex;
  unsigned long inlen;
  unsigned long sampleRate;
} audio_t;
static audio_t aud;


void aboutAlsa(snd_pcm_t *handle,snd_pcm_hw_params_t *params) {
  unsigned int val, val2;
  snd_pcm_format_t val3;
  int dir;
  snd_pcm_uframes_t frames;

  printf("ALSA library version: %s\n",SND_LIB_VERSION_STR);
  printf("PCM handle name = '%s'\n",snd_pcm_name(handle));
  printf("PCM state = %s\n",snd_pcm_state_name(snd_pcm_state(handle)));
  snd_pcm_hw_params_get_access(params,(snd_pcm_access_t *) &val);
  printf("access type = %s\n",snd_pcm_access_name((snd_pcm_access_t)val));
  snd_pcm_hw_params_get_format(params, &val3);
  printf("format = '%s' (%s)\n",snd_pcm_format_name(val3),
    snd_pcm_format_description(val3));
  snd_pcm_hw_params_get_subformat(params,(snd_pcm_subformat_t *)&val);
  printf("subformat = '%s' (%s)\n",snd_pcm_subformat_name((snd_pcm_subformat_t)val),
    snd_pcm_subformat_description((snd_pcm_subformat_t)val));
  snd_pcm_hw_params_get_channels(params, &val);
  printf("channels = %d\n", val);
  snd_pcm_hw_params_get_rate(params, &val, &dir);
  printf("rate = %d bps\n", val);
  snd_pcm_hw_params_get_period_time(params,&val, &dir);
  printf("period time = %d us\n", val);
  snd_pcm_hw_params_get_period_size(params,&frames, &dir);
  printf("period size = %d frames\n", (int)frames);
  snd_pcm_hw_params_get_buffer_time(params,&val, &dir);
  printf("buffer time = %d us\n", val);
  snd_pcm_hw_params_get_buffer_size(params,(snd_pcm_uframes_t *) &val);
  printf("buffer size = %d frames\n", val);
  snd_pcm_hw_params_get_periods(params, &val, &dir);
  printf("periods per buffer = %d frames\n", val);
  snd_pcm_hw_params_get_rate_numden(params,&val, &val2);
  printf("exact rate = %d/%d bps\n", val, val2);
  val = snd_pcm_hw_params_get_sbits(params);
  printf("significant bits = %d\n", val);
  return;
}

static int openKnownAudio(int record) {
  int rc;
  int SAMPLERATE = 16000;
  unsigned int val;
  int dir=0;
  snd_pcm_t *handle;
  snd_pcm_hw_params_t *hw_params=NULL;
  snd_pcm_uframes_t frames;
  size_t esz = 256;
  char err[esz];
  /* Open PCM device for recording (capture). */ 
  if (record) {
    if ((rc=snd_pcm_open(&aud.inhandle, "default",SND_PCM_STREAM_CAPTURE, 0))<0) {
      snprintf(err, esz, "unable to open pcm device for recording: %s\n",snd_strerror(rc));
    }
    handle=aud.inhandle;
  } else {
    if ((rc=snd_pcm_open(&aud.outhandle, "default",SND_PCM_STREAM_PLAYBACK, 0))<0) {
      snprintf(err, esz, "unable to open pcm device for playback: %s\n",snd_strerror(rc));
    }
    handle=aud.outhandle;
  }

  /* Configure hardware parameters  */
  if((rc=snd_pcm_hw_params_malloc(&hw_params)) < 0) {
    snprintf(err, esz, "unable to malloc hw_params: %s\n",snd_strerror(rc));
  }
  if((rc=snd_pcm_hw_params_any(handle, hw_params))<0) {
    snprintf(err, esz, "unable to setup hw_params: %s\n",snd_strerror(rc));
  }
  if((rc=snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED))<0) {
    snprintf(err, esz, "unable to set access mode: %s\n",snd_strerror(rc));
  }
  if((rc=snd_pcm_hw_params_set_format(handle, hw_params, SND_PCM_FORMAT_S16_LE))<0) {
    snprintf(err, esz, "unable to set format: %s\n",snd_strerror(rc));
  }
  if((rc=snd_pcm_hw_params_set_channels(handle, hw_params, 1))<0) {
    snprintf(err, esz, "unable to set channels: %s\n",snd_strerror(rc));
  }
  val = SAMPLERATE;
  dir = 0;
  if((rc=snd_pcm_hw_params_set_rate(handle, hw_params, SAMPLERATE,0))<0) {
    snprintf(err, esz, "unable to set samplerate: %s\n",snd_strerror(rc));
  }
  if (val!=SAMPLERATE) {
    snprintf(err, esz, "unable to set requested samplerate: requested=%i got=%i\n",SAMPLERATE,val);
  }
  frames = 64; 
  if ((rc=snd_pcm_hw_params_set_period_size_near(handle,hw_params, &frames, &dir))<0) {
    snprintf(err, esz, "unable to set period size: %s\n",snd_strerror(rc));
  }
  frames = 4096; 
  if ((rc=snd_pcm_hw_params_set_buffer_size_near(handle,hw_params, &frames))<0) {
    snprintf(err, esz, "unable to set buffer size: %s\n",snd_strerror(rc));
  }

  if ((rc = snd_pcm_hw_params(handle, hw_params))<0) {
    snprintf(err, esz, "unable to set hw parameters: %s\n",snd_strerror(rc));
  }

  aboutAlsa(handle,hw_params);

  snd_pcm_hw_params_free(hw_params);
  aud.recording = (record)? 1:0;
  aud.audio=1;
  return 1;
}

This what I get on raspberry pi when I run it:

ALSA library version: 1.0.28
PCM handle name = 'default'
PCM state = PREPARED
access type = RW_INTERLEAVED
format = 'S16_LE' (Signed 16 bit Little Endian)
subformat = 'STD' (Standard)
channels = 1
rate = 16000 bps
period time = 21333 us
period size = 341 frames
buffer time = 256000 us
buffer size = 4096 frames
periods per buffer = 4096 frames
exact rate = 16000/1 bps
significant bits = 16

And this is what I get when I run it on desktop pc:

ALSA library version: 1.0.28
PCM handle name = 'default'
PCM state = PREPARED
access type = RW_INTERLEAVED
format = 'S16_LE' (Signed 16 bit Little Endian)
subformat = 'STD' (Standard)
channels = 1
rate = 16000 bps
period time = 4000 us
period size = 64 frames
buffer time = 256000 us
buffer size = 4096 frames
periods per buffer = 64 frames
exact rate = 16000/1 bps
significant bits = 16

As you can see I'm trying to set the period size to 64 and getting back 341, this value only changes when I change the rate, lets say I set the rate to 44100 and this what I getting back:

rate = 44100 bps
period time = 21333 us
period size = 940 frames
buffer time = 85328 us
buffer size = 3763 frames
periods per buffer = 3763 frames

On desktop pc this doesn't happens I tried to trace down this functions in alsa-lib but I getting lost there also tried different sound cards and still getting same result .

LichKing
  • 256
  • 1
  • 2
  • 15
  • Have you tried increasing prealloc via /proc files? Second response at this [link](http://www.gossamer-threads.com/lists/mythtv/users/474457). In my experience, that allowed larger buffer size, period, etc. – bjornruffians Jan 06 '17 at 21:32
  • It's possible that the Pi does not use `dmix`. In any case, different hardware has different capabilities. – CL. Jan 06 '17 at 23:06
  • @CL. its not hardware problem. I found that when installing pulseaudio its fixing the problem but making another one, I dont want to use pulseaudio! and pulseaudio comes with trillion packages and I think that one of them fixing the problem maybe even its pulseaudio him self. I guess I'm going to find that out – LichKing Jan 07 '17 at 09:53
  • The struct snd_interval in alsa-lib has min and max value for various configuration(channel, sample bits etc...) This value for Period Size will tell what is the minimum and max value is possible for period size (check for SNDRV_PCM_HW_PARAM_PERIOD_SIZE index in element interval).. If period size value requested is less than min value , alsa-lib will not set it. As @CL has told different HW have different capabilities – Varun Jan 09 '17 at 11:42
  • @Varun where I can see this min/max values? just to be sure I tried to set the period size to different values from very little to very big and it just not changing the value is always stays the same (341 frames) – LichKing Jan 13 '17 at 17:53
  • @LichKing look at the structure snd_pcm_hw_params member intervals index 5 which correspond to SNDRV_PCM_HW_PARAM_PERIOD_SIZE. The struct snd_interval has min and max member elements. The period size should be between them. All these struct are present in file asound.h... – Varun Jan 17 '17 at 10:06

1 Answers1

1

In case of PulseAudio you did set the PulseAudio device , not the real device. The real HW can have the limitation, you must correctly react to. If you'd like to see min/max boundary of some parameter, you can do the next:

  1. using snd_pcm_hw_params_dump function
    snd_pcm_hw_params_t *params;
    snd_pcm_t *pcm_handle;
    int pcm;
    
    /* Open the PCM device in playback mode */
    pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0);
    if (pcm < 0) {
        printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE, snd_strerror(pcm));
        goto error_handling;
    }
    
    /* Allocate parameters object and fill it with default values*/
    snd_pcm_hw_params_alloca(&params);
    
    pcm = snd_pcm_hw_params_any(pcm_handle, params);
    if (pcm < 0) {
        printf("Broken configuration for this PCM: no configurations available\n");
        goto error_handling;
    }
    
    printf("hw boundary params  ***********************\n");
    snd_pcm_hw_params_dump(params, log);
    printf("*******************************************\n");
  1. The same using min/max functions

    snd_pcm_t* pcm;
    snd_pcm_hw_params_t* hw_parameters;
    int parameter;
    
    //... open device and allocate hw params here
    /*Fill params with a full configuration space for a PCM.
     The configuration space will be filled with all possible 
     ranges for the PCM device.*/
    snd_pcm_hw_params_any(pcm,hw_parameters);
    
    /* please substitute <parameter name> with real parameter name 
     for example buffer_size, buffer_time, rate, etc*/
    snd_pcm_hw_params_get_<parameter name>_min(hw_parameters,&parameter);
    printf("<parameter name> min : %d/n", parameter);
    snd_pcm_hw_params_get_<parameter name>_max(hw_parameters,&parameter);
    printf("<parameter name> max : %d/n", parameter);
    

I faced with the same issue, when tried to set the period size. There are my boundary (two different pcm devices):

log #1

hw boundary params  ***********************
ACCESS:  RW_INTERLEAVED
FORMAT:  U8 S16_LE S16_BE S24_LE S24_BE S32_LE S32_BE FLOAT_LE FLOAT_BE MU_LAW A_LAW S24_3LE S24_3BE
SUBFORMAT:  STD
SAMPLE_BITS: [8 32]
FRAME_BITS: [8 1024]
CHANNELS: [1 32]
RATE: [1 192000]
PERIOD_TIME: (5 4294967295)
PERIOD_SIZE: [1 1398102)
PERIOD_BYTES: [128 1398102)
PERIODS: [3 1024]
BUFFER_TIME: (15 4294967295]
BUFFER_SIZE: [3 4194304]
BUFFER_BYTES: [384 4194304]
TICK_TIME: ALL
*******************************************

log#2

**********************************DEBUG 
period time min    : 21333
period time max    : 21334
buffer time min    : 1
buffer time max    : -1
channels min       : 1
channels max       : 10000
rate  min          : 4000
rate  max          : -1
period size min    : 85
period size max    : 91628833
buffer size min    : 170
buffer size max    : 274877906
**********************************DEBUG_END

Here we can't change the period size due to period time limitation.