Golang语音录音功能实现与优化
Golang语音录音功能实现与优化 我一直想知道Go语言是否有任何库,可以让我从Windows机器的麦克风录制语音,并将其以.raw格式保存在本地。
场景 -> 我一直在尝试使用谷歌语音API将语音转换为文本。他们页面上的示例只展示了如何使用.raw文件,这些文件需要我下载并存储在本地。 但我想要录制语音,然后将这个文件提供给谷歌语音API。 任何帮助都将不胜感激。 提前感谢。
1 回复
更多关于Golang语音录音功能实现与优化的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中实现Windows麦克风录音并保存为.raw格式,可以使用portaudio库结合wav或直接写入原始音频数据。以下是具体实现方案:
1. 安装必要库
go get -u github.com/gordonklaus/portaudio
go get -u github.com/go-audio/wav
2. 完整录音实现代码
package main
import (
"fmt"
"os"
"time"
"github.com/gordonklaus/portaudio"
"github.com/go-audio/wav"
)
const (
sampleRate = 16000 // 16kHz,Google Speech API推荐
channels = 1 // 单声道
frameLength = 1024 // 每帧样本数
recordLength = 5 // 录音时长(秒)
)
func main() {
// 初始化PortAudio
portaudio.Initialize()
defer portaudio.Terminate()
// 打开默认输入设备
inputDevice, err := portaudio.DefaultInputDevice()
if err != nil {
panic(err)
}
// 创建音频流参数
streamParams := portaudio.StreamParameters{
Input: portaudio.StreamDeviceParameters{
Device: inputDevice,
Channels: channels,
Latency: inputDevice.DefaultLowInputLatency,
},
SampleRate: sampleRate,
FramesPerBuffer: frameLength,
}
// 创建缓冲区
buffer := make([]int16, frameLength*channels)
// 打开音频流
stream, err := portaudio.OpenStream(streamParams, buffer)
if err != nil {
panic(err)
}
defer stream.Close()
// 开始录音
fmt.Println("开始录音...")
err = stream.Start()
if err != nil {
panic(err)
}
// 创建输出文件
outputFile, err := os.Create("recording.raw")
if err != nil {
panic(err)
}
defer outputFile.Close()
// 录音指定时长
samplesNeeded := sampleRate * recordLength
samplesRecorded := 0
for samplesRecorded < samplesNeeded {
err = stream.Read()
if err != nil {
panic(err)
}
// 写入原始PCM数据
for i := 0; i < len(buffer); i++ {
// 以小端格式写入16位样本
outputFile.Write([]byte{
byte(buffer[i] & 0xFF),
byte((buffer[i] >> 8) & 0xFF),
})
}
samplesRecorded += len(buffer)
fmt.Printf("\r录音进度: %.1f%%", float64(samplesRecorded)/float64(samplesNeeded)*100)
}
// 停止录音
stream.Stop()
fmt.Println("\n录音完成,保存为 recording.raw")
}
3. 优化版本(带WAV头信息)
如果Google Speech API需要WAV格式,可以使用以下代码:
package main
import (
"fmt"
"os"
"time"
"github.com/gordonklaus/portaudio"
"github.com/go-audio/wav"
"github.com/go-audio/audio"
)
func recordWAV(filename string, duration time.Duration) error {
portaudio.Initialize()
defer portaudio.Terminate()
// 音频参数
sampleRate := 16000
channels := 1
frameSize := 1024
// 获取输入设备
inputDevice, err := portaudio.DefaultInputDevice()
if err != nil {
return err
}
// 创建WAV文件
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
// 创建WAV编码器
enc := wav.NewEncoder(file, sampleRate, 16, channels, 1)
// 准备音频流
buffer := make([]int16, frameSize*channels)
stream, err := portaudio.OpenStream(portaudio.StreamParameters{
Input: portaudio.StreamDeviceParameters{
Device: inputDevice,
Channels: channels,
Latency: inputDevice.DefaultLowInputLatency,
},
SampleRate: float64(sampleRate),
FramesPerBuffer: frameSize,
}, buffer)
if err != nil {
return err
}
defer stream.Close()
// 开始录音
fmt.Printf("录音中... (%v秒)\n", duration.Seconds())
err = stream.Start()
if err != nil {
return err
}
// 计算需要录制的帧数
framesNeeded := int(sampleRate * int(duration.Seconds()) / frameSize)
for i := 0; i < framesNeeded; i++ {
err = stream.Read()
if err != nil {
return err
}
// 转换为audio.IntBuffer
intBuffer := &audio.IntBuffer{
Format: &audio.Format{
NumChannels: channels,
SampleRate: sampleRate,
},
Data: make([]int, len(buffer)),
}
for j, sample := range buffer {
intBuffer.Data[j] = int(sample)
}
// 写入WAV文件
if err := enc.Write(intBuffer); err != nil {
return err
}
fmt.Printf("\r进度: %d/%d 帧", i+1, framesNeeded)
}
// 完成录音
stream.Stop()
enc.Close()
fmt.Println("\n录音完成:", filename)
return nil
}
func main() {
// 录制5秒音频
err := recordWAV("recording.wav", 5*time.Second)
if err != nil {
panic(err)
}
// 转换为RAW格式(如果需要)
rawData, err := wavToRaw("recording.wav", "recording.raw")
if err != nil {
panic(err)
}
fmt.Printf("RAW文件大小: %d 字节\n", len(rawData))
}
// WAV转RAW格式
func wavToRaw(wavFile, rawFile string) ([]byte, error) {
// 打开WAV文件
file, err := os.Open(wavFile)
if err != nil {
return nil, err
}
defer file.Close()
// 解码WAV
dec := wav.NewDecoder(file)
buf, err := dec.FullPCMBuffer()
if err != nil {
return nil, err
}
// 提取原始PCM数据
rawData := make([]byte, len(buf.Data)*2)
for i, sample := range buf.Data {
rawData[i*2] = byte(sample & 0xFF)
rawData[i*2+1] = byte((sample >> 8) & 0xFF)
}
// 保存RAW文件
err = os.WriteFile(rawFile, rawData, 0644)
if err != nil {
return nil, err
}
return rawData, nil
}
4. 实时录音流式处理
对于Google Speech API的流式传输:
func streamToGoogleSpeechAPI() error {
portaudio.Initialize()
defer portaudio.Terminate()
sampleRate := 16000
channels := 1
frameSize := 3200 // 200ms的数据(Google推荐)
inputDevice, err := portaudio.DefaultInputDevice()
if err != nil {
return err
}
buffer := make([]int16, frameSize*channels)
stream, err := portaudio.OpenStream(portaudio.StreamParameters{
Input: portaudio.StreamDeviceParameters{
Device: inputDevice,
Channels: channels,
Latency: inputDevice.DefaultLowInputLatency,
},
SampleRate: float64(sampleRate),
FramesPerBuffer: frameSize,
}, buffer)
if err != nil {
return err
}
defer stream.Close()
err = stream.Start()
if err != nil {
return err
}
fmt.Println("开始流式录音... (按Ctrl+C停止)")
for {
err = stream.Read()
if err != nil {
return err
}
// 这里将buffer发送到Google Speech API
// rawData := int16ToBytes(buffer)
// sendToGoogleSpeechAPI(rawData)
fmt.Printf("收到 %d 个样本\n", len(buffer))
}
return nil
}
// 将int16切片转换为字节切片
func int16ToBytes(data []int16) []byte {
bytes := make([]byte, len(data)*2)
for i, sample := range data {
bytes[i*2] = byte(sample & 0xFF)
bytes[i*2+1] = byte((sample >> 8) & 0xFF)
}
return bytes
}
关键点说明:
- PortAudio:跨平台音频I/O库,支持Windows麦克风访问
- 采样率:Google Speech API推荐16kHz
- 格式:RAW文件是纯PCM数据,无文件头
- 字节序:小端格式(Little Endian)
- 声道:单声道(mono)通常足够语音识别使用
这些代码可以直接编译运行在Windows系统上,需要先安装PortAudio的Windows依赖。

