基于Android 9.0
1.概述
本章节主要关注以上思维导图左上HAL层分析部分即可。主要说明了HAL层的框架分析,后面通过源码分析了读音频数据流程、写音频数据流程、设置参数流程、获取参数流程 来深入的理解 HAL层的调用流程。
2.HAL层框架分析
音频系统的整个框架图如下所示:
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库再操作音频驱动程序,音频驱动程序再操作硬件声卡设备。