建立所需的所有格式转换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;
}