Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15532988
  • 博文数量: 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-17 22:33:40

建立所需的所有格式转换plugin插件
int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
                struct snd_pcm_hw_params *params,
                struct snd_pcm_hw_params *slave_params)
{
    struct snd_pcm_plugin_format tmpformat;
    struct snd_pcm_plugin_format dstformat;
    struct snd_pcm_plugin_format srcformat;
    int src_access, dst_access;
    struct snd_pcm_plugin *plugin = NULL;
    int err;
    int stream = snd_pcm_plug_stream(plug);
    int slave_interleaved = (params_channels(slave_params) == 1 ||
                 params_access(slave_params) == SNDRV_PCM_ACCESS_RW_INTERLEAVED);

    switch (stream) { // 音频流模式
    case SNDRV_PCM_STREAM_PLAYBACK:                         // 放音模式
        dstformat.format = params_format(slave_params);     // dst目的format取自slave_params
        dstformat.rate = params_rate(slave_params);         // dst目的rate取自slave_paramsp
        dstformat.channels = params_channels(slave_params); // dst目的channels取自slave_paramsp
        srcformat.format = params_format(params);           // src源format取自params
        srcformat.rate = params_rate(params);               // src源rate取自params
        srcformat.channels = params_channels(params);       // src源channels取自params
        src_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;       // src访问模式为读写交叉访问
        dst_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
                          SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
        break;
    case SNDRV_PCM_STREAM_CAPTURE:                          // 录音模式
        dstformat.format = params_format(params);           // dst目的format取自params
        dstformat.rate = params_rate(params);               // dst目的rate取自params
        dstformat.channels = params_channels(params);       // dst目的channels取自params
        srcformat.format = params_format(slave_params);     // src源format取自slave_params
        srcformat.rate = params_rate(slave_params);         // src源rate取自slave_params
        srcformat.channels = params_channels(slave_params); // src源channels取自slave_params
        src_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
                          SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
        dst_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
        break;
    default:
        snd_BUG();
        return -EINVAL;
    }
    tmpformat = srcformat;  // 后面经过如果tmpformat内部参数调整成功,那么将更新到srcformat上[luther.gliethttp]
        
    pdprintf("srcformat: format=%i, rate=%i, channels=%i\n",
         srcformat.format,
         srcformat.rate,
         srcformat.channels);
    pdprintf("dstformat: format=%i, rate=%i, channels=%i\n",
         dstformat.format,
         dstformat.rate,
         dstformat.channels);

    /* Format change (linearization) */
    if (! rate_match(srcformat.rate, dstformat.rate) && // rate_match检查src和dst的rate是否匹配,它们之间允许有-+5%的误差
        ! snd_pcm_format_linear(srcformat.format)) { // 线性检查,判断pcm_formats[format].signd是否为非负值[luther.gliethttp]
        if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW) // 如果rate没有match或者srcformat非线性,同时又不是u律,所以返回EINVAL
            return -EINVAL;
        // rate没有match或者srcformat非线性,同时srcformat为u律,那么执行如下语句[luther.gliethttp]
        tmpformat.format = SNDRV_PCM_FORMAT_S16; // signed short有符号16bits
        err = snd_pcm_plugin_build_mulaw(plug, // 建立srcformat和tmpformat的音频u律转换plugin插件,回调处理函数为mulaw_transfer 《浅析alsa声卡驱动snd_pcm_plugin_build_mulaw函数》
                         &srcformat, &tmpformat,
                         &plugin);
        if (err < 0)
            return err;
        err = snd_pcm_plugin_append(plugin); // 将u律转换plugin插件追加到plugin链表末尾[luther.gliethttp] 《浅析alsa声卡驱动snd_pcm_plugin_append函数》
        if (err < 0) {
            snd_pcm_plugin_free(plugin);     // 如果追加出现错误,那么释放plugin结构体内部申请到的所有内存[luther.gliethttp]
            return err;
        }
        srcformat = tmpformat;               // 将仅仅修改了format为SNDRV_PCM_FORMAT_S16的tmpformat替换srcformat
        src_access = dst_access;             // 这样src和dst都是线性format了,src和dst之间的数据转换完全由
    }                                        // snd_pcm_plugin_build_mulaw建立的plugin回调函数完成[luther.gliethttp]

    /* channels reduction */
    if (srcformat.channels > dstformat.channels) {
        tmpformat.channels = dstformat.channels;// 尝试降低src的channels通道数
        err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin); // 建立srcformat和tmpformat的音频数据转换route路由plugin插件,回调处理函数为route_transfer 《浅析alsa声卡驱动snd_pcm_plugin_build_route函数》
        pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
        if (err < 0)
            return err;
        err = snd_pcm_plugin_append(plugin);// 将src与dst之间音频数据路由plugin插件追加到plugin链表末尾[luther.gliethttp] 《浅析alsa声卡驱动snd_pcm_plugin_append函数》
        if (err < 0) {
            snd_pcm_plugin_free(plugin);    // 如果追加出现错误,那么释放plugin结构体内部申请到的的所有内存[luther.gliethttp]
            return err;
        }
        srcformat = tmpformat;              // 将降低channels数目的tmpformat作为最终srcformat
        src_access = dst_access;
    }

    /* rate resampling */
    if (!rate_match(srcformat.rate, dstformat.rate)) {
        if (srcformat.format != SNDRV_PCM_FORMAT_S16) {
    // 执行到这里,说明上面的snd_pcm_format_linear(srcformat.format)结果为线性,所以非u律[luther.gliethttp]
            /* convert to S16 for resampling */
            tmpformat.format = SNDRV_PCM_FORMAT_S16; // 强制为SNDRV_PCM_FORMAT_S16格式
            err = snd_pcm_plugin_build_linear(plug,  // 建立srcformat和tmpformat的音频数据转换linear线性plugin插件,回调处理函数为linear_transfer
                              &srcformat, &tmpformat,
                              &plugin);
            if (err < 0)
                return err;
            err = snd_pcm_plugin_append(plugin);// 将src与dst之间音频数据线性转换plugin插件追加到plugin链表末尾[luther.gliethttp] 《浅析alsa声卡驱动snd_pcm_plugin_append函数》
            if (err < 0) {
                snd_pcm_plugin_free(plugin);// 如果追加出现错误,那么释放plugin结构体内部申请到的的所有内存[luther.gliethttp]
                return err;
            }
            srcformat = tmpformat;          // 将强制改变format为SNDRV_PCM_FORMAT_S16的tmpformat作为最终srcformat
            src_access = dst_access;
        }
        tmpformat.rate = dstformat.rate;    // 统一使用dstformat.rate
            err = snd_pcm_plugin_build_rate(plug, // 建立srcformat和tmpformat的音频数据转换rate速率改变匹配plugin插件,回调处理函数为rate_transfer
                            &srcformat, &tmpformat,
                        &plugin);
        pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err);
        if (err < 0)
            return err;
        err = snd_pcm_plugin_append(plugin);// 将src与dst之间音频数据rate速率转换plugin插件追加到plugin链表末尾[luther.gliethttp] 《浅析alsa声卡驱动snd_pcm_plugin_append函数》
        if (err < 0) {
            snd_pcm_plugin_free(plugin);    // 如果追加出现错误,那么释放plugin结构体内部申请到的的所有内存[luther.gliethttp]
            return err;
        }
        srcformat = tmpformat;              // 将改变rate速率的tmpformat作为最终srcformat
        src_access = dst_access;
        }

    /* format change */
    if (srcformat.format != dstformat.format) {
    // 如果format不同,那么强制使用dstformat.format
        tmpformat.format = dstformat.format;
        if (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW ||
            tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
            // 如果src和tmp有一个是u律,那么建立u律plugin插件
            err = snd_pcm_plugin_build_mulaw(plug,// 建立srcformat和tmpformat的音频u律转换plugin插件,回调处理函数为mulaw_transfer 《浅析alsa声卡驱动snd_pcm_plugin_build_mulaw函数》
                             &srcformat, &tmpformat,
                             &plugin);
        }
        else if (snd_pcm_format_linear(srcformat.format) &&
             snd_pcm_format_linear(tmpformat.format)) {
            err = snd_pcm_plugin_build_linear(plug,// 建立srcformat和tmpformat的音频数据转换linear线性plugin插件,回调处理函数为linear_transfer
                              &srcformat, &tmpformat,
                              &plugin);
        }
        else
            return -EINVAL;
        pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
        if (err < 0)
            return err;
        err = snd_pcm_plugin_append(plugin);// 将src与dst之间音频数转换plugin插件追加到plugin链表末尾[luther.gliethttp] 《浅析alsa声卡驱动snd_pcm_plugin_append函数》
        if (err < 0) {
            snd_pcm_plugin_free(plugin);    // 如果追加出现错误,那么释放plugin结构体内部申请到的的所有内存[luther.gliethttp]
            return err;
        }
        srcformat = tmpformat;
        src_access = dst_access;
    }

    /* channels extension */
    if (srcformat.channels < dstformat.channels) {
        tmpformat.channels = dstformat.channels; // 尝试扩充src的channels通道数
        err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);// 建立srcformat和tmpformat的音频数据转换route路由plugin插件,回调处理函数为route_transfer 《浅析alsa声卡驱动snd_pcm_plugin_build_route函数》
        pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
        if (err < 0)
            return err;
        err = snd_pcm_plugin_append(plugin);// 将src与dst之间音频数据路由plugin插件追加到plugin链表末尾[luther.gliethttp] 《浅析alsa声卡驱动snd_pcm_plugin_append函数》
        if (err < 0) {
            snd_pcm_plugin_free(plugin);    // 如果追加出现错误,那么释放plugin结构体内部申请到的的所有内存[luther.gliethttp]
            return err;
        }
        srcformat = tmpformat;              // 将扩充channels数目的tmpformat作为最终srcformat
        src_access = dst_access;
    }

    /* de-interleave */
    if (src_access != dst_access) {
    // 需要建立音频数据之间重新拷贝plugin插件[luther.gliethttp]
        err = snd_pcm_plugin_build_copy(plug, // 建立srcformat和tmpformat的音频数据重新拷贝plugin插件,回调处理函数为copy_transfer
                        &srcformat,
                        &tmpformat,
                        &plugin);
        pdprintf("interleave change (copy: returns %i)\n", err);
        if (err < 0)
            return err;
        err = snd_pcm_plugin_append(plugin);// 将src与dst之间音频数据重新拷贝plugin插件追加到plugin链表末尾[luther.gliethttp] 《浅析alsa声卡驱动snd_pcm_plugin_append函数》
        if (err < 0) {
            snd_pcm_plugin_free(plugin);    // 如果追加出现错误,那么释放plugin结构体内部申请到的的所有内存[luther.gliethttp]
            return err;
        }
    }

    return 0;
}
阅读(2786) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~