package tts import ( "bytes" "context" "fmt" "game-driver/config" "game-driver/leaf" "game-driver/pkg/audio" "game-driver/pkg/errorsx" "go.uber.org/zap" "io" "log" "time" nls "github.com/aliyun/alibabacloud-nls-go-sdk" ) type AliTTS struct { config.AliyunConfig ctx context.Context tokenResult nls.TokenResult } type result struct { Data io.ReadWriter Error error } var DefaultTTS = &AliTTS{} // onTaskFailed 识别过程中的错误处理回调参数 func (tts *AliTTS) onTaskFailed(text string, param interface{}) { p, _ := param.(*result) p.Error = fmt.Errorf("语音合成异常: %v", text) } // onSynthesisResult 语音合成数据回调参数 func (tts *AliTTS) onSynthesisResult(data []byte, param interface{}) { p, _ := param.(*result) p.Data.Write(data) } func (tts *AliTTS) Sound(text string) { if text == "" { return } buf, err := tts.Get(text) if err == nil && buf != nil { audio.PlayWav(tts.ctx, buf) } else { zap.S().Errorln("AliTTS 请求异常: ", err) } } func (tts *AliTTS) getToken() error { if tts.tokenResult.ExpireTime != 0 && time.Unix(tts.tokenResult.ExpireTime, 0).After(time.Now()) { return nil } tts.tokenResult = nls.TokenResult{} resultMessage, err := nls.GetToken("cn-shanghai", "nls-meta.cn-shanghai.aliyuncs.com", tts.AccessKeyID, tts.AccessKeySecret, "2019-02-28") if err != nil { return err } else if resultMessage.ErrMsg != "" { return errorsx.ThirdPartyErr } tts.tokenResult = resultMessage.TokenResult return nil } func (tts *AliTTS) Get(text string) (io.Reader, error) { param := nls.DefaultSpeechSynthesisParam() param.Volume = 100 param.Voice = tts.Voice err := tts.getToken() if err != nil { return nil, err } connectConfig := nls.NewConnectionConfigWithToken(nls.DEFAULT_URL, tts.AppKey, tts.tokenResult.Id) logger := nls.NewNlsLogger(leaf.DefaultWriter, "", log.LstdFlags|log.Ltime) logger.SetLogSil(false) logger.SetDebug(true) ttsData := &result{ Data: &bytes.Buffer{}, } synthesis, err := nls.NewSpeechSynthesis( connectConfig, logger, false, tts.onTaskFailed, tts.onSynthesisResult, nil, nil, nil, ttsData, ) if err != nil { return ttsData.Data, err } defer synthesis.Shutdown() ch, err := synthesis.Start(text, param, nil) if err != nil { return ttsData.Data, err } // 等待语音合成结束 select { case done := <-ch: { if !done { return ttsData.Data, errorsx.ThirdPartyErr } return ttsData.Data, nil } case <-time.After(time.Duration(tts.Timeout) * time.Second): return ttsData.Data, errorsx.DriverTimeoutErr case <-tts.ctx.Done(): return ttsData.Data, errorsx.DriverCancelErr } } func New(ctx context.Context, config config.AliyunConfig) *AliTTS { return &AliTTS{ ctx: ctx, AliyunConfig: config, } }