react-native-davoice-tts 1.0.221 → 1.0.223
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/TTSRNBridge.podspec +1 -1
- package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar +0 -0
- package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar.md5 +1 -1
- package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar.sha1 +1 -1
- package/android/src/main/java/com/davoice/tts/rn/DaVoiceTTSBridge.java +217 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/DavoiceTTS +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/DavoiceTTS +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.abi.json +2683 -2683
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +20 -20
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftinterface +20 -20
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.abi.json +2683 -2683
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +20 -20
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +20 -20
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeDirectory +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeRequirements-1 +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeResources +24 -24
- package/package.json +1 -1
package/TTSRNBridge.podspec
CHANGED
|
@@ -2,7 +2,7 @@ require 'json'
|
|
|
2
2
|
|
|
3
3
|
Pod::Spec.new do |s|
|
|
4
4
|
s.name = "TTSRNBridge"
|
|
5
|
-
s.version = "1.0.
|
|
5
|
+
s.version = "1.0.96" # Update to your package version
|
|
6
6
|
s.summary = "TTS for React Native."
|
|
7
7
|
s.description = <<-DESC
|
|
8
8
|
A React Native module for tts .
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
b6f649e4214247f6227a360f42a39d24 tts-1.0.0.aar
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
cb0eb9b0e301262eeee35378d269f5716fcfe679 tts-1.0.0.aar
|
|
@@ -9,6 +9,14 @@ import com.facebook.react.bridge.ReactMethod;
|
|
|
9
9
|
import com.facebook.react.bridge.ReadableMap;
|
|
10
10
|
import com.facebook.react.bridge.WritableMap;
|
|
11
11
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
12
|
+
// ADD
|
|
13
|
+
import android.net.Uri;
|
|
14
|
+
import java.io.File;
|
|
15
|
+
import java.io.FileOutputStream;
|
|
16
|
+
import java.nio.ByteBuffer;
|
|
17
|
+
import java.nio.ByteOrder;
|
|
18
|
+
import java.util.Locale;
|
|
19
|
+
import android.util.Base64;
|
|
12
20
|
|
|
13
21
|
import com.davoice.tts.DaVoiceTTSInterface;
|
|
14
22
|
|
|
@@ -92,6 +100,215 @@ public class DaVoiceTTSBridge extends ReactContextBaseJavaModule {
|
|
|
92
100
|
promise.reject("DestroyError", e.getMessage(), e);
|
|
93
101
|
}
|
|
94
102
|
}
|
|
103
|
+
// ADD
|
|
104
|
+
private static boolean isHttpOrHttps(String s) {
|
|
105
|
+
if (s == null) return false;
|
|
106
|
+
String ls = s.toLowerCase(Locale.US);
|
|
107
|
+
return ls.startsWith("http://") || ls.startsWith("https://");
|
|
108
|
+
}
|
|
109
|
+
// ADD
|
|
110
|
+
private static boolean isFileUrl(String s) {
|
|
111
|
+
if (s == null) return false;
|
|
112
|
+
String ls = s.toLowerCase(Locale.US);
|
|
113
|
+
return ls.startsWith("file://");
|
|
114
|
+
}
|
|
115
|
+
// ADD
|
|
116
|
+
private static byte[] b64(String base64) throws Exception {
|
|
117
|
+
return Base64.decode(base64, Base64.DEFAULT);
|
|
118
|
+
}
|
|
119
|
+
// ADD
|
|
120
|
+
private static byte[] intLE(int v) {
|
|
121
|
+
return new byte[] {
|
|
122
|
+
(byte)(v & 0xFF),
|
|
123
|
+
(byte)((v >> 8) & 0xFF),
|
|
124
|
+
(byte)((v >> 16) & 0xFF),
|
|
125
|
+
(byte)((v >> 24) & 0xFF)
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// ADD
|
|
129
|
+
private static byte[] shortLE(short v) {
|
|
130
|
+
return new byte[] {
|
|
131
|
+
(byte)(v & 0xFF),
|
|
132
|
+
(byte)((v >> 8) & 0xFF)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// ADD
|
|
136
|
+
private static void writeWavF32(File out, float[] pcm, int sampleRate) throws Exception {
|
|
137
|
+
int numChannels = 1;
|
|
138
|
+
int bitsPerSample = 32;
|
|
139
|
+
int byteRate = sampleRate * numChannels * (bitsPerSample / 8);
|
|
140
|
+
int subchunk2Size = pcm.length * numChannels * (bitsPerSample / 8);
|
|
141
|
+
int chunkSize = 36 + subchunk2Size;
|
|
142
|
+
|
|
143
|
+
try (FileOutputStream fos = new FileOutputStream(out)) {
|
|
144
|
+
fos.write(new byte[] { 'R','I','F','F' });
|
|
145
|
+
fos.write(intLE(chunkSize));
|
|
146
|
+
fos.write(new byte[] { 'W','A','V','E' });
|
|
147
|
+
|
|
148
|
+
fos.write(new byte[] { 'f','m','t',' ' });
|
|
149
|
+
fos.write(intLE(16));
|
|
150
|
+
fos.write(shortLE((short) 3)); // IEEE float
|
|
151
|
+
fos.write(shortLE((short) numChannels));
|
|
152
|
+
fos.write(intLE(sampleRate));
|
|
153
|
+
fos.write(intLE(byteRate));
|
|
154
|
+
fos.write(shortLE((short) (numChannels * (bitsPerSample / 8))));
|
|
155
|
+
fos.write(shortLE((short) bitsPerSample));
|
|
156
|
+
|
|
157
|
+
fos.write(new byte[] { 'd','a','t','a' });
|
|
158
|
+
fos.write(intLE(subchunk2Size));
|
|
159
|
+
|
|
160
|
+
ByteBuffer bb = ByteBuffer.allocate(pcm.length * 4).order(ByteOrder.LITTLE_ENDIAN);
|
|
161
|
+
for (float v : pcm) bb.putFloat(v);
|
|
162
|
+
fos.write(bb.array());
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// ADD
|
|
166
|
+
private static void mixI16InterleavedToMonoF32(short[] src, int channels, float[] dst) {
|
|
167
|
+
int frames = dst.length, idx = 0;
|
|
168
|
+
for (int f = 0; f < frames; f++) {
|
|
169
|
+
int acc = 0;
|
|
170
|
+
for (int ch = 0; ch < channels; ch++) acc += src[idx++];
|
|
171
|
+
dst[f] = (acc / (float) channels) / 32768.0f;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// ADD
|
|
175
|
+
private static void mixI16PlanarToMonoF32(short[] src, int frames, int channels, float[] dst) {
|
|
176
|
+
int plane = frames;
|
|
177
|
+
for (int f = 0; f < frames; f++) {
|
|
178
|
+
int acc = 0;
|
|
179
|
+
for (int ch = 0; ch < channels; ch++) acc += src[ch * plane + f];
|
|
180
|
+
dst[f] = (acc / (float) channels) / 32768.0f;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// ADD
|
|
184
|
+
private static void mixF32InterleavedToMono(float[] src, int channels, float[] dst) {
|
|
185
|
+
int frames = dst.length, idx = 0;
|
|
186
|
+
for (int f = 0; f < frames; f++) {
|
|
187
|
+
float acc = 0f;
|
|
188
|
+
for (int ch = 0; ch < channels; ch++) acc += src[idx++];
|
|
189
|
+
dst[f] = acc / channels;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// ADD
|
|
193
|
+
private static void mixF32PlanarToMono(float[] src, int frames, int channels, float[] dst) {
|
|
194
|
+
int plane = frames;
|
|
195
|
+
for (int f = 0; f < frames; f++) {
|
|
196
|
+
float acc = 0f;
|
|
197
|
+
for (int ch = 0; ch < channels; ch++) acc += src[ch * plane + f];
|
|
198
|
+
dst[f] = acc / channels;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// ADD
|
|
202
|
+
@ReactMethod
|
|
203
|
+
public void playWav(String pathOrURL, boolean markAsLast, Promise promise) {
|
|
204
|
+
try {
|
|
205
|
+
if (isHttpOrHttps(pathOrURL)) {
|
|
206
|
+
promise.reject("unsupported_url", "Remote URLs not supported. Download to a local file first.");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
String path = pathOrURL;
|
|
210
|
+
if (isFileUrl(pathOrURL)) {
|
|
211
|
+
Uri u = Uri.parse(pathOrURL);
|
|
212
|
+
File f = new File(u.getPath());
|
|
213
|
+
path = f.getAbsolutePath();
|
|
214
|
+
}
|
|
215
|
+
if (path == null) {
|
|
216
|
+
promise.reject("bad_path", "Invalid file URL");
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
File f = new File(path);
|
|
220
|
+
if (!f.exists()) {
|
|
221
|
+
promise.reject("file_missing", "WAV file does not exist at path");
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
tts.playWav(f, markAsLast);
|
|
225
|
+
promise.resolve("queued");
|
|
226
|
+
} catch (Exception e) {
|
|
227
|
+
promise.reject("PlayWavError", e.getMessage(), e);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// ADD
|
|
231
|
+
@ReactMethod
|
|
232
|
+
public void playBuffer(ReadableMap desc, Promise promise) {
|
|
233
|
+
try {
|
|
234
|
+
if (desc == null ||
|
|
235
|
+
!desc.hasKey("base64") || desc.isNull("base64") ||
|
|
236
|
+
!desc.hasKey("sampleRate") || desc.isNull("sampleRate") ||
|
|
237
|
+
!desc.hasKey("format") || desc.isNull("format")) {
|
|
238
|
+
promise.reject("invalid_args", "Missing one of base64/sampleRate/format");
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
final String base64 = desc.getString("base64");
|
|
242
|
+
final int sampleRate = desc.getInt("sampleRate");
|
|
243
|
+
final String format = desc.getString("format");
|
|
244
|
+
final int channels = desc.hasKey("channels") && !desc.isNull("channels") ? desc.getInt("channels") : 1;
|
|
245
|
+
final boolean interleaved = desc.hasKey("interleaved") && !desc.isNull("interleaved") ? desc.getBoolean("interleaved") : true;
|
|
246
|
+
final boolean markAsLast = desc.hasKey("markAsLast") && !desc.isNull("markAsLast") ? desc.getBoolean("markAsLast") : true;
|
|
247
|
+
if (sampleRate <= 0 || channels <= 0) {
|
|
248
|
+
promise.reject("bad_params", "sampleRate and channels must be > 0");
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
final byte[] raw = b64(base64);
|
|
253
|
+
if (raw == null || raw.length == 0) {
|
|
254
|
+
promise.reject("bad_base64", "Could not decode base64 payload");
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
float[] mono;
|
|
259
|
+
if ("i16".equalsIgnoreCase(format)) {
|
|
260
|
+
if (raw.length % 2 != 0) {
|
|
261
|
+
promise.reject("bad_buffer", "i16 payload length not multiple of 2");
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
int frames = (raw.length / 2) / Math.max(1, channels);
|
|
265
|
+
mono = new float[frames];
|
|
266
|
+
|
|
267
|
+
short[] s = new short[raw.length / 2];
|
|
268
|
+
ByteBuffer bb = ByteBuffer.wrap(raw).order(ByteOrder.LITTLE_ENDIAN);
|
|
269
|
+
for (int i = 0; i < s.length; i++) s[i] = bb.getShort();
|
|
270
|
+
|
|
271
|
+
if (channels == 1) {
|
|
272
|
+
for (int i = 0; i < frames; i++) mono[i] = s[i] / 32768.0f;
|
|
273
|
+
} else if (interleaved) {
|
|
274
|
+
mixI16InterleavedToMonoF32(s, channels, mono);
|
|
275
|
+
} else {
|
|
276
|
+
mixI16PlanarToMonoF32(s, frames, channels, mono);
|
|
277
|
+
}
|
|
278
|
+
} else if ("f32".equalsIgnoreCase(format)) {
|
|
279
|
+
if (raw.length % 4 != 0) {
|
|
280
|
+
promise.reject("bad_buffer", "f32 payload length not multiple of 4");
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
int totalFloats = raw.length / 4;
|
|
284
|
+
float[] f = new float[totalFloats];
|
|
285
|
+
ByteBuffer bb = ByteBuffer.wrap(raw).order(ByteOrder.LITTLE_ENDIAN);
|
|
286
|
+
for (int i = 0; i < totalFloats; i++) f[i] = bb.getFloat();
|
|
287
|
+
|
|
288
|
+
int frames = totalFloats / Math.max(1, channels);
|
|
289
|
+
mono = new float[frames];
|
|
290
|
+
|
|
291
|
+
if (channels == 1) {
|
|
292
|
+
System.arraycopy(f, 0, mono, 0, frames);
|
|
293
|
+
} else if (interleaved) {
|
|
294
|
+
mixF32InterleavedToMono(f, channels, mono);
|
|
295
|
+
} else {
|
|
296
|
+
mixF32PlanarToMono(f, frames, channels, mono);
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
promise.reject("bad_format", "format must be 'i16' or 'f32'");
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
File out = new File(reactCtx.getCacheDir(), "extbuf_" + System.currentTimeMillis() + ".wav");
|
|
304
|
+
writeWavF32(out, mono, sampleRate);
|
|
305
|
+
|
|
306
|
+
tts.playWav(out, markAsLast);
|
|
307
|
+
promise.resolve("queued");
|
|
308
|
+
} catch (Exception e) {
|
|
309
|
+
promise.reject("PlayBufferError", e.getMessage(), e);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
95
312
|
|
|
96
313
|
// RN event API stubs (required by RN)
|
|
97
314
|
@ReactMethod public void addListener(String eventName) { /* no-op */ }
|
|
Binary file
|