通过tinyalsa一般能看到硬件参数,比如NanoPC-T2的参数如下所示:
$ adb shell tinyalsa pcminfo -D 0
Info for card 0, device 0:
PCM out:
Access: 0x000009
Format[0]: 0x000004
Format[1]: 00000000
Format Name: S16_LE
Subformat: 0x000001
Rate: min=48000Hz max=48000Hz
Channels: min=2 max=2
Sample bits: min=16 max=16
Period size: min=8 max=2048
Period count: min=2 max=64
PCM in:
Access: 0x000009
Format[0]: 0x000004
Format[1]: 00000000
Format Name: S16_LE
Subformat: 0x000001
Rate: min=48000Hz max=48000Hz
Channels: min=2 max=2
Sample bits: min=16 max=16
Period size: min=8 max=2048
Period count: min=2 max=64
$
一般是有Rate
Sample bits
Period size
Period count
这几个参数,并且一部分参数是范围值。真正使用的需要看具体的平台的Audio HAL代码中的定义:
static struct snd_card_dev pcm_out = {
.name = "PCM OUT",
.card = 0,
.device = 0,
.flags = PCM_OUT,
.config = {
.channels = 2,
.rate = 48000,
.period_size = 1024,
.period_count = 4,
.format = PCM_FORMAT_S16_LE,
},
};
static struct snd_card_dev pcm_in = {
.name = "PCM IN",
.card = 0,
.device = 0,
.flags = PCM_IN,
.config = {
.channels = 2,
.rate = 48000,
.period_size = 1024,
.period_count = 4,
.format = PCM_FORMAT_S16_LE,
},
};
但是程序里一般使用的是mFrameSize
,mFrameCount
,mBufferSize
。它们之间的关系是什么呢?
mFrameSize = channels * format / 8 = 2 * 16 / 8 = 4;
mBufferSize = period_size * mFrameSize = 1024 * 4 = 4096;
mFrameCount = mBufferSize / mFrameSize = 4096 / 4 = 1024;
简单讲:就是period_size是可变了,它决定了上层的各个参数值。在HAL中将其设置小一点,上层的各种Size值就会小很多。比如period_size设置成最小的8。
mFrameSize = channels * format / 8 = 2 * 16 / 8 = 4;
mBufferSize = period_size * mFrameSize = 8 * 4 = 32;
mFrameCount = mBufferSize / mFrameSize = 32 / 4 = 8;
可以看到mFrameCount
实质是等于period_size
的值。AudioFlinger
里目前要求的最合适的值是16
。证据如下:
Over and Under Run
当一个声卡活动时,数据总是连续地在硬件缓存区和应用程序缓存区间传输。但是也有例外。在录音例子中,如果应用程序读取数据不够快,循环缓存区将会被新的数据覆盖。这种数据的丢失被称为overrun.在回放例子中,如果应用程序写入数据到缓存区中的速度不够快,缓存区将会”饿死”。这样的错误被称为”underrun”。在ALSA文档中,有时将这两种情形统称为”XRUN”。适当地设计应用程序可以最小化XRUN并且可以从中恢复过来。
来自:http://blog.csdn.net/zhang_danf/article/details/39005767
mNormalFrameCount和mFrameCount的关系
要使用FastMixer
需要搞清楚mNormalFrameCount
和mFrameCount
的关系,因为如果mFrameCount < mNormalFrameCount
才会起用FastMixer
。
// Calculate size of normal sink buffer relative to the HAL output buffer size
double multiplier = 1.0;
if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
kUseFastMixer == FastMixer_Dynamic)) {
size_t minNormalFrameCount = (kMinNormalSinkBufferSizeMs * mSampleRate) / 1000;
size_t maxNormalFrameCount = (kMaxNormalSinkBufferSizeMs * mSampleRate) / 1000;
// round up minimum and round down maximum to nearest 16 frames to satisfy AudioMixer
minNormalFrameCount = (minNormalFrameCount + 15) & ~15;
maxNormalFrameCount = maxNormalFrameCount & ~15;
if (maxNormalFrameCount < minNormalFrameCount) {
maxNormalFrameCount = minNormalFrameCount;
}
multiplier = (double) minNormalFrameCount / (double) mFrameCount;
if (multiplier <= 1.0) {
multiplier = 1.0;
} else if (multiplier <= 2.0) {
if (2 * mFrameCount <= maxNormalFrameCount) {
multiplier = 2.0;
} else {
multiplier = (double) maxNormalFrameCount / (double) mFrameCount;
}
} else {
// prefer an even multiplier, for compatibility with doubling of fast tracks due to HAL
// SRC (it would be unusual for the normal sink buffer size to not be a multiple of fast
// track, but we sometimes have to do this to satisfy the maximum frame count
// constraint)
// FIXME this rounding up should not be done if no HAL SRC
uint32_t truncMult = (uint32_t) multiplier;
if ((truncMult & 1)) {
if ((truncMult + 1) * mFrameCount <= maxNormalFrameCount) {
++truncMult;
}
}
multiplier = (double) truncMult;
}
}
mNormalFrameCount = multiplier * mFrameCount;
// round up to nearest 16 frames to satisfy AudioMixer
if (mType == MIXER || mType == DUPLICATING) {
mNormalFrameCount = (mNormalFrameCount + 15) & ~15;
}
ALOGI("HAL output buffer size %u frames, normal sink buffer size %u frames", mFrameCount,
mNormalFrameCount);