Linux使用alsa快速切换声卡配置文件

背景介绍

  本人使用ArchLinux有一段时间了,在一开始使用的时候有个比较大的问题就是系统没声音,经过查看官方wiki知道是需要alsa,但是即便是安装了alsa还是需要自己写配置文件来指定声卡。这样使用了一段时间后,我觉得还是不方便,因为除了外放,我还有一张USB声卡,我的键盘是带旋钮的,旋钮按下被驱动映射成了音频静音键,所以我就想配置一个CTRL+旋钮,这样的组合键来快速切换声卡。

怎么查看自己的声卡信息

  我们在终端中输入aplay -l即可输出我们电脑中的声卡信息,下面是我执行命令的结果

card 0: NVidia [HDA NVidia], device 3: HDMI 0 [HDMI 0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: NVidia [HDA NVidia], device 7: HDMI 1 [HDMI 1]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: NVidia [HDA NVidia], device 8: HDMI 2 [HDMI 2]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: NVidia [HDA NVidia], device 9: HDMI 3 [HDMI 3]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: Generic [HD-Audio Generic], device 0: ALC287 Analog [ALC287 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

  上面包含NVidia字段的不用参考,我们的外放声卡是最下面的带有Generic字段的声卡。

创建并写入配置文件

  在自己家目录创建一个.asoundrc文件。然后使用文本编辑器打开。然后按照下面的格式写入

defaults.pcm.card 1 //这里为刚才查询声卡中的 card 字段
defaults.pcm.device 0 //这里为刚才查询声卡中的 device 字段
defaults.ctl.card 1 //这里为刚才查询声卡中的 card 字段

tips:
  然后我们可以试着播放一段音频,个人推荐播放本地音乐文件,可以使用vlc这样的播放器,如果尝试使用浏览器播放视频,那么你应该重启浏览器,否则配置文件不生效,这很重要。

配置文件切换代码

  知道了如何写配置文件之后,那么我们的代码逻辑也就明朗了,其实就是往我们的配置文件中写入我们应有的配置。

#include <iostream>
#include <string>
#include <fstream>
#include <unistd.h>
#include <fcntl.h>

using namespace std;

int main()
{
    //执行命令并将执行结果写进管道
    int fds[2];
    pipe(fds);
    dup2(fds[1],1);
    dup2(fds[0],0);
    string command = "aplay -l | grep Generic; aplay -l | grep USB";
    system(command.c_str());

    //创建基准字符串
    string s = R"(defaults.pcm.card 0
defaults.pcm.device 0
defaults.ctl.card 0)";

    //设置O_NONBLOCK,否则getline会阻塞
    int flags = fcntl(fds[0],F_GETFL,0);
    flags |= O_NONBLOCK;
    fcntl(fds[0],F_SETFL,flags);

    //从管道读取声卡参数,第一次读取Generic,所以不做不存在检查
    string buffer;
    getline(cin,buffer);
    //创建Generic配置的字符串
    string s1(s);
    s1[18]=s1[s.size()-1]=buffer[5];
    size_t device1 = buffer.find("device");
    s1[40]=buffer[device1+7];

    string s2(s);
    if(getline(cin,buffer))
    {
        //如果存在USB声卡,创建USB声卡配置的字符串
        s2[18]=s2[s.size()-1]=buffer[5];
        size_t device2 = buffer.find("device");
        s2[40]=buffer[device2+7];
    }

    //读取存在的配置文件
    fstream file;
    file.open(".asoundrc",ios::in|ios::out);
    getline(file,s);
    file.close();

    //重新打开并截断文件
    ofstream file2;
    file2.open(".asoundrc",ios::out|ios::trunc);

    //判断如果存在USB声卡,并且当前配置为Generic声卡则写入USB声卡配置,否则写入Generic声卡配置
    if(!cin.eof()&&s[18]==s1[18]) file2<<s2;
    else file2<<s1;
    file2.close();

    return 0;
}

如何使用这段代码

  首先使用编译器编译一下这段代码,Linux一般默认自带gcc编译器。用gcc
举例:g++ SoundChanger.cc -o SounderChanger
这样就会输出一个SoundChanger可执行文件,接下来根据自己的桌面环境配置按键映射即可,下面按照我自己使用的hyprland举例:
仅需在hyprland的配置文件中加一行:
bind = CTRL, XF86AudioMute, exec, ~/SoundChanger
这样就绑定了按键映射,可以愉快地使用CTRL+旋钮切换声卡了。

后记:

  首先,这段代码仅为我这台设备定制,不过如果你有一些其他的需求,仅需改动很少一部分代码即可。
例如:

1.配置完按键映射之后没有效果是怎么回事?

  这里的话建议刷新一下桌面环境,例如:hyprctl reload或者简单粗暴重启一下即可。

2.我的声卡并不叫GenericUSB该怎么办呢?

  非常简单,在string command = "aplay -l | grep Generic; aplay -l | grep USB";这一行代码中把grep后面的字段名称换成你声卡的名称即可。

3.我需要对配置文件写入别的内容怎么办?

  这里其实非常简单,首先定位到下面这段代码

    //创建基准字符串
    string s = R"(defaults.pcm.card 0
defaults.pcm.device 0
defaults.ctl.card 0)";

    //设置O_NONBLOCK,否则getline会阻塞
    int flags = fcntl(fds[0],F_GETFL,0);
    flags |= O_NONBLOCK;
    fcntl(fds[0],F_SETFL,flags);

    //从管道读取声卡参数,第一次读取Generic,所以不做不存在检查
    string buffer;
    getline(cin,buffer);
    //创建Generic配置的字符串
    string s1(s);
    s1[18]=s1[s.size()-1]=buffer[5];
    size_t device1 = buffer.find("device");
    s1[40]=buffer[device1+7];

    string s2(s);
    if(getline(cin,buffer))
    {
        //如果存在USB声卡,创建USB声卡配置的字符串
        s2[18]=s2[s.size()-1]=buffer[5];
        size_t device2 = buffer.find("device");
        s2[40]=buffer[device2+7];
    }

修改基准字符串的内容,然后更改下面对应声卡配置内容字符串中的下标即可。

4.我的声卡不止两张,该怎么办呢?

  还是上面的那行代码,添加自己的声卡字段,然后找到下面这段代码

    string buffer;
    getline(cin,buffer);
    //创建Generic配置的字符串
    string s1(s);
    s1[18]=s1[s.size()-1]=buffer[5];
    size_t device1 = buffer.find("device");
    s1[40]=buffer[device1+7];

    string s2(s);
    if(getline(cin,buffer))
    {
        //如果存在USB声卡,创建USB声卡配置的字符串
        s2[18]=s2[s.size()-1]=buffer[5];
        size_t device2 = buffer.find("device");
        s2[40]=buffer[device2+7];
    }





    if(!cin.eof()&&s[18]==s1[18]) file2<<s2;
    else file2<<s1;
    file2.close();

在这段代码后面复制粘贴一段,创建新的字符串,进行编辑,然后根据需要调整一下后面的配置文件写入逻辑即可。


  如果有什么问题也欢迎指出。

  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值