代碼段一覽
TEST(AudioPolicyManagerTestInit, Failure) {
AudioPolicyTestClient client;
AudioPolicyTestManager manager(&client);
manager.getConfig().setDefault();
// Since the default client fails to open anything,
// APM should indicate that the initialization didn't succeed.
ASSERT_EQ(NO_INIT, manager.initialize());
ASSERT_EQ(NO_INIT, manager.initCheck());
}
流程分析
根據gtest框架,test代碼最終會執行上面的代碼塊中的內容。
- 首先創建一個
AudioPolicyTestClient
對象
AudioPolicyTestClient
派生於AudioPolicyClientInterface
。是AudioPolicy與AudioFlinger通信的客戶端。AudioPolicyClientInterface
提供了關於硬件的一些操作方法。比如一些常用的接口loadHwModule
、openOutput
、openInput
、getParameters
、setParameters
等。
- 創建
AudioPolicyTestManager
對象
AudioPolicyTestManager
派生於AudioPolicyManager
。而AudioPolicyManager
繼承於AudioPolicyInterface
。AudioPolicyInterface
提供了對音頻流的管理接口。AudioPolicyInterface
提供了對於音頻流控制和策略選擇的操作方法,比如getStrategy
、startOutput
、getOutputForAttr
等。所以AudioPolicyManager
提供了音頻策略和設備管理,以及音頻流控制的功能。AudioPolicyTestManager
的定義如下:
class AudioPolicyTestManager : public AudioPolicyManager {
public:
explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
: AudioPolicyManager(clientInterface, true /*forTesting*/) { }
using AudioPolicyManager::getConfig;
using AudioPolicyManager::initialize;
};
實例化AudiopolicyManager
對象,則會調用父類的AudioPolicyManager(clientInterface, true)
構造函數,在父類的構造函數中會將AudioPolicyTestClient
的實例註冊到mpClientInterface。創建StreamDescriptorCollection
/VolumeCurvesCollection
對象,該對象註冊到mVolumeCurves,mVolumeCurves包含一個mVector,mVector保存着流id
:StreamDescriptor
。創建AudioPolicyConfig
對象註冊到mConfig。代碼如下:
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface,
bool /*forTesting*/)
:
mUidCached(getuid()),
mpClientInterface(clientInterface),
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mA2dpSuspended(false),
#ifdef USE_XML_AUDIO_POLICY_CONF
mVolumeCurves(new VolumeCurvesCollection()),
mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices,
mDefaultOutputDevice, static_cast<VolumeCurvesCollection*>(mVolumeCurves.get())),
#else
mVolumeCurves(new StreamDescriptorCollection()),
mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices,
mDefaultOutputDevice),
#endif
mAudioPortGeneration(1),
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
mBeaconMuted(false),
mTtsOutputAvailable(false),
mMasterMono(false),
mMusicEffectOutput(AUDIO_IO_HANDLE_NONE),
mHasComputedSoundTriggerSupportsConcurrentCapture(false)
{
}
AudioPolicyTestManager
設置配置
- 通過調用
setDefault
來對AudioPolicyTestManager
實例設置配置,具體代碼如下:
manager.getConfig().setDefault()
最終會調用AudioPolicyConfig
中的setDefault()方法。
void setDefault(void)
{
mDefaultOutputDevices = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
sp<HwModule> module;
sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
mAvailableOutputDevices.add(mDefaultOutputDevices);
mAvailableInputDevices.add(defaultInputDevice);
module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY);
sp<OutputProfile> outProfile;
outProfile = new OutputProfile(String8("primary"));
outProfile->attach(module);
outProfile->addAudioProfile(
new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
outProfile->addSupportedDevice(mDefaultOutputDevices);
outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
module->addOutputProfile(outProfile);
sp<InputProfile> inProfile;
inProfile = new InputProfile(String8("primary"));
inProfile->attach(module);
inProfile->addAudioProfile(
new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
inProfile->addSupportedDevice(defaultInputDevice);
module->addInputProfile(inProfile);
mHwModules.add(module);
}
setDefault
流程分析
首先通過newDeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER)
創建一個mDefaultOutputDevices
對象。通過newDeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC)
創建一個defaultInputDevice
對象。最終將mDefaultOutputDevices
和defaultInputDevice
分別註冊mAvailableOutputDevices
和mAvailableInputDevices
鏈表中。
接着通過newHwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY)
創建一個硬件模塊module
。
通過newOutputProfile(String8("primary"))
創建一個輸出配置outProfile
,給輸出配置添加一個newAudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100)
對象,並將之前創建的SPEAK
設備添加到outProfile
中,最後在硬件模塊module
中添加outProfile
。
通過newInputProfile(String8("primary"))
創建一個輸入配置inProfile
,給輸入配置添加一個 newAudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000)
對象,並將之前創建的MIC
設備添加到InputProfile
中,最後在硬件模塊module
中添加InputProfile
。
最後,將module
註冊到mHwModules中。
- 對
manager
的initialize
和initCheck
進行斷言。
具體代碼如下:
ASSERT_EQ(NO_INIT, manager.initialize());
ASSERT_EQ(NO_INIT, manager.initCheck());
- 調用
initializeVolumeCurves
來進行每一個流的StreamDescriptor
策略初始化。如果該Speaker有DRC1功能,則使用默認的VolumeCurvePoint。 - 創建Engine引擎實例,並返回引擎實例。Engine代碼如下:
Engine::Engine()
: mManagerInterface(this),
mPhoneState(AUDIO_MODE_NORMAL),
mApmObserver(NULL)
{
for (int i = 0; i < AUDIO_POLICY_FORCE_USE_CNT; i++) {
mForceUse[i] = AUDIO_POLICY_FORCE_NONE;
}
}
- 將
AudioPolicyManager
註冊到Engine實例中,並做觀察者檢測。
mEngine->setObserver(this);
status_t status = mEngine->initCheck();
if (status != NO_ERROR) {
LOG_FATAL("Policy engine not initialized(err=%d)", status);
return status;
}
- 加載硬件庫,並將其返回句柄添加到
hwModule
中。
for (const auto& hwModule : mHwModulesAll) {
hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
ALOGW("could not open HW module %s", hwModule->getName());
continue;
}
...
}
默認會調用AudioPolicyClient
中的loadHwModule方法,但是測試類重新了此方法。具體代碼如下:
//默認方法
audio_module_handle_t AudioPolicyService::AudioPolicyClient::loadHwModule(const char *name)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return AUDIO_MODULE_HANDLE_NONE;
}
return af->loadHwModule(name);
}
//AudioPolicyTestClient重新的方法
audio_module_handle_t loadHwModule(const char* /*name*/) override {
return AUDIO_MODULE_HANDLE_NONE;
}
如果返回參數爲AUDIO_MODULE_HANDLE_NONE則不調用後面的操作,最終退出循環。
5. 將無效的輸入輸出從mAvailableOutputDevices
和mAvailableInputDevices
列表中移除,並返回NO_INIT
,初始化斷言成功。
6. 調用AudioPolicyManager::initCheck()
來進行初始化檢查。代碼如下:
status_t AudioPolicyManager::initCheck()
{
return hasPrimaryOutput() ? NO_ERROR : NO_INIT;
}
- for循環沒有執行,就沒有創建輸出,故
mPrimaryOutput
爲0。
Dynamic Range Control(動態範圍控制)提供聲音壓縮和放大能力,使聲音聽起來更柔和或更大聲,即一種信號調幅方式。 ↩︎