V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
daijinming
V2EX  ›  程序员

Linux (ubuntu) 下如何通过 c++代码录制系统声音(不是 Mic 输入)

  •  
  •   daijinming · 2023-03-17 14:48:32 +08:00 · 1957 次点击
    这是一个创建于 377 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近有个在 Linux 下录音的功能需要开发,通过 C++代码调用可以实现对系统声音的录制,也就是输出声音的录制,不是 Mic 的输入声音,请教下各位

    12 条回复    2023-03-18 11:22:47 +08:00
    kokutou
        1
    kokutou  
       2023-03-17 14:59:07 +08:00 via Android
    看看 obs 怎么做的
    cogear
        2
    cogear  
       2023-03-17 15:06:24 +08:00
    您好,您可以使用 ALSA 库来实现 Linux 下的录音功能。ALSA 是 Linux 下的音频驱动程序,它提供了一组 API ,可以用于录制和播放音频。您可以使用 ALSA 库来实现对系统声音的录制,也就是输出声音的录制,不是 Mic 的输入声音。这里有一篇关于使用 ALSA 库实现 Linux 下录音的文章,您可以参考一下:1 。

    如果您想要更加深入地了解 ALSA 库,您可以参考 ALSA 官方文档:2 。

    希望这可以帮到您。如果您有任何其他问题,请随时问我。

    ---

    来自 new bing
    cogear
        3
    cogear  
       2023-03-17 15:08:45 +08:00
    lieyan
        4
    lieyan  
       2023-03-17 15:21:50 +08:00
    自己写一个虚拟声卡驱动或者是麦克风驱动
    AlynxZhou
        5
    AlynxZhou  
       2023-03-17 16:29:21 +08:00   ❤️ 1
    你查一下 pulseaudio 或者 pipewire 的接口,现在比较新的系统都用 pipewire 混音,老的用 pulseaudio ,这个足够录 session 级别的声音了。
    Jokeoo
        6
    Jokeoo  
       2023-03-17 17:46:43 +08:00
    在 Linux ( Ubuntu )下,可以使用 PulseAudio 库来捕获系统声音。以下是一个简单的示例代码片段,可以通过 g++编译:

    ```
    #include <pulse/simple.h>
    #include <pulse/error.h>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;

    #define BUFSIZE 1024

    int main(int argc, char const *argv[]) {
    pa_sample_spec ss;
    ss.format = PA_SAMPLE_S16LE;
    ss.channels = 2;
    ss.rate = 44100;
    int error;
    pa_simple *s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error);
    if (!s) {
    cerr << "pa_simple_new() failed: " << pa_strerror(error) << endl;
    return 1;
    }

    char buf[BUFSIZE];
    int cnt = 0;
    while (cnt++ < 100) {
    int ret = pa_simple_read(s, buf, BUFSIZE, &error);
    if (ret < 0) {
    cerr << "pa_simple_read() failed: " << pa_strerror(error) << endl;
    break;
    }
    fwrite(buf, 1, ret, stdout);
    }

    pa_simple_free(s);
    return 0;
    }

    ```

    该代码将捕获系统声音,并将其输出到标准输出( stdout )。您可以将其修改为将音频写入文件或进行其他处理。

    notion AI
    L4Linux
        7
    L4Linux  
       2023-03-17 19:02:16 +08:00 via Android
    @AlynxZhou 就是你们这种人多了,害得我这个只用 ALSA 的人遇到各种问题。除了蓝牙,我想不出 ALSA 哪里不能用了。
    AlynxZhou
        8
    AlynxZhou  
       2023-03-17 20:52:42 +08:00
    @L4Linux 楼主问问题,我按照我的理解给他线索,哪里惹着你了?你自己觉得自己有能耐非要和大众用不一样的东西,那你就应该能自己解决,别来这里怪别人需求和你不一样。我不但要用蓝牙,还要一边放音乐一边看视频,我还要用 JACK 录音,我还要用插件加特效混音,只有 ALSA 怎么用?
    L4Linux
        9
    L4Linux  
       2023-03-17 22:17:13 +08:00 via Android
    @AlynxZhou 1 、你没有惹着我,但是本来直接用 ALSA 本来很好,在 xxx 新框架出来之后越来越糟,以及造成这种现状的社区惹着我了。
    2 、ALSA 是 kernel module ,你以为你只用了 pipewire ,实际上还是在用 ALSA 。
    3 、我不可能今天 ALSA 没声音了去改 ALSA 的代码,明天 UHD 630 卡出屎了又去改显卡驱动等等。
    4 、都用 linux 了还谈大众也比较可笑。
    5 、只有 ALSA 没法用是社区的问题,社区今天推出了 PulseAudio ,明天又搞了 pipewire 。

    最后回到 po 的问题,直接用 ALSA 就行了
    万一别人没用 pipewire ,用 pipewire 录了个寂寞。
    dw2693734d
        10
    dw2693734d  
       2023-03-17 23:01:15 +08:00
    #include <iostream>
    #include <pulse/simple.h>
    #include <pulse/error.h>
    #include <fstream>

    int main() {
    const char* fileName = "output.raw";
    std::ofstream outFile(fileName, std::ios::binary);

    pa_sample_spec sampleSpec;
    sampleSpec.format = PA_SAMPLE_S16LE;
    sampleSpec.rate = 44100;
    sampleSpec.channels = 2;

    pa_simple *pulseAudioSimple = nullptr;
    int error;

    pulseAudioSimple = pa_simple_new(NULL, "record_system_audio", PA_STREAM_RECORD, NULL, "record", &sampleSpec, NULL, NULL, &error);
    if (!pulseAudioSimple) {
    std::cerr << "Error: Could not create PulseAudio simple:" << pa_strerror(error) << std::endl;
    return 1;
    }

    const size_t numSamples = 44100 * 10; // Record for 10 seconds
    int16_t buffer[numSamples];

    if (pa_simple_read(pulseAudioSimple, buffer, sizeof(buffer), &error) < 0) {
    std::cerr << "Error: Could not read from PulseAudio: " << pa_strerror(error) << std::endl;
    pa_simple_free(pulseAudioSimple);
    return 1;
    }

    outFile.write(reinterpret_cast<char*>(buffer), sizeof(buffer));

    pa_simple_free(pulseAudioSimple);
    outFile.close();

    std::cout << "System audio has been recorded successfully. Output saved to " << fileName << std::endl;
    return 0;
    }
    flyqie
        11
    flyqie  
       2023-03-18 03:01:23 +08:00 via Android
    @L4Linux #9

    看了你的回复,不太理解,pulseaudio 及 pipewire 是怎么导致 alsa 越来越糟?

    alsa 分 kernel 和 user 两部分,正常开发基本都用 user 这边的东西吧,怎么会越来越糟,这部分应该是无感的呀,pulseaudio 和 pipewire 不都会对 libalsa 做配置修改来保证所有操作全走他俩吗。

    况且,pulseaudio 和 pipewire 作用难道不是使得 linux 音频这边的架构更加解耦了吗?能够更方便的通过统一体系去处理不同场景中不同的音频设备。
    L4Linux
        12
    L4Linux  
       2023-03-18 11:22:47 +08:00 via Android
    @flyqie 你不用当然没感觉,一是 alsa 渐渐没人维护了啊。有些东西是发现 alsa 实现得不好的,但没人改进,都去维护 pulseaudio 、pipewire 或 jack 去了。还有一个是上层软件。比如 firefox 用 alsa 时 mic 没声音,但以前没有这个问题。用 apulse 假装在用 pulseaudio 的话也没问题。alsa 真的干不好这些事情吗?最后,你以为是用同一体系去处理音频,实际上有 5 个体系去处理。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2998 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 14:51 · PVG 22:51 · LAX 07:51 · JFK 10:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.