1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
//! This library is a wrapper of **MSEdge Read aloud** function API.
//! You can use it to synthesize text to speech with many voices MS provided.
//!
//! # Features
//! + `native-tls`: use native tls for https and websocket. Default
//! + `ssl-key-log`: enbale `SSLKEYLOGFILE` log for some traffic analysis tools like wireshark. Debug Only
//!
//! # How to use
//! 1. You need get a [SpeechConfig](tts::SpeechConfig) to configure the voice of text to speech.
//! This library has a [get_voices_list](voice::get_voices_list) function to get all available voices.
//! You can also use [get_voices_list_async](voice::get_voices_list_async) function to get all available voices asynchronously.
//! [Voice](voice::Voice) implemented [serde::Serialize] and [serde::Deserialize].
//! You can convert [Voice](voice::Voice) to [SpeechConfig](tts::SpeechConfig) simply. For example:
//! ```rust
//! use msedge_tts::voice::get_voices_list;
//! use msedge_tts::tts::SpeechConfig;
//!
//! fn main() {
//! let voices = get_voices_list().unwrap();
//! let speechConfig = SpeechConfig::from(&voices[0]);
//! }
//! ```
//! You can also create [SpeechConfig](tts::SpeechConfig) by yourself. Make sure you know the right **voice name** and **audio format**.
//!
//! 2. Create a synthesis Client or Stream. Both of them have sync and async version. Example below step 3.
//!
//! 3. Synthesize text to speech.
//! ### Sync Client
//! Call client function [synthesize](tts::client::MSEdgeTTSClient::synthesize) to synthesize text to speech. This function return Type [SynthesizedAudio](tts::client::SynthesizedAudio),
//! you can get [audio_bytes](tts::client::SynthesizedAudio::audio_bytes) and [audio_metadata](tts::client::SynthesizedAudio::audio_metadata).
//! ```rust
//! use msedge_tts::{tts::client::MSEdgeTTSClient, tts::SpeechConfig, voice::get_voices_list};
//!
//! fn main() {
//! let voices = get_voices_list().unwrap();
//! for voice in &voices {
//! if voice.name.contains("YunyangNeural") {
//! let config = SpeechConfig::from(voice);
//! let mut tts = MSEdgeTTSClient::connect().unwrap();
//! let audio = tts
//! .synthesize("Hello, World! 你好,世界!", &config)
//! .unwrap();
//! break;
//! }
//! }
//! }
//! ```
//! ### Async Client
//! Call client function [synthesize_async](tts::client::MSEdgeTTSClientAsync::synthesize_async) to synthesize text to speech. This function return Type [SynthesizedAudio](tts::client::SynthesizedAudio),
//! you can get [audio_bytes](tts::client::SynthesizedAudio::audio_bytes) and [audio_metadata](tts::client::SynthesizedAudio::audio_metadata).
//! ```rust
//! use msedge_tts::{tts::client::MSEdgeTTSClientAsync, tts::SpeechConfig, voice::get_voices_list_async};
//!
//! fn main() {
//! smol::block_on(async {
//! let voices = get_voices_list_async().await.unwrap();
//! for voice in &voices {
//! if voice.name.contains("YunyangNeural") {
//! let config = SpeechConfig::from(voice);
//! let mut tts = MSEdgeTTSClientAsync::connect_async().await.unwrap();
//! let audio = tts
//! .synthesize_async("Hello, World! 你好,世界!", &config)
//! .await
//! .unwrap();
//! break;
//! }
//! }
//! });
//! }
//! ```
//! ### Sync Stream
//! Call Sender Stream function [send](tts::stream::Sender::send) to synthesize text to speech. Call Reader Stream function [read](tts::stream::Reader::read) to get data.
//! [read](tts::stream::Reader::read) return [Option\<SynthesizedResponse\>](tts::stream::SynthesizedResponse), the response may be [AudioBytes](tts::stream::SynthesizedResponse::AudioBytes)
//! or [AudioMetadata](tts::stream::SynthesizedResponse::AudioMetadata) or None. This is because the **MSEdge Read aloud** API returns multiple data segment and metadata and other information sequentially.
//!
//! **Caution**: One [send](tts::stream::Sender::send) corresponds to multiple [read](tts::stream::Reader::read). Next [send](tts::stream::Sender::send) call will block until there no data to read.
//! [read](tts::stream::Reader::read) will block before you call a [send](tts::stream::Sender::send).
//! ```rust
//! use msedge_tts::{
//! tts::stream::{msedge_tts_split, SynthesizedResponse},
//! tts::SpeechConfig,
//! voice::get_voices_list,
//! };
//! use std::{
//! sync::{
//! atomic::{AtomicBool, Ordering},
//! Arc,
//! },
//! thread::spawn,
//! };
//!
//! fn main() {
//! let voices = get_voices_list().unwrap();
//! for voice in &voices {
//! if voice.name.contains("YunyangNeural") {
//! let config = SpeechConfig::from(voice);
//! let (mut sender, mut reader) = msedge_tts_split().unwrap();
//!
//! let signal = Arc::new(AtomicBool::new(false));
//! let end = signal.clone();
//! spawn(move || {
//! sender.send("Hello, World! 你好,世界!", &config).unwrap();
//! println!("synthesizing...1");
//! sender.send("Hello, World! 你好,世界!", &config).unwrap();
//! println!("synthesizing...2");
//! sender.send("Hello, World! 你好,世界!", &config).unwrap();
//! println!("synthesizing...3");
//! sender.send("Hello, World! 你好,世界!", &config).unwrap();
//! println!("synthesizing...4");
//! end.store(true, Ordering::Relaxed);
//! });
//!
//! loop {
//! if signal.load(Ordering::Relaxed) && !reader.can_read() {
//! break;
//! }
//! let audio = reader.read().unwrap();
//! if let Some(audio) = audio {
//! match audio {
//! SynthesizedResponse::AudioBytes(_) => {
//! println!("read bytes")
//! }
//! SynthesizedResponse::AudioMetadata(_) => {
//! println!("read metadata")
//! }
//! }
//! } else {
//! println!("read None");
//! }
//! }
//! }
//! }
//! }
//! ```
//! ### Async Stream
//! Call Sender Async function [send](tts::stream::SenderAsync::send) to synthesize text to speech. Call Reader Async function [read](tts::stream::ReaderAsync::read) to get data.
//! [read](tts::stream::ReaderAsync::read) return [Option\<SynthesizedResponse\>](tts::stream::SynthesizedResponse) as above.
//! [send](tts::stream::SenderAsync::send) and [read](tts::stream::ReaderAsync::read) block as above.
//! ```rust
//! use msedge_tts::{
//! tts::{
//! stream::{msedge_tts_split_async, SynthesizedResponse},
//! SpeechConfig,
//! },
//! voice::get_voices_list_async,
//! };
//! use std::{
//! sync::{
//! atomic::{AtomicBool, Ordering},
//! Arc,
//! },
//! };
//!
//! fn main() {
//! smol::block_on(async {
//! let voices = get_voices_list_async().await.unwrap();
//! for voice in &voices {
//! if voice.name.contains("YunyangNeural") {
//! let config = SpeechConfig::from(voice);
//! let (mut sender, mut reader) = msedge_tts_split_async().await.unwrap();
//!
//! let signal = Arc::new(AtomicBool::new(false));
//! let end = signal.clone();
//! smol::spawn(async move {
//! sender
//! .send("Hello, World! 你好,世界!", &config)
//! .await
//! .unwrap();
//! println!("synthesizing...1");
//! sender
//! .send("Hello, World! 你好,世界!", &config)
//! .await
//! .unwrap();
//! println!("synthesizing...2");
//! sender
//! .send("Hello, World! 你好,世界!", &config)
//! .await
//! .unwrap();
//! println!("synthesizing...3");
//! sender
//! .send("Hello, World! 你好,世界!", &config)
//! .await
//! .unwrap();
//! println!("synthesizing...4");
//! end.store(true, Ordering::Relaxed);
//! })
//! .detach();
//!
//! loop {
//! if signal.load(Ordering::Relaxed) && !reader.can_read().await {
//! break;
//! }
//! let audio = reader.read().await.unwrap();
//! if let Some(audio) = audio {
//! match audio {
//! SynthesizedResponse::AudioBytes(_) => {
//! println!("read bytes")
//! }
//! SynthesizedResponse::AudioMetadata(_) => {
//! println!("read metadata")
//! }
//! }
//! } else {
//! println!("read None");
//! }
//! }
//! }
//! }
//! });
//! }
//! ```