首页 > 其他分享 >Android Audio模块 音量增益 framework到HAL 层加载流程

Android Audio模块 音量增益 framework到HAL 层加载流程

时间:2024-06-05 17:04:43浏览次数:12  
标签:HAL 标记 framework 音量 AudioPolicyService Android audio config port

目录

背景

在设备开机的过程中,需要设置用户关机前的音量,因此在开机时可获取当前音量值去设置某个端口的音量增益,来达到设备开机后的音量记忆。

概念

进入代码分析之前,重温一下平时设置的音量1-100和音量增益(Volume Gain)的关系,有助于更好理解Android音量设置原理。

平时在音频设备或软件中设置的音量(比如1-100的范围)通常是一个相对的量度,用于提供给用户一个直观的方式来控制音频输出的响度。这个音量设置并不直接对应于特定的分贝值,而是根据设备的硬件或软件配置来确定增益的大小。

以下是音量设置与增益关系的一般概念:

  1. 相对刻度
  • 音量滑块或旋钮上的1-100通常表示一个从非常安静到非常响亮的相对刻度。
  • 音量增益通常以分贝(dB)为单位进行度量,分贝是一个比例单位。具体的分贝值取决于系统的参考音量级别和增益范围。
  1. 线性关系
  • 在某些系统中,音量和增益可能呈线性关系,这意味着音量的每次增加或减少对应相同的分贝数。
  • 例如,音量每增加10,增益增加1 dB。
  1. 对数关系
  • 更常见的是,音量和增益之间存在对数关系,以模拟人耳对声音的感知。
  • 在对数刻度中,音量的增加不是均匀的,而是随着音量级别的增加而增加的。
  1. 系统校准
  • 音频系统通常会在校准过程中确定1-100音量级别与增益之间的确切映射。
  • 这涉及到设置参考音量(通常是0 dBFS,即满刻度信号)和最大音量对应的最大增益。
  1. 最大音量与增益
  • 最大音量(例如100)通常对应于系统能够安全输出的最大增益,而不会引起失真。
  • 这个最大增益可能是在特定音量级别下不会失真的最高分贝数。
  1. 最小音量与增益
  • 最小音量(例如1)则对应于系统可以输出的最小增益,仍然保持可听见的水平。
  • 这通常远高于0 dB SPL,因为人耳的听觉阈值非常低。
  1. 中间音量级别
  • 中间的音量级别(例如50)通常对应于系统增益的中间点,提供平衡的听感。
  1. 设备差异
  • 不同的音频设备和软件可能会有不同的音量和增益映射方式。
  1. 音量标准化
  • 有些系统可能会采用音量标准化技术,以确保不同音量级别下的音频输出保持一致的响度。

Android Audio调用流程(app-framework-HAL)

应用调用setStreamVolume函数设置音量后会调用mAudioManager.setAudioPortGain来设置硬件增益,达到设备开机后的音量增益记忆。
frameworks/base/services/core/java/com/android/server/tv/TvInputHardwareManager.java

@Override
public void setStreamVolume(float volume) throws RemoteException {
    synchronized (mImplLock) {
	if (mReleased) {
	    throw new IllegalStateException("Device already released.");
         }
	mSourceVolume = volume;
	updateAudioConfigLocked();
     }
}


private float getMediaStreamVolume() {
        return (float) mCurrentIndex / (float) mCurrentMaxIndex;
}
......
private void updateAudioConfigLocked() {
    float volume = mSourceVolume * getMediaStreamVolume();
    //转换应用层的音量为音量增益(单位db)
    gainValue += sourceGain.stepValue() * (int) (volume * steps + 0.5);
    ......
    // size of gain values is 1 in MODE_JOINT
    int[] gainValues = new int[] { gainValue };
    sourceGainConfig = sourceGain.buildConfig(AudioGain.MODE_JOINT,
    sourceGain.channelMask(), gainValues, 0);
    ......
    //调用audio硬件设置音量增益
    mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig);
}

frameworks/base/media/java/android/media/AudioManager.java

    /**
     * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
     * AudioGain.buildConfig()
     * @hide
     */
    public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
        if (port == null || gain == null) {
            return ERROR_BAD_VALUE;
        }
        //调用port对象的activeConfig()方法,获取当前活动的音频端口配置。
        AudioPortConfig activeConfig = port.activeConfig();
	//使用AudioPortConfig构造函数创建一个新的音频端口配置对象config。
        AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
                                        activeConfig.channelMask(), activeConfig.format(), gain);
	//设置config对象的mConfigMask字段为AudioPortConfig.GAIN。
	//这指定了配置掩码,表明只更改增益设置,而不是其他配置如采样率、声道掩码或格式。
        config.mConfigMask = AudioPortConfig.GAIN;
        //应用新的音频端口配置
        return AudioSystem.setAudioPortConfig(config);
    }

frameworks/base/media/java/android/media/AudioSystem.java

//由native 关键字可知使用了本地方法实现函数
public static native int setAudioPortConfig(AudioPortConfig config);

frameworks/base/core/jni/android_media_AudioSystem.cpp

{"setAudioPortConfig", "(Landroid/media/AudioPortConfig;)I",
          (void *)android_media_AudioSystem_setAudioPortConfig},

......
static jint
android_media_AudioSystem_setAudioPortConfig(JNIEnv *env, jobject clazz,
                                 jobject jAudioPortConfig)
{
    ALOGV("setAudioPortConfig");
    if (jAudioPortConfig == NULL) {
        return AUDIO_JAVA_BAD_VALUE;
    }
    //确认jAudioPortConfig是一个正确的AudioPortConfig类的实例,如果不是,返回错误码
    if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
        return AUDIO_JAVA_BAD_VALUE;
    }
    //定义一个本地audio_port_config结构体实例,用于存储转换后的本地音频端口配置。
    struct audio_port_config nAudioPortConfig = {};
    //调用convertAudioPortConfigToNative函数,将Java层的AudioPortConfig对象转换为本地的audio_port_config结构体。
    //返回值jStatus用于检查转换是否成功。
    jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig, true);
    if (jStatus != AUDIO_JAVA_SUCCESS) {
        return jStatus;
    }
    //调用AudioSystem::setAudioPortConfig方法,传入本地音频端口配置,以应用配置。
    //标记0
    status_t status = AudioSystem::setAudioPortConfig(&nAudioPortConfig);
    ALOGV("AudioSystem::setAudioPortConfig() returned %d", status);
    //将本地状态码status转换为Java可以理解的状态码jStatus。
    //返回Java层,这样Java层就可以知道操作是否成功或出现了什么错误。
    jStatus = nativeToJavaStatus(status);
    return jStatus;
}

标记0 libaudioclient

frameworks/av/media/libaudioclient/AudioSystem.cpp

status_t AudioSystem::setAudioPortConfig(const struct audio_port_config* config) {
    if (config == nullptr) {
        return BAD_VALUE;
    }
    //获取音频策略服务的引用(IAudioPolicyService是一个接口,用于与音频策略服务进行交互) 
    //标记1 
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    if (aps == 0) return PERMISSION_DENIED;
    //将传入的audio_port_config结构转换为AIDL(Android Interface Definition Language)格式的AudioPortConfigFw对象。
    //VALUE_OR_RETURN_STATUS是一个宏或模板函数,用于检查转换操作是否成功,并可能返回一个错误状态码。
    media::AudioPortConfigFw configAidl = VALUE_OR_RETURN_STATUS(
            legacy2aidl_audio_port_config_AudioPortConfigFw(*config));
    //标记2
    return statusTFromBinderStatus(aps->setAudioPortConfig(configAidl));
}


标记1 libaudioclient :aps变量赋值

aps的赋值为AudioPolicyService实例

frameworks/av/media/libaudioclient/AudioSystem.cpp
// establish binder interface to AudioPolicyService
const sp<IAudioPolicyService> AudioSystem::get_audio_policy_service() {
    sp<IAudioPolicyService> ap;
    sp<AudioPolicyServiceClient> apc;
    {
        //创建一个自动锁_l,它在作用域开始时自动加锁,并在作用域结束时自动解锁,用于保护临界区代码。
	//gLockAPS是全局的互斥锁,用于同步对共享资源的访问。
        Mutex::Autolock _l(gLockAPS);
	//检查gAudioPolicyService是否已初始化。如果不为null,表示服务连接已建立,可直接返回服务接口。
        if (gAudioPolicyService == 0) {
	    //如果服务尚未连接,它会使用defaultServiceManager()获取系统服务管理器的句柄,并尝试检索"media.audio_policy"服务。如服务未立即可用,它将每半秒重试一次,直到服务出现。
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder;
            do {
		//标记1.1
                binder = sm->getService(String16("media.audio_policy"));
                if (binder != 0)
                    break;
                ALOGW("AudioPolicyService not published, waiting...");
                usleep(500000); // 0.5 s
            } while (true);
            if (gAudioPolicyServiceClient == NULL) {
		//创建AudioPolicyServiceClient客户端,用于接收来自AudioPolicyService的回调通知
                gAudioPolicyServiceClient = new AudioPolicyServiceClient();
            }
            binder->linkToDeath(gAudioPolicyServiceClient);
	    //将binder转换为IAudioPolicyService接口,以便通过定义好的接口与服务交互。
            gAudioPolicyService = interface_cast<IAudioPolicyService>(binder);
            LOG_ALWAYS_FATAL_IF(gAudioPolicyService == 0);
            apc = gAudioPolicyServiceClient;
            // Make sure callbacks can be received by gAudioPolicyServiceClient
            ProcessState::self()->startThreadPool();
        }
        ap = gAudioPolicyService;
    }
    //返回IAudioPolicyService接口指针,使得调用者能够与音频策略服务进行互动。
    return ap;
}
标记1.1 binder变量赋值

binder 变量获取的是media.audio_policy 服务

和media.audio_flinger 服务不一样

在ServiceManager进程中添加media.audio_flinger服务

frameworks/av/services/audioflinger/AudioFlinger.cpp
void AudioFlinger::instantiate() {
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME),
                   new AudioFlingerServerAdapter(new AudioFlinger()), false,
                   IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
}

frameworks/av/media/libaudioclient/include/media/IAudioFlinger.h
class IAudioFlinger : public virtual RefBase {
    static constexpr char DEFAULT_SERVICE_NAME[] = "media.audio_flinger";
}

标记2 audiopolicy

在AudioPolicyService.cpp中没有setAudioPortConfig函数的具体实现,需要查找哪些文件包含了AudioPolicyService.h,并实现了setAudioPortConfig函数。查看发现AudioPolicyInterfaceImpl.cpp(实现的是 StatusAudioPolicyService::setAudioPortConfig(constmedia::AudioPortConfigFw&configAidl))、AudioPolicyClientImpl.cpp(实现的是 AudioPolicyService::AudioPolicyClient::setAudioPortConfig),因此查看AudioPolicyInterfaceImpl.cpp中的实现,由此可以AudioPolicyInterfaceImpl实现了AudioPolicyService.中的一部分函数

frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp //实现了AudioPolicyService.中的一部分函数
#include "AudioPolicyService.h"
Status AudioPolicyService::setAudioPortConfig(const media::AudioPortConfigFw& configAidl)
{
    audio_port_config config = VALUE_OR_RETURN_BINDER_STATUS(
            aidl2legacy_AudioPortConfigFw_audio_port_config(configAidl));
    RETURN_IF_BINDER_ERROR(
            binderStatusFromStatusT(AudioValidator::validateAudioPortConfig(config)));
    ......
    //标记4 mAudioPolicyManager的赋值 //标记5
    return binderStatusFromStatusT(mAudioPolicyManager->setAudioPortConfig(&config));
}


标记4 audiopolicy:mAudioPolicyManager变量赋值

mAudioPolicyManager的赋值为AudioPolicyManager

frameworks/av/services/audiopolicy/service/AudioPolicyService.h
AudioPolicyInterface *mAudioPolicyManager;

frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
void AudioPolicyService::onFirstRef()
{
    ......
    {
	......
        mAudioPolicyClient = new AudioPolicyClient(this);
        loadAudioPolicyManager();
	//标记4.1 传入AudioPolicyClient实例
        mAudioPolicyManager = mCreateAudioPolicyManager(mAudioPolicyClient);
    }
    ......
}

static const char kAudioPolicyManagerCustomPath[] = "libaudiopolicymanagercustom.so";

void AudioPolicyService::loadAudioPolicyManager()
{
    //使用dlopen函数打开一个动态链接库(.so文件),这里指定了库文件的路径kAudioPolicyManagerCustomPath和加载时的属 性RTLD_NOW(立即加载)。mLibraryHandle是AudioPolicyService类中的成员变量,用于存储打开的动态链接库的句柄
    mLibraryHandle = dlopen(kAudioPolicyManagerCustomPath, RTLD_NOW);
    if (mLibraryHandle != nullptr) {
        ALOGI("%s loading %s", __func__, kAudioPolicyManagerCustomPath);
        mCreateAudioPolicyManager = reinterpret_cast<CreateAudioPolicyManagerInstance>
                                            (dlsym(mLibraryHandle, "createAudioPolicyManager"));
    }
}

AudioPolicyService::AudioPolicyService()
    //使用列表初始化(冒号:)来初始化继承自基类的成员。
    //这里BnAudioPolicyService()是基类构造函数的调用,
    //表示AudioPolicyService继承自BnAudioPolicyService。
    : BnAudioPolicyService(),
      ......
      //mCreateAudioPolicyManager是类成员变量,这里被初始化为createAudioPolicyManager,
      //它是一个函数或函数指针,用于创建音频策略管理器实例。
      mCreateAudioPolicyManager(createAudioPolicyManager),
      ......
}

//标记4.1传入参数new AudioPolicyClient的地址
static AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
    auto config = AudioPolicyConfig::loadFromApmXmlConfigWithFallback();  // This can't fail.
    //此处就是标记4中mAudioPolicyManager的地址指向
    AudioPolicyManager *apm = new AudioPolicyManager(
            config, loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix()),
            clientInterface);
    status_t status = apm->initialize();
    ......
    return apm;
}

标记5 audiopolicy

frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.h
//AudioPolicyManager 继承 AudioPolicyInterface
class AudioPolicyManager : public AudioPolicyInterface, public AudioPolicyManagerObserver
{
    virtual status_t setAudioPortConfig(const struct audio_port_config *config);

    AudioPolicyClientInterface *mpClientInterface;
}


frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::setAudioPortConfig(const struct audio_port_config *config)
{
    sp<AudioPortConfig> audioPortConfig;
    ......
    struct audio_port_config backupConfig = {};
    status_t status = audioPortConfig->applyAudioPortConfig(config, &backupConfig);
    if (status == NO_ERROR) {
        struct audio_port_config newConfig = {};
        audioPortConfig->toAudioPortConfig(&newConfig, config);
        //标记6 mpClientInterface赋值  //标记7
        status = mpClientInterface->setAudioPortConfig(&newConfig, 0);
    }
    return status;
}

标记6 audiopolicy:mpClientInterface变量赋值

mpClientInterface变量的赋值AudioPolicyClient实例:

frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
AudioPolicyManager::AudioPolicyManager(const sp<const AudioPolicyConfig>& config,
                                       EngineInstance&& engine,
                                       AudioPolicyClientInterface *clientInterface)
    :
    mUidCached(AID_AUDIOSERVER), // no need to call getuid(), there's only one of us running.
    mConfig(config),
    //在此处赋值,clientInterface是函数指针,在标记4.1中new AudioPolicyManager实例化传入了clientInterface参数new AudioPolicyClient的地址
    mpClientInterface(clientInterface),
    mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
{
}

也就是下面函数
frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
static AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
    auto config = AudioPolicyConfig::loadFromApmXmlConfigWithFallback();  // This can't fail.
    AudioPolicyManager *apm = new AudioPolicyManager(
            config, loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix()),
            clientInterface);
    status_t status = apm->initialize();
    ......
    return apm;
}

AudioPolicyService::AudioPolicyService()
    //使用列表初始化(冒号:)来初始化继承自基类的成员。
    //这里BnAudioPolicyService()是基类构造函数的调用,
    //表示AudioPolicyService继承自BnAudioPolicyService。
    : BnAudioPolicyService(),
      //mCreateAudioPolicyManager是类成员变量,这里被初始化为createAudioPolicyManager,
      //它是一个函数或函数指针,用于创建音频策略管理器实例。
      mCreateAudioPolicyManager(createAudioPolicyManager),
}

void AudioPolicyService::onFirstRef()
{
    {
        mAudioPolicyClient = new AudioPolicyClient(this);

        loadAudioPolicyManager();
	//传入AudioPolicyClient实例
        mAudioPolicyManager = mCreateAudioPolicyManager(mAudioPolicyClient);
    }

static const char kAudioPolicyManagerCustomPath[] = "libaudiopolicymanagercustom.so";

void AudioPolicyService::loadAudioPolicyManager()
{
    //使用dlopen函数打开一个动态链接库(.so文件),这里指定了库文件的路径kAudioPolicyManagerCustomPath和加载时的属 性RTLD_NOW(立即加载)。mLibraryHandle是AudioPolicyService类中的成员变量,用于存储打开的动态链接库的句柄
    mLibraryHandle = dlopen(kAudioPolicyManagerCustomPath, RTLD_NOW);
    if (mLibraryHandle != nullptr) {
        ALOGI("%s loading %s", __func__, kAudioPolicyManagerCustomPath);
        mCreateAudioPolicyManager = reinterpret_cast<CreateAudioPolicyManagerInstance>
                                            (dlsym(mLibraryHandle, "createAudioPolicyManager"));
    }
}

标记7 audiopolicy

AudioPolicyClient继承AudioPolicyClientInterface

frameworks/av/services/audiopolicy/service/AudioPolicyService.h
class AudioPolicyClient : public AudioPolicyClientInterface{
        /* Set audio port configuration */
        virtual status_t setAudioPortConfig(const struct audio_port_config *config, int delayMs);
}

搜索AudioPolicyClient::setAudioPortConfig函数,发现函数实现在下面路径
frameworks/av/services/audiopolicy/service/AudioPolicyClientImpl.cpp
status_t AudioPolicyService::AudioPolicyClient::setAudioPortConfig(
                                                        const struct audio_port_config *config,
                                                        int delayMs)
{
    return mAudioPolicyService->clientSetAudioPortConfig(config, delayMs);
}

frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
status_t AudioPolicyService::clientSetAudioPortConfig(const struct audio_port_config *config,
                                                      int delayMs)
{
    return mAudioCommandThread->setAudioPortConfigCommand(config, delayMs);
}
status_t AudioPolicyService::AudioCommandThread::setAudioPortConfigCommand(
                                            const struct audio_port_config *config, int delayMs)
{
    sp<AudioCommand> command = new AudioCommand();
    //设置需要传入队列的命令
    command->mCommand = SET_AUDIOPORT_CONFIG;
    SetAudioPortConfigData *data = new SetAudioPortConfigData();
    data->mConfig = *config;
    command->mParam = data;
    command->mWaitStatus = true;
    ALOGV("AudioCommandThread() adding set port config delay %d", delayMs);
    //将一个音频命令对象按照指定的延迟时间加入到执行队列,并等待命令执行完成或超时
    //此处发送 SET_AUDIOPORT_CONFIG 音频命令到队列
    //标记8
    return sendCommand(command, delayMs);
}
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
    {
        Mutex::Autolock _l(mLock);
        //调用insertCommand_l成员函数,将传入的command和delayMs插入到线程的命令队列中。
	//insertCommand_l是一个私有成员函数,负责将命令插入到一个按时间排序的队列中。
        insertCommand_l(command, delayMs);
	//mWaitWorkCV是条件变量,用于在有工作可做时通知等待的线程。
	//signal函数唤醒等待条件变量的线程,告知有新的命令可以处理。
        mWaitWorkCV.signal();
    }
    return command->mStatus;
}

标记8 audiopolicy

将一个音频命令对象加入到执行队列等待命令执行完成或超时。因此可以搜索命令SET_AUDIOPORT_CONFIG,看在什么位置进行了处理。

frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
bool AudioPolicyService::AudioCommandThread::threadLoop()
{
switch (command->mCommand) {
......
    case SET_AUDIOPORT_CONFIG: {
                    SetAudioPortConfigData *data = (SetAudioPortConfigData *)command->mParam.get();
                    ALOGV("AudioCommandThread() processing set port config");
		    //标记9 af获取到AudioFlinger服务
                    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
                    if (af == 0) {
                        command->mStatus = PERMISSION_DENIED;
                    } else {
                        mLock.unlock();
			//标记10
                        command->mStatus = af->setAudioPortConfig(&data->mConfig);
                        mLock.lock();
                    }
                    } break;
......

标记10 audioflinger

因此在AudioFlinger.cpp文件中调用setAudioPortConfig

frameworks/av/services/audioflinger/AudioFlinger.cpp
status_t AudioFlinger::setAudioPortConfig(const struct audio_port_config *config)
{
    ......
    audio_module_handle_t module;
    if (config->type == AUDIO_PORT_TYPE_DEVICE) {
        module = config->ext.device.hw_module;
    } else {
        module = config->ext.mix.hw_module;
    }
    ......
    AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(index);
    //使用HAL间接操作audio硬件
    //标记11 hwDevice赋值 //标记13
    return audioHwDevice->hwDevice()->setAudioPortConfig(config);
}

frameworks/av/services/audioflinger/AudioHwDevice.h
sp<DeviceHalInterface> hwDevice() const { return mHwDevice; }

标记11 audioflinger:hwDevice变量赋值

hwDevice类型为sp <DeviceHalInterface>,在标记12中查询到hwDevice最终赋值为DeviceHalLocal的实例地址

frameworks/av/services/audioflinger/AudioHwDevice.h
sp<DeviceHalInterface> hwDevice() const { return mHwDevice; }

//mHwDevice值是在初始化时传入进来的,因此需要找到实例化的地方
AudioHwDevice(audio_module_handle_t handle,
                  const char *moduleName,
                  const sp<DeviceHalInterface>& hwDevice,
                  Flags flags)
        : mHandle(handle)
        , mModuleName(strdup(moduleName))
	//初始化时传入参数
        , mHwDevice(hwDevice)
        , mFlags(flags) { }

正好在AudioFlinger.cpp有new AudioHwDevice在标记14位置
frameworks/av/services/audioflinger/AudioFlinger.cpp
......
mDevicesFactoryHal = DevicesFactoryHalInterface::create();
......
// loadHwModule_l() must be called with AudioFlinger::mLock and AudioFlinger::mHardwareLock held
AudioHwDevice* AudioFlinger::loadHwModule_l(const char *name){
    sp<DeviceHalInterface> dev;
    //打开一个指定名称的音频设备,并获取该设备的智能指针引用
    //标记12 调用到DevicesFactoryHal的openDevice方法打开驱动设备
    int rc = mDevicesFactoryHal->openDevice(name, &dev);
    ......
    //标记14
    AudioHwDevice *audioDevice = new AudioHwDevice(handle, name, dev, flags);
}


标记12 audioflinger

mDevicesFactoryHal的赋值最终调用DevicesFactoryHalLocal,最终差查询到 标记11中类型为sp <DeviceHalInterface>的hwDevice,最终传入了 DeviceHalLocal的实例地址

frameworks/av/services/audioflinger/AudioFlinger.cpp
mDevicesFactoryHal = DevicesFactoryHalInterface::create();

frameworks/av/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h //由libaudiohal可知HAL实现在hardware
class DevicesFactoryHalInterface : public RefBase
{
    virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device) = 0;
}

hardware/amlogic/audio/utils/hidl_interface_7_0/impl/DevicesFactoryHalLocal.h
//DevicesFactoryHalLocal 继承DevicesFactoryHalInterface,因此可以查看DevicesFactoryHalLocal 的实现
class DevicesFactoryHalLocal : public DevicesFactoryHalInterface{
......
}

hardware/amlogic/audio/utils/hidl_interface_7_0/impl/DevicesFactoryHalLocal.cpp 
status_t DevicesFactoryHalLocal::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    audio_hw_device_t *dev;
    //标记12.1 加载音频设备模块
    status_t rc = load_audio_interface(name, &dev);
    if (rc == OK) {
	//标记11中类型为sp <DeviceHalInterface>的hwDevice,最终传入了 DeviceHalLocal的实例地址
        *device = new DeviceHalLocal(dev);
    }
    return rc;
}

标记12.1 hardware:load_audio_interface

load_audio_interface获取对应音频模块

hardware/amlogic/audio/utils/hidl_interface_7_0/impl/DevicesFactoryHalLocal.cpp
//其中load_audio_interface中可以查看到需要获取哪个硬件的模块ID AUDIO_HARDWARE_MODULE_ID
static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev)
{
    //搜索 AUDIO_HARDWARE_MODULE_ID 可以得到很多硬件音频模块USB、远程音频等,找到我们需要的aml即可
    //利用HAL层注册信息id和name,获取相应的模块
    //主要用于id相同、name不同,即获取相同功能但厂家不同的硬件库。
    //获取到HAL层音频模块后,再将mod通过audio_hw_device_open打开
    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
    //调用对应音频模块的open方法
    rc = audio_hw_device_open(mod, dev);
}
其中 audio_hw_device_open
static inline int audio_hw_device_open(const struct hw_module_t* module,
                                       struct audio_hw_device** device)
{
    return module->methods->open(module, AUDIO_HARDWARE_INTERFACE,
                                 TO_HW_DEVICE_T_OPEN(device));//调用硬件模块的open方法
}

搜索 AUDIO_HARDWARE_MODULE_ID 可以得到很多硬件音频模块USB、远程音频等,找到我们需要的aml即可
/hardware/amlogic/audio/audio_hal/audio_hw.c
static struct hw_module_methods_t hal_module_methods = {
    .open = adev_open,
};
struct audio_module HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
        .hal_api_version = HARDWARE_HAL_API_VERSION,
        .id = AUDIO_HARDWARE_MODULE_ID,
        .name = "aml audio HW HAL",
        .author = "amlogic, Corp.",
        .methods = &hal_module_methods,
    },
};
static int adev_open(const hw_module_t* module, const char* name, hw_device_t** device){
    struct aml_audio_device *adev;
    //注意该结构体,hw_device后的函数就是对应framework的接口,=后的函数就是对应hal的接口
    adev->hw_device.set_audio_port_config = adev_set_audio_port_config;
}
static int adev_set_audio_port_config(struct audio_hw_device *dev, const struct audio_port_config *config)
{
     AM_LOGI("id:%d, dev:%s, role:%s, type:%s, gain:%d", config->id, ....)
}

标记13 hardware


frameworks/av/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h //由libaudiohal可知HAL实现在hardware
{
    virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
}

/hardware/amlogic/audio/utils/hidl_interface_7_0/impl/DeviceHalLocal.h
#include <media/audiohal/DeviceHalInterface.h>
class DeviceHalLocal : public DeviceHalInterface{
     virtual status_t setAudioPortConfig(const struct audio_port_config *config);
}

hardware/amlogic/audio/utils/hidl_interface_7_0/impl/DeviceHalLocal.cpp
status_t DeviceHalLocal::setAudioPortConfig(const struct audio_port_config *config) {
    if (version() >= AUDIO_DEVICE_API_VERSION_3_0)
        return mDev->set_audio_port_config(mDev, config);
    else
        return INVALID_OPERATION;
}

dumpsys调试

dumpsys 关于音量的有下面三种属性:
media.audio_flinger、audio、media.audio_policy
其中media.audio_flinger能显示关与aml中关于HAL的信息
    static IBinder getAudioFlinger() {
        return ServiceManager.getService("media.audio_flinger");
    }

标签:HAL,标记,framework,音量,AudioPolicyService,Android,audio,config,port
From: https://blog.csdn.net/qq_41751728/article/details/139476273

相关文章

  • Android应用保活攻略
    前言Android应用保活是一个老生常谈的话题,本文尽可能收集市面上的保活手段,希望能对你有所帮助。在Android系统中,保活(保持应用进程一直存活)就是为了让应用在后台持续运行,来实现某些特定的功能,如实时消息推送、定位服务等。然而,由于Android系统为了节省资源和保护用户隐私,通......
  • 关于Android的学习心得
    一、AS中的主要组件1、Activity组件[1]-Activity的基本使用1.Activity是什么Activity是一种可以包含用户界面的组件,主要用于和用户进行交互。一个应用程序中可以包含零个或多个Activity。2.Activity中的onCreate()方法onCreate()方法:用于在活动(Activity)的生命周期中进行......
  • android12 Settings 添加导航栏和状态栏开关
    平台RK3568,android12添加导航栏和状态栏的开关。 通过设置系统属性来默认系统关闭导航栏和状态栏。Index:device/rockchip/rk356x/device.mk===================================================================---device/rockchip/rk356x/device.mk(revision2442......
  • 基于Android的校园自由贸易系统设计与实现
    临近毕业,许多毕业生都要在离校之前清理自己的物品。以前大多数学生会选择丢弃,造成了资源的大量浪费。而近几年,二手交易市场在校园中如雨后春笋般发展,书籍和某些耐用品一般通过二手交易市场或二手群交易。前者流程繁琐,耗时耗力。后者商品质量,售后得不到保障,还容易因为交涉不清引......
  • [Proxy] 使用 Charles 对 Android 应用进行 HTTPS 数据抓包
    抓包工具Charleshttps://www.charlesproxy.com/操作步骤1.在电脑上安装Charles客户端并进行配置1.1设置ProxySetting1.2设置 SSLProxingSetting1.3重启Charles客户端2.在手机上安装Charles证书2.1将手机与电脑连接到同一WIFI网络2.2设置手机WIF......
  • android view 扩展方法
    importandroid.view.Viewimportandroid.view.ViewGroupimportandroid.view.ViewGroup.MarginLayoutParamsimportandroid.view.ViewTreeObserverimportandroidx.core.view.marginBottomimportandroidx.core.view.marginLeftimportandroidx.core.view.marginRight......
  • android gson 扩展, 序列化int类型被转double 问题
    importcom.google.gson.Gsonimportcom.google.gson.GsonBuilderimportcom.google.gson.ToNumberStrategyimportcom.google.gson.reflect.TypeTokenimportcom.google.gson.stream.JsonReaderimportjava.io.IOExceptionimportjava.lang.reflect.Typeimportjava.m......
  • android kotlin 小数保留格式化位数
    importjava.math.RoundingModeimportjava.text.NumberFormatimportjava.util.*/**支持设置舍入模式的类型小数*/inlinefunAny?.formatDecimalRoundingMode(decimalDigits:Int=2,roundingMode:RoundingMode=RoundingMode.HALF_UP,failValue:Double=0.0):......
  • android viewbinding 自动填充工具
    `importandroid.content.Contextimportandroid.view.LayoutInflaterimportandroidx.lifecycle.*importandroidx.viewbinding.ViewBindingimportjava.lang.reflect.ParameterizedType/**查找某个类找到带有指定泛型的具体类/fungetGenericSuperclass(clazz:Class<......
  • 2.6倍!WhaleTunnel 客户POC实景对弈DataX
    作为阿里早期的开源产品,DataX是一款非常优秀的数据集成工具,普遍被用于多个数据源之间的批量同步,包括类似ApacheDolphinScheduler的Task类型也对DataX进行了适配和增强,可以直接在DolphinScheduler里面利用通用的数据源调用DataX进行数据批量同步。作为DolphinScheduler的社区支......