Compare commits
1 Commits
v1.0.2-rc1
...
v1.0.2-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
| 2331d0c73f |
@@ -10,16 +10,24 @@ import (
|
|||||||
func SoundStart() leaf.HandlerFunc {
|
func SoundStart() leaf.HandlerFunc {
|
||||||
return func(c *leaf.Context) {
|
return func(c *leaf.Context) {
|
||||||
pm := leaf.Value[*schema.PlayModal](c, PayloadJSONKey)
|
pm := leaf.Value[*schema.PlayModal](c, PayloadJSONKey)
|
||||||
tts.DefaultTTS.Sound(pm.TTS.Start)
|
|
||||||
|
// 使用请求的 context,支持取消和超时
|
||||||
|
if pm.TTS.Start != "" {
|
||||||
|
tts.DefaultTTS.SoundWithContext(c, pm.TTS.Start)
|
||||||
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
var text string
|
||||||
switch leaf.Value[leaf.EndType](c, leaf.EndKey) {
|
switch leaf.Value[leaf.EndType](c, leaf.EndKey) {
|
||||||
case leaf.End:
|
case leaf.End:
|
||||||
tts.DefaultTTS.Sound(pm.TTS.End)
|
text = pm.TTS.End
|
||||||
case leaf.EndTimeout:
|
case leaf.EndTimeout:
|
||||||
tts.DefaultTTS.Sound(pm.TTS.Timeout)
|
text = pm.TTS.Timeout
|
||||||
case leaf.EndStop:
|
case leaf.EndStop:
|
||||||
tts.DefaultTTS.Sound(pm.TTS.Stop)
|
text = pm.TTS.Stop
|
||||||
|
}
|
||||||
|
if text != "" {
|
||||||
|
tts.DefaultTTS.SoundWithContext(c, text)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PlayWav(c context.Context, r io.Reader) {
|
func PlayWav(c context.Context, r io.Reader) {
|
||||||
|
zap.S().Debugln("开始 WAV 解码")
|
||||||
streamer, format, err := wav.Decode(r)
|
streamer, format, err := wav.Decode(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Errorln("WAV解码失败: ", err)
|
zap.S().Errorln("WAV解码失败: ", err)
|
||||||
@@ -29,20 +30,25 @@ func PlayWav(c context.Context, r io.Reader) {
|
|||||||
}
|
}
|
||||||
defer streamer.Close()
|
defer streamer.Close()
|
||||||
|
|
||||||
|
zap.S().Debugln("WAV解码成功,采样率:", format.SampleRate)
|
||||||
s := beep.Resample(4, format.SampleRate, DefaultSampleRate, streamer)
|
s := beep.Resample(4, format.SampleRate, DefaultSampleRate, streamer)
|
||||||
|
|
||||||
ctrl := &beep.Ctrl{Streamer: s}
|
ctrl := &beep.Ctrl{Streamer: s}
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
speaker.Play(beep.Seq(ctrl, beep.Callback(func() {
|
speaker.Play(beep.Seq(ctrl, beep.Callback(func() {
|
||||||
|
zap.S().Debugln("音频播放完成")
|
||||||
close(done)
|
close(done)
|
||||||
})))
|
})))
|
||||||
|
|
||||||
|
zap.S().Debugln("等待音频播放完成...")
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
|
zap.S().Infoln("音频播放正常结束")
|
||||||
return
|
return
|
||||||
case <-c.Done():
|
case <-c.Done():
|
||||||
{
|
{
|
||||||
|
zap.S().Infoln("音频播放被 context 取消")
|
||||||
speaker.Lock()
|
speaker.Lock()
|
||||||
ctrl.Streamer = nil
|
ctrl.Streamer = nil
|
||||||
speaker.Unlock()
|
speaker.Unlock()
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ func (tts *AliTTS) Sound(text string) {
|
|||||||
zap.S().Infof("开始播放TTS: %s", text)
|
zap.S().Infof("开始播放TTS: %s", text)
|
||||||
buf, err := tts.Get(text)
|
buf, err := tts.Get(text)
|
||||||
if err == nil && buf != nil {
|
if err == nil && buf != nil {
|
||||||
|
zap.S().Debugln("TTS合成成功,开始播放")
|
||||||
audio.PlayWav(tts.ctx, buf)
|
audio.PlayWav(tts.ctx, buf)
|
||||||
zap.S().Infof("TTS播放完成: %s", text)
|
zap.S().Infof("TTS播放完成: %s", text)
|
||||||
} else {
|
} else {
|
||||||
@@ -55,6 +56,22 @@ func (tts *AliTTS) Sound(text string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SoundWithContext 使用指定的 context 播放 TTS,支持取消和超时
|
||||||
|
func (tts *AliTTS) SoundWithContext(ctx context.Context, text string) {
|
||||||
|
if text == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
zap.S().Infof("开始播放TTS: %s", text)
|
||||||
|
buf, err := tts.Get(text)
|
||||||
|
if err == nil && buf != nil {
|
||||||
|
zap.S().Debugln("TTS合成成功,开始播放")
|
||||||
|
audio.PlayWav(ctx, buf)
|
||||||
|
zap.S().Infof("TTS播放完成: %s", text)
|
||||||
|
} else {
|
||||||
|
zap.S().Errorln("AliTTS 请求异常: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (tts *AliTTS) getToken() error {
|
func (tts *AliTTS) getToken() error {
|
||||||
if tts.tokenResult.ExpireTime != 0 && time.Unix(tts.tokenResult.ExpireTime, 0).After(time.Now()) {
|
if tts.tokenResult.ExpireTime != 0 && time.Unix(tts.tokenResult.ExpireTime, 0).After(time.Now()) {
|
||||||
return nil
|
return nil
|
||||||
@@ -112,13 +129,22 @@ func (tts *AliTTS) Get(text string) (io.Reader, error) {
|
|||||||
case done := <-ch:
|
case done := <-ch:
|
||||||
{
|
{
|
||||||
if !done {
|
if !done {
|
||||||
|
zap.S().Errorln("TTS合成失败: done=false")
|
||||||
|
return ttsData.Data, errorsx.ThirdPartyErr
|
||||||
|
}
|
||||||
|
size := ttsData.Data.(*bytes.Buffer).Len()
|
||||||
|
zap.S().Debugf("TTS合成成功,数据大小: %d bytes", size)
|
||||||
|
if size == 0 {
|
||||||
|
zap.S().Errorln("TTS合成数据为空")
|
||||||
return ttsData.Data, errorsx.ThirdPartyErr
|
return ttsData.Data, errorsx.ThirdPartyErr
|
||||||
}
|
}
|
||||||
return ttsData.Data, nil
|
return ttsData.Data, nil
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(tts.Timeout) * time.Second):
|
case <-time.After(time.Duration(tts.Timeout) * time.Second):
|
||||||
|
zap.S().Errorln("TTS合成超时")
|
||||||
return ttsData.Data, errorsx.DriverTimeoutErr
|
return ttsData.Data, errorsx.DriverTimeoutErr
|
||||||
case <-tts.ctx.Done():
|
case <-tts.ctx.Done():
|
||||||
|
zap.S().Errorln("TTS合成被取消")
|
||||||
return ttsData.Data, errorsx.DriverCancelErr
|
return ttsData.Data, errorsx.DriverCancelErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user