1,说明
本文主要是对Android平台下,如何利用tinyalsa库接口实现audio paly 和audio record.
2,基本知识介绍
2.1 Android audio 框架
这个很多人有描述,基本就是audioframework<——>audio hal<——>tinyalsa<——>alsa驱动
audioframework:这个主要是给上层app提供接口和audio policy管理
audio hal:这个主要是厂家实现,提供audio path的控制,audio 逻辑设备到物理设备的映射,audio校准参数的加载等等
2,2 tinyalsa
这个是alsa库在Android上面的迷你实现,封装了内核alsa接口,和alsa驱动打交道,简化用户空间编程
。
Android 代码目录external/tinyalsa/
2.3 pcm_config
/* Configuration for a stream */
struct pcm_config {
unsigned int channels;
unsigned int rate;
unsigned int period_size;
unsigned int period_count;
enum pcm_format format;
/* Values to use for the ALSA start, stop and silence thresholds. Setting
* any one of these values to 0 will cause the default tinyalsa values to be
* used instead. Tinyalsa defaults are as follows.
*
* start_threshold : period_count * period_size
* stop_threshold : period_count * period_size
* silence_threshold : 0
*/
unsigned int start_threshold;
unsigned int stop_threshold;
unsigned int silence_threshold;
/* Minimum number of frames available before pcm_mmap_write() will actually
* write into the kernel buffer. Only used if the stream is opened in mmap mode
* (pcm_open() called with PCM_MMAP flag set). Use 0 for default.
*/
int avail_min;
};
audio frame count: period_size × period_count
audio fame:channle × sample bytes
pcm类似于文件描述符,不过表示audio stream
3,API介绍
struct pcm *pcm_open(unsigned int card, unsigned int device, unsigned int flags, struct pcm_config *config);
int pcm_write(struct pcm *pcm, const void *data, unsigned int count); //返回0表示成功
int pcm_read(struct pcm *pcm, void *data, unsigned int count);//返回0表示成功
int pcm_close(struct pcm *pcm);
4,一个实际的项目
在Firefox OS上面需实现开机铃声,在播放开机画面的时候,audio hal层还没有初始化,意味着只能
直接利用pcm接口来进行处理。
部分代码
if(set_mixer()){ //设置audio path
ALOGE("set_mixer error\n");
return -1;
}
file = fopen(filename, "rb"); //打开开机铃声
if (!file) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
return 1;
}
config.channels = channels;
config.rate = rate;
config.period_size = period_size;
config.period_count = period_count;
if (bits == 32)
config.format = PCM_FORMAT_S32_LE;
else if (bits == 16)
config.format = PCM_FORMAT_S16_LE;
config.start_threshold = 0;
config.stop_threshold = 0;
config.silence_threshold = 0;
if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) {
return;
}
pcm = pcm_open(card, device, PCM_OUT, &config);
if (!pcm || !pcm_is_ready(pcm)) {
fprintf(stderr, "Unable to open PCM device %u (%s)\n",
device, pcm_get_error(pcm));
return;
}
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
buffer = malloc(size);
if (!buffer) {
fprintf(stderr, "Unable to allocate %d bytes\n", size);
free(buffer);
pcm_close(pcm);
return;
}
pcm_write(pcm, buffer, num_read))
free(buffer);
pcm_close(pcm);
5,一个稍微负责的项目需求
在Firefox上面移植Nuance的音频引擎,实现引擎实时获取pcm数据流。
1,根据Nuance提供的api.h文件实现so库
2,so库主要处理好pcm的实时处理,避免overun问题