可以使用一个模型来描述下面3组参数的意义
struct a { char one_period[runtime->oss.period_bytes] };
struct a periods_array[runtime->oss.periods]
runtime->oss.period_frames为当前可用a[]数组索引号+1,
语言描述的话,一共有periods个重复物理地址上连续的存储空间,每个存储空间的大小为period_bytes
static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *oss_params,
struct snd_pcm_hw_params *slave_params)
{
size_t s;
size_t oss_buffer_size, oss_period_size, oss_periods;
size_t min_period_size, max_period_size;
struct snd_pcm_runtime *runtime = substream->runtime;
size_t oss_frame_size;
oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *
params_channels(oss_params) / 8; // 计算1次采样所需存储字节数,比如8bits量化位数,立体声,那么这里就是8*2/8=2字节
// 对于放音如果没有设置plugin->src_frames的话,将直接返回drv_frames,
// 又因为slave_params是原始值,所以这里oss_buffer_size等于UINT_MAX[luther.gliethttp]
oss_buffer_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
oss_buffer_size = 1 << ld2(oss_buffer_size); // 计算oss_buffer_size最高1有效位的位置+1,
// 使用1 << max方式调整oss_buffer_size大小为为2的整数次密[luther.gliethttp]
if (atomic_read(&substream->mmap_count)) {
if (oss_buffer_size > runtime->oss.mmap_bytes)
oss_buffer_size = runtime->oss.mmap_bytes; // 不能超过mmap申请到的内存大小
}
// 在snd_pcm_oss_init_substream中对substream->oss进行了初始化[luther.gliethttp]
// substream->oss.setup = *setup;
// 所以感觉substream->oss.setup.period_size等于0
if (substream->oss.setup.period_size > 16)
oss_period_size = substream->oss.setup.period_size;
else if (runtime->oss.fragshift) {
oss_period_size = 1 << runtime->oss.fragshift;
if (oss_period_size > oss_buffer_size / 2)
oss_period_size = oss_buffer_size / 2;
} else {
int sd;
size_t bytes_per_sec = params_rate(oss_params) * snd_pcm_format_physical_width(params_format(oss_params)) * params_channels(oss_params) / 8;
// 1秒钟采样数据存储所需字节总数[luther.gliethttp]
oss_period_size = oss_buffer_size;
do {
oss_period_size /= 2;
} while (oss_period_size > bytes_per_sec); // oss_period_size不能大于bytes_per_sec
if (runtime->oss.subdivision == 0) {
// 在snd_pcm_oss_init_substream中初始化runtime->oss.subdivision为0
sd = 4;
if (oss_period_size / sd > 4096) // 降解之后尽量保证不大于4k,即便下面4*2变8,也不能保证
sd *= 2; /* 分频降解系数 */ // oss_period_size / sd就一定小于4k,只是尽量分频降解.
if (oss_period_size / sd < 4096)
sd = 1; // 如果小于4k,那么不用分频降解,系数为1[luther.gleithttp]
} else
sd = runtime->oss.subdivision; // 使用预设分频降解系数
oss_period_size /= sd;
if (oss_period_size < 16) // 分频降解之后不能小于16
oss_period_size = 16;
}
// min_period_size为substream预设的物理最小值[luther.gliethttp]
min_period_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
min_period_size *= oss_frame_size;
min_period_size = 1 << (ld2(min_period_size - 1) + 1);
if (oss_period_size < min_period_size) // oss_period_size不能小于substream预设的物理最小值
oss_period_size = min_period_size;
// max_period_size为substream预设的物理最大值[luther.gliethttp]
max_period_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
max_period_size *= oss_frame_size;
max_period_size = 1 << ld2(max_period_size);
if (oss_period_size > max_period_size) // oss_period_size不能大于substream预设的物理最大值
oss_period_size = max_period_size;
// 等效于struct a { 占用oss_period_size个字节存储空间 };
// 定义a[oss_periods]这样一个一维数组[luther.gliethttp]
// 一个period碎片数据一维数组项数占用oss_period_size字节,所以oss_buffer_size个字节存储空间一共可以提供
// oss_periods个period碎片数据一维数组项数[luther.gliethttp]
oss_periods = oss_buffer_size / oss_period_size;
if (substream->oss.setup.periods > 1)
oss_periods = substream->oss.setup.periods; // 使用强硬指定的periods碎片数据一维数组项数
s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)
s = runtime->oss.maxfrags;
if (oss_periods > s) // 如果计算的oss_periods碎片数据一维数组项数超过物理规定的oss.maxfrags
oss_periods = s; // 最大碎片数据一维数组项数,那么使用oss.maxfrags作为碎片数据一维数组项数[luther.gliethttp]
s = snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
if (s < 2)
s = 2;
if (oss_periods < s) // 一维数组项数不能小于最小值[luther.gliethttp]
oss_periods = s;
while (oss_period_size * oss_periods > oss_buffer_size) // a[oss_periods]数组总大小不能大于申请到的存储空间大小oss_buffer_size
oss_period_size /= 2; // 降低数组中每一项占用空间大小,对应的模型为:a[oss_periods / 2]
if (oss_period_size < 16) // 一个数组项大小不能小于16,因为太小就没有缓冲的意义了[luther.gliethttp]
return -EINVAL;
// ok, 通过上面跋山涉水的运算之后,终于我们得到了最终可用结果
// 可以使用一个模型来描述下面3组参数的意义
// struct a { char one_period[runtime->oss.period_bytes] };
// a[runtime->oss.periods]
// runtime->oss.period_frames为当前可用a[]数组索引号+1,
// 语言描述的话,一共有periods个重复物理地址上连续的存储空间,每个存储空间的大小为period_bytes
runtime->oss.period_bytes = oss_period_size;
runtime->oss.period_frames = 1;
runtime->oss.periods = oss_periods;
return 0;
}
阅读(3431) | 评论(0) | 转发(1) |