Android : android 8.0 audio 接口分析

1、HIDL 的概念

  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/目录下。使用 HDIL 描述的 HAL 接口存放在这些目录下的.hal文件中。比如我们可以在hardware/interfaces/audio/2.0/目录下找到部分 Audio HAL 描述文件,如下:

Android.bpAndroid.mkIDevice.halIDevicesFactory.halIPrimaryDevice.halIStream.halIStreamIn.halIStreamOutCallback.halIStreamOut.haltypes.hal

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

Android.mk                DeviceHalLocal.h             DevicesFactoryHalLocal.h  EffectHalHidl.h             EffectsFactoryHalLocal.h  StreamHalLocal.hConversionHelperHidl.cpp  DevicesFactoryHalHidl.cpp    EffectBufferHalHidl.cpp   EffectHalLocal.cpp          HalDeathHandlerHidl.cppConversionHelperHidl.h    DevicesFactoryHalHidl.h      EffectBufferHalHidl.h     EffectHalLocal.h            includeDeviceHalHidl.cpp         DevicesFactoryHalHybrid.cpp  EffectBufferHalLocal.cpp  EffectsFactoryHalHidl.cpp   StreamHalHidl.cppDeviceHalHidl.h           DevicesFactoryHalHybrid.h    EffectBufferHalLocal.h    EffectsFactoryHalHidl.h     StreamHalHidl.hDeviceHalLocal.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 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);
    // start tone playback thread    mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);    // start audio commands thread    mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);    // start output activity command thread    mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);    mAudioPolicyClient = new AudioPolicyClient(this);    mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient); //对应的模块加载放在AudioPolicyManager的构造函数中   }// load audio processing modulessp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();{    Mutex::Autolock _l(mLock);    mAudioPolicyEffects = audioPolicyEffects;}

}

更多相关文章

  1. Androidの自定义对话框AlertDialog(一)
  2. [Android分享] 如何解决Android(安卓)5.0中出现的警告:Service In
  3. Android基础--Fragment
  4. (Android)搭建NDK开发环境 (二)
  5. Android中字体的处理
  6. Mars Android视频教程完整版高清在线观看
  7. Android(安卓)UI学习 - Tab的学习和使用
  8. Android(安卓)Android(安卓)Studio 快捷键整理分享,IntelliJ IDE
  9. Rexsee API介绍:Android屏幕锁定Keyguard

随机推荐

  1. 在Android上本机运行的服务器
  2. 2020-04-01
  3. 如何申请Android MapView的apiKey
  4. Android Weekly Notes Issue #232
  5. Android开发中怎样调用系统Email发送邮件
  6. 用kotlin打印出漂亮的android日志(三)—
  7. android 修改窗体标题的字体式样和…
  8. Android(安卓)Matrix Riot (IM)SDK 集成专
  9. 实现Android简单动画旋转案例源码
  10. Android中通过xml给布局添加边框