repair-agent 134ccb70f3
All checks were successful
Build and Deploy Backend / build-and-deploy (push) Successful in 5m41s
fix 音频并发优化
2026-03-03 17:21:46 +08:00

67 lines
1.8 KiB
Go

package audio
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// opusJSON 是 Django 预转码上传的 Opus JSON 文件结构。
type opusJSON struct {
SampleRate int `json:"sample_rate"`
Channels int `json:"channels"`
FrameDurationMs int `json:"frame_duration_ms"`
Frames []string `json:"frames"` // base64 编码的 Opus 帧
}
// FetchOpusFrames 从 OSS 下载预转码的 Opus JSON 文件,解析为原始帧列表。
// 跳过 ffmpeg 实时转码,大幅降低 CPU 消耗和首帧延迟。
func FetchOpusFrames(ctx context.Context, opusURL string) ([][]byte, error) {
httpCtx, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(httpCtx, http.MethodGet, opusURL, nil)
if err != nil {
return nil, fmt.Errorf("audio: build opus request: %w", err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("audio: download opus json: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("audio: opus json status %d", resp.StatusCode)
}
body, err := io.ReadAll(io.LimitReader(resp.Body, 50*1024*1024)) // 50MB 上限
if err != nil {
return nil, fmt.Errorf("audio: read opus json: %w", err)
}
var data opusJSON
if err := json.Unmarshal(body, &data); err != nil {
return nil, fmt.Errorf("audio: parse opus json: %w", err)
}
if len(data.Frames) == 0 {
return nil, fmt.Errorf("audio: opus json has no frames")
}
frames := make([][]byte, 0, len(data.Frames))
for i, b64 := range data.Frames {
raw, err := base64.StdEncoding.DecodeString(b64)
if err != nil {
return nil, fmt.Errorf("audio: decode frame %d: %w", i, err)
}
frames = append(frames, raw)
}
return frames, nil
}