【发布时间】:2017-05-21 15:28:19
【问题描述】:
我尝试编写用于录制音频的 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;
}
这是我在运行树莓派时得到的结果:
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 中追踪这个函数但我迷路了那里也尝试了不同的声卡,但仍然得到相同的结果。
【问题讨论】:
-
你试过通过 /proc 文件增加 prealloc 吗?对此link 的第二次回复。根据我的经验,这允许更大的缓冲区大小、周期等。
-
Pi 可能不使用
dmix。无论如何,不同的硬件有不同的能力。 -
@CL。它不是硬件问题。我发现在安装pulseaudio时它可以解决问题但又制作了一个,我不想使用pulseaudio!并且pulseaudio带有万亿包,我认为其中一个可以解决问题,甚至可能是他自己的pulseaudio。我想我会发现的
-
alsa-lib 中的 struct snd_interval 具有各种配置(通道、样本位等)的最小值和最大值。周期大小(检查元素间隔中的 SNDRV_PCM_HW_PARAM_PERIOD_SIZE 索引)。如果请求的周期大小值小于最小值,alsa-lib 将不会设置它。正如@CL 所说,不同的硬件具有不同的功能
-
@Varun 我在哪里可以看到这个最小值/最大值?只是为了确保我尝试将周期大小设置为从很小到很大的不同值,它只是不改变值总是保持不变(341 帧)
标签: c++ raspberry-pi alsa libalsa