Files
game-driver/pkg/audio/play.go
mapleafgo 6d23c1704f
All checks were successful
ci/woodpecker/tag/woodpecker Pipeline was successful
fix(audio): 移除 Resampler 测试代码并优化停滞检测
通过测试确认 Resampler 和 WAV 解码正常工作,移除测试代码:
- 移除手动读取 Resampler 的测试代码(测试读取会破坏 Resampler 内部状态)
- 优化停滞检测逻辑:只有在已经开始播放后才报告停滞
- 修复语法错误(多余的闭合括号)

测试表明 Resampler 本身工作正常,数据读取成功。现在移除测试代码,
观察是否能正常播放完整音频。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 17:11:47 +08:00

109 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package audio
import (
"context"
"io"
"time"
"github.com/gopxl/beep/v2"
"github.com/gopxl/beep/v2/mp3"
"github.com/gopxl/beep/v2/speaker"
"github.com/gopxl/beep/v2/wav"
"go.uber.org/zap"
)
var DefaultSampleRate = beep.SampleRate(44100)
func init() {
err := speaker.Init(DefaultSampleRate, DefaultSampleRate.N(time.Second/10))
if err != nil {
panic("扬声器初始化异常: " + err.Error())
}
zap.S().Infoln("扬声器初始化完成")
}
func PlayWav(c context.Context, r io.Reader) {
zap.S().Debugln("开始 WAV 解码")
streamer, format, err := wav.Decode(r)
if err != nil {
zap.S().Errorln("WAV解码失败: ", err)
return
}
defer streamer.Close()
// 获取音频长度信息
totalSamples := streamer.Len()
zap.S().Debugf("WAV解码成功采样率: %d, 总样本数: %d, 预计时长: %.2f秒",
format.SampleRate, totalSamples, float64(totalSamples)/float64(format.SampleRate))
s := beep.Resample(4, format.SampleRate, DefaultSampleRate, streamer)
ctrl := &beep.Ctrl{Streamer: s}
done := make(chan struct{})
speaker.Play(beep.Seq(ctrl, beep.Callback(func() {
zap.S().Debugln("音频播放完成")
close(done)
})))
zap.S().Debugln("等待音频播放完成...")
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
lastPos := 0
for {
select {
case <-done:
zap.S().Infoln("音频播放正常结束")
return
case <-c.Done():
zap.S().Debugf("音频播放被 context 取消: %v", c.Err())
speaker.Lock()
ctrl.Streamer = nil
speaker.Unlock()
return
case <-ticker.C:
// 获取当前播放位置
pos := streamer.Position()
if pos != lastPos {
progress := float64(pos) / float64(totalSamples) * 100
currentTime := float64(pos) / float64(format.SampleRate)
zap.S().Debugf("播放进度: %d/%d (%.1f%%), %.2f秒", pos, totalSamples, progress, currentTime)
lastPos = pos
} else if lastPos > 0 {
// 只有在已经开始播放后才报告停滞
zap.S().Debugf("播放停滞在位置: %d/%d", pos, totalSamples)
}
}
}
}
func PlayMP3(c context.Context, r io.ReadCloser) {
streamer, format, err := mp3.Decode(r)
if err != nil {
zap.S().Errorln("MP3解码失败: ", err)
return
}
defer streamer.Close()
s := beep.Resample(4, format.SampleRate, DefaultSampleRate, streamer)
ctrl := &beep.Ctrl{Streamer: s}
done := make(chan struct{})
speaker.Play(beep.Seq(ctrl, beep.Callback(func() {
close(done)
})))
for {
select {
case <-done:
return
case <-c.Done():
speaker.Lock()
ctrl.Streamer = nil
speaker.Unlock()
return
}
}
}