@xdfnet/ispeak 1.6.12 → 1.6.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/main.go +33 -63
- package/package.json +1 -1
package/main.go
CHANGED
|
@@ -47,81 +47,51 @@ type StreamPlayer interface {
|
|
|
47
47
|
Abort() error
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
//
|
|
50
|
+
// 最简单的播放器:channel 队列,串行播报
|
|
51
51
|
type Player struct {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
ch chan job
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type job struct {
|
|
56
|
+
text string
|
|
57
|
+
voice VoiceInfo
|
|
58
|
+
cfg Config
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
func NewPlayer() *Player {
|
|
59
|
-
|
|
62
|
+
p := &Player{ch: make(chan job, 256)}
|
|
63
|
+
go p.loop()
|
|
64
|
+
return p
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
func (p *Player) Submit(text string, voice VoiceInfo, cfg Config) {
|
|
63
|
-
p.mu.Lock()
|
|
64
|
-
p.gen++
|
|
65
|
-
currentGen := p.gen
|
|
66
|
-
p.player = nil
|
|
67
|
-
|
|
68
|
-
player, err := newDefaultStreamPlayer()
|
|
69
|
-
if err != nil {
|
|
70
|
-
log.Printf("启动播放器失败: %v", err)
|
|
71
|
-
p.mu.Unlock()
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
p.player = player
|
|
75
68
|
log.Printf("TTS: %s", text)
|
|
69
|
+
p.ch <- job{text, voice, cfg}
|
|
70
|
+
}
|
|
76
71
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}()
|
|
84
|
-
|
|
85
|
-
onAudio := func(audio []byte) error {
|
|
86
|
-
p.mu.Lock()
|
|
87
|
-
stale := currentGen != p.gen
|
|
88
|
-
p.mu.Unlock()
|
|
89
|
-
if stale {
|
|
90
|
-
return errors.New("stale")
|
|
91
|
-
}
|
|
92
|
-
if err := player.Write(audio); err != nil {
|
|
93
|
-
return err
|
|
94
|
-
}
|
|
95
|
-
if len(audio) > 0 {
|
|
96
|
-
log.Printf("首个音频 chunk elapsed=%s bytes=%d", time.Since(startedAt).Round(time.Millisecond), len(audio))
|
|
97
|
-
}
|
|
98
|
-
return nil
|
|
72
|
+
func (p *Player) loop() {
|
|
73
|
+
for j := range p.ch {
|
|
74
|
+
player, err := newDefaultStreamPlayer()
|
|
75
|
+
if err != nil {
|
|
76
|
+
log.Printf("启动播放器失败: %v", err)
|
|
77
|
+
continue
|
|
99
78
|
}
|
|
79
|
+
p.play(j, player)
|
|
80
|
+
_ = player.CloseAndWait()
|
|
81
|
+
}
|
|
82
|
+
}
|
|
100
83
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
p.mu.Lock()
|
|
107
|
-
if p.player == player {
|
|
108
|
-
p.player = nil
|
|
109
|
-
}
|
|
110
|
-
p.mu.Unlock()
|
|
111
|
-
return
|
|
112
|
-
}
|
|
84
|
+
func (p *Player) play(j job, player StreamPlayer) {
|
|
85
|
+
startedAt := time.Now()
|
|
86
|
+
onAudio := func(audio []byte) error {
|
|
87
|
+
return player.Write(audio)
|
|
88
|
+
}
|
|
113
89
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if p.player == player {
|
|
120
|
-
p.player = nil
|
|
121
|
-
}
|
|
122
|
-
p.mu.Unlock()
|
|
123
|
-
}()
|
|
124
|
-
p.mu.Unlock()
|
|
90
|
+
if err := synthesizeStream(context.Background(), j.cfg, j.text, &j.voice, onAudio); err != nil {
|
|
91
|
+
log.Printf("TTS 合成失败: %v", err)
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
log.Printf("TTS: 完成 elapsed=%s", time.Since(startedAt).Round(time.Millisecond))
|
|
125
95
|
}
|
|
126
96
|
|
|
127
97
|
// 音色信息
|
package/package.json
CHANGED