Golang实现音频录制与流式传输
Golang实现音频录制与流式传输 大家好,我在自己的项目上遇到了一个非常棘手的问题。 我正在寻找一种方法,能够从麦克风录制音频,并在录制的同时将其分块发送,以便接收方能够持续听到传输的音频。
我很难确定应该使用哪种音频格式(编解码器),以及Go语言中有哪些好的开源包可以提供帮助……
我考虑过使用PortAudio的Go语言绑定,我认为它可以将音频录制为二进制原始数据。 但是,然后我该如何逐块播放,使得收听是连续的呢? 有人能给我指点一下方向吗?
3 回复
谢谢! 我最终使用了来自“layeh.com/gopus”的gopus,将PCM数据(使用Go plug for portAudio录制)编码为Opus格式。
更多关于Golang实现音频录制与流式传输的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
关于 pcm 怎么样?这就足够了。你也可以将其保存到磁盘。
关于 continuous 的一点小建议:
PhoneA <—(websocket)-> TalkServer-<—(websocket)–>PhoneB
我认为将音频数据发布到 mq 并用另一个程序处理会更好。
也许这个代码库可以帮到你 https://github.com/hraban/opus.git
在Go中实现音频录制与流式传输,推荐使用以下方案:
核心方案:PortAudio + Opus编解码 + WebSocket传输
1. 依赖包
import (
"github.com/gordonklaus/portaudio"
"github.com/pion/opus"
"github.com/gorilla/websocket"
"encoding/binary"
)
2. 音频录制与编码示例
// 音频配置
const (
sampleRate = 48000
channels = 1
frameSize = 960 // 20ms帧
bufferFrames = 4800
)
type AudioStreamer struct {
stream *portaudio.Stream
encoder *opus.Encoder
conn *websocket.Conn
}
func NewAudioStreamer(wsConn *websocket.Conn) (*AudioStreamer, error) {
// 初始化PortAudio
portaudio.Initialize()
// 创建Opus编码器
encoder, err := opus.NewEncoder(sampleRate, channels, opus.AppVoIP)
if err != nil {
return nil, err
}
// 设置编码器比特率
encoder.SetBitrate(64000)
return &AudioStreamer{
encoder: encoder,
conn: wsConn,
}, nil
}
func (as *AudioStreamer) StartRecording() error {
// 打开音频输入流
stream, err := portaudio.OpenDefaultStream(1, 0, sampleRate, frameSize, as.audioCallback)
if err != nil {
return err
}
as.stream = stream
return stream.Start()
}
func (as *AudioStreamer) audioCallback(in []float32) {
// 将float32转换为int16(PCM格式)
pcmData := make([]int16, len(in))
for i, v := range in {
pcmData[i] = int16(v * 32767)
}
// Opus编码
encoded := make([]byte, 4000) // Opus最大帧大小
n, err := as.encoder.Encode(pcmData, encoded)
if err != nil {
return
}
// 通过WebSocket发送编码后的数据
if as.conn != nil {
as.conn.WriteMessage(websocket.BinaryMessage, encoded[:n])
}
}
func (as *AudioStreamer) Stop() {
if as.stream != nil {
as.stream.Stop()
as.stream.Close()
}
portaudio.Terminate()
}
3. WebSocket服务器端
func StartAudioStreamServer() {
upgrader := websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
http.HandleFunc("/stream", func(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
defer conn.Close()
// 创建音频流
streamer, err := NewAudioStreamer(conn)
if err != nil {
return
}
defer streamer.Stop()
// 开始录制和流式传输
streamer.StartRecording()
// 保持连接
for {
_, _, err := conn.ReadMessage()
if err != nil {
break
}
}
})
http.ListenAndServe(":8080", nil)
}
4. 接收端解码播放示例
type AudioPlayer struct {
stream *portaudio.Stream
decoder *opus.Decoder
}
func NewAudioPlayer() (*AudioPlayer, error) {
portaudio.Initialize()
decoder, err := opus.NewDecoder(sampleRate, channels)
if err != nil {
return nil, err
}
player := &AudioPlayer{decoder: decoder}
// 打开音频输出流
stream, err := portaudio.OpenDefaultStream(0, 1, sampleRate, frameSize, player.playCallback)
if err != nil {
return nil, err
}
player.stream = stream
return player, nil
}
func (ap *AudioPlayer) PlayAudioData(encoded []byte) {
// Opus解码
pcmData := make([]int16, frameSize)
n, err := ap.decoder.Decode(encoded, pcmData)
if err != nil {
return
}
// 转换为float32并播放
floatData := make([]float32, n)
for i, v := range pcmData[:n] {
floatData[i] = float32(v) / 32767.0
}
// 这里需要将数据放入播放缓冲区
// 实际实现中需要使用线程安全的缓冲区队列
}
func (ap *AudioPlayer) playCallback(out []float32) {
// 从缓冲区获取数据填充out
// 实现播放逻辑
}
func (ap *AudioPlayer) Start() error {
return ap.stream.Start()
}
5. 客户端接收示例
func ReceiveAudioStream(url string) {
conn, _, err := websocket.DefaultDialer.Dial(url, nil)
if err != nil {
return
}
defer conn.Close()
player, err := NewAudioPlayer()
if err != nil {
return
}
defer player.Stop()
player.Start()
for {
_, message, err := conn.ReadMessage()
if err != nil {
break
}
// 解码并播放
player.PlayAudioData(message)
}
}
关键点说明
- 音频格式选择:使用Opus编解码器,专为实时音频传输设计,延迟低、压缩率高
- 分块传输:每20ms(960个样本)作为一个数据包进行编码和传输
- 实时性保障:WebSocket提供全双工通信,适合实时音频流
- 缓冲区管理:需要实现环形缓冲区来处理音频数据的生产和消费
这个方案可以实现低延迟的音频录制和流式传输,适合语音聊天、实时广播等场景。

