react-native-davoice-tts 1.0.405 → 1.0.406

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 (41) hide show
  1. package/TTSRNBridge.podspec +1 -1
  2. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  3. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  4. package/android/.gradle/9.7.1/checksums/checksums.lock +0 -0
  5. package/android/.gradle/9.7.1/fileHashes/fileHashes.lock +0 -0
  6. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  7. package/android/.gradle/buildOutputCleanup/cache.properties +1 -1
  8. package/android/build/reports/problems/problems-report.html +9 -2
  9. package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar +0 -0
  10. package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar.md5 +1 -1
  11. package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar.sha1 +1 -1
  12. package/android/src/main/java/com/davoice/stt/rn/STTModule.kt +90 -22
  13. package/ios/SpeechBridge/SpeechBridge.m +102 -12
  14. package/ios/TTSRNBridge/DavoiceTTS.xcframework/Info.plist +5 -5
  15. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/DavoiceTTS +0 -0
  16. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/Headers/DavoiceTTS-Swift.h +20 -0
  17. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios.abi.json +1246 -181
  18. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios.private.swiftinterface +34 -0
  19. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  20. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios.swiftinterface +34 -0
  21. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/DavoiceTTS +0 -0
  22. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Headers/DavoiceTTS-Swift.h +40 -0
  23. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.abi.json +1246 -181
  24. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +34 -0
  25. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  26. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftinterface +34 -0
  27. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.abi.json +1246 -181
  28. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +34 -0
  29. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  30. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +34 -0
  31. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeDirectory +0 -0
  32. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeRequirements-1 +0 -0
  33. package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeResources +33 -33
  34. package/package.json +1 -1
  35. package/speech/index.d.ts +37 -1
  36. package/speech/index.ts +99 -4
  37. package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
  38. package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
  39. package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
  40. /package/android/.gradle/{9.2.0 → 9.7.1}/fileChanges/last-build.bin +0 -0
  41. /package/android/.gradle/{9.2.0 → 9.7.1}/gc.properties +0 -0
@@ -1 +1 @@
1
- c3a053f30eb1b1dcf7851eed512231af tts-1.0.0.aar
1
+ e92b94f52a72a258f8b1e37289e0a779 tts-1.0.0.aar
@@ -1 +1 @@
1
- 373f63810dedf05e94f081b7f8550fd4661a7158 tts-1.0.0.aar
1
+ 83fce3d52b29ef2d53b9fc34694262264af77495 tts-1.0.0.aar
@@ -35,19 +35,81 @@ class STTModule(private val rc: ReactApplicationContext)
35
35
  return stt!!
36
36
  }
37
37
 
38
+ // The native side accepts the JSON itself or a path to it.
38
39
  private fun readOnboardingJson(options: ReadableMap?): String? {
39
- var onboardingJson: String? = null
40
- try {
41
- if (options != null && options.hasKey("onboardingJsonPath") && !options.isNull("onboardingJsonPath")) {
42
- val p = options.getString("onboardingJsonPath")
43
- if (!p.isNullOrBlank()) {
44
- onboardingJson = java.io.File(p).readText(Charsets.UTF_8)
45
- }
40
+ if (options == null || !options.hasKey("onboardingJsonPath") || options.isNull("onboardingJsonPath")) return null
41
+ return options.getString("onboardingJsonPath")?.takeIf { it.isNotBlank() }
42
+ }
43
+
44
+ private fun readSpeakerId(options: ReadableMap?): String =
45
+ options?.takeIf { it.hasKey("speakerId") && !it.isNull("speakerId") }?.getString("speakerId")
46
+ ?.takeIf { it.isNotBlank() } ?: "default"
47
+
48
+ // JS [{id, json}] -> List<Map<String, String?>> (json = JSON string or path).
49
+ private fun toSpeakerItems(arr: ReadableArray?): List<Map<String, String?>> {
50
+ if (arr == null) return emptyList()
51
+ val out = ArrayList<Map<String, String?>>()
52
+ for (i in 0 until arr.size()) {
53
+ val m = arr.getMap(i) ?: continue
54
+ val item = HashMap<String, String?>()
55
+ val it = m.keySetIterator()
56
+ while (it.hasNextKey()) {
57
+ val k = it.nextKey()
58
+ if (m.getType(k) == ReadableType.String) item[k] = m.getString(k)
46
59
  }
47
- } catch (_: Throwable) {
48
- onboardingJson = null
60
+ out.add(item)
49
61
  }
50
- return onboardingJson
62
+ return out
63
+ }
64
+
65
+ // `speakers` replaces the set; else `onboardingJsonPath` (+ `speakerId`) adds one
66
+ // speaker; else the current set (if any) is kept.
67
+ private fun startWithOptions(locale: String?, options: ReadableMap?) {
68
+ val speakers = options?.takeIf { it.hasKey("speakers") && !it.isNull("speakers") }?.getArray("speakers")
69
+ if (speakers != null && speakers.size() > 0) {
70
+ ensure().startSpeech(locale, toSpeakerItems(speakers))
71
+ } else {
72
+ ensure().startSpeech(locale, readOnboardingJson(options), null, readSpeakerId(options))
73
+ }
74
+ }
75
+
76
+ private fun speakerIdsArray(): WritableArray =
77
+ Arguments.createArray().apply { (stt?.getSpeakerIds() ?: emptyList()).forEach { pushString(it) } }
78
+
79
+ @ReactMethod
80
+ fun addSpeaker(speakerId: String?, jsonOrPath: String?, promise: Promise) {
81
+ try {
82
+ ensure().addSpeaker(speakerId ?: "default", jsonOrPath ?: "")
83
+ promise.resolve(speakerIdsArray())
84
+ } catch (t: Throwable) {
85
+ promise.reject("sv_add_failed", t.message, t)
86
+ }
87
+ }
88
+
89
+ @ReactMethod
90
+ fun setSpeakers(speakers: ReadableArray?, promise: Promise) {
91
+ try {
92
+ ensure().setSpeakers(toSpeakerItems(speakers))
93
+ promise.resolve(speakerIdsArray())
94
+ } catch (t: Throwable) {
95
+ promise.reject("sv_set_failed", t.message, t)
96
+ }
97
+ }
98
+
99
+ @ReactMethod
100
+ fun removeSpeaker(speakerId: String?, promise: Promise) {
101
+ promise.resolve(stt?.removeSpeaker(speakerId ?: "") ?: false)
102
+ }
103
+
104
+ @ReactMethod
105
+ fun getSpeakerIds(promise: Promise) {
106
+ promise.resolve(speakerIdsArray())
107
+ }
108
+
109
+ @ReactMethod
110
+ fun startSpeechWithSVSpeakers(locale: String?, speakers: ReadableArray?, cb: Callback) {
111
+ ensure().startSpeech(locale, toSpeakerItems(speakers))
112
+ cb.invoke(false)
51
113
  }
52
114
 
53
115
  // ===== JS API =====
@@ -83,15 +145,13 @@ class STTModule(private val rc: ReactApplicationContext)
83
145
  // ANDROID expects (locale, options, callback) like @react-native-voice
84
146
  @ReactMethod
85
147
  fun startSpeech(locale: String?, options: ReadableMap, cb: Callback) {
86
- val onboardingJson = readOnboardingJson(options)
87
- ensure().startSpeech(locale, onboardingJson, null)
148
+ startWithOptions(locale, options)
88
149
  cb.invoke(false) // parity with voice: callback(false) on success
89
150
  }
90
151
 
91
152
  @ReactMethod
92
153
  fun initWithoutModel(locale: String?, options: ReadableMap?, cb: Callback) {
93
- val onboardingJson = readOnboardingJson(options)
94
- ensure().startSpeech(locale, onboardingJson, null)
154
+ startWithOptions(locale, options)
95
155
  cb.invoke(false)
96
156
  }
97
157
 
@@ -222,16 +282,24 @@ class STTModule(private val rc: ReactApplicationContext)
222
282
  send("onSpeechError", m)
223
283
  }
224
284
 
225
- override fun onSpeechResults(best: String, all: List<String>) {
226
- val arr = Arguments.createArray().apply { all.forEach { pushString(it) } }
227
- val m = Arguments.createMap().apply { putArray("value", arr) }
228
- send("onSpeechResults", m)
285
+ // speakerIds/speakerId are added only when speaker verification is on.
286
+ private fun resultMap(values: List<String>, speakerIds: List<String>, speakerId: String?): WritableMap {
287
+ val arr = Arguments.createArray().apply { values.forEach { pushString(it) } }
288
+ return Arguments.createMap().apply {
289
+ putArray("value", arr)
290
+ if (speakerIds.isNotEmpty()) {
291
+ putArray("speakerIds", Arguments.createArray().apply { speakerIds.forEach { pushString(it) } })
292
+ if (speakerId != null) putString("speakerId", speakerId)
293
+ }
294
+ }
295
+ }
296
+
297
+ override fun onSpeechResults(best: String, all: List<String>, speakerIds: List<String>, speakerId: String?) {
298
+ send("onSpeechResults", resultMap(all, speakerIds, speakerId))
229
299
  }
230
300
 
231
- override fun onSpeechPartialResults(list: List<String>) {
232
- val arr = Arguments.createArray().apply { list.forEach { pushString(it) } }
233
- val m = Arguments.createMap().apply { putArray("value", arr) }
234
- send("onSpeechPartialResults", m)
301
+ override fun onSpeechPartialResults(list: List<String>, speakerIds: List<String>, speakerId: String?) {
302
+ send("onSpeechPartialResults", resultMap(list, speakerIds, speakerId))
235
303
  }
236
304
 
237
305
  override fun onSpeechVolumeChanged(value: Float) {
@@ -603,6 +603,106 @@ RCT_EXPORT_METHOD(clearAudioRoutingConfig:(RCTPromiseResolveBlock)resolve
603
603
  }
604
604
 
605
605
  /// initAll({ locale: "en-US", model: "/path/model.onnx", timeoutMs?: 8000 })
606
+ #pragma mark - Speaker verification (live multi-speaker)
607
+
608
+ // JS arrays of {id, json} -> NSArray<NSDictionary<NSString*,NSString*>*> with
609
+ // string values only (json may be the JSON itself or a path to it).
610
+ static NSArray<NSDictionary<NSString *, NSString *> *> *SBSpeakerItems(id raw) {
611
+ NSMutableArray<NSDictionary<NSString *, NSString *> *> *out = [NSMutableArray array];
612
+ if (![raw isKindOfClass:[NSArray class]]) return out;
613
+ for (id item in (NSArray *)raw) {
614
+ if (![item isKindOfClass:[NSDictionary class]]) continue;
615
+ NSMutableDictionary<NSString *, NSString *> *d = [NSMutableDictionary dictionary];
616
+ [(NSDictionary *)item enumerateKeysAndObjectsUsingBlock:^(id k, id v, BOOL *stop) {
617
+ if ([k isKindOfClass:[NSString class]] && [v isKindOfClass:[NSString class]]) d[k] = v;
618
+ }];
619
+ [out addObject:d];
620
+ }
621
+ return out;
622
+ }
623
+
624
+ static BOOL SBNonEmptyString(id v) {
625
+ return [v isKindOfClass:[NSString class]] && [(NSString *)v length] > 0;
626
+ }
627
+
628
+ // Starts STT from initAll-style options: `speakers` (array) replaces the set;
629
+ // otherwise `onboardingJsonPath` (+ optional `speakerId`, default "default") adds
630
+ // one speaker; otherwise the current set (if any) is kept.
631
+ - (void)startSTTWithLocale:(NSString *)locale opts:(NSDictionary *)opts
632
+ {
633
+ NSArray *speakers = SBSpeakerItems(opts[@"speakers"]);
634
+ id onboardingJsonPath = opts[@"onboardingJsonPath"];
635
+ id speakerId = opts[@"speakerId"];
636
+ if (speakers.count > 0) {
637
+ [self.stt startSpeechWithLocaleStr:locale speakers:speakers];
638
+ } else if (SBNonEmptyString(onboardingJsonPath)) {
639
+ [self.stt startSpeechWithLocaleStr:locale
640
+ onboardingJsonPath:onboardingJsonPath
641
+ speakerId:(SBNonEmptyString(speakerId) ? speakerId : @"default")];
642
+ } else {
643
+ [self.stt startSpeechWithLocaleStr:locale];
644
+ }
645
+ }
646
+
647
+ RCT_EXPORT_METHOD(addSpeaker:(NSString *)speakerId
648
+ jsonOrPath:(NSString *)jsonOrPath
649
+ resolver:(RCTPromiseResolveBlock)resolve
650
+ rejecter:(RCTPromiseRejectBlock)reject)
651
+ {
652
+ [self ensureSTT];
653
+ NSError *error = nil;
654
+ if (![self.stt addSpeakerWithId:(speakerId ?: @"default") jsonOrPath:(jsonOrPath ?: @"") error:&error]) {
655
+ reject(@"sv_add_failed", error.localizedDescription ?: @"addSpeaker failed", error);
656
+ return;
657
+ }
658
+ resolve([self.stt getSpeakerIds]);
659
+ }
660
+
661
+ RCT_EXPORT_METHOD(setSpeakers:(NSArray *)speakers
662
+ resolver:(RCTPromiseResolveBlock)resolve
663
+ rejecter:(RCTPromiseRejectBlock)reject)
664
+ {
665
+ [self ensureSTT];
666
+ NSError *error = nil;
667
+ if (![self.stt setSpeakers:SBSpeakerItems(speakers) error:&error]) {
668
+ reject(@"sv_set_failed", error.localizedDescription ?: @"setSpeakers failed", error);
669
+ return;
670
+ }
671
+ resolve([self.stt getSpeakerIds]);
672
+ }
673
+
674
+ RCT_EXPORT_METHOD(removeSpeaker:(NSString *)speakerId
675
+ resolver:(RCTPromiseResolveBlock)resolve
676
+ rejecter:(RCTPromiseRejectBlock)reject)
677
+ {
678
+ if (!self.stt) { resolve(@(NO)); return; }
679
+ resolve(@([self.stt removeSpeakerWithId:(speakerId ?: @"")]));
680
+ }
681
+
682
+ RCT_EXPORT_METHOD(getSpeakerIds:(RCTPromiseResolveBlock)resolve
683
+ rejecter:(RCTPromiseRejectBlock)reject)
684
+ {
685
+ resolve(self.stt ? [self.stt getSpeakerIds] : @[]);
686
+ }
687
+
688
+ RCT_EXPORT_METHOD(startSpeechWithSVSpeakers:(NSString *)locale
689
+ speakers:(NSArray *)speakers
690
+ timeoutMs:(nonnull NSNumber *)timeoutMs
691
+ resolver:(RCTPromiseResolveBlock)resolve
692
+ rejecter:(RCTPromiseRejectBlock)reject)
693
+ {
694
+ [self ensureSTT];
695
+ self.sttEngineHot = NO;
696
+ [self.stt startSpeechWithLocaleStr:locale speakers:SBSpeakerItems(speakers)];
697
+ [self waitForSTTEngineHotWithTimeoutMs:timeoutMs completion:^(BOOL ok) {
698
+ if (!ok) {
699
+ reject(@"stt_start_timeout", @"STT did not become ready before timeout", nil);
700
+ return;
701
+ }
702
+ resolve(@{@"ok": @(YES)});
703
+ }];
704
+ }
705
+
606
706
  RCT_EXPORT_METHOD(initAll:(NSDictionary *)opts
607
707
  resolver:(RCTPromiseResolveBlock)resolve
608
708
  rejecter:(RCTPromiseRejectBlock)reject)
@@ -615,7 +715,6 @@ RCT_EXPORT_METHOD(initAll:(NSDictionary *)opts
615
715
  self.sttEngineHot = NO;
616
716
 
617
717
  NSString *locale = opts[@"locale"] ?: @"en-US";
618
- NSString *onboardingJsonPath = opts[@"onboardingJsonPath"];
619
718
  NSString *modelPath = opts[@"model"];
620
719
  NSNumber *timeoutMs = opts[@"timeoutMs"];
621
720
  if (modelPath.length == 0) {
@@ -632,11 +731,7 @@ RCT_EXPORT_METHOD(initAll:(NSDictionary *)opts
632
731
  [self.stt setLicenseWithLicenseKey:self.lastLicenseKey];
633
732
  }
634
733
  }
635
- if (onboardingJsonPath && (id)onboardingJsonPath != [NSNull null] && onboardingJsonPath.length > 0) {
636
- [self.stt startSpeechWithLocaleStr:locale onboardingJsonPath:onboardingJsonPath];
637
- } else {
638
- [self.stt startSpeechWithLocaleStr:locale];
639
- }
734
+ [self startSTTWithLocale:locale opts:opts];
640
735
 
641
736
  // 2) TTS next
642
737
  NSURL *modelURL = nil;
@@ -740,17 +835,12 @@ RCT_EXPORT_METHOD(initWithoutModel:(NSDictionary *)opts
740
835
  self.sttEngineHot = NO;
741
836
 
742
837
  NSString *locale = opts[@"locale"] ?: @"en-US";
743
- NSString *onboardingJsonPath = opts[@"onboardingJsonPath"];
744
838
  NSNumber *timeoutMs = opts[@"timeoutMs"];
745
839
 
746
840
  [self tearDownSTT];
747
841
 
748
842
  [self ensureSTT];
749
- if (onboardingJsonPath && (id)onboardingJsonPath != [NSNull null] && onboardingJsonPath.length > 0) {
750
- [self.stt startSpeechWithLocaleStr:locale onboardingJsonPath:onboardingJsonPath];
751
- } else {
752
- [self.stt startSpeechWithLocaleStr:locale];
753
- }
843
+ [self startSTTWithLocale:locale opts:opts];
754
844
 
755
845
  [self waitForSTTEngineHotWithTimeoutMs:timeoutMs completion:^(BOOL ok) {
756
846
  if (!ok) {
@@ -8,32 +8,32 @@
8
8
  <key>BinaryPath</key>
9
9
  <string>DavoiceTTS.framework/DavoiceTTS</string>
10
10
  <key>LibraryIdentifier</key>
11
- <string>ios-arm64</string>
11
+ <string>ios-arm64_x86_64-simulator</string>
12
12
  <key>LibraryPath</key>
13
13
  <string>DavoiceTTS.framework</string>
14
14
  <key>SupportedArchitectures</key>
15
15
  <array>
16
16
  <string>arm64</string>
17
+ <string>x86_64</string>
17
18
  </array>
18
19
  <key>SupportedPlatform</key>
19
20
  <string>ios</string>
21
+ <key>SupportedPlatformVariant</key>
22
+ <string>simulator</string>
20
23
  </dict>
21
24
  <dict>
22
25
  <key>BinaryPath</key>
23
26
  <string>DavoiceTTS.framework/DavoiceTTS</string>
24
27
  <key>LibraryIdentifier</key>
25
- <string>ios-arm64_x86_64-simulator</string>
28
+ <string>ios-arm64</string>
26
29
  <key>LibraryPath</key>
27
30
  <string>DavoiceTTS.framework</string>
28
31
  <key>SupportedArchitectures</key>
29
32
  <array>
30
33
  <string>arm64</string>
31
- <string>x86_64</string>
32
34
  </array>
33
35
  <key>SupportedPlatform</key>
34
36
  <string>ios</string>
35
- <key>SupportedPlatformVariant</key>
36
- <string>simulator</string>
37
37
  </dict>
38
38
  </array>
39
39
  <key>CFBundlePackageType</key>
@@ -416,7 +416,27 @@ SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly, copy) NSArray<NSStri
416
416
  - (void)isSpeechAvailable:(void (^ _Nonnull)(BOOL))completion;
417
417
  - (BOOL)isRecognizing SWIFT_WARN_UNUSED_RESULT;
418
418
  - (void)startSpeechWithLocaleStr:(NSString * _Nullable)localeStr;
419
+ /// Starts STT with one speaker. <code>onboardingJsonPath</code> may be a path or the JSON
420
+ /// itself. The speaker is added to the current set (same id or same voiceprint
421
+ /// replaces the older entry) under the id “default”.
419
422
  - (void)startSpeechWithLocaleStr:(NSString * _Nullable)localeStr onboardingJsonPath:(NSString * _Nonnull)onboardingJsonPath;
423
+ - (void)startSpeechWithLocaleStr:(NSString * _Nullable)localeStr onboardingJsonPath:(NSString * _Nonnull)onboardingJsonPath speakerId:(NSString * _Nonnull)speakerId;
424
+ /// Starts STT with an array of speakers, replacing the current set.
425
+ /// Each item: [“id”: speakerId, “json”: JSON string or path to the JSON file].
426
+ - (void)startSpeechWithLocaleStr:(NSString * _Nullable)localeStr speakers:(NSArray<NSDictionary<NSString *, NSString *> *> * _Nonnull)speakers;
427
+ /// Adds one speaker (JSON string or path). Same id or same voiceprint replaces
428
+ /// the older entry. Applies immediately when STT is running, otherwise at the
429
+ /// next start. Throws if the JSON can’t be read or its audio-feature settings
430
+ /// differ from the running engine’s.
431
+ - (BOOL)addSpeakerWithId:(NSString * _Nonnull)id jsonOrPath:(NSString * _Nonnull)jsonOrPath error:(NSError * _Nullable * _Nullable)error;
432
+ /// Replaces the whole speaker set. Items: [“id”: …, “json”: JSON string or path].
433
+ /// An empty array turns speaker verification off.
434
+ - (BOOL)setSpeakers:(NSArray<NSDictionary<NSString *, NSString *> *> * _Nonnull)speakers error:(NSError * _Nullable * _Nullable)error;
435
+ /// Removes a speaker by id. Removing the last one turns the gate off (all audio
436
+ /// passes). Returns false if the id wasn’t enrolled.
437
+ - (BOOL)removeSpeakerWithId:(NSString * _Nonnull)id;
438
+ /// Ids of the enrolled speakers, in insertion order.
439
+ - (NSArray<NSString *> * _Nonnull)getSpeakerIds SWIFT_WARN_UNUSED_RESULT;
420
440
  - (void)stopSpeech:(void (^ _Nullable)(BOOL))completion;
421
441
  - (void)cancelSpeech:(void (^ _Nullable)(BOOL))completion;
422
442
  - (void)destroySpeech:(void (^ _Nullable)(BOOL))completion;