Golang Go语言实现音频采集与播放
哪位用 go 做过音频采集播放,给个例子参考一下,可以发红包 需求大体是这样:
ubuntu 上面,go 程序采集播放声音,对接 livekit 来做个对讲机的东西
联系方式 v:aXJvbmJlYXN0MDAxCg==
Golang Go语言实现音频采集与播放
这种库还是挺多的 https://github.com/ecobee/goalsa ,
不过建议你能用 C 实现就用 C ,因为除了采集可能还有降噪回声消除这些,这些 C 库都很成熟了!
更多关于Golang Go语言实现音频采集与播放的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
可以参考 https://github.com/valentijnnieman/audio_streamer ,运行需要先安装 sudo apt install -y portaudio19-dev
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 支持,需要写大量的功能和业务代码。
感谢各位大佬的回答,这边选 go 是为了方便对接 livekit ,有好用的 c 库的话,可以 cgo 封装也行,再就是在网上发帖子也是因为我时间上来不及做这个
可否加个微信?
加 v 聊?
在Go语言中实现音频采集与播放,通常需要借助一些第三方库来简化操作。以下是一个基本的思路和一些推荐的库:
-
音频采集:
- 可以使用
portaudio
库,它是一个跨平台的音频库,支持实时音频I/O。Go语言中有一个portaudio-go
绑定库,可以方便地进行音频采集。 - 另一个选择是
go-alsa
,这个库适用于Linux系统,特别是需要ALSA(Advanced Linux Sound Architecture)支持的情况。
- 可以使用
-
音频播放:
- 对于播放,
portaudio-go
同样适用,因为它既支持采集也支持播放。 - 如果你只是需要简单的音频播放功能,
mp3
或wav
文件的播放,可以使用github.com/go-audio/audio
库,它提供了对多种音频格式的解码和播放支持。
- 对于播放,
-
实现步骤:
- 安装所需的第三方库(如
portaudio-go
或go-alsa
)。 - 使用这些库来设置音频流,包括采样率、通道数等参数。
- 编写采集代码,从麦克风或其他音频输入设备读取数据。
- 编写播放代码,将采集到的音频数据或预先准备好的音频文件播放出来。
- 安装所需的第三方库(如
-
注意事项:
- 音频处理是一个实时性要求很高的任务,因此要确保代码高效,避免不必要的阻塞。
- 根据具体需求选择合适的音频格式和编码方式。
通过以上步骤,你可以在Go语言中实现基本的音频采集与播放功能。如果需要更复杂的功能,可以进一步研究这些库的文档和示例代码。