ALSA声卡12_从零编写之添加音量控制_学习笔记
1、設置音量時應用程序的調用過程
(1)strace分析: amixer cset numid=1 30?(設置音量)
/dev/snd/controlC0
open
SNDRV_CTL_IOCTL_CARD_INFO
SNDRV_CTL_IOCTL_PVERSION
SNDRV_CTL_IOCTL_ELEM_INFO
SNDRV_CTL_IOCTL_ELEM_READ
SNDRV_CTL_IOCTL_ELEM_WRITE?: snd_ctl_elem_write_user
(2)應用程序調用SNDRV_CTL_IOCTL_ELEM_WRITE時,驅動程序調用snd_ctl_elem_write_user函數,這個函數從用戶空間把一些參數拷貝進來,然后調用函數snd_ctl_elem_write
(3)函數snd_ctl_elem_write
找到一個snd_kcontrol結構體,然后調用snd_control結構體的put函數。
(4)這個snd_kcontrol結構體是誰提供的
ASOC驅動程序分為3大塊(machine,codec,platform),應該在codec這一塊來提供的,因為它跟聲卡密切相關。去調節音量的時候肯定要調整它
2、寫程序(uda1341.c(codec))
(1)結構體snd_kcontrol_new
static const struct?snd_kcontrol_new?uda1341_vol_control =?
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,?//表示snd_kcontrol結構體用于哪一類設備(表示進行參數設置)
? ? .name = "Master Playback Volume", ?//音量控制,每個聲卡驅動程序的snd_kcontrol各不相同,為什么應用程序都可以調整它的音量,對于某些常用的屬性,它們都有固定的名字。應用程序根據名字找到它的snd_kcontrol項,調用里面的put函數。
.info = uda1341_info_vol, ?//獲得一些信息,如音量范圍是多少
.get ?= uda1341_get_vol,//獲得當前的音量值
.put ?= uda1341_put_vol,?//設置音量
};
(2)?獲得音量信息,比如最小值最大值
/*
?* 獲得音量信息,比如最小值最大值
?*/
int uda1341_info_vol(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;//音量值的類型是整數
uinfo->count = 2;//聲道數是雙聲道的
uinfo->value.integer.min = 0;//最小整數,
uinfo->value.integer.max = 63;//最大整數,
return 0;
}
因為uda1341的音量控制是6位的(0表示最大音量,63表示最小音量),而應用程序中0表示最小音量,值越大表示音量越大
(3)獲得當前音量值
/*
?* 獲得當前音量值
?*/
int uda1341_get_vol(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
? ? ucontrol->value.integer.value[1] = \ ?//這里?\ ?表示ucontrol->value.integer.value[0] 等于ucontrol->value.integer.value[1] ,因為是雙聲道
ucontrol->value.integer.value[0] = 63 - snd_soc_read(codec, UDA1341_DATA00);//讀寄存器DAT00的值,因為驅動程序的值和應用程序的值大小是相反的,uda1341不支持寄存器的讀操作,要想得到一個寄存器的值,是去讀某個cache(這個cache保存的是設置寄存器的值)
return 0;
}
(4)?設置當前音量值
/*
?* 設置當前音量值
?*/
int uda1341_put_vol(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int val;
val = 63 - ucontrol->value.integer.value[0];//應用程序傳進來的值寫到寄存器里面要反轉
? ? snd_soc_write(codec, UDA1341_DATA00, val);//把值val寫到寄存器DATA00中去
? ??
return 0;
}
3、結構體snd_kcontrol_new和內核部分的連接
(1)probe函數
static int uda1341_soc_probe(struct snd_soc_codec *codec)
{
? ? int ret;
? ? uda1341_init_regs(codec);
? ??
ret = snd_soc_add_codec_controls(codec, &uda1341_vol_control, 1);
? ? return ret;
}
4、測試
amixer ?controls查看控制項
amixer cget numid=1表示查看當前音量
amixer cset numid=1 30設置音量
5、Input Mux
因為不同的板子的麥克風通道不同(在uda1341),用同一驅動,想錄音時應用程序應該設置input mux選項。
表明它能選擇哪個麥克風通道,當前是哪一個麥克風通道,設置哪一個麥克風通道
值uda134x_mixer_enum[2]是數組的第2項
6、
讓板子使用內核自帶的驅動程序
查看設備節點和控制項(input mux在倒數第二項)
查看控制項第11項的值(當前值是0)
若選擇第1個通道(模擬通道)最后1個參數表明第幾個通道
轉載于:https://www.cnblogs.com/alan666/p/8311864.html
總結
以上是生活随笔為你收集整理的ALSA声卡12_从零编写之添加音量控制_学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux内核移植imx8,NXP iM
- 下一篇: Hadoop之Hbase安装和配置