Android HAL層コード

29009 ワード

AudioFlingerがhalレイヤにデータを書き込むとHalレイヤのout_に呼び出されますwrite関数
pcm streamデバイスを開くとselect_が呼び出されますデバイスとpcm_Open関数
enable_snd_デバイスとenable_audio_route関数がデバイスパスを開くプロセス:
int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
{
    usecase = get_usecase_from_list(adev, uc_id);//  uc_id     usecase  
    if ((usecase->type == VOICE_CALL) || (usecase->type == VOIP_CALL)  ||  
   。。。。
    out_snd_device = platform_get_output_snd_device(adev->platform, usecase->stream.out->devices);

    in_snd_device = platform_get_input_snd_device
if (usecase->type == PCM_PLAYBACK) {  
            usecase->devices = usecase->stream.out->devices;  
            in_snd_device = SND_DEVICE_NONE;  
            out_snd_device = platform_get_output_snd_device(adev->platform,  
                                            usecase->stream.out->devices);  
...//                    
} else if (usecase->type == PCM_CAPTURE) {  
            usecase->devices = usecase->stream.in->device;  
            out_snd_device = SND_DEVICE_NONE;  
            in_snd_device = platform_get_input_snd_device(adev->platform,                                                                 AUDIO_DEVICE_NONE);  
             ...//                  
}  
}     
...  
if (out_snd_device != SND_DEVICE_NONE) {  
...  
        enable_snd_device(adev, out_snd_device, false);//          
}  
if (in_snd_device != SND_DEVICE_NONE) {  
    ....  
    enable_snd_device(adev, in_snd_device, false);//          
}   
...  
usecase->in_snd_device = in_snd_device;  
usecase->out_snd_device = out_snd_device;//              


enable_audio_route(adev, usecase, true);//  audio route 

int enable_snd_device(struct audio_device *adev, snd_device_t snd_device, bool __unused update_mixer) { …. if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0 ) { ALOGE(“%s: Invalid sound device returned”, func); return -EINVAL; }//snd_によるとデバイス名はデバイス_tableでdevice_を検索名前、例えば[SND_DEVICE_OUT_HANDSET]="handset"など…audio_route_apply_and_update_path(adev->audio_route, device_name); //現在のデバイスとnameはmixer_にありますpaths.xmlで対応するデバイスパスを見つけて開きます.
Audio_route.c (\system\media\audio_route)

int audio_route_apply_and_update_path(struct audio_route *ar, const charchar *name)  
{  
if (audio_route_apply_path(ar, name) < 0) {  
//             
        return -1;  
    }  
return audio_route_update_path(ar, name, false /*reverse*/);  
//             “/dev/snd/controlC0”   
}  
int audio_route_apply_path(struct audio_route *ar, const charchar *name)  
{  
    struct mixer_path *path;  
...  
    path = path_get_by_name(ar, name);//                 
...  
    path_apply(ar, path);//                     , mixer_state  


    return 0;  
}  


static int path_apply(struct audio_route *ar, struct mixer_path *path)  
{  
...  
    for (i = 0; i < path->length; i++) {  
        ctl_index = path->setting[i].ctl_index;//     id  
        ctl = index_to_ctl(ar, ctl_index);  
        type = mixer_ctl_get_type(ctl);  
        if (!is_supported_ctl_type(type))  
            continue;  
...  
        memcpy(ar->mixer_state[ctl_index].new_value, path->setting[i].value,  
               path->setting[i].num_values * sizeof(int));//      id         
    }  


    return 0;  
}  


static int audio_route_update_path(struct audio_route *ar, const charchar *name, bool reverse)  
{  
...  
path = path_get_by_name(ar, name);//          
...  
i = reverse ? (path->length - 1) : 0;  
end = reverse ? -1 : (int32_t)path->length;  


while (i != end) {  
...  
ctl_index = path->setting[i].ctl_index;//         id  
struct mixer_state * ms = &ar->mixer_state[ctl_index];//    id          
 ...  
 /* if any value has changed, update the mixer */  
 for (j = 0; j < ms->num_values; j++) {  
    if (ms->old_value[j] != ms->new_value[j]) {  
        if (type == MIXER_CTL_TYPE_ENUM)  
            mixer_ctl_set_value(ms->ctl, 0, ms->new_value[0]);  
//            
        else  
            mixer_ctl_set_array(ms->ctl, ms->new_value, ms->num_values);  
            memcpy(ms->old_value, ms->new_value, ms->num_values * sizeof(int));  
            break;  
    }  
  }  
  i = reverse ? (i - 1) : (i + 1);  
}  
return 0;  
}  
int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)  
{  
struct snd_ctl_elem_value ev;  
...  
memset(&ev, 0, sizeof(ev));  
ev.id.numid = ctl->info->id.numid;  
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);//             
...  
return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);//          /dev/snd/controlC0    
}  

audio routeのプロセス:
int enable_audio_route(struct audio_device *adev,  
                              struct audio_usecase *usecase,  
                              bool __unused update_mixer)  
{  
...  
platform_add_backend_name(mixer_path, snd_device);//          ,       audio route  
...  
audio_route_apply_and_update_path(adev->audio_route, mixer_path);//  audio route,                  
...  
}  

以上のデバイスパスとaudio routeが開いている間に、最終的にmixer_に着きました.ctl_set_value関数、この関数の中で下層がユーザーに提供する空間の設備ノードを利用して下層のオーディオコントロールを制御しますまず、snd_を使用しますcard_create関数でサウンドカードを作成するとsnd_が呼び出されますctl_create関数はcontrol論理デバイスを作成します.
int snd_ctl_create(struct snd_card *card)  
{  
    static struct snd_device_ops ops = {  
        .dev_free = snd_ctl_dev_free,  
        .dev_register = snd_ctl_dev_register,  
        .dev_disconnect = snd_ctl_dev_disconnect,  
    };//  ops     


    if (snd_BUG_ON(!card))  
        return -ENXIO;  
    return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);// control     card->devices    
}  

上にcontrolロジックデバイスを作成したとき、opsのsnd_ctl_dev_registerインタフェース、snd_が呼び出されますregister_デバイス転送snd_ctl_f_ops,このospは実際に使用されているcontrolデバイスの操作関数である.
static const struct file_operations snd_ctl_f_ops =
{
.owner =THIS_MODULE,
.read =snd_ctl_read,
.open =snd_ctl_open,
.release =snd_ctl_release,
.llseek =no_llseek,
.poll =snd_ctl_poll,
.unlocked_ioctl =snd_ctl_ioctl,
.compat_ioctl =snd_ctl_ioctl_compat,
.fasync =snd_ctl_fasync,
};

ユーザースペースでmixer_ctl_set_value関数は最下位のcontrolノードを読み書きしますが、実はsnd_を通じてctl_ioctl関数によって実現されます.
static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
...
case SNDRV_CTL_IOCTL_ELEM_READ:
return snd_ctl_elem_read_user(card, argp);
case SNDRV_CTL_IOCTL_ELEM_WRITE:
return snd_ctl_elem_write_user(ctl, argp);
...
}

最終的にsnd_ctl_elem_read_userとsnd_ctl_elem_write_user関数はそれぞれsnd_を呼び出したkcontrolのgetとput関数はdapm kcontrolコントロールの制御を実現した.
pcm_open
struct pcm_config pcm_config_deep_buffer = {
    .channels = 2,
    .rate = DEFAULT_OUTPUT_SAMPLING_RATE,//48000
    .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE,//960.period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,//8
    .format = PCM_FORMAT_S16_LE,//16 bits = 2bytes( 2  )
    .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
    .stop_threshold = INT_MAX,
    .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
};

1 frame=channels*format=2*2バイト=4バイト(32 bits)Period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960 frames=960*32バイト
struct pcm *pcm_open(unsigned int card, unsigned int device,
                     unsigned int flags, struct pcm_config *config)
{
struct snd_pcm_hw_params params;//    
struct snd_pcm_sw_params sparams;//    
...
pcm = calloc(1, sizeof(struct pcm));
pcm->config = *config;
snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device,
             flags & PCM_IN ? 'c' : 'p');//P       dai_link
pcm->flags = flags;
pcm->fd = open(fn, O_RDWR);//        


param_init(&params);
param_set_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT,
                   pcm_format_to_alsa(config->format));
param_set_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
                   SNDRV_PCM_SUBFORMAT_STD);
param_set_min(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size);
param_set_int(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
                  pcm_format_to_bits(config->format));
param_set_int(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
                  pcm_format_to_bits(config->format) * config->channels);
param_set_int(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
                  config->channels);
param_set_int(&params, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count);
param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, config->rate);


if (flags & PCM_MMAP)
param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
                   SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
else
param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
                   SNDRV_PCM_ACCESS_RW_INTERLEAVED);
//      


if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) {
        oops(pcm, errno, "cannot set hw params");
        goto fail_close;
}//              。


/* get our refined hw_params */
config->period_size = param_get_int(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
//          
config->period_count = param_get_int(&params, SNDRV_PCM_HW_PARAM_PERIODS);
pcm->buffer_size = config->period_count * config->period_size;
//        


 if (flags & PCM_MMAP) {
     pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size),
                                PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0);
  // pcm->buffer_size     
     ...
  }


  memset(&sparams, 0, sizeof(sparams));
  sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE;
  sparams.period_step = 1;
  sparams.start_threshold = config->start_threshold;
  sparams.stop_threshold = config->stop_threshold;
  sparams.avail_min = config->avail_min;
  sparams.xfer_align = config->period_size / 2; /* needed for old kernels */
  sparams.silence_size = 0;
  sparams.silence_threshold = config->silence_threshold;
  pcm->boundary = sparams.boundary = pcm->buffer_size;


  if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) {
        oops(pcm, errno, "cannot set sw params");
        goto fail;
  }//               


  rc = pcm_hw_mmap_status(pcm);
  ..
}

/dev/snd/pcmC%uD%u%cノードの下部に関連する操作関数:Pcm_native.c (\linux\android\kernel\sound\core):
const struct file_operations snd_pcm_f_ops[2] = {
{
.owner =THIS_MODULE,
.write =snd_pcm_write,
.aio_write =snd_pcm_aio_write,
.open =snd_pcm_playback_open,
.release =snd_pcm_release,
.llseek =no_llseek,
.poll =snd_pcm_playback_poll,
.unlocked_ioctl =snd_pcm_playback_ioctl,
.compat_ioctl =snd_pcm_ioctl_compat,
.mmap =snd_pcm_mmap,
.fasync =snd_pcm_fasync,
.get_unmapped_area =snd_pcm_get_unmapped_area,
},
{
.owner =THIS_MODULE,
.read =snd_pcm_read,
.aio_read =snd_pcm_aio_read,
.open =snd_pcm_capture_open,
.release =snd_pcm_release,
.llseek =no_llseek,
.poll =snd_pcm_capture_poll,
.unlocked_ioctl =snd_pcm_capture_ioctl,
.compat_ioctl =snd_pcm_ioctl_compat,
.mmap =snd_pcm_mmap,
.fasync =snd_pcm_fasync,
.get_unmapped_area =snd_pcm_get_unmapped_area,
}
};

ハードウェアパラメータ書き込み:snd_pcm_playback_ioctl -> snd_pcm_playback_ioctl1 -> snd_pcm_common_ioctl1-> snd_pcm_hw_params_user(substream, arg); ここでargはparams static int snd_に対応するpcm_hw_params_user(struct snd_pcm_substream *substream, struct snd_pcm_hw_params __user * _params) { struct snd_pcm_hw_params *params; int err;
params = memdup_user(_params, sizeof(*params));//ユーザーからカーネルへのパラメータのコピー
err = snd_pcm_hw_params(substream, params);//pcmハードウェアデバイスパラメータ設定
kfree(params); return err; }
ソフトウェアパラメータの書き込み、プロセス上のハードウェアの類似、最終的にsnd_pcm_sw_params関数.
pcm_write関数
int pcm_write(struct pcm *pcm, const void *data, unsigned int count)
{
struct snd_xferi x;
...
x.buf = (void*)data;
x.frames = count / (pcm->config.channels *
                        pcm_format_to_bits(pcm->config.format) / 8);
//     

。。。。
for (;;) {
   if (!pcm->running) {
      if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
         return oops(pcm, errno, "cannot prepare channel");
         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))
            return oops(pcm, errno, "cannot write initial data");
         pcm->running = 1;
         return 0;
   }
   if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
         pcm->running = 0return oops(pcm, errno, "cannot write stream data");
   }
   return 0;
}
}
        :
snd_pcm_playback_ioctl1() -> SNDRV_PCM_IOCTL_WRITEI_FRAMES -> snd_pcm_lib_write() ->snd_pcm_lib_write1() -> snd_pcm_lib_write_transfer()

具体的な流れは、snd_pcm_playback_ioctl 1関数では、SNDRV_PCM_IOCTL_WRITEI_FRAMESパラメータは、ユーザ空間から転送されたデータをsnd_に渡すpcm_lib_write()関数:
if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
return -EFAULT;
result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
snd_pcm_lib_write()     snd_pcm_lib_write1()    snd_pcm_lib_write_transfer() size     buf   DSP:
return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock,
 snd_pcm_lib_write_transfer);


static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, 
   unsigned long data,
   snd_pcm_uframes_t size,
   int nonblock,
   transfer_f transfer)
{
...
while (size > 0) {
...
err = transfer(substream, appl_ofs, data, offset, frames);
//  transfer  snd_pcm_lib_write_transfer,      substream->ops->copy(substream, -1, hwoff, buf, frames)     
...
if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
err = snd_pcm_start(substream);
...
}
}
...
}

次にsnd_を見てみましょうpcm_lib_write_transferとsnd_pcm_startの2つの関数.
static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
     unsigned int hwoff,
     unsigned long data, unsigned int off,
     snd_pcm_uframes_t frames)
{
struct snd_pcm_runtime *runtime = substream->runtime;
...
char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
if (substream->ops->copy) {
if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
//  substeam copy       dai  
return err;
} else {
char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
    //           
return -EFAULT;
}
return 0;
}


int snd_pcm_start(struct snd_pcm_substream *substream)
{
return snd_pcm_action(&snd_pcm_action_start, substream,
     SNDRV_PCM_STATE_RUNNING);
}
  ,
static struct action_ops snd_pcm_action_start = {
.pre_action = snd_pcm_pre_start,
.do_action = snd_pcm_do_start,
.undo_action = snd_pcm_undo_start,
.post_action = snd_pcm_post_start
};

snd_pcm_start関数には、snd_pcm_start-> snd_pcm_action -> snd_pcm_action_single
snd_pcm_action_singleではそれぞれ実行されます:ops->pre_action(substream, state); ops->do_action(substream, state); すなわちsnd_pcm_pre_start()とsnd_pcm_do_start()関数、snd_pcm_do_start関数では、substream->ops->trigger(substream、SNDRV_PCM_TRIGGER_START);データコピーがトリガーされます.
Substreamのopsはplatformで実現されていますsnd_soc_dai_linkではplatformを設定しましたname="msm-pcm-dsp.0"では、対応するops関数を見つけることができます.
Msm-pcm-q6-v2.c (\kernel\sound\soc\msm\qdsp6v2)
static struct snd_pcm_ops msm_pcm_ops = {
.open           = msm_pcm_open,
.copy= msm_pcm_copy,
.hw_params= msm_pcm_hw_params,
.close          = msm_pcm_close,
.ioctl          = snd_pcm_lib_ioctl,
.prepare        = msm_pcm_prepare,
.trigger        = msm_pcm_trigger,
.pointer        = msm_pcm_pointer,
.mmap= msm_pcm_mmap,
};

ユーザ空間pcm_write関数は、最下位のmsm_をそれぞれ呼び出します.pcm_copyとmsm_pcm_trigger関数、msm_pcm_copy関数にq 6 asm_が使用されていますwrite関数DSPにデータを書き込み、q 6 asm_writeとmsm_pcm_triggerでは最終的にapr_を通過しますsend_pktはデータを送信します.