5
5
#include < thread>
6
6
7
7
8
+ WasapiPlayer* g_player = nullptr ; // Make it global to avoid multiple voices when reinitializing
9
+
10
+
8
11
static char * trim (char * data, unsigned long * size, WAVEFORMATEX* wfx, int threshold) {
9
12
int channels = wfx->nChannels ;
10
13
int bytesPerSample = wfx->wBitsPerSample / 8 ;
@@ -56,24 +59,30 @@ struct PCMData {
56
59
57
60
std::vector<PCMData> g_dataQueue;
58
61
bool g_threadStarted = false ;
59
- static void sapi_thread (WasapiPlayer* player ) {
60
- if (player == nullptr ) {
62
+ static void sapi_thread () {
63
+ if (g_player == nullptr ) {
61
64
g_threadStarted = false ;
62
65
}
63
66
HRESULT hr;
64
67
while (g_threadStarted) {
65
68
Sleep (1 );
66
69
for (uint64_t i = 0 ; i < g_dataQueue.size (); ++i) {
67
70
68
- hr = player ->feed (g_dataQueue[i].data , g_dataQueue[i].size , nullptr );
71
+ hr = g_player ->feed (g_dataQueue[i].data , g_dataQueue[i].size , nullptr );
69
72
if (FAILED (hr))continue ;
70
- hr = player ->sync ();
73
+ hr = g_player ->sync ();
71
74
if (FAILED (hr))continue ;
72
75
}
73
76
if (g_dataQueue.size () > 0 ) g_dataQueue.clear ();
74
77
}
78
+ delete g_player;
79
+ g_player = nullptr ;
75
80
}
76
81
bool SAPI::Initialize () {
82
+ if (g_player) {
83
+ g_threadStarted = false ;
84
+ g_player->stop ();
85
+ }
77
86
instance = new blastspeak;
78
87
79
88
if (blastspeak_initialize (instance) == 0 ) {
@@ -92,34 +101,31 @@ bool SAPI::Initialize() {
92
101
wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample ) / 8 ;
93
102
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign ;
94
103
wfx.cbSize = 0 ;
95
- player = new WasapiPlayer (device, wfx, callback);
96
- HRESULT hr = player ->open ();
104
+ g_player = new WasapiPlayer (device, wfx, callback);
105
+ HRESULT hr = g_player ->open ();
97
106
if (FAILED (hr)) {
98
- delete player ;
99
- player = nullptr ;
107
+ delete g_player ;
108
+ g_player = nullptr ;
100
109
return false ;
101
110
}
102
111
g_threadStarted = true ;
103
- std::thread t (sapi_thread, player );
112
+ std::thread t (sapi_thread);
104
113
t.detach ();
105
114
return true ;
106
115
}
107
116
bool SAPI::Uninitialize () {
108
- if (instance == nullptr || player == nullptr )return false ;
109
- g_threadStarted = false ;
117
+ if (instance == nullptr || g_player == nullptr )return false ;
118
+ g_threadStarted = false ; // SAPI thread will be stopped when all messages was spoken
110
119
blastspeak_destroy (instance);
111
120
delete instance;
112
121
instance = nullptr ;
113
- StopSpeech ();
114
- delete player;
115
- player = nullptr ;
116
122
return true ;
117
123
}
118
124
bool SAPI::GetActive () {
119
- return instance != nullptr ;
125
+ return instance != nullptr && g_player != nullptr ;
120
126
}
121
127
bool SAPI::Speak (const char * text, bool interrupt) {
122
- if (instance == nullptr || player == nullptr )
128
+ if (instance == nullptr || g_player == nullptr )
123
129
return false ;
124
130
if (interrupt) {
125
131
StopSpeech ();
@@ -145,7 +151,7 @@ bool SAPI::Speak(const char* text, bool interrupt) {
145
151
if (this ->paused ) {
146
152
this ->paused = false ;
147
153
if (!interrupt)
148
- player ->resume ();
154
+ g_player ->resume ();
149
155
}
150
156
g_dataQueue.push_back (dat);
151
157
return true ;
@@ -176,19 +182,19 @@ bool SAPI::SetParameter(int param, int value) {
176
182
177
183
178
184
bool SAPI::StopSpeech () {
179
- if (player == nullptr )return false ;
185
+ if (g_player == nullptr )return false ;
180
186
g_dataQueue.clear ();
181
- player ->stop ();
187
+ g_player ->stop ();
182
188
this ->paused = false ;
183
189
return true ;
184
190
}
185
191
bool SAPI::PauseSpeech () {
186
192
paused = true ;
187
- return SUCCEEDED (player ->pause ());
193
+ return SUCCEEDED (g_player ->pause ());
188
194
}
189
195
bool SAPI::ResumeSpeech () {
190
196
paused = false ;
191
- return SUCCEEDED (player ->resume ());
197
+ return SUCCEEDED (g_player ->resume ());
192
198
}
193
199
void SAPI::SetVolume (uint64_t value) {
194
200
if (instance == nullptr )return ;
0 commit comments