Alsa period_size/periods/buffer_size计算逻辑
背景:
ZX2000 FPGA验证时发现,S24_3LE mono格式的音乐播放时,会有周期性的噪音出现,噪音信号发生时是有音频数据的,只是看起来和原数据相比有位移,用正弦波测试时可以看出噪音信号的包络和原信号有些相似。
用默认配置的时候,读取runtime->period_size = 1366,一个比较奇怪的值。
当用tinyplay –p设置period_size时,发现如果设置的period_size <= 1024的时候,读出的runtime->period_size就会为1024这样常见的值,而此时播放S24_3LE mono格式的音乐就不会有噪音。
runtime->period_size = 1366这个奇怪的值是怎么来的?
原因:
在驱动里,我们会设置
period_bytes_min = 1024 * 4 = 4096,
period_bytes_max = 1024 *16,
alsa会根据上面的最大最小值算出一个合适的值作为runtime->period_size。
在pcm_native.c中,
上面的rule 10/11/12会定义相应的计算规则,其中rule 11是何我们关系最大的。
上面:
a->min = 4096// period_bytes_min
k = 8// (void *) 8, rule -> private
b->max// S24_3LE mono时为24,S24_3LE stereo 时为24*2; S24_LE stereo 时为32*2;S16_LE mono 时为16, S16_LE stereo时为16*2。实际上就是一个frame的bit数。
c->min = a->min * k /b->max = 4096 * 8 /24 = 1365.3333
上面:
i->min = 1024; //tinyplay.c main()中设置的
v->min = c-> min = 1365;
i->min < v->min, so i->min = v->min = 1365;
i->min++ , so i->min = 1366。
也就是runtime->period_size = 1366。
如果在驱动里,我们设置:
period_bytes_min = 1024,
period_bytes_max = 1024 *16,
那么:
a->min = 1024// period_bytes_min
k = 8// (void *) 8, rule -> private
b->max// S24_3LE mono时为24,S24_3LE stereo 时为24*2; S24_LE stereo 时为32*2;S16_LE mono 时为16, S16_LE stereo时为16*2。实际上就是一个frame的bit数。
c->min = a->min * k /b->max = 1024 * 8 /24 = 341.333
i->min = 1024;
v->min = c-> min = 341;
i->min > v->min, so i->min不变
i->min = 1024
也就是runtime->period_size = 1024。
Buffer_size计算逻辑:
Buffer_size = c->min = a->min * b-> min = period_size * periods
底层获得的Periods = 4,是tinplay.c中赋值的,period_size是上面计算出来的值。