Android Framework audio subsystem (03) AudioPolicyService start analysis

This series of articles Master link: Thematic sub-directory Android Framework Class Audio Subsystem


Summary and description of key points in this chapter:

This chapter mainly focuses on ➕ The AudioPolicyService part below the above mind map is enough. It is mainly for the analysis of the AudioPolicyService startup, which involves the detailed analysis process from the AudioPolicyService startup process to the AudioPolicyManager process and AudioPolicyManager process (loading configuration files, loadHwModule
, and openOutput. The related operations of AudioFlinger involved here are analyzed in detail in the next section).


1 From AudioPolicyService startup process to AudioPolicyManager

The start of AudioPolicyService is implemented in Main_mediaserver.cpp, the code is as follows:

int main(int argc __unused, char** argv)
{
    signal(SIGPIPE, SIG_IGN);
    char value[PROPERTY_VALUE_MAX];
    //...
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    //...
    AudioFlinger::instantiate();//AudioFlinger
    MediaPlayerService::instantiate();
    CameraService::instantiate();
    AudioPolicyService::instantiate();//AudioPolicyService
    SoundTriggerHwService::instantiate();
    registerExtensions();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
	//...
}

Here, the AudioFlinger service is started first, and then the AudioFlinger service can be used directly after the AudioPolicyService is started. This chapter focuses on analyzing the implementation of AudioPolicyService :: instantiate (), the code is as follows:

static void instantiate() { publish(); }

Continue to analyze publish, the code is as follows:

    static status_t publish(bool allowIsolated = false) {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(//注册服务到servicemanager中
                String16(SERVICE::getServiceName()),
                new SERVICE(), allowIsolated);
    }

Here the service is registered in service_manager. At the same time, an AudioPolicyService is created here, that is, a constructor that implements AudioPolicyService, the code is as follows:

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

Mainly the initialization of some variables, and then mainly look at the implementation of onFirstRef, the code is as follows:

void AudioPolicyService::onFirstRef()
{
    char value[PROPERTY_VALUE_MAX];
    const struct hw_module_t *module;
    int forced_val;
    int rc;
    {
        Mutex::Autolock _l(mLock);
        //创建3个线程:
        //用于播放tone音
        mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);
        //用于执行audio命令
        mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
        //用于执行输出命令
        mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
#ifdef USE_LEGACY_AUDIO_POLICY
        //老版本的实现,这里忽略
#else
        //AudioFlinger客户端实现,调用AudioFlinger的一些服务
        mAudioPolicyClient = new AudioPolicyClient(this);
        mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
#endif
    }
    // load audio processing modules
    sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();
    {
        Mutex::Autolock _l(mLock);
        mAudioPolicyEffects = audioPolicyEffects;
    }
}

The main concern here is the implementation of createAudioPolicyManager, the code is as follows:

extern "C" AudioPolicyInterface* createAudioPolicyManager(
        AudioPolicyClientInterface *clientInterface)
{
    return new AudioPolicyManager(clientInterface);
}

Continue to analyze the implementation of AudioPolicyManager.


2 AudioPolicyManager detailed analysis

The code implementation of AudioPolicyManager is as follows:

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
    ://test...
    mPrimaryOutput((audio_io_handle_t)0),
    mPhoneState(AUDIO_MODE_NORMAL),
    mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
    //...
{
    //...
    mDefaultOutputDevice = new DeviceDescriptor(String8(""), AUDIO_DEVICE_OUT_SPEAKER);
    //关键点1,加载配置文件 audio_policy.conf
    /*
     系统会首先加载vendor/etc目录下的configure文件,再加载system/etc目录下的configure文件。
     若这两者加载都发生错误的话,系统会加载default配置文件,并命名为primary module,从这可以看
     出,音频系统中一定必须存在的module就是primary了。
     */
    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();
        }
    }
    // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices

    //初始化各种音频流对应的音量调节点
    initializeVolumeCurves();

    // open all output streams needed to access attached devices
    audio_devices_t outputDeviceTypes = mAvailableOutputDevices.types();
    //input等价操作
    for (size_t i = 0; i < mHwModules.size(); i++) {
        //关键点2,使用AudioFlinger加载audio policy硬件抽象库
        mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
        if (mHwModules[i]->mHandle == 0) {
            ALOGW("could not open HW module %s", mHwModules[i]->mName);
            continue;
        }
        
        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
        {
            const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];

            if (outProfile->mSupportedDevices.isEmpty()) {
                ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName);
                continue;
            }

            if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
                continue;
            }
            audio_devices_t profileType = outProfile->mSupportedDevices.types();
            if ((profileType & mDefaultOutputDevice->mDeviceType) != AUDIO_DEVICE_NONE) {
                profileType = mDefaultOutputDevice->mDeviceType;
            } else {
                for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
                    profileType = outProfile->mSupportedDevices[k]->mDeviceType;
                    if ((profileType & outputDeviceTypes) != 0) {
                        break;
                    }
                }
            }
            if ((profileType & outputDeviceTypes) == 0) {
                continue;
            }
            //通过outProfile 构建AudioOutputDescriptor类型的变量outputDesc
            sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(outProfile);

            outputDesc->mDevice = profileType;
            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
            config.sample_rate = outputDesc->mSamplingRate;
            config.channel_mask = outputDesc->mChannelMask;
            config.format = outputDesc->mFormat;
            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
            //关键点3:openOutput
            status_t status = mpClientInterface->openOutput(outProfile->mModule->mHandle,
                                                            &output,
                                                            &config,
                                                            &outputDesc->mDevice,
                                                            String8(""),
                                                            &outputDesc->mLatency,
                                                            outputDesc->mFlags);
            if (status != NO_ERROR) {
                //...
            } else {
                outputDesc->mSamplingRate = config.sample_rate;
                outputDesc->mChannelMask = config.channel_mask;
                outputDesc->mFormat = config.format;
                //...
                /*保存输出设备描述符对象outputDesc到mOutputs,表示已经打开的Output
                 *这样以后就可以根据一个整数output 找到对应的thread和outputDesc
                 */
                addOutput(output, outputDesc);
                //设置输出设备
                setOutputDevice(output,
                                outputDesc->mDevice,
                                true);
            }
        }
        // open input streams needed to access attached devices to validate
        // mAvailableInputDevices list
        //input等价操作
    }
    // make sure all attached devices have been allocated a unique ID
    for (size_t i = 0; i  < mAvailableOutputDevices.size();) {
        if (mAvailableOutputDevices[i]->mId == 0) {
            ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mDeviceType);
            mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
            continue;
        }
        i++;
    }
    //更新输出设备
    updateDevicesAndOutputs();
    //test...
}

Here we analyze three key points: load configuration file and loadHwModule and open output.

2.1 Load configuration file

The code implementation of loadAudioPolicyConfig is as follows:

status_t AudioPolicyManager::loadAudioPolicyConfig(const char *path)
{
    cnode *root;
    char *data;

    data = (char *)load_file(path, NULL);
    if (data == NULL) {
        return -ENODEV;
    }
    root = config_node("", "");
    config_load(root, data);

    loadHwModules(root);
    // legacy audio_policy.conf files have one global_configuration section
    loadGlobalConfig(root, getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY));
    config_free(root);
    free(root);
    free(data);
    return NO_ERROR;
}

This is essentially parsing a file audio_policy.conf, the structure of this file is as follows:

# 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_DEVICE_IN_VOICE_CALL|AUDIO_DEVICE_IN_REMOTE_SUBMIX
}

# 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.<device>.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".

audio_hw_modules {
  primary { #一个module对应厂家提供一个so文件
    outputs { #一个module可以有多个output
      primary { #一个module里表明它的参数
        sampling_rates 48000
        channel_masks AUDIO_CHANNEL_OUT_STEREO
        formats AUDIO_FORMAT_PCM_16_BIT
        devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO
        flags AUDIO_OUTPUT_FLAG_PRIMARY #默认设备
      }
    }
    inputs { #一个module可以有多个input
      primary {
        sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000
        channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO
        formats AUDIO_FORMAT_PCM_16_BIT
        devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET|AUDIO_DEVICE_IN_WIRED_HEADSET|AUDIO_DEVICE_IN_VOICE_CALL
      }
    }
  }
  a2dp {
    outputs {
      a2dp {
        sampling_rates 44100
        channel_masks AUDIO_CHANNEL_OUT_STEREO
        formats AUDIO_FORMAT_PCM_16_BIT
        devices AUDIO_DEVICE_OUT_ALL_A2DP
      }
    }
  }
  //...
}

To sum up, this part of the code is mainly loaded and parsed /vendor/etc/audio_policy.conf or /system/etc/audio_policy.conf, which is mainly divided into 3 steps:

  1. For each module item in the configuration file, new HwModule (name), put in mHwModules array
  2. For each output, new IOProfile in the module, put in the module's mOutputProfiles
  3. For each input, new IOProfile in the module, put in the module's mInputProfiles

This file analysis is represented by a picture, so that the relationship between the hierarchical relationship and the data structure can be seen more clearly, as shown below:

2.2 Implementation of loadHwModule

mpClientInterface-> loadHwModule (mHwModules [i]-> mName), the last call is AudioFlinger's loadHwModule method, its code implementation is as follows:

audio_module_handle_t AudioPolicyService::AudioPolicyClient::loadHwModule(const char *name)
{
    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
    if (af == 0) {
        ALOGW("%s: could not get AudioFlinger", __func__);
        return 0;
    }

    return af->loadHwModule(name);
}

Finally, the loadHwModule method of AudioFlinger is called here. We will analyze this in detail in the next chapter

2.3 Implementation of openOutput

mpClientInterface-> openOutput, the last call is AudioFlinger's openOutput method, and its code is implemented as follows:

status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,
                                                           //...
                                                           audio_output_flags_t flags)
{
    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
    if (af == 0) {
        ALOGW("%s: could not get AudioFlinger", __func__);
        return PERMISSION_DENIED;
    }
    return af->openOutput(module, output, config, devices, address, latencyMs, flags);
}

Finally, the output of AudioFlinger is called here (here, a MixerThread thread will be created and associated with the corresponding output, and then the application can pass the data to the thread and then to the hardware device). We will analyze this in detail in the next chapter.

 

 

 

Published 289 original articles · praised 47 · 30,000+ views

Guess you like

Origin blog.csdn.net/vviccc/article/details/105275077