您尚未登录。

楼主 # 2024-08-29 11:56:59

BH4DGT
会员
注册时间: 2022-08-08
已发帖子: 9
积分: 29

分享: V3S Linux音频库Alsa C代码控制 音量&静音

再搞V3S的Codec,实在是不想用Shell的方式控制音量和静音,于是翻了各种帖子,大部分都是:
    amixer -c 0 sset 'Headphone',0 70% unmute
    aplay 01.wav

CSDN上有控制音量的C代码:
    https://blog.csdn.net/augu_/article/details/140218122
    https://blog.csdn.net/cnclenovo/article/details/46044831
    https://blog.csdn.net/a827143452/article/details/89248136

但是静音控制一直没翻到,无奈只能看“amixer”的源代码了,搜关键字“unmute”倒是很容易找到。

buildroot-2020.02.8\output\build\alsa-utils-1.2.1\amixer\amixer.c

static int sset_channels(snd_mixer_elem_t *elem, unsigned int argc, char **argv)
{
	unsigned int channels = ~0U;
	unsigned int dir = 3, okflag = 3;
	unsigned int idx;
	snd_mixer_selem_channel_id_t chn;
	int check_flag = ignore_error ? 0 : -1;

	for (idx = 1; idx < argc; idx++) {
		char *ptr = argv[idx], *optr;
		int multi, firstchn = 1;
		channels = channels_mask(&ptr, channels);
		if (*ptr == '\0')
			continue;
		dir = dir_mask(&ptr, dir);
		if (*ptr == '\0')
			continue;
		multi = (strchr(ptr, ',') != NULL);
		optr = ptr;
		for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
			char *sptr = NULL;
			int ival;

			if (!(channels & (1 << chn)))
				continue;

			if ((dir & 1) && snd_mixer_selem_has_playback_channel(elem, chn)) {
				sptr = ptr;
				if (!strncmp(ptr, "mute", 4) && snd_mixer_selem_has_playback_switch(elem)) {
					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "mute", 1, ival)) >= 0)
						check_flag = 1;
				} else if (!strncmp(ptr, "off", 3) && snd_mixer_selem_has_playback_switch(elem)) {
					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "off", 1, ival)) >= 0)
						check_flag = 1;
				} else if (!strncmp(ptr, "unmute", 6) && snd_mixer_selem_has_playback_switch(elem)) {
					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "unmute", 0, ival)) >= 0)
						check_flag = 1;
				} else if (!strncmp(ptr, "on", 2) && snd_mixer_selem_has_playback_switch(elem)) {
					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "on", 0, ival)) >= 0)
						check_flag = 1;
				} else if (!strncmp(ptr, "toggle", 6) && snd_mixer_selem_has_playback_switch(elem)) {
					if (firstchn || !snd_mixer_selem_has_playback_switch_joined(elem)) {
						snd_mixer_selem_get_playback_switch(elem, chn, &ival);
						if (snd_mixer_selem_set_playback_switch(elem, chn, (ival ? 1 : 0) ^ 1) >= 0)
							check_flag = 1;
					}
					simple_skip_word(&ptr, "toggle");
				} else if (isdigit(*ptr) || *ptr == '-' || *ptr == '+') {
					if (set_volume_simple(elem, chn, &ptr, 0) >= 0)
						check_flag = 1;
				} else if (simple_skip_word(&ptr, "cap") || simple_skip_word(&ptr, "rec") ||
					   simple_skip_word(&ptr, "nocap") || simple_skip_word(&ptr, "norec")) {
					/* nothing */
				} else {
					okflag &= ~1;
				}
			}
			if ((dir & 2) && snd_mixer_selem_has_capture_channel(elem, chn)) {
				if (sptr != NULL)
					ptr = sptr;
				sptr = ptr;
				if (!strncmp(ptr, "cap", 3) && snd_mixer_selem_has_capture_switch(elem)) {
					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "cap", 0, ival)) >= 0)
						check_flag = 1;
				} else if (!strncmp(ptr, "rec", 3) && snd_mixer_selem_has_capture_switch(elem)) {
					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "rec", 0, ival)) >= 0)
						check_flag = 1;
				} else if (!strncmp(ptr, "nocap", 5) && snd_mixer_selem_has_capture_switch(elem)) {
					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "nocap", 1, ival)) >= 0)
						check_flag = 1;
				} else if (!strncmp(ptr, "norec", 5) && snd_mixer_selem_has_capture_switch(elem)) {
					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "norec", 1, ival)) >= 0)
						check_flag = 1;
				} else if (!strncmp(ptr, "toggle", 6) && snd_mixer_selem_has_capture_switch(elem)) {
					if (firstchn || !snd_mixer_selem_has_capture_switch_joined(elem)) {
						snd_mixer_selem_get_capture_switch(elem, chn, &ival);
						if (snd_mixer_selem_set_capture_switch(elem, chn, (ival ? 1 : 0) ^ 1) >= 0)
							check_flag = 1;
					}
					simple_skip_word(&ptr, "toggle");
				} else if (isdigit(*ptr) || *ptr == '-' || *ptr == '+') {
					if (set_volume_simple(elem, chn, &ptr, 1) >= 0)
						check_flag = 1;
				} else if (simple_skip_word(&ptr, "mute") || simple_skip_word(&ptr, "off") ||
					   simple_skip_word(&ptr, "unmute") || simple_skip_word(&ptr, "on")) {
					/* nothing */
				} else {
					okflag &= ~2;
				}
			}
			if (okflag == 0) {
				if (debugflag) {
					if (dir & 1)
						error("Unknown playback setup '%s'..", ptr);
					if (dir & 2)
						error("Unknown capture setup '%s'..", ptr);
				}
				return 0; /* just skip it */
			}
			if (!multi)
				ptr = optr;
			firstchn = 0;
		}
	}
	return check_flag;
}

找到关键代码:
snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "unmute", 0, ival)

然后去 alsa-lib 中找到了:
int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value)

索性把所有channel都取消静音好了。

离线

楼主 #1 2024-08-29 11:59:28

BH4DGT
会员
注册时间: 2022-08-08
已发帖子: 9
积分: 29

Re: 分享: V3S Linux音频库Alsa C代码控制 音量&静音

源代码如下(借鉴了CSDN上的代码):

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, "default"),"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("Headphone",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, 50);

	/* 关闭 静音 */
	snd_mixer_selem_set_playback_switch_all(elem, 1);

	// 释放资源
	snd_mixer_close(mixer);
}

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn