Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15498848
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2009-11-19 09:58:57

可以使用一个模型来描述下面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;
}
阅读(3436) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~