当前位置: 代码迷 >> 综合 >> 原 Android8.0 Audio系统之AudioPolicy
  详细解决方案

原 Android8.0 Audio系统之AudioPolicy

热度:22   发布时间:2023-12-22 12:49:32.0

Android8.0 Audio系统之AudioPolicy

这里写图片描述

void AudioPolicyService::onFirstRef()
{
    {
    ......// class AudioPolicyClient : public AudioPolicyClientInterfacemAudioPolicyClient = new AudioPolicyClient(this);mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient); //创建Audio管理}
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

头文件 AudioPolicyClientInterface 位于 AudioPolicyInterface.h文件中


extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
    return new AudioPolicyManager(clientInterface);
}

extern “C” void destroyAudioPolicyManager(AudioPolicyInterface *interface)
{
delete interface;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

对于AudioPolicyClientImpl.cpp实现了 AudioPolicyClient,直接与AudioFlinger交互。对于AudioPolicyIntefaceImpl实现了AudioPolicyInterface直接与AudioPolicyManager交互,

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface):
#ifdef AUDIO_POLICY_TESTThread(false),
#endif //AUDIO_POLICY_TESTmLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),mA2dpSuspended(false),mAudioPortGeneration(1),mBeaconMuteRefCount(0),mBeaconPlayingRefCount(0),mBeaconMuted(false),mTtsOutputAvailable(false),mMasterMono(false),mMusicEffectOutput(AUDIO_IO_HANDLE_NONE)
{
    mpClientInterface = clientInterface;bool speakerDrcEnabled = false;//解析 xml Audio策略,路由
#ifdef USE_XML_AUDIO_POLICY_CONFmVolumeCurves = new VolumeCurvesCollection();AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,mDefaultOutputDevice, speakerDrcEnabled,static_cast<VolumeCurvesCollection *>(mVolumeCurves));if (deserializeAudioPolicyXmlConfig(config) != NO_ERROR) {
    
#elsemVolumeCurves = new StreamDescriptorCollection();AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,mDefaultOutputDevice, speakerDrcEnabled);if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&(ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
    
#endifALOGE("could not load audio policy configuration file, setting defaults");config.setDefault();}// must be done after reading the policy (since conditionned by Speaker Drc Enabling)mVolumeCurves->initializeVolumeCurves(speakerDrcEnabled);
<span class="token comment">// Once policy config has been parsed, retrieve an instance of the engine and initialize it</span>
<span class="token comment">//代理引擎</span>
audio_policy<span class="token punctuation">:</span><span class="token punctuation">:</span>EngineInstance <span class="token operator">*</span>engineInstance <span class="token operator">=</span> audio_policy<span class="token punctuation">:</span><span class="token punctuation">:</span>EngineInstance<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>engineInstance<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGE</span><span class="token punctuation">(</span><span class="token string">"%s:  Could not get an instance of policy engine"</span><span class="token punctuation">,</span> __FUNCTION__<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Retrieve the Policy Manager Interface</span>
mEngine <span class="token operator">=</span> engineInstance<span class="token operator">-&gt;</span>queryInterface<span class="token operator">&lt;</span>AudioPolicyManagerInterface<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//获取引擎</span>
mEngine<span class="token operator">-&gt;</span><span class="token function">setObserver</span><span class="token punctuation">(</span>this<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//设为观察者</span>
status_t status <span class="token operator">=</span> mEngine<span class="token operator">-&gt;</span><span class="token function">initCheck</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//初始</span>
<span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> status<span class="token punctuation">;</span>
<span class="token comment">// mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices</span>
<span class="token comment">// open all output streams needed to access attached devices</span>
audio_devices_t outputDeviceTypes <span class="token operator">=</span> mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">types</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
audio_devices_t inputDeviceTypes <span class="token operator">=</span> mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">types</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> <span class="token operator">~</span>AUDIO_DEVICE_BIT_IN<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> mHwModules<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//调用ClientInterface加载Audio模块,ClientInterface将调用AudioFlinger的loadHwModule</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mHandle <span class="token operator">=</span> mpClientInterface<span class="token operator">-&gt;</span><span class="token function">loadHwModule</span><span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mHandle <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"could not open HW module %s"</span><span class="token punctuation">,</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">//查找输出模块设备</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mOutputProfiles<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">const</span> sp<span class="token operator">&lt;</span>IOProfile<span class="token operator">&gt;</span> outProfile <span class="token operator">=</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mOutputProfiles<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>outProfile<span class="token operator">-&gt;</span><span class="token function">hasSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"Output profile contains no device on module %s"</span><span class="token punctuation">,</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> AUDIO_OUTPUT_FLAG_TTS<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>mTtsOutputAvailable <span class="token operator">=</span> true<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> AUDIO_OUTPUT_FLAG_DIRECT<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span>audio_devices_t profileType <span class="token operator">=</span> outProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDevicesType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>profileType <span class="token operator">&amp;</span> mDefaultOutputDevice<span class="token operator">-&gt;</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> AUDIO_DEVICE_NONE<span class="token punctuation">)</span> <span class="token punctuation">{</span>profileType <span class="token operator">=</span> mDefaultOutputDevice<span class="token operator">-&gt;</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>profileType <span class="token operator">=</span> outProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDeviceForType</span><span class="token punctuation">(</span>outputDeviceTypes<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>profileType <span class="token operator">&amp;</span> outputDeviceTypes<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span>sp<span class="token operator">&lt;</span>SwAudioOutputDescriptor<span class="token operator">&gt;</span> outputDesc <span class="token operator">=</span> new <span class="token function">SwAudioOutputDescriptor</span><span class="token punctuation">(</span>outProfile<span class="token punctuation">,</span>mpClientInterface<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> DeviceVector <span class="token operator">&amp;</span>supportedDevices <span class="token operator">=</span> outProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> DeviceVector <span class="token operator">&amp;</span>devicesForType <span class="token operator">=</span> supportedDevices<span class="token punctuation">.</span><span class="token function">getDevicesFromType</span><span class="token punctuation">(</span>profileType<span class="token punctuation">)</span><span class="token punctuation">;</span>String8 address <span class="token operator">=</span> devicesForType<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">?</span> devicesForType<span class="token punctuation">.</span><span class="token function">itemAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span>mAddress<span class="token punctuation">:</span> <span class="token function">String8</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>outputDesc<span class="token operator">-&gt;</span>mDevice <span class="token operator">=</span> profileType<span class="token punctuation">;</span>audio_config_t config <span class="token operator">=</span> AUDIO_CONFIG_INITIALIZER<span class="token punctuation">;</span>config<span class="token punctuation">.</span>sample_rate <span class="token operator">=</span> outputDesc<span class="token operator">-&gt;</span>mSamplingRate<span class="token punctuation">;</span>config<span class="token punctuation">.</span>channel_mask <span class="token operator">=</span> outputDesc<span class="token operator">-&gt;</span>mChannelMask<span class="token punctuation">;</span>config<span class="token punctuation">.</span>format <span class="token operator">=</span> outputDesc<span class="token operator">-&gt;</span>mFormat<span class="token punctuation">;</span>audio_io_handle_t output <span class="token operator">=</span> AUDIO_IO_HANDLE_NONE<span class="token punctuation">;</span><span class="token comment">//熟悉的openOutput</span>status_t status <span class="token operator">=</span> mpClientInterface<span class="token operator">-&gt;</span><span class="token function">openOutput</span><span class="token punctuation">(</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getModuleHandle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token operator">&amp;</span>output<span class="token punctuation">,</span><span class="token operator">&amp;</span>config<span class="token punctuation">,</span><span class="token operator">&amp;</span>outputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>address<span class="token punctuation">,</span><span class="token operator">&amp;</span>outputDesc<span class="token operator">-&gt;</span>mLatency<span class="token punctuation">,</span>outputDesc<span class="token operator">-&gt;</span>mFlags<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>status <span class="token operator">!=</span> NO_ERROR<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"Cannot open output stream for device %08x on hw module %s"</span><span class="token punctuation">,</span>outputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>outputDesc<span class="token operator">-&gt;</span>mSamplingRate <span class="token operator">=</span> config<span class="token punctuation">.</span>sample_rate<span class="token punctuation">;</span>outputDesc<span class="token operator">-&gt;</span>mChannelMask <span class="token operator">=</span> config<span class="token punctuation">.</span>channel_mask<span class="token punctuation">;</span>outputDesc<span class="token operator">-&gt;</span>mFormat <span class="token operator">=</span> config<span class="token punctuation">.</span>format<span class="token punctuation">;</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t k <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> k  <span class="token operator">&lt;</span> supportedDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> k<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>ssize_t index <span class="token operator">=</span> mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>supportedDevices<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// give a valid ID to an attached device once confirmed it is reachable</span><span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&gt;=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>mAvailableOutputDevices<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>mAvailableOutputDevices<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">attach</span><span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span>mPrimaryOutput <span class="token operator">==</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> AUDIO_OUTPUT_FLAG_PRIMARY<span class="token punctuation">)</span> <span class="token punctuation">{</span>mPrimaryOutput <span class="token operator">=</span> outputDesc<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token function">addOutput</span><span class="token punctuation">(</span>output<span class="token punctuation">,</span> outputDesc<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">setOutputDevice</span><span class="token punctuation">(</span>outputDesc<span class="token punctuation">,</span>outputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>true<span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token constant">NULL</span><span class="token punctuation">,</span>address<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">//遍历输入Audio设备</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mInputProfiles<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">const</span> sp<span class="token operator">&lt;</span>IOProfile<span class="token operator">&gt;</span> inProfile <span class="token operator">=</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mInputProfiles<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>inProfile<span class="token operator">-&gt;</span><span class="token function">hasSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"Input profile contains no device on module %s"</span><span class="token punctuation">,</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// chose first device present in profile's SupportedDevices also part of</span><span class="token comment">// inputDeviceTypes</span>audio_devices_t profileType <span class="token operator">=</span> inProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDeviceForType</span><span class="token punctuation">(</span>inputDeviceTypes<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>profileType <span class="token operator">&amp;</span> inputDeviceTypes<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span>sp<span class="token operator">&lt;</span>AudioInputDescriptor<span class="token operator">&gt;</span> inputDesc <span class="token operator">=</span>new <span class="token function">AudioInputDescriptor</span><span class="token punctuation">(</span>inProfile<span class="token punctuation">)</span><span class="token punctuation">;</span>inputDesc<span class="token operator">-&gt;</span>mDevice <span class="token operator">=</span> profileType<span class="token punctuation">;</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>audio_config_t config <span class="token operator">=</span> AUDIO_CONFIG_INITIALIZER<span class="token punctuation">;</span>config<span class="token punctuation">.</span>sample_rate <span class="token operator">=</span> inputDesc<span class="token operator">-&gt;</span>mSamplingRate<span class="token punctuation">;</span>config<span class="token punctuation">.</span>channel_mask <span class="token operator">=</span> inputDesc<span class="token operator">-&gt;</span>mChannelMask<span class="token punctuation">;</span>config<span class="token punctuation">.</span>format <span class="token operator">=</span> inputDesc<span class="token operator">-&gt;</span>mFormat<span class="token punctuation">;</span>audio_io_handle_t input <span class="token operator">=</span> AUDIO_IO_HANDLE_NONE<span class="token punctuation">;</span>status_t status <span class="token operator">=</span> mpClientInterface<span class="token operator">-&gt;</span><span class="token function">openInput</span><span class="token punctuation">(</span>inProfile<span class="token operator">-&gt;</span><span class="token function">getModuleHandle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token operator">&amp;</span>input<span class="token punctuation">,</span><span class="token operator">&amp;</span>config<span class="token punctuation">,</span><span class="token operator">&amp;</span>inputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>address<span class="token punctuation">,</span>AUDIO_SOURCE_MIC<span class="token punctuation">,</span>AUDIO_INPUT_FLAG_NONE<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>status <span class="token operator">==</span> NO_ERROR<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">const</span> DeviceVector <span class="token operator">&amp;</span>supportedDevices <span class="token operator">=</span> inProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t k <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> k  <span class="token operator">&lt;</span> supportedDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> k<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>ssize_t index <span class="token operator">=</span>  mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>supportedDevices<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// give a valid ID to an attached device once confirmed it is reachable</span><span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&gt;=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>sp<span class="token operator">&lt;</span>DeviceDescriptor<span class="token operator">&gt;</span> devDesc <span class="token operator">=</span> mAvailableInputDevices<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>devDesc<span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>devDesc<span class="token operator">-&gt;</span><span class="token function">attach</span><span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>devDesc<span class="token operator">-&gt;</span><span class="token function">importAudioPort</span><span class="token punctuation">(</span>inProfile<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span>mpClientInterface<span class="token operator">-&gt;</span><span class="token function">closeInput</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// make sure all attached devices have been allocated a unique ID</span>
<span class="token comment">//遍历输入输出设备,由路由引擎设置各设备的连接状态</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i  <span class="token operator">&lt;</span> mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mAvailableOutputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>mAvailableOutputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// The device is now validated and can be appended to the available devices of the engine</span>mEngine<span class="token operator">-&gt;</span><span class="token function">setDeviceConnectionState</span><span class="token punctuation">(</span>mAvailableOutputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span>AUDIO_POLICY_DEVICE_STATE_AVAILABLE<span class="token punctuation">)</span><span class="token punctuation">;</span>i<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i  <span class="token operator">&lt;</span> mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mAvailableInputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">;</span>mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>mAvailableInputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// The device is now validated and can be appended to the available devices of the engine</span>mEngine<span class="token operator">-&gt;</span><span class="token function">setDeviceConnectionState</span><span class="token punctuation">(</span>mAvailableInputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span>AUDIO_POLICY_DEVICE_STATE_AVAILABLE<span class="token punctuation">)</span><span class="token punctuation">;</span>i<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token function">updateDevicesAndOutputs</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212

可以看到AudioPolicyManager通过解析Audio配置文件,加载各输入输出音频Module,然后遍历各输入输出设备,找出稳定的设备后,由路由引擎设置各设备的连接状态。在分析AudioFlinger的时候走过 mpClientInterface->openOutput()函数

sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(.....)
{
    //找到Device, 这个函数很重要,稍后分析AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);//音频流输出到硬件设备AudioStreamOut *outputStream = NULL;status_t status = outHwDev->openOutputStream(&outputStream,*output,devices,flags,config,address.string());
mHardwareStatus <span class="token operator">=</span> AUDIO_HW_IDLE<span class="token punctuation">;</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在 createTrack_l()的时候,会去根据流类型来获取路由策略

    uint32_t strategy = AudioSystem::getStrategyForStream(streamType);for (size_t i = 0; i < mTracks.size(); ++i) {
    sp<Track> t = mTracks[i];if (t != 0 && t->isExternalTrack()) {
    //获取路由策略uint32_t actual = AudioSystem::getStrategyForStream(t->streamType());if (sessionId == t->sessionId() && strategy != actual) {
    ALOGE("createTrack_l() mismatched strategy; expected %u but found %u",strategy, actual);lStatus = BAD_VALUE;goto Exit;}}}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

调用 Audio代理服务的 getStrategyForStream

uint32_t AudioSystem::getStrategyForStream(audio_stream_type_t stream)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();if (aps == 0) return 0;return aps->getStrategyForStream(stream);
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

具体的实现在AudioPolicyInterfaceImpl.cpp文件中
\frameworks\av\services\audiopolicy\service\AudioPolicyInterfaceImpl.cpp

uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
{
    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
    return 0;}if (mAudioPolicyManager == NULL) {
    return 0;}return mAudioPolicyManager->getStrategyForStream(stream);
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
uint32_t AudioPolicyManager::getStrategyForStream(audio_stream_type_t stream) {
    return (uint32_t)getStrategy(stream);
}

  
  • 1
  • 2
  • 3
routing_strategy AudioPolicyManager::getStrategy(audio_stream_type_t stream) const
{
    ALOG_ASSERT(stream != AUDIO_STREAM_PATCH,"getStrategy() called for AUDIO_STREAM_PATCH");return mEngine->getStrategyForStream(stream);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在文件 frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.h 中 AudioPolicyManagerInterface *mEngine; 位于frameworks\av\services\audiopolicy\engine\interface\AudioPolicyManagerInterface.h,在frameworks\av\services\audiopolicy\enginedefault\src\Engine.h文件中被实现如下

  /// Interface membersclass ManagerInterfaceImpl : public AudioPolicyManagerInterface{
    public:explicit ManagerInterfaceImpl(Engine *policyEngine): mPolicyEngine(policyEngine) {
    }
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>virtual routing_strategy <span class="token function">getStrategyForStream</span><span class="token punctuation">(</span>audio_stream_type_t stream<span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">return</span> mPolicyEngine<span class="token operator">-&gt;</span><span class="token function">getStrategyForStream</span><span class="token punctuation">(</span>stream<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
private<span class="token punctuation">:</span>Engine <span class="token operator">*</span>mPolicyEngine<span class="token punctuation">;</span>
<span class="token punctuation">}</span> mManagerInterface<span class="token punctuation">;</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

最终将调用Engine.cpp的getStrategyForStream查询音频路由策略

routing_strategy Engine::getStrategyForStream(audio_stream_type_t stream)
{
    // stream to strategy mappingswitch (stream) {
    case AUDIO_STREAM_VOICE_CALL:case AUDIO_STREAM_BLUETOOTH_SCO:return STRATEGY_PHONE;case AUDIO_STREAM_RING:case AUDIO_STREAM_ALARM:return STRATEGY_SONIFICATION;case AUDIO_STREAM_NOTIFICATION:return STRATEGY_SONIFICATION_RESPECTFUL;case AUDIO_STREAM_DTMF:return STRATEGY_DTMF;default:ALOGE("unknown stream type %d", stream);case AUDIO_STREAM_SYSTEM:// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs// while key clicks are played produces a poor resultcase AUDIO_STREAM_MUSIC:return STRATEGY_MEDIA;case AUDIO_STREAM_ENFORCED_AUDIBLE:return STRATEGY_ENFORCED_AUDIBLE;case AUDIO_STREAM_TTS:return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;case AUDIO_STREAM_ACCESSIBILITY:return STRATEGY_ACCESSIBILITY;case AUDIO_STREAM_REROUTING:return STRATEGY_REROUTING;}
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

在AudioPolicyService.h文件中定义了如下函数,用来处理设备改变时调整路由策略

virtual status_t handleDeviceConfigChange(audio_devices_t device,const char *device_address,const char *device_name);

  
  • 1
  • 2
  • 3

至此音频代理路由部分暂到这,目前所看到的只是一小部分,随着Android系统的日益复杂,Audio会变得越来越庞大;
不过万变不离其宗,只要大体架构上不做大改动,也是很容易分析的,下一篇我们来看Audio系统的硬件抽象层。

        </div><link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-258a4616f7.css" rel="stylesheet"></div>
</article>

Android8.0 Audio系统之AudioPolicy

这里写图片描述

void AudioPolicyService::onFirstRef()
{
    {
    ......// class AudioPolicyClient : public AudioPolicyClientInterfacemAudioPolicyClient = new AudioPolicyClient(this);mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient); //创建Audio管理}
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

头文件 AudioPolicyClientInterface 位于 AudioPolicyInterface.h文件中


extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
    return new AudioPolicyManager(clientInterface);
}

extern “C” void destroyAudioPolicyManager(AudioPolicyInterface *interface)
{
delete interface;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

对于AudioPolicyClientImpl.cpp实现了 AudioPolicyClient,直接与AudioFlinger交互。对于AudioPolicyIntefaceImpl实现了AudioPolicyInterface直接与AudioPolicyManager交互,

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface):
#ifdef AUDIO_POLICY_TESTThread(false),
#endif //AUDIO_POLICY_TESTmLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),mA2dpSuspended(false),mAudioPortGeneration(1),mBeaconMuteRefCount(0),mBeaconPlayingRefCount(0),mBeaconMuted(false),mTtsOutputAvailable(false),mMasterMono(false),mMusicEffectOutput(AUDIO_IO_HANDLE_NONE)
{
    mpClientInterface = clientInterface;bool speakerDrcEnabled = false;//解析 xml Audio策略,路由
#ifdef USE_XML_AUDIO_POLICY_CONFmVolumeCurves = new VolumeCurvesCollection();AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,mDefaultOutputDevice, speakerDrcEnabled,static_cast<VolumeCurvesCollection *>(mVolumeCurves));if (deserializeAudioPolicyXmlConfig(config) != NO_ERROR) {
    
#elsemVolumeCurves = new StreamDescriptorCollection();AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,mDefaultOutputDevice, speakerDrcEnabled);if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&(ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
    
#endifALOGE("could not load audio policy configuration file, setting defaults");config.setDefault();}// must be done after reading the policy (since conditionned by Speaker Drc Enabling)mVolumeCurves->initializeVolumeCurves(speakerDrcEnabled);
<span class="token comment">// Once policy config has been parsed, retrieve an instance of the engine and initialize it</span>
<span class="token comment">//代理引擎</span>
audio_policy<span class="token punctuation">:</span><span class="token punctuation">:</span>EngineInstance <span class="token operator">*</span>engineInstance <span class="token operator">=</span> audio_policy<span class="token punctuation">:</span><span class="token punctuation">:</span>EngineInstance<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>engineInstance<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGE</span><span class="token punctuation">(</span><span class="token string">"%s:  Could not get an instance of policy engine"</span><span class="token punctuation">,</span> __FUNCTION__<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Retrieve the Policy Manager Interface</span>
mEngine <span class="token operator">=</span> engineInstance<span class="token operator">-&gt;</span>queryInterface<span class="token operator">&lt;</span>AudioPolicyManagerInterface<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//获取引擎</span>
mEngine<span class="token operator">-&gt;</span><span class="token function">setObserver</span><span class="token punctuation">(</span>this<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//设为观察者</span>
status_t status <span class="token operator">=</span> mEngine<span class="token operator">-&gt;</span><span class="token function">initCheck</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//初始</span>
<span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> status<span class="token punctuation">;</span>
<span class="token comment">// mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices</span>
<span class="token comment">// open all output streams needed to access attached devices</span>
audio_devices_t outputDeviceTypes <span class="token operator">=</span> mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">types</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
audio_devices_t inputDeviceTypes <span class="token operator">=</span> mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">types</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> <span class="token operator">~</span>AUDIO_DEVICE_BIT_IN<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> mHwModules<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//调用ClientInterface加载Audio模块,ClientInterface将调用AudioFlinger的loadHwModule</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mHandle <span class="token operator">=</span> mpClientInterface<span class="token operator">-&gt;</span><span class="token function">loadHwModule</span><span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mHandle <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"could not open HW module %s"</span><span class="token punctuation">,</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">//查找输出模块设备</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mOutputProfiles<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">const</span> sp<span class="token operator">&lt;</span>IOProfile<span class="token operator">&gt;</span> outProfile <span class="token operator">=</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mOutputProfiles<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>outProfile<span class="token operator">-&gt;</span><span class="token function">hasSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"Output profile contains no device on module %s"</span><span class="token punctuation">,</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> AUDIO_OUTPUT_FLAG_TTS<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>mTtsOutputAvailable <span class="token operator">=</span> true<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> AUDIO_OUTPUT_FLAG_DIRECT<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span>audio_devices_t profileType <span class="token operator">=</span> outProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDevicesType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>profileType <span class="token operator">&amp;</span> mDefaultOutputDevice<span class="token operator">-&gt;</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> AUDIO_DEVICE_NONE<span class="token punctuation">)</span> <span class="token punctuation">{</span>profileType <span class="token operator">=</span> mDefaultOutputDevice<span class="token operator">-&gt;</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>profileType <span class="token operator">=</span> outProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDeviceForType</span><span class="token punctuation">(</span>outputDeviceTypes<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>profileType <span class="token operator">&amp;</span> outputDeviceTypes<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span>sp<span class="token operator">&lt;</span>SwAudioOutputDescriptor<span class="token operator">&gt;</span> outputDesc <span class="token operator">=</span> new <span class="token function">SwAudioOutputDescriptor</span><span class="token punctuation">(</span>outProfile<span class="token punctuation">,</span>mpClientInterface<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> DeviceVector <span class="token operator">&amp;</span>supportedDevices <span class="token operator">=</span> outProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> DeviceVector <span class="token operator">&amp;</span>devicesForType <span class="token operator">=</span> supportedDevices<span class="token punctuation">.</span><span class="token function">getDevicesFromType</span><span class="token punctuation">(</span>profileType<span class="token punctuation">)</span><span class="token punctuation">;</span>String8 address <span class="token operator">=</span> devicesForType<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">?</span> devicesForType<span class="token punctuation">.</span><span class="token function">itemAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span>mAddress<span class="token punctuation">:</span> <span class="token function">String8</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>outputDesc<span class="token operator">-&gt;</span>mDevice <span class="token operator">=</span> profileType<span class="token punctuation">;</span>audio_config_t config <span class="token operator">=</span> AUDIO_CONFIG_INITIALIZER<span class="token punctuation">;</span>config<span class="token punctuation">.</span>sample_rate <span class="token operator">=</span> outputDesc<span class="token operator">-&gt;</span>mSamplingRate<span class="token punctuation">;</span>config<span class="token punctuation">.</span>channel_mask <span class="token operator">=</span> outputDesc<span class="token operator">-&gt;</span>mChannelMask<span class="token punctuation">;</span>config<span class="token punctuation">.</span>format <span class="token operator">=</span> outputDesc<span class="token operator">-&gt;</span>mFormat<span class="token punctuation">;</span>audio_io_handle_t output <span class="token operator">=</span> AUDIO_IO_HANDLE_NONE<span class="token punctuation">;</span><span class="token comment">//熟悉的openOutput</span>status_t status <span class="token operator">=</span> mpClientInterface<span class="token operator">-&gt;</span><span class="token function">openOutput</span><span class="token punctuation">(</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getModuleHandle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token operator">&amp;</span>output<span class="token punctuation">,</span><span class="token operator">&amp;</span>config<span class="token punctuation">,</span><span class="token operator">&amp;</span>outputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>address<span class="token punctuation">,</span><span class="token operator">&amp;</span>outputDesc<span class="token operator">-&gt;</span>mLatency<span class="token punctuation">,</span>outputDesc<span class="token operator">-&gt;</span>mFlags<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>status <span class="token operator">!=</span> NO_ERROR<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"Cannot open output stream for device %08x on hw module %s"</span><span class="token punctuation">,</span>outputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>outputDesc<span class="token operator">-&gt;</span>mSamplingRate <span class="token operator">=</span> config<span class="token punctuation">.</span>sample_rate<span class="token punctuation">;</span>outputDesc<span class="token operator">-&gt;</span>mChannelMask <span class="token operator">=</span> config<span class="token punctuation">.</span>channel_mask<span class="token punctuation">;</span>outputDesc<span class="token operator">-&gt;</span>mFormat <span class="token operator">=</span> config<span class="token punctuation">.</span>format<span class="token punctuation">;</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t k <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> k  <span class="token operator">&lt;</span> supportedDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> k<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>ssize_t index <span class="token operator">=</span> mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>supportedDevices<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// give a valid ID to an attached device once confirmed it is reachable</span><span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&gt;=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>mAvailableOutputDevices<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>mAvailableOutputDevices<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">attach</span><span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span>mPrimaryOutput <span class="token operator">==</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> AUDIO_OUTPUT_FLAG_PRIMARY<span class="token punctuation">)</span> <span class="token punctuation">{</span>mPrimaryOutput <span class="token operator">=</span> outputDesc<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token function">addOutput</span><span class="token punctuation">(</span>output<span class="token punctuation">,</span> outputDesc<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">setOutputDevice</span><span class="token punctuation">(</span>outputDesc<span class="token punctuation">,</span>outputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>true<span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token constant">NULL</span><span class="token punctuation">,</span>address<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">//遍历输入Audio设备</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mInputProfiles<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">const</span> sp<span class="token operator">&lt;</span>IOProfile<span class="token operator">&gt;</span> inProfile <span class="token operator">=</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mInputProfiles<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>inProfile<span class="token operator">-&gt;</span><span class="token function">hasSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"Input profile contains no device on module %s"</span><span class="token punctuation">,</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// chose first device present in profile's SupportedDevices also part of</span><span class="token comment">// inputDeviceTypes</span>audio_devices_t profileType <span class="token operator">=</span> inProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDeviceForType</span><span class="token punctuation">(</span>inputDeviceTypes<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>profileType <span class="token operator">&amp;</span> inputDeviceTypes<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span>sp<span class="token operator">&lt;</span>AudioInputDescriptor<span class="token operator">&gt;</span> inputDesc <span class="token operator">=</span>new <span class="token function">AudioInputDescriptor</span><span class="token punctuation">(</span>inProfile<span class="token punctuation">)</span><span class="token punctuation">;</span>inputDesc<span class="token operator">-&gt;</span>mDevice <span class="token operator">=</span> profileType<span class="token punctuation">;</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>audio_config_t config <span class="token operator">=</span> AUDIO_CONFIG_INITIALIZER<span class="token punctuation">;</span>config<span class="token punctuation">.</span>sample_rate <span class="token operator">=</span> inputDesc<span class="token operator">-&gt;</span>mSamplingRate<span class="token punctuation">;</span>config<span class="token punctuation">.</span>channel_mask <span class="token operator">=</span> inputDesc<span class="token operator">-&gt;</span>mChannelMask<span class="token punctuation">;</span>config<span class="token punctuation">.</span>format <span class="token operator">=</span> inputDesc<span class="token operator">-&gt;</span>mFormat<span class="token punctuation">;</span>audio_io_handle_t input <span class="token operator">=</span> AUDIO_IO_HANDLE_NONE<span class="token punctuation">;</span>status_t status <span class="token operator">=</span> mpClientInterface<span class="token operator">-&gt;</span><span class="token function">openInput</span><span class="token punctuation">(</span>inProfile<span class="token operator">-&gt;</span><span class="token function">getModuleHandle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token operator">&amp;</span>input<span class="token punctuation">,</span><span class="token operator">&amp;</span>config<span class="token punctuation">,</span><span class="token operator">&amp;</span>inputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>address<span class="token punctuation">,</span>AUDIO_SOURCE_MIC<span class="token punctuation">,</span>AUDIO_INPUT_FLAG_NONE<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>status <span class="token operator">==</span> NO_ERROR<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">const</span> DeviceVector <span class="token operator">&amp;</span>supportedDevices <span class="token operator">=</span> inProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t k <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> k  <span class="token operator">&lt;</span> supportedDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> k<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>ssize_t index <span class="token operator">=</span>  mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>supportedDevices<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// give a valid ID to an attached device once confirmed it is reachable</span><span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&gt;=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>sp<span class="token operator">&lt;</span>DeviceDescriptor<span class="token operator">&gt;</span> devDesc <span class="token operator">=</span> mAvailableInputDevices<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>devDesc<span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>devDesc<span class="token operator">-&gt;</span><span class="token function">attach</span><span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>devDesc<span class="token operator">-&gt;</span><span class="token function">importAudioPort</span><span class="token punctuation">(</span>inProfile<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span>mpClientInterface<span class="token operator">-&gt;</span><span class="token function">closeInput</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// make sure all attached devices have been allocated a unique ID</span>
<span class="token comment">//遍历输入输出设备,由路由引擎设置各设备的连接状态</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i  <span class="token operator">&lt;</span> mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mAvailableOutputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>mAvailableOutputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// The device is now validated and can be appended to the available devices of the engine</span>mEngine<span class="token operator">-&gt;</span><span class="token function">setDeviceConnectionState</span><span class="token punctuation">(</span>mAvailableOutputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span>AUDIO_POLICY_DEVICE_STATE_AVAILABLE<span class="token punctuation">)</span><span class="token punctuation">;</span>i<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i  <span class="token operator">&lt;</span> mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mAvailableInputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">;</span>mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>mAvailableInputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// The device is now validated and can be appended to the available devices of the engine</span>mEngine<span class="token operator">-&gt;</span><span class="token function">setDeviceConnectionState</span><span class="token punctuation">(</span>mAvailableInputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span>AUDIO_POLICY_DEVICE_STATE_AVAILABLE<span class="token punctuation">)</span><span class="token punctuation">;</span>i<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token function">updateDevicesAndOutputs</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212

可以看到AudioPolicyManager通过解析Audio配置文件,加载各输入输出音频Module,然后遍历各输入输出设备,找出稳定的设备后,由路由引擎设置各设备的连接状态。在分析AudioFlinger的时候走过 mpClientInterface->openOutput()函数

sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(.....)
{
    //找到Device, 这个函数很重要,稍后分析AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);//音频流输出到硬件设备AudioStreamOut *outputStream = NULL;status_t status = outHwDev->openOutputStream(&outputStream,*output,devices,flags,config,address.string());
mHardwareStatus <span class="token operator">=</span> AUDIO_HW_IDLE<span class="token punctuation">;</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在 createTrack_l()的时候,会去根据流类型来获取路由策略

    uint32_t strategy = AudioSystem::getStrategyForStream(streamType);for (size_t i = 0; i < mTracks.size(); ++i) {
    sp<Track> t = mTracks[i];if (t != 0 && t->isExternalTrack()) {
    //获取路由策略uint32_t actual = AudioSystem::getStrategyForStream(t->streamType());if (sessionId == t->sessionId() && strategy != actual) {
    ALOGE("createTrack_l() mismatched strategy; expected %u but found %u",strategy, actual);lStatus = BAD_VALUE;goto Exit;}}}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

调用 Audio代理服务的 getStrategyForStream

uint32_t AudioSystem::getStrategyForStream(audio_stream_type_t stream)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();if (aps == 0) return 0;return aps->getStrategyForStream(stream);
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

具体的实现在AudioPolicyInterfaceImpl.cpp文件中
\frameworks\av\services\audiopolicy\service\AudioPolicyInterfaceImpl.cpp

uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
{
    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
    return 0;}if (mAudioPolicyManager == NULL) {
    return 0;}return mAudioPolicyManager->getStrategyForStream(stream);
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
uint32_t AudioPolicyManager::getStrategyForStream(audio_stream_type_t stream) {
    return (uint32_t)getStrategy(stream);
}

  
  • 1
  • 2
  • 3
routing_strategy AudioPolicyManager::getStrategy(audio_stream_type_t stream) const
{
    ALOG_ASSERT(stream != AUDIO_STREAM_PATCH,"getStrategy() called for AUDIO_STREAM_PATCH");return mEngine->getStrategyForStream(stream);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在文件 frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.h 中 AudioPolicyManagerInterface *mEngine; 位于frameworks\av\services\audiopolicy\engine\interface\AudioPolicyManagerInterface.h,在frameworks\av\services\audiopolicy\enginedefault\src\Engine.h文件中被实现如下

  /// Interface membersclass ManagerInterfaceImpl : public AudioPolicyManagerInterface{
    public:explicit ManagerInterfaceImpl(Engine *policyEngine): mPolicyEngine(policyEngine) {
    }
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>virtual routing_strategy <span class="token function">getStrategyForStream</span><span class="token punctuation">(</span>audio_stream_type_t stream<span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">return</span> mPolicyEngine<span class="token operator">-&gt;</span><span class="token function">getStrategyForStream</span><span class="token punctuation">(</span>stream<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
private<span class="token punctuation">:</span>Engine <span class="token operator">*</span>mPolicyEngine<span class="token punctuation">;</span>
<span class="token punctuation">}</span> mManagerInterface<span class="token punctuation">;</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

最终将调用Engine.cpp的getStrategyForStream查询音频路由策略

routing_strategy Engine::getStrategyForStream(audio_stream_type_t stream)
{
    // stream to strategy mappingswitch (stream) {
    case AUDIO_STREAM_VOICE_CALL:case AUDIO_STREAM_BLUETOOTH_SCO:return STRATEGY_PHONE;case AUDIO_STREAM_RING:case AUDIO_STREAM_ALARM:return STRATEGY_SONIFICATION;case AUDIO_STREAM_NOTIFICATION:return STRATEGY_SONIFICATION_RESPECTFUL;case AUDIO_STREAM_DTMF:return STRATEGY_DTMF;default:ALOGE("unknown stream type %d", stream);case AUDIO_STREAM_SYSTEM:// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs// while key clicks are played produces a poor resultcase AUDIO_STREAM_MUSIC:return STRATEGY_MEDIA;case AUDIO_STREAM_ENFORCED_AUDIBLE:return STRATEGY_ENFORCED_AUDIBLE;case AUDIO_STREAM_TTS:return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;case AUDIO_STREAM_ACCESSIBILITY:return STRATEGY_ACCESSIBILITY;case AUDIO_STREAM_REROUTING:return STRATEGY_REROUTING;}
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

在AudioPolicyService.h文件中定义了如下函数,用来处理设备改变时调整路由策略

virtual status_t handleDeviceConfigChange(audio_devices_t device,const char *device_address,const char *device_name);

  
  • 1
  • 2
  • 3

至此音频代理路由部分暂到这,目前所看到的只是一小部分,随着Android系统的日益复杂,Audio会变得越来越庞大;
不过万变不离其宗,只要大体架构上不做大改动,也是很容易分析的,下一篇我们来看Audio系统的硬件抽象层。

        </div><link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-258a4616f7.css" rel="stylesheet"></div>
</article>

Android8.0 Audio系统之AudioPolicy

这里写图片描述

void AudioPolicyService::onFirstRef()
{
    {
    ......// class AudioPolicyClient : public AudioPolicyClientInterfacemAudioPolicyClient = new AudioPolicyClient(this);mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient); //创建Audio管理}
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

头文件 AudioPolicyClientInterface 位于 AudioPolicyInterface.h文件中


extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
    return new AudioPolicyManager(clientInterface);
}

extern “C” void destroyAudioPolicyManager(AudioPolicyInterface *interface)
{
delete interface;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

对于AudioPolicyClientImpl.cpp实现了 AudioPolicyClient,直接与AudioFlinger交互。对于AudioPolicyIntefaceImpl实现了AudioPolicyInterface直接与AudioPolicyManager交互,

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface):
#ifdef AUDIO_POLICY_TESTThread(false),
#endif //AUDIO_POLICY_TESTmLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),mA2dpSuspended(false),mAudioPortGeneration(1),mBeaconMuteRefCount(0),mBeaconPlayingRefCount(0),mBeaconMuted(false),mTtsOutputAvailable(false),mMasterMono(false),mMusicEffectOutput(AUDIO_IO_HANDLE_NONE)
{
    mpClientInterface = clientInterface;bool speakerDrcEnabled = false;//解析 xml Audio策略,路由
#ifdef USE_XML_AUDIO_POLICY_CONFmVolumeCurves = new VolumeCurvesCollection();AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,mDefaultOutputDevice, speakerDrcEnabled,static_cast<VolumeCurvesCollection *>(mVolumeCurves));if (deserializeAudioPolicyXmlConfig(config) != NO_ERROR) {
    
#elsemVolumeCurves = new StreamDescriptorCollection();AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,mDefaultOutputDevice, speakerDrcEnabled);if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&(ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
    
#endifALOGE("could not load audio policy configuration file, setting defaults");config.setDefault();}// must be done after reading the policy (since conditionned by Speaker Drc Enabling)mVolumeCurves->initializeVolumeCurves(speakerDrcEnabled);
<span class="token comment">// Once policy config has been parsed, retrieve an instance of the engine and initialize it</span>
<span class="token comment">//代理引擎</span>
audio_policy<span class="token punctuation">:</span><span class="token punctuation">:</span>EngineInstance <span class="token operator">*</span>engineInstance <span class="token operator">=</span> audio_policy<span class="token punctuation">:</span><span class="token punctuation">:</span>EngineInstance<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>engineInstance<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGE</span><span class="token punctuation">(</span><span class="token string">"%s:  Could not get an instance of policy engine"</span><span class="token punctuation">,</span> __FUNCTION__<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Retrieve the Policy Manager Interface</span>
mEngine <span class="token operator">=</span> engineInstance<span class="token operator">-&gt;</span>queryInterface<span class="token operator">&lt;</span>AudioPolicyManagerInterface<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//获取引擎</span>
mEngine<span class="token operator">-&gt;</span><span class="token function">setObserver</span><span class="token punctuation">(</span>this<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//设为观察者</span>
status_t status <span class="token operator">=</span> mEngine<span class="token operator">-&gt;</span><span class="token function">initCheck</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//初始</span>
<span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> status<span class="token punctuation">;</span>
<span class="token comment">// mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices</span>
<span class="token comment">// open all output streams needed to access attached devices</span>
audio_devices_t outputDeviceTypes <span class="token operator">=</span> mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">types</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
audio_devices_t inputDeviceTypes <span class="token operator">=</span> mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">types</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> <span class="token operator">~</span>AUDIO_DEVICE_BIT_IN<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> mHwModules<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//调用ClientInterface加载Audio模块,ClientInterface将调用AudioFlinger的loadHwModule</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mHandle <span class="token operator">=</span> mpClientInterface<span class="token operator">-&gt;</span><span class="token function">loadHwModule</span><span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mHandle <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"could not open HW module %s"</span><span class="token punctuation">,</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">//查找输出模块设备</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mOutputProfiles<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">const</span> sp<span class="token operator">&lt;</span>IOProfile<span class="token operator">&gt;</span> outProfile <span class="token operator">=</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mOutputProfiles<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>outProfile<span class="token operator">-&gt;</span><span class="token function">hasSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"Output profile contains no device on module %s"</span><span class="token punctuation">,</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> AUDIO_OUTPUT_FLAG_TTS<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>mTtsOutputAvailable <span class="token operator">=</span> true<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> AUDIO_OUTPUT_FLAG_DIRECT<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span>audio_devices_t profileType <span class="token operator">=</span> outProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDevicesType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>profileType <span class="token operator">&amp;</span> mDefaultOutputDevice<span class="token operator">-&gt;</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> AUDIO_DEVICE_NONE<span class="token punctuation">)</span> <span class="token punctuation">{</span>profileType <span class="token operator">=</span> mDefaultOutputDevice<span class="token operator">-&gt;</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>profileType <span class="token operator">=</span> outProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDeviceForType</span><span class="token punctuation">(</span>outputDeviceTypes<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>profileType <span class="token operator">&amp;</span> outputDeviceTypes<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span>sp<span class="token operator">&lt;</span>SwAudioOutputDescriptor<span class="token operator">&gt;</span> outputDesc <span class="token operator">=</span> new <span class="token function">SwAudioOutputDescriptor</span><span class="token punctuation">(</span>outProfile<span class="token punctuation">,</span>mpClientInterface<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> DeviceVector <span class="token operator">&amp;</span>supportedDevices <span class="token operator">=</span> outProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> DeviceVector <span class="token operator">&amp;</span>devicesForType <span class="token operator">=</span> supportedDevices<span class="token punctuation">.</span><span class="token function">getDevicesFromType</span><span class="token punctuation">(</span>profileType<span class="token punctuation">)</span><span class="token punctuation">;</span>String8 address <span class="token operator">=</span> devicesForType<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">?</span> devicesForType<span class="token punctuation">.</span><span class="token function">itemAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span>mAddress<span class="token punctuation">:</span> <span class="token function">String8</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>outputDesc<span class="token operator">-&gt;</span>mDevice <span class="token operator">=</span> profileType<span class="token punctuation">;</span>audio_config_t config <span class="token operator">=</span> AUDIO_CONFIG_INITIALIZER<span class="token punctuation">;</span>config<span class="token punctuation">.</span>sample_rate <span class="token operator">=</span> outputDesc<span class="token operator">-&gt;</span>mSamplingRate<span class="token punctuation">;</span>config<span class="token punctuation">.</span>channel_mask <span class="token operator">=</span> outputDesc<span class="token operator">-&gt;</span>mChannelMask<span class="token punctuation">;</span>config<span class="token punctuation">.</span>format <span class="token operator">=</span> outputDesc<span class="token operator">-&gt;</span>mFormat<span class="token punctuation">;</span>audio_io_handle_t output <span class="token operator">=</span> AUDIO_IO_HANDLE_NONE<span class="token punctuation">;</span><span class="token comment">//熟悉的openOutput</span>status_t status <span class="token operator">=</span> mpClientInterface<span class="token operator">-&gt;</span><span class="token function">openOutput</span><span class="token punctuation">(</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getModuleHandle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token operator">&amp;</span>output<span class="token punctuation">,</span><span class="token operator">&amp;</span>config<span class="token punctuation">,</span><span class="token operator">&amp;</span>outputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>address<span class="token punctuation">,</span><span class="token operator">&amp;</span>outputDesc<span class="token operator">-&gt;</span>mLatency<span class="token punctuation">,</span>outputDesc<span class="token operator">-&gt;</span>mFlags<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>status <span class="token operator">!=</span> NO_ERROR<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"Cannot open output stream for device %08x on hw module %s"</span><span class="token punctuation">,</span>outputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>outputDesc<span class="token operator">-&gt;</span>mSamplingRate <span class="token operator">=</span> config<span class="token punctuation">.</span>sample_rate<span class="token punctuation">;</span>outputDesc<span class="token operator">-&gt;</span>mChannelMask <span class="token operator">=</span> config<span class="token punctuation">.</span>channel_mask<span class="token punctuation">;</span>outputDesc<span class="token operator">-&gt;</span>mFormat <span class="token operator">=</span> config<span class="token punctuation">.</span>format<span class="token punctuation">;</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t k <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> k  <span class="token operator">&lt;</span> supportedDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> k<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>ssize_t index <span class="token operator">=</span> mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>supportedDevices<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// give a valid ID to an attached device once confirmed it is reachable</span><span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&gt;=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>mAvailableOutputDevices<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>mAvailableOutputDevices<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">attach</span><span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">if</span> <span class="token punctuation">(</span>mPrimaryOutput <span class="token operator">==</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span>outProfile<span class="token operator">-&gt;</span><span class="token function">getFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> AUDIO_OUTPUT_FLAG_PRIMARY<span class="token punctuation">)</span> <span class="token punctuation">{</span>mPrimaryOutput <span class="token operator">=</span> outputDesc<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token function">addOutput</span><span class="token punctuation">(</span>output<span class="token punctuation">,</span> outputDesc<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">setOutputDevice</span><span class="token punctuation">(</span>outputDesc<span class="token punctuation">,</span>outputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>true<span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token constant">NULL</span><span class="token punctuation">,</span>address<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">//遍历输入Audio设备</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mInputProfiles<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">const</span> sp<span class="token operator">&lt;</span>IOProfile<span class="token operator">&gt;</span> inProfile <span class="token operator">=</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span>mInputProfiles<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>inProfile<span class="token operator">-&gt;</span><span class="token function">hasSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">ALOGW</span><span class="token punctuation">(</span><span class="token string">"Input profile contains no device on module %s"</span><span class="token punctuation">,</span> mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// chose first device present in profile's SupportedDevices also part of</span><span class="token comment">// inputDeviceTypes</span>audio_devices_t profileType <span class="token operator">=</span> inProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDeviceForType</span><span class="token punctuation">(</span>inputDeviceTypes<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>profileType <span class="token operator">&amp;</span> inputDeviceTypes<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span>sp<span class="token operator">&lt;</span>AudioInputDescriptor<span class="token operator">&gt;</span> inputDesc <span class="token operator">=</span>new <span class="token function">AudioInputDescriptor</span><span class="token punctuation">(</span>inProfile<span class="token punctuation">)</span><span class="token punctuation">;</span>inputDesc<span class="token operator">-&gt;</span>mDevice <span class="token operator">=</span> profileType<span class="token punctuation">;</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>audio_config_t config <span class="token operator">=</span> AUDIO_CONFIG_INITIALIZER<span class="token punctuation">;</span>config<span class="token punctuation">.</span>sample_rate <span class="token operator">=</span> inputDesc<span class="token operator">-&gt;</span>mSamplingRate<span class="token punctuation">;</span>config<span class="token punctuation">.</span>channel_mask <span class="token operator">=</span> inputDesc<span class="token operator">-&gt;</span>mChannelMask<span class="token punctuation">;</span>config<span class="token punctuation">.</span>format <span class="token operator">=</span> inputDesc<span class="token operator">-&gt;</span>mFormat<span class="token punctuation">;</span>audio_io_handle_t input <span class="token operator">=</span> AUDIO_IO_HANDLE_NONE<span class="token punctuation">;</span>status_t status <span class="token operator">=</span> mpClientInterface<span class="token operator">-&gt;</span><span class="token function">openInput</span><span class="token punctuation">(</span>inProfile<span class="token operator">-&gt;</span><span class="token function">getModuleHandle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token operator">&amp;</span>input<span class="token punctuation">,</span><span class="token operator">&amp;</span>config<span class="token punctuation">,</span><span class="token operator">&amp;</span>inputDesc<span class="token operator">-&gt;</span>mDevice<span class="token punctuation">,</span>address<span class="token punctuation">,</span>AUDIO_SOURCE_MIC<span class="token punctuation">,</span>AUDIO_INPUT_FLAG_NONE<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>status <span class="token operator">==</span> NO_ERROR<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">const</span> DeviceVector <span class="token operator">&amp;</span>supportedDevices <span class="token operator">=</span> inProfile<span class="token operator">-&gt;</span><span class="token function">getSupportedDevices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">for</span> <span class="token punctuation">(</span>size_t k <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> k  <span class="token operator">&lt;</span> supportedDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> k<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>ssize_t index <span class="token operator">=</span>  mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>supportedDevices<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// give a valid ID to an attached device once confirmed it is reachable</span><span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&gt;=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>sp<span class="token operator">&lt;</span>DeviceDescriptor<span class="token operator">&gt;</span> devDesc <span class="token operator">=</span> mAvailableInputDevices<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>devDesc<span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>devDesc<span class="token operator">-&gt;</span><span class="token function">attach</span><span class="token punctuation">(</span>mHwModules<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>devDesc<span class="token operator">-&gt;</span><span class="token function">importAudioPort</span><span class="token punctuation">(</span>inProfile<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span>mpClientInterface<span class="token operator">-&gt;</span><span class="token function">closeInput</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// make sure all attached devices have been allocated a unique ID</span>
<span class="token comment">//遍历输入输出设备,由路由引擎设置各设备的连接状态</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i  <span class="token operator">&lt;</span> mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mAvailableOutputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>mAvailableOutputDevices<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>mAvailableOutputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// The device is now validated and can be appended to the available devices of the engine</span>mEngine<span class="token operator">-&gt;</span><span class="token function">setDeviceConnectionState</span><span class="token punctuation">(</span>mAvailableOutputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span>AUDIO_POLICY_DEVICE_STATE_AVAILABLE<span class="token punctuation">)</span><span class="token punctuation">;</span>i<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i  <span class="token operator">&lt;</span> mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mAvailableInputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-&gt;</span><span class="token function">isAttached</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">;</span>mAvailableInputDevices<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>mAvailableInputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// The device is now validated and can be appended to the available devices of the engine</span>mEngine<span class="token operator">-&gt;</span><span class="token function">setDeviceConnectionState</span><span class="token punctuation">(</span>mAvailableInputDevices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span>AUDIO_POLICY_DEVICE_STATE_AVAILABLE<span class="token punctuation">)</span><span class="token punctuation">;</span>i<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token function">updateDevicesAndOutputs</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212

可以看到AudioPolicyManager通过解析Audio配置文件,加载各输入输出音频Module,然后遍历各输入输出设备,找出稳定的设备后,由路由引擎设置各设备的连接状态。在分析AudioFlinger的时候走过 mpClientInterface->openOutput()函数

sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(.....)
{
    //找到Device, 这个函数很重要,稍后分析AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);//音频流输出到硬件设备AudioStreamOut *outputStream = NULL;status_t status = outHwDev->openOutputStream(&outputStream,*output,devices,flags,config,address.string());
mHardwareStatus <span class="token operator">=</span> AUDIO_HW_IDLE<span class="token punctuation">;</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在 createTrack_l()的时候,会去根据流类型来获取路由策略

    uint32_t strategy = AudioSystem::getStrategyForStream(streamType);for (size_t i = 0; i < mTracks.size(); ++i) {
    sp<Track> t = mTracks[i];if (t != 0 && t->isExternalTrack()) {
    //获取路由策略uint32_t actual = AudioSystem::getStrategyForStream(t->streamType());if (sessionId == t->sessionId() && strategy != actual) {
    ALOGE("createTrack_l() mismatched strategy; expected %u but found %u",strategy, actual);lStatus = BAD_VALUE;goto Exit;}}}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

调用 Audio代理服务的 getStrategyForStream

uint32_t AudioSystem::getStrategyForStream(audio_stream_type_t stream)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();if (aps == 0) return 0;return aps->getStrategyForStream(stream);
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

具体的实现在AudioPolicyInterfaceImpl.cpp文件中
\frameworks\av\services\audiopolicy\service\AudioPolicyInterfaceImpl.cpp

uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
{
    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
    return 0;}if (mAudioPolicyManager == NULL) {
    return 0;}return mAudioPolicyManager->getStrategyForStream(stream);
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
uint32_t AudioPolicyManager::getStrategyForStream(audio_stream_type_t stream) {
    return (uint32_t)getStrategy(stream);
}

  
  • 1
  • 2
  • 3
routing_strategy AudioPolicyManager::getStrategy(audio_stream_type_t stream) const
{
    ALOG_ASSERT(stream != AUDIO_STREAM_PATCH,"getStrategy() called for AUDIO_STREAM_PATCH");return mEngine->getStrategyForStream(stream);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在文件 frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.h 中 AudioPolicyManagerInterface *mEngine; 位于frameworks\av\services\audiopolicy\engine\interface\AudioPolicyManagerInterface.h,在frameworks\av\services\audiopolicy\enginedefault\src\Engine.h文件中被实现如下

  /// Interface membersclass ManagerInterfaceImpl : public AudioPolicyManagerInterface{
    public:explicit ManagerInterfaceImpl(Engine *policyEngine): mPolicyEngine(policyEngine) {
    }
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>virtual routing_strategy <span class="token function">getStrategyForStream</span><span class="token punctuation">(</span>audio_stream_type_t stream<span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">return</span> mPolicyEngine<span class="token operator">-&gt;</span><span class="token function">getStrategyForStream</span><span class="token punctuation">(</span>stream<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
private<span class="token punctuation">:</span>Engine <span clas
  相关解决方案