react-native-wakeword-sid 1.1.99 → 1.1.101
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/android/libs/com/davoice/keyworddetection/1.0.0/keyworddetection-1.0.0.aar +0 -0
- package/android/libs/com/davoice/keyworddetection/1.0.0/keyworddetection-1.0.0.aar.md5 +1 -1
- package/android/libs/com/davoice/keyworddetection/1.0.0/keyworddetection-1.0.0.aar.sha1 +1 -1
- package/android/src/main/java/com/davoice/speakeridrn/SpeakerIdRNBridge.java +154 -0
- package/package.json +1 -1
- package/speakerid/SpeakerIdRNBridge.d.ts +1 -0
- package/speakerid/SpeakerIdRNBridge.js +7 -0
- package/speakerid/index.d.ts +1 -0
- package/speakerid/index.js +1 -0
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
9254ff04488a759290e2498b3deaaa2d keyworddetection-1.0.0.aar
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
72e064d55b4c80a6396644542bd47a3313b76fe0 keyworddetection-1.0.0.aar
|
|
@@ -18,6 +18,13 @@ import java.io.File;
|
|
|
18
18
|
import java.util.HashMap;
|
|
19
19
|
import java.util.Map;
|
|
20
20
|
import java.util.concurrent.*;
|
|
21
|
+
import android.content.res.AssetManager;
|
|
22
|
+
import java.io.InputStream;
|
|
23
|
+
import java.io.BufferedInputStream;
|
|
24
|
+
import java.io.ByteArrayOutputStream;
|
|
25
|
+
import java.io.IOException;
|
|
26
|
+
import java.util.Locale;
|
|
27
|
+
|
|
21
28
|
|
|
22
29
|
/**
|
|
23
30
|
* React Native bridge for the speaker-id Android library.
|
|
@@ -104,6 +111,71 @@ public class SpeakerIdRNBridge extends ReactContextBaseJavaModule {
|
|
|
104
111
|
});
|
|
105
112
|
}
|
|
106
113
|
|
|
114
|
+
@ReactMethod
|
|
115
|
+
public void initVerificationUsingCurrentConfig(Promise promise) {
|
|
116
|
+
SpeakerIdApi api = instances.get(instanceId);
|
|
117
|
+
if (api == null) { promise.reject("InstanceNotFound", instanceId); return; }
|
|
118
|
+
try {
|
|
119
|
+
boolean ok = api.initVerificationUsingCurrentConfig();
|
|
120
|
+
promise.resolve(ok);
|
|
121
|
+
} catch (Throwable t) {
|
|
122
|
+
promise.reject("E_INIT_CHECK", t);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ======= External-audio cluster API (RN) =======
|
|
127
|
+
|
|
128
|
+
@ReactMethod
|
|
129
|
+
public void initCluster(String instanceId, int numOfEmb, Promise promise) {
|
|
130
|
+
SpeakerIdApi api = instances.get(instanceId);
|
|
131
|
+
if (api == null) { promise.reject("InstanceNotFound", instanceId); return; }
|
|
132
|
+
exec.submit(() -> {
|
|
133
|
+
try {
|
|
134
|
+
int cid = api.initCluster(numOfEmb);
|
|
135
|
+
main.post(() -> promise.resolve(cid));
|
|
136
|
+
} catch (Throwable t) {
|
|
137
|
+
main.post(() -> promise.reject("InitClusterError", t.getMessage(), t));
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@ReactMethod
|
|
143
|
+
public void createAndPushEmbeddingsToCluster(String instanceId, int clusterId, ReadableArray pcmI16, int length, Promise promise) {
|
|
144
|
+
SpeakerIdApi api = instances.get(instanceId);
|
|
145
|
+
if (api == null) { promise.reject("InstanceNotFound", instanceId); return; }
|
|
146
|
+
// Convert RN int[] -> short[]
|
|
147
|
+
int n = Math.min(length, pcmI16.size());
|
|
148
|
+
final short[] block = new short[n];
|
|
149
|
+
for (int i = 0; i < n; i++) block[i] = (short) pcmI16.getInt(i);
|
|
150
|
+
|
|
151
|
+
exec.submit(() -> {
|
|
152
|
+
try {
|
|
153
|
+
api.createAndPushEmbeddingsToCluster(clusterId, block, n);
|
|
154
|
+
main.post(() -> promise.resolve(null));
|
|
155
|
+
} catch (Throwable t) {
|
|
156
|
+
main.post(() -> promise.reject("PushClusterError", t.getMessage(), t));
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
@ReactMethod
|
|
162
|
+
public void createAndVerifyEmbeddingsFromCluster(String instanceId, int clusterId, ReadableArray pcmI16, int length, Promise promise) {
|
|
163
|
+
SpeakerIdApi api = instances.get(instanceId);
|
|
164
|
+
if (api == null) { promise.reject("InstanceNotFound", instanceId); return; }
|
|
165
|
+
int n = Math.min(length, pcmI16.size());
|
|
166
|
+
final short[] block = new short[n];
|
|
167
|
+
for (int i = 0; i < n; i++) block[i] = (short) pcmI16.getInt(i);
|
|
168
|
+
|
|
169
|
+
exec.submit(() -> {
|
|
170
|
+
try {
|
|
171
|
+
float score = api.createAndVerifyEmbeddingsFromCluster(clusterId, block, n);
|
|
172
|
+
main.post(() -> promise.resolve(score));
|
|
173
|
+
} catch (Throwable t) {
|
|
174
|
+
main.post(() -> promise.reject("VerifyClusterError", t.getMessage(), t));
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
107
179
|
@ReactMethod
|
|
108
180
|
public void destroyInstance(String instanceId, Promise promise) {
|
|
109
181
|
SpeakerIdApi api;
|
|
@@ -309,6 +381,9 @@ public class SpeakerIdRNBridge extends ReactContextBaseJavaModule {
|
|
|
309
381
|
}
|
|
310
382
|
|
|
311
383
|
// ======= WWD: create instance tuned for wake-word =======
|
|
384
|
+
|
|
385
|
+
private static final boolean DEBUG_SID_ASSETS = true; // set false for production
|
|
386
|
+
|
|
312
387
|
@ReactMethod
|
|
313
388
|
public void createInstanceWWD(String instanceId, Promise promise) {
|
|
314
389
|
if (instances.containsKey(instanceId)) {
|
|
@@ -320,6 +395,11 @@ public class SpeakerIdRNBridge extends ReactContextBaseJavaModule {
|
|
|
320
395
|
SpeakerIdApi api = SpeakerIdApi.createWWD(reactContext);
|
|
321
396
|
synchronized (instances) { instances.put(instanceId, api); }
|
|
322
397
|
main.post(() -> promise.resolve(true));
|
|
398
|
+
// Then run debug async if enabled
|
|
399
|
+
if (DEBUG_SID_ASSETS) {
|
|
400
|
+
exec.submit(() -> debugOnAssetsWWD(instanceId));
|
|
401
|
+
}
|
|
402
|
+
|
|
323
403
|
} catch (Exception e) {
|
|
324
404
|
main.post(() -> promise.reject("CreateWWDError", e.getMessage(), e));
|
|
325
405
|
}
|
|
@@ -424,4 +504,78 @@ public class SpeakerIdRNBridge extends ReactContextBaseJavaModule {
|
|
|
424
504
|
exec.shutdownNow();
|
|
425
505
|
super.onCatalystInstanceDestroy();
|
|
426
506
|
}
|
|
507
|
+
|
|
508
|
+
// ======= DEBUG harness (assets) =======
|
|
509
|
+
|
|
510
|
+
private void emitDebug(String msg) {
|
|
511
|
+
WritableMap m = Arguments.createMap();
|
|
512
|
+
m.putString("line", msg);
|
|
513
|
+
sendEvent("SpeakerIdDebug", m);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
private void debugOnAssetsWWD(String instanceId) {
|
|
517
|
+
try {
|
|
518
|
+
SpeakerIdApi api = instances.get(instanceId);
|
|
519
|
+
if (api == null) { emitDebug("debugOnAssetsWWD: instance gone: " + instanceId); return; }
|
|
520
|
+
|
|
521
|
+
// 1) Init a small FIFO cluster (K=3)
|
|
522
|
+
final int K = 3;
|
|
523
|
+
int clusterId = api.initCluster(K);
|
|
524
|
+
emitDebug("WWD DEBUG: initCluster -> " + clusterId + " (K=" + K + ")");
|
|
525
|
+
|
|
526
|
+
// 2) Onboarding from assets
|
|
527
|
+
String[] onboard = new String[] {
|
|
528
|
+
"onboard1.raw","onboard2.raw","onboard3.raw","onboard4.raw"
|
|
529
|
+
};
|
|
530
|
+
for (int i = 0; i < onboard.length; i++) {
|
|
531
|
+
short[] pcm = readPcm16LeRawAsset(onboard[i]);
|
|
532
|
+
api.createAndPushEmbeddingsToCluster(clusterId, pcm, pcm.length);
|
|
533
|
+
String line = String.format(Locale.US, "WWD DEBUG: push #%d '%s' samples=%d", i+1, onboard[i], pcm.length);
|
|
534
|
+
emitDebug(line);
|
|
535
|
+
}
|
|
536
|
+
emitDebug("WWD DEBUG: onboarding done; cluster+mean saved.");
|
|
537
|
+
|
|
538
|
+
// 3) Verification from assets
|
|
539
|
+
String[] tests = new String[] {
|
|
540
|
+
"test1.raw","test2.raw","test3.raw","test4.raw","test5.raw","test6.raw","test7.raw"
|
|
541
|
+
};
|
|
542
|
+
for (String tf : tests) {
|
|
543
|
+
short[] pcm = readPcm16LeRawAsset(tf);
|
|
544
|
+
float score = api.createAndVerifyEmbeddingsFromCluster(clusterId, pcm, pcm.length);
|
|
545
|
+
String line = String.format(Locale.US, "WWD DEBUG: verify '%s' samples=%d -> score=%.4f",
|
|
546
|
+
tf, pcm.length, score);
|
|
547
|
+
emitDebug(line);
|
|
548
|
+
}
|
|
549
|
+
emitDebug("WWD DEBUG: verification pass completed.");
|
|
550
|
+
} catch (Throwable t) {
|
|
551
|
+
emitDebug("WWD DEBUG ERROR: " + t.getMessage());
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** Read RAW little-endian PCM16 asset → short[] (exactly your requested method) */
|
|
556
|
+
private short[] readPcm16LeRawAsset(String assetName) throws IOException {
|
|
557
|
+
AssetManager am = reactContext.getAssets();
|
|
558
|
+
try (InputStream in = am.open(assetName);
|
|
559
|
+
BufferedInputStream bis = new BufferedInputStream(in);
|
|
560
|
+
ByteArrayOutputStream baos = new ByteArrayOutputStream(32 * 1024)) {
|
|
561
|
+
|
|
562
|
+
byte[] buf = new byte[8192];
|
|
563
|
+
int n;
|
|
564
|
+
while ((n = bis.read(buf)) != -1) {
|
|
565
|
+
baos.write(buf, 0, n);
|
|
566
|
+
}
|
|
567
|
+
byte[] all = baos.toByteArray();
|
|
568
|
+
if ((all.length & 1) != 0) {
|
|
569
|
+
throw new IOException("Asset RAW has odd byte length: " + assetName + " (" + all.length + " bytes)");
|
|
570
|
+
}
|
|
571
|
+
int samples = all.length / 2;
|
|
572
|
+
short[] pcm = new short[samples];
|
|
573
|
+
for (int i = 0, s = 0; i < all.length; i += 2, s++) {
|
|
574
|
+
int lo = (all[i] & 0xFF);
|
|
575
|
+
int hi = (all[i + 1] << 8);
|
|
576
|
+
pcm[s] = (short) (hi | lo);
|
|
577
|
+
}
|
|
578
|
+
return pcm;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
427
581
|
}
|
package/package.json
CHANGED
|
@@ -22,6 +22,7 @@ export class SpeakerIdInstance {
|
|
|
22
22
|
* Verification init
|
|
23
23
|
*/
|
|
24
24
|
initVerificationUsingDefaults(): Promise<any>;
|
|
25
|
+
initVerificationUsingCurrentConfig(): Promise<any>;
|
|
25
26
|
initVerificationWithFiles(meanNpyPath: any, clusterNpyPath: any): Promise<any>;
|
|
26
27
|
/**
|
|
27
28
|
* Verification
|
|
@@ -86,6 +86,13 @@ export class SpeakerIdInstance {
|
|
|
86
86
|
return SpeakerIdRNBridge.onboardFromWav(this.instanceId, String(absPath));
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
async initVerificationUsingCurrentConfig() {
|
|
90
|
+
ensureAndroid();
|
|
91
|
+
// Resolves to boolean
|
|
92
|
+
return SpeakerIdRNBridge.initVerificationUsingCurrentConfig(this.instanceId);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
89
96
|
/**
|
|
90
97
|
* Verification init
|
|
91
98
|
*/
|
package/speakerid/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export function createSpeakerIdInstance(instanceId?: string): Promise<{
|
|
|
4
4
|
onboardFromMicrophoneWWD: (embNum: any, ms: any) => any;
|
|
5
5
|
verifyFromMicrophoneWWD: (ms: any) => any;
|
|
6
6
|
initVerificationUsingDefaults: () => any;
|
|
7
|
+
initVerificationUsingCurrentConfig: () => any;
|
|
7
8
|
initVerificationWithFiles: (m: any, c: any) => any;
|
|
8
9
|
onboardFromMicrophone: (ms: any) => any;
|
|
9
10
|
onboardStartStream: () => any;
|
package/speakerid/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export const createSpeakerIdInstance = async (instanceId = 'sid1') => ({
|
|
|
10
10
|
verifyFromMicrophoneWWD: (ms) =>
|
|
11
11
|
SpeakerIdRNBridge.verifyFromMicrophoneWWD(instanceId, ms ?? 5000),
|
|
12
12
|
initVerificationUsingDefaults: () => SpeakerIdRNBridge.initVerificationUsingDefaults(instanceId),
|
|
13
|
+
initVerificationUsingCurrentConfig: () => SpeakerIdRNBridge.initVerificationUsingDefaults(instanceId),
|
|
13
14
|
initVerificationWithFiles: (m, c) => SpeakerIdRNBridge.initVerificationWithFiles(instanceId, m, c),
|
|
14
15
|
onboardFromMicrophone: (ms) => SpeakerIdRNBridge.onboardFromMicrophone(instanceId, ms ?? 12000),
|
|
15
16
|
onboardStartStream: () => SpeakerIdRNBridge.onboardStartStream(instanceId),
|