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

一、引入:
在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对应的动态库,这是通过loadHwModule@AudioPolicyManager来完成的:

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.h

global_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 chip
audio_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去完成。

你可能感兴趣的:(Android音频)