Android Audio 架构自学笔记(三) audio Flinger 基本概述
通过前两次对android audio整体架构的解析,我们已经基本了解andriod audio框架的基本组成以及android audio hal对上层所提供的基本接口。
由android audio架构中了解,android audio framework中的audioFlinger是andriod audio hal的直接使用者,那么接下来我们就看一下android audioFlinger是如何使用Android audio hal来实现audio基本功能的.
android audioFlinger 服务代码结构大致如下(图中只表现出来一部分);
通过图中文件名称再结合audio hal功能基本解析的结果,我们就可以大概了解其文件内容;
(1)AudioFlinger为audio Flinger服务的入口,其中应该能够包括audioFlinger对外提供的服务;
(2)AudioHwDevice为audio hal的上层抽象,通过名称我们可以猜测这个文件内容中操作大概与audio hal 的操作相对应;
(3)AudioStreamOut为audio hal outputStream的上层抽象。这里面的内容应该就是与audio hal stream_out的操作相对应。
(4)其他,暂时还没什么头绪。
按照以前的分析方法,我们仍然先去调查audioFlinger对外提供了哪些能力。然后再又上到下的调查方法查看这些能力是怎样与底层hal相结合来进行实现的。
audioFlinger文件声明的主要方法如下:
virtual sp<IAudioTrack> createTrack(参数先略)
virtual sp<IAudioRecord> openRecord(
audio_io_handle_t input,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
const String16& opPackageName,
size_t *pFrameCount,
audio_input_flags_t *flags,
pid_t pid,
pid_t tid,
int clientUid,
audio_session_t *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
sp<IMemory>& buffers,
status_t *status /*non-NULL*/,
audio_port_handle_t portId);
virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t *devices,
const String8& address,
uint32_t *latencyMs,
audio_output_flags_t flags);
virtual status_t openInput(audio_module_handle_t module,
audio_io_handle_t *input,
audio_config_t *config,
audio_devices_t *device,
const String8& address,
audio_source_t source,
audio_input_flags_t flags);
virtual audio_module_handle_t loadHwModule(const char *name);
.......
我们先将这些函数摘出来的主要原因是这些函数刚好与我们在hal 层分析的上层操作基本时序相对应,即先加载动态库(loadHwModule),然后根据参数使用方法创建输入输出流(openOutput、openInput),然后再通过流来进行数据操作。
我们先梳理整体时序,然后在了解整体时序的基础之上再对内部细节进行详细了解,否则很容易只关注了细节而忽略了对软件整体设计的理解。
1、virtual audio_module_handle_t loadHwModule(const char *name);通过名称来加载hal
在源码中,我们可以清楚看到loadHwModule对输入参数name合法性检查以及某个系统检查之后就直接调用loadHwModule_l来进行具体功能实现了;
audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
ALOGW("loadHwModule() module %s already loaded", name);
return mAudioHwDevs.keyAt(i);
}
}
sp<DeviceHalInterface> dev;
int rc = mDevicesFactoryHal->openDevice(name, &dev);
if (rc) {
ALOGE("loadHwModule() error %d loading module %s", rc, name);
return AUDIO_MODULE_HANDLE_NONE;
}
mHardwareStatus = AUDIO_HW_INIT;
rc = dev->initCheck();
mHardwareStatus = AUDIO_HW_IDLE;
if (rc) {
ALOGE("loadHwModule() init check error %d for module %s", rc, name);
return AUDIO_MODULE_HANDLE_NONE;
}
// Check and cache this HAL's level of support for master mute and master
// volume. If this is the first HAL opened, and it supports the get
// methods, use the initial values provided by the HAL as the current
// master mute and volume settings.
AudioHwDevice::Flags flags = static_cast<AudioHwDevice::Flags>(0);
{ // scope for auto-lock pattern
AutoMutex lock(mHardwareLock);
if (0 == mAudioHwDevs.size()) {
mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
float mv;
if (OK == dev->getMasterVolume(&mv)) {
mMasterVolume = mv;
}
mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE;
bool mm;
if (OK == dev->getMasterMute(&mm)) {
mMasterMute = mm;
}
}
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
if (OK == dev->setMasterVolume(mMasterVolume)) {
flags = static_cast<AudioHwDevice::Flags>(flags |
AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME);
}
mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
if (OK == dev->setMasterMute(mMasterMute)) {
flags = static_cast<AudioHwDevice::Flags>(flags |
AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE);
}
mHardwareStatus = AUDIO_HW_IDLE;
}
audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
ALOGI("loadHwModule() Loaded %s audio interface, handle %d", name, handle);
return handle;
}
我们对这个函数的基本流程进行梳理:
(1)首先判断输入的参数name是否在某个集合中存在,如果存在则直接返回hanle
(2)如果不存则使用halfactory对象通过名称打开(加载)相应的资源,并返回底层资源对象(dev)
(3)然后通过底层对象dev,先检查资源初始化状态。如果初始化状态符合操作条件则进行下一步操作,否则直接返回错误状态
(4)设置底层设备的音量、mute等属性
(5)生成唯一handle标识,创建上层AudioHwDevice对象与底层资源进行对应。然后将AudioHwDevice对象假如到mAudioHwDevs集合中,并返回对象唯一handle标识
通过上述流程梳理,我们可以了解到如下内容
(1)AudioHwDevice为底层hal的上层抽象,一个AudioHwDevice就对应着一个hal.
(2)我们可以通过AudioHwDevice获取底层资源dev,来对底层资源操作
(3)dev与handle进行绑定。我们可以通过handle在mAudioHwDevs集合中获取AudioHwDevice,然后再获得dev.或者通过name直接获得handle,然后再获得AudioHwDevice进而获得dev
2、virtual status_t openOutputaudio_module_handle_t module...)
在源码中,我们可以清楚看到openOutput对输入参数合法性检查以及某个系统检查之后就直接调用openOutput_l来进行具体功能实现了;
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t devices,
const String8& address,
audio_output_flags_t flags)
{
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
if (outHwDev == NULL) {
return 0;
}
if (*output == AUDIO_IO_HANDLE_NONE) {
*output = nextUniqueId(AUDIO_UNIQUE_ID_USE_OUTPUT);
} else {
// Audio Policy does not currently request a specific output handle.
// If this is ever needed, see openInput_l() for example code.
ALOGE("openOutput_l requested output handle %d is not AUDIO_IO_HANDLE_NONE", *output);
return 0;
}
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
// FOR TESTING ONLY:
// This if statement allows overriding the audio policy settings
// and forcing a specific format or channel mask to the HAL/Sink device for testing.
if (!(flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT))) {
// Check only for Normal Mixing mode
if (kEnableExtendedPrecision) {
// Specify format (uncomment one below to choose)
//config->format = AUDIO_FORMAT_PCM_FLOAT;
//config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
//config->format = AUDIO_FORMAT_PCM_32_BIT;
//config->format = AUDIO_FORMAT_PCM_8_24_BIT;
// ALOGV("openOutput_l() upgrading format to %#08x", config->format);
}
if (kEnableExtendedChannels) {
// Specify channel mask (uncomment one below to choose)
//config->channel_mask = audio_channel_out_mask_from_count(4); // for USB 4ch
//config->channel_mask = audio_channel_mask_from_representation_and_bits(
// AUDIO_CHANNEL_REPRESENTATION_INDEX, (1 << 4) - 1); // another 4ch example
}
}
AudioStreamOut *outputStream = NULL;
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
devices,
flags,
config,
address.string());
mHardwareStatus = AUDIO_HW_IDLE;
if (status == NO_ERROR) {
if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
sp<MmapPlaybackThread> thread =
new MmapPlaybackThread(this, *output, outHwDev, outputStream,
devices, AUDIO_DEVICE_NONE, mSystemReady);
mMmapThreads.add(*output, thread);
ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",
*output, thread.get());
return thread;
} else {
sp<PlaybackThread> thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created offload output: ID %d thread %p",
*output, thread.get());
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !isValidPcmSinkFormat(config->format)
|| !isValidPcmSinkChannelMask(config->channel_mask)) {
thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created direct output: ID %d thread %p",
*output, thread.get());
} else {
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created mixer output: ID %d thread %p",
*output, thread.get());
}
mPlaybackThreads.add(*output, thread);
return thread;
}
}
return 0;
}
我们对这个函数的基本流程进行梳理:
(1)首先根据输入的module以及devices找到底层所使用的hal资源
(2)生成唯一标识的output ID
(3)通过底层资源创建AudioStreamOut 输出数据流
(4)创建一个线程与输出数据流以及outputID进行绑定
(5)将创建的线程进行保存
通过上述流程梳理,我们可以了解到如下内容
(1)openOutput实际就是底层资源根据设备以及设备配置创建输出数据流
(2)每一个数据数据流都与一个线程进行绑定,并以outputID作为唯一标识
那么根据以上内容,我们就可以了解了在audioFlinger对底层audio hal的基本操作模式。
也由此可以推断出上层对数据流的相关操作大概时序为下:
1、先通过openoutput创建数据流
2、通过某种方式获得数据流的唯一标识outputID
3、通过outputID找到数据流对应的线程
4、然后将要写入到输出流的音频数据与线程建立联系,最终将数据写入到hal 层进而写到实际物理设备之中
我们就先将audioFlinger梳理到这里,这次的主要目的就是了解audioflinger与底层hal层的交互的基本步骤,下一步就沿着这个基本步骤,去调查stream对应的线程是如何对stream进行操作的.