alsa sample rate跟踪 <3>

alsa sample rate跟踪 <3>

接着看。
还有一个疑问点,按照之前的分析,如果想要snd_pcm_hw_params被调用,需要调用snd_pcm_rate_open。
但是从上面列出来的函数调用关系没有调用snd_pcm_rate_open,那么这个东东是什么时候被调用的呢?
原来在函数snd_pcm_plug_hw_params中有个判断,如果client params中的参数与slave params中的不一致,将调用snd_pcm_plug_insert_plugins函数。

static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
 snd_pcm_plug_t *plug = pcm->private_data;
 snd_pcm_t *slave = plug->req_slave;
 snd_pcm_plug_params_t clt_params, slv_params;
 snd_pcm_hw_params_t sparams;
 int err;

 err = snd_pcm_plug_hw_refine_sprepare(pcm, &sparams);
 if (err < 0)
  return err;
 err = snd_pcm_plug_hw_refine_schange(pcm, params, &sparams);
 if (err < 0)
  return err;
 err = snd_pcm_hw_refine_soft(slave, &sparams);
 if (err < 0)
  return err;

 INTERNAL(snd_pcm_hw_params_get_access)(params, &clt_params.access);
 INTERNAL(snd_pcm_hw_params_get_format)(params, &clt_params.format);
 INTERNAL(snd_pcm_hw_params_get_channels)(params, &clt_params.channels);
 INTERNAL(snd_pcm_hw_params_get_rate)(params, &clt_params.rate, 0);

 INTERNAL(snd_pcm_hw_params_get_format)(&sparams, &slv_params.format);
 INTERNAL(snd_pcm_hw_params_get_channels)(&sparams, &slv_params.channels);
 INTERNAL(snd_pcm_hw_params_get_rate)(&sparams, &slv_params.rate, 0);
 snd_pcm_plug_clear(pcm);
 if (!(clt_params.format == slv_params.format &&
       clt_params.channels == slv_params.channels &&
       clt_params.rate == slv_params.rate &&
       !plug->ttable &&
       snd_pcm_hw_params_test_access(slave, &sparams,
         clt_params.access) >= 0)) {
  INTERNAL(snd_pcm_hw_params_set_access_first)(slave, &sparams, &slv_params.access);
  err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params);
  if (err < 0)
   return err;
 }
 slave = plug->gen.slave;
 err = _snd_pcm_hw_params(slave, params);
 if (err < 0) {
  snd_pcm_plug_clear(pcm);
  return err;
 }
 snd_pcm_unlink_hw_ptr(pcm, plug->req_slave);
 snd_pcm_unlink_appl_ptr(pcm, plug->req_slave);
 snd_pcm_link_hw_ptr(pcm, slave);
 snd_pcm_link_appl_ptr(pcm, slave);
 return 0;
}


 

函数snd_pcm_plug_insert_plugins中会通过一个while循环,依次调用plugin进行处理,知道client params和slave params完全一致。

static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
           snd_pcm_plug_params_t *client,
           snd_pcm_plug_params_t *slave)
{
 snd_pcm_plug_t *plug = pcm->private_data;
 static int (*const funcs[])(snd_pcm_t *_pcm, snd_pcm_t **new, snd_pcm_plug_params_t *s, snd_pcm_plug_params_t *d) = {
#ifdef BUILD_PCM_PLUGIN_MMAP_EMUL
  snd_pcm_plug_change_mmap,
#endif
  snd_pcm_plug_change_format,
#ifdef BUILD_PCM_PLUGIN_ROUTE
  snd_pcm_plug_change_channels,
#endif
#ifdef BUILD_PCM_PLUGIN_RATE
  snd_pcm_plug_change_rate,
#endif
#ifdef BUILD_PCM_PLUGIN_ROUTE
  snd_pcm_plug_change_channels,
#endif
  snd_pcm_plug_change_format,
  snd_pcm_plug_change_access
 };
 snd_pcm_plug_params_t p = *slave;
 unsigned int k = 0;
 plug->ttable_ok = plug->ttable_last = 0;
 while (client->format != p.format ||
        client->channels != p.channels ||
        client->rate != p.rate ||
        client->access != p.access) {
  snd_pcm_t *new;
  int err;
  if (k >= sizeof(funcs)/sizeof(*funcs))
   return -EINVAL;
  err = funcs[k](pcm, &new, client, &p);
  if (err < 0) {
   snd_pcm_plug_clear(pcm);
   return err;
  }
  if (err) {
   plug->gen.slave = new;
   pcm->fast_ops = new->fast_ops;
   pcm->fast_op_arg = new->fast_op_arg;
  }
  k++;
 }
...
}


 

其中的snd_pcm_plug_change_rate函数调用了snd_pcm_rate_open函数。
函数snd_pcm_plug_insert_plugins中定义了一个snd_pcm_t指针:snd_pcm_t *new,并将其传给了snd_pcm_plug_change_rate。
snd_pcm_plug_change_rate又将new传给了snd_pcm_rate_open函数。
snd_pcm_rate_open函数中将snd_pcm_rate_ops赋值给了new的ops成员:

 pcm->ops = &snd_pcm_rate_ops;



snd_pcm_plug_insert_plugins中判断如果处理都成功,将new赋值给plug->gen.slave:

 snd_pcm_plug_t *plug = pcm->private_data;
   plug->gen.slave = new;



再回到函数snd_pcm_plug_hw_params,其中在调用过snd_pcm_plug_insert_plugins之后,将plug->gen.slave赋值给了slave。
然后以slave为参数调用了函数_snd_pcm_hw_params:

 snd_pcm_plug_t *plug = pcm->private_data;
 slave = plug->gen.slave;
 err = _snd_pcm_hw_params(slave, params);



函数_snd_pcm_hw_params中会调用slave中ops的hw_params函数:

 err = pcm->ops->hw_params(pcm->op_arg, params);



 
看到这儿,发现alsa lib中通常是以pcm为媒介,在open的时候将根据需要将函数指针挂到pcm上。
后面要用的时候再调用pcm上的函数指针。
既然这样,我们就看看在前面的open流程中都往pcm上挂了哪些东东。

你可能感兴趣的:(alsa sample rate跟踪 <3>)