一、引入:
在Android中,应用进行音频回放或者录音时,最终在hal层需要选择用哪个输入/输出设备,而设备的加载,就跟audio_policy.conf息息相关,本博文分析的内容就是Android原生音频audio_policy.conf加载的过程(Android5.1)。

二、源码分析:
1.AudioPolicyService服务的启动:
与音频相关的服务AudioFlinger和AudioPolicyService都是在mediaserver这个进程中:

...    sp<ProcessState> proc(ProcessState::self());        sp<IServiceManager> sm = defaultServiceManager();        ALOGI("ServiceManager: %p", sm.get());        AudioFlinger::instantiate();        MediaPlayerService::instantiate();        CameraService::instantiate();        AudioPolicyService::instantiate();        SoundTriggerHwService::instantiate();...

看一下AudioPolicyService::instantiate():

template<typename SERVICE>class BinderService{public:    static status_t publish(bool allowIsolated = false) {        sp<IServiceManager> sm(defaultServiceManager());        return sm->addService(                String16(SERVICE::getServiceName()),                new SERVICE(), allowIsolated);    }    static void publishAndJoinThreadPool(bool allowIsolated = false) {        publish(allowIsolated);        joinThreadPool();    }    static void instantiate() { publish(); }    static status_t shutdown() { return NO_ERROR; }private:    static void joinThreadPool() {        sp<ProcessState> ps(ProcessState::self());        ps->startThreadPool();        ps->giveThreadPoolName();        IPCThreadState::self()->joinThreadPool();    }};

这是一个模板类,实际上调用的是publish()这个函数,看一下此函数的实现,向SM注册此服务,然后实例化AudioPolicyService,因为addService的第二个参数是强指针传参,所以紧接着会去调用onFirstRef()函数:

AudioPolicyService::AudioPolicyService()    : BnAudioPolicyService(), mpAudioPolicyDev(NULL), mpAudioPolicy(NULL),      mAudioPolicyManager(NULL), mAudioPolicyClient(NULL), mPhoneState(AUDIO_MODE_INVALID){}

AudioPolicyService的构造其实什么事都没有干,但是要注意初始化参数列表中的这几个成员变量,但onFirstRef有干具体的事;

void AudioPolicyService::onFirstRef(){.../* 1.实例化AudioPolicyClient */mAudioPolicyClient = new AudioPolicyClient(this);/* 2.实例化AudioPolicyManager */mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);...}

因为AudioPolicyService是基于binder机制的C/S架构,所以,服务端建立起来之之后,自然不可缺少client端,AudioPolicyClient构造函数在AudioPolicyService.h中,记录了当前的服务AudioPolicyService,可以看到,client端获取audiopolicyservice的服务并不在构造函数中,而是另有他处:

   AudioPolicyClient(AudioPolicyService *service) : mAudioPolicyService(service) {}
extern "C" AudioPolicyInterface* createAudioPolicyManager(        AudioPolicyClientInterface *clientInterface){    return new AudioPolicyManager(clientInterface);}

总结来说,onFirstRef干的事是实例化了一个AudioPolicyClient对象,记录了服务的提供者AudioPolicyService,接着继续构造了AudioPolicyManager;

2.加载audio_policy.conf:
配置文件的加载就是在AudioPolicyManager的构造函数完成的,博文分析的conf文件在文章最后:

if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {        if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {            ALOGE("could not load audio policy configuration file, setting defaults");            defaultAudioPolicyConfig();        }    }

如果代码中的两个路径都没有找到conf文件的话,就会直接生成一个,系统中的audio_policy.conf被读取之后,以profile的形式保存,后续打开/关闭设备的时候,就通过调用profile获取所有的配置参数;
重点分析一下loadAudioPolicyConfig函数:

status_t AudioPolicyManager::loadAudioPolicyConfig(const char *path){    cnode *root;    char *data;/* 1.加载conf文件 */    data = (char *)load_file(path, NULL);    if (data == NULL) {        return -ENODEV;    }/* 2.实例化一个数据储存链表 */    root = config_node("", "");/* 3.读取conf,生成数据节点 */    config_load(root, data);/* 4.加载模块 */    loadHwModules(root);    // legacy audio_policy.conf files have one global_configuration section    /* 5.加载全局配置 */    loadGlobalConfig(root, getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY));    /* 6.释放相关资源 */    config_free(root);    free(root);    free(data);    ALOGI("loadAudioPolicyConfig() loaded %s\n", path);    return NO_ERROR;}

前面两步就是去读取文件中的内容,同时生成一个管理数据的链表,准备去生成profile,第三步就是去解析数据,解析方式有点复杂,没有详细看,大概的原理,就是以“{}”包围的部分识别为一组有效数据,然后储存起来,第四步就是重点了,根据关键字去生成profile:

void AudioPolicyManager::loadHwModules(cnode *root){/* 识别audio_hw_modules关键字的数据块 */    cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);    if (node == NULL) {        return;    }    node = node->first_child;    while (node) {        ALOGE("loadHwModules() loading module %s", node->name);        /* 加载模块 */        loadHwModule(node);        node = node->next;    }}

首先是从profile中读取audio_hw_modules后面的数据块,注意这个module,后续代码中,加载动态库就是根据这个module名来的,从profile中可以看出来,一共有4个模块,分别是primary、a2dp、usb和r_submix,以primary为例,看下loadHwModule:

void AudioPolicyManager::loadHwModule(cnode *root){    status_t status = NAME_NOT_FOUND;    cnode *node;    sp<HwModule> module = new HwModule(root->name);...    node = config_find(root, OUTPUTS_TAG);    if (node != NULL) {        node = node->first_child;        while (node) {            ALOGE("loadHwModule() loading output %s", node->name);            status_t tmpStatus = module->loadOutput(node);            if (status == NAME_NOT_FOUND || status == NO_ERROR) {                status = tmpStatus;            }            node = node->next;        }    }    ...}

primary下属的关键字数据块有两个,分别是outputs和inputs,找到outputs数据块之后,调用loadOutput去生成profile,outputs下面一共有4个profile,分别是primary、hw_av_sync、hw_compress和hw_av_sync_compress:

status_t AudioPolicyManager::HwModule::loadOutput(cnode *root){    cnode *node = root->first_child;    sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SOURCE, this);    while (node) {        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {            profile->loadSamplingRates((char *)node->value);        } else if (strcmp(node->name, FORMATS_TAG) == 0) {            profile->loadFormats((char *)node->value);        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {            profile->loadOutChannels((char *)node->value);        } else if (strcmp(node->name, DEVICES_TAG) == 0) {            profile->mSupportedDevices.loadDevicesFromName((char *)node->value,                                                           mDeclaredDevices);        } else if (strcmp(node->name, FLAGS_TAG) == 0) {            profile->mFlags = parseOutputFlagNames((char *)node->value);        } else if (strcmp(node->name, GAINS_TAG) == 0) {            profile->loadGains(node);        }        node = node->next;    }    ALOGW_IF(profile->mSupportedDevices.isEmpty(),            "loadOutput() invalid supported devices");    ALOGW_IF(profile->mChannelMasks.size() == 0,            "loadOutput() invalid supported channel masks");    ALOGW_IF(profile->mSamplingRates.size() == 0,            "loadOutput() invalid supported sampling rates");    ALOGW_IF(profile->mFormats.size() == 0,            "loadOutput() invalid supported formats");    if (!profile->mSupportedDevices.isEmpty() &&            (profile->mChannelMasks.size() != 0) &&            (profile->mSamplingRates.size() != 0) &&            (profile->mFormats.size() != 0)) {        ALOGE("loadOutput() adding output Supported Devices %04x, mFlags %04x",              profile->mSupportedDevices.types(), profile->mFlags);        mOutputProfiles.add(profile);        return NO_ERROR;    } else {        return BAD_VALUE;    }}

这里就根据具体的配置去生成profile,然后添加到mOutputProfiles中就行了;

3.根据module去加载动态库:
回到AudioPolicyManager的构造函数,在loadAudioPolicyConfig成功之后,接下来要做的事就是去加载各个module对应的动态库,这是通过[email protected]来完成的:

mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);

mpClientInterface前面已经分析过,指向的是类对象AudioPolicyClientInterface,注意成员函数的实现是在AudioPolicyClientImpl.cpp中,找到loadHwModule:

audio_module_handle_t AudioPolicyService::AudioPolicyClient::loadHwModule(const char *name){/* 1.获取audio_flinger服务 */    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();    if (af == 0) {        ALOGW("%s: could not get AudioFlinger", __func__);        return 0;    }/* 2.通过audioflinger去加载动态库 */    return af->loadHwModule(name);}

进入audioflinger,会继续调用loadHwModule_l:

audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name){.../* 动态库的加载 */    int rc = load_audio_interface(name, &dev);    if (rc) {        ALOGI("loadHwModule() error %d loading module %s ", rc, name);        return 0;    }    ...}

继续往下跟踪:

static int load_audio_interface(const char *if_name, audio_hw_device_t **dev){    const hw_module_t *mod;    int rc;/* 根据传入的module名生成动态库 */    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);    ALOGE_IF(rc, "%s couldn't load audio hw module %s.%s (%s)", __func__,                 AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));    if (rc) {        goto out;    }    rc = audio_hw_device_open(mod, dev);    ALOGE_IF(rc, "%s couldn't open audio hw device in %s.%s (%s)", __func__,                 AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));    if (rc) {        goto out;    }    if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {        ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);        rc = BAD_VALUE;        goto out;    }    return 0;out:    *dev = NULL;    return rc;}

重点分析hw_get_module_by_class,传入的名字是“audio” + module,然后根据property_get的结果去拼接最终的库名

int hw_get_module_by_class(const char *class_id, const char *inst,                           const struct hw_module_t **module){.../* 传入的名字name经过拼接,为“audio.primary” */.../* 1.查看属性“ro.hardware.audio.primary”结果 */    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);    if (property_get(prop_name, prop, NULL) > 0) {        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {            goto found;        }    }/* 2.查看VARIANT_KEYS是否有对应属性 */    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {    if (property_get(variant_keys[i], prop, NULL) == 0) {        continue;    }    if (hw_module_exists(path, sizeof(path), name, prop) == 0) {        goto found;    }   }/* 3.如果都没有,就为default */    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {        goto found;    }}

在我的调试的镜像中,第二条ro.hardware属性值为bigfish,所以加载的库为“audio.primary.bigfish.so”,可以看到,库的加载是有优先级的,如果module名相同,而后缀不同的话,那么就会根据优先级进行加载,比如:“audio.primary.bigfish.so”和“audio.primary.default.so”同时存在,加载的就会是前者;
4.去hal层打开输入/输出流:
回到AudioPolicyManager的构造函数,既然已经加载了动态库,接下来就是尝试通过audioflinger去底层打开输入输出流,这里以输出为例:

    status_t status = mpClientInterface->openOutput(outProfile->mModule->mHandle,                                                            &output,                                                            &config,                                                            &outputDesc->mDevice,                                                            String8(""),                                                            &outputDesc->mLatency,                                                            outputDesc->mFlags);

mpClientInterface前面已经分析过,指向的是类对象AudioPolicyClientInterface,注意成员函数的实现是在AudioPolicyClientImpl.cpp中,找到openOutput:

status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,                                                           audio_io_handle_t *output,                                                           audio_config_t *config,                                                           audio_devices_t *devices,                                                           const String8& address,                                                           uint32_t *latencyMs,                                                           audio_output_flags_t flags){/* 1.获取audio_flinger服务 */    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();    if (af == 0) {        ALOGW("%s: could not get AudioFlinger", __func__);        return PERMISSION_DENIED;    }    /* 2.通过audioflinger去打开输出设备 */    return af->openOutput(module, output, config, devices, address, latencyMs, flags);}

这里就可以看到,audiopolicy最终还是通过audioflinger去打开输出设备;
openOutput会继续调用openOutput_l:

sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_t module,                                                            audio_io_handle_t *output,                                                            audio_config_t *config,                                                            audio_devices_t devices,                                                            const String8& address,                                                            audio_output_flags_t flags){/* 1.找到合适的device */    AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);    if (outHwDev == NULL) {        return 0;    }/* 2.去hal层打开设备 */status_t status = hwDevHal->open_output_stream(hwDevHal,                                                   *output,                                                   devices,                                                   flags,                                                   config,                                                   &outStream,                                                   address.string());/* 3.实例化输出流并创建一个thread */mPlaybackThreads.add(*output, thread);return thread;...}

看一下findSuitableHwDev_l:

AudioFlinger::AudioHwDevice* AudioFlinger::findSuitableHwDev_l(        audio_module_handle_t module,        audio_devices_t devices){    // if module is 0, the request comes from an old policy manager and we should load    // well known modules    if (module == 0) {        ALOGW("findSuitableHwDev_l() loading well know audio hw modules");        for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {            loadHwModule_l(audio_interfaces[i]);        }        // then try to find a module supporting the requested device.        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {            AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(i);            audio_hw_device_t *dev = audioHwDevice->hwDevice();            if ((dev->get_supported_devices != NULL) &&                    (dev->get_supported_devices(dev) & devices) == devices)                return audioHwDevice;        }    } else {        // check a match for the requested module handle        AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(module);        if (audioHwDevice != NULL) {            return audioHwDevice;        }    }    return NULL;}

mediaserver启动场景,只会走到else里面去,直接通过module即可找到AudioHwDevice;

三、audio_policy.conf源码:

## Audio policy configuration for generic device builds (goldfish audio HAL - emulator)## Global configuration section: lists input and output devices always present on the device# as well as the output device selected by default.# Devices are designated by a string that corresponds to the enum in audio.hglobal_configuration {  attached_output_devices AUDIO_DEVICE_OUT_SPEAKER  default_output_device AUDIO_DEVICE_OUT_SPEAKER  attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC}# audio hardware module section: contains descriptors for all audio hw modules present on the# device. Each hw module node is named after the corresponding hw module library base name.# For instance, "primary" corresponds to audio.primary..so.# The "primary" module is mandatory and must include at least one output with# AUDIO_OUTPUT_FLAG_PRIMARY flag.# Each module descriptor contains one or more output profile descriptors and zero or more# input profile descriptors. Each profile lists all the parameters supported by a given output# or input stream category.# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n".#device sr changed from 44100 to 48000 to adapt chipaudio_hw_modules {  primary {    outputs {      primary {        sampling_rates 48000        channel_masks AUDIO_CHANNEL_OUT_STEREO        formats AUDIO_FORMAT_PCM_16_BIT        devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI        flags AUDIO_OUTPUT_FLAG_PRIMARY      }      hw_av_sync {        sampling_rates 8000|11025|16000|22050|24000|32000|44100|48000        channel_masks AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_STEREO        formats AUDIO_FORMAT_PCM_16_BIT        devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI        flags AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC      }      hw_compress {        sampling_rates 8000|11025|16000|22050|24000|32000|44100|48000        channel_masks AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1        formats AUDIO_FORMAT_AC3|AUDIO_FORMAT_E_AC3        devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI        flags AUDIO_OUTPUT_FLAG_DIRECT      }      hw_av_sync_compress {        sampling_rates 8000|11025|16000|22050|24000|32000|44100|48000        channel_masks AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1        formats AUDIO_FORMAT_AC3|AUDIO_FORMAT_E_AC3        devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI        flags AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC      }    }    inputs {      primary {        sampling_rates 8000|11025|16000|22050|24000|32000|44100|48000        channel_masks AUDIO_CHANNEL_IN_MONO        formats AUDIO_FORMAT_PCM_16_BIT        devices AUDIO_DEVICE_IN_BUILTIN_MIC      }    }  }  a2dp {      outputs {          a2dp {              sampling_rates 44100|48000                  channel_masks AUDIO_CHANNEL_OUT_STEREO                  formats AUDIO_FORMAT_PCM_16_BIT                  devices AUDIO_DEVICE_OUT_ALL_A2DP          }      }  }  usb {    outputs {      usb_device {        sampling_rates dynamic        channel_masks dynamic        formats dynamic        devices AUDIO_DEVICE_OUT_USB_DEVICE      }    }   inputs {     usb_device {       sampling_rates dynamic       channel_masks dynamic       formats dynamic       devices AUDIO_DEVICE_IN_USB_DEVICE     }   }  } r_submix {   outputs {     submix {       sampling_rates 48000       channel_masks AUDIO_CHANNEL_OUT_STEREO       formats AUDIO_FORMAT_PCM_16_BIT       devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX     }    }   inputs {    submix {      sampling_rates 48000      channel_masks AUDIO_CHANNEL_IN_STEREO      formats AUDIO_FORMAT_PCM_16_BIT      devices AUDIO_DEVICE_IN_REMOTE_SUBMIX     }   }  }}

Android音频系统之AudioPolicyService的启动及audio_policy.conf的加载(Android5.1)_第1张图片

四、启动总结:
Android音频系统之AudioPolicyService的启动及audio_policy.conf的加载(Android5.1)_第2张图片
Mediaserver进程会去创建audiopolicyservice的服务,然后在服务中会去实例化audiopolicymanager,实际上,audiopolicymanager拥有audiopolicyservice的代理权,当涉及具体动作的时候,调用audioflinger去完成。

更多相关文章

  1. Android 中LayoutInflater(布局加载器)之介绍篇
  2. Android与服务器端数据交互
  3. Android 数据库批量查询数据的操作
  4. Android中ListView分页加载数据
  5. Android:数据存取之Preferences
  6. 使用android快速开发框架afinal的FinalDb操作android数据库
  7. Android连接SQLServer详细教程(数据库+服务器+客户端),并在微软Azur

随机推荐

  1. android listiew适配器
  2. android小问题:RadioButton设置文字在图片
  3. Cocos2d-x3.0 捕捉Android的菜单键和返回
  4. Android Webview适配屏幕宽度
  5. Android 数据存储02之文件读写
  6. Android原生的TTS(语音播报功能)
  7. Android3.2运行报错:[2011-09-09 14:50:21
  8. 如何完全卸载Android Studio并进行重新安
  9. Android 4.0 external下功能库说明
  10. Android报错之.android/repositories.cfg