Android 音频子系统--10:HAL层分析

1,234 阅读13分钟

参考:Android Framework 音频子系统(12)HAL层分析

基于Android 9.0

1.概述

本章节主要关注以上思维导图左上HAL层分析部分即可。主要说明了HAL层的框架分析,后面通过源码分析了读音频数据流程、写音频数据流程、设置参数流程、获取参数流程 来深入的理解 HAL层的调用流程。

2.HAL层框架分析

  音频系统的整个框架图如下所示:

image.png

2.1 HAL层分为两部分

  如上图,HAL层有audio的HAL,也有Audio_policy的HAL(基本废弃)。HAL层下一层使用TinyAlsa(AlSA库 裁剪版),HAL层分为两部分:

(1)一部分为各种音频设备,每种音频设备由一个独立的库文件实现:

  • audio.a2dp.default.so(管理蓝牙a2dp音频)

  • audio.usb.default.so(管理usb外接的音频)

  • audio.primary.default.so(管理设备上的大部分音频)

(2)一部分为厂家自己实现的音频策略比如:audio.primary.tiny4412.so。

2.2 关键类与结构体

  一般来讲,为了方便HAL要向上层提供统一的接口,操作硬件也会有一组接口/一个类。分别为:

(1)向上提供接口struct audio_hw_device:

  struct audio_hw_device在audio.h中定义,audio_hw_hal.cpp中实现接口。adev_open方法中对每个方法指针赋值。

  struct audio_hw_device接口在audio_hw_hal.cpp文件中,它是对hw_device_t结构的封装。audio_hw_hal.cpp位于hardware/libhardware_legacy/audio下(新的架构在hardware/libhardware/modules/audio下有个audio_hw.c文件,它就是新的Audio的HAL文件。这个文件同样没有实现,所以libhardware_legacy下的还是起主打作用)。

(2)向下访问硬件class AudioHardware

  一般在device/"平台厂商"/common/libaudio/audioHardware.cpp中实现, 由厂商提供,里面使用到了tinyalsa库的接口。厂商实现硬件的访问接口,Android指定了一套接口给它。几个关键类的继承关系为:

AudioHardwareInterface    //hardware/AudioHardwareInterface.cpp
    ↑
AudioHardwareBase         //hardware/AudioHardwareBase.h 这个应该是audio HAL给厂商定义的接口
    ↑
AudioHardware            //device/friendly-arm/common/libaudio/audioHardware.cpp

在厂商的HAL中,AudioHardware (audioHardware.cpp中)表示一个声卡,它使用audio_stream_out结构来表示输出,使用audio_stream_in来表示输入。(audio_stream_out中有write(),audio_stream_in中有read())。

2.3 HAL相关的数据结构总结

/* 上下衔接
 * Audio HAL的调用流程总结上层应用程序调用
 * audio_hw_hal.cpp中的legacy_adev_open()
 * 会得到一个struct audio_hw_device结构体,
 * 这个结构体代表上层使用硬件的接口,这个
 * 结构体中的函数都依赖于厂家提供的
 * struct AudioHardwareInterface结构。
 */
struct legacy_audio_device {
    struct audio_hw_device device; //规范了向上提供的接口 
    AudioHardwareInterface *hwif; // 向下访问硬件,指向厂家的AudioHardware };

/*由于HAL对上层直接提供的接口中没有read/write函数
 *因此,应用程序想要录音或播放声音的时候需要先打开
 *output或input(audio_hw_device中的open_output_stream/open_input_stream),
 *进而使用其里面的write/read函数通过声卡硬件读/写音频数据。
 *这也就是audio_hw_device与audio_stream_out/audio_stream_in之间的关系
 */
struct legacy_stream_out {
    struct audio_stream_out stream; //规范了向上提供的接口 
    AudioStreamOut *legacy_out; //向下访问硬件,指向厂家的AudioStreamOutALSA };

struct legacy_stream_in {
    struct audio_stream_in stream; //规范了向上提供的接口 
    AudioStreamIn *legacy_in; //向下访问硬件,指向厂家的AudioStreamInALSA };

3.HAL层源码分析

  接下来主要分析几个关键流程(写数据操作、读数据操作、获取参数、设置参数)来解读HAL的调用过程。

3.1 AudioFlinger加载库

  AudioFlinger加载库的过程如下:

AudioFlinger的loadHwModule加载音频硬件抽象库,下面从该方法开始分析:

// AudioFlinger.cpp
audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
{
    if (name == NULL) {
        return AUDIO_MODULE_HANDLE_NONE;
    }
    if (!settingsAllowed()) {
        return AUDIO_MODULE_HANDLE_NONE;
    }
    Mutex::Autolock _l(mLock);
    return loadHwModule_l(name);
}

参数name根据audio_policy_configuration.xml解析出来的:

<module name="primary" halVersion="2.0">

继续看到loadHwModule_l代码实现如下:

// AudioFlinger.cpp
audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
    //是否已经加载过这个interface
    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
        if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
            ALOGW("loadHwModule() module %s already loaded", name);
            return mAudioHwDevs.keyAt(i);
        }
    }

    sp<DeviceHalInterface> dev;
    //关键点:打开audio.primary.XXX.so,构造audio_hw_device
    int rc = mDevicesFactoryHal->openDevice(name, &dev);
    if (rc) {
        ALOGE("loadHwModule() error %d loading module %s", rc, name);
        return AUDIO_MODULE_HANDLE_NONE;
    }

    mHardwareStatus = AUDIO_HW_INIT;
    //初始化
    rc = dev->initCheck();
    mHardwareStatus = AUDIO_HW_IDLE;
    ...
    audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
    //通过dev构建AudioHwDevice,将AudioHwDevice加入到mAudioHwDevs中
    mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));

    ALOGI("loadHwModule() Loaded %s audio interface, handle %d", name, handle);

    return handle;

}

先来看看调用openDevice()方法的mDevicesFactoryHal

mDevicesFactoryHal = DevicesFactoryHalInterface::create();

DevicesFactoryHalInterface::create()代码实现如下:

// frameworks/av/media/libaudiohal/DevicesFactoryHalInterface.cpp
sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
    if (hardware::audio::V4_0::IDevicesFactory::getService() != nullptr) {
        return new V4_0::DevicesFactoryHalHybrid();
    }
    if (hardware::audio::V2_0::IDevicesFactory::getService() != nullptr) {
        return new DevicesFactoryHalHybrid();
    }
    return nullptr;
}

这里有两个版本(2.0和4.0)的DevicesFactoryHalHybrid,到底加载的是哪个?看到下面定义的地方:

// hardware/interfaces/audio/common/all-versions/default/service/service.cpp
int main(int /* argc */, char* /* argv */ []) {
    android::ProcessState::initWithDriver("/dev/vndbinder");
    // start a threadpool for vndbinder interactions
    android::ProcessState::self()->startThreadPool();
    configureRpcThreadpool(16, true /*callerWillJoin*/);

    bool fail = registerPassthroughServiceImplementation<audio::V4_0::IDevicesFactory>() != OK &&
                registerPassthroughServiceImplementation<audio::V2_0::IDevicesFactory>() != OK;
    LOG_ALWAYS_FATAL_IF(fail, "Could not register audio core API 2.0 nor 4.0");

    fail = registerPassthroughServiceImplementation<audio::effect::V4_0::IEffectsFactory>() != OK &&
           registerPassthroughServiceImplementation<audio::effect::V2_0::IEffectsFactory>() != OK,
    LOG_ALWAYS_FATAL_IF(fail, "Could not register audio effect API 2.0 nor 4.0");

    fail = registerPassthroughServiceImplementation<soundtrigger::V2_1::ISoundTriggerHw>() != OK &&
           registerPassthroughServiceImplementation<soundtrigger::V2_0::ISoundTriggerHw>() != OK,
    ALOGW_IF(fail, "Could not register soundtrigger API 2.0 nor 2.1");

    fail =
        registerPassthroughServiceImplementation<bluetooth::a2dp::V1_0::IBluetoothAudioOffload>() !=
        OK;
    ALOGW_IF(fail, "Could not register Bluetooth audio offload 1.0");

    joinRpcThreadpool();
}

2.0和4.0版本都注册的情况下,优先使用4.0的版本。再来看看openDevice():

// frameworks/av/media/libaudiohal/DevicesFactoryHalHybrid.cpp
status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0) {
        return mHidlFactory->openDevice(name, device);
    }
    return mLocalFactory->openDevice(name, device);
}

这里一般会去调用mLocalFactory的openDevice(),代码实现如下:

// frameworks/av/media/libaudiohal/DevicesFactoryHalLocal.cpp
status_t DevicesFactoryHalLocal::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    audio_hw_device_t *dev;
    status_t rc = load_audio_interface(name, &dev);
    if (rc == OK) {
        *device = new DeviceHalLocal(dev);
    }
    return rc;
}

继续分析load_audio_interface():

// frameworks/av/media/libaudiohal/DevicesFactoryHalLocal.cpp
static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev)
{
    const hw_module_t *mod;
    int rc;

    //通过hw_get_module_by_class->load->dlopen->dlsym->dlclose)
    //获得第三方厂家库的hw_module_t结构体指针 &mod
    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
    ...
    //通过&mod构建audio_hw_device_t类型结构体 dev
    rc = audio_hw_device_open(mod, dev);
    ...
}

这里有两个关键方法hw_get_module_by_class()和audio_hw_device_open(),下面将对这两个方法进行分析。

3.1.1 hw_get_module_by_class()

  hw_get_module_by_class()方法主要是从设备上查找so库,查找方法如下:以MTK8666为例。

(1)针对音频class_id: audio(audio)

(2)audio_policy_configuration.xml中的primary/usb/a2dp/...(audio.primary)

(3)property_get(variant_keys[i], prop, NULL)(name:audio.primary,subname:mt6771)

(4)hw_module_exists,从"/odm/lib64/hw","/vendor/lib64/hw","/system/lib64/hw"顺序去查找

/odm/lib64/hw/audio.primary.mt6771.so
/vendor/lib64/hw/audio.primary.mt6771.so
/system/lib64/hw/audio.primary.mt6771.so
int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int i = 0;
    char prop[PATH_MAX] = {0};
    char path[PATH_MAX] = {0};
    char name[PATH_MAX] = {0};
    char prop_name[PATH_MAX] = {0};


    if (inst)
        // name = [class_id].[inst]  (audio.primary)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);

    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */

    /* First try a property specific to the class and possibly instance */
    // prop_name = ro.hardware.audio.primary
    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
    //等同于:getprop ro.hardware.audio.primary,得到[空]
    if (property_get(prop_name, prop, NULL) > 0) {
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
        // property_get等同于执行:(1)getprop ro.hardware,得到mt8666
        // (2)getprop ro.product.board,得到pateo_common
        // (3)getprop ro.board.platform,得到mt6771
        // (4)getprop ro.arch,得到[空]
        // 返回>0成功,0失败
        // 返回结果存入到:prop
        if (property_get(variant_keys[i], prop, NULL) == 0) {
            continue;
        }
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Nothing found, try the default */
    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
        goto found;
    }

    return -ENOENT;

found:
    /* load the module, if this fails, we're doomed, and we should not try
     * to load a different variant. */
    return load(class_id, path, module);
}

参数说明如下:

  • class_id:audio

  • inst:audio_policy_configuration.xml中的primary/usb/a2dp/...(比如primary)

  • module:需要构建的audio_hw_device(封装了hw_module_t)

  再来看看hw_module_exists()方法的代码实现:

static int hw_module_exists(char *path, size_t path_len, const char *name,
                            const char *subname)
{
    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH3, name, subname);
    if (access(path, R_OK) == 0)
        return 0;

    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH2, name, subname);
    if (access(path, R_OK) == 0)
        return 0;

#ifndef __ANDROID_VNDK__
    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH1, name, subname);
    if (access(path, R_OK) == 0)
        return 0;
#endif

    return -ENOENT;
}

参数说明如下:

  • path:需要计算返回的路径
  • path_len:路径长度
  • name:名称(audio.primary)
  • subname:子名称(mt6771)

3.1.2 audio_hw_device_open()

  audio_hw_device_open()方法代码实现如下:

// hardware/libhardware/include/hardware/audio.hstatic 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));
 }

对应执行到如下代码:module->methods->open => legacy_adev_open()

// hardware/libhardware_legacy/audio/audio_hw_hal.cpp
static struct hw_module_methods_t legacy_audio_module_methods = {
        open: legacy_adev_open
};

struct legacy_audio_module HAL_MODULE_INFO_SYM = {
    module: {
        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: "LEGACY Audio HW HAL",
            author: "The Android Open Source Project",
            methods: &legacy_audio_module_methods,
            dso : NULL,
            reserved : {0},
        },
    },
};

所以这里会调用到了HAL层的legacy_adev_open方法,代码实现如下:

// hardware/libhardware_legacy/audio/audio_hw_hal.cpp
static int legacy_adev_open(const hw_module_t* module, const char* name,
                            hw_device_t** device)
{
    struct legacy_audio_device *ladev;
    int ret;
 
    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
        return -EINVAL;
 
    ladev = (struct legacy_audio_device *)calloc(1, sizeof(*ladev));
    if (!ladev)
        return -ENOMEM;
 
    //结构体赋值
    ladev->device.common.tag = HARDWARE_DEVICE_TAG;
    ladev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
    ladev->device.common.module = const_cast<hw_module_t*>(module);
    ladev->device.common.close = legacy_adev_close;
    ladev->device.init_check = adev_init_check;
    ladev->device.set_voice_volume = adev_set_voice_volume;
    ladev->device.set_master_volume = adev_set_master_volume;
    ladev->device.get_master_volume = adev_get_master_volume;
    ladev->device.set_mode = adev_set_mode;
    ladev->device.set_mic_mute = adev_set_mic_mute;
    ladev->device.get_mic_mute = adev_get_mic_mute;
    ladev->device.set_parameters = adev_set_parameters;
    ladev->device.get_parameters = adev_get_parameters;
    ladev->device.get_input_buffer_size = adev_get_input_buffer_size;
    ladev->device.open_output_stream = adev_open_output_stream;
    ladev->device.close_output_stream = adev_close_output_stream;
    ladev->device.open_input_stream = adev_open_input_stream;
    ladev->device.close_input_stream = adev_close_input_stream;
    ladev->device.dump = adev_dump;
    /* 关键点:
     * audio_hw_device_t结构体 和 hwif(hardwareInterface)接口之间建立联系
     * 这里通过createAudioHardware 获取 实现hardwareInterface接口的厂商指针
     * 后面调用hwif的相关操作 <=等价=> 使用厂商的库函数中的方法
     */
    ladev->hwif = createAudioHardware();
    if (!ladev->hwif) {
        ret = -EIO;
        goto err_create_audio_hw;
    }
    *device = &ladev->device.common;
    return 0;
 
err_create_audio_hw:
    free(ladev);
    return ret;
}

通过上面的分析,这里从Framework Native层到HAL层框架,再到第三方平台厂商库的调用,他们之间的关系就打通了。

这里总结下loadHwModule对硬件的封装:

  • AudioFlinger : AudioHwDevice (放入mAudioHwDevs数组中)
  • audio_hw_hal.cpp : audio_hw_device
  • 厂家 : AudioHardware (派生自: AudioHardwareInterface)
  • AudioHwDevice : 对audio_hw_device的封装,
  • audio_hw_device : 函数的实现要通过AudioHardware类对象

3.2 写数据操作

  从Framework的Native层开始,audio_hw_device_t结构体首先会通过adev_open_output_stream获取audio_stream_out,因此从它开始分析。代码如下:

static int adev_open_output_stream(struct audio_hw_device *dev,
                                   audio_io_handle_t handle,
                                   audio_devices_t devices,
                                   audio_output_flags_t flags,
                                   struct audio_config *config,
                                   struct audio_stream_out **stream_out,
                                   const char *address __unused)
{
    struct legacy_audio_device *ladev = to_ladev(dev);
    status_t status;
    struct legacy_stream_out *out;
    int ret;
 
    //这里的legacy_stream_out <=结构体类型 等价=>audio_stream_out
    out = (struct legacy_stream_out *)calloc(1, sizeof(*out));
    if (!out)
        return -ENOMEM;
 
    devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
    //这里将audio_stream_out与ladev->hwif之间建立联系
    out->legacy_out = ladev->hwif->openOutputStreamWithFlags(devices, flags,
                                                    (int *) &config->format,
                                                    &config->channel_mask,
                                                    &config->sample_rate, &status);
    if (!out->legacy_out) {
        ret = status;
        goto err_open;
    }
 
    out->stream.common.get_sample_rate = out_get_sample_rate;
    out->stream.common.set_sample_rate = out_set_sample_rate;
    out->stream.common.get_buffer_size = out_get_buffer_size;
    out->stream.common.get_channels = out_get_channels;
    out->stream.common.get_format = out_get_format;
    out->stream.common.set_format = out_set_format;
    out->stream.common.standby = out_standby;
    out->stream.common.dump = out_dump;
    out->stream.common.set_parameters = out_set_parameters;
    out->stream.common.get_parameters = out_get_parameters;
    out->stream.common.add_audio_effect = out_add_audio_effect;
    out->stream.common.remove_audio_effect = out_remove_audio_effect;
    out->stream.get_latency = out_get_latency;
    out->stream.set_volume = out_set_volume;
    out->stream.write = out_write;
    out->stream.get_render_position = out_get_render_position;
    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
 
    //将out->stream写回到参数stream_out中
    *stream_out = &out->stream;
    return 0;
 
err_open:
    free(out);
    *stream_out = NULL;
    return ret;
}

这里通过hwif获取了音频输出流(audio_stream_out类型),然后对out->stream进行初始化,注册了 写入函数out_write之后将其返回给传递进来的指针变量stream_out(audio_stream_out类型),当上层进行写操作时,就会执行这个out_write函数,代码如下:

static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
                         size_t bytes)
{
    struct legacy_stream_out *out = reinterpret_cast<struct legacy_stream_out *>(stream);
    return out->legacy_out->write(buffer, bytes);
}

这里直接调用到 第三方平台厂商库的write(out->legacy_out->write)方法(如果这里是高通平台,则所谓的hwif就是AudioHardwareALSA,所谓的write就是AudioStreamOutALSA的write方法,最终会调用pcm_write进行写数据操作)。

3.3 读数据操作

  从Framework的Native层开始,audio_hw_device_t 结构体首先会通过adev_open_Input_stream获取audio_stream_in,因此从它开始分析。代码如下:

 
/** This method creates and opens the audio hardware input stream */
static int adev_open_input_stream(struct audio_hw_device *dev,
                                  audio_io_handle_t handle,
                                  audio_devices_t devices,
                                  struct audio_config *config,
                                  struct audio_stream_in **stream_in,
                                  audio_input_flags_t flags __unused,
                                  const char *address __unused,
                                  audio_source_t source __unused)
{
    struct legacy_audio_device *ladev = to_ladev(dev);
    status_t status;
    struct legacy_stream_in *in;
    int ret;
    //这里的legacy_stream_in <=结构体类型 等价=>audio_stream_in
    in = (struct legacy_stream_in *)calloc(1, sizeof(*in));
    if (!in)
        return -ENOMEM;
 
    devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
    //这里将audio_stream_in与ladev->hwif之间建立联系
    in->legacy_in = ladev->hwif->openInputStream(devices, (int *) &config->format,
                                                 &config->channel_mask, &config->sample_rate,
                                                 &status, (AudioSystem::audio_in_acoustics)0);
    if (!in->legacy_in) {
        ret = status;
        goto err_open;
    }
 
    in->stream.common.get_sample_rate = in_get_sample_rate;
    in->stream.common.set_sample_rate = in_set_sample_rate;
    in->stream.common.get_buffer_size = in_get_buffer_size;
    in->stream.common.get_channels = in_get_channels;
    in->stream.common.get_format = in_get_format;
    in->stream.common.set_format = in_set_format;
    in->stream.common.standby = in_standby;
    in->stream.common.dump = in_dump;
    in->stream.common.set_parameters = in_set_parameters;
    in->stream.common.get_parameters = in_get_parameters;
    in->stream.common.add_audio_effect = in_add_audio_effect;
    in->stream.common.remove_audio_effect = in_remove_audio_effect;
    in->stream.set_gain = in_set_gain;
    in->stream.read = in_read;
    in->stream.get_input_frames_lost = in_get_input_frames_lost;
    //将in->stream写回到参数 stream_in中
    *stream_in = &in->stream;
    return 0;
 
err_open:
    free(in);
    *stream_in = NULL;
    return ret;
}

这里通过hwif获取了音频输入流(audio_stream_in类型),然后对in->stream进行初始化,注册了 写入函数in_read 之后将其返回给传递进来的指针变量stream_in(audio_stream_in类型),当上层进行写操作时,就会执行这个in_read函数,代码如下:

static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
                       size_t bytes)
{
    struct legacy_stream_in *in =
        reinterpret_cast<struct legacy_stream_in *>(stream);
    return in->legacy_in->read(buffer, bytes);
}

这里直接调用到 第三方平台厂商库的read(out->legacy_in->read)方法(如果这里是 高通平台,则所谓的hwif就是AudioHardwareALSA,所谓的read就是AudioStreamInALSA的read方法,最终会带哦用pcm_read进行读数据操作)。

3.4 获取参数

  从Framework的Native层开始,audio_hw_device_t 结构体的获取参数的操作最后一定会调用到 adev_get_parameters,因此从它开始分析。代码如下:

static char * adev_get_parameters(const struct audio_hw_device *dev,
                                  const char *keys)
{
    const struct legacy_audio_device *ladev = to_cladev(dev);
    String8 s8;
 
    s8 = ladev->hwif->getParameters(String8(keys));
    return strdup(s8.string());
}

这里直接调用到第三方平台厂商库的getParameters方法。

3.5 设置参数

  从Framework的Native层开始,audio_hw_device_t 结构体的设置参数的操作最后一定会调用到 adev_set_parameters,因此从它开始分析。代码如下:

static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
{
    struct legacy_audio_device *ladev = to_ladev(dev);
    return ladev->hwif->setParameters(String8(kvpairs));
}

这里直接调用到第三方平台厂商库的setParameters方法。

3.6 总结

  • 从配置文件确定库文件的名字。 HAL文件一般位于/system/lib/hardware下面,音频中操作硬件的库文件名称在(厂商提供的HAL部分)在/system/etc/policy_config中指定。
  • 加载库(*.so)文件。打开HAL文件中的open函数,在HAL中会构造audio_hw_device结构体, 该结构体中有各类函数, 特别是 open_output_stream / open_input_stream。AudioFlinger根据audio_hw_device结构体构造一个AudioHwDev对象并放入mAudioHwDevs。
  • 调用HAL结构体audio_hw_device的open_input_stream/open_output_stream,它会构造audio_stream_in/audio_stream_out结构体。
  • 写入/读出数据,调用tinyALSA的一些操作,直接使用系统调用控制声卡的是tinyalsa库,位于目录/external/tinyalsa下,编译生成库文件libtinyalsa.so(只涉及两个文件mixer.c,pcm.c),编译生成工具 tinycap,tinymix,tinypcminfo,tinyplay,可用于直接控制音频通道,进行录音播音测试。使用pcm_XXX操作来操作声卡,是驱动层的封装。
  • tinyALSA库再操作音频驱动程序,音频驱动程序再操作硬件声卡设备。