通過前兩次對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進行操作的.