基于ALSA库实现音量调节
ALSA库实现音量调节
1、使用alsamixer工具查看音频接口
首先可以通过alsamixer工具图形化查看声卡的接口名,也可以使用该工具通过图形尝试调节音频大小,能帮助你后面更好的实现从应用层去调节,直接输入alsamixer
即可自动弹出图形界面,如下图,Speaker是我播放的元素名称,上面的55是音量大小,通过键盘的上下键即可调节大小,这两个参数在后面应用层时都会用到:
2、完整代码
2.1、snd_mixer_open
- 打开并实例化一个空的混音器
2.2、snd_mixer_attach、
- 连接到选择的声卡控制设备
2.3、snd_mixer_selem_register
- 注册混音器
int snd_mixer_selem_register(
snd_mixer_t *mixer,
struct snd_mixer_selem_regopt *options,
snd_mixer_class_t **classp);
2.4、snd_mixer_load
- 加载混音器
2.5、snd_mixer_first_elem/snd_mixer_elem_next
- 找到混音器的第一个元素/查找下一个元素
2.6、snd_mixer_selem_get_playback_volume_range/snd_mixer_selem_get_capture_volume_range
- 获取指定元素的音量范围
int snd_mixer_selem_get_playback_volume_range(
snd_mixer_elem_t *elem,
long *min,
long *max);
int snd_mixer_selem_get_capture_volume_range(
snd_mixer_elem_t *elem,
long *min,
long *max);
2.7、snd_mixer_selem_set_playback_volume_all
- 一次性设置指定元素所有声道的音量
3、完整程序
下面的函数实现音量的获取和调节,通过ALSA库的API接口,注册一个混音器设备对象,使用该对象连接到想要控制的声卡,然后开始查找该声卡中的元素,找到想要控制的元素,然后对元素进行get和set,本函数实现对Speaker元素的调节控制扬声器声音大小,通过应用程序调节完音量后,可以使用alsamixer工具查看音量是否成功调节。
/* volume control init */
void volume_control_init(void)
{
snd_mixer_t *mixer;
snd_mixer_elem_t *elem;
debug_msg(snd_mixer_open(&mixer,0),"opening mixer"); // 打开混音器设备
debug_msg(snd_mixer_attach(mixer, "hw:1"),"attaching mixer"); // 连接到默认的声卡
debug_msg(snd_mixer_selem_register(mixer, NULL, NULL),"registering mixer"); // 载入声卡配置
debug_msg(snd_mixer_load(mixer),"load mixer");
// 循环找到自己想要的element
elem = snd_mixer_first_elem(mixer);
while(elem){
// find element name(此处要找的就是上面看的speaker元素)
if(strcmp("Speaker",snd_mixer_selem_get_name(elem)) == 0){
printf("elem name : %s\n",snd_mixer_selem_get_name(elem));
break;
}
elem = snd_mixer_elem_next(elem);
}
if(!elem){
printf("snd_mixer_find_selem Error\n");
snd_mixer_close(mixer);
mixer = NULL;
return;
}
long min, max;
snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
printf("volume range: %ld -- %ld\n", min, max);
long lVal, rVal;
snd_mixer_handle_events(mixer); // 确保混音器状态和应用程序状态的同步
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &lVal);
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &rVal);
printf("currnet volume: leftVal = %ld, rightVal = %ld\n", lVal, rVal);
snd_mixer_selem_set_playback_volume_all(elem, 25);
// 释放资源
snd_mixer_close(mixer);
}
4、注意细节
4.1、初始化顺序
在初始化混音器设备时,需要先初始化好PCM声卡设备,不然PCM初始化时会重置导致音频设置失效
4.2、声卡设备的选择
程序中通过调用snd_mixer_attach
选择声卡设备,选择时需要注意跟PCM选择声卡设备时不同,PCM初始化时选择的是声卡几设备几,比如声卡1,设备0,那么PCM初始化打开设备时要传入snd_pcm_open(&pb_handle, "plughw:1,0",SND_PCM_STREAM_PLAYBACK, 0)
,而mixer初始化时只需要选择声卡而不用详细到设备,依然是声卡1,设备0,那么mixer连接到声卡时只需要传入snd_mixer_attach(mixer, "hw:1")
。
4.3、元素查找
在mixer中,有很多的element(元素),也就是最开始通过图形化看到的各种元素,在ALSA中好像没有函数能够直接查找到某个元素,只能通过snd_mixer_first_elem
找到第一个元素,然后通过snd_mixer_elem_next
开始查找下一个元素一直查下去,直到通过snd_mixer_selem_get_name
发现当前的元素是你想要调节的元素为止(你可以选择将这种方式封装起来成为一个能指定查找的函数)。
4.4、单双通道音量设置
你可以通过snd_mixer_selem_is_playback_mono
查询该声卡是否是单通道(mono:单,stereo:双),然后通过snd_mixer_selem_set_capture_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, volume)
的第2个参数来指定左右通道的音量,但是我没什么时间深究,所以直接选择snd_mixer_selem_set_capture_volume_all
来设置总音量。
同时需要注意一下音量的调节,虽然在alsamixer工具的图形化中可以看到音量能从0调节到100,但是程序中使用snd_mixer_selem_get_playback_volume
获取音量时会发现范围在0-30,并且如果你使用amixer get 'DAC HPOUT Left'
get一下元素的值查看时就会发现limits的值也为0-30,因此在设置音量时也要注意设置的值不要超过这个范围,不能以图形化中的范围去设置。
root@firefly:~/twoway# amixer get 'DAC HPOUT Left'
Simple mixer control 'DAC HPOUT Left',0
Capabilities: volume volume-joined
Playback channels: Mono
Capture channels: Mono
Limits: 0 - 30
Mono: 30 [100%] [6.00dB]