react-native-davoice-tts 1.0.233 → 1.0.234

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.
@@ -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.106" # Update to your package version
5
+ s.version = "1.0.107" # 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 .
@@ -17,6 +17,12 @@ import java.nio.ByteBuffer;
17
17
  import java.nio.ByteOrder;
18
18
  import java.util.Locale;
19
19
  import android.util.Base64;
20
+ import android.media.MediaPlayer;
21
+
22
+ import android.util.Log;
23
+ import android.content.res.AssetFileDescriptor;
24
+ import java.io.IOException;
25
+
20
26
 
21
27
  import com.davoice.tts.DaVoiceTTSInterface;
22
28
 
@@ -246,34 +252,45 @@ public class DaVoiceTTSBridge extends ReactContextBaseJavaModule {
246
252
  // }
247
253
  // }
248
254
  // ADD
249
- public void playWav(String pathOrURL, boolean markAsLast, Promise promise) {
250
- final String TAG = "TTS";
251
- Log.d(TAG, "playWav() called with: " + pathOrURL + " | markAsLast=" + markAsLast);
252
-
253
- try {
255
+
256
+ @ReactMethod
257
+ public void playWav(String pathOrURL, boolean markAsLast, Promise promise) {
258
+ final String TAG = "TTS";
259
+ Log.d(TAG, "playWav() called with: " + pathOrURL + " | markAsLast=" + markAsLast);
260
+ // 1️⃣ Handle RN dev server URLs (http://localhost:8081/...) by downloading them to cache first
261
+ try {
254
262
  if (isHttpOrHttps(pathOrURL)) {
255
- Log.e(TAG, "Rejected remote URL: " + pathOrURL);
256
- promise.reject("unsupported_url", "Remote URLs not supported. Download to a local file first.");
257
- return;
263
+ Log.w(TAG, "Downloading asset from dev server: " + pathOrURL);
264
+ java.net.URL url = new java.net.URL(pathOrURL);
265
+ java.io.InputStream in = url.openStream();
266
+ File out = new File(reactCtx.getCacheDir(), "rn_asset_" + System.currentTimeMillis() + ".wav");
267
+ try (FileOutputStream fos = new FileOutputStream(out)) {
268
+ byte[] buf = new byte[8192];
269
+ int len;
270
+ while ((len = in.read(buf)) != -1) fos.write(buf, 0, len);
271
+ }
272
+ in.close();
273
+ Log.d(TAG, "Downloaded asset to: " + out.getAbsolutePath());
274
+ tts.playWav(out, markAsLast);
275
+ promise.resolve("queued");
276
+ return;
258
277
  }
259
278
 
260
- // --- NEW: handle require() assets from RN ---
279
+ // 2️⃣ Handle require() assets (resolved as "asset:/...") via Android asset manager
261
280
  if (pathOrURL.startsWith("asset:/")) {
262
281
  String assetName = pathOrURL.replace("asset:/", "");
263
282
  Log.d(TAG, "Detected bundled asset: " + assetName);
264
- try (AssetFileDescriptor afd = getReactApplicationContext().getAssets().openFd(assetName)) {
265
- Log.d(TAG, "Successfully opened asset: " + assetName +
266
- " | startOffset=" + afd.getStartOffset() +
267
- " | length=" + afd.getLength());
268
- tts.playWav(afd, markAsLast); // overload that accepts AssetFileDescriptor
269
- Log.d(TAG, "Queued asset playback successfully.");
270
- promise.resolve("queued");
271
- return;
272
- } catch (IOException e) {
273
- Log.e(TAG, "Failed to open asset: " + assetName + " | " + e.getMessage(), e);
274
- promise.reject("asset_load_failed", "Unable to open bundled asset: " + e.getMessage(), e);
275
- return;
283
+ File tmp = new File(reactCtx.getCacheDir(), "asset_" + System.currentTimeMillis() + ".wav");
284
+ try (java.io.InputStream in = reactCtx.getAssets().open(assetName);
285
+ FileOutputStream out = new FileOutputStream(tmp)) {
286
+ byte[] buf = new byte[8192];
287
+ int len;
288
+ while ((len = in.read(buf)) != -1) out.write(buf, 0, len);
276
289
  }
290
+ Log.d(TAG, "Copied asset to: " + tmp.getAbsolutePath());
291
+ tts.playWav(tmp, markAsLast);
292
+ promise.resolve("queued");
293
+ return;
277
294
  }
278
295
 
279
296
  // --- file:// handling ---
@@ -332,27 +332,85 @@ RCT_EXPORT_METHOD(playWav:(NSString *)pathOrURL
332
332
  resolver:(RCTPromiseResolveBlock)resolve
333
333
  rejecter:(RCTPromiseRejectBlock)reject)
334
334
  {
335
- if (!self.tts) { reject(@"no_tts", @"Call initAll first", nil); return; }
335
+ if (!self.tts) {
336
+ reject(@"no_tts", @"Call initAll first", nil);
337
+ return;
338
+ }
339
+
340
+ if (pathOrURL == nil || pathOrURL.length == 0) {
341
+ reject(@"bad_path", @"Empty pathOrURL", nil);
342
+ return;
343
+ }
336
344
 
337
- NSURL *url = nil;
338
- if ([pathOrURL hasPrefix:@"http://"] || [pathOrURL hasPrefix:@"https://"] || [pathOrURL hasPrefix:@"file://"]) {
339
- url = [NSURL URLWithString:pathOrURL];
340
- if (url.isFileURL == NO) {
341
- // For remote URLs: you’d normally download first. Keep it simple: reject.
342
- reject(@"unsupported_url", @"Remote URLs not supported. Download to a file path first.", nil);
345
+ NSURL *fileURL = nil;
346
+
347
+ // 1️⃣ Handle http(s) URLs — download to temporary file first
348
+ if ([pathOrURL hasPrefix:@"http://"] || [pathOrURL hasPrefix:@"https://"]) {
349
+ NSLog(@"[TTS] Downloading asset from URL: %@", pathOrURL);
350
+ NSURL *remoteURL = [NSURL URLWithString:pathOrURL];
351
+ if (!remoteURL) {
352
+ reject(@"bad_url", @"Invalid remote URL", nil);
343
353
  return;
344
354
  }
345
- } else {
346
- url = [NSURL fileURLWithPath:pathOrURL];
355
+
356
+ NSData *data = [NSData dataWithContentsOfURL:remoteURL];
357
+ if (!data) {
358
+ reject(@"download_failed", @"Failed to download remote asset", nil);
359
+ return;
360
+ }
361
+
362
+ NSString *tempName = [NSString stringWithFormat:@"rn_asset_%f.wav", [[NSDate date] timeIntervalSince1970]];
363
+ NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:tempName];
364
+ if (![data writeToFile:tempPath atomically:YES]) {
365
+ reject(@"write_failed", @"Failed to write temporary file", nil);
366
+ return;
367
+ }
368
+ fileURL = [NSURL fileURLWithPath:tempPath];
369
+ NSLog(@"[TTS] Downloaded to temp file: %@", tempPath);
370
+ }
371
+
372
+ // 2️⃣ Handle bundled asset:/ paths (copied from main bundle)
373
+ else if ([pathOrURL hasPrefix:@"asset:/"]) {
374
+ NSString *assetName = [pathOrURL stringByReplacingOccurrencesOfString:@"asset:/" withString:@""];
375
+ NSLog(@"[TTS] Detected bundled asset: %@", assetName);
376
+ NSString *bundlePath = [[NSBundle mainBundle] pathForResource:[assetName stringByDeletingPathExtension]
377
+ ofType:[assetName pathExtension]];
378
+ if (!bundlePath) {
379
+ reject(@"asset_missing", [NSString stringWithFormat:@"Asset not found in bundle: %@", assetName], nil);
380
+ return;
381
+ }
382
+ // Copy to temp file so we have a writable/accessible URL
383
+ NSString *tempName = [NSString stringWithFormat:@"asset_%f.wav", [[NSDate date] timeIntervalSince1970]];
384
+ NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:tempName];
385
+ NSError *copyError = nil;
386
+ [[NSFileManager defaultManager] copyItemAtPath:bundlePath toPath:tempPath error:&copyError];
387
+ if (copyError) {
388
+ reject(@"asset_copy_failed", copyError.localizedDescription, copyError);
389
+ return;
390
+ }
391
+ fileURL = [NSURL fileURLWithPath:tempPath];
392
+ NSLog(@"[TTS] Copied bundled asset to temp: %@", tempPath);
393
+ }
394
+
395
+ // 3️⃣ Handle file:// URLs
396
+ else if ([pathOrURL hasPrefix:@"file://"]) {
397
+ fileURL = [NSURL URLWithString:pathOrURL];
398
+ }
399
+
400
+ // 4️⃣ Otherwise assume direct local path
401
+ else {
402
+ fileURL = [NSURL fileURLWithPath:pathOrURL];
347
403
  }
348
404
 
349
- if (![[NSFileManager defaultManager] fileExistsAtPath:url.path]) {
350
- reject(@"file_missing", @"WAV file does not exist at path", nil);
405
+ // 5️⃣ Verify existence
406
+ if (!fileURL || ![[NSFileManager defaultManager] fileExistsAtPath:fileURL.path]) {
407
+ reject(@"file_missing", [NSString stringWithFormat:@"File missing: %@", fileURL.path], nil);
351
408
  return;
352
409
  }
353
410
 
354
- // Pass through to DaVoiceTTS (which routes via AEC graph/queue)
355
- [self.tts playWav:url markAsLastUtterance:markAsLast.boolValue];
411
+ // 6️⃣ Play through TTS engine (queued)
412
+ NSLog(@"[TTS] Playing file via DaVoiceTTS: %@", fileURL.path);
413
+ [self.tts playWav:fileURL markAsLastUtterance:markAsLast.boolValue];
356
414
  resolve(@"queued");
357
415
  }
358
416
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-davoice-tts",
3
- "version": "1.0.233",
3
+ "version": "1.0.234",
4
4
  "description": "tts library for React Native",
5
5
  "main": "tts/index.js",
6
6
  "types": "tts/index.d.ts",
package/speech/index.ts CHANGED
@@ -408,18 +408,40 @@ private rewireListenersForMode() {
408
408
 
409
409
  // --- NEW: TTS passthroughs for external audio ---
410
410
  /** Queue a WAV file (local path, file:// URL, or require() asset). */
411
- async playWav(pathOrURL: string | number, markAsLast = true) {
411
+ async playWav(pathOrURL: any, markAsLast = true) {
412
412
  // NEW: resolve require() assets to actual file path/URI
413
+ console.log('[Speech.playWav] called with:', pathOrURL, '| type:', typeof pathOrURL);
414
+ const resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource').default;
415
+
413
416
  const asset = resolveAssetSource(pathOrURL);
414
- const realPath = asset?.uri ?? pathOrURL; // fallback keeps string path intact
417
+ console.log('[Speech.playWav] resolveAssetSource ->', asset);
418
+
419
+ let realPath = asset?.uri ?? pathOrURL; // fallback keeps string path intact
420
+ console.log('[Speech.playWav] resolved realPath:', realPath);
421
+
422
+ // ✅ Coerce to string explicitly
423
+ if (typeof realPath !== 'string') {
424
+ realPath = String(realPath);
425
+ console.log('[Speech.playWav] converted ?? realPath:', realPath);
426
+ }
427
+
428
+ console.log('[Speech.playWav] before checking ios realPath:', realPath);
415
429
 
416
430
  // Prefer unified iOS bridge if present
417
431
  if (Platform.OS === 'ios' && NativeSpeech?.playWav) {
418
432
  return NativeSpeech.playWav(realPath, markAsLast);
419
433
  }
434
+ console.log('[Speech.playWav] after checking ios realPath:', realPath);
435
+ console.log('[Speech.playWav] after checking ios realPath:', typeof(realPath));
420
436
 
421
437
  // Fallback: direct TTS bridge (Android + iOS fallback)
422
- if (!NativeTTS?.playWav) throw new Error('playWav not available on this platform.');
438
+ if (!NativeTTS?.playWav) {
439
+ console.log('[Speech.playWav] NativeTTS:', NativeTTS);
440
+ if (NativeTTS)
441
+ console.log('[Speech.playWav] NativeTTS.playWav :', NativeTTS.playWav);
442
+ throw new Error('playWav not available on this platform.');
443
+ }
444
+ console.log('[Speech.playWav] calling NativeTTS.playWav with type of realPath:', typeof(realPath));
423
445
  return NativeTTS.playWav(realPath, markAsLast);
424
446
  }
425
447