C++ can';t在ALSA raspberry pi c应用程序上配置硬件参数
我试图编写一个用于录制音频的ALSA应用程序,当我试图设置一些参数,然后将它们打印到屏幕上时,我会得到一些无法更改的默认数字C++ can';t在ALSA raspberry pi c应用程序上配置硬件参数,c++,raspberry-pi,alsa,libalsa,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 sam
#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 = 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
在台式pc上,这种情况没有发生,我试图在alsa lib中跟踪此功能,但我在那里迷路了,也尝试了不同的声卡,仍然得到相同的结果。如果是PulseAudio,您设置的是PulseAudio设备,而不是真正的设备。 真正的硬件可能有局限性,您必须正确应对。 如果要查看某个参数的最小/最大边界,可以执行以下操作:
snd_pcm_hw_params_t*params;
snd_pcm_t*pcm_手柄;
int-pcm;
/*在播放模式下打开PCM设备*/
pcm=snd_pcm_打开(&pcm_手柄,pcm_设备,snd_pcm_流播放,0);
如果(pcm<0){
printf(“错误:无法打开\%s\”PCM设备。%s\n”,PCM\u设备,snd\u strerror(PCM));
转到错误处理;
}
/*分配参数对象并用默认值填充它*/
snd_pcm_hw_params_alloca(¶ms);
pcm=snd_pcm_hw_params_any(pcm_handle,params);
如果(pcm<0){
printf(“此PCM的配置中断:没有可用的配置\n”);
转到错误处理;
}
printf(“硬件边界参数************************\n”);
snd_pcm_硬件_参数_转储(参数,日志);
printf(“************************************************************\n”);
snd_pcm_t*pcm;
snd_pcm_硬件参数*硬件参数;
int参数;
//... 在此处打开设备并分配硬件参数
/*用PCM的完整配置空间填充参数。
配置空间将充满所有可能的内容
PCM设备的范围*/
snd_pcm_hw_参数_any(pcm,hw_参数);
/*请用实际参数名替换
例如缓冲区大小、缓冲区时间、速率等*/
snd_pcm_hw_params_get_min(hw_参数和参数);
printf(“最小值:%d/n”,参数);
snd_pcm_hw_params_get_max(hw_参数和参数);
printf(“最大值:%d/n”,参数);
由于时段时间限制,我们无法更改时段大小。您是否尝试过通过/proc文件增加prealloc?这是第二个回应。根据我的经验,这允许更大的缓冲区大小、周期等。Pi可能不使用
dmix
。在任何情况下,不同的硬件具有不同的功能。@CL。这不是硬件问题。我发现当安装pulseaudio时,它解决了问题,但又制造了另一个问题,我不想使用pulseaudio!pulseaudio附带了万亿个软件包,我认为其中一个解决了这个问题,甚至可能是pulseaudio自己。我想我会发现alsa lib中的结构snd_间隔对于各种配置(通道、采样位等)有最小值和最大值。周期大小的这个值将告诉周期大小可能的最小值和最大值(检查元素间隔中的SNDRV_PCM_HW_参数Period_大小索引)。。如果请求的时段大小值小于最小值,alsa lib将不设置该值。正如@CL告诉不同的硬件有不同的capabilities@Varun在哪里可以看到最小/最大值?只是为了确保我试着将周期大小设置为不同的值,从很小到很大,只是不改变值始终保持不变(341帧)
rate = 44100 bps
period time = 21333 us
period size = 940 frames
buffer time = 85328 us
buffer size = 3763 frames
periods per buffer = 3763 frames
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
*******************************************
**********************************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