Android HAL層コード
AudioFlingerがhalレイヤにデータを書き込むとHalレイヤのout_に呼び出されますwrite関数
pcm streamデバイスを開くとselect_が呼び出されますデバイスとpcm_Open関数
enable_snd_デバイスとenable_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のプロセス:
以上のデバイスパスとaudio routeが開いている間に、最終的にmixer_に着きました.ctl_set_value関数、この関数の中で下層がユーザーに提供する空間の設備ノードを利用して下層のオーディオコントロールを制御しますまず、snd_を使用しますcard_create関数でサウンドカードを作成するとsnd_が呼び出されますctl_create関数はcontrol論理デバイスを作成します.
上にcontrolロジックデバイスを作成したとき、opsのsnd_ctl_dev_registerインタフェース、snd_が呼び出されますregister_デバイス転送snd_ctl_f_ops,このospは実際に使用されているcontrolデバイスの操作関数である.
ユーザースペースでmixer_ctl_set_value関数は最下位のcontrolノードを読み書きしますが、実はsnd_を通じてctl_ioctl関数によって実現されます.
最終的にsnd_ctl_elem_read_userとsnd_ctl_elem_write_user関数はそれぞれsnd_を呼び出したkcontrolのgetとput関数はdapm kcontrolコントロールの制御を実現した.
pcm_open
1 frame=channels*format=2*2バイト=4バイト(32 bits)Period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960 frames=960*32バイト
/dev/snd/pcmC%uD%u%cノードの下部に関連する操作関数:Pcm_native.c (\linux\android\kernel\sound\core):
ハードウェアパラメータ書き込み: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関数
具体的な流れは、snd_pcm_playback_ioctl 1関数では、SNDRV_PCM_IOCTL_WRITEI_FRAMESパラメータは、ユーザ空間から転送されたデータをsnd_に渡すpcm_lib_write()関数:
次にsnd_を見てみましょうpcm_lib_write_transferとsnd_pcm_startの2つの関数.
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関数を見つけることができます.
ユーザ空間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はデータを送信します.
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(¶ms);
param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT,
pcm_format_to_alsa(config->format));
param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT,
SNDRV_PCM_SUBFORMAT_STD);
param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size);
param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
pcm_format_to_bits(config->format));
param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS,
pcm_format_to_bits(config->format) * config->channels);
param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS,
config->channels);
param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count);
param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, config->rate);
if (flags & PCM_MMAP)
param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS,
SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
else
param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS,
SNDRV_PCM_ACCESS_RW_INTERLEAVED);
//
if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) {
oops(pcm, errno, "cannot set hw params");
goto fail_close;
}// 。
/* get our refined hw_params */
config->period_size = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
//
config->period_count = param_get_int(¶ms, 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 = 0;
return 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はデータを送信します.