Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9464086
  • 博文数量: 1750
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 20091
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1750)

文章存档

2024年(26)

2023年(26)

2022年(112)

2021年(217)

2020年(157)

2019年(192)

2018年(81)

2017年(78)

2016年(70)

2015年(52)

2014年(40)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: Android平台

2014-07-26 11:32:11



TinyAlsa
是 Android 默认的 alsalib, 封装了内核 ALSA 的接口,用于简化用户空 间的 ALSA 编程。

设计目标

TinyAlsa的设计目标是:

  • Provide a basic pcm and mixer API.
  • If it’s not absolutely needed, don’t add it to the API.
  • Avoid supporting complex and unnecessary operations that could be dealt with at a higher level.

可以看出,TinyAlsa是个很轻量级的库,很容易让我们一窥究竟。

接口

在include/asoundlib.h头文件里声明了TinyAlsa的所有接口。

/* Open and close a stream */
struct pcm *pcm_open(unsigned int card, unsigned int device,
                 unsigned int flags, struct pcm_config *config);
int pcm_close(struct pcm *pcm);
int pcm_is_ready(struct pcm *pcm);
/* PCM API*/
int pcm_write(struct pcm *pcm, const void *data, unsigned int count);
int pcm_read(struct pcm *pcm, void *data, unsigned int count);
int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count);
int pcm_set_avail_min(struct pcm *pcm, int avail_min);
/* MIXER API */
mixer_ctl_get_XX(struct mixer_ctl *ctl);
mixer_ctl_set_XX(struct mixer_ctl *ctl); 

头文件没有暴露struct pcm的内部成员,这意味着调用者只能使用它的API对音频设备 访问。 在播放操作时,pcm_mmap_write()比pcm_write()减少了内存拷贝的开销,但 由于它需要增加系统调用来同步数据指针,在缓冲区小的情况下,效率不一定总是更高, 但它提供了更好的灵活性。

用户配置

合理的pcm_config可以做到更好的低时延和功耗,移动设备的开发优为敏感。

struct pcm_config {
    unsigned int channels;
    unsigned int rate;
    unsigned int period_size;
    unsigned int period_count;
    enum pcm_format format;
    unsigned int start_threshold;
    unsigned int stop_threshold;
    unsigned int silence_threshold;
    int avail_min;
}; 

解释一下结构中的各个参数,每个参数的单位都是frame(1帧 = 通道*采样位深):

  • period_size. 每次传输的数据长度。值越小,时延越小,cpu占用就越高。
  • period_count. 缓之冲区period的个数。缓冲区越大,发生XRUN的机会就越少。
  • format. 定义数据格式,如采样位深,大小端。
  • start_threshold. 缓冲区的数据超过该值时,硬件开始启动数据传输。如果太大, 从开始播放到声音出来时延太长,甚至可导致太短促的声音根本播不出来;如果太小, 又可能容易导致XRUN.
  • stop_threshold. 缓冲区空闲区大于该值时,硬件停止传输。默认情况下,这个数 为整个缓冲区的大小,即整个缓冲区空了,就停止传输。但偶尔的原因导致缓冲区空, 如CPU忙,增大该值,继续播放缓冲区的历史数据,而不关闭再启动硬件传输(一般此 时有明显的声音卡顿),可以达到更好的体验。
  • silence_threshold. 这个值本来是配合stop_threshold使用,往缓冲区填充静音 数据,这样就不会重播历史数据了。但如果没有设定silence_size,这个值会生效吗? 求解??
  • avail_min. 缓冲区空闲区大于该值时,pcm_mmap_write()才往缓冲写数据。这个 值越大,往缓冲区写入数据的次数就越少,面临XRUN的机会就越大。Android samsung tuna 设备在screen_off时增大该值以减小功耗,在screen_on时减小该 值以减小XRUN的机会。

在不同的场景下,合理的参数就是在性能、时延、功耗等之间达到较好的平衡。

实现

有朋友问为什么在pcm_write()/pcm_mmap_write(),而不在pcm_open()调用 pcm_start()? 这是因为音频流与其它的数据不同,实时性要求很高。作为 TinyAlsa的实现者,不能假定在调用者open之后及时的write数据,所以只能在有 数据写入的时候start设备了。

Mixer的实现很明了,通过ioctl()调用访问kcontrols.

TinyAlsa说复杂的操作应该由上层来处理,可能指的是重采样、插件功能等。但由于 不能直接访问声卡设备,以至于要添加一些功能,如非阻塞打开声卡等,只能修改它的 源代码才能实现。导出pcm的文件描述符就有那么难么?

~EOF~
阅读(6630) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~