From baa32fedc39ffba7aa0cd9e866c5b9e09e0fc4e5 Mon Sep 17 00:00:00 2001 From: mapleafgo Date: Wed, 8 Apr 2026 19:32:11 +0800 Subject: [PATCH] =?UTF-8?q?fix(audio):=20=E4=BF=AE=E5=A4=8D=E9=9F=B3?= =?UTF-8?q?=E9=A2=91=E6=92=AD=E6=94=BE=E6=8F=90=E5=89=8D=E7=BB=93=E6=9D=9F?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: - 7秒的音频不到1秒就播完 - player.IsPlaying() 只检查播放状态,不检查数据是否播放完 修复: - 添加等待播放器启动的逻辑 - 等待 IsPlaying() 返回 false - 额外等待 200ms 确保缓冲区数据完全播放 - 添加调试日志输出音频格式信息 测试: - 所有单元测试通过(6/6) --- pkg/audio/play.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pkg/audio/play.go b/pkg/audio/play.go index c85cc12..3182ccb 100644 --- a/pkg/audio/play.go +++ b/pkg/audio/play.go @@ -9,6 +9,7 @@ import ( "github.com/youpy/go-wav" "github.com/hajimehoshi/go-mp3" + "go.uber.org/zap" ) // PlayWav 播放 WAV 文件(阻塞),直到完成或 context 取消 @@ -28,16 +29,33 @@ func PlayWav(ctx context.Context, r io.ReadCloser) error { // Create a reader from the buffered data dec := wav.NewReader(bytes.NewReader(data)) + + // 获取音频格式信息 + format, err := dec.Format() + if err == nil { + duration, _ := dec.Duration() + zap.S().Debugf("WAV 格式: %d ch, %d Hz, %d bits, 时长: %v", + format.NumChannels, format.SampleRate, format.BitsPerSample, duration) + } + player := otoCtx.NewPlayer(dec) defer player.Close() player.Play() + // 等待播放完成 - 确保 Play() 调用后数据都被播放 done := make(chan struct{}) go func() { + // 先确保播放器开始播放 + for !player.IsPlaying() { + time.Sleep(10 * time.Millisecond) + } + // 等待播放结束(播放完所有数据) for player.IsPlaying() { time.Sleep(10 * time.Millisecond) } + // 额外等待 200ms 确保缓冲区数据完全播放 + time.Sleep(200 * time.Millisecond) close(done) }() @@ -63,16 +81,28 @@ func PlayMP3(ctx context.Context, r io.ReadCloser) error { } defer r.Close() + // MP3 解码器信息 + zap.S().Debugf("MP3 采样率: %d Hz, 时长: %d samples", + dec.SampleRate(), dec.Length()) + player := otoCtx.NewPlayer(dec) defer player.Close() player.Play() + // 等待播放完成 - 确保 Play() 调用后数据都被播放 done := make(chan struct{}) go func() { + // 先确保播放器开始播放 + for !player.IsPlaying() { + time.Sleep(10 * time.Millisecond) + } + // 等待播放结束(播放完所有数据) for player.IsPlaying() { time.Sleep(10 * time.Millisecond) } + // 额外等待 200ms 确保缓冲区数据完全播放 + time.Sleep(200 * time.Millisecond) close(done) }()