环境:
嵌入式系统linux ubuntu18.04
需求:
业务层需要对系统音量进行控制
现象:
- alsamixer 操作音量成非线性变现
- supervisor管理进程下,Pulseaudio音量操作失效
解决过程:
方案一
alsamixer ,系统有对应服务
alsamixer -c 2 #选择对应声卡 出现界面,可上下键调节
命令行设置音量
amixer cset numid=2,iface=MIXER,name='Playback Channel Map' 10 #后查看音量是否变化
问题是此时音量并没有按设定的音量进行变化,并且从程序中API来看,对应关系成非线性。
方案二
Pulseaudio
pactl list sinks #查看声卡名称
pactl set-sink-volume 1 55% #命令设置音量
观察alsamixer 的图形界面,音量变化(0-100)误差在±2,±1居多,然后业务层调用命令或者相应API代码:
#include <pulse/pulseaudio.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
const char *sink_name; // 设备名
pa_volume_t volume; // 音量值
pa_mainloop *mainloop; // pa_mainloop 对象
} UserData;
// 回调
void context_state_callback(pa_context *c, void *userdata) {
UserData *m = (UserData *)userdata;
switch (pa_context_get_state(c)) {
case PA_CONTEXT_READY:{
fprintf(stderr, "Connected to PulseAudio.\n");
pa_operation *op;
pa_cvolume volume;
//pa_volume_t vol = PA_VOLUME_NORM * 0.75; // 设置为 75% 音量
// 初始化 pa_cvolume
pa_cvolume_set(&volume, 2, m->volume); // 2 表示双声道(立体声)
op = pa_context_set_sink_volume_by_name(c, m->sink_name, &volume, NULL, NULL);
if (op) {
pa_operation_unref(op);
} else {
fprintf(stderr, "Failed to create operation: device not found or context not ready.\n");
}
pa_mainloop_quit(m->mainloop, 0);
break;
}
case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED:
fprintf(stderr, "Context failed or terminated.\n");
pa_mainloop_quit(m->mainloop, 1);
break;
default:
// 其他状态(如连接中),无需处理
break;
}
}
/* volume control*/
void volume_control(const string &device, int value) {
#if 0 //命令代码
auto cmd = "pactl set-sink-volume 1 " + to_string(value)+"%";
PrintI("set volume: cmd = %s\n", cmd);
System::execute(cmd);
#endif
#if 1
pa_mainloop *m = pa_mainloop_new();
pa_mainloop_api *api = pa_mainloop_get_api(m);
pa_context *context = pa_context_new(api, "pactl");
float ll=(float)value/100;
PrintI("set volume: volume = %f\n", ll);
PrintI("set volume: name = %s\n", device.data());
UserData data = {
.sink_name = device.data(),//"alsa_output.platform-es8388-sound.stereo-fallback", // 设备名
.volume = PA_VOLUME_NORM * ll,
.mainloop = m
};
pa_context_set_state_callback(context, context_state_callback, &data);
pa_context_connect(context, NULL, PA_CONTEXT_NOFLAGS, NULL);
int ret = 1;
pa_mainloop_run(m, &ret);
for (char **env = environ; *env != NULL; env++) {
printf("%s\n", *env);
}
pa_context_unref(context);
pa_mainloop_free(m);
#endif
return ;
}
程序运行及设置均没问题
但是用supervisor管理此进程时,也就是自动启动后,音量操作失效,没有显示明显错误,最后处理方法
- 在应用配置文件中添加环境变量environment中
environment=DISPLAY=":0",PULSE_SERVER="/run/user/1001/pulse/native"
查看PULSE_SERVER,也就是系统中PULSE音频服务器信息 方法:
pactl info
Server String: unix:/run/user/1000/pulse/native #Server String 就是
2.将此变量添加配置文件中command变量中
command='...export DISPLAY=:0 && export PULSE_SERVER=/run/user/1001/pulse/native && ./bin/voice'
reboot #后系统操作音量正常