当前位置: 首页 > news >正文

Android tinyalsa库函数剖析

1. PCM 流控制函数

打开、关闭及状态检查

  • pcm_open(unsigned int card, unsigned int device, unsigned int flags, struct pcm_config *config)
    打开指定声卡(card)和设备(device)的 PCM 流。

    • flags 参数确定流的方向:例如 PCM_IN(录音)或 PCM_OUT(回放)。
    • config 参数为一个结构体,内含通道数、采样率、数据格式、周期大小与周期数等设置。
    • 成功后返回一个 struct pcm * 句柄,用于后续的数据传输操作。
  • pcm_close(struct pcm *pcm)
    关闭之前通过 pcm_open() 打开的 PCM 句柄,释放资源。

  • pcm_is_ready(struct pcm *pcm)
    判断 PCM 流是否已成功打开并处于可用状态。返回非零表示出错或不可用,通常在打开后立即检查以确保后续操作是安全的。


2. PCM 参数管理函数

为了判断硬件支持哪些采样参数,你可以获取 PCM 的能力信息:

  • pcm_params_get(unsigned int card, unsigned int device, unsigned int flags)
    获取指定 PCM 设备的参数集合,返回一个 struct pcm_params *。该结构体中包含了硬件支持的采样率、格式、周期大小等参数范围。

  • pcm_params_free(struct pcm_params *pcm_params)
    释放由 pcm_params_get() 分配的参数信息结构体。

  • 参数查询和设置函数:

    • pcm_params_get_mask(struct pcm_params *pcm_params, enum pcm_param param)
      获取某个参数(如采样率、格式)的支持情况(一个 bit mask)。
    • pcm_params_get_min() / pcm_params_get_max()
      分别获取某个参数所支持的最小或最大值。
    • pcm_params_set_min() / pcm_params_set_max()
      为参数设置新的最小或最大值(一般用于定制或者限制范围)。
  • pcm_params_to_string(struct pcm_params *params, char *string, unsigned int size)
    将参数信息转换为人类可读的字符串,便于调试或者日志输出。返回填充字符串的长度或所需的长度。

  • pcm_params_format_test(struct pcm_params *params, enum pcm_format format)
    检查特定的 PCM 格式(例如 PCM_FORMAT_S16_LE)是否在支持的格式中,返回 1 表示支持,0 表示不支持。


3. PCM 配置操作

有时需要在流打开后获取或调整当前使用的配置:

  • pcm_get_config(struct pcm *pcm, struct pcm_config *config)
    从已打开的 PCM 流中获取当前的配置信息(例如实际启用的通道数、采样率、缓冲区设置等)。

  • pcm_set_config(struct pcm *pcm, struct pcm_config *config)
    修改已经打开的 PCM 流的配置(如果硬件和驱动支持动态调整的话)。


4. 错误信息、格式转换及辅助函数

  • pcm_get_error(struct pcm *pcm)
    返回一个字符串,描述最近一次调用出错时的错误原因,用于调试和错误处理。

  • pcm_format_to_bits(enum pcm_format format)
    返回所使用 PCM 格式的存储位数。例如,对于 PCM_FORMAT_S24_LE,可能返回 32,因为实际存储 32 位数据(尽管只有 24 位有效)。

  • 缓冲区大小转换函数:

    • pcm_get_buffer_size(struct pcm *pcm)
      得到当前 PCM 流推荐使用的总缓冲区大小(单位:帧)。通常总帧数 = period_size * period_count
    • pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames)
      将帧数转换为字节数(考虑到每帧的采样数据大小,依赖通道数和采样格式)。
    • pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes)
      将字节数转换回帧数。
  • pcm_get_latency(struct pcm *pcm)
    返回当前 PCM 流的延迟(以毫秒为单位)。延迟值与缓冲区配置(总大小、采样率等)直接相关。

  • pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail, struct timespec *tstamp)
    获取当前缓冲区状态——返回流中可用帧数以及与之关联的时间戳。

    • 对于输入流,这表示可供应用读取的帧数。
    • 对于输出流,这表示还空闲(可写)的帧数。
  • pcm_get_subdevice(struct pcm *pcm)
    返回实际打开时使用的子设备编号,有些硬件可能提供多个子设备用于并发操作。


5. 数据传输操作

标准读写接口

  • pcm_read(struct pcm *pcm, void *data, unsigned int count)
    从 PCM 输入流(或录音设备)中读取数据。

    • count 参数通常是以字节为单位,读取的数据量应与 pcm_frames_to_bytes() 计算出的单个周期数据一致。
    • 返回值为 0 表示成功,否则返回负值错误码。
  • pcm_write(struct pcm *pcm, const void *data, unsigned int count)
    将数据写入 PCM 输出流(或播放设备):

    • 类似于 pcm_read()count 表示写入的数据量(单位:字节)。
    • 写入操作会触发硬件播放,如果处于中断恢复状态时(例如 FIFO underrun 后)可能会重新启动播放。

内存映射(mmap)接口

直接使用内存映射技术可以降低数据传输的延迟和 CPU 占用:

  • pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, unsigned int *frames)
    获取 PCM 设备内存映射缓冲区的起始地址、当前偏移量以及可操作的帧数。
  • pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames)
    提交写入或读取的数据,更新缓冲区状态。
  • pcm_mmap_write()pcm_mmap_read()
    分别用于直接向缓冲区写数据或从缓冲区读取数据,代替标准的 pcm_write()pcm_read()
  • pcm_mmap_avail(struct pcm *pcm)
    返回当前缓冲区中可供写入或读取的帧数。
  • pcm_mmap_get_hw_ptr(struct pcm* pcm, unsigned int *hw_ptr, struct timespec *tstamp)
    获取当前硬件指针的位置以及它所对应的时间戳,用于同步时钟或进一步的数据处理。

6. 流状态控制和事件接口

  • pcm_prepare(struct pcm *pcm)
    准备 PCM 子流,使其处于可触发状态。常用于在播放或录音前执行预处理(例如重置缓冲区)。

  • pcm_start(struct pcm *pcm)
    启动 PCM 子流进行数据传输,适用于那些不自动启动数据传输的设备或在调用 pcm_write()/pcm_read() 之前要明确启动的数据流。

  • pcm_stop(struct pcm *pcm)
    停止 PCM 子流的数据传输,常用于结束一段播放或录音过程。

  • pcm_ioctl(struct pcm *pcm, int request, ...)
    通过 ioctl 调用发送控制命令给 PCM 驱动,允许更底层的控制和调整,这是更底层的设备操作接口。

  • 事件与等待相关:

    • pcm_wait(struct pcm *pcm, int timeout)
      等待 PCM 设备准备好数据(例如,等待缓冲区有足够数据可读或者有足够空闲帧可写)。
    • pcm_get_poll_fd(struct pcm *pcm)
      得到可以用于 poll()select() 的文件描述符,以便与其他事件循环集成。
    • pcm_set_avail_min(struct pcm *pcm, int avail_min)
      修改在触发 PCM 数据传输前,缓冲区最小应达到的帧数。如果使用 MMAP 模式而且禁用了 IRQ,此设置尤其重要用于降低延迟。

7. Mixer(混音器)控制接口

TinyALSA 同时提供了对硬件混音器的基本控制接口,用于调整音量、开关、通道切换等。

打开、关闭及 Mixer 信息

  • mixer_open(unsigned int card)
    打开指定声卡的混音器设备,返回表示 mixer 的句柄结构。
  • mixer_close(struct mixer *mixer)
    关闭并释放混音器资源。
  • mixer_get_name(struct mixer *mixer)
    获取混音器的名称,通常用于调试或显示硬件信息。

获取混音器控制(Control)

  • mixer_get_num_ctls(struct mixer *mixer)
    返回混音器中包含多少个可控的控件。
  • mixer_get_ctl(struct mixer *mixer, unsigned int id)mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
    通过控件的索引或名称获取某个具体的混音器控制对象。
  • mixer_ctl_get_name(struct mixer_ctl *ctl)
    获取某个混音器控制项的名称。

混音器控件的属性与操作

  • 类型和枚举检查:

    • mixer_ctl_get_type() / mixer_ctl_get_type_string()
      返回控制项的数据类型(例如整数、布尔值、枚举等)。
    • mixer_ctl_get_num_values(struct mixer_ctl *ctl)
      一个控制项可能有多个值,返回值的数量。
    • mixer_ctl_get_num_enums()mixer_ctl_get_enum_string()
      针对枚举类型的控制项,获取枚举数目及对应的字符串名称。
  • 控件数据的获取与设置:

    • mixer_ctl_get_value()mixer_ctl_set_value()
      用于直接获取或设置控制项的具体值。
    • mixer_ctl_get_percent()mixer_ctl_set_percent()
      针对音量等控件,允许以百分比形式获取或设置值。
    • mixer_ctl_get_array()mixer_ctl_set_array()
      用于读取或设置控件的数组数据(适合多通道或复合控件)。
    • mixer_ctl_set_enum_by_string()
      针对枚举控件,通过输入字符串来设置控制值。
  • 范围控制:

    • mixer_ctl_get_range_min() / mixer_ctl_get_range_max()
      获取混音器控件支持的最小或最大值,这对限制控制设置非常有用。

混音器事件支持

  • mixer_subscribe_events(struct mixer *mixer, int subscribe)
    允许应用订阅或取消订阅混音器事件(例如,外部变化触发控制更新)。
  • mixer_wait_event(struct mixer *mixer, int timeout)
    等待混音器事件的发生。
  • mixer_consume_event(struct mixer *mixer)
    消费已经发生的事件,确保事件不会被重复处理。

小结

  • PCM 流相关的函数pcm_openpcm_closepcm_readpcm_write 等)主要负责数据传输的初始化、实时读写操作及状态管理。
  • 参数管理、配置和转换函数(例如 pcm_params_getpcm_frames_to_bytes 等)帮助开发者在运行时查询硬件能力、进行单位转换以及调试配置。
  • 高级数据传输接口(如 pcm_mmap_* 系列函数)提供了直接内存映射方式,可用于降低延迟和优化性能。
  • Mixer 接口 则提供了对硬件混音器(如音量、通道路由、开关等)的操作,以便对声音输入输出进行更细粒度的控制。

相关文章:

  • 几款开源C#插件框架
  • 2025年山东燃气瓶装送气工考试真题练习
  • 单调队列模板cpp
  • Java漏洞原理与实战
  • RT-DETR源码学习bug记录
  • 51单片机实验七:EEPROM AT24C02 与单片机的通信实例
  • 【系统架构设计师】统一过程模型(RUP)
  • python 对接支付宝账单流程及问题处理
  • 告别Feign:基于Spring 6.1 RestClient构建高可用声明式HTTP客户端
  • VUE快速入门-4:简单入门案例
  • postman使用设置
  • ChatGPT-o3辅助学术写作的关键词和引言效果如何?
  • 解锁古籍中的气候密码,探索GPT/BERT在历史灾害研究中的前沿应用;气候史 文本挖掘 防灾减灾;台风案例、干旱案例、暴雨案例
  • 面试面试面试new
  • docker 安装prometheus普罗米修斯
  • 疑难问题解决(2)
  • git常用的命令
  • CSS 美化页面(五)
  • PD分离:优化大语言模型推理效率
  • MDA测量数据查看器【内含工具和源码地址】
  • 天工机器人获首个人形机器人半马冠军
  • 杭州:调整个人购买家庭住房享受契税优惠住房套数查询规则
  • 礼来公布口服降糖药积极结果,或年底前提交用于体重管理上市申请
  • 全球建筑瞭望|与自然共呼吸的溪谷石舍与海边公共空间
  • 俄最高法宣布解除针对阿富汗塔利班的禁令
  • 国际秩序危机下,德国如何重塑欧洲地缘政治