Android : android 9.0 audio 接口分析

    <div id="post_detail">
<div class="post">
	<h2>
		<a id="cb_post_title_url" href="https://www.cnblogs.com/blogs-of-lxl/p/8656286.html">Android : android 8.0 audio 接口分析</a>
	</h2>
	<div id="cnblogs_post_body" class="blogpost-body" deep="3"><h4 id="1hidl-的概念" style="margin: 8px 0px 16px; padding: 0px; color: #4f4f4f; text-transform: none; line-height: 28px; text-indent: 0px; letter-spacing: normal; font-family: -apple-system, 'SF UI Text', Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif, SimHei, SimSun; font-size: 20px; font-style: normal; font-weight: bold; word-spacing: 0px; white-space: normal; box-sizing: border-box; orphans: 2; widows: 2; background-color: #ffffff; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><strong>1、HIDL 的概念</strong></h4>

  HIDL 读作 hide-l,全称是 Hardware Interface Definition Language。它在 Android Project Treble 中被起草,在 Android 8.0 中被全面使用,其诞生目的是使 Android 可以在不重新编译 HAL 的情况下对 Framework 进行 OTA 升级 
  使用 HIDL 描述的 HAL 描述文件替换旧的用头文件描述的 HAL 文件的过程称为 * HAL 的 binder 化(binderization)。所有运行 Android O 的设备都必须只支持 binder 化后的 HAL 模块。 
  已发布的 HIDL package包位于 Android 代码库的hardware/interfaces/vendor/<vendorName>目录下。使用 HDIL 描述的 HAL 接口存放在这些目录下的.hal文件中。比如我们可以在hardware/interfaces/audio/2.0/目录下找到部分 Audio HAL 描述文件,如下:

复制代码
Android.bp
Android.mk
IDevice.hal
IDevicesFactory.hal
IPrimaryDevice.hal
IStream.hal
IStreamIn.hal
IStreamOutCallback.hal
IStreamOut.hal
types.hal
复制代码

另外在frameworks/av/media/下多了个文件夹  libaudiohal :

复制代码
Android.mk                DeviceHalLocal.h             DevicesFactoryHalLocal.h  EffectHalHidl.h             EffectsFactoryHalLocal.h  StreamHalLocal.h
ConversionHelperHidl.cpp  DevicesFactoryHalHidl.cpp    EffectBufferHalHidl.cpp   EffectHalLocal.cpp          HalDeathHandlerHidl.cpp
ConversionHelperHidl.h    DevicesFactoryHalHidl.h      EffectBufferHalHidl.h     EffectHalLocal.h            include
DeviceHalHidl.cpp         DevicesFactoryHalHybrid.cpp  EffectBufferHalLocal.cpp  EffectsFactoryHalHidl.cpp   StreamHalHidl.cpp
DeviceHalHidl.h           DevicesFactoryHalHybrid.h    EffectBufferHalLocal.h    EffectsFactoryHalHidl.h     StreamHalHidl.h
DeviceHalLocal.cpp        DevicesFactoryHalLocal.cpp   EffectHalHidl.cpp         EffectsFactoryHalLocal.cpp  StreamHalLocal.cpp
复制代码

从文件名命名方式来看,一类是以Hidl结尾,一类是Local结尾,Local结尾的应该是兼容之前的方式,即谷歌在文档里描述的:

HIDL 旨在用于进程间通信 (IPC)。进程之间的通信经过 Binder 化。对于必须与进程相关联的代码库,还可以使用直通模式(在 Java 中不受支持):

  要将运行早期版本的 Android 的设备更新为使用 Android O,您可以将惯用的(和旧版)HAL 封装在一个新 HIDL 接口中,该接口将在绑定式模式和同进程(直通)模式提供 HAL。这种封装对于 HAL 和 Android 框架来说都是透明的。直通模式仅适用于 C++ 客户端和实现。运行早期版本的 Android 的设备没有用 Java 编写的 HAL,因此 Java HAL 自然而然经过 Binder 化。

直通式标头文件:

  编译 .hal 文件时,除了用于 Binder 通信的标头之外,hidl-gen 还会生成一个额外的直通标头文件 BsFoo.h;此标头定义了会被执行 dlopen 操作的函数。由于直通式 HAL 在它们被调用的同一进程中运行,因此在大多数情况下,直通方法由直接函数调用(同一线程)来调用。oneway 方法在各自的线程中运行,因为它们不需要等待 HAL 来处理它们(这意味着,在直通模式下使用 oneway 方法的所有 HAL 对于线程必须是安全的)。

  如果有一个 IFoo.halBsFoo.h 会封装 HIDL 生成的方法,以提供额外的功能(例如使 oneway 事务在其他线程中运行)。该文件类似于 BpFoo.h,不过,所需函数是直接调用的,并未使用 Binder 传递调用 IPC。未来,HAL 的实现可能提供多种实现结果,例如 FooFast HAL 和 FooAccurate HAL。在这种情况下,系统会针对每个额外的实现结果创建一个文件(例如 PTFooFast.cpp 和 PTFooAccurate.cpp)。

2、Audio Record 调用分析:

 (1) Java层调用AndroidSDK中的API实例化一个AudioRecord对象

  -》 \android-8.0.0_r4\frameworks\av\media\libaudioclient\AudioRecord.cpp  -》  AudioRecord::AudioRecord

 (2) 设置相应参数 

  -》 mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
                    notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
                    uid, pid, pAttributes);

 (3)打开录音接口

     -》 // create the IAudioRecord
        status_t status = openRecord_l(0 /*epoch*/, mOpPackageName);

 (4) 获取输入设备属性:

     status = AudioSystem::getInputForAttr(&mAttributes, &input,
                                        mSessionId,
                                        // FIXME compare to AudioTrack
                                        mClientPid,
                                        mClientUid,
                                        &config,
                                        mFlags, mSelectedDeviceId, &mPortId);

     其中是通过获取audio_policy_service建立binder接口:

     // establish binder interface to AudioPolicy service
     const sp<IAudioPolicyService> AudioSystem::get_audio_policy_service() 

 (5) 调用AudioPolicyManager的接口 : \android-8.0.0_r4\frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.cpp

   aps->getInputForAttr -》 AudioPolicyManager::getInputForAttr

 (6) 根据app传下的参数获取对应的设备类型:

  device = getDeviceAndMixForInputSource(inputSource, &policyMix); 

  -》Engine::getDeviceForInputSource      (\android-8.0.0_r4\frameworks\av\services\audiopolicy\enginedefault\src\Engine.cpp)

       一般录音软件是:AUDIO_SOURCE_MIC  ,google 语音引擎是:AUDIO_SOURCE_VOICE_RECOGNITION

   再根据当前系统支持的输入设备返回对应的录音设备:(默认的内置mic就是 AUDIO_DEVICE_IN_BUILTIN_MIC)

复制代码
 if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&
                availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) { device = AUDIO_DEVICE_IN_WIRED_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) { device = AUDIO_DEVICE_IN_USB_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) { device = AUDIO_DEVICE_IN_USB_DEVICE; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { device = AUDIO_DEVICE_IN_BUILTIN_MIC; }
复制代码

PS:通过 dumpsys media.audio_policy 指令查看当前系统所支持的设备模块及类型。

可通过\android-8.0.0_r4\frameworks\av\services\audiopolicy目录里面 audio_policy.conf或者audio_policy_configuration.xml配置设备加载,

使用.conf还是.xml取决于frameworks/av/services/audiopolicy/Android.mk 通过宏USE_XML_AUDIO_POLICY_CONF - 1 : 使用 .xml , 0: 使用 .conf。


  (7) 根据返回的device类型获取对应录音设备:

     *input = getInputForDevice(device, address, session, uid, inputSource,
                                 config->sample_rate, config->format, config->channel_mask, flags,
                                 policyMix);

 (8) 调用getInputProfile函数根据传进来的声音采样率、声音格式、通道掩码等参数与获得的设备支持的Input Profile比较返回一个与设备Profile匹配的IOProfile-》

     profile = getInputProfile(device, address,
                                      profileSamplingRate, profileFormat, profileChannelMask,
                                      profileFlags);

 (9) 根据返回的profile调用初始化时加载好的client接口:

复制代码
status_t status = mpClientInterface->openInput(profile->getModuleHandle(),
                                                   &input,
                                                   &config,
                                                   &device,
                                                   address,
                                                   halInputSource,
                                                   profileFlags);
复制代码

PS: mpClientInterface是由AudioPolicyService中加载对应模块传递过来:

复制代码
void AudioPolicyService::onFirstRef()
{
    {
        Mutex::Autolock _l(mLock);
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> start tone playback thread</span>
    mTonePlaybackThread = <span style="color: #0000ff;">new</span> AudioCommandThread(String8(<span style="color: #800000;">"</span><span style="color: #800000;">ApmTone</span><span style="color: #800000;">"</span>), <span style="color: #0000ff;">this</span><span style="color: #000000;">);
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> start audio commands thread</span>
    mAudioCommandThread = <span style="color: #0000ff;">new</span> AudioCommandThread(String8(<span style="color: #800000;">"</span><span style="color: #800000;">ApmAudio</span><span style="color: #800000;">"</span>), <span style="color: #0000ff;">this</span><span style="color: #000000;">);
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> start output activity command thread</span>
    mOutputCommandThread = <span style="color: #0000ff;">new</span> AudioCommandThread(String8(<span style="color: #800000;">"</span><span style="color: #800000;">ApmOutput</span><span style="color: #800000;">"</span>), <span style="color: #0000ff;">this</span><span style="color: #000000;">);

    mAudioPolicyClient </span>= <span style="color: #0000ff;">new</span> AudioPolicyClient(<span style="color: #0000ff;">this</span><span style="color: #000000;">);
    mAudioPolicyManager </span>=<span style="color: #000000;"> createAudioPolicyManager(mAudioPolicyClient); <span style="font-family: Courier New;">//对应的模块加载放在AudioPolicyManager的构造函数中</span>   
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> load audio processing modules</span>
sp&lt;AudioPolicyEffects&gt;audioPolicyEffects = <span style="color: #0000ff;">new</span><span style="color: #000000;"> AudioPolicyEffects();
{
    Mutex::Autolock _l(mLock);
    mAudioPolicyEffects </span>=<span style="color: #000000;"> audioPolicyEffects;
}

}

复制代码

猜你喜欢

转载自blog.csdn.net/zhengdongtao110/article/details/88973038