Gentoo Linux ALSA 指南
ALSA Main Page
Linux音频驱动之二:声卡的创建
Android深入浅出之Audio 第一部分 AudioTrack分析
Android深入浅出之Audio 第二部分 AudioFlinger分析
Android深入浅出之Audio第三部分Audio Policy[1]
audio系统主要分为以下几个层次:
1.media库提供的Audio系统本地部分接口
2.AudioFlinger作为Audio系统的中间层
3.Audio的硬件抽象层提供底层支持
4.Audio通过JNI和java框架提供给上层
以上各个层次抽象成:放音(Track)和录音(Recorder)两个部分。
Java Audio Class(java 框架层) -> Audio JNI(Audio 本地API) -> libmedia -->libaudioflinger.so -->AudioHardwareInterface? --> libaudio.so --> alsa以上的Audio 各个层次都使用一个管理类,和输入输出两个类来表示整个系统。各个层次的目录为:
1 Java 层:frameworks/base/media/java/android/media
2 JNI部分:frameworks/base/core/jni
3 libmedia:frameworks/base/media/libmedia
4 AudioFlinger:frameworks/base/libs/audioflinger
5 AudioHardwareInterface(硬件接口层):hardware/alsa_sound
6 底层:ALSA
在Android中,使用ALSA的api编写了libaudio.so
简介 A card record is the headquarters of the soundcard.这个结构体管理包括PCM、MIDI、mixers、synthesizer在内的声卡设备,并且保存有声卡的ID、声卡的名字(strings)、proc文件、PM以及热插拔管理。
1、 在文件intelmid.c中,下半部分是一个SPI总线的初始化部分,注册一个名为DRIVER_NAME("pmic_audio"@intelmid.h),结构体为snd_intelmad_driver的SPI设备。
2、 然后,通过snd_intelmad_driver中的probe函数。
1> 初始化指向snd_intelmad结构体的指针intelmaddata;
2> 并创建了一个声卡设备:snd_card_create(card_index, card_id, THIS_MODULE, 0, &card);------struct snd_card *card;
3> snd_intelmad_sst_register(intelmaddata);注册一个sst_card,时期能够调用SST的API;
4> 初始化PCM实例、mixer和jack;
5> INIT_WORK(&intelmaddata->mad_jack_msg.wq,sst_process_mad_jack_detection);intelmaddata->mad_jack_wq = create_workqueue("sst_mad_jack_wq");
6> snd_intelmad_register_irq(intelmaddata);
7> snd_intelmad_create(intelmaddata, card);------snd_device_new(card, SNDRV_DEV_LOWLEVEL, intelmaddata, &ops);(attach the components (devices) to the card instance.)
8> 关联与注册声卡设备nd_card_set_dev(card, &spi->dev);snd_card_register(card);
程序说明:
ALSA driver for Intel MID sound card chipset
#include "intelmid_snd_control.h"
#include "intelmid.h"
#include "intelmid_ctrl.h"
module_param : card_index,card_id
int sst_card_vendor_id;
结构体:
struct snd_pcm_hardware snd_intelmad_stream:info:interleaved PCM格式,双声道,支持PAUSE,RESUME,MMAP,两个OSS参数,PCM子流支持同步
.formats .rates .rate_min .rate_max .channels_min .channels_max(单声道或者双声道)
.buffer_bytes_max (MAX_BUFFER 128*1024)
.periodxxxx
//The “period” is a term that corresponds to a fragment in the OSS world. The period defines the size at which a PCM interrupt is generated.
//This size strongly depends on the hardware. Generally, the smaller period size will give you more interrupts, that is, more controls.
//In the case of capture, this size defines the input latency. On the other hand, the whole buffer size defines the output latency for the playback direction.
struct snd_pcm_ops snd_intelmad_playback_ops 与 snd_intelmad_capture_ops
当创建PCM实例后(snd_pcm_new(),一般使用一个函数来调用这个),要将PCM子流与其对应的操作关联起来,上面这两个结构体就是做这个用的。
本程序结构:
本程序是一个SPI结构:
static struct spi_driver snd_intelmad_driver = {
.driver = {
.name = DRIVER_NAME,
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = snd_intelmad_probe,
.remove = __devexit_p(snd_intelmad_remove),
};
/*This function is called when the device is initialized(在注册的时候就调用了)*/
snd_intelmad_probe->snd_card_create
填充intelmaddata结构体
snd_intelmad_sst_register
snd_intelmad_pcm
snd_intelmad_jack
snd_intelmad_mixer
INIT_WORK
snd_intelmad_register_irq
snd_intelmad_create
snd_card_set_dev:
1、snd_intelmad_sst_register:
从芯片读vendor_id,
处理intelmaddata->sstdrv_ops(module_name, vendor_id, scard_ops),通过各个函数初始化sstdrv_ops所有成员
scard_ops:这个结构体与实际的vendor_id对应的数据结构相连:intelmaddata->sstdrv_ops->scard_ops = intelmad_vendor_ops[sst_card_vendor_id];
假如vendor_id为2则通过intelmid_ctrl.c的结构体intelmad_vendor_ops映射到intelmid_v2_control.c上文件最后的结构体snd_pmic_ops_nc中。
/* registering with SST driver to get access to SST APIs to use */
intelmaddata->pmic_status为未初始化状态
2、snd_intelmad_pcm: set up pcm params and functions
snd_pcm_new(card, name, i, PLAYBACK_COUNT, CAPTURE_COUNT, &pcm):PCM实例的构造函数:第一个参数指定将要构造的实例,第二个参数是ID字符串,第三个参数是PCM的index
第四个和第五个参数是playback和capture的个数, 第六个参数是&pcm
/* setup the ops for playback and capture streams */
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intelmad_playback_ops);固定形式,将pcm和后面的结构体相关联,该结构体执行相对的操作
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intelmad_capture_ops);
/* setup private data which can be retrieved when required */
/* allocate dma pages for ALSA stream operations */
3、snd_intelmad_jack:to setup jack settings of the card[Google: ALSA JACK]
4、snd_intelmad_mixer
ret_val = snd_ctl_add(card, snd_ctl_new1(&snd_intelmad_controls[idx], intelmaddata));创建一个声卡控制接口
工作队列:
本驱动程序结构使用到了linux中的中断上半部和下半部的应用,使用了工作队列:
snd_intelmad_probe-->INIT_WORK(&intelmaddata->mad_jack_msg.wq, sst_process_mad_jack_detection);
intelmaddata->mad_jack_wq = create_workqueue("sst_mad_jack_wq");创建自己的工作队列
snd_intelmad_intr_handler-->queue_work(intelmaddata->mad_jack_wq, &intelmaddata->mad_jack_msg.wq);
工作队列通过vendor_id来调用相应的工作的函数:这里是sst_mad_jackdetection_nec(intsts,intelmaddata);根据当前工作状态的标记intsts进行相应的操作。 然后载调用函数sst_mad_send_jack_report(struct snd_jack *jack, int buttonpressevent , int status)
ALSA:
snd_intelmad_pcm_trigger:This function is called whenever an a stream activity is invoked
Driver for Langwell IPC1
部分audio寄存器自己尝试使用默认与auto配置就好