无法在ALSA上配置硬件参数覆盖范围应用

时间:2017-01-06 19:32:06

标签: c++ raspberry-pi alsa libalsa

我尝试编写用于录制音频的ALSA应用程序,当我尝试设置一些参数然后将它们打印到屏幕上时,我得到一些我无法更改的默认数字

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

这是我在运行时获得的覆盆子pi:

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

这是我在桌面电脑上运行时得到的结果:

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

正如你所看到的那样,我试图将周期大小设置为64并返回341,这个值只会在我更改速率时改变,假设我将速率设置为44100,这就是我得到的回复:

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

在桌面电脑上,这不会发生我试图在alsa-lib中追踪这个功能但我迷路了但也尝试了不同的声卡并且仍然得到相同的结果。

1 个答案:

答案 0 :(得分:0)

对于PulseAudio,您确实设置了PulseAudio设备,而不是实际设备。 实际的硬件可能有限制,您必须正确地做出反应。 如果您想查看某个参数的最小/最大边界,则可以执行下一个操作:

  1. 使用snd_pcm_hw_params_dump函数
    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. 使用最小/最大函数相同

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

在尝试设置周期大小时,我遇到了同样的问题。 有我的边界(两个不同的pcm设备):

日志#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

在此,由于时段时间限制,我们无法更改时段大小。