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
}

关键点说明:

  1. PortAudio:跨平台音频I/O库,支持Windows麦克风访问
  2. 采样率:Google Speech API推荐16kHz
  3. 格式:RAW文件是纯PCM数据,无文件头
  4. 字节序:小端格式(Little Endian)
  5. 声道:单声道(mono)通常足够语音识别使用

这些代码可以直接编译运行在Windows系统上,需要先安装PortAudio的Windows依赖。

回到顶部