react-native-davoice-tts 1.0.221 → 1.0.222

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.
Files changed (17) hide show
  1. package/TTSRNBridge.podspec +1 -1
  2. package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar +0 -0
  3. package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar.md5 +1 -1
  4. package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar.sha1 +1 -1
  5. package/android/src/main/java/com/davoice/tts/rn/DaVoiceTTSBridge.java +217 -0
  6. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/DavoiceTTS +0 -0
  7. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/DavoiceTTS +0 -0
  8. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.abi.json +2683 -2683
  9. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +20 -20
  10. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftinterface +20 -20
  11. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.abi.json +2683 -2683
  12. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +20 -20
  13. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +20 -20
  14. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeDirectory +0 -0
  15. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeRequirements-1 +0 -0
  16. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeResources +24 -24
  17. package/package.json +1 -1
@@ -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.94" # Update to your package version
5
+ s.version = "1.0.95" # 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 .
@@ -1 +1 @@
1
- 9d2393d89488225501c6523df0501188 tts-1.0.0.aar
1
+ 30c97d4e8ff0ac2aa50ef1890af1339c tts-1.0.0.aar
@@ -1 +1 @@
1
- d8c0705f0b2d412b01a39af75eff947192920ce7 tts-1.0.0.aar
1
+ f6413e1638332011e6b4dab973174cd2bc2935da 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 */ }