Skip to content

Commit e328002

Browse files
authored
Support decoding multiple streams in Java API. (#2149)
1 parent 48ab90a commit e328002

File tree

7 files changed

+160
-3
lines changed

7 files changed

+160
-3
lines changed

.github/workflows/run-java-test.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ jobs:
166166
rm -rf sherpa-onnx-fire-red-*
167167
168168
./run-non-streaming-decode-file-whisper.sh
169+
170+
./run-non-streaming-decode-file-whisper-multiple.sh
169171
rm -rf sherpa-onnx-whisper-*
170172
171173
./run-non-streaming-decode-file-nemo.sh
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2025 Xiaomi Corporation
2+
3+
// This file shows how to use an offline whisper, i.e., non-streaming whisper,
4+
// to decode files.
5+
import com.k2fsa.sherpa.onnx.*;
6+
7+
public class NonStreamingDecodeFileWhisperMultiple {
8+
public static void main(String[] args) {
9+
// please refer to
10+
// https://k2-fsa.github.io/sherpa/onnx/pretrained_models/whisper/tiny.en.html
11+
// to download model files
12+
String encoder = "./sherpa-onnx-whisper-tiny.en/tiny.en-encoder.int8.onnx";
13+
String decoder = "./sherpa-onnx-whisper-tiny.en/tiny.en-decoder.int8.onnx";
14+
String tokens = "./sherpa-onnx-whisper-tiny.en/tiny.en-tokens.txt";
15+
16+
String waveFilename0 = "./sherpa-onnx-whisper-tiny.en/test_wavs/0.wav";
17+
String waveFilename1 = "./sherpa-onnx-whisper-tiny.en/test_wavs/1.wav";
18+
19+
WaveReader reader0 = new WaveReader(waveFilename0);
20+
WaveReader reader1 = new WaveReader(waveFilename1);
21+
22+
OfflineWhisperModelConfig whisper =
23+
OfflineWhisperModelConfig.builder().setEncoder(encoder).setDecoder(decoder).build();
24+
25+
OfflineModelConfig modelConfig =
26+
OfflineModelConfig.builder()
27+
.setWhisper(whisper)
28+
.setTokens(tokens)
29+
.setNumThreads(1)
30+
.setDebug(true)
31+
.build();
32+
33+
OfflineRecognizerConfig config =
34+
OfflineRecognizerConfig.builder()
35+
.setOfflineModelConfig(modelConfig)
36+
.setDecodingMethod("greedy_search")
37+
.build();
38+
39+
OfflineRecognizer recognizer = new OfflineRecognizer(config);
40+
OfflineStream stream0 = recognizer.createStream();
41+
stream0.acceptWaveform(reader0.getSamples(), reader0.getSampleRate());
42+
43+
OfflineStream stream1 = recognizer.createStream();
44+
stream1.acceptWaveform(reader1.getSamples(), reader1.getSampleRate());
45+
46+
OfflineStream[] ss = new OfflineStream[] {stream0, stream1};
47+
recognizer.decode(ss);
48+
49+
String text0 = recognizer.getResult(stream0).getText();
50+
String text1 = recognizer.getResult(stream1).getText();
51+
52+
System.out.printf("filename0:%s\nresult0:%s\n\n", waveFilename0, text0);
53+
System.out.printf("filename1:%s\nresult1:%s\n\n", waveFilename1, text1);
54+
55+
stream0.release();
56+
stream1.release();
57+
recognizer.release();
58+
}
59+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env bash
2+
3+
set -ex
4+
5+
if [[ ! -f ../build/lib/libsherpa-onnx-jni.dylib && ! -f ../build/lib/libsherpa-onnx-jni.so ]]; then
6+
mkdir -p ../build
7+
pushd ../build
8+
cmake \
9+
-DSHERPA_ONNX_ENABLE_PYTHON=OFF \
10+
-DSHERPA_ONNX_ENABLE_TESTS=OFF \
11+
-DSHERPA_ONNX_ENABLE_CHECK=OFF \
12+
-DBUILD_SHARED_LIBS=ON \
13+
-DSHERPA_ONNX_ENABLE_PORTAUDIO=OFF \
14+
-DSHERPA_ONNX_ENABLE_JNI=ON \
15+
..
16+
17+
make -j4
18+
ls -lh lib
19+
popd
20+
fi
21+
22+
if [ ! -f ../sherpa-onnx/java-api/build/sherpa-onnx.jar ]; then
23+
pushd ../sherpa-onnx/java-api
24+
make
25+
popd
26+
fi
27+
28+
if [ ! -f ./sherpa-onnx-whisper-tiny.en/tiny.en-tokens.txt ]; then
29+
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-whisper-tiny.en.tar.bz2
30+
31+
tar xvf sherpa-onnx-whisper-tiny.en.tar.bz2
32+
rm sherpa-onnx-whisper-tiny.en.tar.bz2
33+
fi
34+
35+
java \
36+
-Djava.library.path=$PWD/../build/lib \
37+
-cp ../sherpa-onnx/java-api/build/sherpa-onnx.jar \
38+
NonStreamingDecodeFileWhisperMultiple.java

sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineRecognizer.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ public void decode(OfflineStream s) {
1717
decode(ptr, s.getPtr());
1818
}
1919

20+
public void decode(OfflineStream[] ss) {
21+
long[] streamPtrs = new long[ss.length];
22+
for (int i = 0; i < ss.length; ++i) {
23+
streamPtrs[i] = ss[i].getPtr();
24+
}
25+
decodeStreams(ptr, streamPtrs);
26+
}
27+
2028
public OfflineStream createStream() {
2129
long p = createStream(ptr);
2230
return new OfflineStream(p);
@@ -55,5 +63,7 @@ public OfflineRecognizerResult getResult(OfflineStream s) {
5563

5664
private native void decode(long ptr, long streamPtr);
5765

66+
private native void decodeStreams(long ptr, long[] streamPtrs);
67+
5868
private native Object[] getResult(long streamPtr);
5969
}

sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OnlineRecognizer.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ public void decode(OnlineStream s) {
1818
decode(ptr, s.getPtr());
1919
}
2020

21+
public void decode(OnlineStream[] ss) {
22+
long[] streamPtrs = new long[ss.length];
23+
for (int i = 0; i < ss.length; ++i) {
24+
streamPtrs[i] = ss[i].getPtr();
25+
}
26+
decodeStreams(ptr, streamPtrs);
27+
}
28+
2129
public boolean isReady(OnlineStream s) {
2230
return isReady(ptr, s.getPtr());
2331
}
@@ -68,6 +76,8 @@ public OnlineRecognizerResult getResult(OnlineStream s) {
6876

6977
private native void decode(long ptr, long streamPtr);
7078

79+
private native void decodeStreams(long ptr, long[] streamPtrs);
80+
7181
private native boolean isEndpoint(long ptr, long streamPtr);
7282

7383
private native boolean isReady(long ptr, long streamPtr);

sherpa-onnx/jni/offline-recognizer.cc

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,21 +366,43 @@ Java_com_k2fsa_sherpa_onnx_OfflineRecognizer_createStream(JNIEnv * /*env*/,
366366

367367
SHERPA_ONNX_EXTERN_C
368368
JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_OfflineRecognizer_decode(
369-
JNIEnv *env, jobject /*obj*/, jlong ptr, jlong streamPtr) {
369+
JNIEnv *env, jobject /*obj*/, jlong ptr, jlong stream_ptr) {
370370
SafeJNI(env, "OfflineRecognizer_decode", [&] {
371371
if (!ValidatePointer(env, ptr, "OfflineRecognizer_decode",
372372
"OfflineRecognizer pointer is null.") ||
373-
!ValidatePointer(env, streamPtr, "OfflineRecognizer_decode",
373+
!ValidatePointer(env, stream_ptr, "OfflineRecognizer_decode",
374374
"OfflineStream pointer is null.")) {
375375
return;
376376
}
377377

378378
auto recognizer = reinterpret_cast<sherpa_onnx::OfflineRecognizer *>(ptr);
379-
auto stream = reinterpret_cast<sherpa_onnx::OfflineStream *>(streamPtr);
379+
auto stream = reinterpret_cast<sherpa_onnx::OfflineStream *>(stream_ptr);
380380
recognizer->DecodeStream(stream);
381381
});
382382
}
383383

384+
SHERPA_ONNX_EXTERN_C
385+
JNIEXPORT void JNICALL
386+
Java_com_k2fsa_sherpa_onnx_OfflineRecognizer_decodeStreams(
387+
JNIEnv *env, jobject /*obj*/, jlong ptr, jlongArray stream_ptrs) {
388+
SafeJNI(env, "OfflineRecognizer_decode_streams", [&] {
389+
if (!ValidatePointer(env, ptr, "OfflineRecognizer_decode_streams",
390+
"OfflineRecognizer pointer is null.")) {
391+
return;
392+
}
393+
394+
auto recognizer = reinterpret_cast<sherpa_onnx::OfflineRecognizer *>(ptr);
395+
396+
jlong *p = env->GetLongArrayElements(stream_ptrs, nullptr);
397+
jsize n = env->GetArrayLength(stream_ptrs);
398+
399+
auto ss = reinterpret_cast<sherpa_onnx::OfflineStream **>(p);
400+
recognizer->DecodeStreams(ss, n);
401+
402+
env->ReleaseLongArrayElements(stream_ptrs, p, JNI_ABORT);
403+
});
404+
}
405+
384406
SHERPA_ONNX_EXTERN_C
385407
JNIEXPORT jobjectArray JNICALL
386408
Java_com_k2fsa_sherpa_onnx_OfflineRecognizer_getResult(JNIEnv *env,

sherpa-onnx/jni/online-recognizer.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,22 @@ JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_OnlineRecognizer_decode(
339339
recognizer->DecodeStream(stream);
340340
}
341341

342+
SHERPA_ONNX_EXTERN_C
343+
JNIEXPORT void JNICALL
344+
Java_com_k2fsa_sherpa_onnx_OnlineRecognizer_decodeStreams(
345+
JNIEnv *env, jobject /*obj*/, jlong ptr, jlongArray stream_ptrs) {
346+
auto recognizer = reinterpret_cast<sherpa_onnx::OnlineRecognizer *>(ptr);
347+
348+
jlong *p = env->GetLongArrayElements(stream_ptrs, nullptr);
349+
jsize n = env->GetArrayLength(stream_ptrs);
350+
351+
auto ss = reinterpret_cast<sherpa_onnx::OnlineStream **>(p);
352+
353+
recognizer->DecodeStreams(ss, n);
354+
355+
env->ReleaseLongArrayElements(stream_ptrs, p, JNI_ABORT);
356+
}
357+
342358
SHERPA_ONNX_EXTERN_C
343359
JNIEXPORT jlong JNICALL
344360
Java_com_k2fsa_sherpa_onnx_OnlineRecognizer_createStream(JNIEnv *env,

0 commit comments

Comments
 (0)