我发现当我对snd_pcm_hw_params_get_*
函数进行一些调用时,一个简单的ALSA回放程序的行为会有所不同。我的程序反复从缓冲区播放正弦波。当我加入电话时,我会得到一个纯正的音调。但是,当我删除电话时,我会收到一连串的哔哔声。这让我很担心,因为我不希望检索数据的调用与声音的播放方式有任何关系。我在廉价的USB声卡和我的(可能更好的)内置声卡上都有这种行为。
以下是代码:
#define GETPARAMS
int main() {
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
const char name[] = "hw:0,0";
int dir;
snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
unsigned int rate = 48000;
unsigned int channels = 2;
unsigned int periods = 4;
snd_pcm_uframes_t periodsize = 2048;
int num_frames = 2*periodsize;
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_open(&handle, name, stream, 0);
snd_pcm_hw_params_any(handle, params);
#ifdef GETPARAMS
printf("\nparameters before setting:\n");
snd_pcm_hw_params_get_rate(params, &rate, &dir);
printf(" rate = %d, dir = %d\n", rate, dir);
snd_pcm_hw_params_get_channels(params, &channels);
printf(" channels = %d\n", channels);
snd_pcm_hw_params_get_periods(params, &periods, &dir);
printf(" periods = %d, dir = %d\n", periods, dir);
snd_pcm_hw_params_get_buffer_size(params, &periodsize);
printf(" periodsize = %ld\n", periodsize);
#endif
snd_pcm_hw_params_set_access(handle, params, access);
snd_pcm_hw_params_set_format(handle, params, format);
snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir);
snd_pcm_hw_params_set_channels(handle, params, 2);
snd_pcm_hw_params_set_periods(handle, params, periods, 0);
snd_pcm_hw_params_set_buffer_size(handle, params, num_frames);
snd_pcm_hw_params(handle, params);
#ifdef GETPARAMS
printf("\nparameters after setting:\n");
snd_pcm_hw_params_get_rate(params, &rate, &dir);
printf(" rate = %d, dir = %d\n", rate, dir);
snd_pcm_hw_params_get_channels(params, &channels);
printf(" channels = %d\n", channels);
snd_pcm_hw_params_get_periods(params, &periods, &dir);
printf(" periods = %d, dir = %d\n", periods, dir);
snd_pcm_hw_params_get_buffer_size(params, &periodsize);
printf(" periodsize = %ld\n\n", periodsize);
#endif
int16_t *data = (int16_t*)calloc(2*periodsize, sizeof(int16_t));
loadpage(data, 2*periodsize);
snd_pcm_sframes_t frames;
snd_pcm_prepare(handle);
for (int i=0; i<8; i++) {
frames = snd_pcm_writei(handle, data, num_frames);
if (frames < 0)
frames = snd_pcm_recover(handle, frames, 0);
if (frames < 0) {
printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
}
if (frames > 0 && frames < num_frames)
printf("short write (expected %d, write %li)\n", num_frames, frames);
}
snd_pcm_close(handle);
free(data);
}
loadpage()
填充缓冲区。当我发表评论#define GETPARAMS
时,我会收到一连串的哔哔声。当我加入它时,我会得到一个纯净的音调。
以下是定义GETPARAMS
时的输出:
parameters before setting:
rate = 48000, dir = 32766
channels = 2
periods = 4, dir = 32766
periodsize = 2048
parameters after setting:
rate = 48000, dir = 0
channels = 2
periods = 4, dir = 0
periodsize = 4096
答案 0 :(得分:0)
如果尚未设置参数,则不得调用snd_pcm_hw_param_get_*()
函数,因为此时配置空间包含参数的多个潜在值。
要打印hw_params
容器的当前状态,请使用snd_pcm_hw_params_dump()
:
snd_output_t *output;
snd_output_stdio_attach(&output, stdout, 0);
...
snd_pcm_hw_params_dump(params, output);
...
snd_output_close(output);
无论如何,问题是periods
,periodsize
和num_frames
的初始值不一致,并且_get_
调用用其他值覆盖这些变量碰巧是一致的。
我不知道你真正想要使用什么值,但请注意,周期大小和缓冲区大小是以帧为单位测量的,并且一帧包含所有通道的所有样本,即在这种情况下,一帧具有四个字节。