用 go 做音频采集播放 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
nullcloud
V2EX    Go 编程语言

用 go 做音频采集播放

  •  
  •   nullcloud 2024 年 5 月 23 日 2002 次点击
    这是一个创建于 606 天前的主题,其中的信息可能已经有所发展或是发生改变。

    哪位用 go 做过音频采集播放,给个例子参考一下,可以发红包 需求大体是这样:

    ubuntu 上面,go 程序采集播放声音,对接 livekit 来做个对讲机的东西

    联系方式 v:aXJvbmJlYXN0MDAxCg==

    7 条回复    2024-05-24 20:36:08 +08:00
    milzero
        1
    milzero  
       2024 年 5 月 23 日
    这种库还是挺多的 https://github.com/ecobee/goalsa
    不过建议你能用 C 实现就用 C ,因为除了采集可能还有降噪回声消除这些,这些 C 库都很成熟了!
    wildlife
        2
    wildlife  
       2024 年 5 月 24 日
    可以参考 https://github.com/valentijnnieman/audio_streamer ,运行需要先安装 sudo apt install -y portaudio19-dev
    kuanat
        3
    kuanat  
       2024 年 5 月 24 日
    Linux 平台搞音频处理,上限高下限也低。用什么语言是其次的,而且很大概率没有太多选择,关键是 Linux 的音频系统过于混乱和复杂,开发更多是做适配而不是写功能代码。



    我有一点语言无关的 Linux 音频开发经验,估计能帮你少走很多弯路。写功能代码不难,难的是处理工程层面的细节。

    - 最好能有输入、输出设备的 Datasheet/TRM 文档,像做嵌入式开发那样。音频必然涉及 ADC/DAC 这个天然的软硬件边界,很多时候只能去适配而不是一般意义上的写代码控制。

    - 统一度量衡。音频(信号)处理是一门科学,所以要用科学的方法来对待。这个层面有几个需要着重关注的点:时钟、精度和单位换算。

    最底层硬件和系统的交互,可能是中断,也可能是某种 IO ,还可以是 DMA 。这些交互有天然的工作频率和延迟,了解这个限制并在软件层面适配,可以避免设计层面产生的 xruns/desync 之类的问题。

    精度核心还是受限于硬件,软件层面通常体现在采样率、中断频率 和 buffer 三个指标(一般两个指标可以确定第三个)。总的思路是中间处理的精度要高于硬件支持的精度(采样定理的结论),然后全程交换都使用相同的数据格式来避免 mix 操作的额外转换。

    时钟和精度是相互制约的,所要要根据使用场景(对于实时性的要求)来确定参数。比如 44.1kHz 采样率,buffer 是 1024 采样,硬件每 256 采样触发一次中断,那么延迟就是 1024/44.1k 大约 24ms ,应用程序需要以 256/44.1kHz 约 6ms 的频率稳定输出。由于 Linux 常规内核是非实时系统,在一些对延迟要求高的场景里,很难保证下限,要考虑实时内核,应用程序也要尽可能减小 buffer 。(舞台演出歌手耳返一般要 15ms 以内,ktv 大概不能超过 30ms ,留给处理系统的时间并不多。)另一个思路是使用 buffer rewinding 之类的数据结构和算法,可以使用无限大 buffer 但是需要匹配硬件层面的时钟信号。

    单位转换还是与软硬件边界有关。音量有 dB/dBFS/SPL/dBV 等等单位,核心思想是全程使用统一的单位与绝对零点参考。有点类似于图像系统中的光学、数码变焦,统一参考点可以使信号更好地位于硬件支持的范围内。超出硬件支持范围的部分要靠软件处理。



    继续说点与 Go 相关的。Linux 音频系统大概可以分三层:内核、底层库和用户层。

    内核层没什么需要深究的,以前还有 OSS 系统,现在 ALSA 完全替代了。内核加载驱动后,ALSA 负责将硬件抽象为具有特定功能的设备/子设备,然后以 sysfs 的形式暴露给用户空间。如果有很特殊的需要,可以用 Go 写 ALSA 的控制模块,但这个交互是绕不开 binding 的,除非完全用 unsafe syscall 实现。其实只有写底层库才会用到,正常只是使用音频设备是用不到的。

    底层库可以大致分为三类:第一类是用来支持用户层的胶水封装,这一类不会用到。第二类是游戏引擎等等常用的抽象后端,比如 libSDL/OpenAL 这些,多数时候也不会用到。还有一类是 GStreamer/LADSPA 这一类,这是很可能用到的,既可以做一般性的降噪消回声,也可以做定制类的变声调音等等,重点在于信号层面的处理。但还是那个问题,GStreamer 这种要用 Go 来调用只能通过 binding ,有个 go-gst 是专门做这个的。估计原文提到的 livekit 也是这个层面的。

    用户层一般叫做 Sound Server ,封装了底层 API 并提供功能抽象,多数都是模块化的,一般的音频处理工具也是在这一层。目前主流的几个是 JACK/PulseAudio/PipeWire ,应用层面 PulseAudio 可能占比更大一些,趋势是往 PipeWire 过渡。

    开发层面,JACK 的主要场景是支持 MIDI 混声和合成器之类的专业设备,设备支持的话尽量还是用 JACK 比较好。有 Go 相关的 binding 但我没有使用过。

    PulseAudio 能实现几乎绝大多数的功能,包括对音频的离线、实时处理也能在这一层做。比较好的地方在于它是多数发行版的默认选项,再就是它有 DBus 接口,可以避免 binding ,自己写个 DBus 封装也不是很麻烦的事情,只要做用到的部分就行。( DBus 其实不太适合低延迟的场景) PulseAudio 有很多非常规的应用,比如支持很多网络协议,当然如果用 Go 的话这部分可能直接用 Go 来写了。

    PipeWire 本身就是 GStreamer 开发者创立的,所以 PipeWire 的好处是不需要在单独考虑 GStreamer 的集成了。我在一两年前用的时候还不是很稳定,但现在应该好很多了。PipeWire 的主要不同是它定位自己是 media stream exchange 框架,而不是封装型框架。开发的时候,调用 PipeWire 层 API 可以某种程度上认为是透传到底层甚至内核,整个过程中采样率、精度、格式和 buffer 都可以很明确地定义和交互。另外就是它可以在 flatpak/AppImage 这样的沙盒环境里使用。不足是它只能通过 binding 供 Go 使用。



    综上考虑的话,能用 C 最好还是用 C 。如果一定要用 Go 就很依赖 binding 库的维护和质量,再就是需要有相对较高的编码水平,能够手动管理对象和内存来避免 GC 的频繁介入。另外如果信号处理层面需要 SIMD 之类的优化,用 Go 也是不合适的。

    这里说的都是实时、在线的音频处理,如果是离线为主的 DAW 场景,比如基于 sequence 的谱曲之类的,用 Go 没什么问题,只是由于缺乏 SDK 支持,需要写大量的功能和业务代码。
    nullcloud
        4
    nullcloud  
    OP
       2024 年 5 月 24 日
    感谢各位大佬的回答,这边选 go 是为了方便对接 livekit ,有好用的 c 库的话,可以 cgo 封装也行,再就是在网上发帖子也是因为我时间上来不及做这个
    nullcloud
        5
    nullcloud  
    OP
       2024 年 5 月 24 日
    @kuanat 可否加个微信?
    nullcloud
        6
    nullcloud  
    OP
       2024 年 5 月 24 日
    @milzero 加 v 聊?
    nullcloud
        7
    nullcloud  
    OP
       2024 年 5 月 24 日
    @wildlife 加 V 聊?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4135 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 10:16 PVG 18:16 LAX 02:16 JFK 05:16
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86