audio代码比较复杂,除了音频参数,我们平时客制化的地方不多。所以没有太深入了解。
建议先抽空看看如下代码:
kernel, linux alsa 架构:
kernel-3.10/sound/soc/mediatek/
kernel-3.10/Documentation/sound/alsa/soc/
android 上层alsa接口
external/tinyalsa/
hal:
vendor/mediatek/proprietary/platform/common/hardware/audio/
vendor/mediatek/proprietary/platform/mt6735/hardware/audio/
andorid audio flinger:
frameworks/av/services/audioflinger/
tinyalsa位于Android源码的external/tinyalsa位置。
关于alsa在Android中,在Android 4.0及之后只要你愿意还是可以使用原版alsa的,因为内核中依然是使用alsa的驱动,只需要把alsa的用户层接口alsa-lib移植到源码中即可。
tinyalsa中主要的头文件和数据结构如下,通过ioctrl和内核的alsa驱动交互。
pcm设备,通过阅读tinyalsa的代码和查看Android下的音频设备节点,可知在Android中一个pcm设备最多可有一个mixer设备"/dev/snd/controlC%u"(一般是controlC0)和32个/dev/snd/pcmC%uD%uc(一般是pcmC0D0c)、/dev/snd/pcmC%uD%u%p
(一般是pcmC0D0p),pcm设备中的C代表card,D代表device,c代表capture,p代表playback。当我们新增一个pcm声卡C的值会+1,D还是从0开始,可能只有c(pcmC1D0c 例如麦克风),可能只有p(pcmC1D0p 例如音响
),可能同时存在c和p(
pcmC1D0c
pcmC1D0p
)。
tinyalsa的对外提供的头文件就我上图提到的一个"
asoundlib.h",提供最基础的pcm和mixer操作。实现文件为
pcm.c(实现pcm api)和mixer.c(实现mixer api)。根据asoundlib.h编写了四个小工具
tinypcminfo tinyplay tinycap tinymix,这四个小工具作为系统命令存放在系统中,可以很方便的使用。tinyasla作为精简版的alsa-lib可能会有人想把它移植到Linux使用,
tinyasla
依赖的库有libcutils && libutils,如果能把依赖的这两个库的一些方法使用Linux接口实现那么剩下的问题应该不大了吧,这个仅仅是我的猜想。
tinypcminfo的实现文件
tinypcminfo.c (查看pcm设备能力)
tinyplay的实现文件
tinyplay.c(使用pcm设备播放wav格式的音频文件)
tinycap的实现文件
tinycap.c(使用pcm设备采集pcm格式的码流,并保存为wav格式的文件)
tinymix的实现文件
tinymix.c(对pcm设备的控制,包括音量调节、设备切换)
这几个命令使用时可以先使用tinypcminfo查看pcm设备的能力,要不当我们使用其他三个命令时使用了不合理的配置会出现parameter invalid的错误。
PCM API
/* 对pcm设备节点的操作 */
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设备的能力 */
struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, unsigned int flags);
void pcm_params_free(struct pcm_params *pcm_params);
unsigned int pcm_params_get_min(struct pcm_params *pcm_params, enum pcm_param param);
unsigned int pcm_params_get_max(struct pcm_params *pcm_params, enum pcm_param param);
/* 配置pcm设备capture和playback的规格 */
int pcm_get_config(struct pcm *pcm, struct pcm_config *config);
int pcm_set_config(struct pcm *pcm, struct pcm_config *config);
/* 返回调用tinyalsa最后的错误信息 */
const char *pcm_get_error(struct pcm *pcm);
/* 设置pcm设备采集和播放的位数,位数越高越接近真实声音 */
unsigned int pcm_format_to_bits(